@spaethtech/svelte-ui 0.1.10 → 0.3.1-dev.3.e16df24

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 (208) hide show
  1. package/README.md +180 -42
  2. package/dist/components/Alert.svelte +119 -0
  3. package/dist/components/Alert.svelte.d.ts +29 -0
  4. package/dist/components/Badge/Badge.svelte +142 -69
  5. package/dist/components/Badge/Badge.svelte.d.ts +26 -6
  6. package/dist/components/Badge/index.d.ts +1 -1
  7. package/dist/components/Badge/index.js +1 -1
  8. package/dist/components/Banner.svelte +133 -0
  9. package/dist/components/Banner.svelte.d.ts +31 -0
  10. package/dist/components/Button.svelte +240 -0
  11. package/dist/components/Button.svelte.d.ts +33 -0
  12. package/dist/components/ButtonDropdown.svelte +145 -0
  13. package/dist/components/ButtonDropdown.svelte.d.ts +31 -0
  14. package/dist/components/Calendar.svelte +259 -0
  15. package/dist/components/Calendar.svelte.d.ts +27 -0
  16. package/dist/components/Card.svelte +78 -0
  17. package/dist/components/Card.svelte.d.ts +17 -0
  18. package/dist/components/CardBody.svelte +41 -0
  19. package/dist/components/CardBody.svelte.d.ts +17 -0
  20. package/dist/components/CardFooter.svelte +49 -0
  21. package/dist/components/CardFooter.svelte.d.ts +16 -0
  22. package/dist/components/CardHeader.svelte +49 -0
  23. package/dist/components/CardHeader.svelte.d.ts +16 -0
  24. package/dist/components/Checkbox.svelte +131 -0
  25. package/dist/components/Checkbox.svelte.d.ts +16 -0
  26. package/dist/components/DataTable.svelte +518 -0
  27. package/dist/components/DataTable.svelte.d.ts +74 -0
  28. package/dist/components/DatePicker.svelte +312 -0
  29. package/dist/components/DatePicker.svelte.d.ts +32 -0
  30. package/dist/components/DateTimeInput.svelte +93 -0
  31. package/dist/components/DateTimeInput.svelte.d.ts +20 -0
  32. package/dist/components/Dialog.svelte +132 -0
  33. package/dist/components/Dialog.svelte.d.ts +24 -0
  34. package/dist/components/{EmailInput/EmailInput.svelte → EmailInput.svelte} +17 -8
  35. package/dist/components/EmailInput.svelte.d.ts +21 -0
  36. package/dist/components/Input.svelte +369 -0
  37. package/dist/components/Input.svelte.d.ts +35 -0
  38. package/dist/components/{List/List.svelte → List.svelte} +194 -133
  39. package/dist/components/{List/List.svelte.d.ts → List.svelte.d.ts} +9 -1
  40. package/dist/components/Menu.svelte +117 -0
  41. package/dist/components/Menu.svelte.d.ts +20 -0
  42. package/dist/components/NotesEditor.svelte +127 -0
  43. package/dist/components/NotesEditor.svelte.d.ts +17 -0
  44. package/dist/components/{NumberInput/NumberInput.svelte → NumberInput.svelte} +146 -105
  45. package/dist/components/{NumberInput/NumberInput.svelte.d.ts → NumberInput.svelte.d.ts} +11 -4
  46. package/dist/components/PasswordInput.svelte +52 -0
  47. package/dist/components/PasswordInput.svelte.d.ts +20 -0
  48. package/dist/components/Popup.svelte +140 -0
  49. package/dist/components/Popup.svelte.d.ts +31 -0
  50. package/dist/components/Query.svelte +284 -0
  51. package/dist/components/Query.svelte.d.ts +15 -0
  52. package/dist/components/{Rating/Rating.svelte → Rating.svelte} +19 -10
  53. package/dist/components/Rating.svelte.d.ts +13 -0
  54. package/dist/components/{SearchInput/SearchInput.svelte → SearchInput.svelte} +19 -8
  55. package/dist/components/{SearchInput/SearchInput.svelte.d.ts → SearchInput.svelte.d.ts} +9 -2
  56. package/dist/components/{Select/Select.svelte → Select.svelte} +48 -76
  57. package/dist/components/{Select/Select.svelte.d.ts → Select.svelte.d.ts} +11 -1
  58. package/dist/components/SideBarMenu/SideBarMenu.svelte +724 -0
  59. package/dist/components/SideBarMenu/SideBarMenu.svelte.d.ts +109 -0
  60. package/dist/components/SideBarMenu/index.d.ts +2 -0
  61. package/dist/components/SideBarMenu/index.js +1 -0
  62. package/dist/components/TabStrip/TabStrip.svelte +384 -0
  63. package/dist/components/TabStrip/TabStrip.svelte.d.ts +50 -0
  64. package/dist/components/TabStrip/index.d.ts +3 -0
  65. package/dist/components/TabStrip/index.js +2 -0
  66. package/dist/components/{TextArea/TextArea.svelte → TextArea.svelte} +143 -112
  67. package/dist/components/TextArea.svelte.d.ts +38 -0
  68. package/dist/components/ThemeSelector.svelte +81 -0
  69. package/dist/components/ThemeSelector.svelte.d.ts +10 -0
  70. package/dist/components/TimePicker.svelte +148 -0
  71. package/dist/components/TimePicker.svelte.d.ts +28 -0
  72. package/dist/components/TimeRangeInput.svelte +203 -0
  73. package/dist/components/TimeRangeInput.svelte.d.ts +29 -0
  74. package/dist/components/TimeSpinner.svelte +202 -0
  75. package/dist/components/TimeSpinner.svelte.d.ts +26 -0
  76. package/dist/components/Toast/Toaster.svelte +51 -0
  77. package/dist/components/Toast/Toaster.svelte.d.ts +12 -0
  78. package/dist/components/Toast/toast.svelte.d.ts +29 -0
  79. package/dist/components/Toast/toast.svelte.js +27 -0
  80. package/dist/components/Toggle.svelte +93 -0
  81. package/dist/components/Toggle.svelte.d.ts +15 -0
  82. package/dist/data/dataset.d.ts +42 -0
  83. package/dist/data/dataset.js +3 -0
  84. package/dist/data/index.d.ts +3 -0
  85. package/dist/data/index.js +3 -0
  86. package/dist/data/query/ast.d.ts +62 -0
  87. package/dist/data/query/ast.js +12 -0
  88. package/dist/data/query/index.d.ts +3 -0
  89. package/dist/data/query/index.js +3 -0
  90. package/dist/data/query/lexer.d.ts +33 -0
  91. package/dist/data/query/lexer.js +225 -0
  92. package/dist/data/query/parser.d.ts +11 -0
  93. package/dist/data/query/parser.js +252 -0
  94. package/dist/data/table/grid.svelte.d.ts +57 -0
  95. package/dist/data/table/grid.svelte.js +139 -0
  96. package/dist/data/table/index.d.ts +2 -0
  97. package/dist/data/table/index.js +2 -0
  98. package/dist/data/table/types.d.ts +79 -0
  99. package/dist/index.d.ts +48 -22
  100. package/dist/index.js +45 -21
  101. package/dist/positioning/anchored.d.ts +61 -0
  102. package/dist/positioning/anchored.js +122 -0
  103. package/dist/positioning/tooltip.d.ts +41 -0
  104. package/dist/positioning/tooltip.js +147 -0
  105. package/dist/theme.css +205 -0
  106. package/dist/types/breakpoints.d.ts +24 -0
  107. package/dist/types/breakpoints.js +13 -0
  108. package/dist/types/responsive.d.ts +32 -0
  109. package/dist/types/responsive.js +54 -0
  110. package/dist/types/sizes.d.ts +10 -3
  111. package/dist/types/time.d.ts +19 -0
  112. package/dist/types/time.js +10 -0
  113. package/dist/types/variants.d.ts +8 -1
  114. package/dist/types/variants.js +16 -1
  115. package/package.json +93 -63
  116. package/dist/components/Button/Button.svelte +0 -172
  117. package/dist/components/Button/Button.svelte.d.ts +0 -32
  118. package/dist/components/Button/index.d.ts +0 -1
  119. package/dist/components/Button/index.js +0 -1
  120. package/dist/components/Dialog/Dialog.svelte +0 -101
  121. package/dist/components/Dialog/Dialog.svelte.d.ts +0 -18
  122. package/dist/components/Dialog/index.d.ts +0 -1
  123. package/dist/components/Dialog/index.js +0 -1
  124. package/dist/components/ElementManager/ElementManager.svelte +0 -397
  125. package/dist/components/ElementManager/ElementManager.svelte.d.ts +0 -43
  126. package/dist/components/ElementManager/index.d.ts +0 -1
  127. package/dist/components/ElementManager/index.js +0 -1
  128. package/dist/components/EmailInput/EmailInput.svelte.d.ts +0 -14
  129. package/dist/components/EmailInput/index.d.ts +0 -1
  130. package/dist/components/EmailInput/index.js +0 -1
  131. package/dist/components/Icon/Icon.svelte +0 -74
  132. package/dist/components/Icon/Icon.svelte.d.ts +0 -13
  133. package/dist/components/Icon/index.d.ts +0 -1
  134. package/dist/components/Icon/index.js +0 -1
  135. package/dist/components/Input/Input.svelte +0 -268
  136. package/dist/components/Input/Input.svelte.d.ts +0 -18
  137. package/dist/components/Input/index.d.ts +0 -1
  138. package/dist/components/Input/index.js +0 -1
  139. package/dist/components/List/index.d.ts +0 -1
  140. package/dist/components/List/index.js +0 -1
  141. package/dist/components/ListItem/ListItem.svelte +0 -175
  142. package/dist/components/ListItem/ListItem.svelte.d.ts +0 -24
  143. package/dist/components/ListItem/index.d.ts +0 -2
  144. package/dist/components/ListItem/index.js +0 -2
  145. package/dist/components/ListView/ListView.svelte +0 -463
  146. package/dist/components/ListView/ListView.svelte.d.ts +0 -37
  147. package/dist/components/ListView/index.d.ts +0 -2
  148. package/dist/components/ListView/index.js +0 -2
  149. package/dist/components/NodeGraph/BaseNode.d.ts +0 -57
  150. package/dist/components/NodeGraph/BaseNode.js +0 -30
  151. package/dist/components/NodeGraph/Edge.svelte +0 -60
  152. package/dist/components/NodeGraph/Edge.svelte.d.ts +0 -16
  153. package/dist/components/NodeGraph/ExpressionEvaluator.d.ts +0 -82
  154. package/dist/components/NodeGraph/ExpressionEvaluator.js +0 -152
  155. package/dist/components/NodeGraph/Node.svelte +0 -100
  156. package/dist/components/NodeGraph/Node.svelte.d.ts +0 -10
  157. package/dist/components/NodeGraph/NodeGraph.svelte +0 -52
  158. package/dist/components/NodeGraph/NodeGraph.svelte.d.ts +0 -14
  159. package/dist/components/NodeGraph/NodeInstance.svelte.d.ts +0 -80
  160. package/dist/components/NodeGraph/NodeInstance.svelte.js +0 -241
  161. package/dist/components/NodeGraph/NodePort.svelte +0 -75
  162. package/dist/components/NodeGraph/NodePort.svelte.d.ts +0 -11
  163. package/dist/components/NodeGraph/decorators.d.ts +0 -81
  164. package/dist/components/NodeGraph/decorators.js +0 -148
  165. package/dist/components/NodeGraph/index.d.ts +0 -9
  166. package/dist/components/NodeGraph/index.js +0 -9
  167. package/dist/components/NodeGraph/types.d.ts +0 -94
  168. package/dist/components/NodeGraph/types.js +0 -33
  169. package/dist/components/NotesEditor/NotesEditor.svelte +0 -203
  170. package/dist/components/NotesEditor/NotesEditor.svelte.d.ts +0 -9
  171. package/dist/components/NotesEditor/index.d.ts +0 -1
  172. package/dist/components/NotesEditor/index.js +0 -1
  173. package/dist/components/NumberInput/index.d.ts +0 -1
  174. package/dist/components/NumberInput/index.js +0 -1
  175. package/dist/components/PasswordInput/PasswordInput.svelte +0 -41
  176. package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +0 -13
  177. package/dist/components/PasswordInput/index.d.ts +0 -1
  178. package/dist/components/PasswordInput/index.js +0 -1
  179. package/dist/components/Popup/index.d.ts +0 -1
  180. package/dist/components/Popup/index.js +0 -1
  181. package/dist/components/Rating/Rating.svelte.d.ts +0 -7
  182. package/dist/components/Rating/index.d.ts +0 -1
  183. package/dist/components/Rating/index.js +0 -1
  184. package/dist/components/ScrollView/ScrollView.svelte +0 -285
  185. package/dist/components/ScrollView/ScrollView.svelte.d.ts +0 -19
  186. package/dist/components/ScrollView/index.d.ts +0 -1
  187. package/dist/components/ScrollView/index.js +0 -1
  188. package/dist/components/SearchInput/index.d.ts +0 -1
  189. package/dist/components/SearchInput/index.js +0 -1
  190. package/dist/components/Select/index.d.ts +0 -1
  191. package/dist/components/Select/index.js +0 -1
  192. package/dist/components/TextArea/TextArea.svelte.d.ts +0 -19
  193. package/dist/components/TextArea/index.d.ts +0 -1
  194. package/dist/components/TextArea/index.js +0 -1
  195. package/dist/components/ThemeSelector/ThemeSelector.svelte +0 -64
  196. package/dist/components/ThemeSelector/ThemeSelector.svelte.d.ts +0 -3
  197. package/dist/components/ThemeSelector/index.d.ts +0 -1
  198. package/dist/components/ThemeSelector/index.js +0 -1
  199. package/dist/components/TooltipHandler/TooltipHandler.svelte +0 -593
  200. package/dist/components/TooltipHandler/TooltipHandler.svelte.d.ts +0 -10
  201. package/dist/components/TooltipHandler/index.d.ts +0 -1
  202. package/dist/components/TooltipHandler/index.js +0 -1
  203. package/dist/styles/sizes.d.ts +0 -78
  204. package/dist/styles/sizes.js +0 -120
  205. package/dist/styles/variants.d.ts +0 -106
  206. package/dist/styles/variants.js +0 -194
  207. package/dist/types/ManagerTypes.d.ts +0 -42
  208. /package/dist/{types/ManagerTypes.js → data/table/types.js} +0 -0
