@urbicon-ui/blocks 6.40.3 → 6.43.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.
Files changed (84) hide show
  1. package/dist/components/Calendar/calendar.variants.d.ts +63 -63
  2. package/dist/components/Chat/A2UIView/A2UINode.svelte +20 -39
  3. package/dist/components/Chat/A2UIView/A2UIView.svelte +47 -50
  4. package/dist/components/Chat/A2UIView/a2ui-basic-catalog.d.ts +17 -0
  5. package/dist/components/Chat/A2UIView/a2ui-basic-catalog.js +69 -0
  6. package/dist/components/Chat/A2UIView/a2ui-catalog.d.ts +95 -0
  7. package/dist/components/Chat/A2UIView/a2ui-catalog.js +87 -0
  8. package/dist/components/Chat/A2UIView/a2ui-node-common.d.ts +40 -0
  9. package/dist/components/Chat/A2UIView/a2ui-node-common.js +72 -0
  10. package/dist/components/Chat/A2UIView/a2ui-prompt.d.ts +21 -10
  11. package/dist/components/Chat/A2UIView/a2ui-prompt.js +170 -24
  12. package/dist/components/Chat/A2UIView/a2ui-registry.d.ts +1 -1
  13. package/dist/components/Chat/A2UIView/a2ui-registry.js +2 -1
  14. package/dist/components/Chat/A2UIView/a2ui-render.d.ts +30 -0
  15. package/dist/components/Chat/A2UIView/a2ui-render.js +61 -23
  16. package/dist/components/Chat/A2UIView/a2ui-router.d.ts +136 -0
  17. package/dist/components/Chat/A2UIView/a2ui-router.js +264 -0
  18. package/dist/components/Chat/A2UIView/a2ui-schema.d.ts +45 -0
  19. package/dist/components/Chat/A2UIView/a2ui-schema.js +133 -0
  20. package/dist/components/Chat/A2UIView/a2ui-stream.d.ts +120 -0
  21. package/dist/components/Chat/A2UIView/a2ui-stream.js +406 -0
  22. package/dist/components/Chat/A2UIView/a2ui-transcript.d.ts +65 -0
  23. package/dist/components/Chat/A2UIView/a2ui-transcript.js +101 -0
  24. package/dist/components/Chat/A2UIView/a2ui-validate.d.ts +33 -1
  25. package/dist/components/Chat/A2UIView/a2ui-validate.js +167 -63
  26. package/dist/components/Chat/A2UIView/a2ui.types.d.ts +50 -0
  27. package/dist/components/Chat/A2UIView/a2ui.types.js +38 -1
  28. package/dist/components/Chat/A2UIView/index.d.ts +35 -2
  29. package/dist/components/Chat/A2UIView/index.js +13 -0
  30. package/dist/components/Chat/A2UIView/urbicon/UrbiconA2UINode.svelte +831 -0
  31. package/dist/components/Chat/A2UIView/urbicon/UrbiconA2UINode.svelte.d.ts +4 -0
  32. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-catalog.d.ts +14 -0
  33. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-catalog.js +87 -0
  34. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-registry.d.ts +78 -0
  35. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-registry.js +783 -0
  36. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon.variants.d.ts +43 -0
  37. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon.variants.js +33 -0
  38. package/dist/components/Chat/A2UIView/urbicon/urbicon-axes.gen.d.ts +7 -0
  39. package/dist/components/Chat/A2UIView/urbicon/urbicon-axes.gen.js +86 -0
  40. package/dist/components/Chat/ChatMessage/chat-message.variants.d.ts +19 -19
  41. package/dist/components/CopyButton/copy-button.variants.d.ts +4 -4
  42. package/dist/components/FileUpload/FileUpload.svelte +8 -5
  43. package/dist/components/FileUpload/fileUpload.variants.js +15 -4
  44. package/dist/components/PinInput/PinInput.svelte +1 -0
  45. package/dist/components/PinInput/pin-input.variants.js +14 -1
  46. package/dist/components/TimeInput/time-input.variants.js +16 -1
  47. package/dist/i18n/index.d.ts +2 -398
  48. package/dist/internal/field-chrome.d.ts +18 -1
  49. package/dist/internal/field-chrome.js +18 -1
  50. package/dist/primitives/Alert/alert.variants.d.ts +8 -8
  51. package/dist/primitives/Avatar/avatar.variants.js +4 -1
  52. package/dist/primitives/Badge/badge.variants.js +11 -2
  53. package/dist/primitives/Button/button.variants.js +4 -1
  54. package/dist/primitives/Card/card.variants.js +4 -1
  55. package/dist/primitives/Checkbox/checkbox.variants.js +7 -1
  56. package/dist/primitives/Combobox/Combobox.svelte +9 -1
  57. package/dist/primitives/Combobox/combobox.variants.d.ts +25 -0
  58. package/dist/primitives/Combobox/combobox.variants.js +32 -3
  59. package/dist/primitives/Combobox/index.d.ts +8 -2
  60. package/dist/primitives/Dialog/dialog.variants.js +4 -1
  61. package/dist/primitives/Drawer/drawer.variants.js +4 -1
  62. package/dist/primitives/Input/input.variants.js +17 -1
  63. package/dist/primitives/JourneyTimeline/journey-timeline.variants.d.ts +22 -22
  64. package/dist/primitives/Menu/menu.variants.js +5 -1
  65. package/dist/primitives/Progress/progress.variants.js +5 -2
  66. package/dist/primitives/RadioGroup/radioGroup.variants.js +68 -9
  67. package/dist/primitives/Select/select.variants.js +13 -4
  68. package/dist/primitives/Slider/Slider.svelte +4 -1
  69. package/dist/primitives/Slider/slider.variants.js +9 -2
  70. package/dist/primitives/Spinner/spinner.variants.d.ts +16 -16
  71. package/dist/primitives/Stepper/stepper.variants.d.ts +11 -11
  72. package/dist/primitives/Textarea/textarea.variants.js +15 -1
  73. package/dist/primitives/Toast/Toaster.svelte +6 -9
  74. package/dist/primitives/Toast/toast.variants.d.ts +12 -12
  75. package/dist/primitives/Toast/toast.variants.js +5 -1
  76. package/dist/primitives/Toggle/toggle.variants.js +92 -18
  77. package/dist/primitives/Tooltip/tooltip.variants.d.ts +3 -3
  78. package/dist/primitives/Tooltip/tooltip.variants.js +5 -1
  79. package/dist/style/themes/index.css +8 -2
  80. package/dist/utils/guide.svelte.js +16 -4
  81. package/dist/utils/persistent-state.svelte.d.ts +25 -1
  82. package/dist/utils/persistent-state.svelte.js +98 -10
  83. package/docs/MIGRATION-v5.md +29 -0
  84. package/package.json +3 -3
