@syware/jlib 0.4.0 → 0.5.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/dist/all.js +8 -3
- package/dist/atoms/jl-badge.d.ts +12 -1
- package/dist/atoms/jl-badge.js +15 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +7 -2
- package/dist/lib/time.d.ts +10 -0
- package/dist/lib/time.js +64 -0
- package/dist/molecules/jl-account-button.css_raw.js +3 -0
- package/dist/molecules/jl-account-button.d.ts +46 -0
- package/dist/molecules/jl-account-button.js +97 -0
- package/dist/molecules/jl-load-state.css_raw.js +3 -0
- package/dist/molecules/jl-load-state.d.ts +61 -0
- package/dist/molecules/jl-load-state.js +200 -0
- package/dist/molecules/jl-search-button.css_raw.js +3 -0
- package/dist/molecules/jl-search-button.d.ts +34 -0
- package/dist/molecules/jl-search-button.js +80 -0
- package/dist/molecules/jl-tooltip.css_raw.js +1 -1
- package/dist/molecules/jl-tooltip.d.ts +26 -1
- package/dist/molecules/jl-tooltip.js +132 -5
- package/dist/organisms/jl-confirm.d.ts +7 -1
- package/dist/organisms/jl-confirm.js +22 -1
- package/dist/organisms/jl-toaster.d.ts +4 -1
- package/dist/organisms/jl-toaster.js +9 -2
- package/dist/styles/control.css_raw.js +1 -1
- package/dist/styles/tokens.css_raw.js +1 -1
- package/dist/templates/jl-page.css_raw.js +3 -0
- package/dist/templates/jl-page.d.ts +49 -0
- package/dist/templates/jl-page.js +102 -0
- package/dist/tokens.css +22 -0
- package/dist/types/jl-badge.types.d.ts +11 -0
- package/dist/types/jl-confirm.types.d.ts +15 -0
- package/dist/types/jl-load-state.types.d.ts +10 -0
- package/dist/types/jl-page.types.d.ts +2 -0
- package/dist/types/jl-toaster.types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/styles/tokens.css?raw
|
|
2
|
-
var tokens_default = "/*\n * The design tokens, as swai and swcode have them: ink and white, flat surfaces separated by lines, and one blue\n * that marks what is live, selected or waiting for a person. Custom properties cross shadow roots, so every\n * component reads them. They sit in the `jlib` layer: any unlayered rule of the page overrides them.\n */\n@layer jlib {\n :root,\n [data-theme=\"light\"] {\n color-scheme: light;\n --jl-font-sans: \"Manrope Variable\", \"Manrope\", system-ui, -apple-system, \"Segoe UI\", sans-serif;\n --jl-font-mono: \"JetBrains Mono Variable\", \"JetBrains Mono\", ui-monospace, \"SF Mono\", Menlo, monospace;\n\n --jl-font-xs: 12px;\n --jl-font-sm: 13px;\n --jl-font-md: 14px;\n --jl-font-lg: 16px;\n --jl-font-xl: 20px;\n --jl-font-2xl: 28px;\n\n --jl-text: #0b0b0c;\n --jl-text-2: #3a3f47;\n /* Secondary text: 6.2:1 on white. */\n --jl-muted: #5b616b;\n /* Icons and decorations only: 3.2:1 on white is enough for them, not for text. */\n --jl-faint: #8a9099;\n\n --jl-bg: #ffffff;\n --jl-surface: #ffffff;\n --jl-surface-2: #f7f8f9;\n --jl-surface-3: #eef0f2;\n --jl-code-bg: #f0f2f4;\n --jl-line: #e6e8eb;\n --jl-line-soft: #eef0f2;\n --jl-line-strong: #d5d9de;\n\n /* The SyWare logo's blue: marks, focus rings, progress. 3.8:1 on white: enough for shapes, never for text. */\n --jl-brand: #0e88d3;\n /* The same hue, deep enough to carry text: buttons, links, the selection. 5.2:1 on white. */\n --jl-accent: #0c72b0;\n --jl-accent-strong: #095a8b;\n --jl-accent-soft: #e9f4fb;\n --jl-accent-line: #b7dbf2;\n --jl-on-accent: #ffffff;\n\n --jl-ok: #17784a;\n --jl-ok-soft: #ecf6f0;\n --jl-warn: #9a5b00;\n --jl-warn-soft: #fcf4e6;\n --jl-danger: #b42318;\n --jl-danger-soft: #fdf0ef;\n --jl-on-danger: #ffffff;\n --jl-info: #0c72b0;\n --jl-info-soft: #e9f4fb;\n\n /* Code: the accent for keywords, quiet colours from the same family for the rest. */\n --jl-code-keyword: #0c72b0;\n --jl-code-tag: #095a8b;\n --jl-code-attribute: #5b48c8;\n --jl-code-string: #17784a;\n --jl-code-number: #9a5b00;\n --jl-code-function: #3d5a80;\n --jl-code-property: #127a72;\n --jl-code-comment: #8a9099;\n\n --jl-radius-xs: 6px;\n --jl-radius-sm: 8px;\n --jl-radius: 10px;\n --jl-radius-lg: 12px;\n --jl-radius-xl: 20px;\n --jl-radius-pill: 999px;\n\n /* Spacing: a 4px grid, for the layouts pages build around the components. */\n --jl-space-1: 4px;\n --jl-space-2: 8px;\n --jl-space-3: 12px;\n --jl-space-4: 16px;\n --jl-space-5: 20px;\n --jl-space-6: 24px;\n --jl-space-8: 32px;\n --jl-space-10: 40px;\n --jl-space-12: 48px;\n --jl-space-16: 64px;\n\n --jl-control-sm: 30px;\n --jl-control-md: 36px;\n --jl-control-lg: 44px;\n\n /* Flat: lines separate; only what floats (menus, dialogs, toasts) casts a shadow. */\n --jl-shadow-sm: 0 1px 2px rgb(11 11 12 / 0.05);\n --jl-shadow: 0 6px 16px -6px rgb(11 11 12 / 0.12);\n --jl-shadow-lg: 0 18px 44px -14px rgb(11 11 12 / 0.22);\n --jl-focus-ring: 0 0 0 3px color-mix(in srgb, var(--jl-brand) 35%, transparent);\n --jl-scrim: rgb(11 11 12 / 0.38);\n\n --jl-ease: cubic-bezier(0.2, 0.7, 0.2, 1);\n --jl-fast: 120ms;\n --jl-slow: 240ms;\n }\n\n @media (prefers-color-scheme: dark) {\n :root:not([data-theme=\"light\"]) {\n color-scheme: dark;\n --jl-text: #eceef1;\n --jl-text-2: #c3c8cf;\n --jl-muted: #959ca6;\n --jl-faint: #6b727c;\n --jl-bg: #0f1113;\n --jl-surface: #0f1113;\n --jl-surface-2: #16191c;\n --jl-surface-3: #1d2125;\n --jl-code-bg: #1d2125;\n --jl-line: #262a2f;\n --jl-line-soft: #1f2327;\n --jl-line-strong: #343a41;\n --jl-brand: #1a9be0;\n --jl-accent: #3ea6e8;\n --jl-accent-strong: #6cc0f2;\n --jl-accent-soft: #0f2a3b;\n --jl-accent-line: #1e4a66;\n --jl-on-accent: #04131c;\n --jl-ok: #4cc38a;\n --jl-ok-soft: #10261c;\n --jl-warn: #e5a54b;\n --jl-warn-soft: #2a2012;\n --jl-danger: #f0786c;\n --jl-danger-soft: #3a1a17;\n --jl-on-danger: #1c0604;\n --jl-info: #3ea6e8;\n --jl-info-soft: #0f2a3b;\n --jl-code-keyword: #3ea6e8;\n --jl-code-tag: #6cc0f2;\n --jl-code-attribute: #a99bf0;\n --jl-code-string: #4cc38a;\n --jl-code-number: #e5a54b;\n --jl-code-function: #8fb0d6;\n --jl-code-property: #4fc1b5;\n --jl-code-comment: #6b727c;\n --jl-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);\n --jl-shadow: 0 6px 18px -6px rgb(0 0 0 / 0.6);\n --jl-shadow-lg: 0 18px 44px -12px rgb(0 0 0 / 0.7);\n --jl-scrim: rgb(0 0 0 / 0.55);\n }\n }\n\n /* Dark: the same blue, lifted to read on a dark ground, with dark text on the buttons. */\n [data-theme=\"dark\"] {\n color-scheme: dark;\n --jl-text: #eceef1;\n --jl-text-2: #c3c8cf;\n --jl-muted: #959ca6;\n --jl-faint: #6b727c;\n --jl-bg: #0f1113;\n --jl-surface: #0f1113;\n --jl-surface-2: #16191c;\n --jl-surface-3: #1d2125;\n --jl-code-bg: #1d2125;\n --jl-line: #262a2f;\n --jl-line-soft: #1f2327;\n --jl-line-strong: #343a41;\n --jl-brand: #1a9be0;\n --jl-accent: #3ea6e8;\n --jl-accent-strong: #6cc0f2;\n --jl-accent-soft: #0f2a3b;\n --jl-accent-line: #1e4a66;\n --jl-on-accent: #04131c;\n --jl-ok: #4cc38a;\n --jl-ok-soft: #10261c;\n --jl-warn: #e5a54b;\n --jl-warn-soft: #2a2012;\n --jl-danger: #f0786c;\n --jl-danger-soft: #3a1a17;\n --jl-on-danger: #1c0604;\n --jl-info: #3ea6e8;\n --jl-info-soft: #0f2a3b;\n --jl-code-keyword: #3ea6e8;\n --jl-code-tag: #6cc0f2;\n --jl-code-attribute: #a99bf0;\n --jl-code-string: #4cc38a;\n --jl-code-number: #e5a54b;\n --jl-code-function: #8fb0d6;\n --jl-code-property: #4fc1b5;\n --jl-code-comment: #6b727c;\n --jl-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);\n --jl-shadow: 0 6px 18px -6px rgb(0 0 0 / 0.6);\n --jl-shadow-lg: 0 18px 44px -12px rgb(0 0 0 / 0.7);\n --jl-scrim: rgb(0 0 0 / 0.55);\n }\n}\n";
|
|
2
|
+
var tokens_default = "/*\n * The design tokens, as swai and swcode have them: ink and white, flat surfaces separated by lines, and one blue\n * that marks what is live, selected or waiting for a person. Custom properties cross shadow roots, so every\n * component reads them. They sit in the `jlib` layer: any unlayered rule of the page overrides them.\n */\n@layer jlib {\n :root,\n [data-theme=\"light\"] {\n color-scheme: light;\n --jl-font-sans: \"Manrope Variable\", \"Manrope\", system-ui, -apple-system, \"Segoe UI\", sans-serif;\n --jl-font-mono: \"JetBrains Mono Variable\", \"JetBrains Mono\", ui-monospace, \"SF Mono\", Menlo, monospace;\n\n --jl-font-xs: 12px;\n --jl-font-sm: 13px;\n --jl-font-md: 14px;\n --jl-font-lg: 16px;\n --jl-font-xl: 20px;\n --jl-font-2xl: 28px;\n\n --jl-text: #0b0b0c;\n --jl-text-2: #3a3f47;\n /* Secondary text: 6.2:1 on white. */\n --jl-muted: #5b616b;\n /* Icons and decorations only: 3.2:1 on white is enough for them, not for text. */\n --jl-faint: #8a9099;\n\n --jl-bg: #ffffff;\n --jl-surface: #ffffff;\n --jl-surface-2: #f7f8f9;\n --jl-surface-3: #eef0f2;\n --jl-code-bg: #f0f2f4;\n --jl-line: #e6e8eb;\n --jl-line-soft: #eef0f2;\n --jl-line-strong: #d5d9de;\n\n /* The SyWare logo's blue: marks, focus rings, progress. 3.8:1 on white: enough for shapes, never for text. */\n --jl-brand: #0e88d3;\n /* The same hue, deep enough to carry text: buttons, links, the selection. 5.2:1 on white. */\n --jl-accent: #0c72b0;\n --jl-accent-strong: #095a8b;\n --jl-accent-soft: #e9f4fb;\n --jl-accent-line: #b7dbf2;\n --jl-on-accent: #ffffff;\n\n --jl-ok: #17784a;\n --jl-ok-soft: #ecf6f0;\n --jl-warn: #9a5b00;\n --jl-warn-soft: #fcf4e6;\n --jl-danger: #b42318;\n --jl-danger-soft: #fdf0ef;\n --jl-on-danger: #ffffff;\n --jl-info: #0c72b0;\n --jl-info-soft: #e9f4fb;\n\n /* Code: the accent for keywords, quiet colours from the same family for the rest. */\n --jl-code-keyword: #0c72b0;\n --jl-code-tag: #095a8b;\n --jl-code-attribute: #5b48c8;\n --jl-code-string: #17784a;\n --jl-code-number: #9a5b00;\n --jl-code-function: #3d5a80;\n --jl-code-property: #127a72;\n --jl-code-comment: #8a9099;\n\n --jl-radius-xs: 6px;\n --jl-radius-sm: 8px;\n --jl-radius: 10px;\n --jl-radius-lg: 12px;\n --jl-radius-xl: 20px;\n --jl-radius-pill: 999px;\n\n /* Spacing: a 4px grid, for the layouts pages build around the components. */\n --jl-space-1: 4px;\n --jl-space-2: 8px;\n --jl-space-3: 12px;\n --jl-space-4: 16px;\n --jl-space-5: 20px;\n --jl-space-6: 24px;\n --jl-space-8: 32px;\n --jl-space-10: 40px;\n --jl-space-12: 48px;\n --jl-space-16: 64px;\n\n --jl-control-sm: 30px;\n --jl-control-md: 36px;\n --jl-control-lg: 44px;\n /* The text people type in fields. */\n --jl-control-font: var(--jl-font-md);\n\n /* The widest a page gets: a form, most pages, and the tables and grids that need the room. */\n --jl-page-form: 720px;\n --jl-page-standard: 1120px;\n --jl-page-wide: 1400px;\n\n /* Flat: lines separate; only what floats (menus, dialogs, toasts) casts a shadow. */\n --jl-shadow-sm: 0 1px 2px rgb(11 11 12 / 0.05);\n --jl-shadow: 0 6px 16px -6px rgb(11 11 12 / 0.12);\n --jl-shadow-lg: 0 18px 44px -14px rgb(11 11 12 / 0.22);\n --jl-focus-ring: 0 0 0 3px color-mix(in srgb, var(--jl-brand) 35%, transparent);\n --jl-scrim: rgb(11 11 12 / 0.38);\n\n --jl-ease: cubic-bezier(0.2, 0.7, 0.2, 1);\n --jl-fast: 120ms;\n --jl-slow: 240ms;\n }\n\n @media (prefers-color-scheme: dark) {\n :root:not([data-theme=\"light\"]) {\n color-scheme: dark;\n --jl-text: #eceef1;\n --jl-text-2: #c3c8cf;\n --jl-muted: #959ca6;\n --jl-faint: #6b727c;\n --jl-bg: #0f1113;\n --jl-surface: #0f1113;\n --jl-surface-2: #16191c;\n --jl-surface-3: #1d2125;\n --jl-code-bg: #1d2125;\n --jl-line: #262a2f;\n --jl-line-soft: #1f2327;\n --jl-line-strong: #343a41;\n --jl-brand: #1a9be0;\n --jl-accent: #3ea6e8;\n --jl-accent-strong: #6cc0f2;\n --jl-accent-soft: #0f2a3b;\n --jl-accent-line: #1e4a66;\n --jl-on-accent: #04131c;\n --jl-ok: #4cc38a;\n --jl-ok-soft: #10261c;\n --jl-warn: #e5a54b;\n --jl-warn-soft: #2a2012;\n --jl-danger: #f0786c;\n --jl-danger-soft: #3a1a17;\n --jl-on-danger: #1c0604;\n --jl-info: #3ea6e8;\n --jl-info-soft: #0f2a3b;\n --jl-code-keyword: #3ea6e8;\n --jl-code-tag: #6cc0f2;\n --jl-code-attribute: #a99bf0;\n --jl-code-string: #4cc38a;\n --jl-code-number: #e5a54b;\n --jl-code-function: #8fb0d6;\n --jl-code-property: #4fc1b5;\n --jl-code-comment: #6b727c;\n --jl-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);\n --jl-shadow: 0 6px 18px -6px rgb(0 0 0 / 0.6);\n --jl-shadow-lg: 0 18px 44px -12px rgb(0 0 0 / 0.7);\n --jl-scrim: rgb(0 0 0 / 0.55);\n }\n }\n\n /* Dark: the same blue, lifted to read on a dark ground, with dark text on the buttons. */\n [data-theme=\"dark\"] {\n color-scheme: dark;\n --jl-text: #eceef1;\n --jl-text-2: #c3c8cf;\n --jl-muted: #959ca6;\n --jl-faint: #6b727c;\n --jl-bg: #0f1113;\n --jl-surface: #0f1113;\n --jl-surface-2: #16191c;\n --jl-surface-3: #1d2125;\n --jl-code-bg: #1d2125;\n --jl-line: #262a2f;\n --jl-line-soft: #1f2327;\n --jl-line-strong: #343a41;\n --jl-brand: #1a9be0;\n --jl-accent: #3ea6e8;\n --jl-accent-strong: #6cc0f2;\n --jl-accent-soft: #0f2a3b;\n --jl-accent-line: #1e4a66;\n --jl-on-accent: #04131c;\n --jl-ok: #4cc38a;\n --jl-ok-soft: #10261c;\n --jl-warn: #e5a54b;\n --jl-warn-soft: #2a2012;\n --jl-danger: #f0786c;\n --jl-danger-soft: #3a1a17;\n --jl-on-danger: #1c0604;\n --jl-info: #3ea6e8;\n --jl-info-soft: #0f2a3b;\n --jl-code-keyword: #3ea6e8;\n --jl-code-tag: #6cc0f2;\n --jl-code-attribute: #a99bf0;\n --jl-code-string: #4cc38a;\n --jl-code-number: #e5a54b;\n --jl-code-function: #8fb0d6;\n --jl-code-property: #4fc1b5;\n --jl-code-comment: #6b727c;\n --jl-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);\n --jl-shadow: 0 6px 18px -6px rgb(0 0 0 / 0.6);\n --jl-shadow-lg: 0 18px 44px -12px rgb(0 0 0 / 0.7);\n --jl-scrim: rgb(0 0 0 / 0.55);\n }\n\n /*\n * Touch screens: controls a finger can hit (44px for most), and field text phones do not zoom into when it takes\n * the focus (16px). Themed parts of a page re-declare the sizes, so they take these too.\n */\n @media (pointer: coarse) {\n :root,\n [data-theme=\"light\"],\n [data-theme=\"dark\"] {\n --jl-control-sm: 36px;\n --jl-control-md: 44px;\n --jl-control-lg: 48px;\n --jl-control-font: 16px;\n }\n }\n}\n";
|
|
3
3
|
export { tokens_default as default };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// src/templates/jl-page.css?raw
|
|
2
|
+
var jl_page_default = ":host {\n display: block;\n container-type: inline-size;\n --page-width: var(--jl-page-standard);\n}\n\n:host([width=\"form\"]) {\n --page-width: var(--jl-page-form);\n}\n\n:host([width=\"wide\"]) {\n --page-width: var(--jl-page-wide);\n}\n\n:host([width=\"full\"]) {\n --page-width: none;\n}\n\n.page {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--jl-space-6);\n max-width: var(--page-width);\n margin: 0 auto;\n padding: var(--jl-space-8) var(--jl-space-10) var(--jl-space-12);\n}\n\n/* A grid's items grow to their content otherwise: a row of chips would widen the page. */\n::slotted(*) {\n min-width: 0;\n}\n\n.back {\n margin-left: -8px;\n}\n\n@container (max-width: 720px) {\n .page {\n padding: var(--jl-space-6) var(--jl-space-4) var(--jl-space-12);\n }\n}\n";
|
|
3
|
+
export { jl_page_default as default };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { JlElement } from '../base/jl-element';
|
|
2
|
+
import type { PageWidth } from '../types/jl-page.types';
|
|
3
|
+
export declare const PAGE_WIDTHS: readonly PageWidth[];
|
|
4
|
+
/**
|
|
5
|
+
* A page of an app: its header (a back link named after the page it leads to, the heading, a sentence on what the
|
|
6
|
+
* page is for or the facts that identify its subject, the status, the actions), then the content, centred at one of
|
|
7
|
+
* four widths. With `app-name`, it also names the browser tab after its heading: "Order #3 · swstock".
|
|
8
|
+
*/
|
|
9
|
+
export declare class JlPage extends JlElement {
|
|
10
|
+
static readonly selector = "jl-page";
|
|
11
|
+
readonly events: Readonly<import("@jadis/core").UseEventsHandler<{
|
|
12
|
+
back: undefined;
|
|
13
|
+
}>>;
|
|
14
|
+
readonly heading: Readonly<Readonly<{
|
|
15
|
+
get(): string;
|
|
16
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
17
|
+
}>>;
|
|
18
|
+
readonly description: Readonly<Readonly<{
|
|
19
|
+
get(): string;
|
|
20
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
21
|
+
}>>;
|
|
22
|
+
/** `form` for one column of fields, `standard` for most pages, `wide` for tables and grids, `full` for the rest. */
|
|
23
|
+
readonly width: Readonly<Readonly<{
|
|
24
|
+
get(): PageWidth;
|
|
25
|
+
set(setter: ((prevState: PageWidth) => PageWidth) | PageWidth): void;
|
|
26
|
+
}>>;
|
|
27
|
+
/** Where the back link leads; no back link without it. */
|
|
28
|
+
readonly back: Readonly<Readonly<{
|
|
29
|
+
get(): string;
|
|
30
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
31
|
+
}>>;
|
|
32
|
+
/** The name of the page the back link leads to: "Orders". */
|
|
33
|
+
readonly backLabel: Readonly<Readonly<{
|
|
34
|
+
get(): string;
|
|
35
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
36
|
+
}>>;
|
|
37
|
+
/** The app's name, after the heading in the browser tab. Without it, the page leaves the tab's title alone. */
|
|
38
|
+
readonly appName: Readonly<Readonly<{
|
|
39
|
+
get(): string;
|
|
40
|
+
set(setter: string | ((prevState: string) => string)): void;
|
|
41
|
+
}>>;
|
|
42
|
+
private readonly _refs;
|
|
43
|
+
templateHtml(): Node;
|
|
44
|
+
templateCss(): string;
|
|
45
|
+
onConnect(): void;
|
|
46
|
+
/** The back link stays out of the header's breadcrumb slot without an address, so the header takes no room for it. */
|
|
47
|
+
private renderBack;
|
|
48
|
+
private renderTitle;
|
|
49
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { BASE_STYLES } from "../styles/shared.js";
|
|
2
|
+
import { JlElement } from "../base/jl-element.js";
|
|
3
|
+
import { oneOf } from "../lib/attributes.js";
|
|
4
|
+
import { define } from "../lib/define.js";
|
|
5
|
+
import { registerIcons } from "../lib/icons.js";
|
|
6
|
+
import { setOrRemove } from "../lib/dom.js";
|
|
7
|
+
import { JlButton } from "../atoms/jl-button.js";
|
|
8
|
+
import { JlPageHeader } from "../organisms/jl-page-header.js";
|
|
9
|
+
import jl_page_default from "./jl-page.css_raw.js";
|
|
10
|
+
import { css } from "@jadis/core";
|
|
11
|
+
import { ArrowLeft } from "lucide";
|
|
12
|
+
import { jsx, jsxs } from "@jadis/core/jsx-runtime";
|
|
13
|
+
// src/templates/jl-page.tsx
|
|
14
|
+
registerIcons({ "arrow-left": ArrowLeft });
|
|
15
|
+
define(JlPageHeader);
|
|
16
|
+
var PAGE_WIDTHS = [
|
|
17
|
+
"standard",
|
|
18
|
+
"form",
|
|
19
|
+
"wide",
|
|
20
|
+
"full"
|
|
21
|
+
];
|
|
22
|
+
var BREADCRUMB_SLOT = "breadcrumb";
|
|
23
|
+
var DEFAULT_BACK_LABEL = "Back";
|
|
24
|
+
var TITLE_SEPARATOR = " · ";
|
|
25
|
+
/**
|
|
26
|
+
* A page of an app: its header (a back link named after the page it leads to, the heading, a sentence on what the
|
|
27
|
+
* page is for or the facts that identify its subject, the status, the actions), then the content, centred at one of
|
|
28
|
+
* four widths. With `app-name`, it also names the browser tab after its heading: "Order #3 · swstock".
|
|
29
|
+
*/
|
|
30
|
+
var JlPage = class extends JlElement {
|
|
31
|
+
static selector = "jl-page";
|
|
32
|
+
events = this.useEvents();
|
|
33
|
+
heading = this.useChange("", (value) => {
|
|
34
|
+
this._refs.header.heading.set(value);
|
|
35
|
+
this.renderTitle();
|
|
36
|
+
}, { attribute: "heading" });
|
|
37
|
+
description = this.useChange("", (value) => this._refs.header.description.set(value), { attribute: "description" });
|
|
38
|
+
/** `form` for one column of fields, `standard` for most pages, `wide` for tables and grids, `full` for the rest. */
|
|
39
|
+
width = this.useChange("standard", (value) => this.reflect("width", value), {
|
|
40
|
+
attribute: "width",
|
|
41
|
+
parse: oneOf(PAGE_WIDTHS, "standard")
|
|
42
|
+
});
|
|
43
|
+
/** Where the back link leads; no back link without it. */
|
|
44
|
+
back = this.useChange("", () => this.renderBack(), { attribute: "back" });
|
|
45
|
+
/** The name of the page the back link leads to: "Orders". */
|
|
46
|
+
backLabel = this.useChange("", () => this.renderBack(), { attribute: "back-label" });
|
|
47
|
+
/** The app's name, after the heading in the browser tab. Without it, the page leaves the tab's title alone. */
|
|
48
|
+
appName = this.useChange("", () => this.renderTitle(), { attribute: "app-name" });
|
|
49
|
+
_refs = this.useRefs((ref) => ({
|
|
50
|
+
back: ref(".back"),
|
|
51
|
+
header: ref("jl-page-header")
|
|
52
|
+
}));
|
|
53
|
+
templateHtml() {
|
|
54
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
55
|
+
class: "page",
|
|
56
|
+
attrs: { part: "base" },
|
|
57
|
+
children: [/* @__PURE__ */ jsxs("jl-page-header", { children: [
|
|
58
|
+
/* @__PURE__ */ jsx(JlButton, {
|
|
59
|
+
class: "back",
|
|
60
|
+
variant: "ghost",
|
|
61
|
+
size: "sm",
|
|
62
|
+
icon: "arrow-left"
|
|
63
|
+
}),
|
|
64
|
+
/* @__PURE__ */ jsx("slot", {
|
|
65
|
+
name: "breadcrumb",
|
|
66
|
+
slot: "breadcrumb"
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ jsx("slot", {
|
|
69
|
+
name: "actions",
|
|
70
|
+
slot: "actions"
|
|
71
|
+
}),
|
|
72
|
+
/* @__PURE__ */ jsx("slot", {
|
|
73
|
+
name: "meta",
|
|
74
|
+
slot: "meta"
|
|
75
|
+
})
|
|
76
|
+
] }), /* @__PURE__ */ jsx("slot", {})]
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
templateCss() {
|
|
80
|
+
return css`${BASE_STYLES}${jl_page_default}`;
|
|
81
|
+
}
|
|
82
|
+
onConnect() {
|
|
83
|
+
this.renderTitle();
|
|
84
|
+
this._refs.back.events.register("press", () => this.events.emit("back"));
|
|
85
|
+
}
|
|
86
|
+
/** The back link stays out of the header's breadcrumb slot without an address, so the header takes no room for it. */
|
|
87
|
+
renderBack() {
|
|
88
|
+
const back = this._refs.back;
|
|
89
|
+
const href = this.back.get();
|
|
90
|
+
back.href.set(href);
|
|
91
|
+
back.label.set(this.backLabel.get() || DEFAULT_BACK_LABEL);
|
|
92
|
+
setOrRemove(back, "slot", href === "" ? "" : BREADCRUMB_SLOT);
|
|
93
|
+
}
|
|
94
|
+
renderTitle() {
|
|
95
|
+
const app = this.appName.get();
|
|
96
|
+
if (app === "" || !this.isConnected) return;
|
|
97
|
+
const heading = this.heading.get();
|
|
98
|
+
document.title = heading === "" ? app : `${heading}${TITLE_SEPARATOR}${app}`;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
JlPage.register();
|
|
102
|
+
export { JlPage, PAGE_WIDTHS };
|
package/dist/tokens.css
CHANGED
|
@@ -84,6 +84,13 @@
|
|
|
84
84
|
--jl-control-sm: 30px;
|
|
85
85
|
--jl-control-md: 36px;
|
|
86
86
|
--jl-control-lg: 44px;
|
|
87
|
+
/* The text people type in fields. */
|
|
88
|
+
--jl-control-font: var(--jl-font-md);
|
|
89
|
+
|
|
90
|
+
/* The widest a page gets: a form, most pages, and the tables and grids that need the room. */
|
|
91
|
+
--jl-page-form: 720px;
|
|
92
|
+
--jl-page-standard: 1120px;
|
|
93
|
+
--jl-page-wide: 1400px;
|
|
87
94
|
|
|
88
95
|
/* Flat: lines separate; only what floats (menus, dialogs, toasts) casts a shadow. */
|
|
89
96
|
--jl-shadow-sm: 0 1px 2px rgb(11 11 12 / 0.05);
|
|
@@ -185,4 +192,19 @@
|
|
|
185
192
|
--jl-shadow-lg: 0 18px 44px -12px rgb(0 0 0 / 0.7);
|
|
186
193
|
--jl-scrim: rgb(0 0 0 / 0.55);
|
|
187
194
|
}
|
|
195
|
+
|
|
196
|
+
/*
|
|
197
|
+
* Touch screens: controls a finger can hit (44px for most), and field text phones do not zoom into when it takes
|
|
198
|
+
* the focus (16px). Themed parts of a page re-declare the sizes, so they take these too.
|
|
199
|
+
*/
|
|
200
|
+
@media (pointer: coarse) {
|
|
201
|
+
:root,
|
|
202
|
+
[data-theme="light"],
|
|
203
|
+
[data-theme="dark"] {
|
|
204
|
+
--jl-control-sm: 36px;
|
|
205
|
+
--jl-control-md: 44px;
|
|
206
|
+
--jl-control-lg: 48px;
|
|
207
|
+
--jl-control-font: 16px;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
188
210
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Tone } from './options.types';
|
|
2
|
+
/**
|
|
3
|
+
* How one state of something shows as a badge: its word, its tone, its icon, and a sentence on what it means. One
|
|
4
|
+
* exhaustive map per kind of thing (`Record<OrderStatus, StatusLook>`) keeps every view saying a state the same way.
|
|
5
|
+
*/
|
|
6
|
+
export type StatusLook = {
|
|
7
|
+
label: string;
|
|
8
|
+
tone: Tone;
|
|
9
|
+
icon?: string;
|
|
10
|
+
hint?: string;
|
|
11
|
+
};
|
|
@@ -8,3 +8,18 @@ export type ConfirmOptions = {
|
|
|
8
8
|
cancelLabel?: string;
|
|
9
9
|
tone?: ConfirmTone;
|
|
10
10
|
};
|
|
11
|
+
/** What `guardLeave()` watches, and what it asks, in the app's words. */
|
|
12
|
+
export type LeaveGuardOptions = {
|
|
13
|
+
/** Whether leaving now would lose changes. */
|
|
14
|
+
isDirty: () => boolean;
|
|
15
|
+
/** Ends the guard, such as the killSignal of the page it guards. */
|
|
16
|
+
signal: AbortSignal;
|
|
17
|
+
/** "Leave without saving?" */
|
|
18
|
+
heading?: string;
|
|
19
|
+
/** "Your changes are lost." */
|
|
20
|
+
text?: string;
|
|
21
|
+
/** "Leave" */
|
|
22
|
+
leaveLabel?: string;
|
|
23
|
+
/** "Keep editing" */
|
|
24
|
+
stayLabel?: string;
|
|
25
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Where the data of a list or a page is: on its way, shown, there but empty, or failed to come. */
|
|
2
|
+
export type LoadState = 'loading' | 'ready' | 'empty' | 'error';
|
|
3
|
+
/** The shape the skeleton takes while the data comes: rows of a list, cards of a grid, or lines of text. */
|
|
4
|
+
export type LoadSkeleton = 'rows' | 'cards' | 'lines';
|
|
5
|
+
/** What `load()` needs: how to fetch the data, how to draw it, and whether it holds nothing to show. */
|
|
6
|
+
export type LoadTask<Value> = {
|
|
7
|
+
fetch: () => Promise<Value>;
|
|
8
|
+
draw: (value: Value) => void;
|
|
9
|
+
isEmpty?: (value: Value) => boolean;
|
|
10
|
+
};
|
|
@@ -8,7 +8,7 @@ export type ToastOptions = {
|
|
|
8
8
|
tone?: ToastTone;
|
|
9
9
|
/** An icon name; the tone's icon when absent. */
|
|
10
10
|
icon?: string;
|
|
11
|
-
/** How long it stays, in milliseconds; 0 keeps it until closed. */
|
|
11
|
+
/** How long it stays, in milliseconds: 5000, or 8000 for an error or with an action; 0 keeps it until closed. */
|
|
12
12
|
duration?: number;
|
|
13
13
|
/** Shows a close button; on by default. */
|
|
14
14
|
closable?: boolean;
|