@@ -0,0 +1,259 @@
1
+ <!--
2
+ /**
3
+ * Calendar — the themed month-grid primitive behind DatePicker. A pure inline calendar (no popup/
4
+ * trigger) so it can live in a Popup, a Dialog, or on a page. Values are ISO `YYYY-MM-DD` (local, not
5
+ * UTC-shifted).
6
+ *
7
+ * `mode="single"` binds `value`; `mode="range"` binds `start`/`end` and paints the band between them
8
+ * (with a live hover preview while picking the end). Keyboard: arrows move the day cursor (crossing
9
+ * months), Home/End jump to row ends, PageUp/PageDown change month, Enter/Space select.
10
+ */
11
+ -->
12
+ <script lang="ts">
13
+ import type { Size } from "../types/sizes.js";
14
+ import { responsiveClasses, type Responsive } from "../types/responsive.js";
15
+ import { variantToken, type Variant } from "../types/variants.js";
16
+ import IconLeft from "~icons/mdi/chevron-left";
17
+ import IconRight from "~icons/mdi/chevron-right";
18
+
19
+ interface Props {
20
+ mode?: "single" | "range";
21
+ /** Single mode: selected date, ISO `YYYY-MM-DD`. Bindable. */
22
+ value?: string;
23
+ /** Range mode: endpoints, ISO `YYYY-MM-DD`. Bindable. */
24
+ start?: string;
25
+ end?: string;
26
+ min?: string;
27
+ max?: string;
28
+ weekStart?: 0 | 1;
29
+ locale?: string;
30
+ size?: Responsive<Size>;
31
+ /** Accent for the selected day + range band. Default primary. */
32
+ variant?: Variant;
33
+ class?: string;
34
+ onselect?: (iso: string) => void;
35
+ onrange?: (r: { start: string; end: string }) => void;
36
+ }
37
+
38
+ let {
39
+ mode = "single",
40
+ value = $bindable(""),
41
+ start = $bindable(""),
42
+ end = $bindable(""),
43
+ min,
44
+ max,
45
+ weekStart,
46
+ locale = typeof navigator !== "undefined" ? navigator.language : "en-US",
47
+ size = "md",
48
+ variant = "primary",
49
+ class: cls = "",
50
+ onselect,
51
+ onrange,
52
+ }: Props = $props();
53
+
54
+ const accent = $derived(`var(${variantToken[variant]})`);
55
+
56
+ const iso = (dt: Date) =>
57
+ `${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, "0")}-${String(dt.getDate()).padStart(2, "0")}`;
58
+ const parse = (s: string) => {
59
+ const [y, m, d] = s.split("-").map(Number);
60
+ return new Date(y, m - 1, d);
61
+ };
62
+ const todayIso = iso(new Date());
63
+
64
+ const resolvedWeekStart = $derived.by<0 | 1>(() => {
65
+ if (weekStart === 0 || weekStart === 1) return weekStart;
66
+ try {
67
+ const loc = new Intl.Locale(locale) as Intl.Locale & {
68
+ weekInfo?: { firstDay: number };
69
+ getWeekInfo?: () => { firstDay: number };
70
+ };
71
+ const first = loc.weekInfo?.firstDay ?? loc.getWeekInfo?.().firstDay;
72
+ return first === 1 ? 1 : 0;
73
+ } catch {
74
+ return 0;
75
+ }
76
+ });
77
+
78
+ const seed = $derived(parse(value || start || todayIso));
79
+ let view = $state({ y: seed.getFullYear(), m: seed.getMonth() });
80
+ let cursor = $state(iso(seed));
81
+ let hover = $state(""); // range: previewed end while picking
82
+
83
+ $effect(() => {
84
+ const anchor = value || start;
85
+ if (!anchor) return;
86
+ const d = parse(anchor);
87
+ if (d.getFullYear() !== view.y || d.getMonth() !== view.m)
88
+ view = { y: d.getFullYear(), m: d.getMonth() };
89
+ });
90
+
91
+ const monthLabel = $derived(
92
+ new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }).format(
93
+ new Date(view.y, view.m, 1),
94
+ ),
95
+ );
96
+ const weekdays = $derived.by(() => {
97
+ const fmt = new Intl.DateTimeFormat(locale, { weekday: "short" });
98
+ return Array.from({ length: 7 }, (_, i) =>
99
+ fmt.format(new Date(2024, 0, 7 + ((i + resolvedWeekStart) % 7))),
100
+ );
101
+ });
102
+ const cells = $derived.by(() => {
103
+ const first = new Date(view.y, view.m, 1);
104
+ const lead = (first.getDay() - resolvedWeekStart + 7) % 7;
105
+ return Array.from({ length: 42 }, (_, i) => new Date(view.y, view.m, 1 - lead + i));
106
+ });
107
+
108
+ const outOfBounds = (i: string) => !!((min && i < min) || (max && i > max));
109
+
110
+ // range: the low/high of the currently-painted span (committed end, else hover preview).
111
+ const selecting = $derived(mode === "range" && !!start && !end);
112
+ const previewEnd = $derived(end || (selecting ? hover : ""));
113
+ const lo = $derived(start && previewEnd ? (start < previewEnd ? start : previewEnd) : start);
114
+ const hi = $derived(start && previewEnd ? (start < previewEnd ? previewEnd : start) : "");
115
+
116
+ // Each field is a per-Size class map → responsiveClasses() so `size` may be scalar OR responsive.
117
+ const cellMap: Record<Size, string> = {
118
+ sm: "size-7 text-xs",
119
+ md: "size-8 text-sm",
120
+ lg: "size-10 text-base",
121
+ };
122
+ const headMap: Record<Size, string> = { sm: "h-9", md: "h-10", lg: "h-11" };
123
+ const labelMap: Record<Size, string> = { sm: "text-xs", md: "text-sm", lg: "text-base" };
124
+ const navMap: Record<Size, string> = { sm: "size-7", md: "size-8", lg: "size-9" };
125
+ const sizing = $derived({
126
+ cell: responsiveClasses(size, cellMap),
127
+ head: responsiveClasses(size, headMap),
128
+ label: responsiveClasses(size, labelMap),
129
+ nav: responsiveClasses(size, navMap),
130
+ });
131
+
132
+ function go(deltaMonths: number) {
133
+ const d = new Date(view.y, view.m + deltaMonths, 1);
134
+ view = { y: d.getFullYear(), m: d.getMonth() };
135
+ }
136
+ function pick(i: string) {
137
+ if (outOfBounds(i)) return;
138
+ cursor = i;
139
+ if (mode === "single") {
140
+ value = i;
141
+ onselect?.(i);
142
+ return;
143
+ }
144
+ if (!start || (start && end)) {
145
+ start = i;
146
+ end = "";
147
+ onrange?.({ start: i, end: "" });
148
+ } else if (i < start) {
149
+ start = i;
150
+ onrange?.({ start: i, end: "" });
151
+ } else {
152
+ end = i;
153
+ onrange?.({ start, end: i });
154
+ }
155
+ }
156
+ function moveCursor(days: number) {
157
+ const d = parse(cursor);
158
+ d.setDate(d.getDate() + days);
159
+ cursor = iso(d);
160
+ if (d.getFullYear() !== view.y || d.getMonth() !== view.m)
161
+ view = { y: d.getFullYear(), m: d.getMonth() };
162
+ }
163
+ function onKey(e: KeyboardEvent) {
164
+ const k = e.key;
165
+ if (k === "ArrowLeft") moveCursor(-1);
166
+ else if (k === "ArrowRight") moveCursor(1);
167
+ else if (k === "ArrowUp") moveCursor(-7);
168
+ else if (k === "ArrowDown") moveCursor(7);
169
+ else if (k === "Home") moveCursor(-((parse(cursor).getDay() - resolvedWeekStart + 7) % 7));
170
+ else if (k === "End") moveCursor(6 - ((parse(cursor).getDay() - resolvedWeekStart + 7) % 7));
171
+ else if (k === "PageUp") go(-1);
172
+ else if (k === "PageDown") go(1);
173
+ else if (k === "Enter" || k === " ") pick(cursor);
174
+ else return;
175
+ e.preventDefault();
176
+ }
177
+
178
+ let gridEl = $state<HTMLDivElement>();
179
+ $effect(() => {
180
+ const btn = gridEl?.querySelector<HTMLButtonElement>(`[data-iso="${cursor}"]`);
181
+ if (btn && gridEl?.contains(document.activeElement)) btn.focus();
182
+ });
183
+
184
+ const subtle = "[color:color-mix(in_srgb,var(--ui-color-text)_55%,transparent)]";
185
+ </script>
186
+
187
+ <div
188
+ class="inline-block select-none rounded-[var(--ui-border-radius)] [color:var(--ui-color-text)] {cls}"
189
+ style="--accent: {accent}"
190
+ >
191
+ <div class="mb-1 flex items-center justify-between {sizing.head}">
192
+ <button
193
+ type="button"
194
+ aria-label="Previous month"
195
+ class="grid {sizing.nav} place-items-center rounded-[var(--ui-border-radius)] hover:[background-color:var(--ui-color-hover)] active:[background-color:var(--ui-color-active)]"
196
+ onclick={() => go(-1)}><IconLeft class="size-5" /></button
197
+ >
198
+ <span class="{sizing.label} font-medium">{monthLabel}</span>
199
+ <button
200
+ type="button"
201
+ aria-label="Next month"
202
+ class="grid {sizing.nav} place-items-center rounded-[var(--ui-border-radius)] hover:[background-color:var(--ui-color-hover)] active:[background-color:var(--ui-color-active)]"
203
+ onclick={() => go(1)}><IconRight class="size-5" /></button
204
+ >
205
+ </div>
206
+
207
+ <div class="grid grid-cols-7 {subtle}">
208
+ {#each weekdays as w (w)}<div class="grid {sizing.cell} place-items-center font-medium">
209
+ {w}
210
+ </div>{/each}
211
+ </div>
212
+
213
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
214
+ <div
215
+ bind:this={gridEl}
216
+ role="grid"
217
+ tabindex="-1"
218
+ class="grid grid-cols-7"
219
+ onkeydown={onKey}
220
+ onmouseleave={() => (hover = "")}
221
+ >
222
+ {#each cells as dt (iso(dt))}
223
+ {@const i = iso(dt)}
224
+ {@const inMonth = dt.getMonth() === view.m}
225
+ {@const edge =
226
+ mode === "single" ? i === value : i === start || i === end || (selecting && i === hover)}
227
+ {@const band = mode === "range" && !!lo && !!hi && i > lo && i < hi}
228
+ {@const isToday = i === todayIso}
229
+ {@const disabled = outOfBounds(i)}
230
+ <div
231
+ class="flex justify-center"
232
+ style={band ? "background-color: color-mix(in srgb, var(--accent) 14%, transparent)" : ""}
233
+ >
234
+ <button
235
+ type="button"
236
+ role="gridcell"
237
+ data-iso={i}
238
+ aria-selected={edge}
239
+ aria-current={isToday ? "date" : undefined}
240
+ tabindex={i === cursor ? 0 : -1}
241
+ {disabled}
242
+ class="grid {sizing.cell} place-items-center rounded-[var(--ui-border-radius)] transition-colors
243
+ {disabled ? 'cursor-not-allowed opacity-30' : 'cursor-pointer'}
244
+ {edge
245
+ ? '[background-color:var(--accent)] font-semibold text-white'
246
+ : !disabled && !band
247
+ ? 'hover:[background-color:var(--ui-color-hover)] active:[background-color:var(--ui-color-active)]'
248
+ : ''}
249
+ {!edge && !inMonth ? subtle : ''}
250
+ {!edge && isToday ? '[box-shadow:inset_0_0_0_1px_var(--ui-color-secondary)]' : ''}"
251
+ onclick={() => pick(i)}
252
+ onmouseenter={() => {
253
+ if (selecting) hover = i;
254
+ }}>{dt.getDate()}</button
255
+ >
256
+ </div>
257
+ {/each}
258
+ </div>
259
+ </div>
@@ -0,0 +1,27 @@
1
+ import type { Size } from "../types/sizes.js";
2
+ import { type Responsive } from "../types/responsive.js";
3
+ import { type Variant } from "../types/variants.js";
4
+ interface Props {
5
+ mode?: "single" | "range";
6
+ /** Single mode: selected date, ISO `YYYY-MM-DD`. Bindable. */
7
+ value?: string;
8
+ /** Range mode: endpoints, ISO `YYYY-MM-DD`. Bindable. */
9
+ start?: string;
10
+ end?: string;
11
+ min?: string;
12
+ max?: string;
13
+ weekStart?: 0 | 1;
14
+ locale?: string;
15
+ size?: Responsive<Size>;
16
+ /** Accent for the selected day + range band. Default primary. */
17
+ variant?: Variant;
18
+ class?: string;
19
+ onselect?: (iso: string) => void;
20
+ onrange?: (r: {
21
+ start: string;
22
+ end: string;
23
+ }) => void;
24
+ }
25
+ declare const Calendar: import("svelte").Component<Props, {}, "start" | "end" | "value">;
26
+ type Calendar = ReturnType<typeof Calendar>;
27
+ export default Calendar;
@@ -0,0 +1,78 @@
1
+ <!--
2
+ /**
3
+ * Card — a bordered surface with rounded corners. The CARD owns the padding, so a `CardHeader` /
4
+ * `CardFooter` separator sits INSIDE that padding (inset, not edge-to-edge). Compose with the
5
+ * sub-components for structure, or pass plain children for a simple panel.
6
+ *
7
+ * Border + radius come from the shared tint tokens (the same scheme Input/DataTable use, so surfaces
8
+ * match): the OUTER frame is the variant token at `--ui-tint-border` (rest) / `--ui-tint-border-hover`
9
+ * (hover) — one calc for every variant, no `secondary` special case — while inset Header/Footer
10
+ * separators stay soft (`--ui-border-color`). `variant` sets the border colour; `size` the padding.
11
+ *
12
+ * Background comes from `--ui-color-background` so the card reads as a raised panel over the page
13
+ * body (matches Input, Dialog, tooltip surface tokens). Themes remap this token to their own
14
+ * surface color; svelte-ui's default is `#ffffff` for a light-UI baseline.
15
+ */
16
+ -->
17
+ <script lang="ts">
18
+ import type { Snippet } from "svelte";
19
+ import type { HTMLAttributes } from "svelte/elements";
20
+ import type { Size } from "../types/sizes.js";
21
+ import { responsiveClasses, type Responsive } from "../types/responsive.js";
22
+ import { variantToken, type Variant } from "../types/variants.js";
23
+
24
+ let {
25
+ variant = "secondary",
26
+ size = "md",
27
+ borderless = false,
28
+ class: cls = "",
29
+ children,
30
+ ...rest
31
+ }: {
32
+ variant?: Variant;
33
+ size?: Responsive<Size>;
34
+ /** Drop the visible frame while keeping the 1px box: border colour = the card's own background.
35
+ * Defaults `false` — a Card reads as a framed surface. */
36
+ borderless?: boolean;
37
+ class?: string;
38
+ children?: Snippet;
39
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
40
+
41
+ const padFor: Record<Size, string> = { sm: "p-3", md: "p-4", lg: "p-6" };
42
+ // Border: ONE calc for EVERY variant (no `secondary`/`--ui-border-color-strong` special case) — the
43
+ // variant token at `--ui-tint-border` (rest) and `--ui-tint-border-hover` (hover), mixed toward
44
+ // transparent, same as Input/TextArea. `borderless` paints it the card's own background (frame gone,
45
+ // box unchanged). Rest goes in inline style (dynamic token); hover needs a class (inline can't do
46
+ // :hover), enumerated per-variant so Tailwind emits it.
47
+ const borderColor = $derived(
48
+ borderless
49
+ ? "var(--ui-color-background)"
50
+ : `color-mix(in srgb, var(${variantToken[variant]}) var(--ui-tint-border), transparent)`,
51
+ );
52
+ const hoverBorderClass: Record<Variant, string> = {
53
+ secondary:
54
+ "hover:[border-color:color-mix(in_srgb,var(--ui-color-secondary)_var(--ui-tint-border-hover),transparent)]",
55
+ primary:
56
+ "hover:[border-color:color-mix(in_srgb,var(--ui-color-primary)_var(--ui-tint-border-hover),transparent)]",
57
+ danger:
58
+ "hover:[border-color:color-mix(in_srgb,var(--ui-color-error)_var(--ui-tint-border-hover),transparent)]",
59
+ info: "hover:[border-color:color-mix(in_srgb,var(--ui-color-info)_var(--ui-tint-border-hover),transparent)]",
60
+ success:
61
+ "hover:[border-color:color-mix(in_srgb,var(--ui-color-success)_var(--ui-tint-border-hover),transparent)]",
62
+ warning:
63
+ "hover:[border-color:color-mix(in_srgb,var(--ui-color-warning)_var(--ui-tint-border-hover),transparent)]",
64
+ neutral:
65
+ "hover:[border-color:color-mix(in_srgb,var(--ui-color-text)_var(--ui-tint-border-hover),transparent)]",
66
+ ghost:
67
+ "hover:[border-color:color-mix(in_srgb,var(--ui-color-text)_var(--ui-tint-border-hover),transparent)]",
68
+ };
69
+ const hoverClass = $derived(borderless ? "" : `transition-colors ${hoverBorderClass[variant]}`);
70
+ </script>
71
+
72
+ <div
73
+ class="border {responsiveClasses(size, padFor)} {hoverClass} {cls}"
74
+ style="border-radius: var(--ui-border-radius); border-color: {borderColor}; background: var(--ui-color-background)"
75
+ {...rest}
76
+ >
77
+ {@render children?.()}
78
+ </div>
@@ -0,0 +1,17 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import type { Size } from "../types/sizes.js";
4
+ import { type Responsive } from "../types/responsive.js";
5
+ import { type Variant } from "../types/variants.js";
6
+ type $$ComponentProps = {
7
+ variant?: Variant;
8
+ size?: Responsive<Size>;
9
+ /** Drop the visible frame while keeping the 1px box: border colour = the card's own background.
10
+ * Defaults `false` — a Card reads as a framed surface. */
11
+ borderless?: boolean;
12
+ class?: string;
13
+ children?: Snippet;
14
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class">;
15
+ declare const Card: import("svelte").Component<$$ComponentProps, {}, "">;
16
+ type Card = ReturnType<typeof Card>;
17
+ export default Card;
@@ -0,0 +1,41 @@
1
+ <!--
2
+ /**
3
+ * CardBody — the main content region of a Card. A semantic wrapper; the Card already provides the
4
+ * padding, so this just groups the body content between an optional CardHeader and CardFooter. Pass a
5
+ * `class` for body-specific layout (e.g. `space-y-3`).
6
+ */
7
+ -->
8
+ <script lang="ts">
9
+ import type { Snippet } from "svelte";
10
+ import type { HTMLAttributes } from "svelte/elements";
11
+ import type { Size } from "../types/sizes.js";
12
+ import { responsiveClasses, type Responsive } from "../types/responsive.js";
13
+ import { variantToken, type Variant } from "../types/variants.js";
14
+
15
+ let {
16
+ variant,
17
+ size = "md",
18
+ class: cls = "",
19
+ children,
20
+ ...rest
21
+ }: {
22
+ /** Scopes the accent to the body subtree — points `--ui-accent` at the variant token (via
23
+ * `.ui-accent`), so interactive children (hover tints, etc.) pick up that colour. */
24
+ variant?: Variant;
25
+ /** Body text tier (sm/md/lg). */
26
+ size?: Responsive<Size>;
27
+ class?: string;
28
+ children?: Snippet;
29
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
30
+
31
+ const textMap: Record<Size, string> = { sm: "text-sm", md: "", lg: "text-lg" };
32
+ const accentVar = $derived(variant ? `--ui-accent: var(${variantToken[variant]});` : "");
33
+ </script>
34
+
35
+ <div
36
+ class="{variant ? 'ui-accent ' : ''}{responsiveClasses(size, textMap)} {cls}"
37
+ style={accentVar}
38
+ {...rest}
39
+ >
40
+ {@render children?.()}
41
+ </div>
@@ -0,0 +1,17 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import type { Size } from "../types/sizes.js";
4
+ import { type Responsive } from "../types/responsive.js";
5
+ import { type Variant } from "../types/variants.js";
6
+ type $$ComponentProps = {
7
+ /** Scopes the accent to the body subtree — points `--ui-accent` at the variant token (via
8
+ * `.ui-accent`), so interactive children (hover tints, etc.) pick up that colour. */
9
+ variant?: Variant;
10
+ /** Body text tier (sm/md/lg). */
11
+ size?: Responsive<Size>;
12
+ class?: string;
13
+ children?: Snippet;
14
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class">;
15
+ declare const CardBody: import("svelte").Component<$$ComponentProps, {}, "">;
16
+ type CardBody = ReturnType<typeof CardBody>;
17
+ export default CardBody;
@@ -0,0 +1,49 @@
1
+ <!--
2
+ /**
3
+ * CardFooter — the bottom section of a Card, with a top separator (inset by the Card's padding). The
4
+ * separator is configurable HERE: `variant` sets its colour, `separator={false}` removes it, `size`
5
+ * sets the spacing. Lays out as a flex row with the content end-aligned (action buttons) by default;
6
+ * override via `class`.
7
+ */
8
+ -->
9
+ <script lang="ts">
10
+ import type { Snippet } from "svelte";
11
+ import type { HTMLAttributes } from "svelte/elements";
12
+ import type { Size } from "../types/sizes.js";
13
+ import { responsiveClasses, type Responsive } from "../types/responsive.js";
14
+ import { variantToken, type Variant } from "../types/variants.js";
15
+
16
+ let {
17
+ variant = "secondary",
18
+ size = "md",
19
+ separator = true,
20
+ class: cls = "",
21
+ children,
22
+ ...rest
23
+ }: {
24
+ variant?: Variant;
25
+ size?: Responsive<Size>;
26
+ /** Show the top separator (default true). */
27
+ separator?: boolean;
28
+ class?: string;
29
+ children?: Snippet;
30
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
31
+
32
+ const space: Record<Size, string> = { sm: "pt-2 mt-2", md: "pt-3 mt-3", lg: "pt-4 mt-4" };
33
+ // Neutral default (secondary) → the shared surface border; any other variant → that accent.
34
+ const sepColor = $derived(
35
+ variant === "secondary"
36
+ ? "var(--ui-border-color)"
37
+ : `color-mix(in srgb, var(${variantToken[variant]}) var(--ui-tint-border), transparent)`,
38
+ );
39
+ </script>
40
+
41
+ <div
42
+ class="flex items-center justify-end gap-3 {separator
43
+ ? 'border-t ' + responsiveClasses(size, space)
44
+ : ''} {cls}"
45
+ style={separator ? `border-color: ${sepColor}` : ""}
46
+ {...rest}
47
+ >
48
+ {@render children?.()}
49
+ </div>
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import type { Size } from "../types/sizes.js";
4
+ import { type Responsive } from "../types/responsive.js";
5
+ import { type Variant } from "../types/variants.js";
6
+ type $$ComponentProps = {
7
+ variant?: Variant;
8
+ size?: Responsive<Size>;
9
+ /** Show the top separator (default true). */
10
+ separator?: boolean;
11
+ class?: string;
12
+ children?: Snippet;
13
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class">;
14
+ declare const CardFooter: import("svelte").Component<$$ComponentProps, {}, "">;
15
+ type CardFooter = ReturnType<typeof CardFooter>;
16
+ export default CardFooter;
@@ -0,0 +1,49 @@
1
+ <!--
2
+ /**
3
+ * CardHeader — the top section of a Card, with a bottom separator. It lives inside the Card's padding,
4
+ * so the separator is naturally inset. The separator is configurable HERE: `variant` sets its colour,
5
+ * `separator={false}` removes it, `size` sets the spacing around it. Lays out as a flex row
6
+ * (title left, actions right) by default; override via `class`.
7
+ */
8
+ -->
9
+ <script lang="ts">
10
+ import type { Snippet } from "svelte";
11
+ import type { HTMLAttributes } from "svelte/elements";
12
+ import type { Size } from "../types/sizes.js";
13
+ import { responsiveClasses, type Responsive } from "../types/responsive.js";
14
+ import { variantToken, type Variant } from "../types/variants.js";
15
+
16
+ let {
17
+ variant = "secondary",
18
+ size = "md",
19
+ separator = true,
20
+ class: cls = "",
21
+ children,
22
+ ...rest
23
+ }: {
24
+ variant?: Variant;
25
+ size?: Responsive<Size>;
26
+ /** Show the bottom separator (default true). */
27
+ separator?: boolean;
28
+ class?: string;
29
+ children?: Snippet;
30
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
31
+
32
+ const space: Record<Size, string> = { sm: "pb-2 mb-2", md: "pb-3 mb-3", lg: "pb-4 mb-4" };
33
+ // Neutral default (secondary) → the shared surface border; any other variant → that accent.
34
+ const sepColor = $derived(
35
+ variant === "secondary"
36
+ ? "var(--ui-border-color)"
37
+ : `color-mix(in srgb, var(${variantToken[variant]}) var(--ui-tint-border), transparent)`,
38
+ );
39
+ </script>
40
+
41
+ <div
42
+ class="flex items-center justify-between gap-3 {separator
43
+ ? 'border-b ' + responsiveClasses(size, space)
44
+ : ''} {cls}"
45
+ style={separator ? `border-color: ${sepColor}` : ""}
46
+ {...rest}
47
+ >
48
+ {@render children?.()}
49
+ </div>
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import type { Size } from "../types/sizes.js";
4
+ import { type Responsive } from "../types/responsive.js";
5
+ import { type Variant } from "../types/variants.js";
6
+ type $$ComponentProps = {
7
+ variant?: Variant;
8
+ size?: Responsive<Size>;
9
+ /** Show the bottom separator (default true). */
10
+ separator?: boolean;
11
+ class?: string;
12
+ children?: Snippet;
13
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class">;
14
+ declare const CardHeader: import("svelte").Component<$$ComponentProps, {}, "">;
15
+ type CardHeader = ReturnType<typeof CardHeader>;
16
+ export default CardHeader;