zabi-components 7.0.2 → 8.0.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 (174) hide show
  1. package/README.md +46 -3
  2. package/THEMING.md +255 -15
  3. package/dist/atoms/ActionPanel.svelte +12 -7
  4. package/dist/atoms/ActionPanel.svelte.d.ts +2 -0
  5. package/dist/atoms/Badge.svelte +93 -56
  6. package/dist/atoms/Badge.svelte.d.ts +15 -3
  7. package/dist/atoms/Button.svelte +49 -49
  8. package/dist/atoms/Button.svelte.d.ts +3 -0
  9. package/dist/atoms/Card.svelte +31 -28
  10. package/dist/atoms/Card.svelte.d.ts +5 -2
  11. package/dist/atoms/CardContent.svelte +10 -2
  12. package/dist/atoms/CardContent.svelte.d.ts +2 -0
  13. package/dist/atoms/CardFooter.svelte +10 -2
  14. package/dist/atoms/CardFooter.svelte.d.ts +2 -0
  15. package/dist/atoms/CardHeader.svelte +10 -2
  16. package/dist/atoms/CardHeader.svelte.d.ts +2 -0
  17. package/dist/atoms/Checkbox.svelte +4 -0
  18. package/dist/atoms/Checkbox.svelte.d.ts +2 -0
  19. package/dist/atoms/CodeBlock.svelte +15 -7
  20. package/dist/atoms/CodeBlock.svelte.d.ts +9 -3
  21. package/dist/atoms/ColorPicker.svelte +19 -9
  22. package/dist/atoms/ColorPicker.svelte.d.ts +3 -1
  23. package/dist/atoms/Container.svelte +2 -3
  24. package/dist/atoms/Divider.svelte +4 -4
  25. package/dist/atoms/FeatureCard.svelte +4 -3
  26. package/dist/atoms/Heading.svelte +56 -27
  27. package/dist/atoms/Heading.svelte.d.ts +17 -4
  28. package/dist/atoms/IconButton.svelte +30 -37
  29. package/dist/atoms/Input.svelte +26 -34
  30. package/dist/atoms/List.svelte +10 -2
  31. package/dist/atoms/List.svelte.d.ts +2 -0
  32. package/dist/atoms/ListItem.svelte +2 -2
  33. package/dist/atoms/ListItemLeading.svelte +4 -2
  34. package/dist/atoms/ListItemLeading.svelte.d.ts +1 -1
  35. package/dist/atoms/OptimizedImage.svelte +11 -2
  36. package/dist/atoms/OptimizedImage.svelte.d.ts +2 -0
  37. package/dist/atoms/Progress.svelte +4 -1
  38. package/dist/atoms/Progress.svelte.d.ts +2 -0
  39. package/dist/atoms/Radio.svelte +4 -0
  40. package/dist/atoms/Radio.svelte.d.ts +2 -0
  41. package/dist/atoms/Select.svelte +65 -67
  42. package/dist/atoms/Select.svelte.d.ts +4 -0
  43. package/dist/atoms/SelectionControl.svelte +5 -1
  44. package/dist/atoms/SelectionControl.svelte.d.ts +2 -0
  45. package/dist/atoms/Skeleton.svelte +5 -3
  46. package/dist/atoms/Table.svelte +2 -1
  47. package/dist/atoms/Text.svelte +34 -5
  48. package/dist/atoms/Text.svelte.d.ts +7 -1
  49. package/dist/atoms/Textarea.svelte +7 -6
  50. package/dist/atoms/ThemeToggle.svelte +17 -14
  51. package/dist/atoms/ThemeToggle.svelte.d.ts +2 -0
  52. package/dist/atoms/Toast.svelte +10 -8
  53. package/dist/atoms/Toggle.svelte +21 -13
  54. package/dist/atoms/Toggle.svelte.d.ts +7 -0
  55. package/dist/atoms/Tooltip.svelte +80 -22
  56. package/dist/atoms/Tooltip.svelte.d.ts +15 -0
  57. package/dist/components/index.d.ts +3 -1
  58. package/dist/components/index.d.ts.map +1 -1
  59. package/dist/components/organisms/index.d.ts +1 -0
  60. package/dist/components/organisms/index.d.ts.map +1 -1
  61. package/dist/components/util/cn.d.ts +8 -0
  62. package/dist/components/util/cn.d.ts.map +1 -0
  63. package/dist/components/util/ssr-safe.d.ts +4 -4
  64. package/dist/components/util/ssr-safe.d.ts.map +1 -1
  65. package/dist/index.d.ts +3 -1
  66. package/dist/index.js +3 -6
  67. package/dist/molecules/Alert.svelte +43 -64
  68. package/dist/molecules/Alert.svelte.d.ts +7 -1
  69. package/dist/molecules/ComponentDemo.svelte +10 -2
  70. package/dist/molecules/ComponentDemo.svelte.d.ts +2 -0
  71. package/dist/molecules/ContactForm.svelte +12 -2
  72. package/dist/molecules/ContactForm.svelte.d.ts +2 -0
  73. package/dist/molecules/Dropdown.svelte +40 -11
  74. package/dist/molecules/Dropdown.svelte.d.ts +4 -0
  75. package/dist/molecules/EmptyState.svelte +2 -1
  76. package/dist/molecules/Form.svelte +25 -14
  77. package/dist/molecules/Form.svelte.d.ts +13 -5
  78. package/dist/molecules/FormField.svelte +2 -1
  79. package/dist/molecules/Header.svelte +13 -3
  80. package/dist/molecules/Header.svelte.d.ts +2 -0
  81. package/dist/molecules/ImageUpload.svelte +54 -15
  82. package/dist/molecules/ImageUpload.svelte.d.ts +16 -5
  83. package/dist/molecules/Modal.svelte +110 -31
  84. package/dist/molecules/Modal.svelte.d.ts +9 -6
  85. package/dist/molecules/NavigationMenu.svelte +15 -3
  86. package/dist/molecules/NavigationMenu.svelte.d.ts +4 -0
  87. package/dist/molecules/NavigationMenuContent.svelte +36 -38
  88. package/dist/molecules/NavigationMenuContent.svelte.d.ts +2 -0
  89. package/dist/molecules/NavigationMenuItem.svelte +10 -2
  90. package/dist/molecules/NavigationMenuItem.svelte.d.ts +2 -0
  91. package/dist/molecules/NavigationMenuLink.svelte +10 -2
  92. package/dist/molecules/NavigationMenuLink.svelte.d.ts +2 -0
  93. package/dist/molecules/NavigationMenuList.svelte +10 -2
  94. package/dist/molecules/NavigationMenuList.svelte.d.ts +2 -0
  95. package/dist/molecules/NavigationMenuTrigger.svelte +16 -3
  96. package/dist/molecules/NavigationMenuTrigger.svelte.d.ts +2 -0
  97. package/dist/molecules/Page.svelte +8 -2
  98. package/dist/molecules/Page.svelte.d.ts +2 -0
  99. package/dist/molecules/PropsTable.svelte +6 -3
  100. package/dist/molecules/PropsTable.svelte.d.ts +2 -0
  101. package/dist/molecules/RadioGroup.svelte +5 -1
  102. package/dist/molecules/RadioGroup.svelte.d.ts +2 -0
  103. package/dist/molecules/Section.svelte +12 -4
  104. package/dist/molecules/Section.svelte.d.ts +3 -1
  105. package/dist/molecules/SidebarBrandHeader.svelte +13 -4
  106. package/dist/molecules/SidebarBrandHeader.svelte.d.ts +2 -0
  107. package/dist/molecules/SidebarFooter.svelte +12 -4
  108. package/dist/molecules/SidebarFooter.svelte.d.ts +2 -0
  109. package/dist/molecules/SidebarNavSection.svelte +12 -4
  110. package/dist/molecules/SidebarNavSection.svelte.d.ts +2 -0
  111. package/dist/molecules/SlideUp.svelte +85 -21
  112. package/dist/molecules/SlideUp.svelte.d.ts +5 -4
  113. package/dist/molecules/Tabs.svelte +25 -19
  114. package/dist/molecules/Tabs.svelte.d.ts +8 -4
  115. package/dist/molecules/Toaster.svelte +3 -2
  116. package/dist/molecules/ToasterToast.svelte +41 -10
  117. package/dist/molecules/ToasterToast.svelte.d.ts +2 -0
  118. package/dist/organisms/SidebarAccountPanel.svelte +4 -0
  119. package/dist/organisms/SidebarAccountPanel.svelte.d.ts +2 -0
  120. package/dist/organisms/SidebarNavigation.svelte +102 -59
  121. package/dist/organisms/SidebarNavigation.svelte.d.ts +2 -0
  122. package/dist/organisms/SidebarPanel.svelte +19 -11
  123. package/dist/organisms/SidebarPanel.svelte.d.ts +2 -0
  124. package/dist/organisms/SidebarShell.svelte +112 -0
  125. package/dist/organisms/SidebarShell.svelte.d.ts +52 -0
  126. package/dist/organisms/TopNavbar.svelte +88 -17
  127. package/dist/organisms/TopNavbar.svelte.d.ts +2 -0
  128. package/dist/organisms/index.d.ts +1 -0
  129. package/dist/organisms/index.js +1 -0
  130. package/dist/routes/lib/variant-utils.d.ts +26 -0
  131. package/dist/routes/lib/{variant-utils.ts → variant-utils.js} +15 -46
  132. package/dist/types/events.js +1 -0
  133. package/dist/types/index.js +3 -0
  134. package/dist/util/cn.d.ts +7 -0
  135. package/dist/util/cn.js +48 -0
  136. package/dist/util/ssr-safe.d.ts +4 -4
  137. package/dist/zabi-components-colors.css +2 -2
  138. package/dist/zabi-components-theme-dark-only.css +139 -92
  139. package/dist/zabi-components-theme-dark.css +139 -92
  140. package/dist/zabi-components-theme-only.css +268 -122
  141. package/dist/zabi-components-theme.css +268 -122
  142. package/dist/zabi-components.css +831 -883
  143. package/docs/lucide-icons.md +3 -1
  144. package/package.json +19 -24
  145. package/dist/lib/layout-width-tokens.d.ts +0 -17
  146. package/dist/lib/layout-width-tokens.d.ts.map +0 -1
  147. package/dist/lib/showcase/component-docs/Button.d.ts +0 -3
  148. package/dist/lib/showcase/component-docs/Button.d.ts.map +0 -1
  149. package/dist/lib/showcase/component-docs/Input.d.ts +0 -3
  150. package/dist/lib/showcase/component-docs/Input.d.ts.map +0 -1
  151. package/dist/lib/showcase/component-docs/List.d.ts +0 -3
  152. package/dist/lib/showcase/component-docs/List.d.ts.map +0 -1
  153. package/dist/lib/showcase/component-docs/Modal.d.ts +0 -3
  154. package/dist/lib/showcase/component-docs/Modal.d.ts.map +0 -1
  155. package/dist/lib/showcase/component-docs/Radio.d.ts +0 -3
  156. package/dist/lib/showcase/component-docs/Radio.d.ts.map +0 -1
  157. package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts +0 -3
  158. package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts.map +0 -1
  159. package/dist/lib/showcase/component-docs/Skeleton.d.ts +0 -3
  160. package/dist/lib/showcase/component-docs/Skeleton.d.ts.map +0 -1
  161. package/dist/lib/showcase/component-docs/_shared.d.ts +0 -12
  162. package/dist/lib/showcase/component-docs/_shared.d.ts.map +0 -1
  163. package/dist/lib/showcase/component-docs/index.d.ts +0 -4
  164. package/dist/lib/showcase/component-docs/index.d.ts.map +0 -1
  165. package/dist/lib/showcase/components-catalog.d.ts +0 -3
  166. package/dist/lib/showcase/components-catalog.d.ts.map +0 -1
  167. package/dist/lib/showcase/components-showcase-constants.d.ts +0 -89
  168. package/dist/lib/showcase/components-showcase-constants.d.ts.map +0 -1
  169. package/dist/lib/showcase/docs-sidebar-helpers.d.ts +0 -15
  170. package/dist/lib/showcase/docs-sidebar-helpers.d.ts.map +0 -1
  171. package/dist/routes/lib/focus-utils.d.ts +0 -12
  172. package/dist/routes/lib/focus-utils.ts +0 -110
  173. package/dist/routes/lib/ssr-safe.ts +0 -58
  174. package/scripts/fix-lucide-svelte-icon-dts.js +0 -35
