@hyvnt/hyvui 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +37 -7
  2. package/dist/components/ambient/ArcaneVein.svelte +151 -0
  3. package/dist/components/ambient/ArcaneVein.svelte.d.ts +31 -0
  4. package/dist/components/ambient/BrassFiligree.svelte +109 -0
  5. package/dist/components/ambient/BrassFiligree.svelte.d.ts +20 -0
  6. package/dist/components/ambient/CornerBrackets.svelte +8 -0
  7. package/dist/components/ambient/CornerBrackets.svelte.d.ts +8 -0
  8. package/dist/components/ambient/CrystalShard.svelte +151 -0
  9. package/dist/components/ambient/CrystalShard.svelte.d.ts +19 -0
  10. package/dist/components/ambient/DataStream.svelte +7 -1
  11. package/dist/components/ambient/DataStream.svelte.d.ts +6 -0
  12. package/dist/components/ambient/EnergyArc.svelte +189 -0
  13. package/dist/components/ambient/EnergyArc.svelte.d.ts +32 -0
  14. package/dist/components/ambient/GlyphMark.svelte +6 -0
  15. package/dist/components/ambient/GlyphMark.svelte.d.ts +6 -0
  16. package/dist/components/ambient/GridOverlay.svelte +8 -0
  17. package/dist/components/ambient/GridOverlay.svelte.d.ts +8 -0
  18. package/dist/components/ambient/HexGrid.svelte +119 -0
  19. package/dist/components/ambient/HexGrid.svelte.d.ts +21 -0
  20. package/dist/components/ambient/ParallaxLayer.svelte +9 -1
  21. package/dist/components/ambient/ParallaxLayer.svelte.d.ts +7 -0
  22. package/dist/components/ambient/ScanBand.svelte +8 -0
  23. package/dist/components/ambient/ScanBand.svelte.d.ts +8 -0
  24. package/dist/components/ambient/ShimmerCloud.svelte +180 -0
  25. package/dist/components/ambient/ShimmerCloud.svelte.d.ts +21 -0
  26. package/dist/components/ambient/SignalRing.svelte +7 -1
  27. package/dist/components/ambient/SignalRing.svelte.d.ts +6 -0
  28. package/dist/components/ambient/ThreadLine.svelte +7 -0
  29. package/dist/components/ambient/ThreadLine.svelte.d.ts +7 -0
  30. package/dist/components/ambient/Vignette.svelte +6 -0
  31. package/dist/components/ambient/Vignette.svelte.d.ts +6 -0
  32. package/dist/components/depth/DepthLayer.svelte +8 -0
  33. package/dist/components/depth/DepthLayer.svelte.d.ts +8 -0
  34. package/dist/components/depth/DepthStage.svelte +8 -4
  35. package/dist/components/depth/DepthStage.svelte.d.ts +8 -0
  36. package/dist/components/depth/FloatCard.svelte +17 -1
  37. package/dist/components/depth/FloatCard.svelte.d.ts +8 -0
  38. package/dist/components/depth/HorizonGrid.svelte +25 -0
  39. package/dist/components/depth/HorizonGrid.svelte.d.ts +9 -0
  40. package/dist/components/depth/Plinth.svelte +10 -0
  41. package/dist/components/depth/Plinth.svelte.d.ts +10 -0
  42. package/dist/components/display/Avatar.svelte +5 -0
  43. package/dist/components/display/Avatar.svelte.d.ts +5 -0
  44. package/dist/components/display/Badge.svelte +16 -0
  45. package/dist/components/display/Badge.svelte.d.ts +6 -0
  46. package/dist/components/display/Blockquote.svelte +4 -0
  47. package/dist/components/display/Blockquote.svelte.d.ts +4 -0
  48. package/dist/components/display/CodeBlock.svelte +5 -0
  49. package/dist/components/display/CodeBlock.svelte.d.ts +5 -0
  50. package/dist/components/display/MetricCard.svelte +23 -0
  51. package/dist/components/display/MetricCard.svelte.d.ts +6 -0
  52. package/dist/components/display/Table.svelte +7 -0
  53. package/dist/components/display/Table.svelte.d.ts +7 -0
  54. package/dist/components/feedback/Alert.svelte +24 -0
  55. package/dist/components/feedback/Alert.svelte.d.ts +6 -0
  56. package/dist/components/feedback/EmptyState.svelte +7 -0
  57. package/dist/components/feedback/EmptyState.svelte.d.ts +7 -0
  58. package/dist/components/feedback/ErrorState.svelte +5 -0
  59. package/dist/components/feedback/ErrorState.svelte.d.ts +5 -0
  60. package/dist/components/feedback/Skeleton.svelte +6 -0
  61. package/dist/components/feedback/Skeleton.svelte.d.ts +6 -0
  62. package/dist/components/feedback/StatusDot.svelte +36 -1
  63. package/dist/components/feedback/StatusDot.svelte.d.ts +6 -0
  64. package/dist/components/feedback/StatusLine.svelte +8 -2
  65. package/dist/components/feedback/StatusLine.svelte.d.ts +6 -0
  66. package/dist/components/feedback/Toast.svelte +16 -2
  67. package/dist/components/feedback/Toast.svelte.d.ts +10 -0
  68. package/dist/components/inputs/Button.svelte +74 -4
  69. package/dist/components/inputs/Button.svelte.d.ts +8 -0
  70. package/dist/components/inputs/Checkbox.svelte +5 -0
  71. package/dist/components/inputs/Checkbox.svelte.d.ts +5 -0
  72. package/dist/components/inputs/FileUpload.svelte +5 -0
  73. package/dist/components/inputs/FileUpload.svelte.d.ts +5 -0
  74. package/dist/components/inputs/Input.svelte +10 -2
  75. package/dist/components/inputs/Input.svelte.d.ts +7 -0
  76. package/dist/components/inputs/Select.svelte +8 -0
  77. package/dist/components/inputs/Select.svelte.d.ts +8 -0
  78. package/dist/components/inputs/Textarea.svelte +9 -2
  79. package/dist/components/inputs/Textarea.svelte.d.ts +6 -0
  80. package/dist/components/inputs/Toggle.svelte +6 -1
  81. package/dist/components/inputs/Toggle.svelte.d.ts +5 -0
  82. package/dist/components/layout/Card.svelte +11 -0
  83. package/dist/components/layout/Card.svelte.d.ts +11 -0
  84. package/dist/components/layout/Drawer.svelte +7 -0
  85. package/dist/components/layout/Drawer.svelte.d.ts +6 -0
  86. package/dist/components/layout/Grid.svelte +10 -0
  87. package/dist/components/layout/Grid.svelte.d.ts +10 -0
  88. package/dist/components/layout/Modal.svelte +15 -0
  89. package/dist/components/layout/Modal.svelte.d.ts +10 -0
  90. package/dist/components/layout/Panel.svelte +9 -0
  91. package/dist/components/layout/Panel.svelte.d.ts +9 -0
  92. package/dist/components/layout/Popover.svelte +10 -0
  93. package/dist/components/layout/Popover.svelte.d.ts +9 -0
  94. package/dist/components/layout/Stack.svelte +12 -0
  95. package/dist/components/layout/Stack.svelte.d.ts +12 -0
  96. package/dist/components/navigation/Breadcrumb.svelte +8 -0
  97. package/dist/components/navigation/Breadcrumb.svelte.d.ts +8 -0
  98. package/dist/components/navigation/DropdownMenu.svelte +12 -0
  99. package/dist/components/navigation/DropdownMenu.svelte.d.ts +12 -0
  100. package/dist/components/navigation/SidebarNav.svelte +10 -0
  101. package/dist/components/navigation/SidebarNav.svelte.d.ts +9 -0
  102. package/dist/components/navigation/Tabs.svelte +26 -1
  103. package/dist/components/navigation/Tabs.svelte.d.ts +8 -0
  104. package/dist/components/navigation/Topbar.svelte +9 -0
  105. package/dist/components/navigation/Topbar.svelte.d.ts +9 -0
  106. package/dist/components/patterns/ActionBar.svelte +11 -0
  107. package/dist/components/patterns/ActionBar.svelte.d.ts +10 -0
  108. package/dist/components/patterns/ChapterMark.svelte +152 -0
  109. package/dist/components/patterns/ChapterMark.svelte.d.ts +19 -0
  110. package/dist/components/patterns/ConfirmDialog.svelte +12 -0
  111. package/dist/components/patterns/ConfirmDialog.svelte.d.ts +12 -0
  112. package/dist/components/patterns/DepthPortal.svelte +123 -0
  113. package/dist/components/patterns/DepthPortal.svelte.d.ts +24 -0
  114. package/dist/components/patterns/Manifesto.svelte +171 -0
  115. package/dist/components/patterns/Manifesto.svelte.d.ts +25 -0
  116. package/dist/components/patterns/PageHeader.svelte +8 -0
  117. package/dist/components/patterns/PageHeader.svelte.d.ts +8 -0
  118. package/dist/components/patterns/PullQuote.svelte +145 -0
  119. package/dist/components/patterns/PullQuote.svelte.d.ts +23 -0
  120. package/dist/components/patterns/RegisterSwitcher.svelte +132 -0
  121. package/dist/components/patterns/RegisterSwitcher.svelte.d.ts +21 -0
  122. package/dist/components/patterns/SearchBar.svelte +5 -0
  123. package/dist/components/patterns/SearchBar.svelte.d.ts +5 -0
  124. package/dist/components/patterns/ShowcaseFrame.svelte +117 -0
  125. package/dist/components/patterns/ShowcaseFrame.svelte.d.ts +28 -0
  126. package/dist/components/patterns/TerminalBoot.svelte +15 -1
  127. package/dist/components/patterns/TerminalBoot.svelte.d.ts +12 -0
  128. package/dist/components/primitives/Divider.svelte +30 -0
  129. package/dist/components/primitives/Divider.svelte.d.ts +5 -0
  130. package/dist/components/primitives/Icon.svelte +9 -0
  131. package/dist/components/primitives/Icon.svelte.d.ts +9 -0
  132. package/dist/components/primitives/Label.svelte +6 -0
  133. package/dist/components/primitives/Label.svelte.d.ts +6 -0
  134. package/dist/components/primitives/Surface.svelte +67 -2
  135. package/dist/components/primitives/Surface.svelte.d.ts +7 -0
  136. package/dist/components/primitives/Text.svelte +32 -0
  137. package/dist/components/primitives/Text.svelte.d.ts +7 -0
  138. package/dist/components/scenes/ArchiveScene.svelte +10 -0
  139. package/dist/components/scenes/ArchiveScene.svelte.d.ts +10 -0
  140. package/dist/components/scenes/DepthScene.svelte +128 -0
  141. package/dist/components/scenes/DepthScene.svelte.d.ts +36 -0
  142. package/dist/components/scenes/LogScene.svelte +14 -0
  143. package/dist/components/scenes/LogScene.svelte.d.ts +14 -0
  144. package/dist/components/scenes/NarrativeScene.svelte +9 -0
  145. package/dist/components/scenes/NarrativeScene.svelte.d.ts +9 -0
  146. package/dist/components/scenes/ReadoutScene.svelte +11 -0
  147. package/dist/components/scenes/ReadoutScene.svelte.d.ts +11 -0
  148. package/dist/components/scenes/StageScene.svelte +14 -0
  149. package/dist/components/scenes/StageScene.svelte.d.ts +14 -0
  150. package/dist/components/system/AppShell.svelte +62 -0
  151. package/dist/components/system/AppShell.svelte.d.ts +32 -0
  152. package/dist/examples/ArcaneShard.svelte +364 -0
  153. package/dist/examples/ArcaneShard.svelte.d.ts +3 -0
  154. package/dist/examples/HextechForge.svelte +324 -0
  155. package/dist/examples/HextechForge.svelte.d.ts +3 -0
  156. package/dist/index.d.ts +15 -1
  157. package/dist/index.js +16 -1
  158. package/dist/styles.css +2 -0
  159. package/dist/system/actions/echo.js +13 -4
  160. package/dist/system/actions/resolve.js +20 -6
  161. package/dist/system/actions/reveal.js +1 -1
  162. package/dist/system/actions/surface.js +1 -3
  163. package/dist/system/register.d.ts +1 -1
  164. package/dist/system/register.js +5 -1
  165. package/dist/tokens/arcane.css +96 -0
  166. package/dist/tokens/hextech.css +96 -0
  167. package/dist/tokens/tokens.css +6 -4
  168. package/dist/tokens/tokens.d.ts +41 -0
  169. package/dist/tokens/tokens.js +41 -0
  170. package/package.json +6 -2
