svelora 3.0.5 → 3.0.7

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 (189) hide show
  1. package/dist/BentoGrid/BentoCard.svelte +45 -0
  2. package/dist/BentoGrid/BentoCard.svelte.d.ts +4 -0
  3. package/dist/BentoGrid/BentoGrid.svelte +9 -0
  4. package/dist/BentoGrid/BentoGrid.svelte.d.ts +4 -0
  5. package/dist/BentoGrid/bento-grid.types.d.ts +47 -0
  6. package/dist/BentoGrid/bento-grid.types.js +1 -0
  7. package/dist/BentoGrid/bento-grid.variants.d.ts +30 -0
  8. package/dist/BentoGrid/bento-grid.variants.js +16 -0
  9. package/dist/BentoGrid/index.d.ts +5 -0
  10. package/dist/BentoGrid/index.js +5 -0
  11. package/dist/Chart/Chart.svelte +47 -0
  12. package/dist/Chart/Chart.svelte.d.ts +4 -0
  13. package/dist/Chart/chart.types.d.ts +20 -0
  14. package/dist/Chart/chart.types.js +1 -0
  15. package/dist/Chart/chart.variants.d.ts +3 -0
  16. package/dist/Chart/chart.variants.js +4 -0
  17. package/dist/Chart/index.d.ts +4 -0
  18. package/dist/Chart/index.js +4 -0
  19. package/dist/Chat/ChatBubble.svelte +30 -0
  20. package/dist/Chat/ChatBubble.svelte.d.ts +4 -0
  21. package/dist/Chat/ChatInput.svelte +50 -0
  22. package/dist/Chat/ChatInput.svelte.d.ts +4 -0
  23. package/dist/Chat/ChatMessage.svelte +15 -0
  24. package/dist/Chat/ChatMessage.svelte.d.ts +4 -0
  25. package/dist/Chat/chat.types.d.ts +63 -0
  26. package/dist/Chat/chat.types.js +1 -0
  27. package/dist/Chat/chat.variants.d.ts +117 -0
  28. package/dist/Chat/chat.variants.js +47 -0
  29. package/dist/Chat/index.d.ts +6 -0
  30. package/dist/Chat/index.js +6 -0
  31. package/dist/ColorPicker/ColorPicker.svelte +109 -0
  32. package/dist/ColorPicker/ColorPicker.svelte.d.ts +4 -0
  33. package/dist/ColorPicker/color-picker.types.d.ts +26 -0
  34. package/dist/ColorPicker/color-picker.types.js +1 -0
  35. package/dist/ColorPicker/color-picker.variants.d.ts +69 -0
  36. package/dist/ColorPicker/color-picker.variants.js +13 -0
  37. package/dist/ColorPicker/index.d.ts +4 -0
  38. package/dist/ColorPicker/index.js +4 -0
  39. package/dist/DateRangePicker/DateRangePicker.svelte +59 -0
  40. package/dist/DateRangePicker/DateRangePicker.svelte.d.ts +4 -0
  41. package/dist/DateRangePicker/date-range-picker.types.d.ts +34 -0
  42. package/dist/DateRangePicker/date-range-picker.types.js +1 -0
  43. package/dist/DateRangePicker/date-range-picker.variants.d.ts +39 -0
  44. package/dist/DateRangePicker/date-range-picker.variants.js +20 -0
  45. package/dist/DateRangePicker/index.d.ts +4 -0
  46. package/dist/DateRangePicker/index.js +4 -0
  47. package/dist/Fonts/fonts.js +3 -1
  48. package/dist/Link/Link.context-harness.svelte +8 -0
  49. package/dist/Link/Link.context-harness.svelte.d.ts +7 -0
  50. package/dist/Link/Link.svelte +57 -30
  51. package/dist/Link/index.d.ts +2 -0
  52. package/dist/Link/index.js +1 -0
  53. package/dist/Link/location-context.d.ts +4 -0
  54. package/dist/Link/location-context.js +1 -0
  55. package/dist/List/List.svelte +14 -0
  56. package/dist/List/List.svelte.d.ts +4 -0
  57. package/dist/List/ListItem.svelte +64 -0
  58. package/dist/List/ListItem.svelte.d.ts +4 -0
  59. package/dist/List/index.d.ts +5 -0
  60. package/dist/List/index.js +5 -0
  61. package/dist/List/list.types.d.ts +62 -0
  62. package/dist/List/list.types.js +1 -0
  63. package/dist/List/list.variants.d.ts +99 -0
  64. package/dist/List/list.variants.js +42 -0
  65. package/dist/Marquee/Marquee.svelte +50 -0
  66. package/dist/Marquee/Marquee.svelte.d.ts +4 -0
  67. package/dist/Marquee/index.d.ts +4 -0
  68. package/dist/Marquee/index.js +4 -0
  69. package/dist/Marquee/marquee.types.d.ts +38 -0
  70. package/dist/Marquee/marquee.types.js +1 -0
  71. package/dist/Marquee/marquee.variants.d.ts +78 -0
  72. package/dist/Marquee/marquee.variants.js +28 -0
  73. package/dist/Menu/Menu.svelte +134 -0
  74. package/dist/Menu/Menu.svelte.d.ts +4 -0
  75. package/dist/Menu/index.d.ts +4 -0
  76. package/dist/Menu/index.js +4 -0
  77. package/dist/Menu/menu.types.d.ts +82 -0
  78. package/dist/Menu/menu.types.js +1 -0
  79. package/dist/Menu/menu.variants.d.ts +46 -0
  80. package/dist/Menu/menu.variants.js +32 -0
  81. package/dist/NumberTicker/NumberTicker.svelte +59 -0
  82. package/dist/NumberTicker/NumberTicker.svelte.d.ts +4 -0
  83. package/dist/NumberTicker/index.d.ts +4 -0
  84. package/dist/NumberTicker/index.js +4 -0
  85. package/dist/NumberTicker/number-ticker.types.d.ts +26 -0
  86. package/dist/NumberTicker/number-ticker.types.js +1 -0
  87. package/dist/NumberTicker/number-ticker.variants.d.ts +27 -0
  88. package/dist/NumberTicker/number-ticker.variants.js +6 -0
  89. package/dist/PasswordInput/PasswordInput.svelte +74 -0
  90. package/dist/PasswordInput/PasswordInput.svelte.d.ts +4 -0
  91. package/dist/PasswordInput/index.d.ts +4 -0
  92. package/dist/PasswordInput/index.js +4 -0
  93. package/dist/PasswordInput/password-input.types.d.ts +18 -0
  94. package/dist/PasswordInput/password-input.types.js +1 -0
  95. package/dist/PasswordInput/password-input.variants.d.ts +57 -0
  96. package/dist/PasswordInput/password-input.variants.js +11 -0
  97. package/dist/Prose/Prose.svelte +13 -0
  98. package/dist/Prose/Prose.svelte.d.ts +4 -0
  99. package/dist/Prose/index.d.ts +4 -0
  100. package/dist/Prose/index.js +4 -0
  101. package/dist/Prose/prose.types.d.ts +22 -0
  102. package/dist/Prose/prose.types.js +1 -0
  103. package/dist/Prose/prose.variants.d.ts +45 -0
  104. package/dist/Prose/prose.variants.js +45 -0
  105. package/dist/Rating/Rating.svelte +93 -0
  106. package/dist/Rating/Rating.svelte.d.ts +4 -0
  107. package/dist/Rating/index.d.ts +4 -0
  108. package/dist/Rating/index.js +4 -0
  109. package/dist/Rating/rating.types.d.ts +59 -0
  110. package/dist/Rating/rating.types.js +1 -0
  111. package/dist/Rating/rating.variants.d.ts +93 -0
  112. package/dist/Rating/rating.variants.js +32 -0
  113. package/dist/Resizable/Resizable.svelte +9 -0
  114. package/dist/Resizable/Resizable.svelte.d.ts +4 -0
  115. package/dist/Resizable/index.d.ts +4 -0
  116. package/dist/Resizable/index.js +4 -0
  117. package/dist/Resizable/resizable.types.d.ts +18 -0
  118. package/dist/Resizable/resizable.types.js +1 -0
  119. package/dist/Resizable/resizable.variants.d.ts +48 -0
  120. package/dist/Resizable/resizable.variants.js +17 -0
  121. package/dist/ScrollArea/ScrollArea.svelte +54 -0
  122. package/dist/ScrollArea/ScrollArea.svelte.d.ts +4 -0
  123. package/dist/ScrollArea/index.d.ts +4 -0
  124. package/dist/ScrollArea/index.js +4 -0
  125. package/dist/ScrollArea/scroll-area.types.d.ts +27 -0
  126. package/dist/ScrollArea/scroll-area.types.js +1 -0
  127. package/dist/ScrollArea/scroll-area.variants.d.ts +45 -0
  128. package/dist/ScrollArea/scroll-area.variants.js +27 -0
  129. package/dist/SelectMenu/SelectMenu.svelte +46 -14
  130. package/dist/Sidebar/Sidebar.svelte +30 -0
  131. package/dist/Sidebar/Sidebar.svelte.d.ts +4 -0
  132. package/dist/Sidebar/index.d.ts +4 -0
  133. package/dist/Sidebar/index.js +4 -0
  134. package/dist/Sidebar/sidebar.types.d.ts +31 -0
  135. package/dist/Sidebar/sidebar.types.js +1 -0
  136. package/dist/Sidebar/sidebar.variants.d.ts +69 -0
  137. package/dist/Sidebar/sidebar.variants.js +23 -0
  138. package/dist/Spotlight/Spotlight.svelte +31 -0
  139. package/dist/Spotlight/Spotlight.svelte.d.ts +4 -0
  140. package/dist/Spotlight/index.d.ts +4 -0
  141. package/dist/Spotlight/index.js +4 -0
  142. package/dist/Spotlight/spotlight.types.d.ts +22 -0
  143. package/dist/Spotlight/spotlight.types.js +1 -0
  144. package/dist/Spotlight/spotlight.variants.d.ts +39 -0
  145. package/dist/Spotlight/spotlight.variants.js +8 -0
  146. package/dist/Stepper/Stepper.svelte +12 -9
  147. package/dist/TagsInput/TagsInput.svelte +100 -0
  148. package/dist/TagsInput/TagsInput.svelte.d.ts +4 -0
  149. package/dist/TagsInput/index.d.ts +4 -0
  150. package/dist/TagsInput/index.js +4 -0
  151. package/dist/TagsInput/tags-input.types.d.ts +32 -0
  152. package/dist/TagsInput/tags-input.types.js +1 -0
  153. package/dist/TagsInput/tags-input.variants.d.ts +45 -0
  154. package/dist/TagsInput/tags-input.variants.js +22 -0
  155. package/dist/TreeView/TreeView.svelte +95 -0
  156. package/dist/TreeView/TreeView.svelte.d.ts +4 -0
  157. package/dist/TreeView/index.d.ts +4 -0
  158. package/dist/TreeView/index.js +4 -0
  159. package/dist/TreeView/tree-view.types.d.ts +68 -0
  160. package/dist/TreeView/tree-view.types.js +1 -0
  161. package/dist/TreeView/tree-view.variants.d.ts +69 -0
  162. package/dist/TreeView/tree-view.variants.js +30 -0
  163. package/dist/docs/navigation.js +162 -0
  164. package/dist/hooks/index.d.ts +14 -0
  165. package/dist/hooks/index.js +9 -0
  166. package/dist/hooks/useDebouncedState.svelte.d.ts +30 -0
  167. package/dist/hooks/useDebouncedState.svelte.js +45 -0
  168. package/dist/hooks/useEventListener.svelte.d.ts +30 -0
  169. package/dist/hooks/useEventListener.svelte.js +16 -0
  170. package/dist/hooks/useFocusTrap.svelte.d.ts +42 -0
  171. package/dist/hooks/useFocusTrap.svelte.js +87 -0
  172. package/dist/hooks/useIntersectionObserver.svelte.d.ts +30 -0
  173. package/dist/hooks/useIntersectionObserver.svelte.js +46 -0
  174. package/dist/hooks/useLocalStorage.svelte.d.ts +39 -0
  175. package/dist/hooks/useLocalStorage.svelte.js +73 -0
  176. package/dist/hooks/useResizeObserver.svelte.d.ts +50 -0
  177. package/dist/hooks/useResizeObserver.svelte.js +71 -0
  178. package/dist/hooks/useScrollLock.svelte.d.ts +28 -0
  179. package/dist/hooks/useScrollLock.svelte.js +79 -0
  180. package/dist/hooks/useThrottle.svelte.d.ts +37 -0
  181. package/dist/hooks/useThrottle.svelte.js +72 -0
  182. package/dist/hooks/useTimers.svelte.d.ts +62 -0
  183. package/dist/hooks/useTimers.svelte.js +90 -0
  184. package/dist/hooks/utils.d.ts +1 -0
  185. package/dist/hooks/utils.js +3 -0
  186. package/dist/index.d.ts +18 -0
  187. package/dist/index.js +18 -0
  188. package/dist/mcp/svelora-docs.data.json +59 -5
  189. package/package.json +8 -6