@@ -1,7 +1,15 @@
1
1
  <script lang="ts">
2
2
  import { generateId } from "../util/ssr-safe.js";
3
+ import { cn } from "../util/cn.js";
3
4
 
4
5
  interface Props {
6
+ /** Extra classes for the host element. */
7
+ class?: string;
8
+ /** Omit to auto-generate; pass to pair with an external `<label for>`. */
9
+ id?: string;
10
+ /** When set, a hidden input submits `value` with native forms while checked. */
11
+ name?: string;
12
+ value?: string;
5
13
  checked?: boolean;
6
14
  disabled?: boolean;
7
15
  loading?: boolean;
@@ -11,6 +19,10 @@
11
19
  }
12
20
 
13
21
  let {
22
+ class: className = "",
23
+ id: idProp,
24
+ name = "",
25
+ value = "on",
14
26
  checked = $bindable(false),
15
27
  disabled = false,
16
28
  loading = false,
@@ -20,7 +32,8 @@
20
32
  ...restProps
21
33
  }: Props = $props();
22
34
 
23
- const toggleId = generateId("toggle");
35
+ const fallbackId = generateId("toggle");
36
+ const toggleId = $derived(idProp ?? fallbackId);
24
37
  const isDisabled = $derived(disabled || loading);
25
38
 
