@aspect-ops/exon-ui 0.0.3 → 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 (65) hide show
  1. package/README.md +793 -43
  2. package/dist/components/Accordion/Accordion.svelte +79 -0
  3. package/dist/components/Accordion/Accordion.svelte.d.ts +10 -0
  4. package/dist/components/Accordion/AccordionItem.svelte +198 -0
  5. package/dist/components/Accordion/AccordionItem.svelte.d.ts +10 -0
  6. package/dist/components/Accordion/index.d.ts +2 -0
  7. package/dist/components/Accordion/index.js +2 -0
  8. package/dist/components/Carousel/Carousel.svelte +454 -0
  9. package/dist/components/Carousel/Carousel.svelte.d.ts +14 -0
  10. package/dist/components/Carousel/CarouselSlide.svelte +22 -0
  11. package/dist/components/Carousel/CarouselSlide.svelte.d.ts +7 -0
  12. package/dist/components/Carousel/index.d.ts +2 -0
  13. package/dist/components/Carousel/index.js +2 -0
  14. package/dist/components/Chip/Chip.svelte +461 -0
  15. package/dist/components/Chip/Chip.svelte.d.ts +17 -0
  16. package/dist/components/Chip/ChipGroup.svelte +76 -0
  17. package/dist/components/Chip/ChipGroup.svelte.d.ts +9 -0
  18. package/dist/components/Chip/index.d.ts +2 -0
  19. package/dist/components/Chip/index.js +2 -0
  20. package/dist/components/DatePicker/DatePicker.svelte +746 -0
  21. package/dist/components/DatePicker/DatePicker.svelte.d.ts +19 -0
  22. package/dist/components/DatePicker/index.d.ts +1 -0
  23. package/dist/components/DatePicker/index.js +1 -0
  24. package/dist/components/FileUpload/FileUpload.svelte +484 -0
  25. package/dist/components/FileUpload/FileUpload.svelte.d.ts +16 -0
  26. package/dist/components/FileUpload/index.d.ts +1 -0
  27. package/dist/components/FileUpload/index.js +1 -0
  28. package/dist/components/Image/Image.svelte +223 -0
  29. package/dist/components/Image/Image.svelte.d.ts +19 -0
  30. package/dist/components/Image/index.d.ts +1 -0
  31. package/dist/components/Image/index.js +1 -0
  32. package/dist/components/OTPInput/OTPInput.svelte +312 -0
  33. package/dist/components/OTPInput/OTPInput.svelte.d.ts +57 -0
  34. package/dist/components/OTPInput/index.d.ts +1 -0
  35. package/dist/components/OTPInput/index.js +1 -0
  36. package/dist/components/Rating/Rating.svelte +316 -0
  37. package/dist/components/Rating/Rating.svelte.d.ts +16 -0
  38. package/dist/components/Rating/index.d.ts +1 -0
  39. package/dist/components/Rating/index.js +1 -0
  40. package/dist/components/SearchInput/SearchInput.svelte +480 -0
  41. package/dist/components/SearchInput/SearchInput.svelte.d.ts +22 -0
  42. package/dist/components/SearchInput/index.d.ts +1 -0
  43. package/dist/components/SearchInput/index.js +1 -0
  44. package/dist/components/Slider/Slider.svelte +324 -0
  45. package/dist/components/Slider/Slider.svelte.d.ts +14 -0
  46. package/dist/components/Slider/index.d.ts +1 -0
  47. package/dist/components/Slider/index.js +1 -0
  48. package/dist/components/Stepper/Stepper.svelte +100 -0
  49. package/dist/components/Stepper/Stepper.svelte.d.ts +11 -0
  50. package/dist/components/Stepper/StepperStep.svelte +391 -0
  51. package/dist/components/Stepper/StepperStep.svelte.d.ts +13 -0
  52. package/dist/components/Stepper/index.d.ts +2 -0
  53. package/dist/components/Stepper/index.js +2 -0
  54. package/dist/components/TimePicker/TimePicker.svelte +803 -0
  55. package/dist/components/TimePicker/TimePicker.svelte.d.ts +17 -0
  56. package/dist/components/TimePicker/index.d.ts +1 -0
  57. package/dist/components/TimePicker/index.js +1 -0
  58. package/dist/index.d.ts +10 -1
  59. package/dist/index.js +9 -0
  60. package/dist/types/data-display.d.ts +68 -0
  61. package/dist/types/index.d.ts +3 -2
  62. package/dist/types/input.d.ts +67 -0
  63. package/dist/types/input.js +2 -0
  64. package/dist/types/navigation.d.ts +15 -0
  65. package/package.json +1 -1