@@ -1,6 +1,12 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils/cn.js';
3
3
 
4
+ /**
5
+ * @example
6
+ * <StatusDot status="ok" />
7
+ * <StatusDot status="pend" pulse={false} />
8
+ * <StatusDot status="fail" size={8} />
9
+ */
4
10
  interface Props {
5
11
  /** Status state determining the dot color. */
6
12
  status?: 'ok' | 'pend' | 'warn' | 'fail';
@@ -38,7 +44,7 @@
38
44
  }
39
45
 
40
46
  .hyvui-status-dot-pulse {
41
- animation: pulse-dot 2s ease-in-out infinite;
47
+ animation: pulse-dot 2s cubic-bezier(0.37, 0, 0.63, 1) infinite;
42
48
  }
43
49
 
44
50
  @media (prefers-reduced-motion: reduce) {
@@ -46,4 +52,33 @@
46
52
  animation: none;
47
53
  }
48
54
  }
55
+
56
+ /* ── hextech: cyan ring pulse instead of scale ────────────────────── */
57
+ :global([data-register='hextech']) .hyvui-status-dot-pulse {
58
+ animation: sd-hextech-pulse 2.4s cubic-bezier(0.16, 1, 0.3, 1) infinite;
59
+ }
60
+
61
+ @keyframes sd-hextech-pulse {
62
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(93, 217, 240, 0.0); }
63
+ 50% { box-shadow: 0 0 0 4px rgba(93, 217, 240, 0.0); opacity: 1; }
64
+ 30% { box-shadow: 0 0 0 3px rgba(93, 217, 240, 0.35); opacity: 1; }
65
+ }
66
+
67
+ /* ── arcane: shimmer ripple ───────────────────────────────────────── */
68
+ :global([data-register='arcane']) .hyvui-status-dot-pulse {
69
+ animation: sd-arcane-pulse 2s cubic-bezier(0.6, 0, 0.4, 1) infinite;
70
+ }
71
+
72
+ @keyframes sd-arcane-pulse {
73
+ 0% { box-shadow: 0 0 0 0 rgba(184, 69, 201, 0.6); opacity: 1; }
74
+ 70% { box-shadow: 0 0 0 5px rgba(184, 69, 201, 0); opacity: 0.85; }
75
+ 100% { box-shadow: 0 0 0 0 rgba(184, 69, 201, 0); opacity: 1; }
76
+ }
77
+
78
+ @media (prefers-reduced-motion: reduce) {
79
+ :global([data-register='hextech']) .hyvui-status-dot-pulse,
80
+ :global([data-register='arcane']) .hyvui-status-dot-pulse {
81
+ animation: none;
82
+ }
83
+ }
49
84
  </style>