26
39
  function handleClick(event: MouseEvent) {
@@ -36,7 +49,7 @@
36
49
  "focus-ring relative inline-flex w-10 h-6 flex-shrink-0 rounded-full border-0 transition-colors duration-200 ease-in-out focus:outline-none focus-visible:outline-none";
37
50
  const colorClass = checked
38
51
  ? "bg-action-primary hover:bg-action-primary-hover active:bg-action-primary-active"
39
- : "bg-base-400 hover:bg-base-500 active:bg-base-500";
52
+ : "bg-control-track hover:bg-control-track-hover active:bg-control-track-active";
40
53
  const stateClass = isDisabled
41
54
  ? "opacity-50 cursor-not-allowed"
42
55
  : "cursor-pointer";
@@ -45,21 +58,13 @@
45
58
 
46
59
  const toggleThumbClasses = $derived(() => {
47
60
  const base =
48
- "pointer-events-none absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-card shadow transition-transform duration-200 ease-in-out flex items-center justify-center";
61
+ "pointer-events-none absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-card shadow-sm transition-transform duration-200 ease-in-out flex items-center justify-center";
49
62
  const positionClasses = checked ? "translate-x-4" : "translate-x-0";
50
63
  return `${base} ${positionClasses}`;
51
64
  });
52
-
53
- function handleKeydown(event: KeyboardEvent) {
54
- if (isDisabled) return;
55
- if (event.key === " " || event.key === "Enter") {
56
- event.preventDefault();
57
- handleClick(event as unknown as MouseEvent);
58
- }
59
- }
60
65
  </script>
61
66
 
62
- <div class="flex items-center gap-3">
67
+ <div class={cn("flex items-center gap-3", className)}>
63
68
  <button
64
69
  type="button"
65
70
  role="switch"
@@ -69,7 +74,6 @@
69
74
  aria-busy={loading ? "true" : undefined}
70
75
  disabled={isDisabled}
71
76
  onclick={handleClick}
72
- onkeydown={handleKeydown}
73
77
  class={toggleButtonClasses()}
74
78
  {...restProps}
75
79
  >
@@ -83,6 +87,10 @@
83
87
  </span>
84
88
  </button>
85
89
 
90
+ {#if name && checked}
91
+ <input type="hidden" {name} {value} />
92
+ {/if}
93
+
86
94
  {#if label}
87
95
  <label
88
96
  for={toggleId}
@@ -1,4 +1,11 @@
1
1
  interface Props {
2
+ /** Extra classes for the host element. */
3
+ class?: string;
4
+ /** Omit to auto-generate; pass to pair with an external `<label for>`. */
5
+ id?: string;
6
+ /** When set, a hidden input submits `value` with native forms while checked. */
7
+ name?: string;
8
+ value?: string;
2
9
  checked?: boolean;
3
10
  disabled?: boolean;
4
11
  loading?: boolean;
@@ -4,11 +4,27 @@
4
4
  import { onDestroy } from "svelte";
5
5
  import { generateId } from "../util/ssr-safe.js";
6
6
 
7
+ import { cn } from "../util/cn.js";
7
8
  type Props = Omit<HTMLAttributes<HTMLDivElement>, "class"> & {
8
9
  content?: string;
9
10
  placement?: "top" | "bottom" | "left" | "right";
10
11
  delay?: number;
11
12
  disabled?: boolean;
13
+ /**
14
+ * Lay the trigger out as a full-width block instead of an inline-block.
15
+ * A prop rather than a `class="block w-full"` override, because `block`
16
+ * and `inline-block` are equal-specificity utilities: the winner would
17
+ * be whichever Tailwind emits later, not whichever the caller passed.
18
+ */
19
+ block?: boolean;
20
+ /**
21
+ * Position the bubble against the viewport instead of the trigger's
22
+ * offset parent. An absolutely-positioned tooltip cannot escape an
23
+ * ancestor that scrolls: a collapsed sidebar rail sits inside an
24
+ * `overflow-y-auto overflow-x-hidden` list, which clipped the bubble
25
+ * at the rail edge and left only the arrow showing.
26
+ */
27
+ fixed?: boolean;
12
28
  class?: string;
13
29
  children?: Snippet;
14
30
  };
@@ -22,10 +38,43 @@
22
38
  placement = "top",
23
39
  delay = 0,
24
40
  disabled = false,
41
+ block = false,
42
+ fixed = false,
43
+ class: className = "",
25
44
  children,
26
45
  ...restProps
27
46
  }: Props = $props();
28
47
 
48
+ let fixedStyle = $state("");
49
+
50
+ /** Gap must match --tooltip-gap's default (0.5rem). */
51
+ const FIXED_GAP = 8;
52
+
53
+ function positionFixed(): void {
54
+ if (!fixed || !triggerElement) return;
55
+ const r = triggerElement.getBoundingClientRect();
56
+ const coords = {
57
+ top: [r.left + r.width / 2, r.top - FIXED_GAP],
58
+ bottom: [r.left + r.width / 2, r.bottom + FIXED_GAP],
59
+ left: [r.left - FIXED_GAP, r.top + r.height / 2],
60
+ right: [r.right + FIXED_GAP, r.top + r.height / 2],
61
+ }[placement];
62
+ fixedStyle = `left:${coords[0]}px;top:${coords[1]}px;`;
63
+ }
64
+
65
+ $effect(() => {
66
+ if (!fixed || !isVisible) return;
67
+ positionFixed();
68
+ const onMove = () => positionFixed();
69
+ // `true` so ancestor scrolls (the nav list itself) are caught too.
70
+ window.addEventListener("scroll", onMove, true);
71
+ window.addEventListener("resize", onMove);
72
+ return () => {
73
+ window.removeEventListener("scroll", onMove, true);
74
+ window.removeEventListener("resize", onMove);
75
+ };
76
+ });
77
+
29
78
  const triggerId = generateId("tooltip-trigger");
30
79
  const tooltipId = generateId("tooltip");
31
80
  let isVisible = $state(false);
@@ -99,7 +148,11 @@
99
148
  clearShowDelay();
100
149
  clearHideBlurTimeout();
101
150
  isVisible = false;
102
- triggerElement?.focus();
151
+ // Keep focus on the described control; never steal it when the tooltip was hover-only.
152
+ const target = triggerElement ? findDescribedTarget(triggerElement) : null;
153
+ if (target && triggerElement?.contains(document.activeElement)) {
154
+ target.focus();
155
+ }
103
156
  }
104
157
  }
105
158
 
@@ -145,8 +198,13 @@
145
198
  <svelte:window onkeydown={handleKeydown} />
146
199
 
147
200
  <div
148
- class="tooltip-container relative inline-block"
201
+ class={cn(
202
+ "tooltip-container relative",
203
+ block ? "block w-full" : "inline-block",
204
+ className,
205
+ )}
149
206
  data-placement={placement}
207
+ data-strategy={fixed ? "fixed" : "absolute"}
150
208
  data-disabled={disabled}
151
209
  onmouseenter={handleMouseEnter}
152
210
  onmouseleave={handleMouseLeave}
@@ -154,18 +212,19 @@
154
212
  onfocusout={handleBlur}
155
213
  {...restProps}
156
214
  >
157
- <div bind:this={triggerElement} id={triggerId}>
215
+ <div bind:this={triggerElement} id={triggerId} class={block ? "w-full" : undefined}>
158
216
  {@render children?.()}
159
217
  </div>
160
218
 
161
219
  {#if content && !disabled}
162
220
  <div
163
221
  id={tooltipId}
164
- class="tooltip pointer-events-none invisible absolute z-tooltip whitespace-normal wrap-break-word rounded-lg bg-tooltip-bg px-3 py-2 text-sm leading-5 text-tooltip-fg opacity-0 transition-[opacity,visibility,transform] duration-200 ease-in-out"
222
+ class="tooltip pointer-events-none invisible absolute z-tooltip whitespace-normal wrap-break-word rounded-control bg-tooltip-bg px-3 py-2 text-sm leading-5 text-tooltip-fg opacity-0 transition-[opacity,visibility,transform] duration-200 ease-in-out"
165
223
  role="tooltip"
166
224
  aria-hidden={!isVisible}
167
225
  data-visible={isVisible}
168
226
  data-placement={placement}
227
+ style={fixed ? fixedStyle : undefined}
169
228
  >
170
229
  {content}
171
230
  </div>
@@ -173,13 +232,7 @@
173
232
  </div>
174
233
 
175
234
  <style>
176
- :root {
177
- /* Cap only very long copy; width:max-content keeps typical sentences on one line until this limit */
178
- --tooltip-max-width: min(24rem, calc(100vw - 2rem));
179
- --tooltip-gap: 0.5rem;
180
- --tooltip-arrow-size: 4px;
181
- }
182
-
235
+ /* Tunables (override on :root or any ancestor): --tooltip-max-width, --tooltip-gap, --tooltip-arrow-size. Defaults live in the var() fallbacks. */
183
236
  /* max-width: policy forbids max-w-* utilities on packaged atoms; variable used by sm: override */
184
237
  .tooltip {
185
238
  width: -moz-max-content;
@@ -191,7 +244,7 @@
191
244
  inset-block-end: 100%;
192
245
  inset-inline-start: 50%;
193
246
  transform: translateX(-50%) translateY(4px) scale(0.95);
194
- margin-block-end: var(--tooltip-gap);
247
+ margin-block-end: var(--tooltip-gap, 0.5rem);
195
248
  }
196
249
 
197
250
  .tooltip-container[data-placement="top"] .tooltip[data-visible="true"] {
@@ -204,7 +257,7 @@
204
257
  inset-block-start: 100%;
205
258
  inset-inline-start: 50%;
206
259
  transform: translateX(-50%) translateY(-4px) scale(0.95);
207
- margin-block-start: var(--tooltip-gap);
260
+ margin-block-start: var(--tooltip-gap, 0.5rem);
208
261
  }
209
262
 
210
263
  .tooltip-container[data-placement="bottom"] .tooltip[data-visible="true"] {
@@ -217,7 +270,7 @@
217
270
  inset-inline-end: 100%;
218
271
  inset-block-start: 50%;
219
272
  transform: translateY(-50%) translateX(4px) scale(0.95);
220
- margin-inline-end: var(--tooltip-gap);
273
+ margin-inline-end: var(--tooltip-gap, 0.5rem);
221
274
  }
222
275
 
223
276
  .tooltip-container[data-placement="left"] .tooltip[data-visible="true"] {
@@ -230,7 +283,7 @@
230
283
  inset-inline-start: 100%;
231
284
  inset-block-start: 50%;
232
285
  transform: translateY(-50%) translateX(-4px) scale(0.95);
233
- margin-inline-start: var(--tooltip-gap);
286
+ margin-inline-start: var(--tooltip-gap, 0.5rem);
234
287
  }
235
288
 
236
289
  .tooltip-container[data-placement="right"] .tooltip[data-visible="true"] {
@@ -239,11 +292,20 @@
239
292
  transform: translateY(-50%) translateX(0) scale(1);
240
293
  }
241
294
 
295
+ /* Fixed strategy: the bubble is placed against the viewport from the
296
+ trigger's rect, so a scrolling ancestor cannot clip it. Insets and
297
+ margins are reset; the transforms above still do the centring. */
298
+ .tooltip-container[data-strategy="fixed"] .tooltip {
299
+ position: fixed;
300
+ inset: auto;
301
+ margin: 0;
302
+ }
303
+
242
304
  .tooltip::before {
243
305
  content: "";
244
306
  position: absolute;
245
- width: calc(var(--tooltip-arrow-size) * 2);
246
- height: calc(var(--tooltip-arrow-size) * 2);
307
+ width: calc(var(--tooltip-arrow-size, 4px) * 2);
308
+ height: calc(var(--tooltip-arrow-size, 4px) * 2);
247
309
  background-color: var(--color-tooltip-bg);
248
310
  }
249
311
 
@@ -275,17 +337,13 @@
275
337
  clip-path: polygon(0 50%, 100% 0, 100% 100%);
276
338
  }
277
339
 
278
- .tooltip-container[data-delay] .tooltip {
279
- transition-delay: calc(var(--tooltip-delay, 0) * 1ms);
280
- }
281
-
282
340
  @media (max-width: 640px) {
283
341
  .tooltip {
284
342
  --tooltip-max-width: calc(100vw - 2rem);
285
343
  inset-inline-start: 50% !important;
286
344
  inset-inline-end: auto !important;
287
345
  transform: translateX(-50%) scale(0.95) !important;
288
- margin: var(--tooltip-gap) 0 !important;
346
+ margin: var(--tooltip-gap, 0.5rem) 0 !important;
289
347
  }
290
348
 
291
349
  .tooltip[data-visible="true"] {
@@ -5,6 +5,21 @@ type Props = Omit<HTMLAttributes<HTMLDivElement>, "class"> & {
5
5
  placement?: "top" | "bottom" | "left" | "right";
6
6
  delay?: number;
7
7
  disabled?: boolean;
8
+ /**
9
+ * Lay the trigger out as a full-width block instead of an inline-block.
10
+ * A prop rather than a `class="block w-full"` override, because `block`
11
+ * and `inline-block` are equal-specificity utilities: the winner would
12
+ * be whichever Tailwind emits later, not whichever the caller passed.
13
+ */
14
+ block?: boolean;
15
+ /**
16
+ * Position the bubble against the viewport instead of the trigger's
17
+ * offset parent. An absolutely-positioned tooltip cannot escape an
18
+ * ancestor that scrolls: a collapsed sidebar rail sits inside an
19
+ * `overflow-y-auto overflow-x-hidden` list, which clipped the bubble
20
+ * at the rail edge and left only the arrow showing.
21
+ */
22
+ fixed?: boolean;
8
23
  class?: string;
9
24
  children?: Snippet;
10
25
  };
@@ -56,9 +56,11 @@ export { default as SidebarNavSection } from './molecules/SidebarNavSection.svel
56
56
  export { toastStore, pushToast, dismissToast, type ToastItem, type ToastLevel, } from './molecules/toast-store.js';
57
57
  export { default as TopNavbar } from './organisms/TopNavbar.svelte';
58
58
  export { default as SidebarNavigation } from './organisms/SidebarNavigation.svelte';
59
+ export { default as SidebarShell } from './organisms/SidebarShell.svelte';
59
60
  export { default as SidebarAccountPanel } from './organisms/SidebarAccountPanel.svelte';
60
61
  export { default as SidebarPanel } from './organisms/SidebarPanel.svelte';
61
- export declare const generateId: (prefix?: string) => string;
62
+ import { generateId } from './util/ssr-safe.js';
63
+ export { generateId };
62
64
  export declare const createId: (prefix?: string) => string;
63
65
  export declare const cn: (...classes: (string | undefined | null | false)[]) => string;
64
66
  export declare const getFormData: (form: HTMLFormElement) => Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  export { default as TopNavbar } from './TopNavbar.svelte';
2
2
  export { default as SidebarNavigation } from './SidebarNavigation.svelte';
3
+ export { default as SidebarShell } from './SidebarShell.svelte';
3
4
  export { default as SidebarAccountPanel } from './SidebarAccountPanel.svelte';
4
5
  export { default as SidebarPanel } from './SidebarPanel.svelte';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/organisms/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/organisms/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Merge class values, last conflicting utility wins.
3
+ *
4
+ * Falsy entries are dropped, so `cn(base, isActive && activeClasses, className)`
5
+ * is safe.
6
+ */
7
+ export declare function cn(...classes: (string | false | null | undefined)[]): string;
8
+ //# sourceMappingURL=cn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../../src/components/util/cn.ts"],"names":[],"mappings":"AA6CA;;;;;GAKG;AACH,wBAAgB,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,MAAM,CAE5E"}
@@ -9,9 +9,9 @@ export declare function safeDocument(): Document | undefined;
9
9
  export declare function safeLocalStorage(): Storage | undefined;
10
10
  export declare function safeSessionStorage(): Storage | undefined;
11
11
  export declare function safeRequestAnimationFrame(callback: FrameRequestCallback): number | undefined;
12
- export declare function safeSetTimeout(callback: () => void, delay: number): NodeJS.Timeout | undefined;
13
- export declare function safeClearTimeout(id: NodeJS.Timeout | undefined): void;
14
- export declare function safeSetInterval(callback: () => void, delay: number): NodeJS.Timeout | undefined;
15
- export declare function safeClearInterval(id: NodeJS.Timeout | undefined): void;
12
+ export declare function safeSetTimeout(callback: () => void, delay: number): ReturnType<typeof setTimeout> | undefined;
13
+ export declare function safeClearTimeout(id: ReturnType<typeof setTimeout> | undefined): void;
14
+ export declare function safeSetInterval(callback: () => void, delay: number): ReturnType<typeof setInterval> | undefined;
15
+ export declare function safeClearInterval(id: ReturnType<typeof setInterval> | undefined): void;
16
16
  export declare function generateId(prefix?: string): string;
17
17
  //# sourceMappingURL=ssr-safe.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ssr-safe.d.ts","sourceRoot":"","sources":["../../../src/components/util/ssr-safe.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED,wBAAgB,UAAU,IAAI,MAAM,GAAG,SAAS,CAE/C;AAED,wBAAgB,YAAY,IAAI,QAAQ,GAAG,SAAS,CAEnD;AAED,wBAAgB,gBAAgB,IAAI,OAAO,GAAG,SAAS,CAEtD;AAED,wBAAgB,kBAAkB,IAAI,OAAO,GAAG,SAAS,CAExD;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAE5F;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,GAAG,SAAS,CAE9F;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,GAAG,IAAI,CAIrE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,GAAG,SAAS,CAE/F;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,GAAG,IAAI,CAItE;AAGD,wBAAgB,UAAU,CAAC,MAAM,GAAE,MAAa,GAAG,MAAM,CAMxD"}
1
+ {"version":3,"file":"ssr-safe.d.ts","sourceRoot":"","sources":["../../../src/components/util/ssr-safe.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED,wBAAgB,UAAU,IAAI,MAAM,GAAG,SAAS,CAE/C;AAED,wBAAgB,YAAY,IAAI,QAAQ,GAAG,SAAS,CAEnD;AAED,wBAAgB,gBAAgB,IAAI,OAAO,GAAG,SAAS,CAEtD;AAED,wBAAgB,kBAAkB,IAAI,OAAO,GAAG,SAAS,CAExD;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAE5F;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,SAAS,CAE7G;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,SAAS,GAAG,IAAI,CAIpF;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,GAAG,SAAS,CAE/G;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,GAAG,SAAS,GAAG,IAAI,CAItF;AAGD,wBAAgB,UAAU,CAAC,MAAM,GAAE,MAAa,GAAG,MAAM,CAMxD"}
package/dist/index.d.ts CHANGED
@@ -56,9 +56,11 @@ export { default as SidebarNavSection } from './molecules/SidebarNavSection.svel
56
56
  export { toastStore, pushToast, dismissToast, type ToastItem, type ToastLevel, } from './molecules/toast-store.js';
57
57
  export { default as TopNavbar } from './organisms/TopNavbar.svelte';
58
58
  export { default as SidebarNavigation } from './organisms/SidebarNavigation.svelte';
59
+ export { default as SidebarShell } from './organisms/SidebarShell.svelte';
59
60
  export { default as SidebarAccountPanel } from './organisms/SidebarAccountPanel.svelte';
60
61
  export { default as SidebarPanel } from './organisms/SidebarPanel.svelte';
61
- export declare const generateId: (prefix?: string) => string;
62
+ import { generateId } from './util/ssr-safe.js';
63
+ export { generateId };
62
64
  export declare const createId: (prefix?: string) => string;
63
65
  export declare const cn: (...classes: (string | undefined | null | false)[]) => string;
64
66
  export declare const getFormData: (form: HTMLFormElement) => Record<string, unknown>;
package/dist/index.js CHANGED
@@ -56,14 +56,11 @@ export { default as SidebarNavSection } from './molecules/SidebarNavSection.svel
56
56
  export { toastStore, pushToast, dismissToast, } from './molecules/toast-store.js';
57
57
  export { default as TopNavbar } from './organisms/TopNavbar.svelte';
58
58
  export { default as SidebarNavigation } from './organisms/SidebarNavigation.svelte';
59
+ export { default as SidebarShell } from './organisms/SidebarShell.svelte';
59
60
  export { default as SidebarAccountPanel } from './organisms/SidebarAccountPanel.svelte';
60
61
  export { default as SidebarPanel } from './organisms/SidebarPanel.svelte';
61
- export const generateId = (prefix = 'id') => {
62
- if (typeof window !== 'undefined') {
63
- return `${prefix}-${Math.random().toString(36).substr(2, 9)}`;
64
- }
65
- return `${prefix}-ssr-${Date.now()}`;
66
- };
62
+ import { generateId } from './util/ssr-safe.js';
63
+ export { generateId };
67
64
  export const createId = (prefix = 'id') => generateId(prefix);
68
65
  export const cn = (...classes) => classes.filter(Boolean).join(' ');
69
66
  export const getFormData = (form) => {
@@ -1,5 +1,7 @@
1
1
  <script lang="ts">
2
+ import { Check, TriangleAlert, X, Info, Zap } from "@lucide/svelte";
2
3
  import type { ExtendedSemanticVariant } from "../types/variants.js";
4
+ import { cn } from "../util/cn.js";
3
5
  type AlertVisualVariant = Exclude<ExtendedSemanticVariant, "default">;
4
6
 
5
7
  interface Props {
@@ -7,6 +9,12 @@
7
9
  title?: string;
8
10
  message?: string;
9
11
  closable?: boolean;
12
+ /** Visible state; `closable` dismiss sets it to `false`. Supports `bind:open`. */
13
+ open?: boolean;
14
+ /** Shrink to content instead of filling the container. */
15
+ inline?: boolean;
16
+ class?: string;
17
+ /** @deprecated use `class` — kept so 7.x call sites keep working. */
10
18
  className?: string;
11
19
  onclick?: (event: Event) => void;
12
20
  }
@@ -16,6 +24,9 @@
16
24
  title = "",
17
25
  message = "",
18
26
  closable = false,
27
+ open = $bindable(true),
28
+ inline = false,
29
+ class: classProp = "",
19
30
  className = "",
20
31
  onclick,
21
32
  children,
@@ -23,6 +34,7 @@
23
34
  }: Props & { children?: any } = $props();
24
35
 
25
36
  function handleDismiss(event: MouseEvent) {
37
+ open = false;
26
38
  if (onclick) {
27
39
  onclick(event);
28
40
  }
@@ -32,13 +44,20 @@
32
44
  variant === "default" ? "info" : variant,
33
45
  );
34
46
 
47
+ /**
48
+ * A tinted fill plus a tinted edge, not a bare 1px outline on a
49
+ * transparent ground — an outline-only alert on a light page barely
50
+ * registers, and the pale warning and citron borders were close to
51
+ * invisible. The icon carries the family colour at its `-text` step.
52
+ */
35
53
  let alertClasses = $derived({
36
- info: "text-info border border-info",
37
- success: "text-success border border-success",
38
- warning: "text-warning border border-warning",
39
- error: "text-error border border-error",
40
- neutral: "text-neutral border border-neutral",
41
- energetic: "text-energetic border border-energetic",
54
+ info: "bg-info-subtle border-info-border text-info-text",
55
+ success: "bg-success-subtle border-success-border text-success-text",
56
+ warning: "bg-warning-subtle border-warning-border text-warning-text",
57
+ error: "bg-error-subtle border-error-border text-error-text",
58
+ neutral: "bg-neutral-subtle border-neutral-border text-neutral-text",
59
+ energetic:
60
+ "bg-energetic-subtle border-energetic-border text-energetic-text",
42
61
  });
43
62
 
44
63
  let alertRole = $derived(
@@ -48,83 +67,42 @@
48
67
 
49
68
  {#snippet icon()}
50
69
  {#if visualVariant === "info"}
51
- <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
52
- <path
53
- fill-rule="evenodd"
54
- d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
55
- clip-rule="evenodd"
56
- />
57
- </svg>
70
+ <Info size={20} aria-hidden="true" />
58
71
  {:else if visualVariant === "success"}
59
- <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
60
- <path
61
- fill-rule="evenodd"
62
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
63
- clip-rule="evenodd"
64
- />
65
- </svg>
72
+ <Check size={20} aria-hidden="true" />
66
73
  {:else if visualVariant === "warning"}
67
- <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
68
- <path
69
- fill-rule="evenodd"
70
- d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
71
- clip-rule="evenodd"
72
- />
73
- </svg>
74
+ <TriangleAlert size={20} aria-hidden="true" />
74
75
  {:else if visualVariant === "error"}
75
- <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
76
- <path
77
- fill-rule="evenodd"
78
- d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
79
- clip-rule="evenodd"
80
- />
81
- </svg>
76
+ <X size={20} aria-hidden="true" />
82
77
  {:else if visualVariant === "neutral"}
83
- <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
84
- <path
85
- fill-rule="evenodd"
86
- d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM10 9a1 1 0 100 2 1 1 0 000-2z"
87
- clip-rule="evenodd"
88
- />
89
- </svg>
78
+ <Info size={20} aria-hidden="true" />
90
79
  {:else}
91
- <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
92
- <path d="M11 3L4 14h6l-1 7 7-11h-6l1-7z" />
93
- </svg>
80
+ <Zap size={20} aria-hidden="true" />
94
81
  {/if}
95
82
  {/snippet}
96
83
 
84
+ {#if open}
97
85
  <div
98
- class="relative rounded-md p-4 border {alertClasses[
99
- visualVariant
100
- ]} transition-all duration-200 motion-reduce:transition-none {className}"
86
+ class={cn(
87
+ 'relative rounded-container p-4 border',
88
+ inline ? 'inline-block' : 'block w-full',
89
+ alertClasses[visualVariant],
90
+ 'transition-colors duration-150 motion-reduce:transition-none',
91
+ classProp,
92
+ className,
93
+ )}
101
94
  role={alertRole}
102
- aria-live={visualVariant === "success" || visualVariant === "info"
103
- ? "polite"
104
- : "assertive"}
105
95
  aria-atomic="true"
106
96
  {...restProps}
107
97
  >
108
98
  {#if closable}
109
99
  <button
110
100
  onclick={handleDismiss}
111
- class="group absolute right-2 top-2 z-10 flex h-6 w-6 cursor-pointer items-center justify-center rounded-full text-description transition-colors duration-200 hover:text-body motion-reduce:transition-none focus-ring"
101
+ class="absolute right-2 top-2 z-10 flex size-6 cursor-pointer items-center justify-center rounded-control text-description transition-colors duration-150 hover:bg-surface-hover hover:text-body motion-reduce:transition-none focus-ring--muted"
112
102
  aria-label="Dismiss alert"
113
103
  type="button"
114
104
  >
115
- <svg
116
- class="w-4 h-4 text-current group-hover:scale-110 transition-transform duration-200 motion-reduce:transition-none"
117
- fill="none"
118
- stroke="currentColor"
119
- viewBox="0 0 24 24"
120
- >
121
- <path
122
- stroke-linecap="round"
123
- stroke-linejoin="round"
124
- stroke-width="2"
125
- d="M6 18L18 6M6 6l12 12"
126
- />
127
- </svg>
105
+ <X size={16} aria-hidden="true" />
128
106
  </button>
129
107
  {/if}
130
108
 
@@ -148,3 +126,4 @@
148
126
  </div>
149
127
  </div>
150
128
  </div>
129
+ {/if}
@@ -4,12 +4,18 @@ interface Props {
4
4
  title?: string;
5
5
  message?: string;
6
6
  closable?: boolean;
7
+ /** Visible state; `closable` dismiss sets it to `false`. Supports `bind:open`. */
8
+ open?: boolean;
9
+ /** Shrink to content instead of filling the container. */
10
+ inline?: boolean;
11
+ class?: string;
12
+ /** @deprecated use `class` — kept so 7.x call sites keep working. */
7
13
  className?: string;
8
14
  onclick?: (event: Event) => void;
9
15
  }
10
16
  type $$ComponentProps = Props & {
11
17
  children?: any;
12
18
  };
13
- declare const Alert: import("svelte").Component<$$ComponentProps, {}, "">;
19
+ declare const Alert: import("svelte").Component<$$ComponentProps, {}, "open">;
14
20
  type Alert = ReturnType<typeof Alert>;
15
21
  export default Alert;