First Commit

This commit is contained in:
Fabian Stamm 2020-03-29 16:05:39 +02:00
commit 3f63c202f6
17 changed files with 498 additions and 0 deletions

5
.editorconfig Normal file
View File

@ -0,0 +1,5 @@
[*]
indent_size = 3
indent_style = space
charset = utf-8
insert_final_newline = true

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
out/
node_modules/

24
package-lock.json generated Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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"]
}