@urbicon-ui/blocks 6.21.1 → 6.21.3
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/components/NumberInput/NumberInput.svelte +197 -0
- package/dist/components/NumberInput/NumberInput.svelte.d.ts +4 -0
- package/dist/components/NumberInput/index.d.ts +55 -0
- package/dist/components/NumberInput/index.js +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +1 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/primitives/Avatar/avatar.variants.d.ts +6 -6
- package/dist/primitives/Badge/Badge.svelte +18 -8
- package/dist/primitives/Badge/index.d.ts +26 -6
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte +11 -6
- package/dist/primitives/Breadcrumb/index.d.ts +2 -2
- package/dist/primitives/Button/button.variants.d.ts +4 -4
- package/dist/primitives/ButtonGroup/index.d.ts +1 -1
- package/dist/primitives/Card/card.variants.d.ts +5 -5
- package/dist/primitives/Checkbox/Checkbox.svelte +3 -3
- package/dist/primitives/Combobox/Combobox.svelte +478 -104
- package/dist/primitives/Combobox/combobox.variants.d.ts +89 -17
- package/dist/primitives/Combobox/combobox.variants.js +94 -13
- package/dist/primitives/Combobox/index.d.ts +166 -51
- package/dist/primitives/ConfirmDialog/index.d.ts +19 -0
- package/dist/primitives/Dialog/Dialog.svelte +74 -0
- package/dist/primitives/Dialog/dialog.variants.d.ts +9 -9
- package/dist/primitives/Dialog/index.d.ts +12 -1
- package/dist/primitives/Drawer/Drawer.svelte +2 -1
- package/dist/primitives/Drawer/drawer.variants.d.ts +8 -0
- package/dist/primitives/Drawer/drawer.variants.js +45 -10
- package/dist/primitives/Drawer/index.d.ts +13 -4
- package/dist/primitives/FormField/FormField.svelte +6 -6
- package/dist/primitives/FormField/index.d.ts +13 -4
- package/dist/primitives/Input/Input.svelte +8 -4
- package/dist/primitives/Input/input.variants.d.ts +9 -9
- package/dist/primitives/Menu/Menu.svelte +66 -4
- package/dist/primitives/Menu/index.d.ts +25 -0
- package/dist/primitives/Pagination/Pagination.svelte +28 -13
- package/dist/primitives/Pagination/index.d.ts +44 -0
- package/dist/primitives/Popover/Popover.svelte +34 -3
- package/dist/primitives/Popover/index.d.ts +3 -3
- package/dist/primitives/RadioGroup/RadioGroup.svelte +3 -3
- package/dist/primitives/Select/Select.svelte +21 -11
- package/dist/primitives/Select/index.d.ts +7 -0
- package/dist/primitives/Select/select.variants.d.ts +17 -17
- package/dist/primitives/Select/select.variants.js +18 -0
- package/dist/primitives/Skeleton/skeleton.variants.d.ts +3 -3
- package/dist/primitives/Slider/Slider.svelte +4 -8
- package/dist/primitives/Spinner/spinner.variants.d.ts +16 -16
- package/dist/primitives/Textarea/Textarea.svelte +13 -5
- package/dist/primitives/Textarea/textarea.variants.d.ts +7 -7
- package/dist/primitives/Textarea/textarea.variants.js +5 -2
- package/dist/primitives/Toast/Toaster.svelte +42 -2
- package/dist/primitives/Toast/index.d.ts +30 -0
- package/dist/primitives/Toast/toast.store.svelte.d.ts +25 -1
- package/dist/primitives/Toast/toast.store.svelte.js +91 -1
- package/dist/primitives/Toast/toast.variants.d.ts +18 -0
- package/dist/primitives/Toast/toast.variants.js +15 -0
- package/dist/primitives/Toggle/Toggle.svelte +17 -3
- package/dist/primitives/Toggle/index.d.ts +8 -2
- package/dist/primitives/Toggle/toggle.variants.d.ts +7 -0
- package/dist/primitives/Toggle/toggle.variants.js +26 -0
- package/dist/primitives/Toolbar/toolbar.variants.d.ts +6 -6
- package/dist/primitives/Tooltip/Tooltip.svelte +47 -21
- package/dist/primitives/Tooltip/Tooltip.svelte.d.ts +1 -1
- package/dist/primitives/Tooltip/index.d.ts +31 -3
- package/dist/primitives/Tooltip/tooltip.variants.d.ts +4 -4
- package/dist/primitives/Tooltip/tooltip.variants.js +2 -2
- package/dist/primitives/index.d.ts +3 -3
- package/dist/style/semantic.css +55 -29
- package/dist/translations/de.d.ts +3 -0
- package/dist/translations/de.js +4 -1
- package/dist/translations/en.d.ts +3 -0
- package/dist/translations/en.js +4 -1
- package/dist/utils/figma-token-export.d.ts +13 -0
- package/dist/utils/figma-token-export.js +99 -26
- package/dist/utils/guide.svelte.d.ts +8 -2
- package/dist/utils/guide.svelte.js +86 -5
- package/dist/utils/use-form-field.svelte.d.ts +9 -9
- package/dist/utils/use-form-field.svelte.js +12 -12
- package/package.json +3 -3
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { type SlotNames, type VariantProps } from '../../utils/variants.js';
|
|
2
2
|
export declare const tooltipVariants: ((props?: {
|
|
3
|
-
|
|
3
|
+
open?: boolean | undefined;
|
|
4
4
|
intent?: "primary" | "secondary" | "info" | "success" | "warning" | "danger" | "neutral" | undefined;
|
|
5
5
|
size?: "sm" | "md" | "lg" | undefined;
|
|
6
6
|
} | undefined) => {
|
|
7
7
|
base: (props?: ({
|
|
8
|
-
|
|
8
|
+
open?: boolean | undefined;
|
|
9
9
|
intent?: "primary" | "secondary" | "info" | "success" | "warning" | "danger" | "neutral" | undefined;
|
|
10
10
|
size?: "sm" | "md" | "lg" | undefined;
|
|
11
11
|
} & {
|
|
12
12
|
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
13
13
|
}) | undefined) => string;
|
|
14
14
|
arrow: (props?: ({
|
|
15
|
-
|
|
15
|
+
open?: boolean | undefined;
|
|
16
16
|
intent?: "primary" | "secondary" | "info" | "success" | "warning" | "danger" | "neutral" | undefined;
|
|
17
17
|
size?: "sm" | "md" | "lg" | undefined;
|
|
18
18
|
} & {
|
|
@@ -21,6 +21,6 @@ export declare const tooltipVariants: ((props?: {
|
|
|
21
21
|
}) & {
|
|
22
22
|
readonly config: import("../../utils/variants.js").TVConfig;
|
|
23
23
|
};
|
|
24
|
-
export type TooltipVariants = Omit<VariantProps<typeof tooltipVariants>, '
|
|
24
|
+
export type TooltipVariants = Omit<VariantProps<typeof tooltipVariants>, 'open'>;
|
|
25
25
|
/** Slot names derived from the `tv()` config above — single source of truth for `slotClasses`. */
|
|
26
26
|
export type TooltipSlots = SlotNames<typeof tooltipVariants>;
|
|
@@ -33,7 +33,7 @@ export const tooltipVariants = tv({
|
|
|
33
33
|
arrow: ['absolute w-2 h-2', 'bg-inherit transform rotate-45']
|
|
34
34
|
},
|
|
35
35
|
variants: {
|
|
36
|
-
|
|
36
|
+
open: {
|
|
37
37
|
true: { base: 'opacity-100' },
|
|
38
38
|
false: { base: 'opacity-0' }
|
|
39
39
|
},
|
|
@@ -53,7 +53,7 @@ export const tooltipVariants = tv({
|
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
55
|
defaultVariants: {
|
|
56
|
-
|
|
56
|
+
open: false,
|
|
57
57
|
intent: 'neutral',
|
|
58
58
|
size: 'md'
|
|
59
59
|
}
|
|
@@ -18,7 +18,7 @@ export type { CheckboxProps } from './Checkbox/index.js';
|
|
|
18
18
|
export * from './Checkbox/index.js';
|
|
19
19
|
export type { CollapsibleProps } from './Collapsible/index.js';
|
|
20
20
|
export * from './Collapsible/index.js';
|
|
21
|
-
export type { ComboboxOptionType, ComboboxProps } from './Combobox/index.js';
|
|
21
|
+
export type { ComboboxGroup, ComboboxOptionType, ComboboxProps } from './Combobox/index.js';
|
|
22
22
|
export * from './Combobox/index.js';
|
|
23
23
|
export type { ConfirmDialogProps, ConfirmIntent } from './ConfirmDialog/index.js';
|
|
24
24
|
export * from './ConfirmDialog/index.js';
|
|
@@ -34,7 +34,7 @@ export type { JourneyNode, JourneyStatus, JourneyTimelineProps } from './Journey
|
|
|
34
34
|
export * from './JourneyTimeline/index.js';
|
|
35
35
|
export type { MenuContext, MenuCustomSlots, MenuItemType, MenuObjectOption, MenuOption, MenuProps, MenuSectionHeader } from './Menu/index.js';
|
|
36
36
|
export * from './Menu/index.js';
|
|
37
|
-
export type { PaginationItemProps, PaginationProps } from './Pagination/index.js';
|
|
37
|
+
export type { PaginationItemContext, PaginationItemProps, PaginationProps } from './Pagination/index.js';
|
|
38
38
|
export * from './Pagination/index.js';
|
|
39
39
|
export * from './Popover/index.js';
|
|
40
40
|
export type { ProgressProps } from './Progress/index.js';
|
|
@@ -61,7 +61,7 @@ export type { TabItemProps, TabPanelProps, TabProps } from './Tab/index.js';
|
|
|
61
61
|
export * from './Tab/index.js';
|
|
62
62
|
export type { TextareaProps } from './Textarea/index.js';
|
|
63
63
|
export * from './Textarea/index.js';
|
|
64
|
-
export type { ToastData, ToastInput, ToastIntent, ToastPlacement, ToastProps, ToastShorthandOpts } from './Toast/index.js';
|
|
64
|
+
export type { ToastAction, ToastData, ToastInput, ToastIntent, ToastPlacement, ToastPromiseOptions, ToastProps, ToastShorthandOpts } from './Toast/index.js';
|
|
65
65
|
export * from './Toast/index.js';
|
|
66
66
|
export { TOAST_INTENTS } from './Toast/index.js';
|
|
67
67
|
export type { ToggleProps } from './Toggle/index.js';
|
package/dist/style/semantic.css
CHANGED
|
@@ -183,7 +183,12 @@
|
|
|
183
183
|
|
|
184
184
|
/* === SHADOWS ===
|
|
185
185
|
Dark mode uses higher alpha to compensate for low contrast against
|
|
186
|
-
dark surfaces. light-dark()
|
|
186
|
+
dark surfaces. light-dark() may wrap ONLY the per-layer <color> —
|
|
187
|
+
it is a color function, and layers must stay top-level
|
|
188
|
+
comma-separated. Wrapping the whole multi-layer list made every
|
|
189
|
+
`box-shadow: var(--blocks-shadow-*)` invalid at computed-value time
|
|
190
|
+
(shadows silently rendered as none, library-wide) — verified in
|
|
191
|
+
chromium before the 2026-07-13 fix.
|
|
187
192
|
|
|
188
193
|
The shadow tint (`--blocks-shadow-tint`) is an oklch L C H triplet
|
|
189
194
|
WITHOUT the alpha channel — declared on `:root` (not inside @theme)
|
|
@@ -192,34 +197,55 @@
|
|
|
192
197
|
their shadow palette — e.g. editorial sets it to a dark brown so
|
|
193
198
|
shadows blend with cream surfaces instead of reading as cool
|
|
194
199
|
smudges. */
|
|
195
|
-
--color-shadow-xs:
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
0
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
--color-shadow-
|
|
212
|
-
0
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
200
|
+
--color-shadow-xs: 0 1px 2px 0
|
|
201
|
+
light-dark(
|
|
202
|
+
oklch(var(--blocks-shadow-tint) / 0.05),
|
|
203
|
+
oklch(var(--blocks-shadow-tint) / 0.2)
|
|
204
|
+
);
|
|
205
|
+
--color-shadow-sm:
|
|
206
|
+
0 1px 3px 0
|
|
207
|
+
light-dark(
|
|
208
|
+
oklch(var(--blocks-shadow-tint) / 0.1),
|
|
209
|
+
oklch(var(--blocks-shadow-tint) / 0.3)
|
|
210
|
+
),
|
|
211
|
+
0 1px 2px -1px
|
|
212
|
+
light-dark(
|
|
213
|
+
oklch(var(--blocks-shadow-tint) / 0.1),
|
|
214
|
+
oklch(var(--blocks-shadow-tint) / 0.3)
|
|
215
|
+
);
|
|
216
|
+
--color-shadow-base:
|
|
217
|
+
0 4px 6px -1px
|
|
218
|
+
light-dark(
|
|
219
|
+
oklch(var(--blocks-shadow-tint) / 0.1),
|
|
220
|
+
oklch(var(--blocks-shadow-tint) / 0.4)
|
|
221
|
+
),
|
|
222
|
+
0 2px 4px -2px
|
|
223
|
+
light-dark(
|
|
224
|
+
oklch(var(--blocks-shadow-tint) / 0.1),
|
|
225
|
+
oklch(var(--blocks-shadow-tint) / 0.4)
|
|
226
|
+
);
|
|
227
|
+
--color-shadow-md:
|
|
228
|
+
0 10px 15px -3px
|
|
229
|
+
light-dark(
|
|
230
|
+
oklch(var(--blocks-shadow-tint) / 0.1),
|
|
231
|
+
oklch(var(--blocks-shadow-tint) / 0.4)
|
|
232
|
+
),
|
|
233
|
+
0 4px 6px -4px
|
|
234
|
+
light-dark(
|
|
235
|
+
oklch(var(--blocks-shadow-tint) / 0.1),
|
|
236
|
+
oklch(var(--blocks-shadow-tint) / 0.4)
|
|
237
|
+
);
|
|
238
|
+
--color-shadow-lg:
|
|
239
|
+
0 20px 25px -5px
|
|
240
|
+
light-dark(
|
|
241
|
+
oklch(var(--blocks-shadow-tint) / 0.1),
|
|
242
|
+
oklch(var(--blocks-shadow-tint) / 0.5)
|
|
243
|
+
),
|
|
244
|
+
0 8px 10px -6px
|
|
245
|
+
light-dark(
|
|
246
|
+
oklch(var(--blocks-shadow-tint) / 0.1),
|
|
247
|
+
oklch(var(--blocks-shadow-tint) / 0.5)
|
|
248
|
+
);
|
|
223
249
|
}
|
|
224
250
|
|
|
225
251
|
/* Shadow tint — declared on :root rather than inside @theme because
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
declare const _default: {
|
|
2
2
|
readonly accessibility: {
|
|
3
3
|
readonly avatar: "Avatar";
|
|
4
|
+
readonly breadcrumb: "Pfadnavigation";
|
|
5
|
+
readonly breadcrumbExpand: "Alle Pfadebenen anzeigen";
|
|
4
6
|
readonly clearInput: "Eingabe löschen";
|
|
5
7
|
readonly clearSearch: "Suche löschen";
|
|
6
8
|
readonly clearSelection: "Auswahl löschen";
|
|
@@ -19,6 +21,7 @@ declare const _default: {
|
|
|
19
21
|
readonly removableBadge: "Entfernbarer Badge";
|
|
20
22
|
readonly removeBadge: "Badge entfernen";
|
|
21
23
|
readonly removeFile: "{{name}} entfernen";
|
|
24
|
+
readonly removeTag: "{{label}} entfernen";
|
|
22
25
|
};
|
|
23
26
|
readonly button: {
|
|
24
27
|
readonly close: "Schließen";
|
package/dist/translations/de.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
accessibility: {
|
|
3
3
|
avatar: 'Avatar',
|
|
4
|
+
breadcrumb: 'Pfadnavigation',
|
|
5
|
+
breadcrumbExpand: 'Alle Pfadebenen anzeigen',
|
|
4
6
|
clearInput: 'Eingabe löschen',
|
|
5
7
|
clearSearch: 'Suche löschen',
|
|
6
8
|
clearSelection: 'Auswahl löschen',
|
|
@@ -18,7 +20,8 @@ export default {
|
|
|
18
20
|
toggleOptions: 'Optionen umschalten',
|
|
19
21
|
removableBadge: 'Entfernbarer Badge',
|
|
20
22
|
removeBadge: 'Badge entfernen',
|
|
21
|
-
removeFile: '{{name}} entfernen'
|
|
23
|
+
removeFile: '{{name}} entfernen',
|
|
24
|
+
removeTag: '{{label}} entfernen'
|
|
22
25
|
},
|
|
23
26
|
button: {
|
|
24
27
|
close: 'Schließen',
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
declare const _default: {
|
|
2
2
|
readonly accessibility: {
|
|
3
3
|
readonly avatar: "Avatar";
|
|
4
|
+
readonly breadcrumb: "Breadcrumb";
|
|
5
|
+
readonly breadcrumbExpand: "Show all breadcrumb items";
|
|
4
6
|
readonly clearInput: "Clear input";
|
|
5
7
|
readonly clearSearch: "Clear search";
|
|
6
8
|
readonly clearSelection: "Clear selection";
|
|
@@ -19,6 +21,7 @@ declare const _default: {
|
|
|
19
21
|
readonly removableBadge: "Removable badge";
|
|
20
22
|
readonly removeBadge: "Remove badge";
|
|
21
23
|
readonly removeFile: "Remove {{name}}";
|
|
24
|
+
readonly removeTag: "Remove {{label}}";
|
|
22
25
|
};
|
|
23
26
|
readonly button: {
|
|
24
27
|
readonly close: "Close";
|
package/dist/translations/en.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
accessibility: {
|
|
3
3
|
avatar: 'Avatar',
|
|
4
|
+
breadcrumb: 'Breadcrumb',
|
|
5
|
+
breadcrumbExpand: 'Show all breadcrumb items',
|
|
4
6
|
clearInput: 'Clear input',
|
|
5
7
|
clearSearch: 'Clear search',
|
|
6
8
|
clearSelection: 'Clear selection',
|
|
@@ -18,7 +20,8 @@ export default {
|
|
|
18
20
|
toggleOptions: 'Toggle options',
|
|
19
21
|
removableBadge: 'Removable badge',
|
|
20
22
|
removeBadge: 'Remove badge',
|
|
21
|
-
removeFile: 'Remove {{name}}'
|
|
23
|
+
removeFile: 'Remove {{name}}',
|
|
24
|
+
removeTag: 'Remove {{label}}'
|
|
22
25
|
},
|
|
23
26
|
button: {
|
|
24
27
|
close: 'Close',
|
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
* Generates a Tokens Studio-compatible JSON export from the Urbicon UI
|
|
5
5
|
* OKLCH design token system. Suitable for Figma plugins like "Tokens Studio
|
|
6
6
|
* for Figma" (formerly Figma Tokens).
|
|
7
|
+
*
|
|
8
|
+
* The values below mirror the token truth in `../style/foundation.css`
|
|
9
|
+
* (palettes, radii) and `../style/semantic.css` (surface/text/border roles,
|
|
10
|
+
* shadows). They are hardcoded — this module runs in the browser and cannot
|
|
11
|
+
* read the CSS files at runtime — but guarded against drift by the
|
|
12
|
+
* co-located `figma-token-export.test.ts`, which parses both CSS files and
|
|
13
|
+
* compares every value. If you change a token in the CSS, that test fails
|
|
14
|
+
* until the export here is updated to match.
|
|
15
|
+
*
|
|
16
|
+
* Semantic tokens resolve light/dark via CSS `light-dark()`; this export
|
|
17
|
+
* carries the **light-mode** resolution (Figma has no mode-aware token
|
|
18
|
+
* values in plain Tokens Studio JSON). Dark mode swaps at the foundation
|
|
19
|
+
* layer, so the palette ramps below contain every shade both modes use.
|
|
7
20
|
*/
|
|
8
21
|
export interface FigmaToken {
|
|
9
22
|
value: string;
|
|
@@ -4,10 +4,24 @@
|
|
|
4
4
|
* Generates a Tokens Studio-compatible JSON export from the Urbicon UI
|
|
5
5
|
* OKLCH design token system. Suitable for Figma plugins like "Tokens Studio
|
|
6
6
|
* for Figma" (formerly Figma Tokens).
|
|
7
|
+
*
|
|
8
|
+
* The values below mirror the token truth in `../style/foundation.css`
|
|
9
|
+
* (palettes, radii) and `../style/semantic.css` (surface/text/border roles,
|
|
10
|
+
* shadows). They are hardcoded — this module runs in the browser and cannot
|
|
11
|
+
* read the CSS files at runtime — but guarded against drift by the
|
|
12
|
+
* co-located `figma-token-export.test.ts`, which parses both CSS files and
|
|
13
|
+
* compares every value. If you change a token in the CSS, that test fails
|
|
14
|
+
* until the export here is updated to match.
|
|
15
|
+
*
|
|
16
|
+
* Semantic tokens resolve light/dark via CSS `light-dark()`; this export
|
|
17
|
+
* carries the **light-mode** resolution (Figma has no mode-aware token
|
|
18
|
+
* values in plain Tokens Studio JSON). Dark mode swaps at the foundation
|
|
19
|
+
* layer, so the palette ramps below contain every shade both modes use.
|
|
7
20
|
*/
|
|
8
21
|
const foundationColors = {
|
|
9
22
|
neutral: {
|
|
10
23
|
'0': 'oklch(1 0 0)',
|
|
24
|
+
'25': 'oklch(0.99 0.002 240)',
|
|
11
25
|
'50': 'oklch(0.98 0.005 240)',
|
|
12
26
|
'100': 'oklch(0.95 0.008 240)',
|
|
13
27
|
'200': 'oklch(0.89 0.012 240)',
|
|
@@ -15,8 +29,11 @@ const foundationColors = {
|
|
|
15
29
|
'400': 'oklch(0.7 0.015 240)',
|
|
16
30
|
'500': 'oklch(0.55 0.016 240)',
|
|
17
31
|
'600': 'oklch(0.42 0.017 240)',
|
|
32
|
+
'650': 'oklch(0.38 0.016 240)',
|
|
18
33
|
'700': 'oklch(0.32 0.016 240)',
|
|
34
|
+
'750': 'oklch(0.28 0.014 240)',
|
|
19
35
|
'800': 'oklch(0.23 0.015 240)',
|
|
36
|
+
'850': 'oklch(0.18 0.014 240)',
|
|
20
37
|
'900': 'oklch(0.15 0.012 240)',
|
|
21
38
|
'950': 'oklch(0.08 0.008 240)'
|
|
22
39
|
},
|
|
@@ -46,18 +63,33 @@ const foundationColors = {
|
|
|
46
63
|
'900': 'oklch(0.25 0.08 280)',
|
|
47
64
|
'950': 'oklch(0.18 0.05 280)'
|
|
48
65
|
},
|
|
66
|
+
'warm-neutral': {
|
|
67
|
+
'50': 'oklch(0.96 0.004 45)',
|
|
68
|
+
'100': 'oklch(0.92 0.006 45)',
|
|
69
|
+
'200': 'oklch(0.86 0.008 45)',
|
|
70
|
+
'300': 'oklch(0.78 0.01 45)',
|
|
71
|
+
'400': 'oklch(0.65 0.012 45)',
|
|
72
|
+
'500': 'oklch(0.5 0.008 45)',
|
|
73
|
+
'600': 'oklch(0.42 0.01 45)',
|
|
74
|
+
'700': 'oklch(0.35 0.012 45)',
|
|
75
|
+
'800': 'oklch(0.28 0.01 45)',
|
|
76
|
+
'900': 'oklch(0.2 0.008 45)',
|
|
77
|
+
'950': 'oklch(0.12 0.006 45)'
|
|
78
|
+
},
|
|
79
|
+
/* success/danger 400–700 are the WCAG-darkened ramps: white text on the
|
|
80
|
+
solid intent backgrounds passes AA (4.5:1). */
|
|
49
81
|
success: {
|
|
50
82
|
'50': 'oklch(0.95 0.03 140)',
|
|
51
83
|
'100': 'oklch(0.9 0.05 140)',
|
|
52
84
|
'200': 'oklch(0.82 0.08 140)',
|
|
53
85
|
'300': 'oklch(0.74 0.11 140)',
|
|
54
|
-
'400': 'oklch(0.
|
|
55
|
-
'500': 'oklch(0.
|
|
56
|
-
'600': 'oklch(0.
|
|
57
|
-
'700': 'oklch(0.
|
|
58
|
-
'800': 'oklch(0.
|
|
59
|
-
'900': 'oklch(0.
|
|
60
|
-
'950': 'oklch(0.
|
|
86
|
+
'400': 'oklch(0.62 0.14 140)',
|
|
87
|
+
'500': 'oklch(0.5 0.15 140)',
|
|
88
|
+
'600': 'oklch(0.44 0.14 140)',
|
|
89
|
+
'700': 'oklch(0.38 0.12 140)',
|
|
90
|
+
'800': 'oklch(0.3 0.1 140)',
|
|
91
|
+
'900': 'oklch(0.22 0.08 140)',
|
|
92
|
+
'950': 'oklch(0.14 0.05 140)'
|
|
61
93
|
},
|
|
62
94
|
warning: {
|
|
63
95
|
'50': 'oklch(0.95 0.05 80)',
|
|
@@ -77,39 +109,67 @@ const foundationColors = {
|
|
|
77
109
|
'100': 'oklch(0.9 0.08 25)',
|
|
78
110
|
'200': 'oklch(0.82 0.1 25)',
|
|
79
111
|
'300': 'oklch(0.74 0.12 25)',
|
|
80
|
-
'400': 'oklch(0.
|
|
81
|
-
'500': 'oklch(0.
|
|
82
|
-
'600': 'oklch(0.
|
|
83
|
-
'700': 'oklch(0.
|
|
84
|
-
'800': 'oklch(0.
|
|
85
|
-
'900': 'oklch(0.
|
|
86
|
-
'950': 'oklch(0.
|
|
112
|
+
'400': 'oklch(0.62 0.16 25)',
|
|
113
|
+
'500': 'oklch(0.5 0.17 25)',
|
|
114
|
+
'600': 'oklch(0.44 0.16 25)',
|
|
115
|
+
'700': 'oklch(0.38 0.14 25)',
|
|
116
|
+
'800': 'oklch(0.3 0.12 25)',
|
|
117
|
+
'900': 'oklch(0.22 0.1 25)',
|
|
118
|
+
'950': 'oklch(0.14 0.07 25)'
|
|
119
|
+
},
|
|
120
|
+
info: {
|
|
121
|
+
'50': 'oklch(0.96 0.025 220)',
|
|
122
|
+
'100': 'oklch(0.92 0.045 220)',
|
|
123
|
+
'200': 'oklch(0.84 0.075 220)',
|
|
124
|
+
'300': 'oklch(0.76 0.105 220)',
|
|
125
|
+
'400': 'oklch(0.66 0.13 220)',
|
|
126
|
+
'500': 'oklch(0.55 0.14 220)',
|
|
127
|
+
'600': 'oklch(0.48 0.13 220)',
|
|
128
|
+
'700': 'oklch(0.4 0.11 220)',
|
|
129
|
+
'800': 'oklch(0.32 0.09 220)',
|
|
130
|
+
'900': 'oklch(0.24 0.07 220)',
|
|
131
|
+
'950': 'oklch(0.16 0.05 220)'
|
|
87
132
|
}
|
|
88
133
|
};
|
|
134
|
+
/** Light-mode resolution of the semantic color roles in semantic.css. */
|
|
89
135
|
const semanticTokens = {
|
|
90
136
|
surface: {
|
|
91
|
-
base: { value: '{color.neutral.0}', description: '
|
|
92
|
-
|
|
93
|
-
elevated: { value: '{color.neutral.50}', description: '
|
|
94
|
-
overlay: { value: '{color.neutral.0}', description: '
|
|
137
|
+
base: { value: '{color.neutral.0}', description: 'L1 — the page itself' },
|
|
138
|
+
quiet: { value: '{color.neutral.25}', description: 'L0 — ground beneath the page' },
|
|
139
|
+
elevated: { value: '{color.neutral.50}', description: 'L2 — lifted surfaces (popover, menu)' },
|
|
140
|
+
overlay: { value: '{color.neutral.0}', description: 'L3 — dialog/drawer/toast background' },
|
|
141
|
+
interactive: { value: '{color.neutral.100}', description: 'Interactive control background' },
|
|
142
|
+
hover: { value: '{color.neutral.100}', description: 'Hover state background' },
|
|
143
|
+
active: { value: '{color.neutral.200}', description: 'Active/pressed state background' },
|
|
144
|
+
disabled: { value: '{color.neutral.100}', description: 'Disabled surface' },
|
|
145
|
+
selected: { value: '{color.primary.50}', description: 'Selected item background' },
|
|
95
146
|
subtle: { value: '{color.neutral.50}', description: 'Subtle background' },
|
|
96
147
|
inverted: { value: '{color.neutral.900}', description: 'Inverted surface' }
|
|
97
148
|
},
|
|
98
149
|
text: {
|
|
99
150
|
primary: { value: '{color.neutral.900}', description: 'Primary text' },
|
|
151
|
+
inverted: { value: '{color.neutral.0}', description: 'Inverted text (on dark bg)' },
|
|
100
152
|
secondary: { value: '{color.neutral.700}', description: 'Secondary text' },
|
|
101
|
-
tertiary: { value: '{color.neutral.
|
|
153
|
+
tertiary: { value: '{color.neutral.600}', description: 'Tertiary text (WCAG AA on base)' },
|
|
154
|
+
quaternary: { value: '{color.neutral.500}', description: 'Quaternary text (lowest emphasis)' },
|
|
102
155
|
disabled: { value: '{color.neutral.300}', description: 'Disabled text' },
|
|
103
|
-
|
|
104
|
-
'on-primary': { value: '{color.neutral.0}', description: 'Text on primary color bg' }
|
|
156
|
+
'on-dark': { value: '{color.neutral.0}', description: 'Text on dark surfaces' },
|
|
157
|
+
'on-primary': { value: '{color.neutral.0}', description: 'Text on primary color bg' },
|
|
158
|
+
'on-surface': { value: '{color.neutral.900}', description: 'Text on tinted surfaces' }
|
|
105
159
|
},
|
|
106
160
|
border: {
|
|
161
|
+
hairline: {
|
|
162
|
+
value: 'rgb(0 0 0 / 0.08)',
|
|
163
|
+
description: 'Quietest structural divider (rows, separators)'
|
|
164
|
+
},
|
|
107
165
|
subtle: { value: '{color.neutral.200}', description: 'Subtle border' },
|
|
108
166
|
default: { value: '{color.neutral.300}', description: 'Default border' },
|
|
109
167
|
emphasis: { value: '{color.neutral.400}', description: 'Emphasized border' },
|
|
110
168
|
strong: { value: '{color.neutral.500}', description: 'Strong border' }
|
|
111
169
|
}
|
|
112
170
|
};
|
|
171
|
+
/* Tailwind 4 default spacing scale (4px per unit) — blocks defines no
|
|
172
|
+
custom spacing tokens. */
|
|
113
173
|
const spacingTokens = {
|
|
114
174
|
'0': '0',
|
|
115
175
|
'1': '4px',
|
|
@@ -123,14 +183,24 @@ const spacingTokens = {
|
|
|
123
183
|
'12': '48px',
|
|
124
184
|
'16': '64px'
|
|
125
185
|
};
|
|
186
|
+
/* Physical radius scale + the semantic 3-tier vocabulary (commit/modify/
|
|
187
|
+
contain, plus the bridge adjacency radius) from foundation.css.
|
|
188
|
+
rem values are exported as px (1rem = 16px) for Figma. */
|
|
126
189
|
const borderRadiusTokens = {
|
|
127
|
-
|
|
128
|
-
sm: '
|
|
190
|
+
xs: '2px',
|
|
191
|
+
sm: '4px',
|
|
129
192
|
md: '6px',
|
|
130
193
|
lg: '8px',
|
|
131
194
|
xl: '12px',
|
|
132
|
-
|
|
195
|
+
'2xl': '16px',
|
|
196
|
+
'3xl': '24px',
|
|
197
|
+
'4xl': '32px',
|
|
198
|
+
commit: { value: '9999px', description: 'Tier: actions, identity, status (pill)' },
|
|
199
|
+
modify: { value: '{borderRadius.sm}', description: 'Tier: editable surfaces, navigation' },
|
|
200
|
+
contain: { value: '{borderRadius.xs}', description: 'Tier: containers, panels, layout' },
|
|
201
|
+
bridge: { value: '{borderRadius.md}', description: 'Adjacency radius: panel anchored to a pill' }
|
|
133
202
|
};
|
|
203
|
+
/** Light-mode resolution of the shadow tokens (shadow tint = pure black). */
|
|
134
204
|
const shadowTokens = {
|
|
135
205
|
xs: '0 1px 2px 0 rgba(0,0,0,0.05)',
|
|
136
206
|
sm: '0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px -1px rgba(0,0,0,0.1)',
|
|
@@ -174,8 +244,11 @@ function buildSpacingTokens() {
|
|
|
174
244
|
}
|
|
175
245
|
function buildBorderRadiusTokens() {
|
|
176
246
|
const result = {};
|
|
177
|
-
for (const [name,
|
|
178
|
-
result[name] =
|
|
247
|
+
for (const [name, def] of Object.entries(borderRadiusTokens)) {
|
|
248
|
+
result[name] =
|
|
249
|
+
typeof def === 'string'
|
|
250
|
+
? { value: def, type: 'borderRadius' }
|
|
251
|
+
: { value: def.value, type: 'borderRadius', description: def.description };
|
|
179
252
|
}
|
|
180
253
|
return result;
|
|
181
254
|
}
|
|
@@ -103,8 +103,14 @@ export interface GuideTour {
|
|
|
103
103
|
* consumer can inject a server-state adapter. Kept deliberately tiny.
|
|
104
104
|
*/
|
|
105
105
|
export interface GuideStorageAdapter {
|
|
106
|
-
/**
|
|
107
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Returns the persisted set of seen/completed ids. Return a `string[]`
|
|
108
|
+
* synchronously (localStorage, the default) or a `Promise<string[]>` for a
|
|
109
|
+
* DB-/remote-backed store. While an async load is pending the seen set starts
|
|
110
|
+
* empty and is merged (union) with the resolved ids once they arrive — so a
|
|
111
|
+
* tour may briefly be startable before the store answers.
|
|
112
|
+
*/
|
|
113
|
+
load(): string[] | Promise<string[]>;
|
|
108
114
|
/** Persists the full set of seen/completed ids. */
|
|
109
115
|
save(ids: string[]): void;
|
|
110
116
|
}
|
|
@@ -156,6 +156,22 @@ export class GuideController {
|
|
|
156
156
|
#targets = new SvelteMap();
|
|
157
157
|
/** Persisted "seen" ids. */
|
|
158
158
|
#seen;
|
|
159
|
+
/** False only while an async `storage.load()` is still pending. */
|
|
160
|
+
#seenLoaded = true;
|
|
161
|
+
/**
|
|
162
|
+
* Set when the user writes (markSeen/resetSeen) while an async load is still
|
|
163
|
+
* pending, so the load's `.then` persists the merged union once — writing
|
|
164
|
+
* mid-load directly would clobber the remote store before its ids are merged in.
|
|
165
|
+
*/
|
|
166
|
+
#pendingSeenWrite = false;
|
|
167
|
+
/**
|
|
168
|
+
* Ids the user forgot during the load window, so the merge doesn't resurrect
|
|
169
|
+
* them from the freshly-loaded remote set. A plain `Set` — pure bookkeeping,
|
|
170
|
+
* never rendered, so the `SvelteSet` rule doesn't apply.
|
|
171
|
+
*/
|
|
172
|
+
#pendingRemovals = new Set();
|
|
173
|
+
/** `resetSeen()` (clear-all) during the load window: drop the remote set entirely. */
|
|
174
|
+
#pendingClearAll = false;
|
|
159
175
|
#storage;
|
|
160
176
|
#overlayStack;
|
|
161
177
|
#dev;
|
|
@@ -209,7 +225,58 @@ export class GuideController {
|
|
|
209
225
|
// `?? false` keeps `#dev` a strict boolean and means non-Vite consumers
|
|
210
226
|
// simply get no dev warnings (rather than a crash).
|
|
211
227
|
this.#dev = options.dev ?? import.meta.env?.DEV ?? false;
|
|
212
|
-
|
|
228
|
+
// Sync adapters (localStorage) seed the set immediately. Async adapters
|
|
229
|
+
// (DB/remote) start empty and get their ids merged in when the promise
|
|
230
|
+
// settles — union, not replace, so anything marked seen in the meantime
|
|
231
|
+
// survives. A rejected load is swallowed (dev-warned): the tour just stays
|
|
232
|
+
// "unseen", which fails open rather than hiding help behind a broken store.
|
|
233
|
+
const loaded = this.#storage.load();
|
|
234
|
+
if (Array.isArray(loaded)) {
|
|
235
|
+
this.#seen = new SvelteSet(loaded);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
this.#seen = new SvelteSet();
|
|
239
|
+
this.#seenLoaded = false;
|
|
240
|
+
loaded
|
|
241
|
+
.then((ids) => {
|
|
242
|
+
// Merge the loaded set in, but honour writes made during the window:
|
|
243
|
+
// skip everything if the user cleared all, and don't resurrect ids the
|
|
244
|
+
// user explicitly forgot. Adds are safe (union is idempotent).
|
|
245
|
+
if (!this.#pendingClearAll) {
|
|
246
|
+
for (const id of ids) {
|
|
247
|
+
if (!this.#pendingRemovals.has(id))
|
|
248
|
+
this.#seen.add(id);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
this.#seenLoaded = true;
|
|
252
|
+
// Reconcile persistence: if the user wrote during the window, the store
|
|
253
|
+
// still holds the pre-merge state (we deliberately didn't save then), so
|
|
254
|
+
// persist the union now. Nothing wrote → leave the store untouched (no
|
|
255
|
+
// write-amplification of a remote we just read).
|
|
256
|
+
if (this.#pendingSeenWrite)
|
|
257
|
+
this.#storage.save([...this.#seen]);
|
|
258
|
+
})
|
|
259
|
+
.catch((err) => {
|
|
260
|
+
// Read failed: fail open (tour stays "unseen"). We don't persist the
|
|
261
|
+
// window's in-memory writes here — the store is in an unknown state, and
|
|
262
|
+
// blindly saving could destroy data we simply couldn't read ("read
|
|
263
|
+
// tolerant, write strict"). Later writes persist normally.
|
|
264
|
+
this.#seenLoaded = true;
|
|
265
|
+
if (this.#dev)
|
|
266
|
+
console.warn('[Guide] storage.load() rejected:', err);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Persist the seen-set — unless an async load is still pending, in which case a
|
|
272
|
+
* direct save would clobber the not-yet-loaded remote store. Defer to the load's
|
|
273
|
+
* `.then` reconciliation instead (see the constructor).
|
|
274
|
+
*/
|
|
275
|
+
#persistSeen() {
|
|
276
|
+
if (this.#seenLoaded)
|
|
277
|
+
this.#storage.save([...this.#seen]);
|
|
278
|
+
else
|
|
279
|
+
this.#pendingSeenWrite = true;
|
|
213
280
|
}
|
|
214
281
|
// ─── Target registry ──────────────────────────────────────────────────────
|
|
215
282
|
/**
|
|
@@ -738,15 +805,29 @@ export class GuideController {
|
|
|
738
805
|
if (this.#seen.has(id))
|
|
739
806
|
return;
|
|
740
807
|
this.#seen.add(id);
|
|
741
|
-
|
|
808
|
+
// Re-seeing an id undoes a forget that's still pending reconciliation.
|
|
809
|
+
if (!this.#seenLoaded)
|
|
810
|
+
this.#pendingRemovals.delete(id);
|
|
811
|
+
this.#persistSeen();
|
|
742
812
|
}
|
|
743
813
|
/** Forget one id, or all of them when called without an argument. */
|
|
744
814
|
resetSeen(id) {
|
|
745
|
-
if (id === undefined)
|
|
815
|
+
if (id === undefined) {
|
|
746
816
|
this.#seen.clear();
|
|
747
|
-
|
|
817
|
+
// Clear-all during a pending load must survive the merge: drop the whole
|
|
818
|
+
// remote set, superseding any earlier pending removals.
|
|
819
|
+
if (!this.#seenLoaded) {
|
|
820
|
+
this.#pendingClearAll = true;
|
|
821
|
+
this.#pendingRemovals.clear();
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
else {
|
|
748
825
|
this.#seen.delete(id);
|
|
749
|
-
|
|
826
|
+
// Record the forget so the pending-load merge doesn't resurrect it.
|
|
827
|
+
if (!this.#seenLoaded)
|
|
828
|
+
this.#pendingRemovals.add(id);
|
|
829
|
+
}
|
|
830
|
+
this.#persistSeen();
|
|
750
831
|
}
|
|
751
832
|
/** Snapshot of all seen ids. */
|
|
752
833
|
get seenIds() {
|