First Commit
This commit is contained in:
commit
3f63c202f6
5
.editorconfig
Normal file
5
.editorconfig
Normal file
@ -0,0 +1,5 @@
|
||||
[*]
|
||||
indent_size = 3
|
||||
indent_style = space
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
out/
|
||||
node_modules/
|
24
package-lock.json
generated
Normal file
24
package-lock.json
generated
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@hibas123/theme-preact",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@hibas123/theme": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@hibas123/theme/-/theme-2.0.2.tgz",
|
||||
"integrity": "sha512-bx9g8OgxaMtsgnOEh+152WRC6hE8pHNR+Q2g/K9cfIY9Uy7k6ZHrsWz2ql8HJNJ/0Tn6/a15l5wQJyqBRnLnvQ=="
|
||||
},
|
||||
"preact": {
|
||||
"version": "10.3.4",
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.3.4.tgz",
|
||||
"integrity": "sha512-wMgzs/RGYf0I1PZf8ZFJdyU/3kCcwepJyVYe+N9FGajyQWarMoPrPfrQajcG0psPj6ySYv2cSuLYFCihvV/Qrw=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
||||
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
23
package.json
Normal file
23
package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "@hibas123/theme-preact",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "out/index.js",
|
||||
"dependencies": {
|
||||
"@hibas123/theme": "^2.0.2",
|
||||
"preact": "^10.3.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"preact": "^10.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"watch": "tsc -w"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
45
src/Button.tsx
Normal file
45
src/Button.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import { h, JSX } from "preact";
|
||||
|
||||
export enum ButtonFormats {
|
||||
DEFAULT,
|
||||
PRIMARY,
|
||||
SECONDARY,
|
||||
ERROR,
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
export interface IButtonProps extends JSX.HTMLAttributes<HTMLButtonElement> {
|
||||
format: ButtonFormats;
|
||||
}
|
||||
|
||||
export default function Button({
|
||||
children,
|
||||
format,
|
||||
className,
|
||||
...props
|
||||
}: IButtonProps) {
|
||||
let cl = "ht-btn";
|
||||
|
||||
if (className) cl += " " + className;
|
||||
|
||||
switch (format) {
|
||||
case ButtonFormats.DEFAULT:
|
||||
break;
|
||||
case ButtonFormats.PRIMARY:
|
||||
cl += " ht-btn-primary";
|
||||
break;
|
||||
case ButtonFormats.SECONDARY:
|
||||
cl += " ht-btn-secondary";
|
||||
break;
|
||||
case ButtonFormats.ERROR:
|
||||
cl += " ht-btn-error";
|
||||
break;
|
||||
case ButtonFormats.SUCCESS:
|
||||
cl += " ht-btn-success";
|
||||
break;
|
||||
}
|
||||
|
||||
<button className={cl} {...props}>
|
||||
{children}
|
||||
</button>;
|
||||
}
|
12
src/Card.tsx
Normal file
12
src/Card.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { h, JSX } from "preact";
|
||||
export default function Card({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div className={"ht-card " + className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
12
src/Container.tsx
Normal file
12
src/Container.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { h, JSX } from "preact";
|
||||
export default function Container({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div className={"ht-container " + className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
16
src/Fab.tsx
Normal file
16
src/Fab.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { h, JSX } from "preact";
|
||||
|
||||
export default function Fab({
|
||||
className,
|
||||
children,
|
||||
alignLeft,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLButtonElement> & { alignLeft: boolean }) {
|
||||
let cl = "ht-fab " + (alignLeft ? "ht-fab-left " : "");
|
||||
|
||||
return (
|
||||
<button className={cl + className} {...props}>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
15
src/Header.tsx
Normal file
15
src/Header.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { h, JSX } from "preact";
|
||||
|
||||
//TODO: Implement predefined children styles
|
||||
|
||||
export default function Header({
|
||||
children,
|
||||
className,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<header className={"ht-header " + className} {...props}>
|
||||
{children}
|
||||
</header>
|
||||
);
|
||||
}
|
12
src/IconButton.tsx
Normal file
12
src/IconButton.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { h, JSX } from "preact";
|
||||
export default function IconButton({
|
||||
children,
|
||||
className,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLButtonElement>) {
|
||||
return (
|
||||
<button className={"ht-btn ht-btn-icon " + className} {...props}>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
81
src/Input.tsx
Normal file
81
src/Input.tsx
Normal file
@ -0,0 +1,81 @@
|
||||
import { h, JSX } from "preact";
|
||||
|
||||
export function Input({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLInputElement>) {
|
||||
return (
|
||||
<input className={"ht-inp " + className} {...props}>
|
||||
{children}
|
||||
</input>
|
||||
);
|
||||
}
|
||||
|
||||
export function TextArea({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLTextAreaElement>) {
|
||||
return (
|
||||
<textarea className={"ht-inp " + className} {...props}>
|
||||
{children}
|
||||
</textarea>
|
||||
);
|
||||
}
|
||||
|
||||
export function InputGroup({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div className={"ht-input-group " + className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export interface IInputCheckboxProps {
|
||||
label: string;
|
||||
}
|
||||
export function InputCheckbox({
|
||||
label,
|
||||
...props
|
||||
}: IInputCheckboxProps & JSX.HTMLAttributes<HTMLInputElement>) {
|
||||
return (
|
||||
<label class="ht-input-checkbox">
|
||||
{label}
|
||||
<input type="checkbox" {...props} />
|
||||
<span></span>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
export interface IInputRadioProps {
|
||||
label: string;
|
||||
}
|
||||
export function InputRadio({
|
||||
label,
|
||||
...props
|
||||
}: IInputCheckboxProps & JSX.HTMLAttributes<HTMLInputElement>) {
|
||||
return (
|
||||
<label class="ht-input-checkbox">
|
||||
{label}
|
||||
<input type="radio" {...props} />
|
||||
<span></span>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
export function InputSelect({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLSelectElement>) {
|
||||
return (
|
||||
<select className={"ht-inp " + className} {...props}>
|
||||
{children}
|
||||
</select>
|
||||
);
|
||||
}
|
27
src/List.tsx
Normal file
27
src/List.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { h, JSX } from "preact";
|
||||
|
||||
export interface IListProps {
|
||||
clickable?: boolean;
|
||||
divider?: boolean;
|
||||
}
|
||||
|
||||
export default function List({
|
||||
clickable,
|
||||
divider,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLUListElement> & IListProps) {
|
||||
let cl = "ht-list ";
|
||||
if (clickable) cl += "ht-list-clickable ";
|
||||
|
||||
if (divider) cl += "ht-list-divider ";
|
||||
|
||||
cl += className;
|
||||
|
||||
return (
|
||||
<ul className={className} {...props}>
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
}
|
53
src/Modal.tsx
Normal file
53
src/Modal.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { h, JSX } from "preact";
|
||||
|
||||
export function Modal({
|
||||
hidden,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLDivElement> & { hidden?: boolean }) {
|
||||
return (
|
||||
<div
|
||||
className={"ht-modal " + className + (hidden ? "ht-modal-hidden" : "")}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ModalTitle({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div className={"ht-modal-title " + className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ModalContent({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div className={"ht-modal-content " + className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ModalActions({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div className={"ht-modal-action " + className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
13
src/Table.tsx
Normal file
13
src/Table.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import { h, JSX } from "preact";
|
||||
|
||||
export default function Table({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div className={"ht-table " + className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
106
src/Theme.tsx
Normal file
106
src/Theme.tsx
Normal file
@ -0,0 +1,106 @@
|
||||
import { h } from "preact";
|
||||
import { useEffect, useState, useMemo } from "preact/hooks";
|
||||
|
||||
export enum ThemeModes {
|
||||
AUTO,
|
||||
LIGHT,
|
||||
DARK
|
||||
}
|
||||
|
||||
export interface IThemeProps {
|
||||
mode: ThemeModes;
|
||||
children: any;
|
||||
|
||||
primary?: string;
|
||||
onPrimary?: string;
|
||||
secondary?: string;
|
||||
onSecondary?: string;
|
||||
error?: string;
|
||||
onError?: string;
|
||||
success?: string;
|
||||
onSuccess?: string;
|
||||
}
|
||||
|
||||
const modeMediaQuery = window.matchMedia("prefers-color-scheme: dark");
|
||||
|
||||
export default function Theme({ mode, children, ...colors }: IThemeProps) {
|
||||
const [isDark, setIsDark] = useState(
|
||||
mode === ThemeModes.AUTO
|
||||
? modeMediaQuery.matches
|
||||
: mode === ThemeModes.DARK
|
||||
);
|
||||
useEffect(() => {
|
||||
if (mode === ThemeModes.AUTO) {
|
||||
const listener = (ev: MediaQueryListEvent) => {
|
||||
setIsDark(ev.matches);
|
||||
};
|
||||
modeMediaQuery.addListener(listener);
|
||||
|
||||
setIsDark(modeMediaQuery.matches);
|
||||
|
||||
return modeMediaQuery.removeListener(listener);
|
||||
}
|
||||
}, [mode]);
|
||||
|
||||
const style = useMemo(() => {
|
||||
let style = "";
|
||||
const getRGB = (color: string) => {
|
||||
const cv = document.createElement("canvas");
|
||||
cv.width = 10;
|
||||
cv.height = 10;
|
||||
|
||||
const ctx = cv.getContext("2d");
|
||||
ctx.rect(0, 0, 1, 1);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
|
||||
const [r, g, b] = ctx.getImageData(0, 0, 10, 10).data;
|
||||
|
||||
return [r, g, b];
|
||||
};
|
||||
|
||||
const add = (name: string, value: string) =>
|
||||
(style += `--${name}: ${value};`);
|
||||
|
||||
if (colors.primary) {
|
||||
add("primary:", colors.primary);
|
||||
add("primary-rgb", getRGB(colors.primary).join(", "));
|
||||
}
|
||||
if (colors.onPrimary) add("on-primary:", colors.onPrimary);
|
||||
|
||||
if (colors.secondary) {
|
||||
add("secondary:", colors.secondary);
|
||||
add("secondary-rgb", getRGB(colors.secondary).join(", "));
|
||||
}
|
||||
if (colors.onSecondary) add("on-secondary:", colors.onSecondary);
|
||||
|
||||
if (colors.error) {
|
||||
add("error:", colors.error);
|
||||
add("error-rgb", getRGB(colors.error).join(", "));
|
||||
}
|
||||
if (colors.onError) add("on-error:", colors.onError);
|
||||
|
||||
if (colors.success) {
|
||||
add("success:", colors.success);
|
||||
add("success-rgb", getRGB(colors.success).join(", "));
|
||||
}
|
||||
if (colors.onSuccess) add("on-success:", colors.onSuccess);
|
||||
|
||||
return style;
|
||||
}, [
|
||||
colors.primary,
|
||||
colors.secondary,
|
||||
colors.error,
|
||||
colors.success,
|
||||
colors.onPrimary,
|
||||
colors.onSecondary,
|
||||
colors.onError,
|
||||
colors.onSuccess
|
||||
]);
|
||||
|
||||
return (
|
||||
<div class={isDark ? "dark-theme" : "light-theme"} style={style}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
39
src/index.ts
Normal file
39
src/index.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import "@hibas123/theme/out/pref.css";
|
||||
|
||||
import Theme, { IThemeProps, ThemeModes } from "./Theme";
|
||||
import Container from "./Container";
|
||||
import Button, { ButtonFormats, IButtonProps } from "./Button";
|
||||
import Fab from "./Fab";
|
||||
import Card from "./Card";
|
||||
import Header from "./Header";
|
||||
import IconButton from "./IconButton";
|
||||
import List from "./List";
|
||||
export { Modal, ModalActions, ModalContent, ModalTitle } from "./Modal";
|
||||
import Table from "./Table";
|
||||
|
||||
export {
|
||||
IInputCheckboxProps,
|
||||
IInputRadioProps,
|
||||
Input,
|
||||
InputCheckbox,
|
||||
InputGroup,
|
||||
InputRadio,
|
||||
InputSelect,
|
||||
TextArea
|
||||
} from "./Input";
|
||||
|
||||
export {
|
||||
Theme,
|
||||
IThemeProps,
|
||||
ThemeModes,
|
||||
Container,
|
||||
Button,
|
||||
ButtonFormats,
|
||||
IButtonProps,
|
||||
Fab,
|
||||
Card,
|
||||
IconButton,
|
||||
Header,
|
||||
List,
|
||||
Table
|
||||
};
|
13
tsconfig.json
Normal file
13
tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"target": "ES2019",
|
||||
"jsx": "react",
|
||||
"jsxFactory": "h",
|
||||
"outDir": "out/",
|
||||
"sourceMap": true,
|
||||
"declaration": true
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"]
|
||||
}
|
Loading…
Reference in New Issue
Block a user