@@ -0,0 +1,316 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ value?: number;
4
+ max?: number;
5
+ allowHalf?: boolean;
6
+ readonly?: boolean;
7
+ disabled?: boolean;
8
+ size?: 'sm' | 'md' | 'lg';
9
+ color?: string;
10
+ emptyColor?: string;
11
+ showValue?: boolean;
12
+ class?: string;
13
+ onchange?: (value: number) => void;
14
+ }
15
+
16
+ let {
17
+ value = $bindable(0),
18
+ max = 5,
19
+ allowHalf = false,
20
+ readonly = false,
21
+ disabled = false,
22
+ size = 'md',
23
+ color,
24
+ emptyColor,
25
+ showValue = false,
26
+ class: className = '',
27
+ onchange
28
+ }: Props = $props();
29
+
30
+ let hoverValue = $state<number | null>(null);
31
+ let containerRef: HTMLDivElement | null = $state(null);
32
+
33
+ const displayValue = $derived(hoverValue ?? value);
34
+
35
+ // Size mapping for star dimensions
36
+ const sizeMap = {
37
+ sm: '20px',
38
+ md: '24px',
39
+ lg: '32px'
40
+ };
41
+
42
+ // Calculate star state (filled, half, or empty)
43
+ function getStarState(index: number): 'filled' | 'half' | 'empty' {
44
+ const starNumber = index + 1;
45
+ if (displayValue >= starNumber) return 'filled';
46
+ if (allowHalf && displayValue >= starNumber - 0.5) return 'half';
47
+ return 'empty';
48
+ }
49
+
50
+ // Handle star click
51
+ function handleStarClick(index: number, e: MouseEvent) {
52
+ if (readonly || disabled) return;
53
+
54
+ const star = e.currentTarget as HTMLElement;
55
+ const rect = star.getBoundingClientRect();
56
+ const clickX = e.clientX - rect.left;
57
+ const isLeftHalf = clickX < rect.width / 2;
58
+
59
+ let newValue: number;
60
+ if (allowHalf && isLeftHalf) {
61
+ newValue = index + 0.5;
62
+ } else {
63
+ newValue = index + 1;
64
+ }
65
+
66
+ // Allow clicking same value to reset to 0
67
+ if (newValue === value) {
68
+ newValue = 0;
69
+ }
70
+
71
+ value = newValue;
72
+ onchange?.(newValue);
73
+ }
74
+
75
+ // Handle hover
76
+ function handleStarHover(index: number, e: MouseEvent) {
77
+ if (readonly || disabled) return;
78
+
79
+ const star = e.currentTarget as HTMLElement;
80
+ const rect = star.getBoundingClientRect();
81
+ const hoverX = e.clientX - rect.left;
82
+ const isLeftHalf = hoverX < rect.width / 2;
83
+
84
+ if (allowHalf && isLeftHalf) {
85
+ hoverValue = index + 0.5;
86
+ } else {
87
+ hoverValue = index + 1;
88
+ }
89
+ }
90
+
91
+ // Clear hover
92
+ function handleMouseLeave() {
93
+ hoverValue = null;
94
+ }
95
+
96
+ // Keyboard navigation
97
+ function handleKeyDown(e: KeyboardEvent) {
98
+ if (readonly || disabled) return;
99
+
100
+ let newValue = value;
101
+ const step = allowHalf ? 0.5 : 1;
102
+
103
+ switch (e.key) {
104
+ case 'ArrowRight':
105
+ case 'ArrowUp':
106
+ e.preventDefault();
107
+ newValue = Math.min(max, value + step);
108
+ break;
109
+ case 'ArrowLeft':
110
+ case 'ArrowDown':
111
+ e.preventDefault();
112
+ newValue = Math.max(0, value - step);
113
+ break;
114
+ case 'Home':
115
+ e.preventDefault();
116
+ newValue = 0;
117
+ break;
118
+ case 'End':
119
+ e.preventDefault();
120
+ newValue = max;
121
+ break;
122
+ default:
123
+ return;
124
+ }
125
+
126
+ if (newValue !== value) {
127
+ value = newValue;
128
+ onchange?.(newValue);
129
+ }
130
+ }
131
+
132
+ // Generate array of star indices
133
+ const stars = $derived(Array.from({ length: max }, (_, i) => i));
134
+
135
+ // ARIA label
136
+ const ariaLabel = $derived(`Rating: ${value} out of ${max} stars`);
137
+ </script>
138
+
139
+ <div
140
+ bind:this={containerRef}
141
+ class="rating rating--{size} {className}"
142
+ class:rating--readonly={readonly}
143
+ class:rating--disabled={disabled}
144
+ role="slider"
145
+ aria-label={ariaLabel}
146
+ aria-valuemin={0}
147
+ aria-valuemax={max}
148
+ aria-valuenow={value}
149
+ aria-readonly={readonly}
150
+ aria-disabled={disabled}
151
+ tabindex={readonly || disabled ? -1 : 0}
152
+ onkeydown={handleKeyDown}
153
+ onmouseleave={handleMouseLeave}
154
+ >
155
+ <div class="rating-stars">
156
+ {#each stars as index (index)}
157
+ {@const state = getStarState(index)}
158
+ <div
159
+ class="rating-star"
160
+ class:rating-star--filled={state === 'filled'}
161
+ class:rating-star--half={state === 'half'}
162
+ class:rating-star--empty={state === 'empty'}
163
+ onclick={(e) => handleStarClick(index, e)}
164
+ onmousemove={(e) => handleStarHover(index, e)}
165
+ role="presentation"
166
+ style:--star-color={color}
167
+ style:--star-empty-color={emptyColor}
168
+ >
169
+ {#if state === 'filled'}
170
+ <!-- Filled star -->
171
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
172
+ <path
173
+ d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
174
+ />
175
+ </svg>
176
+ {:else if state === 'half'}
177
+ <!-- Half star -->
178
+ <svg viewBox="0 0 24 24" aria-hidden="true" class="rating-star-half">
179
+ <defs>
180
+ <linearGradient id="half-{index}">
181
+ <stop offset="50%" stop-color="currentColor" />
182
+ <stop offset="50%" stop-color="transparent" />
183
+ </linearGradient>
184
+ </defs>
185
+ <path
186
+ d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
187
+ fill="url(#half-{index})"
188
+ stroke="currentColor"
189
+ stroke-width="1.5"
190
+ />
191
+ </svg>
192
+ {:else}
193
+ <!-- Empty star -->
194
+ <svg
195
+ viewBox="0 0 24 24"
196
+ fill="none"
197
+ stroke="currentColor"
198
+ stroke-width="2"
199
+ aria-hidden="true"
200
+ >
201
+ <path
202
+ d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
203
+ />
204
+ </svg>
205
+ {/if}
206
+ </div>
207
+ {/each}
208
+ </div>
209
+
210
+ {#if showValue}
211
+ <div class="rating-value" aria-hidden="true">
212
+ {value.toFixed(allowHalf ? 1 : 0)}
213
+ </div>
214
+ {/if}
215
+ </div>
216
+
217
+ <style>
218
+ .rating {
219
+ display: inline-flex;
220
+ align-items: center;
221
+ gap: var(--space-xs, 0.25rem);
222
+ outline: none;
223
+ }
224
+
225
+ .rating:focus-visible {
226
+ outline: 2px solid var(--color-primary, #0090ff);
227
+ outline-offset: 4px;
228
+ border-radius: var(--radius-sm, 0.25rem);
229
+ }
230
+
231
+ .rating--disabled {
232
+ opacity: 0.5;
233
+ cursor: not-allowed;
234
+ }
235
+
236
+ .rating-stars {
237
+ display: inline-flex;
238
+ gap: var(--space-xs, 0.25rem);
239
+ }
240
+
241
+ .rating-star {
242
+ position: relative;
243
+ display: inline-flex;
244
+ align-items: center;
245
+ justify-content: center;
246
+ cursor: pointer;
247
+ transition:
248
+ transform var(--transition-fast, 150ms ease),
249
+ color var(--transition-fast, 150ms ease);
250
+ -webkit-tap-highlight-color: transparent;
251
+
252
+ /* Touch target */
253
+ min-width: var(--touch-target-min, 44px);
254
+ min-height: var(--touch-target-min, 44px);
255
+ }
256
+
257
+ .rating--readonly .rating-star,
258
+ .rating--disabled .rating-star {
259
+ cursor: default;
260
+ }
261
+
262
+ .rating-star svg {
263
+ display: block;
264
+ width: var(--star-size, 24px);
265
+ height: var(--star-size, 24px);
266
+ pointer-events: none;
267
+ }
268
+
269
+ /* Size variants */
270
+ .rating--sm {
271
+ --star-size: 20px;
272
+ }
273
+
274
+ .rating--md {
275
+ --star-size: 24px;
276
+ }
277
+
278
+ .rating--lg {
279
+ --star-size: 32px;
280
+ }
281
+
282
+ /* Star states */
283
+ .rating-star--filled {
284
+ color: var(--star-color, var(--color-warning, #ffc107));
285
+ }
286
+
287
+ .rating-star--half {
288
+ color: var(--star-color, var(--color-warning, #ffc107));
289
+ }
290
+
291
+ .rating-star--half path {
292
+ stroke: var(--star-empty-color, var(--color-border, #d9d9d9));
293
+ }
294
+
295
+ .rating-star--empty {
296
+ color: var(--star-empty-color, var(--color-border, #d9d9d9));
297
+ }
298
+
299
+ /* Hover effects - only when not readonly/disabled */
300
+ .rating:not(.rating--readonly):not(.rating--disabled) .rating-star:hover {
301
+ transform: scale(1.15);
302
+ }
303
+
304
+ .rating:not(.rating--readonly):not(.rating--disabled) .rating-star:active {
305
+ transform: scale(1.05);
306
+ }
307
+
308
+ /* Value display */
309
+ .rating-value {
310
+ margin-left: var(--space-xs, 0.25rem);
311
+ font-size: var(--text-sm, 0.875rem);
312
+ font-weight: var(--font-medium, 500);
313
+ color: var(--color-text-secondary, #666666);
314
+ line-height: 1;
315
+ }
316
+ </style>
@@ -0,0 +1,16 @@
1
+ interface Props {
2
+ value?: number;
3
+ max?: number;
4
+ allowHalf?: boolean;
5
+ readonly?: boolean;
6
+ disabled?: boolean;
7
+ size?: 'sm' | 'md' | 'lg';
8
+ color?: string;
9
+ emptyColor?: string;
10
+ showValue?: boolean;
11
+ class?: string;
12
+ onchange?: (value: number) => void;
13
+ }
14
+ declare const Rating: import("svelte").Component<Props, {}, "value">;
15
+ type Rating = ReturnType<typeof Rating>;
16
+ export default Rating;
@@ -0,0 +1 @@
1
+ export { default as Rating } from './Rating.svelte';
@@ -0,0 +1 @@
1
+ export { default as Rating } from './Rating.svelte';