@delightstack/components 0.1.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 (195) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +136 -0
  3. package/SKILL.md +149 -0
  4. package/bin/agents.js +63 -0
  5. package/dist/actions/Alert.svelte +202 -0
  6. package/dist/actions/Alert.svelte.d.ts +36 -0
  7. package/dist/actions/Alert.svelte.d.ts.map +1 -0
  8. package/dist/actions/Button.svelte +1450 -0
  9. package/dist/actions/Button.svelte.d.ts +56 -0
  10. package/dist/actions/Button.svelte.d.ts.map +1 -0
  11. package/dist/actions/ButtonGroup.svelte +111 -0
  12. package/dist/actions/ButtonGroup.svelte.d.ts +41 -0
  13. package/dist/actions/ButtonGroup.svelte.d.ts.map +1 -0
  14. package/dist/actions/CommandPalette.svelte +939 -0
  15. package/dist/actions/CommandPalette.svelte.d.ts +37 -0
  16. package/dist/actions/CommandPalette.svelte.d.ts.map +1 -0
  17. package/dist/actions/ContextMenu.svelte +138 -0
  18. package/dist/actions/ContextMenu.svelte.d.ts +54 -0
  19. package/dist/actions/ContextMenu.svelte.d.ts.map +1 -0
  20. package/dist/actions/Modal.svelte +474 -0
  21. package/dist/actions/Modal.svelte.d.ts +28 -0
  22. package/dist/actions/Modal.svelte.d.ts.map +1 -0
  23. package/dist/actions/Popover.svelte +1214 -0
  24. package/dist/actions/Popover.svelte.d.ts +31 -0
  25. package/dist/actions/Popover.svelte.d.ts.map +1 -0
  26. package/dist/actions/Portal.svelte +80 -0
  27. package/dist/actions/Portal.svelte.d.ts +17 -0
  28. package/dist/actions/Portal.svelte.d.ts.map +1 -0
  29. package/dist/actions/ThemeToggle.svelte +345 -0
  30. package/dist/actions/ThemeToggle.svelte.d.ts +15 -0
  31. package/dist/actions/ThemeToggle.svelte.d.ts.map +1 -0
  32. package/dist/actions/index.d.ts +13 -0
  33. package/dist/actions/index.d.ts.map +1 -0
  34. package/dist/actions/index.js +10 -0
  35. package/dist/actions/scrollbar.d.ts +48 -0
  36. package/dist/actions/scrollbar.d.ts.map +1 -0
  37. package/dist/actions/scrollbar.js +404 -0
  38. package/dist/display/Accordion.svelte +586 -0
  39. package/dist/display/Accordion.svelte.d.ts +41 -0
  40. package/dist/display/Accordion.svelte.d.ts.map +1 -0
  41. package/dist/display/Avatar.svelte +527 -0
  42. package/dist/display/Avatar.svelte.d.ts +22 -0
  43. package/dist/display/Avatar.svelte.d.ts.map +1 -0
  44. package/dist/display/AvatarGroup.svelte +298 -0
  45. package/dist/display/AvatarGroup.svelte.d.ts +31 -0
  46. package/dist/display/AvatarGroup.svelte.d.ts.map +1 -0
  47. package/dist/display/Calendar.svelte +1366 -0
  48. package/dist/display/Calendar.svelte.d.ts +58 -0
  49. package/dist/display/Calendar.svelte.d.ts.map +1 -0
  50. package/dist/display/Chart.svelte +1426 -0
  51. package/dist/display/Chart.svelte.d.ts +35 -0
  52. package/dist/display/Chart.svelte.d.ts.map +1 -0
  53. package/dist/display/Code.svelte +780 -0
  54. package/dist/display/Code.svelte.d.ts +19 -0
  55. package/dist/display/Code.svelte.d.ts.map +1 -0
  56. package/dist/display/Comparison.svelte +686 -0
  57. package/dist/display/Comparison.svelte.d.ts +22 -0
  58. package/dist/display/Comparison.svelte.d.ts.map +1 -0
  59. package/dist/display/Counter.svelte +285 -0
  60. package/dist/display/Counter.svelte.d.ts +21 -0
  61. package/dist/display/Counter.svelte.d.ts.map +1 -0
  62. package/dist/display/Expand.svelte +48 -0
  63. package/dist/display/Expand.svelte.d.ts +9 -0
  64. package/dist/display/Expand.svelte.d.ts.map +1 -0
  65. package/dist/display/List.svelte +294 -0
  66. package/dist/display/List.svelte.d.ts +40 -0
  67. package/dist/display/List.svelte.d.ts.map +1 -0
  68. package/dist/display/ListContextReset.svelte +19 -0
  69. package/dist/display/ListContextReset.svelte.d.ts +7 -0
  70. package/dist/display/ListContextReset.svelte.d.ts.map +1 -0
  71. package/dist/display/ListItem.svelte +834 -0
  72. package/dist/display/ListItem.svelte.d.ts +22 -0
  73. package/dist/display/ListItem.svelte.d.ts.map +1 -0
  74. package/dist/display/QR.svelte +1193 -0
  75. package/dist/display/QR.svelte.d.ts +23 -0
  76. package/dist/display/QR.svelte.d.ts.map +1 -0
  77. package/dist/display/SplitPane.svelte +744 -0
  78. package/dist/display/SplitPane.svelte.d.ts +25 -0
  79. package/dist/display/SplitPane.svelte.d.ts.map +1 -0
  80. package/dist/display/Stat.svelte +439 -0
  81. package/dist/display/Stat.svelte.d.ts +24 -0
  82. package/dist/display/Stat.svelte.d.ts.map +1 -0
  83. package/dist/display/Table.svelte +4654 -0
  84. package/dist/display/Table.svelte.d.ts +249 -0
  85. package/dist/display/Table.svelte.d.ts.map +1 -0
  86. package/dist/display/TableCellEditor.svelte +935 -0
  87. package/dist/display/TableCellEditor.svelte.d.ts +58 -0
  88. package/dist/display/TableCellEditor.svelte.d.ts.map +1 -0
  89. package/dist/display/Timeline.svelte +1258 -0
  90. package/dist/display/Timeline.svelte.d.ts +43 -0
  91. package/dist/display/Timeline.svelte.d.ts.map +1 -0
  92. package/dist/display/Tree.svelte +1740 -0
  93. package/dist/display/Tree.svelte.d.ts +74 -0
  94. package/dist/display/Tree.svelte.d.ts.map +1 -0
  95. package/dist/display/Typewriter.svelte +338 -0
  96. package/dist/display/Typewriter.svelte.d.ts +22 -0
  97. package/dist/display/Typewriter.svelte.d.ts.map +1 -0
  98. package/dist/display/index.d.ts +24 -0
  99. package/dist/display/index.d.ts.map +1 -0
  100. package/dist/display/index.js +18 -0
  101. package/dist/feedback/Callout.svelte +529 -0
  102. package/dist/feedback/Callout.svelte.d.ts +24 -0
  103. package/dist/feedback/Callout.svelte.d.ts.map +1 -0
  104. package/dist/feedback/Confetti.svelte +631 -0
  105. package/dist/feedback/Confetti.svelte.d.ts +90 -0
  106. package/dist/feedback/Confetti.svelte.d.ts.map +1 -0
  107. package/dist/feedback/Progress.svelte +382 -0
  108. package/dist/feedback/Progress.svelte.d.ts +25 -0
  109. package/dist/feedback/Progress.svelte.d.ts.map +1 -0
  110. package/dist/feedback/Toast.svelte +967 -0
  111. package/dist/feedback/Toast.svelte.d.ts +54 -0
  112. package/dist/feedback/Toast.svelte.d.ts.map +1 -0
  113. package/dist/feedback/index.d.ts +7 -0
  114. package/dist/feedback/index.d.ts.map +1 -0
  115. package/dist/feedback/index.js +4 -0
  116. package/dist/form/Checkbox.svelte +449 -0
  117. package/dist/form/Checkbox.svelte.d.ts +27 -0
  118. package/dist/form/Checkbox.svelte.d.ts.map +1 -0
  119. package/dist/form/Fieldset.svelte +410 -0
  120. package/dist/form/Fieldset.svelte.d.ts +22 -0
  121. package/dist/form/Fieldset.svelte.d.ts.map +1 -0
  122. package/dist/form/FileUpload.svelte +934 -0
  123. package/dist/form/FileUpload.svelte.d.ts +41 -0
  124. package/dist/form/FileUpload.svelte.d.ts.map +1 -0
  125. package/dist/form/Form.svelte +530 -0
  126. package/dist/form/Form.svelte.d.ts +120 -0
  127. package/dist/form/Form.svelte.d.ts.map +1 -0
  128. package/dist/form/Input.svelte +2858 -0
  129. package/dist/form/Input.svelte.d.ts +66 -0
  130. package/dist/form/Input.svelte.d.ts.map +1 -0
  131. package/dist/form/Radio.svelte +507 -0
  132. package/dist/form/Radio.svelte.d.ts +39 -0
  133. package/dist/form/Radio.svelte.d.ts.map +1 -0
  134. package/dist/form/Range.svelte +912 -0
  135. package/dist/form/Range.svelte.d.ts +33 -0
  136. package/dist/form/Range.svelte.d.ts.map +1 -0
  137. package/dist/form/Rating.svelte +429 -0
  138. package/dist/form/Rating.svelte.d.ts +28 -0
  139. package/dist/form/Rating.svelte.d.ts.map +1 -0
  140. package/dist/form/Select.svelte +1933 -0
  141. package/dist/form/Select.svelte.d.ts +54 -0
  142. package/dist/form/Select.svelte.d.ts.map +1 -0
  143. package/dist/form/Toggle.svelte +645 -0
  144. package/dist/form/Toggle.svelte.d.ts +50 -0
  145. package/dist/form/Toggle.svelte.d.ts.map +1 -0
  146. package/dist/form/index.d.ts +15 -0
  147. package/dist/form/index.d.ts.map +1 -0
  148. package/dist/form/index.js +10 -0
  149. package/dist/index.d.ts +7 -0
  150. package/dist/index.d.ts.map +1 -0
  151. package/dist/index.js +6 -0
  152. package/dist/layout/README.md +172 -0
  153. package/dist/media/Carousel.svelte +2424 -0
  154. package/dist/media/Carousel.svelte.d.ts +47 -0
  155. package/dist/media/Carousel.svelte.d.ts.map +1 -0
  156. package/dist/media/Gallery.svelte +2881 -0
  157. package/dist/media/Gallery.svelte.d.ts +82 -0
  158. package/dist/media/Gallery.svelte.d.ts.map +1 -0
  159. package/dist/media/Image.svelte +389 -0
  160. package/dist/media/Image.svelte.d.ts +33 -0
  161. package/dist/media/Image.svelte.d.ts.map +1 -0
  162. package/dist/media/PDF.svelte +1793 -0
  163. package/dist/media/PDF.svelte.d.ts +44 -0
  164. package/dist/media/PDF.svelte.d.ts.map +1 -0
  165. package/dist/media/Panorama.svelte +1391 -0
  166. package/dist/media/Panorama.svelte.d.ts +47 -0
  167. package/dist/media/Panorama.svelte.d.ts.map +1 -0
  168. package/dist/media/Video.svelte +2501 -0
  169. package/dist/media/Video.svelte.d.ts +58 -0
  170. package/dist/media/Video.svelte.d.ts.map +1 -0
  171. package/dist/media/carousel.d.ts +211 -0
  172. package/dist/media/carousel.d.ts.map +1 -0
  173. package/dist/media/carousel.js +408 -0
  174. package/dist/media/index.d.ts +11 -0
  175. package/dist/media/index.d.ts.map +1 -0
  176. package/dist/media/index.js +5 -0
  177. package/dist/navigation/BottomSheet.svelte +636 -0
  178. package/dist/navigation/BottomSheet.svelte.d.ts +27 -0
  179. package/dist/navigation/BottomSheet.svelte.d.ts.map +1 -0
  180. package/dist/navigation/Breadcrumbs.svelte +611 -0
  181. package/dist/navigation/Breadcrumbs.svelte.d.ts +28 -0
  182. package/dist/navigation/Breadcrumbs.svelte.d.ts.map +1 -0
  183. package/dist/navigation/Pagination.svelte +641 -0
  184. package/dist/navigation/Pagination.svelte.d.ts +27 -0
  185. package/dist/navigation/Pagination.svelte.d.ts.map +1 -0
  186. package/dist/navigation/Steps.svelte +965 -0
  187. package/dist/navigation/Steps.svelte.d.ts +43 -0
  188. package/dist/navigation/Steps.svelte.d.ts.map +1 -0
  189. package/dist/navigation/Tabs.svelte +698 -0
  190. package/dist/navigation/Tabs.svelte.d.ts +41 -0
  191. package/dist/navigation/Tabs.svelte.d.ts.map +1 -0
  192. package/dist/navigation/index.d.ts +8 -0
  193. package/dist/navigation/index.d.ts.map +1 -0
  194. package/dist/navigation/index.js +5 -0
  195. package/package.json +139 -0
