@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.
- package/README.md +793 -43
- package/dist/components/Accordion/Accordion.svelte +79 -0
- package/dist/components/Accordion/Accordion.svelte.d.ts +10 -0
- package/dist/components/Accordion/AccordionItem.svelte +198 -0
- package/dist/components/Accordion/AccordionItem.svelte.d.ts +10 -0
- package/dist/components/Accordion/index.d.ts +2 -0
- package/dist/components/Accordion/index.js +2 -0
- package/dist/components/Carousel/Carousel.svelte +454 -0
- package/dist/components/Carousel/Carousel.svelte.d.ts +14 -0
- package/dist/components/Carousel/CarouselSlide.svelte +22 -0
- package/dist/components/Carousel/CarouselSlide.svelte.d.ts +7 -0
- package/dist/components/Carousel/index.d.ts +2 -0
- package/dist/components/Carousel/index.js +2 -0
- package/dist/components/Chip/Chip.svelte +461 -0
- package/dist/components/Chip/Chip.svelte.d.ts +17 -0
- package/dist/components/Chip/ChipGroup.svelte +76 -0
- package/dist/components/Chip/ChipGroup.svelte.d.ts +9 -0
- package/dist/components/Chip/index.d.ts +2 -0
- package/dist/components/Chip/index.js +2 -0
- package/dist/components/DatePicker/DatePicker.svelte +746 -0
- package/dist/components/DatePicker/DatePicker.svelte.d.ts +19 -0
- package/dist/components/DatePicker/index.d.ts +1 -0
- package/dist/components/DatePicker/index.js +1 -0
- package/dist/components/FileUpload/FileUpload.svelte +484 -0
- package/dist/components/FileUpload/FileUpload.svelte.d.ts +16 -0
- package/dist/components/FileUpload/index.d.ts +1 -0
- package/dist/components/FileUpload/index.js +1 -0
- package/dist/components/Image/Image.svelte +223 -0
- package/dist/components/Image/Image.svelte.d.ts +19 -0
- package/dist/components/Image/index.d.ts +1 -0
- package/dist/components/Image/index.js +1 -0
- package/dist/components/OTPInput/OTPInput.svelte +312 -0
- package/dist/components/OTPInput/OTPInput.svelte.d.ts +57 -0
- package/dist/components/OTPInput/index.d.ts +1 -0
- package/dist/components/OTPInput/index.js +1 -0
- package/dist/components/Rating/Rating.svelte +316 -0
- package/dist/components/Rating/Rating.svelte.d.ts +16 -0
- package/dist/components/Rating/index.d.ts +1 -0
- package/dist/components/Rating/index.js +1 -0
- package/dist/components/SearchInput/SearchInput.svelte +480 -0
- package/dist/components/SearchInput/SearchInput.svelte.d.ts +22 -0
- package/dist/components/SearchInput/index.d.ts +1 -0
- package/dist/components/SearchInput/index.js +1 -0
- package/dist/components/Slider/Slider.svelte +324 -0
- package/dist/components/Slider/Slider.svelte.d.ts +14 -0
- package/dist/components/Slider/index.d.ts +1 -0
- package/dist/components/Slider/index.js +1 -0
- package/dist/components/Stepper/Stepper.svelte +100 -0
- package/dist/components/Stepper/Stepper.svelte.d.ts +11 -0
- package/dist/components/Stepper/StepperStep.svelte +391 -0
- package/dist/components/Stepper/StepperStep.svelte.d.ts +13 -0
- package/dist/components/Stepper/index.d.ts +2 -0
- package/dist/components/Stepper/index.js +2 -0
- package/dist/components/TimePicker/TimePicker.svelte +803 -0
- package/dist/components/TimePicker/TimePicker.svelte.d.ts +17 -0
- package/dist/components/TimePicker/index.d.ts +1 -0
- package/dist/components/TimePicker/index.js +1 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.js +9 -0
- package/dist/types/data-display.d.ts +68 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/input.d.ts +67 -0
- package/dist/types/input.js +2 -0
- package/dist/types/navigation.d.ts +15 -0
- 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';
|