@@ -1,3 +1,9 @@
1
+ /**
2
+ * @example
3
+ * <StatusDot status="ok" />
4
+ * <StatusDot status="pend" pulse={false} />
5
+ * <StatusDot status="fail" size={8} />
6
+ */
1
7
  interface Props {
2
8
  /** Status state determining the dot color. */
3
9
  status?: 'ok' | 'pend' | 'warn' | 'fail';
@@ -1,6 +1,12 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils/cn.js';
3
3
 
4
+ /**
5
+ * @example
6
+ * <StatusLine status="ok" message="database connected" visible={true} />
7
+ * <StatusLine status="pend" message="waiting for signal" visible={show} cursor />
8
+ * <StatusLine status="fail" message="stream interrupted" visible={true} tone="line" />
9
+ */
4
10
  interface Props {
5
11
  /** Status determining the glyph and color. */
6
12
  status?: 'ok' | 'pend' | 'warn' | 'fail';
@@ -69,8 +75,8 @@
69
75
  opacity: 0;
70
76
  transform: translateY(6px);
71
77
  transition:
72
- opacity 0.5s cubic-bezier(0.22, 1, 0.36, 1),
73
- transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
78
+ opacity var(--transition-smooth),
79
+ transform var(--transition-smooth);
74
80
  }
75
81
 
76
82
  .hyvui-status-line-visible {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * @example
3
+ * <StatusLine status="ok" message="database connected" visible={true} />
4
+ * <StatusLine status="pend" message="waiting for signal" visible={show} cursor />
5
+ * <StatusLine status="fail" message="stream interrupted" visible={true} tone="line" />
6
+ */
1
7
  interface Props {
2
8
  /** Status determining the glyph and color. */
3
9
  status?: 'ok' | 'pend' | 'warn' | 'fail';
@@ -29,6 +29,16 @@
29
29
  import { cn } from '../../utils/cn.js';
30
30
  import { flip } from 'svelte/animate';
31
31
 
32
+ /**
33
+ * Place once in your root layout. Trigger toasts anywhere via `toastStore.push(message, variant)`.
34
+ * Variants: 'ok' | 'pend' | 'warn' | 'fail'
35
+ * @example
36
+ * <Toast position="bottom-right" />
37
+ * @example
38
+ * toastStore.push('file saved', 'ok');
39
+ * toastStore.push('connection lost', 'fail');
40
+ * toastStore.push('uploading...', 'pend', 8000);
41
+ */
32
42
  interface Props {
33
43
  /** Position of the toast stack. */
34
44
  position?: 'bottom-right' | 'bottom-center';
@@ -40,8 +50,11 @@
40
50
 
41
51
  let items: ToastItem[] = $state([]);
42
52
 
43
- toastStore.subscribe((v) => {
44
- items = v;
53
+ $effect(() => {
54
+ const unsub = toastStore.subscribe((v) => {
55
+ items = v;
56
+ });
57
+ return unsub;
45
58
  });
46
59
 
47
60
  const statusColorMap: Record<string, string> = {
@@ -95,6 +108,7 @@
95
108
  align-items: center;
96
109
  gap: 0.625rem;
97
110
  pointer-events: auto;
111
+ backface-visibility: hidden;
98
112
  animation: toast-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
99
113
  }
100
114
 
@@ -10,6 +10,16 @@ export declare const toastStore: {
10
10
  /** Push a new toast notification. */
11
11
  push(message: string, variant?: "ok" | "pend" | "warn" | "fail", duration?: number): void;
12
12
  };
13
+ /**
14
+ * Place once in your root layout. Trigger toasts anywhere via `toastStore.push(message, variant)`.
15
+ * Variants: 'ok' | 'pend' | 'warn' | 'fail'
16
+ * @example
17
+ * <Toast position="bottom-right" />
18
+ * @example
19
+ * toastStore.push('file saved', 'ok');
20
+ * toastStore.push('connection lost', 'fail');
21
+ * toastStore.push('uploading...', 'pend', 8000);
22
+ */
13
23
  interface Props {
14
24
  /** Position of the toast stack. */
15
25
  position?: 'bottom-right' | 'bottom-center';
@@ -3,6 +3,14 @@
3
3
  import type { Snippet } from 'svelte';
4
4
  import { echo as echoAction } from '../../system/actions/echo.js';
5
5
 
6
+ /**
7
+ * @see echo — add `echo` prop (or `use:echo` directly) for a gold click-pulse ripple.
8
+ * @example
9
+ * <Button variant="primary" onclick={handleSubmit}>submit</Button>
10
+ * <Button variant="ghost" href="/back">go back</Button>
11
+ * <Button variant="destructive" loading>deleting...</Button>
12
+ * <Button variant="primary" echo onclick={confirm}>confirm</Button>
13
+ */
6
14
  interface Props {
7
15
  /** Button visual style. */
8
16
  variant?: 'primary' | 'secondary' | 'ghost' | 'destructive';
@@ -123,9 +131,10 @@
123
131
  justify-content: center;
124
132
  gap: var(--control-gap);
125
133
  transition:
126
- color var(--transition-smooth),
127
- border-color var(--transition-smooth),
128
- background var(--transition-smooth),
134
+ color var(--transition-fast),
135
+ border-color var(--transition-fast),
136
+ background var(--transition-fast),
137
+ filter var(--transition-fast),
129
138
  transform var(--transition-smooth),
130
139
  box-shadow var(--transition-smooth);
131
140
  white-space: nowrap;
@@ -221,7 +230,7 @@
221
230
  height: 6px;
222
231
  border-radius: 50%;
223
232
  background-color: var(--status-pend);
224
- animation: pulse-dot 2s ease-in-out infinite;
233
+ animation: pulse-dot 2s cubic-bezier(0.37, 0, 0.63, 1) infinite;
225
234
  }
226
235
 
227
236
  @media (prefers-reduced-motion: reduce) {
@@ -237,4 +246,65 @@
237
246
  animation: none;
238
247
  }
239
248
  }
249
+
250
+ /* ── hextech ornament ─────────────────────────────────────────────── */
251
+ :global([data-register='hextech']) .hyvui-btn {
252
+ border-radius: var(--radius-sm);
253
+ }
254
+
255
+ /* brass corner pip — top-left notch */
256
+ :global([data-register='hextech']) .hyvui-btn::before {
257
+ content: '';
258
+ position: absolute;
259
+ top: 0;
260
+ left: 0;
261
+ width: 7px;
262
+ height: 7px;
263
+ border-top: 1.5px solid rgba(212, 165, 116, 0.55);
264
+ border-left: 1.5px solid rgba(212, 165, 116, 0.55);
265
+ pointer-events: none;
266
+ }
267
+
268
+ :global([data-register='hextech']) .hyvui-btn-primary:hover:not(:disabled):not(.hyvui-btn-disabled),
269
+ :global([data-register='hextech']) .hyvui-btn-primary:focus-visible {
270
+ box-shadow:
271
+ inset 0 1px 0 rgba(255, 255, 255, 0.2),
272
+ 0 0 18px rgba(93, 217, 240, 0.3),
273
+ 0 14px 26px rgba(184, 115, 51, 0.18);
274
+ }
275
+
276
+ :global([data-register='hextech']) .hyvui-btn-secondary:hover:not(:disabled):not(.hyvui-btn-disabled),
277
+ :global([data-register='hextech']) .hyvui-btn-secondary:focus-visible {
278
+ box-shadow: 0 0 12px rgba(93, 217, 240, 0.2);
279
+ border-color: rgba(93, 217, 240, 0.4);
280
+ }
281
+
282
+ /* ── arcane ornament ──────────────────────────────────────────────── */
283
+
284
+ /* crystal accent — top-right shard corner */
285
+ :global([data-register='arcane']) .hyvui-btn::after {
286
+ content: '';
287
+ position: absolute;
288
+ top: -1px;
289
+ right: -1px;
290
+ width: 8px;
291
+ height: 8px;
292
+ background: rgba(233, 76, 188, 0.55);
293
+ clip-path: polygon(100% 0, 100% 100%, 0 0);
294
+ pointer-events: none;
295
+ }
296
+
297
+ :global([data-register='arcane']) .hyvui-btn-primary:hover:not(:disabled):not(.hyvui-btn-disabled),
298
+ :global([data-register='arcane']) .hyvui-btn-primary:focus-visible {
299
+ box-shadow:
300
+ inset 0 1px 0 rgba(255, 255, 255, 0.14),
301
+ 0 0 22px rgba(184, 69, 201, 0.38),
302
+ 0 14px 26px rgba(184, 69, 201, 0.14);
303
+ }
304
+
305
+ :global([data-register='arcane']) .hyvui-btn-secondary:hover:not(:disabled):not(.hyvui-btn-disabled),
306
+ :global([data-register='arcane']) .hyvui-btn-secondary:focus-visible {
307
+ box-shadow: 0 0 14px rgba(184, 69, 201, 0.28);
308
+ border-color: rgba(184, 69, 201, 0.5);
309
+ }
240
310
  </style>
@@ -1,4 +1,12 @@
1
1
  import type { Snippet } from 'svelte';
2
+ /**
3
+ * @see echo — add `echo` prop (or `use:echo` directly) for a gold click-pulse ripple.
4
+ * @example
5
+ * <Button variant="primary" onclick={handleSubmit}>submit</Button>
6
+ * <Button variant="ghost" href="/back">go back</Button>
7
+ * <Button variant="destructive" loading>deleting...</Button>
8
+ * <Button variant="primary" echo onclick={confirm}>confirm</Button>
9
+ */
2
10
  interface Props {
3
11
  /** Button visual style. */
4
12
  variant?: 'primary' | 'secondary' | 'ghost' | 'destructive';
@@ -1,6 +1,11 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils/cn.js';
3
3
 
4
+ /**
5
+ * @example
6
+ * <Checkbox label="accept terms" bind:checked={accepted} />
7
+ * <Checkbox label="notify me" bind:checked={notify} onchange={handleChange} />
8
+ */
4
9
  interface Props {
5
10
  /** Whether the checkbox is checked (bindable). */
6
11
  checked?: boolean;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @example
3
+ * <Checkbox label="accept terms" bind:checked={accepted} />
4
+ * <Checkbox label="notify me" bind:checked={notify} onchange={handleChange} />
5
+ */
1
6
  interface Props {
2
7
  /** Whether the checkbox is checked (bindable). */
3
8
  checked?: boolean;
@@ -1,6 +1,11 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils/cn.js';
3
3
 
4
+ /**
5
+ * @example
6
+ * <FileUpload accept="image/*" onfiles={handleImages} />
7
+ * <FileUpload multiple accept=".csv,.json" onfiles={handleData} label="drop data files here" />
8
+ */
4
9
  interface Props {
5
10
  /** Accepted file types (e.g. "image/*"). */
6
11
  accept?: string;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @example
3
+ * <FileUpload accept="image/*" onfiles={handleImages} />
4
+ * <FileUpload multiple accept=".csv,.json" onfiles={handleData} label="drop data files here" />
5
+ */
1
6
  interface Props {
2
7
  /** Accepted file types (e.g. "image/*"). */
3
8
  accept?: string;
@@ -1,6 +1,13 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils/cn.js';
3
3
 
4
+ /**
5
+ * @see resolve — wrap parent `<form>` with `use:resolve` to flash status on submit.
6
+ * @example
7
+ * <Input label="api key" bind:value={key} placeholder="sk-..." />
8
+ * <Input label="email" type="email" bind:value={email} error={emailError} />
9
+ * <Input label="search" type="search" bind:value={query} hint="press enter to search" />
10
+ */
4
11
  interface Props {
5
12
  /** Input type. */
6
13
  type?: 'text' | 'number' | 'password' | 'email' | 'search';
@@ -50,14 +57,15 @@
50
57
  bind:value
51
58
  {placeholder}
52
59
  {disabled}
60
+ aria-describedby={(error || hint) ? `${inputId}-desc` : undefined}
53
61
  class={cn('hyvui-input', error && 'hyvui-input-error')}
54
62
  {oninput}
55
63
  {onchange}
56
64
  />
57
65
  {#if error}
58
- <span class="hyvui-input-message hyvui-input-message-error">{error}</span>
66
+ <span id="{inputId}-desc" class="hyvui-input-message hyvui-input-message-error">{error}</span>
59
67
  {:else if hint}
60
- <span class="hyvui-input-message">{hint}</span>
68
+ <span id="{inputId}-desc" class="hyvui-input-message">{hint}</span>
61
69
  {/if}
62
70
  </div>
63
71
 
@@ -1,3 +1,10 @@
1
+ /**
2
+ * @see resolve — wrap parent `<form>` with `use:resolve` to flash status on submit.
3
+ * @example
4
+ * <Input label="api key" bind:value={key} placeholder="sk-..." />
5
+ * <Input label="email" type="email" bind:value={email} error={emailError} />
6
+ * <Input label="search" type="search" bind:value={query} hint="press enter to search" />
7
+ */
1
8
  interface Props {
2
9
  /** Input type. */
3
10
  type?: 'text' | 'number' | 'password' | 'email' | 'search';
@@ -6,6 +6,14 @@
6
6
  label: string;
7
7
  }
8
8
 
9
+ /**
10
+ * @example
11
+ * <Select label="region" bind:value={region} options={[
12
+ * { value: 'us', label: 'united states' },
13
+ * { value: 'eu', label: 'europe' }
14
+ * ]} />
15
+ * <Select label="status" bind:value={status} options={statusOptions} error={statusError} />
16
+ */
9
17
  interface Props {
10
18
  /** Available options. */
11
19
  options?: SelectOption[];
@@ -2,6 +2,14 @@ interface SelectOption {
2
2
  value: string;
3
3
  label: string;
4
4
  }
5
+ /**
6
+ * @example
7
+ * <Select label="region" bind:value={region} options={[
8
+ * { value: 'us', label: 'united states' },
9
+ * { value: 'eu', label: 'europe' }
10
+ * ]} />
11
+ * <Select label="status" bind:value={status} options={statusOptions} error={statusError} />
12
+ */
5
13
  interface Props {
6
14
  /** Available options. */
7
15
  options?: SelectOption[];
@@ -1,6 +1,12 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils/cn.js';
3
3
 
4
+ /**
5
+ * @see resolve — wrap parent `<form>` with `use:resolve` to flash status on submit.
6
+ * @example
7
+ * <Textarea label="notes" bind:value={notes} placeholder="enter notes..." />
8
+ * <Textarea label="message" rows={6} bind:value={msg} autoresize error={msgError} />
9
+ */
4
10
  interface Props {
5
11
  /** Current value (bindable). */
6
12
  value?: string;
@@ -61,13 +67,14 @@
61
67
  {rows}
62
68
  {placeholder}
63
69
  {disabled}
70
+ aria-describedby={(error || hint) ? `${textareaId}-desc` : undefined}
64
71
  class={cn('hyvui-textarea', error && 'hyvui-textarea-error')}
65
72
  oninput={handleInput}
66
73
  ></textarea>
67
74
  {#if error}
68
- <span class="hyvui-textarea-message hyvui-textarea-message-error">{error}</span>
75
+ <span id="{textareaId}-desc" class="hyvui-textarea-message hyvui-textarea-message-error">{error}</span>
69
76
  {:else if hint}
70
- <span class="hyvui-textarea-message">{hint}</span>
77
+ <span id="{textareaId}-desc" class="hyvui-textarea-message">{hint}</span>
71
78
  {/if}
72
79
  </div>
73
80
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * @see resolve — wrap parent `<form>` with `use:resolve` to flash status on submit.
3
+ * @example
4
+ * <Textarea label="notes" bind:value={notes} placeholder="enter notes..." />
5
+ * <Textarea label="message" rows={6} bind:value={msg} autoresize error={msgError} />
6
+ */
1
7
  interface Props {
2
8
  /** Current value (bindable). */
3
9
  value?: string;
@@ -1,6 +1,11 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils/cn.js';
3
3
 
4
+ /**
5
+ * @example
6
+ * <Toggle label="enable notifications" bind:checked={enabled} />
7
+ * <Toggle label="dark mode" bind:checked={dark} onchange={applyTheme} />
8
+ */
4
9
  interface Props {
5
10
  /** Whether the toggle is on (bindable). */
6
11
  checked?: boolean;
@@ -95,7 +100,7 @@
95
100
  border-radius: 50%;
96
101
  background-color: var(--muted);
97
102
  transition:
98
- transform var(--transition-fast),
103
+ transform var(--transition-smooth),
99
104
  background-color var(--transition-fast);
100
105
  }
101
106
 
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @example
3
+ * <Toggle label="enable notifications" bind:checked={enabled} />
4
+ * <Toggle label="dark mode" bind:checked={dark} onchange={applyTheme} />
5
+ */
1
6
  interface Props {
2
7
  /** Whether the toggle is on (bindable). */
3
8
  checked?: boolean;
@@ -3,6 +3,17 @@
3
3
  import Surface from '../primitives/Surface.svelte';
4
4
  import type { Snippet } from 'svelte';
5
5
 
6
+ /**
7
+ * @see surface — add `use:surface` on Card for an entrance animation on mount.
8
+ * @see reveal — add `use:reveal={{ target: '.meta' }}` on the Card for hover-reveal of child elements.
9
+ * @example
10
+ * <Card>
11
+ * {#snippet header()}<Label>project alpha</Label>{/snippet}
12
+ * <Text>card body content here.</Text>
13
+ * {#snippet footer()}<Button variant="ghost" size="sm">view details</Button>{/snippet}
14
+ * </Card>
15
+ * <Card staggerOffset="1.2rem">offset card in a grid</Card>
16
+ */
6
17
  interface Props {
7
18
  /** TranslateY offset for staggered card grids. */
8
19
  staggerOffset?: string;
@@ -1,4 +1,15 @@
1
1
  import type { Snippet } from 'svelte';
2
+ /**
3
+ * @see surface — add `use:surface` on Card for an entrance animation on mount.
4
+ * @see reveal — add `use:reveal={{ target: '.meta' }}` on the Card for hover-reveal of child elements.
5
+ * @example
6
+ * <Card>
7
+ * {#snippet header()}<Label>project alpha</Label>{/snippet}
8
+ * <Text>card body content here.</Text>
9
+ * {#snippet footer()}<Button variant="ghost" size="sm">view details</Button>{/snippet}
10
+ * </Card>
11
+ * <Card staggerOffset="1.2rem">offset card in a grid</Card>
12
+ */
2
13
  interface Props {
3
14
  /** TranslateY offset for staggered card grids. */
4
15
  staggerOffset?: string;
@@ -4,6 +4,12 @@
4
4
  import Surface from '../primitives/Surface.svelte';
5
5
  import type { Snippet } from 'svelte';
6
6
 
7
+ /**
8
+ * @example
9
+ * <Drawer open={showDrawer} side="right" onclose={() => showDrawer = false}>
10
+ * <SidebarNav items={navItems} />
11
+ * </Drawer>
12
+ */
7
13
  interface Props {
8
14
  /** Controls drawer visibility. */
9
15
  open?: boolean;
@@ -86,6 +92,7 @@
86
92
  z-index: var(--z-modal);
87
93
  inline-size: min(var(--hyvui-drawer-w, 320px), 100dvw);
88
94
  max-inline-size: 100dvw;
95
+ backface-visibility: hidden;
89
96
  }
90
97
 
91
98
  .hyvui-drawer-left {
@@ -1,4 +1,10 @@
1
1
  import type { Snippet } from 'svelte';
2
+ /**
3
+ * @example
4
+ * <Drawer open={showDrawer} side="right" onclose={() => showDrawer = false}>
5
+ * <SidebarNav items={navItems} />
6
+ * </Drawer>
7
+ */
2
8
  interface Props {
3
9
  /** Controls drawer visibility. */
4
10
  open?: boolean;
@@ -2,6 +2,16 @@
2
2
  import { cn } from '../../utils/cn.js';
3
3
  import type { Snippet } from 'svelte';
4
4
 
5
+ /**
6
+ * @example
7
+ * <Grid minColWidth="18rem" maxCols={3}>
8
+ * {#each items as item}<Card>{item.name}</Card>{/each}
9
+ * </Grid>
10
+ * <Grid mode="template" cols="1fr 2fr">
11
+ * <aside>sidebar</aside>
12
+ * <main>content</main>
13
+ * </Grid>
14
+ */
5
15
  interface Props {
6
16
  /** Grid mode. `auto` computes columns from container width. */
7
17
  mode?: 'auto' | 'template';
@@ -1,4 +1,14 @@
1
1
  import type { Snippet } from 'svelte';
2
+ /**
3
+ * @example
4
+ * <Grid minColWidth="18rem" maxCols={3}>
5
+ * {#each items as item}<Card>{item.name}</Card>{/each}
6
+ * </Grid>
7
+ * <Grid mode="template" cols="1fr 2fr">
8
+ * <aside>sidebar</aside>
9
+ * <main>content</main>
10
+ * </Grid>
11
+ */
2
12
  interface Props {
3
13
  /** Grid mode. `auto` computes columns from container width. */
4
14
  mode?: 'auto' | 'template';
@@ -4,6 +4,16 @@
4
4
  import Surface from '../primitives/Surface.svelte';
5
5
  import type { Snippet } from 'svelte';
6
6
 
7
+ /**
8
+ * @example
9
+ * <Modal open={showModal} title="confirm action" onclose={() => showModal = false}>
10
+ * <Text>are you sure you want to proceed?</Text>
11
+ * {#snippet footer()}
12
+ * <Button variant="primary" onclick={confirm}>proceed</Button>
13
+ * <Button variant="ghost" onclick={() => showModal = false}>cancel</Button>
14
+ * {/snippet}
15
+ * </Modal>
16
+ */
7
17
  interface Props {
8
18
  /** Controls modal visibility. */
9
19
  open?: boolean;
@@ -32,13 +42,17 @@
32
42
  }: Props = $props();
33
43
 
34
44
  let dialogEl: HTMLDialogElement | undefined = $state();
45
+ let previousFocus: Element | null = null;
35
46
 
36
47
  $effect(() => {
37
48
  if (!dialogEl) return;
38
49
  if (open) {
50
+ previousFocus = document.activeElement;
39
51
  if (!dialogEl.open) dialogEl.showModal();
40
52
  } else {
41
53
  if (dialogEl.open) dialogEl.close();
54
+ if (previousFocus instanceof HTMLElement) previousFocus.focus();
55
+ previousFocus = null;
42
56
  }
43
57
  });
44
58
 
@@ -121,6 +135,7 @@
121
135
  display: flex;
122
136
  flex-direction: column;
123
137
  min-height: 0;
138
+ backface-visibility: hidden;
124
139
  animation: modal-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
125
140
  }
126
141
 
@@ -1,4 +1,14 @@
1
1
  import type { Snippet } from 'svelte';
2
+ /**
3
+ * @example
4
+ * <Modal open={showModal} title="confirm action" onclose={() => showModal = false}>
5
+ * <Text>are you sure you want to proceed?</Text>
6
+ * {#snippet footer()}
7
+ * <Button variant="primary" onclick={confirm}>proceed</Button>
8
+ * <Button variant="ghost" onclick={() => showModal = false}>cancel</Button>
9
+ * {/snippet}
10
+ * </Modal>
11
+ */
2
12
  interface Props {
3
13
  /** Controls modal visibility. */
4
14
  open?: boolean;
@@ -3,6 +3,15 @@
3
3
  import Surface from '../primitives/Surface.svelte';
4
4
  import type { Snippet } from 'svelte';
5
5
 
6
+ /**
7
+ * @see surface — add `use:surface` on Panel for an entrance animation on mount.
8
+ * @example
9
+ * <Panel>
10
+ * {#snippet header()}<Label color="accent">system status</Label>{/snippet}
11
+ * <StatusDot status="ok" />
12
+ * </Panel>
13
+ * <Panel withInset>panel with teal inset border</Panel>
14
+ */
6
15
  interface Props {
7
16
  /** Adds a pseudoelement teal inset border. */
8
17
  withInset?: boolean;
@@ -1,4 +1,13 @@
1
1
  import type { Snippet } from 'svelte';
2
+ /**
3
+ * @see surface — add `use:surface` on Panel for an entrance animation on mount.
4
+ * @example
5
+ * <Panel>
6
+ * {#snippet header()}<Label color="accent">system status</Label>{/snippet}
7
+ * <StatusDot status="ok" />
8
+ * </Panel>
9
+ * <Panel withInset>panel with teal inset border</Panel>
10
+ */
2
11
  interface Props {
3
12
  /** Adds a pseudoelement teal inset border. */
4
13
  withInset?: boolean;