@@ -1,70 +1,70 @@
1
1
  import { type SlotNames, type VariantProps } from '../../utils/variants.js';
2
2
  export declare const toastVariants: ((props?: {
3
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
3
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
4
4
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
5
5
  } | undefined) => {
6
6
  container: (props?: ({
7
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
7
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
8
8
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
9
9
  } & {
10
10
  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;
11
11
  }) | undefined) => string;
12
12
  toast: (props?: ({
13
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
13
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
14
14
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
15
15
  } & {
16
16
  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;
17
17
  }) | undefined) => string;
18
18
  icon: (props?: ({
19
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
19
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
20
20
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
21
21
  } & {
22
22
  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;
23
23
  }) | undefined) => string;
24
24
  content: (props?: ({
25
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
25
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
26
26
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
27
27
  } & {
28
28
  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;
29
29
  }) | undefined) => string;
30
30
  title: (props?: ({
31
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
31
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
32
32
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
33
33
  } & {
34
34
  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;
35
35
  }) | undefined) => string;
36
36
  description: (props?: ({
37
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
37
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
38
38
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
39
39
  } & {
40
40
  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;
41
41
  }) | undefined) => string;
42
42
  actions: (props?: ({
43
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
43
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
44
44
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
45
45
  } & {
46
46
  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;
47
47
  }) | undefined) => string;
48
48
  actionButton: (props?: ({
49
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
49
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
50
50
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
51
51
  } & {
52
52
  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;
53
53
  }) | undefined) => string;
54
54
  cancelButton: (props?: ({
55
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
55
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
56
56
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
57
57
  } & {
58
58
  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;
59
59
  }) | undefined) => string;
60
60
  dismissButton: (props?: ({
61
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
61
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
62
62
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
63
63
  } & {
64
64
  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;
65
65
  }) | undefined) => string;
66
66
  progress: (props?: ({
67
- intent?: "info" | "primary" | "success" | "warning" | "danger" | "neutral" | undefined;
67
+ intent?: "primary" | "success" | "warning" | "danger" | "neutral" | "info" | undefined;
68
68
  placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
69
69
  } & {
70
70
  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;
@@ -10,7 +10,11 @@ export const toastVariants = tv({
10
10
  'pointer-events-auto flex items-start gap-3 w-full max-w-sm',
11
11
  'rounded-contain p-4',
12
12
  'shadow-[var(--blocks-shadow-lg)]',
13
- 'transition-[color,background-color,box-shadow,opacity,transform] duration-[var(--blocks-duration-normal)] ease-[var(--blocks-ease-smooth)]'
13
+ // No transform entry: the enter/exit motion is Svelte's `transition:fly`,
14
+ // which runs as a CSS *animation* (keyframes) and ignores
15
+ // `transition-property` entirely. Nothing on this slot sets a
16
+ // scale/translate/rotate utility, so a `transform` entry was dead weight.
17
+ 'transition-[color,background-color,box-shadow,opacity] duration-[var(--blocks-duration-normal)] ease-[var(--blocks-ease-smooth)]'
14
18
  ],
15
19
  icon: 'shrink-0 mt-0.5 w-5 h-5',
16
20
  content: 'flex-1 min-w-0',
@@ -8,7 +8,26 @@ export const toggleVariants = tv({
8
8
  // rectangle switch that reads as inline-toolbar control.
9
9
  track: [
10
10
  'relative inline-flex items-center',
11
- 'transition-[color,background-color,border-color,box-shadow] duration-[var(--blocks-duration-fast)] ease-out',
11
+ 'transition-[color,background-color,border-color,box-shadow,scale] duration-[var(--blocks-duration-fast)] ease-out',
12
+ // Press feedback on the control surface — the same small-element press
13
+ // cue Checkbox took from Badge/Avatar (`scale-95`), with `group-active`
14
+ // so pressing the label squeezes the switch too. It rides the TRACK,
15
+ // not the thumb, for three reasons:
16
+ // 1. the track is the switch's control surface — Checkbox puts the
17
+ // cue on `box`, and the whole subtree (thumb included) squeezes
18
+ // with it, so one class covers the entire control;
19
+ // 2. the `dot` variant *hides* the thumb, so a thumb-mounted cue
20
+ // would silently vanish exactly where the control is smallest;
21
+ // 3. the thumb already drives motion through `translate` (its
22
+ // resting `-translate-y-1/2` plus the per-size `translate-x-*`).
23
+ // Tailwind 4 compiles `scale-*` to the discrete `scale` property,
24
+ // which CSS applies AFTER `translate` about the element's own
25
+ // centre — so a thumb-mounted cue would shrink the knob in place
26
+ // at whichever end of the track it sits, reading as a rendering
27
+ // glitch rather than a press.
28
+ // `scale` is in the transition list above, and reduced motion collapses
29
+ // `--blocks-duration-fast` to 1ms.
30
+ 'group-active:scale-95',
12
31
  'border border-transparent',
13
32
  'peer-focus-visible:ring-2 peer-focus-visible:ring-primary/50',
14
33
  'peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-surface-base'
@@ -104,7 +123,18 @@ export const toggleVariants = tv({
104
123
  variant: 'default',
105
124
  checked: false,
106
125
  class: {
107
- track: 'bg-surface-interactive',
126
+ // Off-state hover steps the boundary up to `border-emphasis` — the
127
+ // same destination Checkbox's unchecked `outlined` box reaches, on
128
+ // the border the track already reserves (`border border-transparent`
129
+ // in the slot base, so nothing shifts).
130
+ // Deliberately NOT a fill step: the off track sits on
131
+ // `surface-interactive`, which resolves to the SAME value as
132
+ // `surface-hover` in light mode (both neutral-100) and as
133
+ // `surface-active` in dark (both neutral-700) — in the library
134
+ // default *and* under the docs Rooms skin. Either fill token would
135
+ // therefore be a silent no-op in one of the two modes; the border is
136
+ // the only step that reads in both.
137
+ track: 'bg-surface-interactive group-hover:border-border-emphasis',
108
138
  thumb: 'translate-x-0'
109
139
  }
110
140
  },
@@ -113,7 +143,11 @@ export const toggleVariants = tv({
113
143
  variant: 'default',
114
144
  checked: false,
115
145
  withBorder: true,
116
- class: { track: 'border-border-strong' }
146
+ // `border-strong` is the top of the border ladder, so the off-state
147
+ // hover above would *weaken* it (strong → emphasis). Pin the hover
148
+ // bucket to strong: an opt-in permanent boundary must not soften when
149
+ // the pointer arrives.
150
+ class: { track: 'border-border-strong group-hover:border-border-strong' }
117
151
  },
118
152
  {
119
153
  variant: 'default',
@@ -122,41 +156,58 @@ export const toggleVariants = tv({
122
156
  class: { track: 'ring-1 ring-inset ring-surface-base/40' }
123
157
  },
124
158
  // ── Checked track per intent (Switch-Pill only) ──
159
+ // Hover/active darken through the intent interaction-layer tokens — the
160
+ // same `bg-<intent>-hover` / `bg-<intent>-active` ladder Button and
161
+ // Checkbox use — via `group-*` so hovering/pressing the label counts too.
162
+ // The border stays on the base intent stop (as in Checkbox), leaving a
163
+ // hairline rim that makes the fill step legible.
125
164
  {
126
165
  variant: 'default',
127
166
  checked: true,
128
167
  intent: 'primary',
129
- class: { track: 'bg-primary border-primary' }
168
+ class: {
169
+ track: 'bg-primary border-primary group-hover:bg-primary-hover group-active:bg-primary-active'
170
+ }
130
171
  },
131
172
  {
132
173
  variant: 'default',
133
174
  checked: true,
134
175
  intent: 'secondary',
135
- class: { track: 'bg-secondary border-secondary' }
176
+ class: {
177
+ track: 'bg-secondary border-secondary group-hover:bg-secondary-hover group-active:bg-secondary-active'
178
+ }
136
179
  },
137
180
  {
138
181
  variant: 'default',
139
182
  checked: true,
140
183
  intent: 'success',
141
- class: { track: 'bg-success border-success' }
184
+ class: {
185
+ track: 'bg-success border-success group-hover:bg-success-hover group-active:bg-success-active'
186
+ }
142
187
  },
143
188
  {
144
189
  variant: 'default',
145
190
  checked: true,
146
191
  intent: 'warning',
147
- class: { track: 'bg-warning border-warning' }
192
+ class: {
193
+ track: 'bg-warning border-warning group-hover:bg-warning-hover group-active:bg-warning-active'
194
+ }
148
195
  },
149
196
  {
150
197
  variant: 'default',
151
198
  checked: true,
152
199
  intent: 'danger',
153
- class: { track: 'bg-danger border-danger' }
200
+ class: {
201
+ track: 'bg-danger border-danger group-hover:bg-danger-hover group-active:bg-danger-active'
202
+ }
154
203
  },
155
204
  {
156
205
  variant: 'default',
157
206
  checked: true,
158
207
  intent: 'neutral',
159
- class: { track: 'bg-neutral border-neutral' }
208
+ class: {
209
+ track: 'bg-neutral border-neutral group-hover:bg-neutral-hover group-active:bg-neutral-active'
210
+ }
160
211
  },
161
212
  // ── Error state: danger boundary on the unchecked track (Switch-Pill) ──
162
213
  // Mirrors Checkbox ("error overrides unchecked border"): the off state
@@ -165,11 +216,16 @@ export const toggleVariants = tv({
165
216
  // The dot-variant twin lives at the END of the compound list so it
166
217
  // folds over the dot-unchecked `border-border-default` (order is
167
218
  // semantic — later compounds win conflicting buckets).
219
+ // `group-hover:border-danger` pins the hover bucket as well — without it
220
+ // the off-state hover step above would repaint the error boundary neutral
221
+ // the moment the pointer arrives, which is exactly when the mark matters.
168
222
  {
169
223
  variant: 'default',
170
224
  error: true,
171
225
  checked: false,
172
- class: { track: 'border-danger peer-focus-visible:ring-danger/40' }
226
+ class: {
227
+ track: 'border-danger group-hover:border-danger peer-focus-visible:ring-danger/40'
228
+ }
173
229
  },
174
230
  // ── Thumb translation per size when checked (Switch-Pill only) ──
175
231
  { variant: 'default', checked: true, size: 'xs', class: { thumb: 'translate-x-4' } },
@@ -193,50 +249,68 @@ export const toggleVariants = tv({
193
249
  {
194
250
  variant: 'dot',
195
251
  checked: false,
196
- class: { track: 'border-border-default' }
252
+ // Off-state hover: `border-default` → `border-emphasis`, the exact
253
+ // ladder Checkbox's unchecked `outlined` box walks (the dot is
254
+ // outline-only, so its boundary is the whole control).
255
+ class: { track: 'border-border-default group-hover:border-border-emphasis' }
197
256
  },
257
+ // Same intent interaction layer as the Switch-Pill above — the dot is a
258
+ // filled intent surface too, just a 14px one.
198
259
  {
199
260
  variant: 'dot',
200
261
  checked: true,
201
262
  intent: 'primary',
202
- class: { track: 'border-primary bg-primary' }
263
+ class: {
264
+ track: 'border-primary bg-primary group-hover:bg-primary-hover group-active:bg-primary-active'
265
+ }
203
266
  },
204
267
  {
205
268
  variant: 'dot',
206
269
  checked: true,
207
270
  intent: 'secondary',
208
- class: { track: 'border-secondary bg-secondary' }
271
+ class: {
272
+ track: 'border-secondary bg-secondary group-hover:bg-secondary-hover group-active:bg-secondary-active'
273
+ }
209
274
  },
210
275
  {
211
276
  variant: 'dot',
212
277
  checked: true,
213
278
  intent: 'success',
214
- class: { track: 'border-success bg-success' }
279
+ class: {
280
+ track: 'border-success bg-success group-hover:bg-success-hover group-active:bg-success-active'
281
+ }
215
282
  },
216
283
  {
217
284
  variant: 'dot',
218
285
  checked: true,
219
286
  intent: 'warning',
220
- class: { track: 'border-warning bg-warning' }
287
+ class: {
288
+ track: 'border-warning bg-warning group-hover:bg-warning-hover group-active:bg-warning-active'
289
+ }
221
290
  },
222
291
  {
223
292
  variant: 'dot',
224
293
  checked: true,
225
294
  intent: 'danger',
226
- class: { track: 'border-danger bg-danger' }
295
+ class: {
296
+ track: 'border-danger bg-danger group-hover:bg-danger-hover group-active:bg-danger-active'
297
+ }
227
298
  },
228
299
  {
229
300
  variant: 'dot',
230
301
  checked: true,
231
302
  intent: 'neutral',
232
- class: { track: 'border-neutral bg-neutral' }
303
+ class: {
304
+ track: 'border-neutral bg-neutral group-hover:bg-neutral-hover group-active:bg-neutral-active'
305
+ }
233
306
  },
234
307
  // ── Error state, dot variant (must fold over dot-unchecked border) ──
308
+ // Pins the hover bucket too, for the same reason as the Switch-Pill twin.
235
309
  {
236
310
  variant: 'dot',
237
311
  error: true,
238
312
  checked: false,
239
- class: { track: 'border-danger' }
313
+ class: { track: 'border-danger group-hover:border-danger' }
240
314
  }
241
315
  ],
242
316
  defaultVariants: {
@@ -1,19 +1,19 @@
1
1
  import { type SlotNames, type VariantProps } from '../../utils/variants.js';
2
2
  export declare const tooltipVariants: ((props?: {
3
3
  open?: boolean | undefined;
4
- intent?: "info" | "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
4
+ intent?: "primary" | "secondary" | "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
- intent?: "info" | "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
9
+ intent?: "primary" | "secondary" | "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
- intent?: "info" | "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
16
+ intent?: "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
17
17
  size?: "sm" | "md" | "lg" | undefined;
18
18
  } & {
19
19
  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;
@@ -48,10 +48,14 @@ export const tooltipVariants = tv({
48
48
  true: { base: 'opacity-100 starting:opacity-0' },
49
49
  false: { base: 'opacity-0' }
50
50
  },
51
+ // The standard six-value palette. `info` is deliberately absent: it belongs
52
+ // to the feedback family (Alert, Toast), where it means "informational, and
53
+ // stable under a rebrand" — a tooltip is a container, and `info` sat one
54
+ // hue-step from `primary` (220 vs 240), so the two were barely
55
+ // distinguishable while implying a distinction that wasn't there.
51
56
  intent: {
52
57
  primary: { base: 'bg-primary text-text-on-primary' },
53
58
  secondary: { base: 'bg-secondary text-text-on-primary' },
54
- info: { base: 'bg-info text-text-on-primary' },
55
59
  success: { base: 'bg-success text-text-on-primary' },
56
60
  warning: { base: 'bg-warning text-text-on-warning' },
57
61
  danger: { base: 'bg-danger text-text-on-primary' },
@@ -23,8 +23,14 @@
23
23
  * (e.g. Sunset shifts it warm, Ocean cool) so that
24
24
  * surfaces, text and borders harmonise instead of
25
25
  * reading as a fixed cool grey. Only the hue shifts;
26
- * lightness and chroma match the foundation ramp, so
27
- * WCAG contrast is preserved.
26
+ * lightness and chroma match the foundation ramp. On this
27
+ * near-zero-chroma chassis ramp (chroma ≈ 0.01) that keeps
28
+ * WCAG contrast effectively unchanged (measured 5.95–6.05:1
29
+ * across every theme). It is NOT a general rule: at higher
30
+ * chroma, luminance still moves with hue at constant L/C
31
+ * (an accent ramp can slip under AA that way), which is why
32
+ * contrast.test.ts measures every theme rather than trusting
33
+ * this comment.
28
34
  *
29
35
  * Because surface-*, text-* and border-* all derive from --color-neutral-*
30
36
  * in semantic.css, re-tinting that one ramp flows through the whole chassis
@@ -103,10 +103,12 @@ const ROUTE_TARGET_TIMEOUT_MS = 4000;
103
103
  * `route` is a normalized pathname (leading `/`), so the suffix test lands on a real segment
104
104
  * boundary — `/myexpenses` does not end with `/expenses`.
105
105
  */
106
+ /** Drop a single trailing slash (except the root) — the one normalization both the
107
+ * own-vs-foreign heuristic and the pre-navigation skip agree on. */
108
+ const stripTrailingSlash = (s) => (s.length > 1 && s.endsWith('/') ? s.slice(0, -1) : s);
106
109
  function looksLikeNormalizedRoute(landed, route) {
107
- const stripSlash = (s) => (s.length > 1 && s.endsWith('/') ? s.slice(0, -1) : s);
108
- const l = stripSlash(landed);
109
- const r = stripSlash(route);
110
+ const l = stripTrailingSlash(landed);
111
+ const r = stripTrailingSlash(route);
110
112
  return l === r || l.endsWith(r);
111
113
  }
112
114
  let tourIdCounter = 0;
@@ -510,7 +512,17 @@ export class GuideController {
510
512
  const route = this.currentStep?.route;
511
513
  if (route == null)
512
514
  return;
513
- if (route === this.#navSource.current())
515
+ // Already on the (logical) route nothing to do. Normalize only a trailing
516
+ // slash before comparing, NOT the full own-vs-foreign heuristic: under a
517
+ // normalizing router the current path is `/expenses/` for a step route of
518
+ // `/expenses`, and an exact compare would re-navigate to the same logical
519
+ // route — a router that no-op's that `goto` emits no report, leaving a
520
+ // targetless expectation armed (a spurious DEV foreign-nav warning). The
521
+ // heuristic's `endsWith` prefix match is deliberately NOT used here: it would
522
+ // treat a genuine `/reports/summary` → `/summary` advance as "already there"
523
+ // and silently strand the tour. Prefix/locale forms are still recognized as
524
+ // OWN *after* navigating, on the async path (where they are DEV-warned).
525
+ if (stripTrailingSlash(route) === stripTrailingSlash(this.#navSource.current()))
514
526
  return;
515
527
  if (!this.#navigate) {
516
528
  if (this.#dev) {
@@ -13,15 +13,39 @@ export interface PersistentStateConfig<T> {
13
13
  /**
14
14
  * Create a persistent state that automatically syncs with storage
15
15
  * Uses Svelte 5 $state() for reactivity
16
+ *
17
+ * Besides `value`, the returned object exposes `hasStoredValue` — whether an
18
+ * entry for this key exists in storage. That is what lets a consumer tell a
19
+ * *stored empty* value (`[]`, `''`, `null` — the user cleared it) from *nothing
20
+ * stored at all*, so a cleared state can win over a default/seed instead of
21
+ * being re-applied on every load. Two rules keep that signal meaningful: a save
22
+ * that would not change the stored bytes is skipped, and an instance nobody
23
+ * wrote to never creates an entry for its own default (so `reset()` is not
24
+ * undone by the auto-save, and untouched state stays out of storage). Writing
25
+ * the default *back* — clearing — is a real write and does create the entry.
26
+ *
27
+ * Values must round-trip through the configured `serialize`/`deserialize`;
28
+ * `Set`/`Map` do not under the `JSON.stringify` default (they serialize to
29
+ * `{}`), so pass converting functions or store plain arrays/objects.
16
30
  */
17
31
  export declare function createPersistentState<T>(config: PersistentStateConfig<T>): {
18
32
  value: T;
33
+ /**
34
+ * Whether storage currently holds an entry for this key: `true` when
35
+ * construction (or `reload()`) found a parseable entry, and after a write
36
+ * actually reached storage; `false` when the key was absent or corrupt,
37
+ * after `reset()`, and always without a working storage (SSR, private
38
+ * mode). Use it to distinguish a stored empty value from an absent one.
39
+ */
40
+ readonly hasStoredValue: boolean;
19
41
  /**
20
42
  * Reset to default value and clear storage
21
43
  */
22
44
  reset(): void;
23
45
  /**
24
- * Force immediate save (bypasses debounce)
46
+ * Force immediate save (bypasses debounce). A no-op when storage already
47
+ * holds exactly this value, and — like the auto-save — when the instance
48
+ * was never written to and still holds its default.
25
49
  */
26
50
  forceSave(): void;
27
51
  /**