@ternkit/tern 1.2.1 → 1.4.0
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/goscript/index.svelte.d.ts +32 -2
- package/dist/goscript/index.svelte.js +257 -31
- package/dist/goscript/patch.d.ts +6 -0
- package/dist/goscript/patch.js +25 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/runtime/validate.d.ts +31 -0
- package/dist/runtime/validate.js +168 -0
- package/dist/server/intl.js +55 -12
- package/dist/ui/Accordion.svelte +84 -0
- package/dist/ui/Accordion.svelte.d.ts +20 -0
- package/dist/ui/Alert.svelte +76 -0
- package/dist/ui/Alert.svelte.d.ts +12 -0
- package/dist/ui/AlertDialog.svelte +79 -0
- package/dist/ui/AlertDialog.svelte.d.ts +24 -0
- package/dist/ui/AreaChart.svelte +9 -0
- package/dist/ui/AreaChart.svelte.d.ts +26 -0
- package/dist/ui/AspectRatio.svelte +33 -0
- package/dist/ui/AspectRatio.svelte.d.ts +10 -0
- package/dist/ui/Avatar.svelte +48 -0
- package/dist/ui/Avatar.svelte.d.ts +10 -0
- package/dist/ui/Badge.svelte +54 -0
- package/dist/ui/Badge.svelte.d.ts +10 -0
- package/dist/ui/BarChart.svelte +170 -0
- package/dist/ui/BarChart.svelte.d.ts +40 -0
- package/dist/ui/Breadcrumb.svelte +92 -0
- package/dist/ui/Breadcrumb.svelte.d.ts +14 -0
- package/dist/ui/Button.svelte +136 -0
- package/dist/ui/Button.svelte.d.ts +18 -0
- package/dist/ui/ButtonGroup.svelte +61 -0
- package/dist/ui/ButtonGroup.svelte.d.ts +12 -0
- package/dist/ui/Calendar.svelte +265 -0
- package/dist/ui/Calendar.svelte.d.ts +28 -0
- package/dist/ui/Card.svelte +74 -0
- package/dist/ui/Card.svelte.d.ts +18 -0
- package/dist/ui/Carousel.svelte +169 -0
- package/dist/ui/Carousel.svelte.d.ts +36 -0
- package/dist/ui/ChartFrame.svelte +174 -0
- package/dist/ui/ChartFrame.svelte.d.ts +24 -0
- package/dist/ui/Checkbox.svelte +112 -0
- package/dist/ui/Checkbox.svelte.d.ts +14 -0
- package/dist/ui/Collapsible.svelte +59 -0
- package/dist/ui/Collapsible.svelte.d.ts +12 -0
- package/dist/ui/Combobox.svelte +350 -0
- package/dist/ui/Combobox.svelte.d.ts +24 -0
- package/dist/ui/Command.svelte +268 -0
- package/dist/ui/Command.svelte.d.ts +28 -0
- package/dist/ui/ConsentScreen.svelte +125 -0
- package/dist/ui/ConsentScreen.svelte.d.ts +21 -0
- package/dist/ui/ContextMenu.svelte +78 -0
- package/dist/ui/ContextMenu.svelte.d.ts +13 -0
- package/dist/ui/DataTable.svelte +277 -0
- package/dist/ui/DataTable.svelte.d.ts +53 -0
- package/dist/ui/DatePicker.svelte +138 -0
- package/dist/ui/DatePicker.svelte.d.ts +25 -0
- package/dist/ui/Dialog.svelte +301 -0
- package/dist/ui/Dialog.svelte.d.ts +30 -0
- package/dist/ui/DonutChart.svelte +115 -0
- package/dist/ui/DonutChart.svelte.d.ts +40 -0
- package/dist/ui/Drawer.svelte +19 -0
- package/dist/ui/Drawer.svelte.d.ts +14 -0
- package/dist/ui/Empty.svelte +62 -0
- package/dist/ui/Empty.svelte.d.ts +15 -0
- package/dist/ui/Field.svelte +97 -0
- package/dist/ui/Field.svelte.d.ts +19 -0
- package/dist/ui/Form.svelte +159 -0
- package/dist/ui/Form.svelte.d.ts +21 -0
- package/dist/ui/HoverCard.svelte +106 -0
- package/dist/ui/HoverCard.svelte.d.ts +26 -0
- package/dist/ui/Input.svelte +62 -0
- package/dist/ui/Input.svelte.d.ts +7 -0
- package/dist/ui/InputGroup.svelte +80 -0
- package/dist/ui/InputGroup.svelte.d.ts +13 -0
- package/dist/ui/InputOTP.svelte +140 -0
- package/dist/ui/InputOTP.svelte.d.ts +18 -0
- package/dist/ui/Item.svelte +86 -0
- package/dist/ui/Item.svelte.d.ts +17 -0
- package/dist/ui/Kbd.svelte +24 -0
- package/dist/ui/Kbd.svelte.d.ts +7 -0
- package/dist/ui/Label.svelte +29 -0
- package/dist/ui/Label.svelte.d.ts +10 -0
- package/dist/ui/LineChart.svelte +171 -0
- package/dist/ui/LineChart.svelte.d.ts +42 -0
- package/dist/ui/Menu.svelte +103 -0
- package/dist/ui/Menu.svelte.d.ts +15 -0
- package/dist/ui/MenuList.svelte +317 -0
- package/dist/ui/MenuList.svelte.d.ts +29 -0
- package/dist/ui/Menubar.svelte +133 -0
- package/dist/ui/Menubar.svelte.d.ts +14 -0
- package/dist/ui/NavigationMenu.svelte +208 -0
- package/dist/ui/NavigationMenu.svelte.d.ts +18 -0
- package/dist/ui/Pagination.svelte +114 -0
- package/dist/ui/Pagination.svelte.d.ts +16 -0
- package/dist/ui/PasswordInput.svelte +134 -0
- package/dist/ui/PasswordInput.svelte.d.ts +11 -0
- package/dist/ui/Popover.svelte +127 -0
- package/dist/ui/Popover.svelte.d.ts +29 -0
- package/dist/ui/Progress.svelte +73 -0
- package/dist/ui/Progress.svelte.d.ts +12 -0
- package/dist/ui/RadioGroup.svelte +105 -0
- package/dist/ui/RadioGroup.svelte.d.ts +21 -0
- package/dist/ui/Resizable.svelte +122 -0
- package/dist/ui/Resizable.svelte.d.ts +16 -0
- package/dist/ui/ScrollArea.svelte +43 -0
- package/dist/ui/ScrollArea.svelte.d.ts +13 -0
- package/dist/ui/Select.svelte +77 -0
- package/dist/ui/Select.svelte.d.ts +18 -0
- package/dist/ui/SelectMenu.svelte +301 -0
- package/dist/ui/SelectMenu.svelte.d.ts +18 -0
- package/dist/ui/Separator.svelte +19 -0
- package/dist/ui/Separator.svelte.d.ts +7 -0
- package/dist/ui/Sheet.svelte +21 -0
- package/dist/ui/Sheet.svelte.d.ts +16 -0
- package/dist/ui/Sidebar.svelte +263 -0
- package/dist/ui/Sidebar.svelte.d.ts +35 -0
- package/dist/ui/SignIn.svelte +182 -0
- package/dist/ui/SignIn.svelte.d.ts +38 -0
- package/dist/ui/SignUp.svelte +106 -0
- package/dist/ui/SignUp.svelte.d.ts +23 -0
- package/dist/ui/Skeleton.svelte +29 -0
- package/dist/ui/Skeleton.svelte.d.ts +9 -0
- package/dist/ui/Slider.svelte +196 -0
- package/dist/ui/Slider.svelte.d.ts +19 -0
- package/dist/ui/Sparkline.svelte +23 -0
- package/dist/ui/Sparkline.svelte.d.ts +11 -0
- package/dist/ui/Spinner.svelte +42 -0
- package/dist/ui/Spinner.svelte.d.ts +8 -0
- package/dist/ui/Stat.svelte +91 -0
- package/dist/ui/Stat.svelte.d.ts +18 -0
- package/dist/ui/Switch.svelte +90 -0
- package/dist/ui/Switch.svelte.d.ts +12 -0
- package/dist/ui/Table.svelte +70 -0
- package/dist/ui/Table.svelte.d.ts +36 -0
- package/dist/ui/Tabs.svelte +112 -0
- package/dist/ui/Tabs.svelte.d.ts +19 -0
- package/dist/ui/Textarea.svelte +52 -0
- package/dist/ui/Textarea.svelte.d.ts +7 -0
- package/dist/ui/Toaster.svelte +146 -0
- package/dist/ui/Toaster.svelte.d.ts +6 -0
- package/dist/ui/Toggle.svelte +82 -0
- package/dist/ui/Toggle.svelte.d.ts +17 -0
- package/dist/ui/ToggleGroup.svelte +143 -0
- package/dist/ui/ToggleGroup.svelte.d.ts +27 -0
- package/dist/ui/Tooltip.svelte +85 -0
- package/dist/ui/Tooltip.svelte.d.ts +16 -0
- package/dist/ui/chart.d.ts +26 -0
- package/dist/ui/chart.js +89 -0
- package/dist/ui/dates.d.ts +13 -0
- package/dist/ui/dates.js +64 -0
- package/dist/ui/field.d.ts +18 -0
- package/dist/ui/field.js +8 -0
- package/dist/ui/floating.d.ts +44 -0
- package/dist/ui/floating.js +97 -0
- package/dist/ui/form.d.ts +12 -0
- package/dist/ui/form.js +8 -0
- package/dist/ui/index.d.ts +78 -0
- package/dist/ui/index.js +70 -0
- package/dist/ui/menu.d.ts +25 -0
- package/dist/ui/menu.js +1 -0
- package/dist/ui/options.d.ts +17 -0
- package/dist/ui/options.js +22 -0
- package/dist/ui/table.d.ts +26 -0
- package/dist/ui/table.js +1 -0
- package/dist/ui/theme.css +176 -0
- package/dist/ui/toast.svelte.d.ts +19 -0
- package/dist/ui/toast.svelte.js +18 -0
- package/dist/vite/goscript.d.ts +14 -0
- package/dist/vite/goscript.js +45 -16
- package/dist/vite/index.js +15 -4
- package/package.json +7 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** An entry in a Menu, ContextMenu or Menubar. */
|
|
2
|
+
export type MenuItem = {
|
|
3
|
+
/** The text; also what typing a letter jumps to. */
|
|
4
|
+
label?: string;
|
|
5
|
+
onselect?: () => void;
|
|
6
|
+
/** Makes the item a link. */
|
|
7
|
+
href?: string;
|
|
8
|
+
danger?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
/** A keyboard shortcut to show, such as "⌘K". It's only shown: bind the key yourself. */
|
|
11
|
+
shortcut?: string;
|
|
12
|
+
/** For type "checkbox" or "radio": whether it's checked. Flip it in onselect. */
|
|
13
|
+
checked?: boolean;
|
|
14
|
+
type?: 'checkbox' | 'radio';
|
|
15
|
+
/** Items of a submenu, opened with ArrowRight, Enter or by hovering. */
|
|
16
|
+
items?: MenuItem[];
|
|
17
|
+
/** Draws a line instead of an item. */
|
|
18
|
+
separator?: boolean;
|
|
19
|
+
/** Starts a labelled group of the items after it. */
|
|
20
|
+
heading?: string;
|
|
21
|
+
};
|
|
22
|
+
export type MenuClose = {
|
|
23
|
+
all: boolean;
|
|
24
|
+
returnFocus: boolean;
|
|
25
|
+
};
|
package/dist/ui/menu.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** An option in a Combobox or SelectMenu. */
|
|
2
|
+
export type Option = {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
/** A second line, such as an email under a name. */
|
|
6
|
+
description?: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
/** Groups options under this heading. */
|
|
9
|
+
group?: string;
|
|
10
|
+
};
|
|
11
|
+
/** Matches when every word of the query starts a word of the text, or, from three letters, appears anywhere in it. Ignores case and accents. */
|
|
12
|
+
export declare function matches(text: string, query: string): boolean;
|
|
13
|
+
/** Splits options into groups, keeping their order. */
|
|
14
|
+
export declare function grouped(options: Option[]): {
|
|
15
|
+
group?: string;
|
|
16
|
+
options: Option[];
|
|
17
|
+
}[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Matches when every word of the query starts a word of the text, or, from three letters, appears anywhere in it. Ignores case and accents. */
|
|
2
|
+
export function matches(text, query) {
|
|
3
|
+
const norm = (s) => s.normalize('NFD').replace(/\p{Diacritic}/gu, '').toLowerCase();
|
|
4
|
+
const words = norm(text).split(/[\s\-_/.@]+/);
|
|
5
|
+
const hay = norm(text);
|
|
6
|
+
return norm(query)
|
|
7
|
+
.split(/\s+/)
|
|
8
|
+
.filter(Boolean)
|
|
9
|
+
.every((q) => words.some((w) => w.startsWith(q)) || (q.length >= 3 && hay.includes(q)));
|
|
10
|
+
}
|
|
11
|
+
/** Splits options into groups, keeping their order. */
|
|
12
|
+
export function grouped(options) {
|
|
13
|
+
const out = [];
|
|
14
|
+
for (const o of options) {
|
|
15
|
+
const last = out[out.length - 1];
|
|
16
|
+
if (last && last.group === o.group)
|
|
17
|
+
last.options.push(o);
|
|
18
|
+
else
|
|
19
|
+
out.push({ group: o.group, options: [o] });
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
/** A column of a Table or DataTable. */
|
|
3
|
+
export type Column<R> = {
|
|
4
|
+
/** The field shown, or an id when cell draws it. */
|
|
5
|
+
key: keyof R & string;
|
|
6
|
+
header: string;
|
|
7
|
+
/** end for numbers. */
|
|
8
|
+
align?: 'start' | 'end' | 'center';
|
|
9
|
+
/** Draws the cell instead of the value. */
|
|
10
|
+
cell?: Snippet<[R]>;
|
|
11
|
+
/** For DataTable: whether the column sorts. */
|
|
12
|
+
sortable?: boolean;
|
|
13
|
+
/** For DataTable: the value it sorts and filters by, if not the field. */
|
|
14
|
+
value?: (row: R) => string | number | Date | null | undefined;
|
|
15
|
+
width?: string;
|
|
16
|
+
};
|
|
17
|
+
/** What a DataTable shows: passed to onquery when the server sorts, searches and pages. */
|
|
18
|
+
export type DataQuery = {
|
|
19
|
+
page: number;
|
|
20
|
+
pageSize: number;
|
|
21
|
+
sort: {
|
|
22
|
+
key: string;
|
|
23
|
+
dir: 'asc' | 'desc';
|
|
24
|
+
} | null;
|
|
25
|
+
search: string;
|
|
26
|
+
};
|
package/dist/ui/table.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tern UI theme. Import once, in your root layout:
|
|
3
|
+
*
|
|
4
|
+
* import '@ternkit/tern/ui/theme.css';
|
|
5
|
+
*
|
|
6
|
+
* Every component reads these custom properties, so a theme is a set of
|
|
7
|
+
* overrides on :root (or any element, for a part of the page). Dark mode
|
|
8
|
+
* follows the system, or set data-theme="dark" / "light" on <html>.
|
|
9
|
+
*/
|
|
10
|
+
:root {
|
|
11
|
+
color-scheme: light;
|
|
12
|
+
--tern-font: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
|
|
13
|
+
--tern-font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
|
|
14
|
+
|
|
15
|
+
/* Surfaces and ink */
|
|
16
|
+
--tern-bg: oklch(0.99 0.004 220);
|
|
17
|
+
--tern-surface: oklch(1 0 0);
|
|
18
|
+
--tern-surface-2: oklch(0.97 0.006 220);
|
|
19
|
+
--tern-fg: oklch(0.24 0.02 240);
|
|
20
|
+
--tern-muted: oklch(0.5 0.02 240);
|
|
21
|
+
--tern-border: oklch(0.9 0.01 230);
|
|
22
|
+
--tern-border-strong: oklch(0.8 0.015 230);
|
|
23
|
+
|
|
24
|
+
/* The accent: a deep sea teal */
|
|
25
|
+
--tern-accent: oklch(0.52 0.1 205);
|
|
26
|
+
--tern-accent-hover: oklch(0.46 0.1 205);
|
|
27
|
+
--tern-accent-fg: oklch(0.99 0.01 205);
|
|
28
|
+
--tern-accent-soft: oklch(0.95 0.03 205);
|
|
29
|
+
|
|
30
|
+
--tern-danger: oklch(0.55 0.19 25);
|
|
31
|
+
--tern-danger-hover: oklch(0.49 0.19 25);
|
|
32
|
+
--tern-danger-fg: oklch(0.99 0 0);
|
|
33
|
+
--tern-danger-soft: oklch(0.96 0.03 25);
|
|
34
|
+
--tern-success: oklch(0.55 0.13 155);
|
|
35
|
+
--tern-success-soft: oklch(0.96 0.04 155);
|
|
36
|
+
--tern-warning: oklch(0.6 0.13 75);
|
|
37
|
+
--tern-warning-soft: oklch(0.97 0.05 85);
|
|
38
|
+
|
|
39
|
+
--tern-ring: oklch(0.6 0.12 205);
|
|
40
|
+
--tern-radius: 10px;
|
|
41
|
+
--tern-radius-sm: 7px;
|
|
42
|
+
--tern-shadow: 0 1px 2px oklch(0.24 0.02 240 / 0.06), 0 1px 1px oklch(0.24 0.02 240 / 0.04);
|
|
43
|
+
--tern-shadow-lg: 0 12px 32px -8px oklch(0.24 0.02 240 / 0.18), 0 2px 6px oklch(0.24 0.02 240 / 0.08);
|
|
44
|
+
--tern-control-height: 2.25rem;
|
|
45
|
+
/* Chart series, in order; validated for color vision deficiencies on these surfaces. */
|
|
46
|
+
--tern-chart-1: #2a78d6;
|
|
47
|
+
--tern-chart-2: #eb6834;
|
|
48
|
+
--tern-chart-3: #1baf7a;
|
|
49
|
+
--tern-chart-4: #eda100;
|
|
50
|
+
--tern-chart-5: #e87ba4;
|
|
51
|
+
--tern-chart-6: #008300;
|
|
52
|
+
--tern-chart-7: #6250d6;
|
|
53
|
+
--tern-chart-8: #e34948;
|
|
54
|
+
--tern-duration: 140ms;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@media (prefers-color-scheme: dark) {
|
|
58
|
+
:root:not([data-theme='light']) {
|
|
59
|
+
color-scheme: dark;
|
|
60
|
+
--tern-bg: oklch(0.17 0.015 240);
|
|
61
|
+
--tern-surface: oklch(0.21 0.017 240);
|
|
62
|
+
--tern-surface-2: oklch(0.25 0.018 240);
|
|
63
|
+
--tern-fg: oklch(0.94 0.01 230);
|
|
64
|
+
--tern-muted: oklch(0.7 0.02 230);
|
|
65
|
+
--tern-border: oklch(0.32 0.02 240);
|
|
66
|
+
--tern-border-strong: oklch(0.42 0.02 240);
|
|
67
|
+
--tern-accent: oklch(0.72 0.11 200);
|
|
68
|
+
--tern-accent-hover: oklch(0.78 0.1 200);
|
|
69
|
+
--tern-accent-fg: oklch(0.18 0.03 220);
|
|
70
|
+
--tern-accent-soft: oklch(0.3 0.05 205);
|
|
71
|
+
--tern-danger: oklch(0.7 0.17 25);
|
|
72
|
+
--tern-danger-hover: oklch(0.76 0.15 25);
|
|
73
|
+
--tern-danger-fg: oklch(0.18 0.04 25);
|
|
74
|
+
--tern-danger-soft: oklch(0.3 0.07 25);
|
|
75
|
+
--tern-success: oklch(0.72 0.14 155);
|
|
76
|
+
--tern-success-soft: oklch(0.29 0.05 155);
|
|
77
|
+
--tern-warning: oklch(0.78 0.13 80);
|
|
78
|
+
--tern-warning-soft: oklch(0.31 0.05 80);
|
|
79
|
+
--tern-ring: oklch(0.75 0.11 200);
|
|
80
|
+
--tern-shadow: 0 1px 2px oklch(0 0 0 / 0.4);
|
|
81
|
+
--tern-shadow-lg: 0 16px 40px -8px oklch(0 0 0 / 0.6), 0 2px 8px oklch(0 0 0 / 0.4);
|
|
82
|
+
--tern-chart-1: #3987e5;
|
|
83
|
+
--tern-chart-2: #d95926;
|
|
84
|
+
--tern-chart-3: #199e70;
|
|
85
|
+
--tern-chart-4: #c98500;
|
|
86
|
+
--tern-chart-5: #d55181;
|
|
87
|
+
--tern-chart-6: #008300;
|
|
88
|
+
--tern-chart-7: #9085e9;
|
|
89
|
+
--tern-chart-8: #e66767;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
:root[data-theme='dark'] {
|
|
94
|
+
color-scheme: dark;
|
|
95
|
+
--tern-bg: oklch(0.17 0.015 240);
|
|
96
|
+
--tern-surface: oklch(0.21 0.017 240);
|
|
97
|
+
--tern-surface-2: oklch(0.25 0.018 240);
|
|
98
|
+
--tern-fg: oklch(0.94 0.01 230);
|
|
99
|
+
--tern-muted: oklch(0.7 0.02 230);
|
|
100
|
+
--tern-border: oklch(0.32 0.02 240);
|
|
101
|
+
--tern-border-strong: oklch(0.42 0.02 240);
|
|
102
|
+
--tern-accent: oklch(0.72 0.11 200);
|
|
103
|
+
--tern-accent-hover: oklch(0.78 0.1 200);
|
|
104
|
+
--tern-accent-fg: oklch(0.18 0.03 220);
|
|
105
|
+
--tern-accent-soft: oklch(0.3 0.05 205);
|
|
106
|
+
--tern-danger: oklch(0.7 0.17 25);
|
|
107
|
+
--tern-danger-hover: oklch(0.76 0.15 25);
|
|
108
|
+
--tern-danger-fg: oklch(0.18 0.04 25);
|
|
109
|
+
--tern-danger-soft: oklch(0.3 0.07 25);
|
|
110
|
+
--tern-success: oklch(0.72 0.14 155);
|
|
111
|
+
--tern-success-soft: oklch(0.29 0.05 155);
|
|
112
|
+
--tern-warning: oklch(0.78 0.13 80);
|
|
113
|
+
--tern-warning-soft: oklch(0.31 0.05 80);
|
|
114
|
+
--tern-ring: oklch(0.75 0.11 200);
|
|
115
|
+
--tern-shadow: 0 1px 2px oklch(0 0 0 / 0.4);
|
|
116
|
+
--tern-shadow-lg: 0 16px 40px -8px oklch(0 0 0 / 0.6), 0 2px 8px oklch(0 0 0 / 0.4);
|
|
117
|
+
--tern-chart-1: #3987e5;
|
|
118
|
+
--tern-chart-2: #d95926;
|
|
119
|
+
--tern-chart-3: #199e70;
|
|
120
|
+
--tern-chart-4: #c98500;
|
|
121
|
+
--tern-chart-5: #d55181;
|
|
122
|
+
--tern-chart-6: #008300;
|
|
123
|
+
--tern-chart-7: #9085e9;
|
|
124
|
+
--tern-chart-8: #e66767;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@media (prefers-reduced-motion: reduce) {
|
|
128
|
+
:root {
|
|
129
|
+
--tern-duration: 0ms;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Base styles, opt-in with class="tern" on <body> or any container. */
|
|
134
|
+
.tern {
|
|
135
|
+
font-family: var(--tern-font);
|
|
136
|
+
color: var(--tern-fg);
|
|
137
|
+
background: var(--tern-bg);
|
|
138
|
+
line-height: 1.5;
|
|
139
|
+
-webkit-font-smoothing: antialiased;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Semantic tables: <table class="tern-table">. */
|
|
143
|
+
.tern-table {
|
|
144
|
+
width: 100%;
|
|
145
|
+
border-collapse: collapse;
|
|
146
|
+
font-size: 0.875rem;
|
|
147
|
+
}
|
|
148
|
+
.tern-table th {
|
|
149
|
+
text-align: start;
|
|
150
|
+
font-weight: 600;
|
|
151
|
+
color: var(--tern-muted);
|
|
152
|
+
font-size: 0.75rem;
|
|
153
|
+
text-transform: uppercase;
|
|
154
|
+
letter-spacing: 0.04em;
|
|
155
|
+
}
|
|
156
|
+
.tern-table th,
|
|
157
|
+
.tern-table td {
|
|
158
|
+
padding: 0.625rem 0.75rem;
|
|
159
|
+
border-bottom: 1px solid var(--tern-border);
|
|
160
|
+
}
|
|
161
|
+
.tern-table tbody tr:hover {
|
|
162
|
+
background: var(--tern-surface-2);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* Hidden visually, still read by screen readers. */
|
|
166
|
+
.tern-sr-only {
|
|
167
|
+
position: absolute;
|
|
168
|
+
width: 1px;
|
|
169
|
+
height: 1px;
|
|
170
|
+
padding: 0;
|
|
171
|
+
margin: -1px;
|
|
172
|
+
overflow: hidden;
|
|
173
|
+
clip: rect(0, 0, 0, 0);
|
|
174
|
+
white-space: nowrap;
|
|
175
|
+
border: 0;
|
|
176
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type Tone = 'neutral' | 'success' | 'danger' | 'warning';
|
|
2
|
+
export interface Toast {
|
|
3
|
+
id: number;
|
|
4
|
+
message: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
tone: Tone;
|
|
7
|
+
/** How long it stays, in milliseconds; 0 keeps it until dismissed. */
|
|
8
|
+
duration: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const toasts: Toast[];
|
|
11
|
+
/** Shows a toast and returns its id. */
|
|
12
|
+
export declare function toast(message: string, opts?: Partial<Omit<Toast, 'id' | 'message'>>): number;
|
|
13
|
+
export declare namespace toast {
|
|
14
|
+
var success: (message: string, opts?: Partial<Omit<Toast, "id" | "message" | "tone">>) => number;
|
|
15
|
+
var error: (message: string, opts?: Partial<Omit<Toast, "id" | "message" | "tone">>) => number;
|
|
16
|
+
var warning: (message: string, opts?: Partial<Omit<Toast, "id" | "message" | "tone">>) => number;
|
|
17
|
+
}
|
|
18
|
+
/** Removes a toast. */
|
|
19
|
+
export declare function dismiss(id: number): void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Toasts: short messages that confirm what happened, shown by <Toaster />.
|
|
2
|
+
let next = 1;
|
|
3
|
+
export const toasts = $state([]);
|
|
4
|
+
/** Shows a toast and returns its id. */
|
|
5
|
+
export function toast(message, opts = {}) {
|
|
6
|
+
const t = { id: next++, message, tone: 'neutral', duration: opts.tone === 'danger' ? 8000 : 5000, ...opts };
|
|
7
|
+
toasts.push(t);
|
|
8
|
+
return t.id;
|
|
9
|
+
}
|
|
10
|
+
/** Removes a toast. */
|
|
11
|
+
export function dismiss(id) {
|
|
12
|
+
const i = toasts.findIndex((t) => t.id === id);
|
|
13
|
+
if (i >= 0)
|
|
14
|
+
toasts.splice(i, 1);
|
|
15
|
+
}
|
|
16
|
+
toast.success = (message, opts) => toast(message, { ...opts, tone: 'success' });
|
|
17
|
+
toast.error = (message, opts) => toast(message, { ...opts, tone: 'danger' });
|
|
18
|
+
toast.warning = (message, opts) => toast(message, { ...opts, tone: 'warning' });
|
package/dist/vite/goscript.d.ts
CHANGED
|
@@ -6,6 +6,20 @@ export declare function exportedNames(source: string): {
|
|
|
6
6
|
values: string[];
|
|
7
7
|
funcs: string[];
|
|
8
8
|
};
|
|
9
|
+
/**
|
|
10
|
+
* The TypeScript that replaces a live component's Go script. The markup
|
|
11
|
+
* sees each State, Derived and Show value, each Func (callable, with
|
|
12
|
+
* .pending, .error, .optimistic and .debounce) and live: the connection,
|
|
13
|
+
* pending state, bindings, and live.props, everything the parent passed,
|
|
14
|
+
* such as children and event handlers.
|
|
15
|
+
*/
|
|
16
|
+
export declare function liveBindings(id: string, values: string[], funcs: string[]): string;
|
|
17
|
+
/**
|
|
18
|
+
* Wraps a live component's markup so it renders once the component has
|
|
19
|
+
* state (at once after a server render, after the first message after a
|
|
20
|
+
* client-side navigation), and embeds the server-rendered state.
|
|
21
|
+
*/
|
|
22
|
+
export declare function wrapLiveMarkup(content: string): string;
|
|
9
23
|
/** Replaces <script lang="go"> with the JavaScript that binds it to Go. */
|
|
10
24
|
export declare function goScriptPreprocessor(getRoot: () => string): PreprocessorGroup;
|
|
11
25
|
/** Builds the Go code at startup and on changes. */
|
package/dist/vite/goscript.js
CHANGED
|
@@ -136,6 +136,46 @@ function initialState(root, id) {
|
|
|
136
136
|
return {};
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* The TypeScript that replaces a live component's Go script. The markup
|
|
141
|
+
* sees each State, Derived and Show value, each Func (callable, with
|
|
142
|
+
* .pending, .error, .optimistic and .debounce) and live: the connection,
|
|
143
|
+
* pending state, bindings, and live.props, everything the parent passed,
|
|
144
|
+
* such as children and event handlers.
|
|
145
|
+
*/
|
|
146
|
+
export function liveBindings(id, values, funcs) {
|
|
147
|
+
const taken = new Set([...values, ...funcs]);
|
|
148
|
+
let code = `
|
|
149
|
+
import { useLive } from '@ternkit/tern/goscript';
|
|
150
|
+
let __goProps = $props();
|
|
151
|
+
const __goUID = $props.id();
|
|
152
|
+
const __go = useLive(${JSON.stringify(id)}, __goUID, () => ({ ...__goProps }));
|
|
153
|
+
`;
|
|
154
|
+
if (!taken.has('live'))
|
|
155
|
+
code += '\tconst live = __go;\n';
|
|
156
|
+
for (const v of values)
|
|
157
|
+
code += `\tconst ${v} = $derived(__go.state[${JSON.stringify(v)}] as any);\n`;
|
|
158
|
+
for (const f of funcs)
|
|
159
|
+
code += `\tconst ${f}: any = __go.fn(${JSON.stringify(f)});\n`;
|
|
160
|
+
return code;
|
|
161
|
+
}
|
|
162
|
+
/** Top-level blocks that stay outside the markup's {#if}. */
|
|
163
|
+
const OUTSIDE = /<script\b[\s\S]*?<\/script>|<style\b[\s\S]*?<\/style>|<svelte:head\b[\s\S]*?<\/svelte:head>|<svelte:(?:options|window|document|body)\b[^>]*?\/>|<svelte:(window|document|body)\b[^>]*?>[\s\S]*?<\/svelte:\1>/g;
|
|
164
|
+
/**
|
|
165
|
+
* Wraps a live component's markup so it renders once the component has
|
|
166
|
+
* state (at once after a server render, after the first message after a
|
|
167
|
+
* client-side navigation), and embeds the server-rendered state.
|
|
168
|
+
*/
|
|
169
|
+
export function wrapLiveMarkup(content) {
|
|
170
|
+
const kept = [];
|
|
171
|
+
let markup = content.replace(OUTSIDE, (block) => {
|
|
172
|
+
kept.push(block);
|
|
173
|
+
// Keep line numbers for the markup's compile errors.
|
|
174
|
+
return '\n'.repeat(block.split('\n').length - 1);
|
|
175
|
+
});
|
|
176
|
+
markup = markup.trim() ? `{#if __go.loaded}${markup}{/if}` : markup;
|
|
177
|
+
return markup + '\n' + kept.join('\n') + '\n<svelte:head>{@html __go.stateScript}</svelte:head>\n';
|
|
178
|
+
}
|
|
139
179
|
/** Replaces <script lang="go"> with the JavaScript that binds it to Go. */
|
|
140
180
|
export function goScriptPreprocessor(getRoot) {
|
|
141
181
|
return {
|
|
@@ -146,30 +186,19 @@ export function goScriptPreprocessor(getRoot) {
|
|
|
146
186
|
const m = GO_SCRIPT.exec(content);
|
|
147
187
|
if (!m || !/(^|\s)live(\s|=|$)/.test(m[1]))
|
|
148
188
|
return;
|
|
149
|
-
return { code: content
|
|
189
|
+
return { code: wrapLiveMarkup(content) };
|
|
150
190
|
},
|
|
151
191
|
script({ content, attributes, filename }) {
|
|
152
192
|
if (attributes.lang !== 'go' || !filename)
|
|
153
193
|
return;
|
|
154
194
|
const root = getRoot();
|
|
155
|
-
if (!goScriptEnabled(root)) {
|
|
156
|
-
throw new Error(`${filename}: <script lang="go"> is experimental; enable it with "experimental": { "goScript": true } in tern.json`);
|
|
157
|
-
}
|
|
158
195
|
const id = componentID(root, filename);
|
|
159
196
|
const { values, funcs } = exportedNames(content);
|
|
160
197
|
const { lang: _lang, live, ...rest } = attributes;
|
|
161
|
-
if (live)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const __goUID = $props.id();
|
|
166
|
-
const __go = useLive(${JSON.stringify(id)}, __goUID, () => ({ ...__goProps }));
|
|
167
|
-
`;
|
|
168
|
-
for (const v of values)
|
|
169
|
-
code += `\tconst ${v} = $derived(__go.state[${JSON.stringify(v)}] as any);\n`;
|
|
170
|
-
for (const f of funcs)
|
|
171
|
-
code += `\tconst ${f} = (...args: unknown[]): any => __go.call(${JSON.stringify(f)}, ...args);\n`;
|
|
172
|
-
return { code, attributes: { ...rest, lang: 'ts' } };
|
|
198
|
+
if (live)
|
|
199
|
+
return { code: liveBindings(id, values, funcs), attributes: { ...rest, lang: 'ts' } };
|
|
200
|
+
if (!goScriptEnabled(root)) {
|
|
201
|
+
throw new Error(`${filename}: <script lang="go"> in WebAssembly is experimental; enable it with "experimental": { "goScript": true } in tern.json, or add live to run it on the server`);
|
|
173
202
|
}
|
|
174
203
|
const base = path.join(root, DIR).split(path.sep).join('/');
|
|
175
204
|
let code = `
|
package/dist/vite/index.js
CHANGED
|
@@ -66,7 +66,7 @@ export function tern(options = {}) {
|
|
|
66
66
|
target: 'es2022',
|
|
67
67
|
rolldownOptions: {
|
|
68
68
|
input: source,
|
|
69
|
-
output: { format: 'iife', entryFileNames: 'service-worker.js' }
|
|
69
|
+
output: { format: 'iife', entryFileNames: 'service-worker.js', banner: '"use strict";' }
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
};
|
|
@@ -84,7 +84,10 @@ export function tern(options = {}) {
|
|
|
84
84
|
target: 'es2023',
|
|
85
85
|
rolldownOptions: {
|
|
86
86
|
input: path.join(root, SERVER_ENTRY),
|
|
87
|
-
|
|
87
|
+
// Strict, like the modules it is built from: the minifier's output
|
|
88
|
+
// assumes it, and in sloppy mode a renamed block-level function can
|
|
89
|
+
// shadow a variable (Annex B), which made bindings loop forever.
|
|
90
|
+
output: { format: 'iife', name: '__tern_server', entryFileNames: 'server.js', banner: '"use strict";' }
|
|
88
91
|
}
|
|
89
92
|
},
|
|
90
93
|
// One self-contained file: the renderer runs in an embedded engine
|
|
@@ -125,8 +128,16 @@ export function tern(options = {}) {
|
|
|
125
128
|
}
|
|
126
129
|
};
|
|
127
130
|
},
|
|
128
|
-
resolveId(id) {
|
|
129
|
-
|
|
131
|
+
resolveId(id, importer) {
|
|
132
|
+
if (id === SW_MODULE)
|
|
133
|
+
return '\0' + SW_MODULE;
|
|
134
|
+
// ./$forms sits next to ./$types, in .tern/types, written by tern gen.
|
|
135
|
+
if (id === './$forms' && importer) {
|
|
136
|
+
const dir = path.relative(root, path.dirname(importer.split('?')[0]));
|
|
137
|
+
if (!dir.startsWith('..'))
|
|
138
|
+
return path.join(root, '.tern/types', dir, '$forms.js');
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
130
141
|
},
|
|
131
142
|
load(id) {
|
|
132
143
|
if (id !== '\0' + SW_MODULE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ternkit/tern",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Client runtime and Vite plugin for Tern: Svelte on the client, Go on the server",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -34,6 +34,12 @@
|
|
|
34
34
|
"svelte": "./dist/goscript/index.svelte.js",
|
|
35
35
|
"default": "./dist/goscript/index.svelte.js"
|
|
36
36
|
},
|
|
37
|
+
"./ui": {
|
|
38
|
+
"types": "./dist/ui/index.d.ts",
|
|
39
|
+
"svelte": "./dist/ui/index.js",
|
|
40
|
+
"default": "./dist/ui/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./ui/theme.css": "./dist/ui/theme.css",
|
|
37
43
|
"./server": {
|
|
38
44
|
"types": "./dist/server/index.d.ts",
|
|
39
45
|
"svelte": "./dist/server/index.js",
|