elbe-ui 0.2.26 → 0.2.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bit/bit.js +83 -0
- package/dist/bit/ctrl_bit.js +89 -0
- package/dist/elbe.css +621 -0
- package/dist/elbe.css.map +1 -0
- package/dist/index.d.ts +1549 -17
- package/dist/index.js +64 -18577
- package/dist/service/s_api.js +89 -0
- package/dist/ui/components/badge.d.ts +5 -5
- package/dist/ui/components/badge.js +53 -0
- package/dist/ui/components/base/box.d.ts +2564 -0
- package/dist/ui/components/base/box.js +30 -0
- package/dist/ui/components/base/card.d.ts +14 -0
- package/dist/ui/components/base/card.js +11 -0
- package/dist/ui/components/base/padded.js +28 -0
- package/dist/ui/components/button/button.d.ts +21 -0
- package/dist/ui/components/button/button.js +27 -0
- package/dist/ui/components/button/choose_button.d.ts +14 -0
- package/dist/ui/components/button/choose_button.js +11 -0
- package/dist/ui/components/button/icon_button.d.ts +17 -0
- package/dist/ui/components/button/icon_button.js +31 -0
- package/dist/ui/components/button/toggle_button.d.ts +10 -0
- package/dist/ui/components/button/toggle_button.js +11 -0
- package/dist/ui/components/dialog.js +14 -0
- package/dist/ui/components/error_view.js +26 -0
- package/dist/ui/components/input/checkbox.d.ts +1 -1
- package/dist/ui/components/input/checkbox.js +12 -0
- package/dist/ui/components/input/input_field.d.ts +1 -1
- package/dist/ui/components/input/input_field.js +31 -0
- package/dist/ui/components/input/range.d.ts +1 -1
- package/dist/ui/components/input/range.js +14 -0
- package/dist/ui/components/input/select.d.ts +1 -1
- package/dist/ui/components/input/select.js +8 -0
- package/dist/ui/components/input/text_area.d.ts +1 -1
- package/dist/ui/components/input/text_area.js +13 -0
- package/dist/ui/components/{flex.d.ts → layout/flex.d.ts} +1 -1
- package/dist/ui/components/layout/flex.js +23 -0
- package/dist/ui/components/{scaffold.d.ts → layout/scaffold.d.ts} +7 -3
- package/dist/ui/components/layout/scaffold.js +44 -0
- package/dist/ui/components/layout/scroll.d.ts +18 -0
- package/dist/ui/components/layout/scroll.js +20 -0
- package/dist/ui/components/layout/spaced.js +7 -0
- package/dist/ui/components/spinner.d.ts +10 -2
- package/dist/ui/components/spinner.js +48 -0
- package/dist/ui/components/text.d.ts +5 -5
- package/dist/ui/components/text.js +42 -0
- package/dist/ui/theme/color_theme.d.ts +2 -0
- package/dist/ui/theme/color_theme.js +63 -0
- package/dist/ui/theme/colors.d.ts +142 -0
- package/dist/ui/theme/colors.js +317 -0
- package/dist/ui/theme/geometry_theme.d.ts +16 -0
- package/dist/ui/theme/geometry_theme.js +38 -0
- package/dist/ui/theme/theme.d.ts +28 -0
- package/dist/ui/theme/theme.js +49 -0
- package/dist/ui/theme/type_theme.d.ts +38 -0
- package/dist/ui/theme/type_theme.js +98 -0
- package/dist/ui/util/confirm_dialog.js +46 -0
- package/dist/ui/util/error_view.js +8 -0
- package/dist/ui/util/toast.js +17 -0
- package/dist/ui/util/util.d.ts +2 -0
- package/dist/ui/util/util.js +39 -0
- package/package.json +14 -15
- package/dist/ui/color_theme.d.ts +0 -5
- package/dist/ui/components/box.d.ts +0 -1027
- package/dist/ui/components/button.d.ts +0 -23
- package/dist/ui/components/card.d.ts +0 -14
- package/dist/ui/components/icon_button.d.ts +0 -19
- package/dist/ui/components/toggle_button.d.ts +0 -12
- package/elbe.scss +0 -100
- package/src/bit/bit.tsx +0 -128
- package/src/bit/ctrl_bit.tsx +0 -112
- package/src/index.tsx +0 -29
- package/src/service/s_api.ts +0 -102
- package/src/ui/color_theme.ts +0 -24
- package/src/ui/components/badge.tsx +0 -78
- package/src/ui/components/box.tsx +0 -49
- package/src/ui/components/button.tsx +0 -61
- package/src/ui/components/card.tsx +0 -45
- package/src/ui/components/dialog.tsx +0 -51
- package/src/ui/components/error_view.tsx +0 -72
- package/src/ui/components/flex.tsx +0 -64
- package/src/ui/components/icon_button.tsx +0 -56
- package/src/ui/components/input/checkbox.tsx +0 -32
- package/src/ui/components/input/input_field.tsx +0 -57
- package/src/ui/components/input/range.tsx +0 -37
- package/src/ui/components/input/select.tsx +0 -29
- package/src/ui/components/input/text_area.tsx +0 -45
- package/src/ui/components/padded.tsx +0 -62
- package/src/ui/components/scaffold.tsx +0 -79
- package/src/ui/components/spinner.tsx +0 -11
- package/src/ui/components/text.tsx +0 -78
- package/src/ui/components/toggle_button.tsx +0 -52
- package/src/ui/components/util.tsx +0 -3
- package/src/ui/util/confirm_dialog.ts +0 -53
- package/src/ui/util/error_view.tsx +0 -16
- package/src/ui/util/toast.ts +0 -14
- package/src/ui/util/util.ts +0 -36
- package/style/color_style.scss +0 -149
- package/style/components.scss +0 -476
- package/style/root.scss +0 -50
- package/style/type_style.scss +0 -22
- /package/dist/ui/components/{padded.d.ts → base/padded.d.ts} +0 -0
- /package/dist/ui/components/{util.d.ts → layout/spaced.d.ts} +0 -0
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import React from "preact/compat";
|
|
2
|
-
import type { ElbeColorManners, ElbeColorStyles } from "../color_theme";
|
|
3
|
-
import { _ElbeErr } from "../util/error_view";
|
|
4
|
-
import { applyProps, type ElbeProps } from "./box";
|
|
5
|
-
import type { IconChild } from "./icon_button";
|
|
6
|
-
|
|
7
|
-
export type ButtonProps = ElbeProps & {
|
|
8
|
-
colorStyle?: ElbeColorStyles;
|
|
9
|
-
onTap?: () => void;
|
|
10
|
-
} & (
|
|
11
|
-
| { icon?: IconChild; label: string }
|
|
12
|
-
| {
|
|
13
|
-
icon: IconChild;
|
|
14
|
-
label?: string;
|
|
15
|
-
}
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
export class Button extends React.Component<
|
|
19
|
-
ButtonProps & {
|
|
20
|
-
colorManner: ElbeColorManners;
|
|
21
|
-
}
|
|
22
|
-
> {
|
|
23
|
-
static major = (p: ButtonProps) => _btn(p, "major");
|
|
24
|
-
static minor = (p: ButtonProps) => _btn(p, "minor");
|
|
25
|
-
static action = (p: ButtonProps) => _btn(p, "action");
|
|
26
|
-
static integrated = (p: ButtonProps) => _btn(p, "integrated");
|
|
27
|
-
|
|
28
|
-
render() {
|
|
29
|
-
return _btn(this.props, this.props.colorManner);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function _btn(
|
|
34
|
-
{ colorStyle, onTap, icon, label, ...elbe }: ButtonProps,
|
|
35
|
-
colorManner: ElbeColorManners
|
|
36
|
-
) {
|
|
37
|
-
return label || icon ? (
|
|
38
|
-
<button
|
|
39
|
-
{...applyProps(
|
|
40
|
-
elbe,
|
|
41
|
-
[
|
|
42
|
-
"row",
|
|
43
|
-
"main-center",
|
|
44
|
-
"gap-half",
|
|
45
|
-
colorStyle ?? "accent",
|
|
46
|
-
colorManner,
|
|
47
|
-
!onTap && "disabled",
|
|
48
|
-
],
|
|
49
|
-
{
|
|
50
|
-
border: "none",
|
|
51
|
-
}
|
|
52
|
-
)}
|
|
53
|
-
onClick={() => onTap && onTap()}
|
|
54
|
-
>
|
|
55
|
-
{typeof icon === "function" ? icon({}) : icon}
|
|
56
|
-
{label && <span>{label}</span>}
|
|
57
|
-
</button>
|
|
58
|
-
) : (
|
|
59
|
-
_ElbeErr("Button requires either an icon or a message")
|
|
60
|
-
);
|
|
61
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ElbeColorManners,
|
|
3
|
-
ElbeColorModes,
|
|
4
|
-
ElbeColorStyles,
|
|
5
|
-
ElbeColorThemes,
|
|
6
|
-
} from "../color_theme";
|
|
7
|
-
import type { ElbeChildren } from "../util/util";
|
|
8
|
-
import { applyProps, type ElbeProps } from "./box";
|
|
9
|
-
|
|
10
|
-
export function Card({
|
|
11
|
-
mode,
|
|
12
|
-
colorScheme = "primary",
|
|
13
|
-
colorStyle,
|
|
14
|
-
colorManner,
|
|
15
|
-
padding = 1,
|
|
16
|
-
margin = 0,
|
|
17
|
-
onTap,
|
|
18
|
-
onLongTap,
|
|
19
|
-
children,
|
|
20
|
-
...elbe
|
|
21
|
-
}: {
|
|
22
|
-
mode?: ElbeColorModes;
|
|
23
|
-
colorScheme?: ElbeColorThemes;
|
|
24
|
-
colorStyle?: ElbeColorStyles;
|
|
25
|
-
colorManner?: ElbeColorManners;
|
|
26
|
-
padding?: number;
|
|
27
|
-
margin?: number;
|
|
28
|
-
onTap?: () => void;
|
|
29
|
-
onLongTap?: () => void;
|
|
30
|
-
children: ElbeChildren;
|
|
31
|
-
} & ElbeProps) {
|
|
32
|
-
return (
|
|
33
|
-
<div
|
|
34
|
-
{...applyProps(
|
|
35
|
-
elbe,
|
|
36
|
-
["card", colorScheme, colorStyle, colorManner, mode],
|
|
37
|
-
{ padding: `${padding}rem`, margin: `${margin}rem` }
|
|
38
|
-
)}
|
|
39
|
-
onClick={onTap}
|
|
40
|
-
onContextMenu={onLongTap}
|
|
41
|
-
>
|
|
42
|
-
{children}
|
|
43
|
-
</div>
|
|
44
|
-
);
|
|
45
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { X } from "lucide-react";
|
|
2
|
-
import type { ElbeChildren } from "../util/util";
|
|
3
|
-
import { Spaced } from "./util";
|
|
4
|
-
|
|
5
|
-
export function ElbeDialog({
|
|
6
|
-
title,
|
|
7
|
-
open,
|
|
8
|
-
onClose,
|
|
9
|
-
children,
|
|
10
|
-
_style,
|
|
11
|
-
}: {
|
|
12
|
-
_style?: string;
|
|
13
|
-
title: string;
|
|
14
|
-
open: boolean;
|
|
15
|
-
onClose: () => void;
|
|
16
|
-
children: ElbeChildren;
|
|
17
|
-
}) {
|
|
18
|
-
return (
|
|
19
|
-
<dialog
|
|
20
|
-
onClick={(e) => e.stopPropagation()}
|
|
21
|
-
open={open}
|
|
22
|
-
style={"text-align: start" + (_style ?? "")}
|
|
23
|
-
>
|
|
24
|
-
<div
|
|
25
|
-
class=" card plain-opaque padding-none"
|
|
26
|
-
style="max-width: 40rem; min-width: 10rem"
|
|
27
|
-
>
|
|
28
|
-
<div class="row cross-start padded">
|
|
29
|
-
<div class="flex-1 b" style="margin-top: 0.6rem; font-size: 1.2rem">
|
|
30
|
-
{title}
|
|
31
|
-
</div>
|
|
32
|
-
<button
|
|
33
|
-
class="integrated"
|
|
34
|
-
style="width: 3rem"
|
|
35
|
-
onClick={(e) => {
|
|
36
|
-
e.stopPropagation();
|
|
37
|
-
e.preventDefault();
|
|
38
|
-
onClose();
|
|
39
|
-
}}
|
|
40
|
-
>
|
|
41
|
-
<X />
|
|
42
|
-
</button>
|
|
43
|
-
</div>
|
|
44
|
-
<Spaced amount={0.5} />
|
|
45
|
-
<div class="padded" style="max-height: 80vh; overflow: auto">
|
|
46
|
-
{children}
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
</dialog>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { useSignal } from "@preact/signals";
|
|
2
|
-
import { route } from "preact-router";
|
|
3
|
-
import { ElbeDialog, Icons } from "../..";
|
|
4
|
-
import { ifApiError, type ApiError } from "../../service/s_api";
|
|
5
|
-
|
|
6
|
-
export function ErrorView({
|
|
7
|
-
error,
|
|
8
|
-
retry,
|
|
9
|
-
debug,
|
|
10
|
-
}: {
|
|
11
|
-
error: any;
|
|
12
|
-
retry?: () => any;
|
|
13
|
-
debug?: boolean;
|
|
14
|
-
}) {
|
|
15
|
-
const apiError: ApiError = ifApiError(error) ?? {
|
|
16
|
-
code: 0,
|
|
17
|
-
message: "unknown error",
|
|
18
|
-
data: error,
|
|
19
|
-
};
|
|
20
|
-
return !debug ? (
|
|
21
|
-
<PrettyErrorView apiError={apiError} retry={retry} />
|
|
22
|
-
) : (
|
|
23
|
-
<div class="column padded card inverse cross-stretch">
|
|
24
|
-
<h3 style="margin: 0">ERROR: {apiError.code}</h3>
|
|
25
|
-
<p>{apiError.message}</p>
|
|
26
|
-
<pre>{JSON.stringify(apiError.data, null, 2)}</pre>
|
|
27
|
-
</div>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function PrettyErrorView({
|
|
32
|
-
apiError,
|
|
33
|
-
retry,
|
|
34
|
-
labels = {
|
|
35
|
-
retry: "retry",
|
|
36
|
-
home: "go home",
|
|
37
|
-
details: "error details",
|
|
38
|
-
},
|
|
39
|
-
}: {
|
|
40
|
-
apiError: ApiError;
|
|
41
|
-
retry?: () => any;
|
|
42
|
-
labels?: { retry?: string; home?: string; details?: string };
|
|
43
|
-
}) {
|
|
44
|
-
const openSig = useSignal(false);
|
|
45
|
-
return (
|
|
46
|
-
<div class="column padded cross-center" style="margin: 1rem 0">
|
|
47
|
-
<Icons.OctagonAlert />
|
|
48
|
-
<h3 style="margin: 0">{apiError.code}</h3>
|
|
49
|
-
<span class="pointer" onClick={() => (openSig.value = true)}>
|
|
50
|
-
{apiError.message}
|
|
51
|
-
</span>
|
|
52
|
-
{retry && (
|
|
53
|
-
<button class="action" onClick={() => retry()}>
|
|
54
|
-
<Icons.RotateCcw /> {labels.retry ?? "retry"}
|
|
55
|
-
</button>
|
|
56
|
-
)}
|
|
57
|
-
{apiError.code === 404 && (
|
|
58
|
-
<button class="action" onClick={() => route("/")}>
|
|
59
|
-
<Icons.House />
|
|
60
|
-
{labels.home ?? "go home"}
|
|
61
|
-
</button>
|
|
62
|
-
)}
|
|
63
|
-
<ElbeDialog
|
|
64
|
-
title={labels.details ?? "error details"}
|
|
65
|
-
open={openSig.value}
|
|
66
|
-
onClose={() => (openSig.value = false)}
|
|
67
|
-
>
|
|
68
|
-
<pre class="card inverse">{JSON.stringify(apiError.data, null, 2)}</pre>
|
|
69
|
-
</ElbeDialog>
|
|
70
|
-
</div>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { applyProps, type ElbeProps } from "./box";
|
|
2
|
-
|
|
3
|
-
export type FlexProps = {
|
|
4
|
-
children: any;
|
|
5
|
-
gap?: number;
|
|
6
|
-
// shorthand for cross="stretch"
|
|
7
|
-
stretch?: boolean;
|
|
8
|
-
main?:
|
|
9
|
-
| "start"
|
|
10
|
-
| "center"
|
|
11
|
-
| "end"
|
|
12
|
-
| "stretch"
|
|
13
|
-
| "space-between"
|
|
14
|
-
| "space-around"
|
|
15
|
-
| "space-evenly";
|
|
16
|
-
cross?:
|
|
17
|
-
| "start"
|
|
18
|
-
| "center"
|
|
19
|
-
| "end"
|
|
20
|
-
| "stretch"
|
|
21
|
-
| "space-between"
|
|
22
|
-
| "space-around"
|
|
23
|
-
| "space-evenly";
|
|
24
|
-
} & ElbeProps;
|
|
25
|
-
|
|
26
|
-
export function FlexSpace({}) {
|
|
27
|
-
return <div style="flex:1"></div>;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function Column({
|
|
31
|
-
gap = 1,
|
|
32
|
-
main = "start",
|
|
33
|
-
cross = "stretch",
|
|
34
|
-
stretch = false,
|
|
35
|
-
children,
|
|
36
|
-
...p
|
|
37
|
-
}: FlexProps) {
|
|
38
|
-
return _Flex(false, { gap, main, cross, stretch, children }, p);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function Row({
|
|
42
|
-
gap = 1,
|
|
43
|
-
main = "start",
|
|
44
|
-
cross,
|
|
45
|
-
stretch = false,
|
|
46
|
-
children,
|
|
47
|
-
...p
|
|
48
|
-
}: FlexProps) {
|
|
49
|
-
return _Flex(true, { gap, main, cross, stretch, children }, p);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function _Flex(row: boolean, p: FlexProps, elbe: ElbeProps) {
|
|
53
|
-
return (
|
|
54
|
-
<div
|
|
55
|
-
{...applyProps(elbe, row ? "row" : "column", {
|
|
56
|
-
justifyContent: p.main,
|
|
57
|
-
alignItems: p.cross || (p.stretch ? "stretch" : "center"),
|
|
58
|
-
gap: `${p.gap}rem`,
|
|
59
|
-
})}
|
|
60
|
-
>
|
|
61
|
-
{p.children}
|
|
62
|
-
</div>
|
|
63
|
-
);
|
|
64
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import React from "preact/compat";
|
|
2
|
-
import type { ElbeColorManners, ElbeColorStyles } from "../color_theme";
|
|
3
|
-
import type { ElbeChild } from "../util/util";
|
|
4
|
-
import { applyProps, type ElbeProps } from "./box";
|
|
5
|
-
|
|
6
|
-
export type IconChild = ElbeChild | ((_: any) => ElbeChild);
|
|
7
|
-
|
|
8
|
-
export type IconButtonProps = {
|
|
9
|
-
icon?: IconChild;
|
|
10
|
-
colorStyle?: ElbeColorStyles;
|
|
11
|
-
|
|
12
|
-
onTap?: () => void;
|
|
13
|
-
} & ElbeProps;
|
|
14
|
-
|
|
15
|
-
export class IconButton extends React.Component<
|
|
16
|
-
IconButtonProps & { colorManner?: ElbeColorManners }
|
|
17
|
-
> {
|
|
18
|
-
static major = (p: IconButtonProps) => _btn(p, "major");
|
|
19
|
-
static minor = (p: IconButtonProps) => _btn(p, "minor");
|
|
20
|
-
static action = (p: IconButtonProps) => _btn(p, "action");
|
|
21
|
-
static integrated = (p: IconButtonProps) => _btn(p, "integrated");
|
|
22
|
-
|
|
23
|
-
render() {
|
|
24
|
-
return _btn(this.props, this.props.colorManner);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function _btn(
|
|
29
|
-
{ icon, onTap, ...elbe }: IconButtonProps,
|
|
30
|
-
colorManner: ElbeColorManners = "major"
|
|
31
|
-
) {
|
|
32
|
-
return (
|
|
33
|
-
<button
|
|
34
|
-
{...applyProps(
|
|
35
|
-
elbe,
|
|
36
|
-
[
|
|
37
|
-
"row",
|
|
38
|
-
"main-center",
|
|
39
|
-
"gap-half",
|
|
40
|
-
elbe.colorStyle,
|
|
41
|
-
colorManner,
|
|
42
|
-
!onTap && "disabled",
|
|
43
|
-
],
|
|
44
|
-
{
|
|
45
|
-
border: "none",
|
|
46
|
-
borderRadius: "3rem",
|
|
47
|
-
height: "3rem",
|
|
48
|
-
width: "3rem",
|
|
49
|
-
}
|
|
50
|
-
)}
|
|
51
|
-
onClick={() => onTap && onTap()}
|
|
52
|
-
>
|
|
53
|
-
{typeof icon === "function" ? icon({}) : icon}
|
|
54
|
-
</button>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { applyProps, type ElbeProps } from "../box";
|
|
2
|
-
|
|
3
|
-
export function Checkbox({
|
|
4
|
-
value,
|
|
5
|
-
label,
|
|
6
|
-
onChange,
|
|
7
|
-
...elbe
|
|
8
|
-
}: {
|
|
9
|
-
value: boolean;
|
|
10
|
-
label?: string;
|
|
11
|
-
onChange?: ((checked: boolean) => void) | null;
|
|
12
|
-
} & ElbeProps) {
|
|
13
|
-
return (
|
|
14
|
-
<div
|
|
15
|
-
class={`row ${onChange ? "" : "disabled"}`}
|
|
16
|
-
style={{
|
|
17
|
-
gap: ".75rem",
|
|
18
|
-
filter: onChange ? "" : "grayscale(1)",
|
|
19
|
-
opacity: onChange ? "" : "0.5",
|
|
20
|
-
}}
|
|
21
|
-
>
|
|
22
|
-
<input
|
|
23
|
-
type="checkbox"
|
|
24
|
-
{...applyProps(elbe)}
|
|
25
|
-
disabled={!onChange}
|
|
26
|
-
checked={value}
|
|
27
|
-
onChange={(e) => onChange?.(e.currentTarget.checked)}
|
|
28
|
-
/>
|
|
29
|
-
{label && <div style="margin-top: -.25rem">{label}</div>}
|
|
30
|
-
</div>
|
|
31
|
-
);
|
|
32
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import React from "preact/compat";
|
|
2
|
-
import { applyProps, type ElbeProps } from "../box";
|
|
3
|
-
import { _TextArea } from "./text_area";
|
|
4
|
-
|
|
5
|
-
export type InputFieldProps = {
|
|
6
|
-
label?: string;
|
|
7
|
-
hint: string;
|
|
8
|
-
readonly?: boolean;
|
|
9
|
-
value: string | number;
|
|
10
|
-
onInput?: (value: string) => void;
|
|
11
|
-
} & ElbeProps;
|
|
12
|
-
|
|
13
|
-
export class Field extends React.Component<
|
|
14
|
-
InputFieldProps & {
|
|
15
|
-
type?: "text" | "number" | "password" | "date" | "time" | "email";
|
|
16
|
-
}
|
|
17
|
-
> {
|
|
18
|
-
static text = (p: InputFieldProps) => <Field {...p} type="text" />;
|
|
19
|
-
static number = (p: InputFieldProps) => <Field {...p} type="number" />;
|
|
20
|
-
static password = (p: InputFieldProps) => <Field {...p} type="password" />;
|
|
21
|
-
static date = (p: InputFieldProps) => <Field {...p} type="date" />;
|
|
22
|
-
static time = (p: InputFieldProps) => <Field {...p} type="time" />;
|
|
23
|
-
static email = (p: InputFieldProps) => <Field {...p} type="email" />;
|
|
24
|
-
|
|
25
|
-
static multiLine = _TextArea;
|
|
26
|
-
|
|
27
|
-
render() {
|
|
28
|
-
const { label, hint, readonly, type, value, onInput, ...elbe } = this.props;
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<div
|
|
32
|
-
style={{
|
|
33
|
-
width: "12rem !important",
|
|
34
|
-
display: "flex",
|
|
35
|
-
flexDirection: "column",
|
|
36
|
-
alignItems: "stretch",
|
|
37
|
-
}}
|
|
38
|
-
data-tooltip={this.props?.tooltip}
|
|
39
|
-
>
|
|
40
|
-
<input
|
|
41
|
-
type={this.props.type}
|
|
42
|
-
{...applyProps(this.props, null, {
|
|
43
|
-
width: "100%",
|
|
44
|
-
})}
|
|
45
|
-
size={5}
|
|
46
|
-
label={this.props.label}
|
|
47
|
-
placeholder={this.props.hint}
|
|
48
|
-
value={this.props.value}
|
|
49
|
-
onInput={(e) =>
|
|
50
|
-
this.props.onInput && this.props.onInput(e.currentTarget.value)
|
|
51
|
-
}
|
|
52
|
-
readonly={this.props.readonly}
|
|
53
|
-
/>
|
|
54
|
-
</div>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { _ElbeErr } from "../../util/error_view";
|
|
2
|
-
import { applyProps, type ElbeProps } from "../box";
|
|
3
|
-
|
|
4
|
-
export function Range({
|
|
5
|
-
value,
|
|
6
|
-
onChange,
|
|
7
|
-
min = 0,
|
|
8
|
-
max = 100,
|
|
9
|
-
step = 1,
|
|
10
|
-
...elbe
|
|
11
|
-
}: {
|
|
12
|
-
value: number;
|
|
13
|
-
min?: number;
|
|
14
|
-
step?: number;
|
|
15
|
-
max?: number;
|
|
16
|
-
onChange?: ((value: number) => void) | null;
|
|
17
|
-
} & ElbeProps) {
|
|
18
|
-
return min > max ? (
|
|
19
|
-
_ElbeErr("Range: max is smaller than min")
|
|
20
|
-
) : (
|
|
21
|
-
<input
|
|
22
|
-
type="range"
|
|
23
|
-
{...applyProps(elbe, null, {
|
|
24
|
-
filter: onChange ? "" : "grayscale(1)",
|
|
25
|
-
opacity: onChange ? "" : "0.5",
|
|
26
|
-
cursor: onChange ? "pointer" : "not-allowed",
|
|
27
|
-
width: "100%",
|
|
28
|
-
})}
|
|
29
|
-
min={min}
|
|
30
|
-
max={max}
|
|
31
|
-
step={step}
|
|
32
|
-
disabled={!onChange}
|
|
33
|
-
value={value}
|
|
34
|
-
onInput={(e) => onChange?.(Number(e.currentTarget.value))}
|
|
35
|
-
/>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { applyProps, type ElbeProps } from "../box";
|
|
2
|
-
|
|
3
|
-
export function Select({
|
|
4
|
-
options,
|
|
5
|
-
value,
|
|
6
|
-
label,
|
|
7
|
-
onChange,
|
|
8
|
-
...elbe
|
|
9
|
-
}: {
|
|
10
|
-
options: { key: string; label: string }[];
|
|
11
|
-
value?: string;
|
|
12
|
-
label?: string;
|
|
13
|
-
onChange: (value: string) => any;
|
|
14
|
-
} & ElbeProps) {
|
|
15
|
-
return (
|
|
16
|
-
<select
|
|
17
|
-
{...applyProps(elbe)}
|
|
18
|
-
value={value}
|
|
19
|
-
label={label}
|
|
20
|
-
onChange={(e) => onChange(e.currentTarget.value)}
|
|
21
|
-
>
|
|
22
|
-
{options.map(({ key, label }) => (
|
|
23
|
-
<option key={key} value={key}>
|
|
24
|
-
{label}
|
|
25
|
-
</option>
|
|
26
|
-
))}
|
|
27
|
-
</select>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { applyProps, type ElbeProps } from "../box";
|
|
2
|
-
|
|
3
|
-
export function _TextArea({
|
|
4
|
-
label,
|
|
5
|
-
hint,
|
|
6
|
-
readonly,
|
|
7
|
-
rows = 4,
|
|
8
|
-
maxLength,
|
|
9
|
-
value,
|
|
10
|
-
onInput,
|
|
11
|
-
...elbe
|
|
12
|
-
}: {
|
|
13
|
-
label?: string;
|
|
14
|
-
hint: string;
|
|
15
|
-
rows?: number;
|
|
16
|
-
maxLength?: number;
|
|
17
|
-
readonly?: boolean;
|
|
18
|
-
value: string | number;
|
|
19
|
-
onInput?: (value: string) => void;
|
|
20
|
-
} & ElbeProps) {
|
|
21
|
-
return (
|
|
22
|
-
<div
|
|
23
|
-
style={{
|
|
24
|
-
width: "12rem !important",
|
|
25
|
-
display: "flex",
|
|
26
|
-
flexDirection: "column",
|
|
27
|
-
alignItems: "stretch",
|
|
28
|
-
}}
|
|
29
|
-
data-tooltip={elbe.tooltip}
|
|
30
|
-
>
|
|
31
|
-
<textarea
|
|
32
|
-
{...applyProps(elbe, null, { width: "100%" })}
|
|
33
|
-
label={label}
|
|
34
|
-
size={5}
|
|
35
|
-
cols={5}
|
|
36
|
-
placeholder={hint}
|
|
37
|
-
rows={rows}
|
|
38
|
-
maxLength={maxLength}
|
|
39
|
-
value={value}
|
|
40
|
-
onInput={(e) => onInput && onInput(e.currentTarget.value)}
|
|
41
|
-
readonly={readonly}
|
|
42
|
-
/>
|
|
43
|
-
</div>
|
|
44
|
-
);
|
|
45
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import React from "preact/compat";
|
|
2
|
-
|
|
3
|
-
export type PaddedProps = {
|
|
4
|
-
children: any;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export class Padded extends React.Component<
|
|
8
|
-
PaddedProps & {
|
|
9
|
-
top: number;
|
|
10
|
-
right: number;
|
|
11
|
-
bottom: number;
|
|
12
|
-
left: number;
|
|
13
|
-
}
|
|
14
|
-
> {
|
|
15
|
-
constructor(
|
|
16
|
-
props: PaddedProps & {
|
|
17
|
-
top: number;
|
|
18
|
-
right: number;
|
|
19
|
-
bottom: number;
|
|
20
|
-
left: number;
|
|
21
|
-
}
|
|
22
|
-
) {
|
|
23
|
-
super(props);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
static all = ({ amount = 1, ...p }: PaddedProps & { amount: number }) => (
|
|
27
|
-
<Padded
|
|
28
|
-
{...{ ...p, top: amount, right: amount, bottom: amount, left: amount }}
|
|
29
|
-
/>
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
static symmetric = ({
|
|
33
|
-
vertical = 0,
|
|
34
|
-
horizontal = 0,
|
|
35
|
-
...p
|
|
36
|
-
}: PaddedProps & { vertical: number; horizontal: number }) => (
|
|
37
|
-
<Padded
|
|
38
|
-
{...{
|
|
39
|
-
...p,
|
|
40
|
-
top: vertical,
|
|
41
|
-
bottom: vertical,
|
|
42
|
-
left: horizontal,
|
|
43
|
-
right: horizontal,
|
|
44
|
-
}}
|
|
45
|
-
/>
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
render() {
|
|
49
|
-
return (
|
|
50
|
-
<div
|
|
51
|
-
style={{
|
|
52
|
-
paddingTop: `${this.props.top}rem`,
|
|
53
|
-
paddingRight: `${this.props.right}rem`,
|
|
54
|
-
paddingBottom: `${this.props.bottom}rem`,
|
|
55
|
-
paddingLeft: `${this.props.left}rem`,
|
|
56
|
-
}}
|
|
57
|
-
>
|
|
58
|
-
{this.props.children}
|
|
59
|
-
</div>
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "preact/compat";
|
|
2
|
-
import { Column, IconButton, Icons, Row, Text } from "../..";
|
|
3
|
-
|
|
4
|
-
type HeaderParams = {
|
|
5
|
-
title?: string;
|
|
6
|
-
back: null | "close" | "back";
|
|
7
|
-
actions?: any;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Header is a layout component that provides a header for a page.
|
|
12
|
-
* It is used to create a consistent header for pages.
|
|
13
|
-
* @param back - The back button type. If null, no back button is shown. If "close", a close button is shown. If "back", a back button is shown.
|
|
14
|
-
* @param title - The title of the page.
|
|
15
|
-
* @param actions - The actions to show on the right side of the header.
|
|
16
|
-
*/
|
|
17
|
-
export function Header({ back, title, actions }: HeaderParams) {
|
|
18
|
-
if (history.length == 0) back = null;
|
|
19
|
-
const goBack = () => history.go(-1);
|
|
20
|
-
|
|
21
|
-
const [isScrolledTop, setIsScrolled] = useState(false);
|
|
22
|
-
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
const _handle = () => setIsScrolled(window.scrollY > 0);
|
|
25
|
-
window.addEventListener("scroll", _handle);
|
|
26
|
-
return () => {
|
|
27
|
-
window.removeEventListener("scroll", _handle);
|
|
28
|
-
};
|
|
29
|
-
}, []);
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<div>
|
|
33
|
-
<div style="height: 4.5rem"></div>
|
|
34
|
-
<div
|
|
35
|
-
class="header"
|
|
36
|
-
style={isScrolledTop ? "" : "border-color: transparent"}
|
|
37
|
-
>
|
|
38
|
-
<div class="flex-1">
|
|
39
|
-
{back === "close" ? (
|
|
40
|
-
<IconButton.integrated icon={Icons.X} onTap={goBack} />
|
|
41
|
-
) : back === "back" ? (
|
|
42
|
-
<IconButton.integrated icon={Icons.ArrowLeft} onTap={goBack} />
|
|
43
|
-
) : null}
|
|
44
|
-
</div>
|
|
45
|
-
<Text.h4 v={title} />
|
|
46
|
-
<Row class="flex-1" gap={0.5} main="end">
|
|
47
|
-
{actions}
|
|
48
|
-
</Row>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Scaffold is a layout component that provides a header and a content area.
|
|
56
|
-
* It is used to create a consistent layout for pages.
|
|
57
|
-
*/
|
|
58
|
-
export function Scaffold({
|
|
59
|
-
children,
|
|
60
|
-
limited = false,
|
|
61
|
-
gap = 1,
|
|
62
|
-
...header
|
|
63
|
-
}: {
|
|
64
|
-
limited?: boolean;
|
|
65
|
-
children: any;
|
|
66
|
-
gap?: number;
|
|
67
|
-
} & HeaderParams) {
|
|
68
|
-
return (
|
|
69
|
-
<Column cross="stretch" gap={0}>
|
|
70
|
-
<Header {...header} />
|
|
71
|
-
|
|
72
|
-
<div class={`padded ${limited ? "base-limited" : ""}`}>
|
|
73
|
-
<Column cross="stretch" gap={gap ?? 1}>
|
|
74
|
-
{children}
|
|
75
|
-
</Column>
|
|
76
|
-
</div>
|
|
77
|
-
</Column>
|
|
78
|
-
);
|
|
79
|
-
}
|