elbe-ui 0.3.1 → 0.4.1
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/README.md +12 -0
- package/dist/elbe.css +57 -56
- package/dist/elbe.css.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +6 -3
- package/dist/ui/components/badge.d.ts +1 -1
- package/dist/ui/components/banner.d.ts +3 -2
- package/dist/ui/components/banner.js +13 -7
- package/dist/ui/components/base/box.d.ts +28 -27
- package/dist/ui/components/base/card.d.ts +6 -4
- package/dist/ui/components/base/card.js +6 -2
- package/dist/ui/components/base/roles.d.ts +1 -0
- package/dist/ui/components/base/roles.js +1 -0
- package/dist/ui/components/button/button.d.ts +1 -0
- package/dist/ui/components/button/button.js +12 -4
- package/dist/ui/components/button/choose_button.js +3 -2
- package/dist/ui/components/button/icon_button.d.ts +3 -0
- package/dist/ui/components/button/icon_button.js +9 -2
- package/dist/ui/components/button/toggle_button.js +7 -1
- package/dist/ui/components/dialog.d.ts +1 -1
- package/dist/ui/components/footer.js +1 -1
- package/dist/ui/components/input/checkbox.d.ts +2 -5
- package/dist/ui/components/input/checkbox.js +10 -19
- package/dist/ui/components/input/range.js +4 -1
- package/dist/ui/components/input/select.js +1 -1
- package/dist/ui/components/input/switch.d.ts +6 -2
- package/dist/ui/components/input/switch.js +25 -22
- package/dist/ui/components/input/text/input_field.d.ts +28 -0
- package/dist/ui/components/input/text/input_field.js +70 -0
- package/dist/ui/components/input/text/multi_line.d.ts +10 -0
- package/dist/ui/components/input/text/multi_line.js +19 -0
- package/dist/ui/components/input/text/single_line.d.ts +18 -0
- package/dist/ui/components/input/text/single_line.js +28 -0
- package/dist/ui/components/layout/app_base.d.ts +14 -0
- package/dist/ui/components/layout/app_base.js +30 -0
- package/dist/ui/components/layout/ctx_app_base.d.ts +16 -0
- package/dist/ui/components/layout/ctx_app_base.js +13 -0
- package/dist/ui/components/layout/flex.d.ts +4 -2
- package/dist/ui/components/layout/flex.js +13 -5
- package/dist/ui/components/layout/header.d.ts +18 -18
- package/dist/ui/components/layout/header.js +54 -48
- package/dist/ui/components/layout/menu.d.ts +12 -0
- package/dist/ui/components/layout/menu.js +59 -0
- package/dist/ui/components/layout/spaced.d.ts +4 -2
- package/dist/ui/components/layout/spaced.js +6 -2
- package/dist/ui/components/layout/toolbar.d.ts +7 -0
- package/dist/ui/components/layout/toolbar.js +71 -0
- package/dist/ui/components/progress_bar.js +7 -5
- package/dist/ui/components/spinner.js +4 -0
- package/dist/ui/components/text.d.ts +1 -1
- package/dist/ui/components/text.js +4 -4
- package/dist/ui/theme/color_theme.d.ts +1 -1
- package/dist/ui/theme/color_theme.js +63 -52
- package/dist/ui/theme/colors.d.ts +33 -13
- package/dist/ui/theme/colors.js +42 -15
- package/dist/ui/theme/geometry_theme.js +2 -4
- package/dist/ui/theme/seed.d.ts +18 -8
- package/dist/ui/theme/seed.js +4 -1
- package/dist/ui/theme/theme.d.ts +3 -5
- package/dist/ui/theme/theme.js +9 -12
- package/dist/ui/theme/theme_context.d.ts +18 -0
- package/dist/ui/theme/theme_context.js +26 -0
- package/dist/ui/theme/type_theme.js +5 -2
- package/dist/ui/util/ctx_toolbar.d.ts +8 -0
- package/dist/ui/util/ctx_toolbar.js +9 -0
- package/dist/ui/util/l10n/l10n.d.ts +35 -0
- package/dist/ui/util/l10n/l10n.js +68 -0
- package/dist/ui/util/single_key.d.ts +11 -0
- package/dist/ui/util/single_key.js +1 -0
- package/dist/ui/util/types.d.ts +9 -0
- package/dist/ui/util/types.js +1 -0
- package/dist/ui/util/util.d.ts +5 -3
- package/dist/ui/util/util.js +36 -1
- package/package.json +1 -1
- package/dist/ui/components/input/input_field.d.ts +0 -22
- package/dist/ui/components/input/input_field.js +0 -36
- package/dist/ui/components/input/text_area.d.ts +0 -10
- package/dist/ui/components/input/text_area.js +0 -22
- package/dist/ui/components/layout/scaffold.d.ts +0 -15
- package/dist/ui/components/layout/scaffold.js +0 -31
|
@@ -1,18 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ColorThemeSeed, PartialColorThemeSeed, ThemeColors } from "./seed";
|
|
2
|
+
export type ElbeColorContrasts = "normal" | "highvis";
|
|
2
3
|
export type ElbeColorModes = "light" | "dark";
|
|
3
4
|
export type ElbeColorSchemes = "primary" | "secondary" | "inverse";
|
|
4
5
|
export type ElbeAlertKinds = "success" | "warning" | "error" | "info";
|
|
5
6
|
export type ElbeColorKinds = ElbeAlertKinds | "plain" | "accent";
|
|
6
7
|
export type ElbeColorManners = "major" | "minor" | "flat" | "plain";
|
|
8
|
+
export declare const cContrasts: ElbeColorContrasts[];
|
|
7
9
|
export declare const cModes: ElbeColorModes[];
|
|
8
10
|
export declare const cSchemes: ElbeColorSchemes[];
|
|
9
11
|
export declare const cKinds: ElbeColorKinds[];
|
|
10
12
|
export declare const cManners: ElbeColorManners[];
|
|
11
13
|
export declare const cStates: string[];
|
|
12
14
|
export declare const cLayers: string[];
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
type _SeedSelInput = {
|
|
16
|
+
path: string[];
|
|
17
|
+
seed: ColorThemeSeed;
|
|
18
|
+
base: LayerColor;
|
|
19
|
+
};
|
|
20
|
+
export type SeedSelector = (p: _SeedSelInput) => LayerColor;
|
|
21
|
+
export type SeedModifier = (p: _SeedSelInput) => ColorThemeSeed;
|
|
22
|
+
export type SeedFlatSelector = (p: _SeedSelInput & {
|
|
23
|
+
style?: LayerColor;
|
|
24
|
+
}) => LayerColor;
|
|
25
|
+
export type SeedStyleSelector = (p: _SeedSelInput & {
|
|
26
|
+
style: LayerColor;
|
|
27
|
+
}) => LayerColor;
|
|
16
28
|
export declare class RGBAColor {
|
|
17
29
|
r: number;
|
|
18
30
|
g: number;
|
|
@@ -67,7 +79,7 @@ export declare class StateColor extends LayerColor {
|
|
|
67
79
|
disabled: LayerColor;
|
|
68
80
|
constructor(neutral: LayerColor, hover: LayerColor, active: LayerColor, disabled: LayerColor);
|
|
69
81
|
asCss(): string;
|
|
70
|
-
static generate(_: ColorThemeSeed, context: LayerColor, style: LayerColor, fromFront?: boolean): StateColor;
|
|
82
|
+
static generate(p: string[], _: ColorThemeSeed, context: LayerColor, style: LayerColor, fromFront?: boolean): StateColor;
|
|
71
83
|
}
|
|
72
84
|
export declare class MannerColor extends StateColor {
|
|
73
85
|
major: StateColor | null;
|
|
@@ -76,7 +88,7 @@ export declare class MannerColor extends StateColor {
|
|
|
76
88
|
constructor(major: StateColor | null, minor: StateColor | null, flat: StateColor);
|
|
77
89
|
asCss(fallback?: MannerColor): string;
|
|
78
90
|
raisedCss(): string;
|
|
79
|
-
static generate(
|
|
91
|
+
static generate(path: string[], seed: ColorThemeSeed, base: LayerColor, style?: LayerColor): MannerColor;
|
|
80
92
|
}
|
|
81
93
|
export declare class KindColor extends MannerColor {
|
|
82
94
|
plain: MannerColor;
|
|
@@ -87,7 +99,7 @@ export declare class KindColor extends MannerColor {
|
|
|
87
99
|
error: MannerColor;
|
|
88
100
|
constructor(plain: MannerColor, accent: MannerColor, info: MannerColor, success: MannerColor, warning: MannerColor, error: MannerColor);
|
|
89
101
|
asCss(): string;
|
|
90
|
-
static generate(
|
|
102
|
+
static generate(path: string[], seed: ColorThemeSeed, base: LayerColor): KindColor;
|
|
91
103
|
}
|
|
92
104
|
export declare class SchemeColor extends KindColor {
|
|
93
105
|
primary: KindColor;
|
|
@@ -95,19 +107,27 @@ export declare class SchemeColor extends KindColor {
|
|
|
95
107
|
inverse: KindColor;
|
|
96
108
|
constructor(primary: KindColor, secondary: KindColor, inverse: KindColor);
|
|
97
109
|
asCss(): string;
|
|
98
|
-
static generate(seed: ColorThemeSeed,
|
|
110
|
+
static generate(path: string[], seed: ColorThemeSeed, base: LayerColor): SchemeColor;
|
|
99
111
|
}
|
|
100
112
|
export declare class ModeColor extends SchemeColor {
|
|
101
113
|
light: SchemeColor;
|
|
102
114
|
dark: SchemeColor;
|
|
103
115
|
constructor(light: SchemeColor, dark: SchemeColor);
|
|
104
116
|
asCss(): string;
|
|
105
|
-
static generate(seed: ColorThemeSeed): ModeColor;
|
|
117
|
+
static generate(path: string[], seed: ColorThemeSeed): ModeColor;
|
|
118
|
+
}
|
|
119
|
+
export declare class ContrastColor extends ModeColor {
|
|
120
|
+
normal: ModeColor;
|
|
121
|
+
highvis: ModeColor;
|
|
122
|
+
constructor(normal: ModeColor, highvis: ModeColor);
|
|
123
|
+
asCss(): string;
|
|
124
|
+
static generate(path: string[], seed: ColorThemeSeed): ContrastColor;
|
|
106
125
|
}
|
|
107
126
|
export declare class ColorTheme {
|
|
108
|
-
colors:
|
|
109
|
-
color:
|
|
110
|
-
constructor(colors:
|
|
127
|
+
colors: ThemeColors;
|
|
128
|
+
color: ContrastColor;
|
|
129
|
+
constructor(colors: ThemeColors, color: ContrastColor);
|
|
111
130
|
asCss(): string;
|
|
112
|
-
static generate(seed?: Partial<PartialColorThemeSeed
|
|
131
|
+
static generate(seed?: Partial<PartialColorThemeSeed>): ColorTheme;
|
|
113
132
|
}
|
|
133
|
+
export {};
|
package/dist/ui/theme/colors.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { hslToRgb, rgbToHsl } from "colors-convert";
|
|
2
2
|
import { clamp } from "../util/util";
|
|
3
3
|
import { colorThemePreset } from "./color_theme";
|
|
4
|
+
import { lColor, } from "./seed";
|
|
5
|
+
export const cContrasts = ["normal", "highvis"];
|
|
4
6
|
export const cModes = ["light", "dark"];
|
|
5
7
|
export const cSchemes = ["primary", "secondary", "inverse"];
|
|
6
8
|
export const cKinds = [
|
|
@@ -159,7 +161,7 @@ export class StateColor extends LayerColor {
|
|
|
159
161
|
`${activeS} { ${this.active.asCss()} }\n` +
|
|
160
162
|
`${disS} { ${this.disabled.asCss()} }`);
|
|
161
163
|
}
|
|
162
|
-
static generate(_, context, style, fromFront) {
|
|
164
|
+
static generate(p, _, context, style, fromFront) {
|
|
163
165
|
function _make(factor) {
|
|
164
166
|
const front = style.front;
|
|
165
167
|
return new LayerColor((fromFront
|
|
@@ -192,8 +194,12 @@ export class MannerColor extends StateColor {
|
|
|
192
194
|
return ((maj ? ` .major { ${maj.asCss()} } \n` : "") +
|
|
193
195
|
(min ? ` .minor { ${min.asCss()} } \n` : ""));
|
|
194
196
|
}
|
|
195
|
-
static generate(
|
|
196
|
-
return new MannerColor(style
|
|
197
|
+
static generate(path, seed, base, style) {
|
|
198
|
+
return new MannerColor(style
|
|
199
|
+
? StateColor.generate([...path, "major"], seed, base, seed.variant.major({ path, seed, base, style }))
|
|
200
|
+
: null, style
|
|
201
|
+
? StateColor.generate([...path, "minor"], seed, base, seed.variant.minor({ path, seed, base, style }))
|
|
202
|
+
: null, StateColor.generate([...path, "flat"], seed, base, seed.variant.flat({ path, seed, base, style }), true));
|
|
197
203
|
/*
|
|
198
204
|
if (!style) {
|
|
199
205
|
return new MannerColor(null, null, StateColor.generate(s, c, c, true));
|
|
@@ -226,8 +232,8 @@ export class KindColor extends MannerColor {
|
|
|
226
232
|
`.warning { ${this.warning.asCss()} }\n` +
|
|
227
233
|
`.error { ${this.error.asCss()} }`);
|
|
228
234
|
}
|
|
229
|
-
static generate(
|
|
230
|
-
return new KindColor(MannerColor.generate(
|
|
235
|
+
static generate(path, seed, base) {
|
|
236
|
+
return new KindColor(MannerColor.generate([...path, "plain"], seed, base), MannerColor.generate([...path, "accent"], seed, base, seed.style.accent({ path, seed, base, style: lColor(seed.accent) })), MannerColor.generate([...path, "info"], seed, base, seed.style.info({ path, seed, base, style: lColor(seed.info) })), MannerColor.generate([...path, "success"], seed, base, seed.style.success({ path, seed, base, style: lColor(seed.success) })), MannerColor.generate([...path, "warning"], seed, base, seed.style.warning({ path, seed, base, style: lColor(seed.warning) })), MannerColor.generate([...path, "error"], seed, base, seed.style.error({ path, seed, base, style: lColor(seed.error) })));
|
|
231
237
|
}
|
|
232
238
|
}
|
|
233
239
|
export class SchemeColor extends KindColor {
|
|
@@ -243,9 +249,9 @@ export class SchemeColor extends KindColor {
|
|
|
243
249
|
`.secondary { ${this.secondary.asCss()} }\n` +
|
|
244
250
|
`.inverse { ${this.inverse.asCss()} }`);
|
|
245
251
|
}
|
|
246
|
-
static generate(seed,
|
|
252
|
+
static generate(path, seed, base) {
|
|
247
253
|
const m = seed.scheme;
|
|
248
|
-
return new SchemeColor(KindColor.generate(seed, m.primary(seed,
|
|
254
|
+
return new SchemeColor(KindColor.generate([...path, "primary"], seed, m.primary({ path, seed, base })), KindColor.generate([...path, "secondary"], seed, m.secondary({ path, seed, base })), KindColor.generate([...path, "inverse"], seed, m.inverse({ path, seed, base })));
|
|
249
255
|
}
|
|
250
256
|
}
|
|
251
257
|
export class ModeColor extends SchemeColor {
|
|
@@ -255,10 +261,24 @@ export class ModeColor extends SchemeColor {
|
|
|
255
261
|
this.dark = dark;
|
|
256
262
|
}
|
|
257
263
|
asCss() {
|
|
258
|
-
return
|
|
264
|
+
return `&{ ${this.light.asCss()}}` + `&.dark { ${this.dark.asCss()}}`;
|
|
259
265
|
}
|
|
260
|
-
static generate(seed) {
|
|
261
|
-
return new ModeColor(SchemeColor.generate(seed, seed.base), SchemeColor.generate(seed, seed.mode.dark(seed, seed.base)));
|
|
266
|
+
static generate(path, seed) {
|
|
267
|
+
return new ModeColor(SchemeColor.generate(path, seed, lColor(seed.base)), SchemeColor.generate([...path, "dark"], seed, seed.mode.dark({ path, seed, base: lColor(seed.base) })));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
export class ContrastColor extends ModeColor {
|
|
271
|
+
constructor(normal, highvis) {
|
|
272
|
+
super(normal.light, normal.dark);
|
|
273
|
+
this.normal = normal;
|
|
274
|
+
this.highvis = highvis;
|
|
275
|
+
}
|
|
276
|
+
asCss() {
|
|
277
|
+
return (`& { ${this.normal.asCss()}}` + `&.highvis { ${this.highvis.asCss()}}`);
|
|
278
|
+
}
|
|
279
|
+
static generate(path, seed) {
|
|
280
|
+
const p = { path, base: lColor(seed.base), seed };
|
|
281
|
+
return new ContrastColor(ModeColor.generate(path, seed.contrast.normal(p)), ModeColor.generate([...path, "highvis"], seed.contrast.highvis(p)));
|
|
262
282
|
}
|
|
263
283
|
}
|
|
264
284
|
export class ColorTheme {
|
|
@@ -267,17 +287,24 @@ export class ColorTheme {
|
|
|
267
287
|
this.color = color;
|
|
268
288
|
}
|
|
269
289
|
asCss() {
|
|
270
|
-
return
|
|
290
|
+
return `
|
|
271
291
|
--c-accent: ${this.colors.accent.back.asCss()};
|
|
272
292
|
--c-info: ${this.colors.info.back.asCss()};
|
|
273
293
|
--c-success: ${this.colors.success.back.asCss()};
|
|
274
294
|
--c-warning: ${this.colors.warning.back.asCss()};
|
|
275
295
|
--c-error: ${this.colors.error.back.asCss()};
|
|
276
|
-
|
|
296
|
+
${this.color.asCss()}`;
|
|
277
297
|
}
|
|
278
|
-
static generate(seed
|
|
279
|
-
const s = colorThemePreset(seed
|
|
280
|
-
return new ColorTheme(
|
|
298
|
+
static generate(seed) {
|
|
299
|
+
const s = colorThemePreset(seed);
|
|
300
|
+
return new ColorTheme({
|
|
301
|
+
base: lColor(s.base),
|
|
302
|
+
accent: lColor(s.accent),
|
|
303
|
+
info: lColor(s.info),
|
|
304
|
+
success: lColor(s.success),
|
|
305
|
+
warning: lColor(s.warning),
|
|
306
|
+
error: lColor(s.error),
|
|
307
|
+
}, ContrastColor.generate([], s));
|
|
281
308
|
}
|
|
282
309
|
}
|
|
283
310
|
//Bun.write("./example.css", ColorTheme.generate().asCss());
|
|
@@ -6,12 +6,10 @@ export class GeometryTheme {
|
|
|
6
6
|
this.borderWidth = borderWidth;
|
|
7
7
|
}
|
|
8
8
|
asCss() {
|
|
9
|
-
return (
|
|
10
|
-
`--g-size: ${this.size}px;` +
|
|
9
|
+
return (`--g-size: ${this.size}px;` +
|
|
11
10
|
`--g-radius: ${this.radius}rem;` +
|
|
12
11
|
`--g-padding: ${this.padding}rem;` +
|
|
13
|
-
`--g-border-width: ${this.borderWidth}rem;`
|
|
14
|
-
"}");
|
|
12
|
+
`--g-border-width: ${this.borderWidth}rem;`);
|
|
15
13
|
}
|
|
16
14
|
static generate(seed) {
|
|
17
15
|
const s = geometryThemePreset(seed);
|
package/dist/ui/theme/seed.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import { LayerColor, SeedFlatSelector, SeedSelector, SeedStyleSelector } from "../..";
|
|
2
|
-
export type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { LayerColor, SeedFlatSelector, SeedModifier, SeedSelector, SeedStyleSelector } from "../..";
|
|
2
|
+
export type HexColor = `#${string}`;
|
|
3
|
+
export type ColorSeedColors = _Colors<LayerColor | HexColor>;
|
|
4
|
+
export type ThemeColors = _Colors<LayerColor>;
|
|
5
|
+
type _Colors<T> = {
|
|
6
|
+
base: T;
|
|
7
|
+
accent: T;
|
|
8
|
+
info: T;
|
|
9
|
+
success: T;
|
|
10
|
+
warning: T;
|
|
11
|
+
error: T;
|
|
12
|
+
};
|
|
13
|
+
type _ContrastSeed = {
|
|
14
|
+
highvis: SeedModifier;
|
|
15
|
+
normal: SeedModifier;
|
|
9
16
|
};
|
|
10
17
|
type _ModeSeed = {
|
|
11
18
|
light: SeedSelector;
|
|
@@ -29,15 +36,18 @@ type _VariantSeed = {
|
|
|
29
36
|
flat: SeedFlatSelector;
|
|
30
37
|
};
|
|
31
38
|
export type ColorThemeSeed = ColorSeedColors & {
|
|
39
|
+
contrast: _ContrastSeed;
|
|
32
40
|
mode: _ModeSeed;
|
|
33
41
|
scheme: _SchemeSeed;
|
|
34
42
|
style: _StyleSeed;
|
|
35
43
|
variant: _VariantSeed;
|
|
36
44
|
};
|
|
37
45
|
export type PartialColorThemeSeed = Partial<ColorSeedColors> & {
|
|
46
|
+
contrast?: Partial<_ContrastSeed>;
|
|
38
47
|
mode?: Partial<_ModeSeed>;
|
|
39
48
|
scheme?: Partial<_SchemeSeed>;
|
|
40
49
|
style?: Partial<_StyleSeed>;
|
|
41
50
|
variant?: Partial<_VariantSeed>;
|
|
42
51
|
};
|
|
52
|
+
export declare function lColor(color: LayerColor | HexColor): LayerColor;
|
|
43
53
|
export {};
|
package/dist/ui/theme/seed.js
CHANGED
package/dist/ui/theme/theme.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import "../../elbe.css";
|
|
|
2
2
|
import { ColorTheme } from "./colors";
|
|
3
3
|
import { GeometryTheme, type GeometryThemeSeed } from "./geometry_theme";
|
|
4
4
|
import { PartialColorThemeSeed } from "./seed";
|
|
5
|
+
import { ElbeThemeConfig } from "./theme_context";
|
|
5
6
|
import { TypeTheme, type TypeThemeSeed } from "./type_theme";
|
|
6
7
|
export * from "./color_theme";
|
|
7
8
|
export * from "./colors";
|
|
@@ -18,15 +19,12 @@ export declare class ElbeThemeData {
|
|
|
18
19
|
readonly geometry: GeometryTheme;
|
|
19
20
|
constructor(color: ColorTheme, type: TypeTheme, geometry: GeometryTheme);
|
|
20
21
|
asCss(): string;
|
|
21
|
-
|
|
22
|
-
static fromSeed(seed: ElbeThemeSeed, highVis: boolean): ElbeThemeData;
|
|
22
|
+
static fromSeed(seed: ElbeThemeSeed): ElbeThemeData;
|
|
23
23
|
}
|
|
24
24
|
export declare function ElbeTheme(p: {
|
|
25
25
|
children: any;
|
|
26
|
-
dark?: boolean;
|
|
27
26
|
todoOverlay?: boolean;
|
|
28
|
-
|
|
29
|
-
} & ({
|
|
27
|
+
} & Partial<ElbeThemeConfig> & ({
|
|
30
28
|
theme: ElbeThemeData;
|
|
31
29
|
} | {
|
|
32
30
|
seed?: ElbeThemeSeed;
|
package/dist/ui/theme/theme.js
CHANGED
|
@@ -3,6 +3,7 @@ import "../../elbe.css";
|
|
|
3
3
|
import { ToDo } from "../components/dev/todo";
|
|
4
4
|
import { ColorTheme } from "./colors";
|
|
5
5
|
import { GeometryTheme } from "./geometry_theme";
|
|
6
|
+
import { _configCss, makeThemeConfig, ThemeConfigContext, ThemeContext, } from "./theme_context";
|
|
6
7
|
import { TypeTheme } from "./type_theme";
|
|
7
8
|
export * from "./color_theme";
|
|
8
9
|
export * from "./colors";
|
|
@@ -15,22 +16,18 @@ export class ElbeThemeData {
|
|
|
15
16
|
this.geometry = geometry;
|
|
16
17
|
}
|
|
17
18
|
asCss() {
|
|
18
|
-
|
|
19
|
+
const inner = [this.color, this.type, this.geometry]
|
|
19
20
|
.map((s) => s.asCss())
|
|
20
21
|
.join("\n");
|
|
22
|
+
return `.elbe {${inner}}`;
|
|
21
23
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return `html,:root {${(!!dark ? c.dark : c.light).asCss()};`;
|
|
25
|
-
}
|
|
26
|
-
static fromSeed(seed, highVis) {
|
|
27
|
-
return new ElbeThemeData(ColorTheme.generate(seed.color, highVis), TypeTheme.generate(seed.type), GeometryTheme.generate(seed.geometry));
|
|
24
|
+
static fromSeed(seed) {
|
|
25
|
+
return new ElbeThemeData(ColorTheme.generate(seed.color), TypeTheme.generate(seed.type), GeometryTheme.generate(seed.geometry));
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
28
|
export function ElbeTheme(p) {
|
|
31
|
-
var _a
|
|
32
|
-
const theme = "theme" in p
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return (_jsxs("div", { class: `elbe ${p.dark ? "dark" : ""} ${p.highVis ? "high_vis" : ""}`, children: [p.todoOverlay && _jsx(ToDo.Overlay, {}), _jsx("style", { children: theme.asCss() }), _jsx("style", { children: theme._pageBackground(p.dark) }), p.children] }));
|
|
29
|
+
var _a;
|
|
30
|
+
const theme = "theme" in p ? p.theme : ElbeThemeData.fromSeed((_a = p.seed) !== null && _a !== void 0 ? _a : {});
|
|
31
|
+
const config = makeThemeConfig(p);
|
|
32
|
+
return (_jsxs("div", { class: `elbe ${config.dark ? "dark" : ""} ${config.highVis ? "highvis" : ""} ${config.reducedMotion ? "reduced_motion" : ""}`, children: [p.todoOverlay && _jsx(ToDo.Overlay, {}), _jsx("style", { children: theme.asCss() }), _jsx("style", { children: _configCss(theme, config) }), _jsx(ThemeConfigContext.Provider, { value: config, children: _jsx(ThemeContext.Provider, { value: theme, children: p.children }) })] }));
|
|
36
33
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ElbeThemeData } from "./theme";
|
|
2
|
+
export interface ElbeThemeConfig {
|
|
3
|
+
highVis: boolean;
|
|
4
|
+
dark: boolean;
|
|
5
|
+
reducedMotion: boolean;
|
|
6
|
+
scale: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function makeThemeConfig(p: Partial<ElbeThemeConfig>): {
|
|
9
|
+
highVis: boolean;
|
|
10
|
+
dark: boolean;
|
|
11
|
+
reducedMotion: boolean;
|
|
12
|
+
scale: number;
|
|
13
|
+
};
|
|
14
|
+
export declare const ThemeConfigContext: import("preact").Context<ElbeThemeConfig>;
|
|
15
|
+
export declare function _configCss(t: ElbeThemeData, c: ElbeThemeConfig): string;
|
|
16
|
+
export declare const ThemeContext: import("preact").Context<ElbeThemeData>;
|
|
17
|
+
export declare function useThemeConfig(): ElbeThemeConfig;
|
|
18
|
+
export declare function useTheme(): ElbeThemeData;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createContext } from "preact";
|
|
2
|
+
import { useContext } from "preact/hooks";
|
|
3
|
+
import { ElbeThemeData } from "./theme";
|
|
4
|
+
export function makeThemeConfig(p) {
|
|
5
|
+
var _a, _b, _c, _d;
|
|
6
|
+
return {
|
|
7
|
+
highVis: (_a = p.highVis) !== null && _a !== void 0 ? _a : false,
|
|
8
|
+
dark: (_b = p.dark) !== null && _b !== void 0 ? _b : false,
|
|
9
|
+
reducedMotion: (_c = p.reducedMotion) !== null && _c !== void 0 ? _c : false,
|
|
10
|
+
scale: (_d = p.scale) !== null && _d !== void 0 ? _d : 1,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export const ThemeConfigContext = createContext(makeThemeConfig({}));
|
|
14
|
+
export function _configCss(t, c) {
|
|
15
|
+
const cBack = c.dark ? t.color.color.dark : t.color.color.light;
|
|
16
|
+
return `html,:root {
|
|
17
|
+
font-size: ${c.scale * 16}px;
|
|
18
|
+
${cBack.asCss()};}`;
|
|
19
|
+
}
|
|
20
|
+
export const ThemeContext = createContext(ElbeThemeData.fromSeed({}));
|
|
21
|
+
export function useThemeConfig() {
|
|
22
|
+
return useContext(ThemeConfigContext);
|
|
23
|
+
}
|
|
24
|
+
export function useTheme() {
|
|
25
|
+
return useContext(ThemeContext);
|
|
26
|
+
}
|
|
@@ -51,7 +51,7 @@ export function typeThemePreset(merge) {
|
|
|
51
51
|
return Object.assign({ heading: {
|
|
52
52
|
bold: true,
|
|
53
53
|
family: ["Calistoga", "Arial", "sans-serif"],
|
|
54
|
-
size: 2
|
|
54
|
+
size: 2,
|
|
55
55
|
}, body: {
|
|
56
56
|
bold: false,
|
|
57
57
|
family: ["Helvetica", "Arial", "sans-serif"],
|
|
@@ -61,7 +61,10 @@ export function typeThemePreset(merge) {
|
|
|
61
61
|
family: ["Courier", "monospace"],
|
|
62
62
|
size: 1,
|
|
63
63
|
}, headingVariants: (style, variant) => {
|
|
64
|
-
const
|
|
64
|
+
const reg = 1;
|
|
65
|
+
const diff = style.size - reg;
|
|
66
|
+
const varFac = (4 - (variant - 2)) / 6;
|
|
67
|
+
const size = reg + diff * Math.pow(varFac, 1.5);
|
|
65
68
|
return Object.assign(Object.assign({}, style), { size });
|
|
66
69
|
}, bodyVariants: (style, variant) => {
|
|
67
70
|
const size = style.size * (variant === "s" ? 0.8 : 1.2);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "preact/compat";
|
|
2
|
+
type _ToolbarState = "toolbar" | "overflow" | null;
|
|
3
|
+
export declare const ToolbarContext: React.Context<_ToolbarState>;
|
|
4
|
+
export declare function useToolbar(): {
|
|
5
|
+
isInToolbar: boolean;
|
|
6
|
+
isInOverflow: boolean;
|
|
7
|
+
};
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React, { useContext } from "preact/compat";
|
|
2
|
+
export const ToolbarContext = React.createContext(null);
|
|
3
|
+
export function useToolbar() {
|
|
4
|
+
const ctx = useContext(ToolbarContext);
|
|
5
|
+
return {
|
|
6
|
+
isInToolbar: ctx === "toolbar",
|
|
7
|
+
isInOverflow: ctx === "overflow",
|
|
8
|
+
};
|
|
9
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "preact/compat";
|
|
2
|
+
import { ElbeChildren } from "../types";
|
|
3
|
+
type _LocaleID = `${string}_${string}` | `${string}`;
|
|
4
|
+
type _LocaleIDEasy = `${string}_${string}_easy` | _LocaleID;
|
|
5
|
+
type _L10nData = {
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
};
|
|
8
|
+
export interface _L10nState<T extends _L10nData> {
|
|
9
|
+
/** the current locale */
|
|
10
|
+
c: T;
|
|
11
|
+
locale: string;
|
|
12
|
+
easyLang: boolean;
|
|
13
|
+
setLocale: (locale: string) => void;
|
|
14
|
+
setEasyLang: (easyLang: boolean) => void;
|
|
15
|
+
}
|
|
16
|
+
type _L10nProps = {
|
|
17
|
+
children: ElbeChildren;
|
|
18
|
+
initialLocale?: _LocaleID;
|
|
19
|
+
initialEasyLang?: boolean;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* L10nBase is a function that creates a localization context provider and a hook to use the localization context.
|
|
23
|
+
* @param fallback this is the fallback locale, which is used if no other locale is found. It is the basis for the locale type and must thus be complete.
|
|
24
|
+
* @param supported this is a list of supported locales. It is a map of locale IDs to partial localization data. The keys are the locale IDs, and the values are the localization data.
|
|
25
|
+
* @returns an object with the L10n component and the useL10n hook.
|
|
26
|
+
*/
|
|
27
|
+
export declare function makeL10n<T extends _L10nData>(fallback: {
|
|
28
|
+
[locale: _LocaleIDEasy]: T;
|
|
29
|
+
}, supported: {
|
|
30
|
+
[locale: _LocaleIDEasy]: Partial<T>;
|
|
31
|
+
}): {
|
|
32
|
+
L10n: React.FunctionComponent<_L10nProps>;
|
|
33
|
+
useL10n: () => _L10nState<T>;
|
|
34
|
+
};
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
import { createContext } from "preact";
|
|
3
|
+
import { useContext, useEffect, useState } from "preact/hooks";
|
|
4
|
+
const _L10nContext = createContext(null);
|
|
5
|
+
function _useL10n() {
|
|
6
|
+
const ctx = useContext(_L10nContext);
|
|
7
|
+
if (!ctx)
|
|
8
|
+
throw new Error("useL10n must be used within a L10n");
|
|
9
|
+
return ctx;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* L10nBase is a function that creates a localization context provider and a hook to use the localization context.
|
|
13
|
+
* @param fallback this is the fallback locale, which is used if no other locale is found. It is the basis for the locale type and must thus be complete.
|
|
14
|
+
* @param supported this is a list of supported locales. It is a map of locale IDs to partial localization data. The keys are the locale IDs, and the values are the localization data.
|
|
15
|
+
* @returns an object with the L10n component and the useL10n hook.
|
|
16
|
+
*/
|
|
17
|
+
export function makeL10n(fallback, supported) {
|
|
18
|
+
if (Object.keys(supported).length === 0) {
|
|
19
|
+
throw new Error("L10nBase: No fallback locales provided");
|
|
20
|
+
}
|
|
21
|
+
const fallbackLocale = Object.keys(fallback)[0];
|
|
22
|
+
const fallbackValue = fallback[fallbackLocale];
|
|
23
|
+
const supportedLocales = Object.assign(Object.assign({}, supported), fallback);
|
|
24
|
+
const useL10n = (_useL10n);
|
|
25
|
+
const L10n = (p) => {
|
|
26
|
+
var _a, _b;
|
|
27
|
+
const [loc, setLoc] = useState((_a = p.initialLocale) !== null && _a !== void 0 ? _a : navigator.language);
|
|
28
|
+
const [easy, setEasy] = useState((_b = p.initialEasyLang) !== null && _b !== void 0 ? _b : false);
|
|
29
|
+
const [currentLang, setCurrentLang] = useState(fallbackValue);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
var _a;
|
|
32
|
+
const match = _bestMatch(loc, easy, Object.keys(supportedLocales));
|
|
33
|
+
setCurrentLang(Object.assign(Object.assign({}, fallbackValue), ((_a = supportedLocales[match !== null && match !== void 0 ? match : ""]) !== null && _a !== void 0 ? _a : {})));
|
|
34
|
+
}, [loc, easy]);
|
|
35
|
+
return (_jsx(_L10nContext.Provider, { value: {
|
|
36
|
+
c: currentLang,
|
|
37
|
+
locale: loc,
|
|
38
|
+
easyLang: easy,
|
|
39
|
+
setLocale: (l) => setLoc(l),
|
|
40
|
+
setEasyLang: (e) => setEasy(e),
|
|
41
|
+
}, children: p.children }));
|
|
42
|
+
};
|
|
43
|
+
return { L10n, useL10n };
|
|
44
|
+
}
|
|
45
|
+
function _locale(l) {
|
|
46
|
+
const parts = l.split("_");
|
|
47
|
+
const easy = parts.length > 2 && parts[2] === "easy";
|
|
48
|
+
const region = parts.length > 1 ? parts[1].toLowerCase() : null;
|
|
49
|
+
const lang = parts[0].toLowerCase();
|
|
50
|
+
return { full: l, lang, region, easy };
|
|
51
|
+
}
|
|
52
|
+
function _bestMatch(locale, easy, locales) {
|
|
53
|
+
const loc = _locale(locale.replaceAll("-", "_"));
|
|
54
|
+
const asLocales = locales.map((l) => _locale(l));
|
|
55
|
+
// filter by language
|
|
56
|
+
const langMatch = asLocales.filter((l) => loc.lang === l.lang);
|
|
57
|
+
// filter by easy
|
|
58
|
+
const easyMatch = langMatch.filter((l) => l.easy === easy);
|
|
59
|
+
// filter by region
|
|
60
|
+
const regionMatch = easyMatch.filter((l) => l.region === loc.region);
|
|
61
|
+
if (regionMatch.length > 0)
|
|
62
|
+
return regionMatch[0].full;
|
|
63
|
+
if (easyMatch.length > 0)
|
|
64
|
+
return easyMatch[0].full;
|
|
65
|
+
if (langMatch.length > 0)
|
|
66
|
+
return langMatch[0].full;
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @see https://stackoverflow.com/questions/53953814/typescript-check-if-a-type-is-a-union/53955431
|
|
3
|
+
*/
|
|
4
|
+
type IsSingleton<T> = [T] extends [UnionToIntersection<T>] ? true : false;
|
|
5
|
+
/**
|
|
6
|
+
* @author https://stackoverflow.com/users/2887218/jcalz
|
|
7
|
+
* @see https://stackoverflow.com/a/50375286/10325032
|
|
8
|
+
*/
|
|
9
|
+
type UnionToIntersection<Union> = (Union extends any ? (argument: Union) => void : never) extends (argument: infer Intersection) => void ? Intersection : never;
|
|
10
|
+
export type SingletonOnly<T> = IsSingleton<T> extends true ? T : never;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type int = number;
|
|
2
|
+
export type float = number;
|
|
3
|
+
/** a unix epoch timestamp in milliseconds */
|
|
4
|
+
export type UnixMS = int;
|
|
5
|
+
export type ElbeChild = React.ReactNode;
|
|
6
|
+
export type ElbeChildren = ElbeChild[] | ElbeChild;
|
|
7
|
+
export type s = string;
|
|
8
|
+
export type n = number;
|
|
9
|
+
export type b = boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/ui/util/util.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
export type ElbeChild = React.ReactNode;
|
|
3
|
-
export type ElbeChildren = ElbeChild[] | ElbeChild;
|
|
1
|
+
import { int } from "../..";
|
|
4
2
|
export declare function clamp(value: number, min: number, max: number): number;
|
|
5
3
|
export declare function classString(classes: (string | false | null | undefined)[]): string;
|
|
6
4
|
/**
|
|
@@ -20,3 +18,7 @@ export declare function share(data: {
|
|
|
20
18
|
*/
|
|
21
19
|
export declare function copyToClipboard(text: string, toastMsg?: string): void;
|
|
22
20
|
export declare function scrollToId(id: string): void;
|
|
21
|
+
export declare function randomAlphaNum(length: int, prefix?: string): string;
|
|
22
|
+
export type LayoutModes = "mobile" | "narrow" | "wide";
|
|
23
|
+
export declare function useLayoutMode(): LayoutModes;
|
|
24
|
+
export declare function useSiteScroll(): number;
|
package/dist/ui/util/util.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState } from "preact/compat";
|
|
2
|
+
import { showToast } from "../..";
|
|
2
3
|
export function clamp(value, min, max) {
|
|
3
4
|
return Math.min(Math.max(value, min), max);
|
|
4
5
|
}
|
|
@@ -36,3 +37,37 @@ export function scrollToId(id) {
|
|
|
36
37
|
if (el)
|
|
37
38
|
el.scrollIntoView({ behavior: "smooth" });
|
|
38
39
|
}
|
|
40
|
+
export function randomAlphaNum(length, prefix = "") {
|
|
41
|
+
const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
42
|
+
let result = prefix;
|
|
43
|
+
for (let i = 0; i < length; i++) {
|
|
44
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
function _layoutMode() {
|
|
49
|
+
const w = window.innerWidth;
|
|
50
|
+
if (w < 700)
|
|
51
|
+
return "mobile";
|
|
52
|
+
if (w < 1100)
|
|
53
|
+
return "narrow";
|
|
54
|
+
return "wide";
|
|
55
|
+
}
|
|
56
|
+
export function useLayoutMode() {
|
|
57
|
+
const [mode, setMode] = useState(_layoutMode());
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
const onResize = () => setMode(_layoutMode());
|
|
60
|
+
window.addEventListener("resize", onResize);
|
|
61
|
+
return () => window.removeEventListener("resize", onResize);
|
|
62
|
+
});
|
|
63
|
+
return mode;
|
|
64
|
+
}
|
|
65
|
+
export function useSiteScroll() {
|
|
66
|
+
const [scroll, setScroll] = useState(0);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
const onScroll = () => setScroll(window.scrollY);
|
|
69
|
+
window.addEventListener("scroll", onScroll);
|
|
70
|
+
return () => window.removeEventListener("scroll", onScroll);
|
|
71
|
+
}, []);
|
|
72
|
+
return scroll;
|
|
73
|
+
}
|