@@ -0,0 +1,109 @@
1
+ <script lang="ts">import { twMerge } from "tailwind-merge";
2
+ import { Popover } from "../Popover/index.js";
3
+ import { Input } from "../Input/index.js";
4
+ import Icon from "../Icon/Icon.svelte";
5
+ import { colorPickerVariants } from "./color-picker.variants.js";
6
+ let { value = $bindable("#000000"), placeholder = "Select color", swatches = [
7
+ "#ef4444",
8
+ "#f97316",
9
+ "#f59e0b",
10
+ "#eab308",
11
+ "#84cc16",
12
+ "#22c55e",
13
+ "#10b981",
14
+ "#14b8a6",
15
+ "#06b6d4",
16
+ "#0ea5e9",
17
+ "#3b82f6",
18
+ "#6366f1",
19
+ "#8b5cf6",
20
+ "#a855f7",
21
+ "#d946ef",
22
+ "#ec4899",
23
+ "#f43f5e",
24
+ "#ffffff",
25
+ "#94a3b8",
26
+ "#000000"
27
+ ], disabled = false, class: className, ...restProps } = $props();
28
+ const styles = $derived(colorPickerVariants());
29
+ // Validate hex
30
+ let hexInput = $state(value);
31
+ $effect(() => {
32
+ hexInput = value;
33
+ });
34
+ function handleHexInput(e) {
35
+ const target = e.target;
36
+ let val = target.value;
37
+ if (!val.startsWith("#")) {
38
+ val = "#" + val;
39
+ }
40
+ hexInput = val;
41
+ // Basic hex validation regex (3, 4, 6, or 8 digits)
42
+ if (/^#([A-Fa-f0-9]{3,4}){1,2}$/.test(val)) {
43
+ value = val;
44
+ }
45
+ }
46
+ function setSwatch(swatch) {
47
+ value = swatch;
48
+ hexInput = swatch;
49
+ }
50
+ </script>
51
+
52
+ <div class={twMerge(styles.base(), className)} {...restProps}>
53
+ <Popover>
54
+ {#snippet children({ open })}
55
+ <div
56
+ class={styles.trigger()}
57
+ aria-disabled={disabled}
58
+ >
59
+ <div
60
+ class={styles.colorIndicator()}
61
+ style="background-color: {value || '#000'};"
62
+ ></div>
63
+ <span class="truncate flex-1 text-left text-on-surface">
64
+ {value || placeholder}
65
+ </span>
66
+ <Icon name="lucide:chevron-down" class="text-on-surface-variant w-4 h-4" />
67
+ </div>
68
+ {/snippet}
69
+
70
+ {#snippet content()}
71
+ <div class={styles.content()}>
72
+ <div class={styles.hexInputWrapper()}>
73
+ <span class="text-sm font-medium">Hex</span>
74
+ <Input
75
+ value={hexInput}
76
+ oninput={handleHexInput}
77
+ class="h-8 font-mono text-xs"
78
+ />
79
+ </div>
80
+
81
+ <div class={styles.swatchGrid()}>
82
+ {#each swatches as swatch}
83
+ <button
84
+ type="button"
85
+ class={styles.swatch()}
86
+ style="background-color: {swatch};"
87
+ title={swatch}
88
+ aria-label={`Select color ${swatch}`}
89
+ onclick={() => setSwatch(swatch)}
90
+ ></button>
91
+ {/each}
92
+ </div>
93
+
94
+ <div class="pt-2 border-t border-outline-variant flex flex-col gap-1">
95
+ <span class="text-xs text-on-surface-variant mb-1">Custom Color</span>
96
+ <!-- Native color picker wrapper -->
97
+ <label class="cursor-pointer relative overflow-hidden rounded-md border border-outline-variant w-full h-8 flex items-center justify-center bg-surface-container hover:bg-surface-container-high transition-colors">
98
+ <span class="text-xs font-medium z-10 pointer-events-none mix-blend-difference text-white">Pick Custom</span>
99
+ <input
100
+ type="color"
101
+ bind:value
102
+ class="absolute inset-0 opacity-0 w-full h-full cursor-pointer scale-150"
103
+ />
104
+ </label>
105
+ </div>
106
+ </div>
107
+ {/snippet}
108
+ </Popover>
109
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { ColorPickerProps } from './color-picker.types.js';
2
+ declare const ColorPicker: import("svelte").Component<ColorPickerProps, {}, "value">;
3
+ type ColorPicker = ReturnType<typeof ColorPicker>;
4
+ export default ColorPicker;
@@ -0,0 +1,26 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ export interface ColorPickerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'value'> {
3
+ /**
4
+ * The bound color value (Hex format).
5
+ * @default '#000000'
6
+ */
7
+ value?: string;
8
+ /**
9
+ * Placeholder text when no color is selected.
10
+ * @default 'Select color'
11
+ */
12
+ placeholder?: string;
13
+ /**
14
+ * Array of predefined color swatches.
15
+ */
16
+ swatches?: string[];
17
+ /**
18
+ * Whether the color picker is disabled.
19
+ * @default false
20
+ */
21
+ disabled?: boolean;
22
+ /**
23
+ * Additional CSS classes.
24
+ */
25
+ class?: string;
26
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,69 @@
1
+ import { type VariantProps } from 'tailwind-variants';
2
+ export declare const colorPickerVariants: import("tailwind-variants").TVReturnType<{
3
+ [key: string]: {
4
+ [key: string]: import("tailwind-merge").ClassNameValue | {
5
+ base?: import("tailwind-merge").ClassNameValue;
6
+ content?: import("tailwind-merge").ClassNameValue;
7
+ trigger?: import("tailwind-merge").ClassNameValue;
8
+ colorIndicator?: import("tailwind-merge").ClassNameValue;
9
+ swatchGrid?: import("tailwind-merge").ClassNameValue;
10
+ swatch?: import("tailwind-merge").ClassNameValue;
11
+ nativeInput?: import("tailwind-merge").ClassNameValue;
12
+ hexInputWrapper?: import("tailwind-merge").ClassNameValue;
13
+ };
14
+ };
15
+ } | {
16
+ [x: string]: {
17
+ [x: string]: import("tailwind-merge").ClassNameValue | {
18
+ base?: import("tailwind-merge").ClassNameValue;
19
+ content?: import("tailwind-merge").ClassNameValue;
20
+ trigger?: import("tailwind-merge").ClassNameValue;
21
+ colorIndicator?: import("tailwind-merge").ClassNameValue;
22
+ swatchGrid?: import("tailwind-merge").ClassNameValue;
23
+ swatch?: import("tailwind-merge").ClassNameValue;
24
+ nativeInput?: import("tailwind-merge").ClassNameValue;
25
+ hexInputWrapper?: import("tailwind-merge").ClassNameValue;
26
+ };
27
+ };
28
+ } | {}, {
29
+ base: string;
30
+ trigger: string;
31
+ colorIndicator: string;
32
+ content: string;
33
+ swatchGrid: string;
34
+ swatch: string;
35
+ nativeInput: string;
36
+ hexInputWrapper: string;
37
+ }, undefined, {
38
+ [key: string]: {
39
+ [key: string]: import("tailwind-merge").ClassNameValue | {
40
+ base?: import("tailwind-merge").ClassNameValue;
41
+ content?: import("tailwind-merge").ClassNameValue;
42
+ trigger?: import("tailwind-merge").ClassNameValue;
43
+ colorIndicator?: import("tailwind-merge").ClassNameValue;
44
+ swatchGrid?: import("tailwind-merge").ClassNameValue;
45
+ swatch?: import("tailwind-merge").ClassNameValue;
46
+ nativeInput?: import("tailwind-merge").ClassNameValue;
47
+ hexInputWrapper?: import("tailwind-merge").ClassNameValue;
48
+ };
49
+ };
50
+ } | {}, {
51
+ base: string;
52
+ trigger: string;
53
+ colorIndicator: string;
54
+ content: string;
55
+ swatchGrid: string;
56
+ swatch: string;
57
+ nativeInput: string;
58
+ hexInputWrapper: string;
59
+ }, import("tailwind-variants").TVReturnType<unknown, {
60
+ base: string;
61
+ trigger: string;
62
+ colorIndicator: string;
63
+ content: string;
64
+ swatchGrid: string;
65
+ swatch: string;
66
+ nativeInput: string;
67
+ hexInputWrapper: string;
68
+ }, undefined, unknown, unknown, undefined>>;
69
+ export type ColorPickerVariantProps = VariantProps<typeof colorPickerVariants>;
@@ -0,0 +1,13 @@
1
+ import { tv } from 'tailwind-variants';
2
+ export const colorPickerVariants = tv({
3
+ slots: {
4
+ base: 'relative inline-flex',
5
+ trigger: 'flex items-center gap-2 px-3 py-2 border border-outline-variant rounded-md bg-surface text-sm w-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary',
6
+ colorIndicator: 'w-5 h-5 rounded border border-outline/50 shrink-0',
7
+ content: 'w-64 p-3 flex flex-col gap-3 bg-surface border border-outline-variant rounded-md shadow-md',
8
+ swatchGrid: 'grid grid-cols-6 gap-2',
9
+ swatch: 'w-6 h-6 rounded border border-outline/50 cursor-pointer hover:scale-110 transition-transform focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary',
10
+ nativeInput: 'w-full h-8 cursor-pointer rounded overflow-hidden',
11
+ hexInputWrapper: 'flex items-center gap-2'
12
+ }
13
+ });
@@ -0,0 +1,4 @@
1
+ import ColorPicker from './ColorPicker.svelte';
2
+ export { ColorPicker };
3
+ export * from './color-picker.types.js';
4
+ export * from './color-picker.variants.js';
@@ -0,0 +1,4 @@
1
+ import ColorPicker from './ColorPicker.svelte';
2
+ export { ColorPicker };
3
+ export * from './color-picker.types.js';
4
+ export * from './color-picker.variants.js';
@@ -0,0 +1,59 @@
1
+ <script lang="ts">import { twMerge } from "tailwind-merge";
2
+ import { DateFormatter } from "@internationalized/date";
3
+ import Icon from "../Icon/Icon.svelte";
4
+ import Popover from "../Popover/Popover.svelte";
5
+ import Calendar from "../Calendar/Calendar.svelte";
6
+ import { dateRangePickerVariants } from "./date-range-picker.variants.js";
7
+ let { value = $bindable({
8
+ start: undefined,
9
+ end: undefined
10
+ }), placeholder = "Select date range", numberOfMonths = 2, disabled = false, class: className, onchange, ...restProps } = $props();
11
+ let styles = $derived(dateRangePickerVariants({ disabled }));
12
+ // Internal state for popover
13
+ let open = $state(false);
14
+ // Formatter for displaying dates
15
+ const df = new DateFormatter("en-US", { dateStyle: "medium" });
16
+ let displayText = $derived.by(() => {
17
+ if (value.start) {
18
+ if (value.end) {
19
+ return `${df.format(value.start.toDate("UTC"))} - ${df.format(value.end.toDate("UTC"))}`;
20
+ }
21
+ return df.format(value.start.toDate("UTC"));
22
+ }
23
+ return placeholder;
24
+ });
25
+ function handleDateChange(v) {
26
+ // Range calendar passes an object with start/end
27
+ const rangeValue = v;
28
+ value = rangeValue;
29
+ onchange?.(rangeValue);
30
+ }
31
+ </script>
32
+
33
+ <Popover bind:open>
34
+ {#snippet children({ open })}
35
+ <button
36
+ type="button"
37
+ class={twMerge(styles.trigger() as string, className, !value.start && 'text-surface-500')}
38
+ {disabled}
39
+ {...restProps}
40
+ >
41
+ <div class="flex items-center gap-2 overflow-hidden">
42
+ <Icon name="lucide:calendar" class={styles.icon() as string} />
43
+ <span class={styles.triggerText() as string}>{displayText}</span>
44
+ </div>
45
+ <Icon name="lucide:chevron-down" class={styles.icon() as string} />
46
+ </button>
47
+ {/snippet}
48
+
49
+ {#snippet content()}
50
+ <div class={styles.popoverContent() as string}>
51
+ <Calendar
52
+ range={true}
53
+ value={value as any}
54
+ {numberOfMonths}
55
+ onValueChange={handleDateChange}
56
+ />
57
+ </div>
58
+ {/snippet}
59
+ </Popover>
@@ -0,0 +1,4 @@
1
+ import type { DateRangePickerProps } from './date-range-picker.types.js';
2
+ declare const DateRangePicker: import("svelte").Component<DateRangePickerProps, {}, "value">;
3
+ type DateRangePicker = ReturnType<typeof DateRangePicker>;
4
+ export default DateRangePicker;
@@ -0,0 +1,34 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import type { DateValue } from '@internationalized/date';
3
+ export interface DateRange {
4
+ start: DateValue | undefined;
5
+ end: DateValue | undefined;
6
+ }
7
+ export interface DateRangePickerProps extends Omit<HTMLAttributes<HTMLButtonElement>, 'value' | 'onchange'> {
8
+ /**
9
+ * The selected date range.
10
+ */
11
+ value?: DateRange;
12
+ /**
13
+ * Placeholder text when no dates are selected.
14
+ * @default 'Select date range'
15
+ */
16
+ placeholder?: string;
17
+ /**
18
+ * Number of months to display side-by-side.
19
+ * @default 2
20
+ */
21
+ numberOfMonths?: number;
22
+ /**
23
+ * Whether the picker is disabled.
24
+ */
25
+ disabled?: boolean;
26
+ /**
27
+ * Additional CSS classes for the trigger button.
28
+ */
29
+ class?: string;
30
+ /**
31
+ * Event fired when the date range changes.
32
+ */
33
+ onchange?: (value: DateRange) => void;
34
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,39 @@
1
+ import { type VariantProps } from 'tailwind-variants';
2
+ export declare const dateRangePickerVariants: import("tailwind-variants").TVReturnType<{
3
+ disabled: {
4
+ true: {
5
+ trigger: string;
6
+ };
7
+ };
8
+ }, {
9
+ trigger: string;
10
+ triggerText: string;
11
+ icon: string;
12
+ popoverContent: string;
13
+ calendarWrapper: string;
14
+ }, undefined, {
15
+ disabled: {
16
+ true: {
17
+ trigger: string;
18
+ };
19
+ };
20
+ }, {
21
+ trigger: string;
22
+ triggerText: string;
23
+ icon: string;
24
+ popoverContent: string;
25
+ calendarWrapper: string;
26
+ }, import("tailwind-variants").TVReturnType<{
27
+ disabled: {
28
+ true: {
29
+ trigger: string;
30
+ };
31
+ };
32
+ }, {
33
+ trigger: string;
34
+ triggerText: string;
35
+ icon: string;
36
+ popoverContent: string;
37
+ calendarWrapper: string;
38
+ }, undefined, unknown, unknown, undefined>>;
39
+ export type DateRangePickerVariantProps = VariantProps<typeof dateRangePickerVariants>;
@@ -0,0 +1,20 @@
1
+ import { tv } from 'tailwind-variants';
2
+ export const dateRangePickerVariants = tv({
3
+ slots: {
4
+ trigger: 'flex w-full items-center justify-between gap-2 px-3 py-2 text-sm text-left border border-outline-variant bg-surface-50 dark:bg-surface-900 rounded-md hover:bg-surface-100 dark:hover:bg-surface-800 focus:outline-none focus:ring-2 focus:ring-primary transition-colors',
5
+ triggerText: 'truncate flex-1',
6
+ icon: 'w-4 h-4 shrink-0 text-surface-500',
7
+ popoverContent: 'w-auto p-3 bg-surface-50 dark:bg-surface-900 border border-outline-variant rounded-md shadow-md',
8
+ calendarWrapper: 'flex flex-col sm:flex-row gap-4'
9
+ },
10
+ variants: {
11
+ disabled: {
12
+ true: {
13
+ trigger: 'opacity-50 cursor-not-allowed pointer-events-none'
14
+ }
15
+ }
16
+ },
17
+ defaultVariants: {
18
+ disabled: false
19
+ }
20
+ });
@@ -0,0 +1,4 @@
1
+ import DateRangePicker from './DateRangePicker.svelte';
2
+ export { DateRangePicker };
3
+ export * from './date-range-picker.types.js';
4
+ export * from './date-range-picker.variants.js';
@@ -0,0 +1,4 @@
1
+ import DateRangePicker from './DateRangePicker.svelte';
2
+ export { DateRangePicker };
3
+ export * from './date-range-picker.types.js';
4
+ export * from './date-range-picker.variants.js';
@@ -70,7 +70,9 @@ export function buildGoogleFontsUrl(fonts, display = 'swap') {
70
70
  .filter((family, index, source) => family.length > 0 && source.indexOf(family) === index);
71
71
  if (families.length === 0)
72
72
  return '';
73
- const familyParams = families.map((f) => `family=${f}`).join('&');
73
+ const familyParams = families
74
+ .map((f) => `family=${encodeURIComponent(f).replaceAll('%2B', '+')}`)
75
+ .join('&');
74
76
  return `https://fonts.googleapis.com/css2?${familyParams}&display=${display}`;
75
77
  }
76
78
  export function buildFontFamily(font) {
@@ -0,0 +1,8 @@
1
+ <script lang="ts">import { setContext } from "svelte";
2
+ import Link from "./Link.svelte";
3
+ import { LINK_LOCATION_CONTEXT_KEY } from "./location-context.js";
4
+ let { url } = $props();
5
+ setContext(LINK_LOCATION_CONTEXT_KEY, { currentUrl: () => url });
6
+ </script>
7
+
8
+ <Link href="/from-context" />
@@ -0,0 +1,7 @@
1
+ import Link from './Link.svelte';
2
+ type $$ComponentProps = {
3
+ url: URL;
4
+ };
5
+ declare const Link: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type Link = ReturnType<typeof Link>;
7
+ export default Link;
@@ -1,5 +1,6 @@
1
- <script lang="ts" module>const navigationEvent = "svelora:navigation";
2
- let isHistoryPatched = false;
1
+ <script lang="ts" module>const locationSubscribers = new Set();
2
+ let stopLocationTracking;
3
+ let lastKnownHref = "";
3
4
  function parseUrl(url, baseUrl) {
4
5
  try {
5
6
  const parsed = new URL(url, baseUrl.origin);
@@ -35,60 +36,86 @@ function isPathnameMatch(linkPath, currentPath, exactMatch) {
35
36
  const current = currentPath.replace(/\/$/, "") || "/";
36
37
  return link === "/" ? current === "/" : current === link || current.startsWith(`${link}/`);
37
38
  }
38
- function dispatchNavigationEvent() {
39
+ function dispatchLocationChange() {
39
40
  if (typeof window === "undefined") {
40
41
  return;
41
42
  }
42
- window.dispatchEvent(new Event(navigationEvent));
43
+ for (const callback of locationSubscribers) {
44
+ callback();
45
+ }
43
46
  }
44
- function patchHistoryMethod(method) {
45
- const historyMethod = window.history[method].bind(window.history);
46
- Object.defineProperty(window.history, method, {
47
- configurable: true,
48
- value: (...args) => {
49
- historyMethod(...args);
50
- dispatchNavigationEvent();
51
- }
52
- });
47
+ function syncLocation(force = false) {
48
+ if (typeof window === "undefined") {
49
+ return;
50
+ }
51
+ const href = window.location.href;
52
+ if (!force && href === lastKnownHref) {
53
+ return;
54
+ }
55
+ lastKnownHref = href;
56
+ dispatchLocationChange();
53
57
  }
54
- function ensureNavigationEvents() {
55
- if (typeof window === "undefined" || isHistoryPatched) {
58
+ function scheduleLocationSync() {
59
+ if (typeof window === "undefined") {
60
+ return;
61
+ }
62
+ queueMicrotask(() => syncLocation());
63
+ window.setTimeout(() => syncLocation(), 0);
64
+ window.requestAnimationFrame(() => syncLocation());
65
+ }
66
+ function ensureLocationTracking() {
67
+ if (typeof window === "undefined" || stopLocationTracking) {
56
68
  return;
57
69
  }
58
- isHistoryPatched = true;
59
- patchHistoryMethod("pushState");
60
- patchHistoryMethod("replaceState");
70
+ lastKnownHref = window.location.href;
71
+ const handleImmediateLocationChange = () => syncLocation();
72
+ const handleDeferredLocationChange = () => scheduleLocationSync();
73
+ const intervalId = window.setInterval(() => syncLocation(), 125);
74
+ window.addEventListener("popstate", handleImmediateLocationChange);
75
+ window.addEventListener("hashchange", handleImmediateLocationChange);
76
+ document.addEventListener("click", handleDeferredLocationChange, true);
77
+ stopLocationTracking = () => {
78
+ window.clearInterval(intervalId);
79
+ window.removeEventListener("popstate", handleImmediateLocationChange);
80
+ window.removeEventListener("hashchange", handleImmediateLocationChange);
81
+ document.removeEventListener("click", handleDeferredLocationChange, true);
82
+ stopLocationTracking = undefined;
83
+ };
61
84
  }
62
85
  function subscribeToLocation(callback) {
63
86
  if (typeof window === "undefined") {
64
87
  return () => undefined;
65
88
  }
66
- ensureNavigationEvents();
67
- const handleLocationChange = () => callback();
68
- handleLocationChange();
69
- window.addEventListener("popstate", handleLocationChange);
70
- window.addEventListener("hashchange", handleLocationChange);
71
- window.addEventListener(navigationEvent, handleLocationChange);
89
+ ensureLocationTracking();
90
+ locationSubscribers.add(callback);
91
+ callback();
72
92
  return () => {
73
- window.removeEventListener("popstate", handleLocationChange);
74
- window.removeEventListener("hashchange", handleLocationChange);
75
- window.removeEventListener(navigationEvent, handleLocationChange);
93
+ locationSubscribers.delete(callback);
94
+ if (locationSubscribers.size === 0) {
95
+ stopLocationTracking?.();
96
+ }
76
97
  };
77
98
  }
78
99
  export {};
79
100
  </script>
80
101
 
81
- <script lang="ts">import { onMount } from "svelte";
102
+ <script lang="ts">import { getContext, onMount } from "svelte";
82
103
  import { twMerge } from "tailwind-merge";
83
104
  import { getComponentConfig } from "../config.js";
105
+ import { LINK_LOCATION_CONTEXT_KEY } from "./location-context.js";
84
106
  import { linkDefaults, linkVariants } from "./link.variants.js";
85
107
  const config = getComponentConfig("link", linkDefaults);
86
108
  let { ref = $bindable(null), href, type, active, exact = false, exactQuery = false, exactHash = false, activeClass, inactiveClass, disabled = false, raw = false, external, children, class: className, ui, target, rel, onclick, ...restProps } = $props();
87
109
  const isLink = $derived(!!href);
88
- let currentUrl = $state(undefined);
110
+ const locationContext = getContext(LINK_LOCATION_CONTEXT_KEY);
111
+ let observedUrl = $state(undefined);
112
+ const currentUrl = $derived.by(() => locationContext?.currentUrl() ?? observedUrl);
89
113
  onMount(() => {
114
+ if (locationContext) {
115
+ return;
116
+ }
90
117
  return subscribeToLocation(() => {
91
- currentUrl = new URL(window.location.href);
118
+ observedUrl = new URL(window.location.href);
92
119
  });
93
120
  });
94
121
  const isExternal = $derived(isLink && (external ?? (href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//"))));
@@ -1,2 +1,4 @@
1
1
  export { default as Link } from './Link.svelte';
2
+ export { LINK_LOCATION_CONTEXT_KEY } from './location-context.js';
3
+ export type { LinkLocationContext } from './location-context.js';
2
4
  export type { LinkProps } from './link.types.js';
@@ -1 +1,2 @@
1
1
  export { default as Link } from './Link.svelte';
2
+ export { LINK_LOCATION_CONTEXT_KEY } from './location-context.js';
@@ -0,0 +1,4 @@
1
+ export declare const LINK_LOCATION_CONTEXT_KEY: unique symbol;
2
+ export interface LinkLocationContext {
3
+ currentUrl: () => URL;
4
+ }
@@ -0,0 +1 @@
1
+ export const LINK_LOCATION_CONTEXT_KEY = Symbol('svelora:link-location');
@@ -0,0 +1,14 @@
1
+ <script lang="ts">import { twMerge } from "tailwind-merge";
2
+ import { setContext } from "svelte";
3
+ import { listVariants } from "./list.variants.js";
4
+ let { variant = "default", class: className, children, ...restProps } = $props();
5
+ let styles = $derived(listVariants({ variant }));
6
+ // Pass the variant down to children if needed, or just let them style themselves
7
+ // Since the variant affects the parent 'base', but 'bordered' also affects 'item',
8
+ // we should provide the list context so ListItems know the current variant.
9
+ setContext("list-variant", () => variant);
10
+ </script>
11
+
12
+ <ul class={twMerge(styles.base(), className)} {...restProps}>
13
+ {@render children?.()}
14
+ </ul>
@@ -0,0 +1,4 @@
1
+ import type { ListProps } from './list.types.js';
2
+ declare const List: import("svelte").Component<ListProps, {}, "">;
3
+ type List = ReturnType<typeof List>;
4
+ export default List;