@@ -0,0 +1,33 @@
1
+ declare const Range: import("svelte").Component<{
2
+ value?: number | [number, number];
3
+ min?: number;
4
+ max?: number;
5
+ step?: number;
6
+ range?: boolean;
7
+ disabled?: boolean;
8
+ size?: "0" | "1" | "2" | "3";
9
+ show_value?: boolean;
10
+ show_ticks?: boolean;
11
+ tick_labels?: string[] | undefined;
12
+ format_value?: ((n: number) => string) | undefined;
13
+ label?: string | undefined;
14
+ tooltip?: string | undefined;
15
+ dense?: boolean;
16
+ comfortable?: boolean;
17
+ vertical?: boolean;
18
+ id?: string;
19
+ name?: string | undefined;
20
+ error?: string;
21
+ parse?: ((value: unknown) => unknown) | undefined;
22
+ aria_label?: string | undefined;
23
+ class?: string;
24
+ onchange?: ((detail: {
25
+ value: number | [number, number];
26
+ }) => void) | undefined;
27
+ oninput?: ((detail: {
28
+ value: number | [number, number];
29
+ }) => void) | undefined;
30
+ }, {}, "value">;
31
+ type Range = ReturnType<typeof Range>;
32
+ export default Range;
33
+ //# sourceMappingURL=Range.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Range.svelte.d.ts","sourceRoot":"","sources":["../../src/form/Range.svelte.ts"],"names":[],"mappings":"AAqdA,QAAA,MAAM,KAAK;YAzcsE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;UAAQ,MAAM;UAAQ,MAAM;WAAS,MAAM;YAAU,OAAO;eAAa,OAAO;WAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;iBAAe,OAAO;iBAAe,OAAO;kBAAgB,MAAM,EAAE,GAAG,SAAS;mBAAiB,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS;YAAU,MAAM,GAAG,SAAS;cAAY,MAAM,GAAG,SAAS;YAAU,OAAO;kBAAgB,OAAO;eAAa,OAAO;;WAA6B,MAAM,GAAG,SAAS;YAAU,MAAM;YAAU,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,SAAS;iBAAe,MAAM,GAAG,SAAS;YAAU,MAAM;eAAe,CAAC,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC,GACvrB,SAAS;cAAc,CAAC,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC,GAC/E,SAAS;eAucqC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -0,0 +1,429 @@
1
+ <script lang="ts">
2
+ import { tooltip } from '@delightstack/utilities';
3
+ import { getContext } from 'svelte';
4
+ import type { FormContext } from './Form.svelte';
5
+
6
+ const propId = $props.id();
7
+ let {
8
+ /** The current rating value */
9
+ value = $bindable(0),
10
+
11
+ /** The maximum number of stars */
12
+ max = 5,
13
+
14
+ /** The rating precision: 1 for whole stars, 0.5 for half-star */
15
+ precision = 1 as 0.5 | 1,
16
+
17
+ /** The size of the stars. 0=16px, 1=24px, 2=32px, 3=40px */
18
+ size = '1' as '0' | '1' | '2' | '3',
19
+
20
+ /** Whether the rating is read-only (display only) */
21
+ readonly = false,
22
+
23
+ /** Whether the rating is disabled */
24
+ disabled = false,
25
+
26
+ /** The fill color of active stars */
27
+ color = '',
28
+
29
+ /** Whether to show the numeric value next to the stars */
30
+ show_value = false,
31
+
32
+ /** Whether clicking the current value clears the rating */
33
+ clearable = false,
34
+
35
+ /** The tooltip message shown on hover */
36
+ tooltip: tooltip_message = '',
37
+
38
+ /** Whether to display in a condensed view */
39
+ dense = false,
40
+
41
+ /** Whether to display in an expanded view */
42
+ comfortable = false,
43
+
44
+ /** The ID of the rating element */
45
+ id = propId,
46
+
47
+ /** The name attribute for the hidden input */
48
+ name = '',
49
+
50
+ /** Error message shown below the stars */
51
+ error = '',
52
+
53
+ /** Parses & validates the value (e.g. a database table form field's
54
+ * `parse`). Inside a Form it is registered with the form, which runs it
55
+ * on the form's validation timing. */
56
+ parse = undefined as ((value: unknown) => unknown) | undefined,
57
+
58
+ /** Specifies a custom class name */
59
+ class: class_name = '',
60
+
61
+ /** Called when the rating value changes */
62
+ onchange = undefined as ((detail: { value: number }) => void) | undefined,
63
+
64
+ /** Called when hovering over a star */
65
+ onhover = undefined as ((detail: { value: number }) => void) | undefined,
66
+ } = $props();
67
+
68
+ const sizes: Record<string, number> = { '0': 16, '1': 24, '2': 32, '3': 40 };
69
+ const px = $derived(sizes[size] ?? 24);
70
+
71
+ /* ------------------------------------------------------------------ */
72
+ /* Form context integration */
73
+ /* ------------------------------------------------------------------ */
74
+
75
+ const form_ctx = getContext<FormContext | undefined>('form');
76
+ let root_element = $state<HTMLElement | undefined>(undefined);
77
+
78
+ /** Disabled merges the parent form's disabled/submitting state */
79
+ const effectively_disabled = $derived(disabled || (form_ctx?.disabled ?? false));
80
+
81
+ /** Error from the local prop or the parent form context */
82
+ const resolved_error = $derived.by(() => {
83
+ if (error) return error;
84
+ if (form_ctx && name && form_ctx.errors[name]) return form_ctx.errors[name];
85
+ return '';
86
+ });
87
+
88
+ // Register with a parent Form (focus-on-error target + field validator).
89
+ $effect(() => {
90
+ if (!form_ctx || !name) return;
91
+ if (root_element) form_ctx.register(name, root_element, parse);
92
+ return () => form_ctx.unregister(name);
93
+ });
94
+
95
+ // Context-driven: drive the rating value from the form data when inside a
96
+ // Form with a name — no bind:value needed.
97
+ $effect(() => {
98
+ if (!form_ctx || !name) return;
99
+ const ctx_value = form_ctx.getValue(name);
100
+ const next = ctx_value == null ? 0 : Number(ctx_value);
101
+ if (!Number.isNaN(next) && next !== value) value = next;
102
+ });
103
+
104
+ /** Writes the value into the form data, marks touched, and emits onchange */
105
+ function emitChange() {
106
+ if (form_ctx && name) {
107
+ form_ctx.setValue(name, value);
108
+ form_ctx.setTouched(name);
109
+ }
110
+ onchange?.({ value: value });
111
+ }
112
+
113
+ let hoverValue = $state(0);
114
+ let isHovering = $state(false);
115
+ let bounceStar = $state(-1);
116
+
117
+ const displayValue = $derived(isHovering ? hoverValue : value);
118
+ const isInteractive = $derived(!readonly && !effectively_disabled);
119
+
120
+ // Star path (5-pointed star)
121
+ const starPath =
122
+ 'M12 2l2.93 6.26L22 9.27l-5 4.87L18.18 22 12 18.27 5.82 22 7 14.14l-5-4.87 7.07-1.01L12 2z';
123
+
124
+ function starValues(index: number): { full: number; half: number } {
125
+ return {
126
+ full: index + 1,
127
+ half: index + 0.5,
128
+ };
129
+ }
130
+
131
+ function selectValue(newValue: number) {
132
+ if (!isInteractive) return;
133
+ if (clearable && newValue === value) {
134
+ value = 0;
135
+ } else {
136
+ value = newValue;
137
+ }
138
+ bounceStar = newValue;
139
+ setTimeout(() => (bounceStar = -1), 300);
140
+ emitChange();
141
+ }
142
+
143
+ function hoverStar(newValue: number) {
144
+ if (!isInteractive) return;
145
+ hoverValue = newValue;
146
+ isHovering = true;
147
+ onhover?.({ value: newValue });
148
+ }
149
+
150
+ function hoverEnd() {
151
+ isHovering = false;
152
+ hoverValue = 0;
153
+ }
154
+
155
+ function onKeyDown(e: KeyboardEvent) {
156
+ if (!isInteractive) return;
157
+ const step = precision === 0.5 ? 0.5 : 1;
158
+ if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {
159
+ e.preventDefault();
160
+ const next = Math.min(max, value + step);
161
+ value = next;
162
+ emitChange();
163
+ } else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {
164
+ e.preventDefault();
165
+ const next = Math.max(0, value - step);
166
+ value = next;
167
+ emitChange();
168
+ } else if (e.key === 'Home') {
169
+ e.preventDefault();
170
+ value = 0;
171
+ emitChange();
172
+ } else if (e.key === 'End') {
173
+ e.preventDefault();
174
+ value = max;
175
+ emitChange();
176
+ }
177
+ }
178
+
179
+ function getStarFill(index: number): 'full' | 'half' | 'empty' {
180
+ const starNum = index + 1;
181
+ if (displayValue >= starNum) return 'full';
182
+ if (displayValue >= starNum - 0.5 && precision === 0.5) return 'half';
183
+ return 'empty';
184
+ }
185
+ </script>
186
+
187
+ <div class="rating-field" class:has-error={!!resolved_error}>
188
+ <div
189
+ bind:this={root_element}
190
+ class={['rating', class_name].filter(Boolean).join(' ')}
191
+ class:readonly
192
+ class:disabled={effectively_disabled}
193
+ class:dense
194
+ class:comfortable
195
+ role="slider"
196
+ aria-valuenow={value}
197
+ aria-valuemin={0}
198
+ aria-valuemax={max}
199
+ aria-label="Rating"
200
+ tabindex={isInteractive ? 0 : -1}
201
+ onkeydown={onKeyDown}
202
+ onmouseleave={hoverEnd}
203
+ {@attach tooltip(tooltip_message)}
204
+ style:font-size={`var(--control-font-${size})`}
205
+ {id}>
206
+ <!-- Hidden native input for form submission -->
207
+ <input type="hidden" {name} value={value.toString()} />
208
+
209
+ <div class="stars" style:--star-color={color || null}>
210
+ {#each { length: max } as _, i}
211
+ {@const fill = getStarFill(i)}
212
+ {@const vals = starValues(i)}
213
+ {@const isBouncing = bounceStar === vals.full || bounceStar === vals.half}
214
+ <div
215
+ class="star-wrapper"
216
+ class:bouncing={isBouncing}
217
+ style:width="{px}px"
218
+ style:height="{px}px">
219
+ {#if precision === 0.5 && isInteractive}
220
+ <!-- Left half (0.5) -->
221
+ <button
222
+ type="button"
223
+ class="star-half left"
224
+ tabindex={-1}
225
+ disabled={effectively_disabled}
226
+ aria-hidden="true"
227
+ onclick={() => selectValue(vals.half)}
228
+ onmouseenter={() => hoverStar(vals.half)}>
229
+ <svg
230
+ viewBox="0 0 24 24"
231
+ width={px}
232
+ height={px}
233
+ aria-hidden="true"
234
+ style="clip-path: inset(0 50% 0 0)">
235
+ <path
236
+ d={starPath}
237
+ class="star-path"
238
+ class:filled={fill === 'full' || fill === 'half'} />
239
+ </svg>
240
+ </button>
241
+ <!-- Right half (1.0) -->
242
+ <button
243
+ type="button"
244
+ class="star-half right"
245
+ tabindex={-1}
246
+ disabled={effectively_disabled}
247
+ aria-hidden="true"
248
+ onclick={() => selectValue(vals.full)}
249
+ onmouseenter={() => hoverStar(vals.full)}>
250
+ <svg
251
+ viewBox="0 0 24 24"
252
+ width={px}
253
+ height={px}
254
+ aria-hidden="true"
255
+ style="clip-path: inset(0 0 0 50%)">
256
+ <path d={starPath} class="star-path" class:filled={fill === 'full'} />
257
+ </svg>
258
+ </button>
259
+ {:else}
260
+ <!-- Full star button -->
261
+ <button
262
+ type="button"
263
+ class="star-full"
264
+ tabindex={-1}
265
+ disabled={effectively_disabled || readonly}
266
+ aria-hidden="true"
267
+ onclick={() => selectValue(vals.full)}
268
+ onmouseenter={() => hoverStar(vals.full)}>
269
+ <svg viewBox="0 0 24 24" width={px} height={px} aria-hidden="true">
270
+ <path
271
+ d={starPath}
272
+ class="star-path"
273
+ class:filled={fill === 'full' || fill === 'half'} />
274
+ </svg>
275
+ </button>
276
+ {/if}
277
+ </div>
278
+ {/each}
279
+ </div>
280
+
281
+ {#if show_value}
282
+ <span class="value-display">{value}</span>
283
+ {/if}
284
+ </div>
285
+
286
+ {#if resolved_error}
287
+ <span class="error-text">{resolved_error}</span>
288
+ {/if}
289
+ </div>
290
+
291
+ <style>
292
+ .rating-field {
293
+ display: inline-flex;
294
+ flex-direction: column;
295
+ align-items: flex-start;
296
+ gap: 0.25em;
297
+
298
+ .error-text {
299
+ font-size: 0.8em;
300
+ color: var(--color-error, #d32f2f);
301
+ }
302
+ }
303
+
304
+ .rating {
305
+ display: inline-flex;
306
+ align-items: center;
307
+ gap: 0.5em;
308
+ outline: none;
309
+
310
+ &.dense {
311
+ gap: 0.25em;
312
+ }
313
+ &.comfortable {
314
+ gap: 0.75em;
315
+ }
316
+ &.disabled {
317
+ opacity: 0.5;
318
+ pointer-events: none;
319
+ }
320
+ &.readonly {
321
+ pointer-events: none;
322
+ }
323
+
324
+ &:focus-visible .stars {
325
+ outline: 2px solid var(--color-text, currentColor);
326
+ outline-offset: 4px;
327
+ border-radius: 4px;
328
+ }
329
+ }
330
+
331
+ .stars {
332
+ --star-active: var(--star-color, #f59e0b);
333
+ /* Empty stars use the neutral border gray (absolute lightness: light in
334
+ light mode, dark in dark mode) rather than --color-text-disabled, which
335
+ is a *relative* nudge of currentColor — against dark page text that
336
+ resolved to a near-black fill, making empty stars look selected. */
337
+ --star-inactive: light-dark(
338
+ var(--color-border, #d4d4d8),
339
+ var(--color-border, #52525b)
340
+ );
341
+ display: inline-flex;
342
+ align-items: center;
343
+ gap: 2px;
344
+ }
345
+
346
+ .star-wrapper {
347
+ position: relative;
348
+ display: inline-flex;
349
+ flex-shrink: 0;
350
+ perspective: 100px;
351
+
352
+ &.bouncing {
353
+ animation: bounce 300ms cubic-bezier(0.4, 0, 0.2, 1);
354
+ }
355
+ }
356
+
357
+ .star-full,
358
+ .star-half {
359
+ position: absolute;
360
+ top: 0;
361
+ left: 0;
362
+ width: 100%;
363
+ height: 100%;
364
+ padding: 0;
365
+ margin: 0;
366
+ border: none;
367
+ background: none;
368
+ cursor: pointer;
369
+ display: flex;
370
+ align-items: center;
371
+ justify-content: center;
372
+ box-shadow: none;
373
+ outline: none;
374
+ -webkit-tap-highlight-color: transparent;
375
+ transition: translate 200ms ease;
376
+
377
+ &:active:not(:disabled) {
378
+ translate: 0px 1px clamp(-20px, calc(0.2em - 17px), -2px);
379
+ }
380
+
381
+ &:disabled {
382
+ cursor: default;
383
+ }
384
+
385
+ svg {
386
+ display: block;
387
+ pointer-events: none;
388
+ }
389
+ }
390
+
391
+ .star-half.left {
392
+ clip-path: inset(0 50% 0 0);
393
+ z-index: 1;
394
+ }
395
+
396
+ .star-half.right {
397
+ clip-path: inset(0 0 0 50%);
398
+ }
399
+
400
+ .star-path {
401
+ fill: var(--star-inactive);
402
+ stroke: none;
403
+ transition: fill 150ms ease;
404
+
405
+ &.filled {
406
+ fill: var(--star-active);
407
+ }
408
+ }
409
+
410
+ .value-display {
411
+ font-size: 0.9em;
412
+ font-weight: 600;
413
+ color: var(--color-text, inherit);
414
+ min-width: 1.5em;
415
+ text-align: center;
416
+ }
417
+
418
+ @keyframes bounce {
419
+ 0% {
420
+ transform: scale(1);
421
+ }
422
+ 40% {
423
+ transform: scale(1.25);
424
+ }
425
+ 100% {
426
+ transform: scale(1);
427
+ }
428
+ }
429
+ </style>
@@ -0,0 +1,28 @@
1
+ declare const Rating: import("svelte").Component<{
2
+ value?: number;
3
+ max?: number;
4
+ precision?: 0.5 | 1;
5
+ size?: "0" | "1" | "2" | "3";
6
+ readonly?: boolean;
7
+ disabled?: boolean;
8
+ color?: string;
9
+ show_value?: boolean;
10
+ clearable?: boolean;
11
+ tooltip?: string;
12
+ dense?: boolean;
13
+ comfortable?: boolean;
14
+ id?: string;
15
+ name?: string;
16
+ error?: string;
17
+ parse?: ((value: unknown) => unknown) | undefined;
18
+ class?: string;
19
+ onchange?: ((detail: {
20
+ value: number;
21
+ }) => void) | undefined;
22
+ onhover?: ((detail: {
23
+ value: number;
24
+ }) => void) | undefined;
25
+ }, {}, "value">;
26
+ type Rating = ReturnType<typeof Rating>;
27
+ export default Rating;
28
+ //# sourceMappingURL=Rating.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Rating.svelte.d.ts","sourceRoot":"","sources":["../../src/form/Rating.svelte.ts"],"names":[],"mappings":"AAmPA,QAAA,MAAM,MAAM;YAvOqE,MAAM;UAAQ,MAAM;gBAAc,GAAG,GAAG,CAAC;WAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;eAAa,OAAO;eAAa,OAAO;YAAU,MAAM;iBAAe,OAAO;gBAAc,OAAO;cAAY,MAAM;YAAU,OAAO;kBAAgB,OAAO;;WAA6B,MAAM;YAAU,MAAM;YAAU,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,SAAS;YAAU,MAAM;eAAa,CAAC,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,SAAS;cAAY,CAAC,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,SAAS;eAuOlf,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}