staffa 0.1.0 → 0.3.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/README.md +161 -97
- package/dist/components/autocomplete.js +21 -20
- package/dist/components/box.d.ts +8 -6
- package/dist/components/box.js +16 -12
- package/dist/components/button.d.ts +21 -35
- package/dist/components/button.js +46 -39
- package/dist/components/buttonChooser.d.ts +41 -0
- package/dist/components/buttonChooser.js +38 -0
- package/dist/components/buttonGroup.d.ts +3 -3
- package/dist/components/buttonGroup.js +18 -21
- package/dist/components/checkbox.js +7 -7
- package/dist/components/dialog.d.ts +20 -25
- package/dist/components/dialog.js +81 -91
- package/dist/components/field.d.ts +8 -6
- package/dist/components/field.js +16 -18
- package/dist/components/form.d.ts +3 -3
- package/dist/components/form.js +4 -4
- package/dist/components/main.d.ts +41 -14
- package/dist/components/main.js +193 -53
- package/dist/components/menu.d.ts +118 -0
- package/dist/components/menu.js +218 -0
- package/dist/components/select.d.ts +1 -1
- package/dist/components/select.js +5 -5
- package/dist/components/tabs.d.ts +5 -5
- package/dist/components/tabs.js +15 -22
- package/dist/components/textarea.js +4 -4
- package/dist/components/textline.js +1 -1
- package/dist/components/toast.d.ts +37 -0
- package/dist/components/toast.js +79 -0
- package/dist/components/tooltip.d.ts +32 -0
- package/dist/components/tooltip.js +130 -0
- package/dist/core.d.ts +26 -39
- package/dist/core.js +6 -5
- package/dist/icons-helpers.d.ts +46 -0
- package/dist/icons-helpers.js +44 -0
- package/dist/icons.d.ts +1960 -0
- package/dist/icons.js +1972 -0
- package/dist/index.d.ts +21 -8
- package/dist/index.js +17 -8
- package/dist/staffa.esm.js +1 -0
- package/dist/theme.d.ts +9 -75
- package/dist/theme.js +279 -82
- package/package.json +12 -5
- package/src/components/autocomplete.ts +21 -20
- package/src/components/box.ts +21 -15
- package/src/components/button.ts +59 -75
- package/src/components/buttonChooser.ts +65 -0
- package/src/components/buttonGroup.ts +18 -21
- package/src/components/checkbox.ts +7 -7
- package/src/components/dialog.ts +101 -102
- package/src/components/field.ts +22 -22
- package/src/components/form.ts +7 -7
- package/src/components/main.ts +212 -52
- package/src/components/menu.ts +288 -0
- package/src/components/select.ts +4 -4
- package/src/components/tabs.ts +20 -27
- package/src/components/textarea.ts +4 -4
- package/src/components/textline.ts +1 -1
- package/src/components/toast.ts +115 -0
- package/src/components/tooltip.ts +139 -0
- package/src/core.ts +26 -40
- package/src/icons-helpers.ts +90 -0
- package/src/icons.ts +1977 -0
- package/src/index.ts +21 -8
- package/src/theme.ts +300 -135
- package/dist/components/modal.d.ts +0 -2
- package/dist/components/modal.js +0 -2
- package/dist/skye.esm.js +0 -1
package/src/index.ts
CHANGED
|
@@ -30,21 +30,26 @@
|
|
|
30
30
|
* mutate it. See `AGENTS.md` for the design philosophy.
|
|
31
31
|
*/
|
|
32
32
|
// Importing the theme module installs spacing vars, the reactive theme and the
|
|
33
|
-
// base stylesheet. Customise
|
|
34
|
-
|
|
33
|
+
// base stylesheet. Customise it from your app with A.insertGlobalCss (see
|
|
34
|
+
// theme.ts); toggle modes with setDarkMode / getDarkMode.
|
|
35
|
+
import { setDarkMode, getDarkMode } from "./theme.js";
|
|
35
36
|
|
|
36
37
|
import { autocomplete } from "./components/autocomplete.js";
|
|
37
38
|
import { box } from "./components/box.js";
|
|
38
39
|
import { button } from "./components/button.js";
|
|
40
|
+
import { buttonChooser } from "./components/buttonChooser.js";
|
|
39
41
|
import { buttonGroup } from "./components/buttonGroup.js";
|
|
40
42
|
import { checkbox } from "./components/checkbox.js";
|
|
41
43
|
import { form } from "./components/form.js";
|
|
42
44
|
import { main } from "./components/main.js";
|
|
45
|
+
import { menuButton, showFloatingMenu } from "./components/menu.js";
|
|
43
46
|
import { dialog, alert, confirm, prompt } from "./components/dialog.js";
|
|
44
47
|
import { select } from "./components/select.js";
|
|
45
48
|
import { tabs } from "./components/tabs.js";
|
|
46
49
|
import { textarea } from "./components/textarea.js";
|
|
47
50
|
import { textline } from "./components/textline.js";
|
|
51
|
+
import { toast } from "./components/toast.js";
|
|
52
|
+
import { addTooltip } from "./components/tooltip.js";
|
|
48
53
|
|
|
49
54
|
/** The Staffa component namespace. */
|
|
50
55
|
export const S = {
|
|
@@ -55,16 +60,19 @@ export const S = {
|
|
|
55
60
|
confirm,
|
|
56
61
|
prompt,
|
|
57
62
|
form,
|
|
63
|
+
menuButton,
|
|
64
|
+
showFloatingMenu,
|
|
58
65
|
textline,
|
|
59
66
|
textarea,
|
|
60
67
|
checkbox,
|
|
61
68
|
tabs,
|
|
62
69
|
button,
|
|
70
|
+
buttonChooser,
|
|
63
71
|
buttonGroup,
|
|
64
72
|
autocomplete,
|
|
65
73
|
select,
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
toast,
|
|
75
|
+
addTooltip,
|
|
68
76
|
setDarkMode,
|
|
69
77
|
getDarkMode,
|
|
70
78
|
};
|
|
@@ -72,26 +80,31 @@ export const S = {
|
|
|
72
80
|
export default S;
|
|
73
81
|
|
|
74
82
|
// Re-export theming and shared types for advanced use.
|
|
75
|
-
export {
|
|
83
|
+
export { setDarkMode, getDarkMode } from "./theme.js";
|
|
84
|
+
export type { SurfaceRole, Variant } from "./theme.js";
|
|
76
85
|
export type {
|
|
77
|
-
BaseOptions,
|
|
78
86
|
ContentOptions,
|
|
79
87
|
Bindable,
|
|
80
88
|
Content,
|
|
81
89
|
Slot,
|
|
82
|
-
Styling,
|
|
90
|
+
Attributes as Styling,
|
|
83
91
|
} from "./core.js";
|
|
84
92
|
export { drawSlot, uniqueId } from "./core.js";
|
|
85
93
|
|
|
86
94
|
export type { FieldOptions } from "./components/field.js";
|
|
87
95
|
export type { MainOptions } from "./components/main.js";
|
|
96
|
+
export type { MenuOptions, MenuEntry, MenuItem, MenuSeparator, FloatingMenuOptions } from "./components/menu.js";
|
|
97
|
+
export { drawMenu } from "./components/menu.js";
|
|
98
|
+
export type { ToastOptions } from "./components/toast.js";
|
|
99
|
+
export type { TooltipOptions } from "./components/tooltip.js";
|
|
88
100
|
export type { BoxOptions } from "./components/box.js";
|
|
89
101
|
export type { FormOptions } from "./components/form.js";
|
|
90
102
|
export type { TextlineOptions, TextlineType } from "./components/textline.js";
|
|
91
103
|
export type { TextareaOptions } from "./components/textarea.js";
|
|
92
104
|
export type { CheckboxOptions } from "./components/checkbox.js";
|
|
93
105
|
export type { Tab, TabsOptions } from "./components/tabs.js";
|
|
94
|
-
export type { ButtonOptions
|
|
106
|
+
export type { ButtonOptions } from "./components/button.js";
|
|
107
|
+
export type { ButtonChooserOptions } from "./components/buttonChooser.js";
|
|
95
108
|
export type { ButtonGroupOptions } from "./components/buttonGroup.js";
|
|
96
109
|
export type { AutocompleteOptions, AutocompleteOptionInput } from "./components/autocomplete.js";
|
|
97
110
|
export type { SelectOptions, SelectOptionInput } from "./components/select.js";
|
package/src/theme.ts
CHANGED
|
@@ -1,126 +1,102 @@
|
|
|
1
1
|
import A from "aberdeen";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Staffa is themed entirely through CSS custom properties (via Aberdeen's
|
|
7
|
-
* {@link A.cssVars}). Components reference these with `var(--sPrimary)` etc., so
|
|
8
|
-
* changing a single variable restyles the whole app — at runtime, reactively.
|
|
9
|
-
*
|
|
10
|
-
* Unlike typical Aberdeen apps (which use component-local `insertCss`), Staffa uses
|
|
11
|
-
* **global** CSS (`insertGlobalCss`) with class names prefixed `S_`. This is a
|
|
12
|
-
* deliberate trade-off: it lets application authors override any Staffa style from
|
|
13
|
-
* their own stylesheet without fighting scoped class names.
|
|
4
|
+
* The named accent roles for interactive elements (buttons, tabs, badges, …).
|
|
5
|
+
* Each maps to a `.s-s.<role>` class that sets `--s-a` (ink) and `--s-b` (fill).
|
|
14
6
|
*/
|
|
7
|
+
export type SurfaceRole = "primary" | "secondary" | "gradient" | "neutral" | "danger" | "success" | "warning";
|
|
15
8
|
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
* length strings. Override any subset by mutating {@link darkTheme} /
|
|
19
|
-
* {@link lightTheme}.
|
|
20
|
-
*/
|
|
21
|
-
export interface Theme {
|
|
22
|
-
/** Page background — the darkest surface. */
|
|
23
|
-
sBg: string;
|
|
24
|
-
/** Default surface for cards, inputs, menus. */
|
|
25
|
-
sSurface: string;
|
|
26
|
-
/** Raised surface for headers, footers, chips, hover states. */
|
|
27
|
-
sSurfaceHi: string;
|
|
28
|
-
/** Primary foreground / text color. */
|
|
29
|
-
sFg: string;
|
|
30
|
-
/** Muted text (help text, subtitles). */
|
|
31
|
-
sFgMuted: string;
|
|
32
|
-
/** Faint text (placeholders, disabled). */
|
|
33
|
-
sFgFaint: string;
|
|
34
|
-
/** Default border color. */
|
|
35
|
-
sBorder: string;
|
|
36
|
-
/** Stronger border / neutral control color. */
|
|
37
|
-
sBorderStrong: string;
|
|
38
|
-
/** Brand / accent color. */
|
|
39
|
-
sPrimary: string;
|
|
40
|
-
/** Brand color, hover/brighter. */
|
|
41
|
-
sPrimaryHover: string;
|
|
42
|
-
/** Text drawn on top of {@link Theme.sPrimary}. */
|
|
43
|
-
sPrimaryFg: string;
|
|
44
|
-
/** Destructive / error color. */
|
|
45
|
-
sDanger: string;
|
|
46
|
-
/** Positive / success color. */
|
|
47
|
-
sSuccess: string;
|
|
48
|
-
/** Caution color. */
|
|
49
|
-
sWarning: string;
|
|
50
|
-
/** Focus-ring color (usually a translucent primary). */
|
|
51
|
-
sFocus: string;
|
|
52
|
-
/** Default corner radius. */
|
|
53
|
-
sRadius: string;
|
|
54
|
-
/** Larger corner radius (e.g. the {@link import("./components/main").main} sheet). */
|
|
55
|
-
sRadiusLg: string;
|
|
56
|
-
/** Elevation shadow for menus, dialogs, the framed content sheet. */
|
|
57
|
-
sShadow: string;
|
|
58
|
-
}
|
|
9
|
+
/** How a surface's two colours are rendered. `filled` is the default. */
|
|
10
|
+
export type Variant = "filled" | "tonal" | "outlined";
|
|
59
11
|
|
|
60
12
|
/**
|
|
61
|
-
*
|
|
62
|
-
* stands out of the box.
|
|
13
|
+
* Theming and global base styles for Staffa.
|
|
63
14
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
sFgMuted: "#a6acba",
|
|
74
|
-
sFgFaint: "#6b7280",
|
|
75
|
-
sBorder: "#2c313c",
|
|
76
|
-
sBorderStrong: "#3c4352",
|
|
77
|
-
sPrimary: "#8b7bff",
|
|
78
|
-
sPrimaryHover: "#a99dff",
|
|
79
|
-
sPrimaryFg: "#0c0a1a",
|
|
80
|
-
sDanger: "#ff6b6b",
|
|
81
|
-
sSuccess: "#46d39a",
|
|
82
|
-
sWarning: "#fbbf24",
|
|
83
|
-
sFocus: "rgba(139, 123, 255, 0.45)",
|
|
84
|
-
sRadius: "10px",
|
|
85
|
-
sRadiusLg: "16px",
|
|
86
|
-
sShadow: "0 8px 30px rgba(0, 0, 0, 0.45)",
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* The light Staffa theme — the same lavender brand, retuned for a bright,
|
|
91
|
-
* modern surface: white cards on a soft grey page, a deeper primary so it
|
|
92
|
-
* reads well on light backgrounds, and a softer elevation shadow.
|
|
15
|
+
* # The surface model
|
|
16
|
+
*
|
|
17
|
+
* A Staffa app is a tree of **surfaces**. A surface is anything with its own
|
|
18
|
+
* background and the text colour that goes on it — the page, a card, a raised
|
|
19
|
+
* header, a coloured button. Mark an element as a surface with the `.s-s` class,
|
|
20
|
+
* then add modifier classes to colour it. A surface carries two colours:
|
|
21
|
+
*
|
|
22
|
+
* - `--s-a` — its default **foreground** (ink)
|
|
23
|
+
* - `--s-b` — its default **background** (fill)
|
|
93
24
|
*
|
|
94
|
-
*
|
|
25
|
+
* set by a **level** modifier — `.base` (the page), `.panel` (the default card),
|
|
26
|
+
* `.raised` (elevated chrome) — or an **accent role** modifier — `.primary`,
|
|
27
|
+
* `.secondary`, `.gradient` (the brand sweep), `.neutral`, `.danger`,
|
|
28
|
+
* `.success`, `.warning`.
|
|
29
|
+
*
|
|
30
|
+
* A **variant** modifier — `.filled` (the default), `.tonal` or `.outlined` —
|
|
31
|
+
* decides how `--s-a`/`--s-b` map onto the tokens widgets read
|
|
32
|
+
* (`--s-fg`/`--s-bg`). A shared rule then derives muted/faint/border from that
|
|
33
|
+
* pair and paints the element. Because the derivation reads `$s-fg`/`$s-bg`,
|
|
34
|
+
* every surface gets its *own* legible secondary colours: drop a widget on any
|
|
35
|
+
* surface and it adapts. (`:root` is an implicit filled surface, so the page
|
|
36
|
+
* renders without extra classes.)
|
|
37
|
+
*
|
|
38
|
+
* Components build surfaces by combining classes, e.g.
|
|
39
|
+
* `A("div.s-s.panel.outlined", opts.attrs)` — and because `opts.attrs` is the
|
|
40
|
+
* caller's escape hatch, passing e.g. `.filled` or `.danger` overrides the
|
|
41
|
+
* default look.
|
|
42
|
+
*
|
|
43
|
+
* | token | meaning |
|
|
44
|
+
* | ---------------- | ---------------------------------------- |
|
|
45
|
+
* | `--s-fg` | default text |
|
|
46
|
+
* | `--s-bg` | background |
|
|
47
|
+
* | `--s-fg-muted` | secondary text (subtitles, help) |
|
|
48
|
+
* | `--s-fg-faint` | placeholders, disabled |
|
|
49
|
+
* | `--s-border` / `--s-border-strong` | borders |
|
|
50
|
+
* | `--s-accent` | brand "pop" colour (active indicators, etc.) |
|
|
51
|
+
* | `--s-gradient` | primary→secondary brand sweep (mark, primary buttons, active nav) |
|
|
52
|
+
* | `--s-glow` | soft coloured shadow for lit brand elements |
|
|
53
|
+
* | `--s-link` / `--s-focus` | link & focus-ring colours |
|
|
54
|
+
* | `--s-radius` / `--s-radius-lg` / `--s-shadow` | shape tokens |
|
|
55
|
+
*
|
|
56
|
+
* `--s-accent` and `--s-link` default to the brand / link colour, but on a
|
|
57
|
+
* bright coloured surface (`.primary`, `.danger`, …) they fall back to that
|
|
58
|
+
* surface's own ink so they stay legible.
|
|
59
|
+
*
|
|
60
|
+
* # The palette
|
|
61
|
+
*
|
|
62
|
+
* All colours come from a small set of named **palette** tokens on `:root`, set
|
|
63
|
+
* per mode — the only place colours live, and the single place to re-skin:
|
|
64
|
+
* `--s-primary`, `--s-secondary` (the two ends of `--s-gradient`), `--s-danger`,
|
|
65
|
+
* `--s-success`, `--s-warning` (accent fills, which
|
|
66
|
+
* double as semantic *ink* on neutral surfaces), `--s-neutral`, `--s-page`,
|
|
67
|
+
* `--s-panel`, `--s-raised` (neutral fills), `--s-ink` (text on neutral) and
|
|
68
|
+
* `--s-on-accent` (text on accent fills), plus `--s-link`/`--s-focus` and the
|
|
69
|
+
* shape tokens. Every surface rule is wired to these, so they adapt with the
|
|
70
|
+
* mode and with any override.
|
|
71
|
+
*
|
|
72
|
+
* # Variants
|
|
73
|
+
*
|
|
74
|
+
* Because the variant decides how `--s-a`/`--s-b` become `--s-fg`/`--s-bg`, the
|
|
75
|
+
* three looks are generic and work on *any* role: `.tonal` reads the fill colour
|
|
76
|
+
* as ink over a soft self-tint; `.outlined` reads it as ink over a transparent
|
|
77
|
+
* fill with a coloured edge (inheriting the parent's background, so its derived
|
|
78
|
+
* tokens read the real surroundings). Inside any of them `--s-fg`/`--s-bg` still
|
|
79
|
+
* describe the real, rendered colours.
|
|
80
|
+
*
|
|
81
|
+
* # Customising
|
|
82
|
+
*
|
|
83
|
+
* There's no JS theme object — the colours live in the palette `insertGlobalCss`
|
|
84
|
+
* call below, branched on {@link getDarkMode}. Re-skin from your app by
|
|
85
|
+
* overriding palette tokens (per mode if you like), or give a surface an
|
|
86
|
+
* image/gradient background (set `--s-b` to the dominant fallback colour so
|
|
87
|
+
* derived tokens stay sensible). Staffa uses global, `s-`-prefixed classes, so
|
|
88
|
+
* nothing is scoped away from you.
|
|
89
|
+
*
|
|
90
|
+
* ```ts
|
|
91
|
+
* A(() => A.insertGlobalCss({ ":root": getDarkMode() ? "--s-primary:#28c4a0" : "--s-primary:#1f9d6b" }));
|
|
92
|
+
* A.insertGlobalCss({ ".s-s.panel": "background: url(paper.png); --s-b: #efe9dd" });
|
|
93
|
+
* ```
|
|
95
94
|
*/
|
|
96
|
-
|
|
97
|
-
sBg: "#f3f4f8",
|
|
98
|
-
sSurface: "#ffffff",
|
|
99
|
-
sSurfaceHi: "#eceef4",
|
|
100
|
-
sFg: "#1b1e27",
|
|
101
|
-
sFgMuted: "#5b6273",
|
|
102
|
-
sFgFaint: "#9aa1b2",
|
|
103
|
-
sBorder: "#e2e5ee",
|
|
104
|
-
sBorderStrong: "#c7ccda",
|
|
105
|
-
sPrimary: "#6c5ce7",
|
|
106
|
-
sPrimaryHover: "#5847d4",
|
|
107
|
-
sPrimaryFg: "#ffffff",
|
|
108
|
-
sDanger: "#e23b3b",
|
|
109
|
-
sSuccess: "#1f9d6b",
|
|
110
|
-
sWarning: "#d97706",
|
|
111
|
-
sFocus: "rgba(108, 92, 231, 0.35)",
|
|
112
|
-
sRadius: "10px",
|
|
113
|
-
sRadiusLg: "16px",
|
|
114
|
-
sShadow: "0 6px 24px rgba(20, 24, 40, 0.12)",
|
|
115
|
-
});
|
|
95
|
+
|
|
116
96
|
|
|
117
97
|
const STORAGE_KEY = "staffa:darkMode";
|
|
118
98
|
|
|
119
|
-
/**
|
|
120
|
-
* The explicit dark-mode choice — `true` (force dark), `false` (force light) or
|
|
121
|
-
* `undefined` (follow the OS via {@link A.darkMode}). A reactive proxy, seeded
|
|
122
|
-
* from localStorage so the persisted preference applies on the first paint.
|
|
123
|
-
*/
|
|
99
|
+
/** The explicit dark-mode choice; `undefined` follows the OS via {@link A.darkMode}. */
|
|
124
100
|
const $override = A.proxy<{ value: boolean | undefined }>({ value: readStoredOverride() });
|
|
125
101
|
|
|
126
102
|
/** Read the persisted dark-mode override from localStorage (defensively). */
|
|
@@ -137,8 +113,7 @@ function readStoredOverride(): boolean | undefined {
|
|
|
137
113
|
|
|
138
114
|
/**
|
|
139
115
|
* Force dark mode (`true`), light mode (`false`), or follow the OS preference
|
|
140
|
-
* (`undefined`). Takes effect immediately and is persisted to localStorage
|
|
141
|
-
* the choice survives reloads.
|
|
116
|
+
* (`undefined`). Takes effect immediately and is persisted to localStorage.
|
|
142
117
|
*/
|
|
143
118
|
export function setDarkMode(value: boolean | undefined): void {
|
|
144
119
|
$override.value = value;
|
|
@@ -154,42 +129,232 @@ export function setDarkMode(value: boolean | undefined): void {
|
|
|
154
129
|
* Whether dark mode is currently active. Reactive — read it inside a scope to
|
|
155
130
|
* re-run on changes.
|
|
156
131
|
*
|
|
157
|
-
* @param allowAuto - When `true`, returns `undefined` (rather than
|
|
158
|
-
*
|
|
159
|
-
*
|
|
132
|
+
* @param allowAuto - When `true`, returns `undefined` (rather than a boolean) if
|
|
133
|
+
* the user is following the OS preference, so a dark/light/auto control can
|
|
134
|
+
* tell the three states apart.
|
|
160
135
|
*/
|
|
161
136
|
export function getDarkMode(allowAuto = false): boolean | undefined {
|
|
162
137
|
const v = $override.value;
|
|
163
138
|
return v === undefined && !allowAuto ? A.darkMode() : v;
|
|
164
139
|
}
|
|
165
140
|
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
// so
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
// Reactive palette — the ONE place colours live, and the only thing that
|
|
143
|
+
// differs between light and dark. Everything else is wired to these named
|
|
144
|
+
// tokens, so an app can re-skin by overriding just a few of them. The accent
|
|
145
|
+
// names (--s-primary/-danger/-success/-warning) double as semantic *ink*
|
|
146
|
+
// colours, legible as text/borders on neutral surfaces.
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
173
148
|
A(() => {
|
|
174
|
-
|
|
149
|
+
if (getDarkMode()) {
|
|
150
|
+
A.insertGlobalCss({
|
|
151
|
+
":root":
|
|
152
|
+
"--s-primary:#8b7bff --s-secondary:#ef7fd0 --s-danger:#ff6b6b --s-success:#46d39a --s-warning:#fbbf24 " +
|
|
153
|
+
"--s-neutral:#3c4352 --s-page:#0e1015 --s-panel:#181b22 --s-raised:#222632 " +
|
|
154
|
+
"--s-ink:#e8eaf0 --s-on-accent:#0c0a14 --s-focus:rgba(139,123,255,0.45) " +
|
|
155
|
+
"--s-radius:12px --s-radius-lg:18px --s-shadow: 0 10px 34px rgba(0,0,0,0.5);",
|
|
156
|
+
// Contextual link, restored across the neutral group (see static block).
|
|
157
|
+
":root, .s-s.base, .s-s.panel, .s-s.raised, .s-s.neutral": "--s-link:#6db3ff",
|
|
158
|
+
});
|
|
159
|
+
} else {
|
|
160
|
+
A.insertGlobalCss({
|
|
161
|
+
":root":
|
|
162
|
+
"--s-primary:#6c5ce7 --s-secondary:#d6459e --s-danger:#e23b3b --s-success:#1f9d6b --s-warning:#d97706 " +
|
|
163
|
+
"--s-neutral:#c7ccda --s-page:#f3f4f8 --s-panel:#ffffff --s-raised:#eceef4 " +
|
|
164
|
+
"--s-ink:#1b1e27 --s-on-accent:#0c0a14 --s-focus:rgba(108,92,231,0.35) " +
|
|
165
|
+
"--s-radius:12px --s-radius-lg:18px --s-shadow: 0 10px 30px rgba(20,24,40,0.13);",
|
|
166
|
+
":root, .s-s.base, .s-s.panel, .s-s.raised, .s-s.neutral": "--s-link:#2563eb",
|
|
167
|
+
});
|
|
168
|
+
}
|
|
175
169
|
});
|
|
176
170
|
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
// Static structure — inserted once, all wired to the palette above.
|
|
173
|
+
//
|
|
174
|
+
// A surface is marked with `.s-s`. Its level/role modifier sets two anchors
|
|
175
|
+
// (--s-a ink, --s-b fill); its variant modifier (`.filled` default, `.tonal`,
|
|
176
|
+
// `.outlined`) decides how those anchors map onto the rendered fg/bg. `:root`
|
|
177
|
+
// (the page) is an implicit filled surface. Every `.s-s` then runs the same
|
|
178
|
+
// derive+paint step, reading the resolved fg/bg, so each one gets its own
|
|
179
|
+
// legible secondary tokens regardless of variant.
|
|
180
|
+
//
|
|
181
|
+
// Rule order matters: the variant/role rules below all share specificity, so a
|
|
182
|
+
// later one wins. `.filled` therefore comes *last* among the variants — that's
|
|
183
|
+
// what lets a caller's `attrs: ".filled"` override a component's default
|
|
184
|
+
// `.tonal`/`.outlined`.
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
A.setSpacingCssVars();
|
|
188
|
+
|
|
189
|
+
A.insertGlobalCss({
|
|
190
|
+
// Derived brand tokens. These only reference the per-mode palette colours, so
|
|
191
|
+
// they're defined once here and track the active mode (and any re-skin):
|
|
192
|
+
// `--s-gradient` is the primary→secondary brand sweep used for the headline
|
|
193
|
+
// mark, primary buttons and the active nav pill; `--s-glow` is a soft coloured
|
|
194
|
+
// shadow that makes those same elements feel lit; `--s-page-bg` is a faint
|
|
195
|
+
// twin-corner aurora wash painted on the page surface.
|
|
196
|
+
":root":
|
|
197
|
+
"--s-gradient: linear-gradient(135deg, $s-primary, $s-secondary); " +
|
|
198
|
+
"--s-glow: 0 8px 24px color-mix(in srgb, $s-primary 32%, transparent); " +
|
|
199
|
+
"--s-page-bg: radial-gradient(120% 80% at 100% 0%, color-mix(in oklab, $s-secondary, transparent 86%), transparent 56%), radial-gradient(120% 80% at 0% 0%, color-mix(in oklab, $s-primary, transparent 87%), transparent 56%), $s-page;",
|
|
200
|
+
|
|
201
|
+
// Level/role modifier → anchors. Levels (neutral elevations) use the shared
|
|
202
|
+
// ink; accent roles use the on-accent ink over their named fill. The page
|
|
203
|
+
// (`.base`) additionally paints the aurora wash; `--s-b` keeps the solid
|
|
204
|
+
// fallback so every derived token stays sensible.
|
|
205
|
+
":root, .s-s.base": "--s-a:$s-ink --s-b:$s-page",
|
|
206
|
+
".s-s.base": "background: $s-page-bg;",
|
|
207
|
+
".s-s.panel": "--s-a:$s-ink --s-b:$s-panel",
|
|
208
|
+
".s-s.raised": "--s-a:$s-ink --s-b:$s-raised",
|
|
209
|
+
".s-s.neutral": "--s-a:$s-ink --s-b:$s-neutral",
|
|
210
|
+
".s-s.primary": "--s-a:$s-on-accent --s-b:$s-primary",
|
|
211
|
+
".s-s.secondary": "--s-a:$s-on-accent --s-b:$s-secondary",
|
|
212
|
+
".s-s.danger": "--s-a:$s-on-accent --s-b:$s-danger",
|
|
213
|
+
".s-s.success": "--s-a:$s-on-accent --s-b:$s-success",
|
|
214
|
+
".s-s.warning": "--s-a:$s-on-accent --s-b:$s-warning",
|
|
215
|
+
// `.gradient` is an accent role whose fill is the brand sweep. Its `--s-b`
|
|
216
|
+
// anchor stays the solid `--s-primary` so the derived tokens (muted ink,
|
|
217
|
+
// border, …) remain sensible; the gradient itself is painted further down,
|
|
218
|
+
// only in the filled context (tonal/outlined read the solid fallback instead).
|
|
219
|
+
".s-s.gradient": "--s-a:$s-on-accent --s-b:$s-primary",
|
|
220
|
+
|
|
221
|
+
// Filled default (bare `.s-s` and `:root`): map the anchors to fg/bg, derive
|
|
222
|
+
// the secondary tokens from that pair, then paint. var() resolves at use time,
|
|
223
|
+
// so the tonal/outlined remaps below feed back into the derived tokens.
|
|
224
|
+
":root, .s-s":
|
|
225
|
+
"--s-fg:$s-a --s-bg:$s-b " +
|
|
226
|
+
"--s-fg-muted: color-mix(in oklab, $s-fg, $s-bg 42%); " +
|
|
227
|
+
"--s-fg-faint: color-mix(in oklab, $s-fg, $s-bg 64%); " +
|
|
228
|
+
"--s-border: color-mix(in oklab, $s-fg, $s-bg 82%); " +
|
|
229
|
+
"--s-border-strong: color-mix(in oklab, $s-fg, $s-bg 68%); " +
|
|
230
|
+
// Themed scrollbars (standard properties, honoured by Firefox and modern
|
|
231
|
+
// Chromium): the thumb uses the surface's derived border token, so the bar
|
|
232
|
+
// tracks the active mode/re-skin and a nested surface's own colours.
|
|
233
|
+
"scrollbar-width:thin scrollbar-color: $s-border-strong transparent; " +
|
|
234
|
+
"background:$s-bg color:$s-fg",
|
|
235
|
+
// WebKit/older-Chromium counterpart to the standard `scrollbar-*` props above:
|
|
236
|
+
// a transparent track and a rounded thumb (border-clipped to leave breathing
|
|
237
|
+
// room) that brightens on hover.
|
|
238
|
+
".s-s::-webkit-scrollbar, .s-s ::-webkit-scrollbar": "width:10px height:10px",
|
|
239
|
+
".s-s::-webkit-scrollbar-track, .s-s ::-webkit-scrollbar-track": "background:transparent",
|
|
240
|
+
".s-s::-webkit-scrollbar-thumb, .s-s ::-webkit-scrollbar-thumb": "background:$s-border-strong border-radius:99px border: 2px solid transparent; background-clip:padding-box",
|
|
241
|
+
".s-s::-webkit-scrollbar-thumb:hover, .s-s ::-webkit-scrollbar-thumb:hover": "background:$s-fg-faint background-clip:padding-box",
|
|
242
|
+
// Tonal: the fill colour becomes the ink, over a soft tint of itself.
|
|
243
|
+
".s-s.tonal": "--s-fg:$s-b --s-bg: color-mix(in srgb, $s-b 16%, transparent);",
|
|
244
|
+
// Outlined: the fill colour is the ink; --s-bg *inherits* the parent's bg (the
|
|
245
|
+
// token the derivations read, so the edge mixes ink with the real surroundings)
|
|
246
|
+
// while the painted background is transparent, letting that parent fill — even
|
|
247
|
+
// a gradient or image — show through.
|
|
248
|
+
".s-s.outlined": "--s-fg:$s-b --s-bg:inherit background:transparent --s-border: color-mix(in srgb, $s-fg 55%, $s-bg);",
|
|
249
|
+
// Filled, explicit — last among the variants so a caller's `attrs: ".filled"`
|
|
250
|
+
// overrides a component's default `.tonal`/`.outlined` (resetting both the
|
|
251
|
+
// anchors and the painted background).
|
|
252
|
+
".s-s.filled": "--s-fg:$s-a --s-bg:$s-b background:$s-bg;",
|
|
253
|
+
// Paint the brand sweep for a filled `.gradient` surface. Sits after the
|
|
254
|
+
// variant rules and is keyed on `:not(.tonal):not(.outlined)`, so those
|
|
255
|
+
// variants keep their solid-primary tint/edge.
|
|
256
|
+
".s-s.gradient:not(.tonal):not(.outlined)": "background: $s-gradient;",
|
|
257
|
+
|
|
258
|
+
// Contextual accent: the brand pop colour on neutral surfaces. Declared on the
|
|
259
|
+
// whole neutral group so re-entering a neutral surface under a coloured one
|
|
260
|
+
// restores it. (--s-link gets the same treatment in the reactive block, where
|
|
261
|
+
// its per-mode literal lives — it can't reference the palette, as the palette
|
|
262
|
+
// source and the contextual token share the name --s-link.)
|
|
263
|
+
":root, .s-s.base, .s-s.panel, .s-s.raised, .s-s.neutral": "--s-accent:$s-primary",
|
|
264
|
+
// On a bright coloured surface those wouldn't be legible, so they fall back to
|
|
265
|
+
// the surface's own ink. (Keyed on the role modifier, so it holds across
|
|
266
|
+
// variants — and tracks the tonal/outlined fg remap.)
|
|
267
|
+
".s-s.primary, .s-s.secondary, .s-s.danger, .s-s.success, .s-s.warning, .s-s.gradient": "--s-accent:$s-fg --s-link:$s-fg",
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// A deliberately light reset. Colours/shape come from the contextual tokens, so
|
|
271
|
+
// rich content (e.g. markdown-to-HTML) adapts to whatever surface holds it. The
|
|
272
|
+
// vertical rhythm / typography of block elements is handled separately, below.
|
|
180
273
|
A.insertGlobalCss({
|
|
181
274
|
"*, *::before, *::after": "box-sizing:border-box",
|
|
182
275
|
html: "text-size-adjust:100%",
|
|
183
|
-
body: "m:0
|
|
184
|
-
a: "
|
|
185
|
-
"a:hover": "
|
|
276
|
+
body: "m:0 line-height:1.5 font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; -webkit-font-smoothing:antialiased",
|
|
277
|
+
a: "color: $s-link; text-decoration:underline text-underline-offset:2px; transition: color 0.12s, filter 0.12s;",
|
|
278
|
+
"a:hover": "filter: brightness(1.15)",
|
|
186
279
|
"input, button, textarea, select": "font:inherit color:inherit",
|
|
187
280
|
"code, kbd, samp, pre": "font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;",
|
|
188
|
-
code: "bg
|
|
189
|
-
pre: "bg
|
|
190
|
-
"pre code": "
|
|
281
|
+
code: "background: color-mix(in oklab, $s-fg, $s-bg 86%); padding: 0.12em 0.34em; r:4px font-size:0.9em",
|
|
282
|
+
pre: "background: color-mix(in oklab, $s-fg, $s-bg 92%); p:$3 r: $s-radius; overflow:auto",
|
|
283
|
+
"pre code": "background:transparent p:0",
|
|
191
284
|
"img, svg, video, canvas": "max-width:100% h:auto",
|
|
192
|
-
hr: "border:0 border-top: 1px solid $
|
|
193
|
-
"::placeholder": "fg
|
|
194
|
-
":focus-visible": "outline: 2px solid $
|
|
285
|
+
hr: "border:0 border-top: 1px solid $s-border;",
|
|
286
|
+
"::placeholder": "color: $s-fg-faint; opacity:1",
|
|
287
|
+
":focus-visible": "outline: 2px solid $s-focus; outline-offset:2px",
|
|
288
|
+
small: "color:$s-fg-muted font-size:0.9em",
|
|
289
|
+
// Respect users who prefer less motion: keep transitions essentially instant.
|
|
290
|
+
"@media (prefers-reduced-motion: reduce)": {
|
|
291
|
+
"*, *::before, *::after": "transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; scroll-behavior: auto !important;",
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// ── Suppress transitions during the initial load ─────────────────────────────
|
|
296
|
+
// Buttons (and links) transition their colours, so a light↔dark switch animates
|
|
297
|
+
// smoothly. On a *cold* load that's a liability: elements mount and paint in the
|
|
298
|
+
// active theme in one pass, but a transitioning element animates from its
|
|
299
|
+
// default (unstyled) colours into the theme — so a fresh button visibly slides
|
|
300
|
+
// from light to dark while the rest of the page is already correct. Tag <html>
|
|
301
|
+
// until the first frame has painted and hard-disable transitions under that tag,
|
|
302
|
+
// so the initial render snaps straight to the right colours. Two rAFs: the first
|
|
303
|
+
// runs before the paint that shows the themed UI, the second clears the tag just
|
|
304
|
+
// after it — later theme switches then animate as normal.
|
|
305
|
+
A.insertGlobalCss({
|
|
306
|
+
".s-preload, .s-preload *, .s-preload *::before, .s-preload *::after":
|
|
307
|
+
"transition: none !important; animation: none !important;",
|
|
308
|
+
});
|
|
309
|
+
if (typeof document !== "undefined" && typeof requestAnimationFrame === "function") {
|
|
310
|
+
const root = document.documentElement;
|
|
311
|
+
root.classList.add("s-preload");
|
|
312
|
+
requestAnimationFrame(() => requestAnimationFrame(() => root.classList.remove("s-preload")));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// ── Flow content: vertical rhythm & light typography ─────────────────────────
|
|
316
|
+
// Sensible block defaults for *any* content — your own UI just as much as
|
|
317
|
+
// markdown-rendered HTML. The rhythm: strip the browser's block margins, then
|
|
318
|
+
// give every block a *top* margin only when it isn't its parent's first child.
|
|
319
|
+
// Content sits flush against its container's edges, and space appears solely
|
|
320
|
+
// *between* siblings. These are intentionally low-specificity defaults — a
|
|
321
|
+
// component or utility that sets its own margin (or an inline `mt:` shortcut)
|
|
322
|
+
// always wins, so a class only ever changes what it actually names.
|
|
323
|
+
const BLOCK = "p, ul, ol, dl, blockquote, pre, table, figure, hr, h1, h2, h3, h4, h5, h6";
|
|
324
|
+
|
|
325
|
+
A.insertGlobalCss({
|
|
326
|
+
[`${BLOCK}`]: {
|
|
327
|
+
"&": "margin:0",
|
|
328
|
+
"&:not(:first-child)": "margin-top:$3",
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
// Headings: bold, tight, balanced. Big levels get slightly negative tracking,
|
|
332
|
+
// small levels become spaced "labels" — so adjacent levels stay distinct. The
|
|
333
|
+
// em-based top margin gives larger headings a little more room above.
|
|
334
|
+
"h1, h2, h3, h4, h5, h6": {
|
|
335
|
+
"&": "line-height:1.15 font-weight:700 text-wrap:balance",
|
|
336
|
+
"&:not(:first-child)": "margin-top:1.4em",
|
|
337
|
+
},
|
|
338
|
+
h1: "font-size:2em font-weight:800 letter-spacing:-0.022em",
|
|
339
|
+
h2: "font-size:1.55em letter-spacing:-0.018em",
|
|
340
|
+
h3: "font-size:1.3em letter-spacing:-0.011em",
|
|
341
|
+
h4: "font-size:1.1em",
|
|
342
|
+
h5: "font-size:0.95em letter-spacing:0.005em",
|
|
343
|
+
h6: "font-size:0.8em fg:$s-fg-muted text-transform:uppercase letter-spacing:0.07em",
|
|
344
|
+
|
|
345
|
+
// Lists: markers, a sensible indent, gently spaced items, tight nesting.
|
|
346
|
+
"ul, ol": {
|
|
347
|
+
"&": "padding-left:1.5em",
|
|
348
|
+
"> li:not(:first-child), li > &:not(:first-child)": "margin-top:$1",
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
// Blockquote, tables, definition lists, figure captions.
|
|
352
|
+
blockquote: "border-left: 3px solid $s-border; padding-left: $3; fg: $s-fg-muted",
|
|
353
|
+
table: "border-collapse:collapse",
|
|
354
|
+
"th, td": "text-align:left padding: $1 $2; border-bottom: 1px solid $s-border; vertical-align:top",
|
|
355
|
+
th: "font-weight:600",
|
|
356
|
+
"thead th": "border-bottom: 2px solid $s-border-strong;",
|
|
357
|
+
dt: "font-weight:600",
|
|
358
|
+
dd: "margin-left: 1.5em",
|
|
359
|
+
figcaption: "fg:$s-fg-muted font-size:0.9em margin-top:$1 text-align:center",
|
|
195
360
|
});
|
package/dist/components/modal.js
DELETED
package/dist/skye.esm.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import w from"aberdeen";var P=w.proxy({sBg:"#0e1015",sSurface:"#181b22",sSurfaceHi:"#222632",sFg:"#e8eaf0",sFgMuted:"#a6acba",sFgFaint:"#6b7280",sBorder:"#2c313c",sBorderStrong:"#3c4352",sPrimary:"#8b7bff",sPrimaryHover:"#a99dff",sPrimaryFg:"#0c0a1a",sDanger:"#ff6b6b",sSuccess:"#46d39a",sWarning:"#fbbf24",sFocus:"rgba(139, 123, 255, 0.45)",sRadius:"10px",sRadiusLg:"16px",sShadow:"0 8px 30px rgba(0, 0, 0, 0.45)"}),D=w.proxy({sBg:"#f3f4f8",sSurface:"#ffffff",sSurfaceHi:"#eceef4",sFg:"#1b1e27",sFgMuted:"#5b6273",sFgFaint:"#9aa1b2",sBorder:"#e2e5ee",sBorderStrong:"#c7ccda",sPrimary:"#6c5ce7",sPrimaryHover:"#5847d4",sPrimaryFg:"#ffffff",sDanger:"#e23b3b",sSuccess:"#1f9d6b",sWarning:"#d97706",sFocus:"rgba(108, 92, 231, 0.35)",sRadius:"10px",sRadiusLg:"16px",sShadow:"0 6px 24px rgba(20, 24, 40, 0.12)"}),R="skye:darkMode",V=w.proxy({value:ae()});function ae(){try{let e=localStorage.getItem(R);if(e==="dark")return!0;if(e==="light")return!1}catch{}}function j(e){V.value=e;try{e===void 0?localStorage.removeItem(R):localStorage.setItem(R,e?"dark":"light")}catch{}}function z(e=!1){let t=V.value;return t===void 0&&!e?w.darkMode():t}w.setSpacingCssVars();w(()=>{w.merge(w.cssVars,z()?P:D)});w.insertGlobalCss({"*, *::before, *::after":"box-sizing:border-box",html:"text-size-adjust:100%",body:"m:0 bg:$sBg fg:$sFg line-height:1.5 font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; -webkit-font-smoothing:antialiased",a:"fg:$sPrimary text-decoration:underline text-underline-offset:2px","a:hover":"fg:$sPrimaryHover","input, button, textarea, select":"font:inherit color:inherit","code, kbd, samp, pre":"font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;",code:"bg:$sSurfaceHi padding: 0.12em 0.34em; r:4px font-size:0.9em",pre:"bg:$sSurface p:$3 r:$sRadius overflow:auto","pre code":"bg:transparent p:0","img, svg, video, canvas":"max-width:100% h:auto",hr:"border:0 border-top: 1px solid $sBorder; margin: $3 0;","::placeholder":"fg:$sFgFaint opacity:1",":focus-visible":"outline: 2px solid $sFocus; outline-offset:2px"});import o from"aberdeen";import le from"aberdeen";var se=0;function O(e="s"){return`${e}-${++se}`}function c(e){e!=null&&(typeof e=="function"?e():le("#",e))}import b from"aberdeen";b.insertGlobalCss({".S_field":{"&":"display:flex flex-direction:column gap:$1","> label":"font-weight:600 font-size:0.9em fg:$sFg user-select:none"},".S_req":"fg:$sDanger margin-left:2px",".S_help":"font-size:0.82em fg:$sFgMuted",".S_error":"font-size:0.82em fg:$sDanger",".S_input":{"&":"w:100% bg:$sSurface fg:$sFg border: 1px solid $sBorder; r:$sRadius padding: 0.55em 0.7em; transition: border-color 0.15s, box-shadow 0.15s;","&:hover:not(:disabled)":"border-color:$sBorderStrong","&:focus-visible":"border-color:$sPrimary box-shadow: 0 0 0 3px $sFocus; outline:none","&:disabled":"opacity:0.6 cursor:not-allowed","&[aria-invalid=true]":"border-color:$sDanger"}});function C(e,t){let n=e.id??O("field"),i=()=>!!e.error;b("div.S_field",e.root,()=>{b(()=>{e.label!=null&&b(`label for=${n}`,()=>{c(e.label),e.required&&b("span.S_req aria-hidden=true #*")})}),t(n,i),b(()=>{e.help!=null&&!e.error&&b("div.S_help",()=>c(e.help))}),b(()=>{e.error&&b("div.S_error role=alert #",e.error)})})}function I(e,t,n,i){b(`id=${t}`),e.name&&b(`name=${e.name}`),b(()=>{e.disabled&&b("disabled=true")}),b(()=>{e.required&&b("aria-required=true")}),b(()=>b("aria-invalid=",n()?"true":"false")),i&&b("bind=",i)}o.insertGlobalCss({".S_ac":{"&":"position:relative","> .S_control":"display:flex flex-wrap:wrap align-items:center gap:$1 bg:$sSurface fg:$sFg border: 1px solid $sBorder; r:$sRadius padding: 0.3em 0.4em; cursor:text; transition: border-color 0.15s, box-shadow 0.15s;","> .S_control:hover":"border-color:$sBorderStrong","> .S_control:focus-within":"border-color:$sPrimary box-shadow: 0 0 0 3px $sFocus;","&[aria-invalid=true] > .S_control":"border-color:$sDanger",".S_chip":"display:inline-flex align-items:center gap:$1 font-size:0.85em bg:$sSurfaceHi border: 1px solid $sBorder; r:$sRadius padding: 0.1em 0.2em 0.1em 0.5em;",".S_chip > button":"cursor:pointer border:0 background:transparent fg:$sFgMuted font-size:1.1em line-height:1 padding: 0 0.2em; r:4px",".S_chip > button:hover":"fg:$sFg background:$sBorder",input:"flex:1 min-width:6ch border:0 background:transparent color:inherit outline:none padding:0.25em","> .S_menu":"position:absolute top:100% left:0 right:0 z-index:20 margin-top:4px max-height:15rem overflow-y:auto list-style:none p:$1 margin-bottom:0 bg:$sSurface border: 1px solid $sBorder; r:$sRadius box-shadow:$sShadow",".S_option":"padding: 0.45em 0.6em; r:6px cursor:pointer",".S_option[aria-selected=true]":"background:$sSurfaceHi",".S_add":"fg:$sPrimary font-style:italic",".S_empty":"padding: 0.45em 0.6em; fg:$sFgMuted"}});function de(e){return typeof e=="string"?{value:e,label:e}:{value:e.value,label:e.label??e.value}}function W(e){let t=O("ac-menu"),n=o.proxy({query:"",open:!1,active:0}),i=()=>(typeof e.options=="function"?e.options():e.options).map(de),r=()=>{let l=e.bind?.value;return l==null||l===""?[]:Array.isArray(l)?l:[l]},s=l=>i().find(h=>h.value===l)?.label??l;if(!e.multi){let l=e.bind?o.peek(e.bind,"value"):void 0;typeof l=="string"&&l&&(n.query=o.peek(()=>s(l)))}let a=()=>{let l=new Set(r()),h=i();e.multi&&(h=h.filter(g=>!l.has(g.value)));let m=n.query.trim().toLowerCase();return m&&(h=h.filter(g=>g.label.toLowerCase().includes(m))),h},d=(l,h)=>{if(e.multi){let m=Array.isArray(e.bind?.value)?[...e.bind.value]:[];m.includes(l)||m.push(l),e.bind&&(e.bind.value=m),n.query=""}else e.bind&&(e.bind.value=l),n.query=s(l),n.open=!1;n.active=0,h?.focus()},x=l=>{if(!e.bind)return;let h=e.bind.value??[];e.bind.value=h.filter(m=>m!==l)};C(e,(l,h)=>{o("div.S_ac",e.control,()=>{o(()=>o("aria-invalid=",h()?"true":"false"));let m;o("div.S_control",()=>{o("click=",()=>m?.focus()),o(()=>{if(e.multi)for(let g of r())o("span.S_chip",()=>{o("span #",o.peek(()=>s(g))),o("button type=button aria-label=",`Remove ${g}`,()=>{o("#\xD7"),o("click=",y=>{y.stopPropagation(),x(g),m?.focus()})})})}),m=o("input type=text role=combobox autocomplete=off",()=>{o(`id=${l} aria-controls=${t} aria-autocomplete=list`),e.placeholder!=null&&o("placeholder=",e.placeholder),e.disabled&&o("disabled=true"),e.required&&o("aria-required=true"),o("bind=",o.ref(n,"query")),o(()=>o("aria-expanded=",n.open?"true":"false")),o(()=>{let y=a()[n.active];o("aria-activedescendant=",n.open&&y?`${t}-opt-${n.active}`:"")}),o("input=",()=>{n.open=!0,n.active=0}),o("focus=",()=>{n.open=!0}),o("blur=",()=>{setTimeout(()=>L(),150)}),o("keydown=",g=>B(g,m))})}),o(()=>{if(!n.open)return;let g=a(),y=n.query.trim(),K=e.allowCustom!==!1&&y!==""&&!g.some(E=>E.label.toLowerCase()===y.toLowerCase());o("ul.S_menu role=listbox",`id=${t}`,()=>{g.forEach((E,G)=>{o("li.S_option role=option",`id=${t}-opt-${G}`,()=>{o(()=>o("aria-selected=",n.active===G?"true":"false")),o("#",E.label),o("mousedown=",ie=>ie.preventDefault()),o("click=",()=>d(E.value,m)),o("mousemove=",()=>{n.active=G})})}),K&&o("li.S_option.S_add role=option",()=>{o("#",`Add "${y}"`),o("mousedown=",E=>E.preventDefault()),o("click=",()=>d(y,m))}),g.length===0&&!K&&o("li.S_empty #No matches")})}),o(()=>{if(e.name)if(e.multi)for(let g of r())o("input type=hidden",()=>{o("name=",e.name),o("value=",g)});else o("input type=hidden",()=>{o("name=",e.name),o("value=",r()[0]??"")})})})});function B(l,h){let m=a(),g=m.length-1;if(l.key==="ArrowDown")l.preventDefault(),n.open=!0,n.active=Math.min(g,n.active+1);else if(l.key==="ArrowUp")l.preventDefault(),n.active=Math.max(0,n.active-1);else if(l.key==="Enter"){l.preventDefault();let y=m[n.active];y?d(y.value,h):e.allowCustom!==!1&&n.query.trim()?d(n.query.trim(),h):n.open&&(n.open=!1)}else if(l.key==="Escape")n.open=!1,e.multi||(n.query=s(r()[0]??""));else if(l.key==="Backspace"&&e.multi&&n.query===""){let y=r();y.length&&x(y[y.length-1])}}function L(){n.open=!1,e.multi?n.query="":e.allowCustom!==!1&&n.query.trim()?d(n.query.trim()):n.query=s(r()[0]??"")}}import F from"aberdeen";F.insertGlobalCss({".S_box":{"&":"display:flex flex-direction:column bg:$sSurface border: 1px solid $sBorder; r:$sRadius overflow:hidden","> header":"display:flex align-items:center gap:$2 padding: $2 $3; bg:$sSurfaceHi border-bottom: 1px solid $sBorder; font-weight:600","> footer":"display:flex align-items:center gap:$2 padding: $2 $3; bg:$sSurfaceHi border-top: 1px solid $sBorder;","> div":"p:$3 gap:$3"}});function U(e={}){let t=typeof e=="function"?{content:e}:e;F("section.S_box",t.root,()=>{F(()=>{t.header!=null&&F("header",t.headerInner,()=>c(t.header))}),F("div",t.inner,()=>{t.content&&t.content()}),F(()=>{t.footer!=null&&F("footer",t.footerInner,()=>c(t.footer))})})}import k from"aberdeen";k.insertGlobalCss({".S_btn":{"&":"--c:$sPrimary --cfg:$sPrimaryFg display:inline-flex align-items:center justify-content:center gap:$2 font-weight:600 line-height:1.2 white-space:nowrap cursor:pointer text-decoration:none border: 1px solid transparent; r:$sRadius padding: 0.5em 1em; transition: background 0.15s, border-color 0.15s, filter 0.15s, box-shadow 0.15s;","&:focus-visible":"outline:none box-shadow: 0 0 0 3px $sFocus;","&:disabled, &[aria-disabled=true]":"opacity:0.45 cursor:not-allowed pointer-events:none filter:saturate(0.6)","&.S_neutral":"--c:$sBorderStrong --cfg:$sFg","&.S_danger":"--c:$sDanger --cfg:#fff","&.S_success":"--c:$sSuccess --cfg:#08110d","&.S_filled":"background:$c color:$cfg border-color:$c","&.S_filled:hover":"filter:brightness(1.1)","&.S_tonal":"color:$c background: color-mix(in srgb, $c 20%, transparent); border-color: color-mix(in srgb, $c 30%, transparent);","&.S_tonal:hover":"background: color-mix(in srgb, $c 30%, transparent);","&.S_outlined":"color:$c background:transparent border-color: color-mix(in srgb, $c 55%, $sBorder);","&.S_outlined:hover":"background: color-mix(in srgb, $c 12%, transparent);","&.S_sm":"padding: 0.32em 0.7em; font-size:0.85em","&.S_lg":"padding: 0.66em 1.3em; font-size:1.1em"}});function $(e={}){let t=typeof e=="string"?{text:e}:typeof e=="function"?{content:e}:e,n=t.href!=null?"a":"button",i=t.variant??"filled",r=t.color??"primary",s=t.size==="sm"||t.size==="lg"?`.S_${t.size}`:"",a=r==="primary"||r==="neutral"||r==="danger"||r==="success",d=a?`.S_${r}`:"",x=k(`${n}.S_btn.S_${i}${d}${s}`,t.root,t.inner,()=>{t.href!=null?(k(`href=${t.href} role=button`),t.disabled&&k("aria-disabled=true")):(k("type=",t.type??"button"),t.disabled&&k("disabled=true")),t.ariaLabel&&k("aria-label=",t.ariaLabel),t.click&&k("click=",t.click),c(t.icon),t.content?t.content():t.text!=null&&k("#",t.text)});!a&&x instanceof HTMLElement&&x.style.setProperty("--c",r.startsWith("$")?`var(--${r.slice(1)})`:r)}import Y from"aberdeen";Y.insertGlobalCss({".S_bgroup":{"&":"display:inline-flex align-items:stretch","&.S_spaced":"gap:$2 flex-wrap:wrap","&.S_vertical":"flex-direction:column","&.S_attached":"gap:0","&.S_attached:not(.S_vertical) > .S_btn:not(:first-child)":"margin-left:-1px","&.S_attached:not(.S_vertical) > .S_btn:not(:first-child):not(:last-child)":"r:0","&.S_attached:not(.S_vertical) > .S_btn:first-child:not(:last-child)":"border-top-right-radius:0 border-bottom-right-radius:0","&.S_attached:not(.S_vertical) > .S_btn:last-child:not(:first-child)":"border-top-left-radius:0 border-bottom-left-radius:0","&.S_attached.S_vertical > .S_btn:not(:first-child)":"margin-top:-1px","&.S_attached.S_vertical > .S_btn:not(:first-child):not(:last-child)":"r:0","&.S_attached.S_vertical > .S_btn:first-child:not(:last-child)":"border-bottom-left-radius:0 border-bottom-right-radius:0","&.S_attached.S_vertical > .S_btn:last-child:not(:first-child)":"border-top-left-radius:0 border-top-right-radius:0","&.S_attached > .S_btn:hover, &.S_attached > .S_btn:focus-visible":"z-index:1"}});function M(e={}){let n=`.S_${e.layout??"attached"}${e.vertical?".S_vertical":""}`;Y(`div.S_bgroup${n} role=group`,e.root,e.inner,()=>{if(e.buttons)for(let i of e.buttons)$(i);e.content&&e.content()})}import p from"aberdeen";p.insertGlobalCss({".S_check":{"&":"display:flex flex-direction:column gap:$1","> label":"display:flex align-items:center gap:$2 cursor:pointer user-select:none","> label:has(input:disabled)":"cursor:not-allowed opacity:0.6",input:"width:1.15em height:1.15em accent-color:$sPrimary cursor:inherit m:0"}});function N(e={}){let t=e.id??O("check");p("div.S_check",e.root,()=>{p(`label for=${t}`,()=>{p("input type=checkbox",e.control,()=>{p(`id=${t}`),e.name&&p(`name=${e.name}`),e.checked&&!e.bind&&p("checked=true"),e.change&&p("change=",e.change),p(()=>{e.disabled&&p("disabled=true")}),p(()=>{e.required&&p("aria-required=true")}),e.bind&&p("bind=",e.bind)}),p(()=>{e.label!=null&&c(e.label),e.required&&p("span.S_req aria-hidden=true #*")})}),p(()=>{e.help!=null&&!e.error&&p("div.S_help",()=>c(e.help))}),p(()=>{e.error&&p("div.S_error role=alert #",e.error)})})}import T from"aberdeen";T.insertGlobalCss({".S_form":{"&":"display:flex flex-direction:column gap:$3","&.grid":"display:grid grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap:$3","&.grid > .S_wide, &.grid > footer":"grid-column: 1 / -1;","> footer":"display:flex align-items:center gap:$2 flex-wrap:wrap margin-top:$1"}});function J(e={}){let t=typeof e=="function"?{content:e}:e;T("form.S_form",t.root,t.inner,()=>{T(()=>{T(".grid=",t.layout==="grid")}),T("submit=",n=>{if(n.preventDefault(),t.submit){let i=new FormData(n.target),r={};for(let s of new Set(i.keys())){let a=i.getAll(s);r[s]=a.length===1?a[0]:a}t.submit(r,n)}}),t.content&&t.content(),T(()=>{t.actions&&T("footer",t.actionsInner,()=>t.actions?.())})})}import f from"aberdeen";f.insertGlobalCss({".S_main":{"&":"display:flex flex-direction:column min-height:100vh max-height:100vh bg:$sBg fg:$sFg","> header":"display:flex align-items:center gap:$3 padding: $2 $3; bg:$sSurfaceHi border-bottom: 1px solid $sBorder; position:sticky top:0 z-index:10","> header .S_icon":"display:flex align-items:center font-size:1.4em","> header .S_titles":"display:flex flex-direction:column min-width:0 flex:1","> header .S_title":"font-weight:700 font-size:1.1em line-height:1.2 overflow:hidden text-overflow:ellipsis white-space:nowrap","> header .S_subtitle":"fg:$sFgMuted font-size:0.85em overflow:hidden text-overflow:ellipsis white-space:nowrap","> header .S_menu":"display:flex align-items:center gap:$2","> main":"flex:1 overflow-y:auto display:flex flex-direction:column","> main > .S_content":"width:100% flex:1","> main > .S_content.S_framed":"margin: $3 auto; bg:$sSurface border: 1px solid $sBorder; r:$sRadiusLg box-shadow:$sShadow p:$4","> main > .S_content.S_plain":"p:$3","> footer":"display:flex align-items:center gap:$2 padding: $2 $3; bg:$sSurfaceHi border-top: 1px solid $sBorder; fg:$sFgMuted"}});function Q(e={}){f("div.S_main",e.root,()=>{f(()=>{(e.title!=null||e.subtitle!=null||e.icon!=null||e.menu!=null)&&f("header",e.topbarInner,()=>{f(()=>{e.icon!=null&&f("div.S_icon",()=>c(e.icon))}),f("div.S_titles",()=>{f(()=>{e.title!=null&&f("div.S_title",()=>c(e.title))}),f(()=>{e.subtitle!=null&&f("div.S_subtitle",()=>c(e.subtitle))})}),f(()=>{e.menu&&f("div.S_menu",()=>e.menu?.())})})}),f("main",()=>{f("div.S_content",e.inner,()=>{f(()=>{let t=e.maxWidth;t!=null?f(".S_framed max-width:",t):f(".S_plain")}),e.content&&e.content()})}),f(()=>{e.footer!=null&&f("footer",()=>c(e.footer))})})}import u from"aberdeen";import A from"aberdeen";function H(e={}){C(e,(t,n)=>{A("input.S_input",e.control,()=>{A("type=",e.type??"text"),e.placeholder!=null&&A("placeholder=",e.placeholder),e.autocomplete!=null&&A("autocomplete=",e.autocomplete),e.value!=null&&!e.bind&&A("value=",e.value),e.input&&A("input=",e.input),e.change&&A("change=",e.change),I(e,t,n,e.bind)})})}u.insertGlobalCss({".S_backdrop":{"&":"position:fixed inset:0 z-index:200; background: rgba(0,0,0,0.55); transition: opacity 0.2s ease;","&:not(:has(~ .S_backdrop))":"display:block","&:not(:has(~ .S_backdrop)) + .S_dialog":"display:flex flex-direction:column","&.hidden":"opacity:0 pointer-events:none"},".S_dialog":{"&":"position:fixed z-index:201 top:50% left:50% transform:translate(-50%,-50%) min-width:20rem max-width:min(90vw,44rem) max-height:min(88vh,800px) bg:$sSurface border: 1px solid $sBorder; r:$sRadiusLg box-shadow:$sShadow overflow:hidden transition: opacity 0.2s ease, transform 0.2s ease;","> header":"display:flex align-items:center gap:$2 padding: $2 $3; bg:$sSurfaceHi border-bottom: 1px solid $sBorder; font-weight:600 flex-shrink:0","> footer":"display:flex align-items:center gap:$2 padding: $2 $3; bg:$sSurfaceHi border-top: 1px solid $sBorder; flex-shrink:0","> div":"p:$3 gap:$3 display:flex flex-direction:column overflow-y:auto flex:1 min-height:0","&.hidden":"opacity:0 pointer-events:none transform: translate(-50%, calc(-50% + 20px));","&.hidden *":"pointer-events:none"}});function q(e){return new Promise(t=>{let n=u.proxy(!1),i=()=>{n.value=!0},r=!1,s=()=>{r||(r=!0,e.onClose?.(),t())};u.mount(document.body,()=>{if(u.peek(n,"value"),n.value)return;let a=d=>{d.key==="Escape"&&e.allowCancel!==!1&&i()};document.addEventListener("keydown",a),u.clean(()=>{document.removeEventListener("keydown",a),s()}),u("div.S_backdrop create=hidden destroy=hidden",()=>{u("click=",()=>{e.allowCancel!==!1&&i()})}),u("div.S_dialog create=hidden destroy=hidden",e.root,()=>{u(()=>{e.header!=null&&u("header",e.headerInner,()=>c(e.header))}),u("div",e.inner,()=>{e.content&&e.content(i)}),u(()=>{e.footer!=null&&u("footer",e.footerInner,()=>c(e.footer))})})})})}function X(e,t={}){return q({header:"Alert",allowCancel:!0,content:n=>{u("p",()=>{u("#",e)}),M({layout:"spaced",root:"align-self:flex-end",content:()=>{$({text:"OK",click:n})}})},...t})}function Z(e,t={}){return new Promise(n=>{let i=!1;q({header:"Confirm",allowCancel:!0,content:r=>{u("p",()=>{u("#",e)}),M({layout:"spaced",root:"align-self:flex-end",content:()=>{$({text:"Cancel",variant:"outlined",color:"neutral",click:r}),$({text:"OK",click:()=>{i=!0,r()}})}})},...t,onClose:()=>{n(i),t.onClose?.()}})})}function ee(e,t="",n={}){return new Promise(i=>{let r=null;q({header:"Input",allowCancel:!0,content:s=>{u("p",()=>{u("#",e)});let a=u.proxy({value:t});u("form display:contents",()=>{u("submit=",d=>{d.preventDefault(),r=a.value,s()}),H({bind:u.ref(a,"value")}),M({layout:"spaced",root:"align-self:flex-end",content:()=>{$({text:"Cancel",variant:"outlined",color:"neutral",type:"button",click:s}),$({text:"OK",type:"submit"})}})})},...n,onClose:()=>{i(r),n.onClose?.()}})})}import v from"aberdeen";v.insertGlobalCss({".S_select_wrap":{"&":"position:relative display:block",select:"w:100% cursor:pointer padding-right:2.2em; appearance:none","&::after":"content: '\u25BE'; position:absolute right:0.7em top:50%; transform: translateY(-50%); pointer-events:none fg:$sFgMuted font-size:0.85em"}});function te(e){C(e,(t,n)=>{v("div.S_select_wrap",e.control,()=>{v("select.S_input",()=>{I(e,t,n),v("change=",i=>{e.bind&&(e.bind.value=i.target.value)}),v(()=>{let i=typeof e.options=="function"?e.options():e.options,r=e.bind?.value??"";e.placeholder!=null&&v("option",()=>{v("value= disabled=true hidden=true"),r||v("selected=true"),v("#",e.placeholder)});for(let s of i){let a=typeof s=="string"?{value:s,label:s}:{value:s.value,label:s.label??s.value};v("option",()=>{v("value=",a.value),a.value===r&&v("selected=true"),v("#",a.label)})}})})})})}import S from"aberdeen";S.insertGlobalCss({".S_tabs":{"&":"display:flex flex-direction:column gap:$3",".S_tablist":"display:flex gap:$1 align-items:stretch",".S_tab":"display:inline-flex align-items:center gap:$2 cursor:pointer background:transparent border:0 fg:$sFgMuted font-weight:600 padding: 0.6em 0.9em; transition: color 0.15s, background 0.15s, border-color 0.15s;",".S_tab:hover:not(:disabled)":"fg:$sFg",".S_tab:disabled":"opacity:0.5 cursor:not-allowed",".S_tab:focus-visible":"outline:none box-shadow: 0 0 0 3px $sFocus; r:$sRadius","&.S_underline .S_tablist":"border-bottom: 1px solid $sBorder;","&.S_underline .S_tab":"border-bottom: 2px solid transparent; margin-bottom:-1px","&.S_underline .S_tab[aria-selected=true]":"fg:$sFg border-bottom-color:$sPrimary","&.S_pills .S_tab":"r:$sRadius","&.S_pills .S_tab[aria-selected=true]":"fg:$sPrimaryFg background:$sPrimary",".S_tabpanel":"display:block"}});function ne(e){let t=e.variant??"underline",n=O("tabs"),i=(a,d)=>a.id??String(d),r=e.bind??S.proxy(i(e.tabs[0]??{label:""},0)),s=(a,d)=>{a.disabled||(r.value=i(a,d))};S(`div.S_tabs.S_${t}`,e.root,()=>{S("div.S_tablist role=tablist",()=>{e.tabs.forEach((a,d)=>{let x=i(a,d);S("button.S_tab type=button role=tab",()=>{S(`id=${n}-tab-${x} aria-controls=${n}-panel-${x}`),S(()=>{let B=r.value===x;S("aria-selected=",B?"true":"false"),S("tabindex=",B?"0":"-1")}),a.disabled&&S("disabled=true"),S("click=",()=>s(a,d)),S("keydown=",B=>ce(B,e.tabs,d,s)),c(a.icon),c(a.label)})})}),S("div.S_tabpanel role=tabpanel",e.inner,()=>{S(()=>{let a=r.value,d=e.tabs.findIndex((B,L)=>i(B,L)===a),x=e.tabs[d]??e.tabs[0];x&&(S(`id=${n}-panel-${i(x,d)} aria-labelledby=${n}-tab-${i(x,d)}`),x.content?.())})})})}function ce(e,t,n,i){let r=n;if(e.key==="ArrowRight"||e.key==="ArrowDown")r=(n+1)%t.length;else if(e.key==="ArrowLeft"||e.key==="ArrowUp")r=(n-1+t.length)%t.length;else if(e.key==="Home")r=0;else if(e.key==="End")r=t.length-1;else return;e.preventDefault();let s=r>=n?1:-1;for(let a=0;a<t.length;a++){let d=t[r];if(d&&!d.disabled){i(d,r),e.currentTarget?.parentElement?.children[r]?.focus();return}r=(r+s+t.length)%t.length}}import _ from"aberdeen";_.insertGlobalCss({"textarea.S_input":"resize:vertical min-height:3em line-height:1.45","textarea.S_input.S_autoGrow":"resize:none min-height:2.5em overflow-y:hidden"});function re(e={}){let t=e.autoGrow!==!1;C(e,(n,i)=>{let r=_("textarea.S_input",e.control,()=>{t?(_(".S_autoGrow"),_("input=",s=>{oe(s.currentTarget),e.input&&e.input(s)})):(_("rows=",e.rows??4),_("resize:",e.resize??"vertical"),e.input&&_("input=",e.input)),e.placeholder!=null&&_("placeholder=",e.placeholder),e.value!=null&&!e.bind&&_("value=",e.value),e.change&&_("change=",e.change),I(e,n,i,e.bind)});t&&requestAnimationFrame(()=>oe(r))})}function oe(e){e.style.height="auto",e.style.height=`${e.scrollHeight}px`}var ue={main:Q,box:U,dialog:q,alert:X,confirm:Z,prompt:ee,form:J,textline:H,textarea:re,checkbox:N,tabs:ne,button:$,buttonGroup:M,autocomplete:W,select:te,darkTheme:P,lightTheme:D,setDarkMode:j,getDarkMode:z},ht=ue;export{ue as S,P as darkTheme,ht as default,c as drawSlot,z as getDarkMode,D as lightTheme,j as setDarkMode,O as uniqueId};
|