@placeholderco/placeholder-ui 1.0.3 → 1.0.6

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 (136) hide show
  1. package/LICENSE +26 -26
  2. package/README.md +179 -179
  3. package/dist/display/Alert.svelte +179 -179
  4. package/dist/display/Avatar.svelte +166 -166
  5. package/dist/display/LinkCollection.svelte +161 -161
  6. package/dist/display/Paper.svelte +118 -118
  7. package/dist/form/Autocomplete.svelte +223 -191
  8. package/dist/form/Autocomplete.svelte.d.ts +3 -1
  9. package/dist/form/AutocompleteMulti.svelte +356 -0
  10. package/dist/form/AutocompleteMulti.svelte.d.ts +28 -0
  11. package/dist/form/Checkbox.svelte +201 -201
  12. package/dist/form/Chips.svelte +128 -128
  13. package/dist/form/ComboBox.svelte +158 -158
  14. package/dist/form/ComboBox.svelte.d.ts +1 -1
  15. package/dist/form/ComboBoxItemBuilder.svelte +460 -460
  16. package/dist/form/ComboBoxMulti.svelte +197 -197
  17. package/dist/form/ComboBoxMulti.svelte.d.ts +1 -1
  18. package/dist/form/CronBuilder.svelte +693 -693
  19. package/dist/form/DatePicker.svelte +672 -672
  20. package/dist/form/DateTimePicker.svelte +712 -712
  21. package/dist/form/FileInput.svelte +235 -235
  22. package/dist/form/FormGroup.svelte +68 -68
  23. package/dist/form/Number.svelte +238 -238
  24. package/dist/form/PasswordInput.svelte +252 -252
  25. package/dist/form/RadioGroup.svelte +210 -210
  26. package/dist/form/Rating.svelte +235 -235
  27. package/dist/form/SegmentedControl.svelte +149 -149
  28. package/dist/form/Select.svelte +590 -590
  29. package/dist/form/Select.svelte.d.ts +1 -1
  30. package/dist/form/SelectMulti.svelte +613 -613
  31. package/dist/form/SelectMulti.svelte.d.ts +1 -1
  32. package/dist/form/Slider.svelte +358 -358
  33. package/dist/form/Switch.svelte +147 -147
  34. package/dist/form/TextArea.svelte +148 -148
  35. package/dist/form/Textbox.svelte +228 -228
  36. package/dist/form/TimePicker.svelte +267 -267
  37. package/dist/icon/Icon.svelte +52 -52
  38. package/dist/icon/alert-octagon.svg +5 -5
  39. package/dist/icon/alert-triangle.svg +5 -5
  40. package/dist/icon/archive.svg +1 -1
  41. package/dist/icon/arrow-down.svg +1 -1
  42. package/dist/icon/arrow-left.svg +1 -1
  43. package/dist/icon/arrow-right.svg +1 -1
  44. package/dist/icon/arrow-up.svg +1 -1
  45. package/dist/icon/at.svg +1 -1
  46. package/dist/icon/bell.svg +1 -1
  47. package/dist/icon/bookmark.svg +1 -1
  48. package/dist/icon/calendar.svg +1 -1
  49. package/dist/icon/camera.svg +1 -1
  50. package/dist/icon/chart-bar.svg +1 -1
  51. package/dist/icon/chart-line.svg +1 -1
  52. package/dist/icon/chart-pie.svg +1 -1
  53. package/dist/icon/checkbox.svg +1 -1
  54. package/dist/icon/checklist.svg +1 -1
  55. package/dist/icon/circle-check.svg +1 -1
  56. package/dist/icon/circle-x.svg +1 -1
  57. package/dist/icon/clock.svg +1 -1
  58. package/dist/icon/credit-card.svg +1 -1
  59. package/dist/icon/dots-vertical.svg +1 -1
  60. package/dist/icon/dots.svg +1 -1
  61. package/dist/icon/external-link.svg +1 -1
  62. package/dist/icon/eye-off.svg +1 -1
  63. package/dist/icon/eye.svg +1 -1
  64. package/dist/icon/filter.svg +1 -1
  65. package/dist/icon/fingerprint.svg +1 -1
  66. package/dist/icon/flag.svg +1 -1
  67. package/dist/icon/heart.svg +1 -1
  68. package/dist/icon/home.svg +1 -1
  69. package/dist/icon/key.svg +1 -1
  70. package/dist/icon/list-check.svg +1 -1
  71. package/dist/icon/login.svg +1 -1
  72. package/dist/icon/logout.svg +1 -1
  73. package/dist/icon/map-pin.svg +1 -1
  74. package/dist/icon/maximize.svg +1 -1
  75. package/dist/icon/microphone.svg +1 -1
  76. package/dist/icon/minimize.svg +1 -1
  77. package/dist/icon/note.svg +1 -1
  78. package/dist/icon/player-pause.svg +1 -1
  79. package/dist/icon/printer.svg +1 -1
  80. package/dist/icon/qrcode.svg +1 -1
  81. package/dist/icon/send.svg +1 -1
  82. package/dist/icon/settings.svg +1 -1
  83. package/dist/icon/share.svg +1 -1
  84. package/dist/icon/shopping-cart.svg +1 -1
  85. package/dist/icon/sort-ascending.svg +1 -1
  86. package/dist/icon/sort-descending.svg +1 -1
  87. package/dist/icon/star.svg +1 -1
  88. package/dist/icon/tag.svg +1 -1
  89. package/dist/icon/trending-down.svg +1 -1
  90. package/dist/icon/trending-up.svg +1 -1
  91. package/dist/icon/upload.svg +1 -1
  92. package/dist/icon/volume-off.svg +1 -1
  93. package/dist/icon/volume.svg +1 -1
  94. package/dist/icon/world.svg +1 -1
  95. package/dist/icon/zoom-in.svg +1 -1
  96. package/dist/icon/zoom-out.svg +1 -1
  97. package/dist/index.d.ts +1 -0
  98. package/dist/index.js +1 -0
  99. package/dist/layout/AppShell.svelte +169 -169
  100. package/dist/layout/CustomNavbar.svelte +61 -61
  101. package/dist/layout/Navbar.svelte +206 -206
  102. package/dist/layout/NavbarItemDisplay.svelte +29 -29
  103. package/dist/layout/Sidenav.svelte +712 -712
  104. package/dist/styles/components.css +199 -199
  105. package/dist/styles/dark.css +146 -146
  106. package/dist/styles/index.css +116 -116
  107. package/dist/styles/reset.css +110 -110
  108. package/dist/styles/semantic.css +86 -86
  109. package/dist/styles/tokens.css +203 -197
  110. package/dist/styles/utilities.css +523 -523
  111. package/dist/ui/Accordion.svelte +289 -289
  112. package/dist/ui/ActionIcon.svelte +76 -76
  113. package/dist/ui/Badge.svelte +329 -279
  114. package/dist/ui/Breadcrumbs.svelte +131 -131
  115. package/dist/ui/Button.svelte +432 -370
  116. package/dist/ui/ButtonVariant.d.ts +1 -1
  117. package/dist/ui/Dialog.svelte +307 -307
  118. package/dist/ui/Drawer.svelte +524 -524
  119. package/dist/ui/Dropdown.svelte +97 -97
  120. package/dist/ui/Dropzone.svelte +122 -122
  121. package/dist/ui/Link.svelte +32 -32
  122. package/dist/ui/Loader.svelte +70 -70
  123. package/dist/ui/LoadingOverlay.svelte +53 -53
  124. package/dist/ui/Pagination.svelte +135 -135
  125. package/dist/ui/Popover.svelte +225 -225
  126. package/dist/ui/Progress.svelte +191 -191
  127. package/dist/ui/RingProgress.svelte +141 -141
  128. package/dist/ui/Skeleton.svelte +85 -85
  129. package/dist/ui/Stepper.svelte +355 -355
  130. package/dist/ui/Table.svelte +345 -345
  131. package/dist/ui/Tabs.svelte +146 -146
  132. package/dist/ui/ThemeSwitcher.svelte +39 -39
  133. package/dist/ui/Timeline.svelte +225 -225
  134. package/dist/ui/Toaster.svelte +6 -6
  135. package/dist/ui/Tooltip.svelte +434 -434
  136. package/package.json +14 -14
@@ -1,358 +1,358 @@
1
- <script lang="ts">
2
- import FormGroup from './FormGroup.svelte';
3
-
4
- interface Mark {
5
- value: number;
6
- label?: string;
7
- }
8
-
9
- interface Props {
10
- label?: string;
11
- value?: number;
12
- min?: number;
13
- max?: number;
14
- step?: number;
15
- marks?: Mark[] | boolean;
16
- showValue?: boolean;
17
- labelAlwaysOn?: boolean;
18
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
19
- color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'danger';
20
- radius?: 'none' | 'sm' | 'md' | 'lg' | 'full';
21
- disabled?: boolean;
22
- class?: string;
23
- containerClass?: string;
24
- required?: boolean;
25
- showError?: boolean;
26
- errorText?: string;
27
- tooltipLocation?: 'top' | 'bottom' | 'left' | 'right';
28
- tooltipText?: string;
29
- onchange?: (value: number) => void;
30
- oninput?: (value: number) => void;
31
- }
32
-
33
- let {
34
- label = '',
35
- value = $bindable(0),
36
- min = 0,
37
- max = 100,
38
- step = 1,
39
- marks = false,
40
- showValue = false,
41
- labelAlwaysOn = false,
42
- size = 'md',
43
- color = 'primary',
44
- radius = 'full',
45
- disabled = false,
46
- class: classes = '',
47
- containerClass = '',
48
- required = false,
49
- showError = false,
50
- errorText = '',
51
- tooltipLocation = 'top',
52
- tooltipText = undefined,
53
- onchange,
54
- oninput
55
- }: Props = $props();
56
-
57
- let isDragging = $state(false);
58
-
59
- const percentage = $derived(((value - min) / (max - min)) * 100);
60
-
61
- // Generate marks if boolean true
62
- const computedMarks = $derived.by(() => {
63
- if (marks === false) return [];
64
- if (marks === true) {
65
- // Generate marks at 0%, 25%, 50%, 75%, 100%
66
- const range = max - min;
67
- return [
68
- { value: min, label: String(min) },
69
- { value: min + range * 0.25, label: String(min + range * 0.25) },
70
- { value: min + range * 0.5, label: String(min + range * 0.5) },
71
- { value: min + range * 0.75, label: String(min + range * 0.75) },
72
- { value: max, label: String(max) }
73
- ];
74
- }
75
- return marks;
76
- });
77
-
78
- function handleInput(e: Event) {
79
- const target = e.target as HTMLInputElement;
80
- value = Number(target.value);
81
- oninput?.(value);
82
- }
83
-
84
- function handleChange(e: Event) {
85
- const target = e.target as HTMLInputElement;
86
- value = Number(target.value);
87
- onchange?.(value);
88
- }
89
- </script>
90
-
91
- <div class="slider-container {containerClass}">
92
- <FormGroup
93
- {label}
94
- {required}
95
- class={classes}
96
- {tooltipLocation}
97
- {tooltipText}
98
- {showError}
99
- {errorText}
100
- >
101
- <div class="slider-wrapper size-{size}">
102
- {#if showValue}
103
- <div class="slider-value-display">
104
- <span>{value}</span>
105
- </div>
106
- {/if}
107
- <div class="slider-track-wrapper">
108
- <input
109
- type="range"
110
- class="slider color-{color} radius-{radius}"
111
- {min}
112
- {max}
113
- {step}
114
- {disabled}
115
- bind:value
116
- oninput={handleInput}
117
- onchange={handleChange}
118
- onmousedown={() => (isDragging = true)}
119
- onmouseup={() => (isDragging = false)}
120
- ontouchstart={() => (isDragging = true)}
121
- ontouchend={() => (isDragging = false)}
122
- style="--slider-percentage: {percentage}%;"
123
- />
124
- {#if labelAlwaysOn || isDragging}
125
- <div class="slider-thumb-label" style="left: {percentage}%;">
126
- {value}
127
- </div>
128
- {/if}
129
- </div>
130
- {#if computedMarks.length > 0}
131
- <div class="slider-marks">
132
- {#each computedMarks as mark}
133
- {@const markPercentage = ((mark.value - min) / (max - min)) * 100}
134
- <div class="slider-mark" style="left: {markPercentage}%;">
135
- <div class="mark-dot" class:active={value >= mark.value}></div>
136
- {#if mark.label}
137
- <div class="mark-label">{mark.label}</div>
138
- {/if}
139
- </div>
140
- {/each}
141
- </div>
142
- {/if}
143
- </div>
144
- </FormGroup>
145
- </div>
146
-
147
- <style>
148
- .slider-container {
149
- width: 100%;
150
- }
151
-
152
- .slider-wrapper {
153
- width: 100%;
154
- padding-top: var(--pui-spacing-1);
155
- }
156
-
157
- .slider-value-display {
158
- text-align: right;
159
- font-size: var(--pui-font-size-sm);
160
- font-weight: var(--pui-font-weight-medium);
161
- color: var(--pui-text-secondary);
162
- margin-bottom: var(--pui-spacing-1);
163
- }
164
-
165
- :global(.dark) .slider-value-display {
166
- color: var(--pui-color-gray-300);
167
- }
168
-
169
- .slider-track-wrapper {
170
- position: relative;
171
- width: 100%;
172
- }
173
-
174
- .slider {
175
- -webkit-appearance: none;
176
- appearance: none;
177
- width: 100%;
178
- background: transparent;
179
- cursor: pointer;
180
- }
181
-
182
- .slider:disabled {
183
- opacity: 0.5;
184
- cursor: not-allowed;
185
- }
186
-
187
- /* Track */
188
- .slider::-webkit-slider-runnable-track {
189
- height: var(--track-height, 6px);
190
- background: linear-gradient(
191
- to right,
192
- var(--slider-color, var(--pui-color-primary)) 0%,
193
- var(--slider-color, var(--pui-color-primary)) var(--slider-percentage),
194
- var(--pui-color-gray-300) var(--slider-percentage),
195
- var(--pui-color-gray-300) 100%
196
- );
197
- border-radius: var(--track-radius, var(--pui-radius-full));
198
- }
199
-
200
- :global(.dark) .slider::-webkit-slider-runnable-track {
201
- background: linear-gradient(
202
- to right,
203
- var(--slider-color, var(--pui-color-primary)) 0%,
204
- var(--slider-color, var(--pui-color-primary)) var(--slider-percentage),
205
- var(--pui-color-dark-border) var(--slider-percentage),
206
- var(--pui-color-dark-border) 100%
207
- );
208
- }
209
-
210
- .slider::-moz-range-track {
211
- height: var(--track-height, 6px);
212
- background: var(--pui-color-gray-300);
213
- border-radius: var(--track-radius, var(--pui-radius-full));
214
- }
215
-
216
- .slider::-moz-range-progress {
217
- background: var(--slider-color, var(--pui-color-primary));
218
- height: var(--track-height, 6px);
219
- border-radius: var(--track-radius, var(--pui-radius-full));
220
- }
221
-
222
- /* Thumb */
223
- .slider::-webkit-slider-thumb {
224
- -webkit-appearance: none;
225
- appearance: none;
226
- width: var(--thumb-size, 16px);
227
- height: var(--thumb-size, 16px);
228
- background: var(--pui-color-white);
229
- border: 2px solid var(--slider-color, var(--pui-color-primary));
230
- border-radius: 50%;
231
- margin-top: calc((var(--track-height, 6px) - var(--thumb-size, 16px)) / 2);
232
- box-shadow: var(--pui-shadow-sm);
233
- transition: transform var(--pui-transition-fast) var(--pui-ease-out);
234
- }
235
-
236
- .slider::-webkit-slider-thumb:hover {
237
- transform: scale(1.1);
238
- }
239
-
240
- .slider::-moz-range-thumb {
241
- width: var(--thumb-size, 16px);
242
- height: var(--thumb-size, 16px);
243
- background: var(--pui-color-white);
244
- border: 2px solid var(--slider-color, var(--pui-color-primary));
245
- border-radius: 50%;
246
- box-shadow: var(--pui-shadow-sm);
247
- }
248
-
249
- /* Sizes */
250
- .size-xs {
251
- --track-height: 4px;
252
- --thumb-size: 12px;
253
- }
254
- .size-sm {
255
- --track-height: 5px;
256
- --thumb-size: 14px;
257
- }
258
- .size-md {
259
- --track-height: 6px;
260
- --thumb-size: 16px;
261
- }
262
- .size-lg {
263
- --track-height: 8px;
264
- --thumb-size: 20px;
265
- }
266
- .size-xl {
267
- --track-height: 10px;
268
- --thumb-size: 24px;
269
- }
270
-
271
- /* Colors */
272
- .color-primary {
273
- --slider-color: var(--pui-color-primary);
274
- }
275
- .color-secondary {
276
- --slider-color: var(--pui-color-secondary);
277
- }
278
- .color-accent {
279
- --slider-color: var(--pui-color-accent);
280
- }
281
- .color-success {
282
- --slider-color: var(--pui-color-success);
283
- }
284
- .color-warning {
285
- --slider-color: var(--pui-color-warning);
286
- }
287
- .color-danger {
288
- --slider-color: var(--pui-color-danger);
289
- }
290
-
291
- /* Radius */
292
- .radius-none {
293
- --track-radius: 0;
294
- }
295
- .radius-sm {
296
- --track-radius: var(--pui-radius-sm);
297
- }
298
- .radius-md {
299
- --track-radius: var(--pui-radius-md);
300
- }
301
- .radius-lg {
302
- --track-radius: var(--pui-radius-lg);
303
- }
304
- .radius-full {
305
- --track-radius: var(--pui-radius-full);
306
- }
307
-
308
- /* Thumb label */
309
- .slider-thumb-label {
310
- position: absolute;
311
- top: -28px;
312
- transform: translateX(-50%);
313
- background: var(--pui-color-gray-800);
314
- color: var(--pui-color-white);
315
- font-size: var(--pui-font-size-xs);
316
- padding: 2px 6px;
317
- border-radius: var(--pui-radius-sm);
318
- white-space: nowrap;
319
- pointer-events: none;
320
- }
321
-
322
- /* Marks */
323
- .slider-marks {
324
- position: relative;
325
- width: 100%;
326
- height: 20px;
327
- margin-top: var(--pui-spacing-1);
328
- }
329
-
330
- .slider-mark {
331
- position: absolute;
332
- transform: translateX(-50%);
333
- display: flex;
334
- flex-direction: column;
335
- align-items: center;
336
- }
337
-
338
- .mark-dot {
339
- width: 6px;
340
- height: 6px;
341
- border-radius: 50%;
342
- background: var(--pui-color-gray-400);
343
- margin-bottom: var(--pui-spacing-1);
344
- }
345
-
346
- .mark-dot.active {
347
- background: var(--slider-color, var(--pui-color-primary));
348
- }
349
-
350
- .mark-label {
351
- font-size: var(--pui-font-size-xs);
352
- color: var(--pui-color-gray-600);
353
- }
354
-
355
- :global(.dark) .mark-label {
356
- color: var(--pui-color-gray-400);
357
- }
358
- </style>
1
+ <script lang="ts">
2
+ import FormGroup from './FormGroup.svelte';
3
+
4
+ interface Mark {
5
+ value: number;
6
+ label?: string;
7
+ }
8
+
9
+ interface Props {
10
+ label?: string;
11
+ value?: number;
12
+ min?: number;
13
+ max?: number;
14
+ step?: number;
15
+ marks?: Mark[] | boolean;
16
+ showValue?: boolean;
17
+ labelAlwaysOn?: boolean;
18
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
19
+ color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'danger';
20
+ radius?: 'none' | 'sm' | 'md' | 'lg' | 'full';
21
+ disabled?: boolean;
22
+ class?: string;
23
+ containerClass?: string;
24
+ required?: boolean;
25
+ showError?: boolean;
26
+ errorText?: string;
27
+ tooltipLocation?: 'top' | 'bottom' | 'left' | 'right';
28
+ tooltipText?: string;
29
+ onchange?: (value: number) => void;
30
+ oninput?: (value: number) => void;
31
+ }
32
+
33
+ let {
34
+ label = '',
35
+ value = $bindable(0),
36
+ min = 0,
37
+ max = 100,
38
+ step = 1,
39
+ marks = false,
40
+ showValue = false,
41
+ labelAlwaysOn = false,
42
+ size = 'md',
43
+ color = 'primary',
44
+ radius = 'full',
45
+ disabled = false,
46
+ class: classes = '',
47
+ containerClass = '',
48
+ required = false,
49
+ showError = false,
50
+ errorText = '',
51
+ tooltipLocation = 'top',
52
+ tooltipText = undefined,
53
+ onchange,
54
+ oninput
55
+ }: Props = $props();
56
+
57
+ let isDragging = $state(false);
58
+
59
+ const percentage = $derived(((value - min) / (max - min)) * 100);
60
+
61
+ // Generate marks if boolean true
62
+ const computedMarks = $derived.by(() => {
63
+ if (marks === false) return [];
64
+ if (marks === true) {
65
+ // Generate marks at 0%, 25%, 50%, 75%, 100%
66
+ const range = max - min;
67
+ return [
68
+ { value: min, label: String(min) },
69
+ { value: min + range * 0.25, label: String(min + range * 0.25) },
70
+ { value: min + range * 0.5, label: String(min + range * 0.5) },
71
+ { value: min + range * 0.75, label: String(min + range * 0.75) },
72
+ { value: max, label: String(max) }
73
+ ];
74
+ }
75
+ return marks;
76
+ });
77
+
78
+ function handleInput(e: Event) {
79
+ const target = e.target as HTMLInputElement;
80
+ value = Number(target.value);
81
+ oninput?.(value);
82
+ }
83
+
84
+ function handleChange(e: Event) {
85
+ const target = e.target as HTMLInputElement;
86
+ value = Number(target.value);
87
+ onchange?.(value);
88
+ }
89
+ </script>
90
+
91
+ <div class="slider-container {containerClass}">
92
+ <FormGroup
93
+ {label}
94
+ {required}
95
+ class={classes}
96
+ {tooltipLocation}
97
+ {tooltipText}
98
+ {showError}
99
+ {errorText}
100
+ >
101
+ <div class="slider-wrapper size-{size}">
102
+ {#if showValue}
103
+ <div class="slider-value-display">
104
+ <span>{value}</span>
105
+ </div>
106
+ {/if}
107
+ <div class="slider-track-wrapper">
108
+ <input
109
+ type="range"
110
+ class="slider color-{color} radius-{radius}"
111
+ {min}
112
+ {max}
113
+ {step}
114
+ {disabled}
115
+ bind:value
116
+ oninput={handleInput}
117
+ onchange={handleChange}
118
+ onmousedown={() => (isDragging = true)}
119
+ onmouseup={() => (isDragging = false)}
120
+ ontouchstart={() => (isDragging = true)}
121
+ ontouchend={() => (isDragging = false)}
122
+ style="--slider-percentage: {percentage}%;"
123
+ />
124
+ {#if labelAlwaysOn || isDragging}
125
+ <div class="slider-thumb-label" style="left: {percentage}%;">
126
+ {value}
127
+ </div>
128
+ {/if}
129
+ </div>
130
+ {#if computedMarks.length > 0}
131
+ <div class="slider-marks">
132
+ {#each computedMarks as mark}
133
+ {@const markPercentage = ((mark.value - min) / (max - min)) * 100}
134
+ <div class="slider-mark" style="left: {markPercentage}%;">
135
+ <div class="mark-dot" class:active={value >= mark.value}></div>
136
+ {#if mark.label}
137
+ <div class="mark-label">{mark.label}</div>
138
+ {/if}
139
+ </div>
140
+ {/each}
141
+ </div>
142
+ {/if}
143
+ </div>
144
+ </FormGroup>
145
+ </div>
146
+
147
+ <style>
148
+ .slider-container {
149
+ width: 100%;
150
+ }
151
+
152
+ .slider-wrapper {
153
+ width: 100%;
154
+ padding-top: var(--pui-spacing-1);
155
+ }
156
+
157
+ .slider-value-display {
158
+ text-align: right;
159
+ font-size: var(--pui-font-size-sm);
160
+ font-weight: var(--pui-font-weight-medium);
161
+ color: var(--pui-text-secondary);
162
+ margin-bottom: var(--pui-spacing-1);
163
+ }
164
+
165
+ :global(.dark) .slider-value-display {
166
+ color: var(--pui-color-gray-300);
167
+ }
168
+
169
+ .slider-track-wrapper {
170
+ position: relative;
171
+ width: 100%;
172
+ }
173
+
174
+ .slider {
175
+ -webkit-appearance: none;
176
+ appearance: none;
177
+ width: 100%;
178
+ background: transparent;
179
+ cursor: pointer;
180
+ }
181
+
182
+ .slider:disabled {
183
+ opacity: 0.5;
184
+ cursor: not-allowed;
185
+ }
186
+
187
+ /* Track */
188
+ .slider::-webkit-slider-runnable-track {
189
+ height: var(--track-height, 6px);
190
+ background: linear-gradient(
191
+ to right,
192
+ var(--slider-color, var(--pui-color-primary)) 0%,
193
+ var(--slider-color, var(--pui-color-primary)) var(--slider-percentage),
194
+ var(--pui-color-gray-300) var(--slider-percentage),
195
+ var(--pui-color-gray-300) 100%
196
+ );
197
+ border-radius: var(--track-radius, var(--pui-radius-full));
198
+ }
199
+
200
+ :global(.dark) .slider::-webkit-slider-runnable-track {
201
+ background: linear-gradient(
202
+ to right,
203
+ var(--slider-color, var(--pui-color-primary)) 0%,
204
+ var(--slider-color, var(--pui-color-primary)) var(--slider-percentage),
205
+ var(--pui-color-dark-border) var(--slider-percentage),
206
+ var(--pui-color-dark-border) 100%
207
+ );
208
+ }
209
+
210
+ .slider::-moz-range-track {
211
+ height: var(--track-height, 6px);
212
+ background: var(--pui-color-gray-300);
213
+ border-radius: var(--track-radius, var(--pui-radius-full));
214
+ }
215
+
216
+ .slider::-moz-range-progress {
217
+ background: var(--slider-color, var(--pui-color-primary));
218
+ height: var(--track-height, 6px);
219
+ border-radius: var(--track-radius, var(--pui-radius-full));
220
+ }
221
+
222
+ /* Thumb */
223
+ .slider::-webkit-slider-thumb {
224
+ -webkit-appearance: none;
225
+ appearance: none;
226
+ width: var(--thumb-size, 16px);
227
+ height: var(--thumb-size, 16px);
228
+ background: var(--pui-color-white);
229
+ border: 2px solid var(--slider-color, var(--pui-color-primary));
230
+ border-radius: 50%;
231
+ margin-top: calc((var(--track-height, 6px) - var(--thumb-size, 16px)) / 2);
232
+ box-shadow: var(--pui-shadow-sm);
233
+ transition: transform var(--pui-transition-fast) var(--pui-ease-out);
234
+ }
235
+
236
+ .slider::-webkit-slider-thumb:hover {
237
+ transform: scale(1.1);
238
+ }
239
+
240
+ .slider::-moz-range-thumb {
241
+ width: var(--thumb-size, 16px);
242
+ height: var(--thumb-size, 16px);
243
+ background: var(--pui-color-white);
244
+ border: 2px solid var(--slider-color, var(--pui-color-primary));
245
+ border-radius: 50%;
246
+ box-shadow: var(--pui-shadow-sm);
247
+ }
248
+
249
+ /* Sizes */
250
+ .size-xs {
251
+ --track-height: 4px;
252
+ --thumb-size: 12px;
253
+ }
254
+ .size-sm {
255
+ --track-height: 5px;
256
+ --thumb-size: 14px;
257
+ }
258
+ .size-md {
259
+ --track-height: 6px;
260
+ --thumb-size: 16px;
261
+ }
262
+ .size-lg {
263
+ --track-height: 8px;
264
+ --thumb-size: 20px;
265
+ }
266
+ .size-xl {
267
+ --track-height: 10px;
268
+ --thumb-size: 24px;
269
+ }
270
+
271
+ /* Colors */
272
+ .color-primary {
273
+ --slider-color: var(--pui-color-primary);
274
+ }
275
+ .color-secondary {
276
+ --slider-color: var(--pui-color-secondary);
277
+ }
278
+ .color-accent {
279
+ --slider-color: var(--pui-color-accent);
280
+ }
281
+ .color-success {
282
+ --slider-color: var(--pui-color-success);
283
+ }
284
+ .color-warning {
285
+ --slider-color: var(--pui-color-warning);
286
+ }
287
+ .color-danger {
288
+ --slider-color: var(--pui-color-danger);
289
+ }
290
+
291
+ /* Radius */
292
+ .radius-none {
293
+ --track-radius: 0;
294
+ }
295
+ .radius-sm {
296
+ --track-radius: var(--pui-radius-sm);
297
+ }
298
+ .radius-md {
299
+ --track-radius: var(--pui-radius-md);
300
+ }
301
+ .radius-lg {
302
+ --track-radius: var(--pui-radius-lg);
303
+ }
304
+ .radius-full {
305
+ --track-radius: var(--pui-radius-full);
306
+ }
307
+
308
+ /* Thumb label */
309
+ .slider-thumb-label {
310
+ position: absolute;
311
+ top: -28px;
312
+ transform: translateX(-50%);
313
+ background: var(--pui-color-gray-800);
314
+ color: var(--pui-color-white);
315
+ font-size: var(--pui-font-size-xs);
316
+ padding: 2px 6px;
317
+ border-radius: var(--pui-radius-sm);
318
+ white-space: nowrap;
319
+ pointer-events: none;
320
+ }
321
+
322
+ /* Marks */
323
+ .slider-marks {
324
+ position: relative;
325
+ width: 100%;
326
+ height: 20px;
327
+ margin-top: var(--pui-spacing-1);
328
+ }
329
+
330
+ .slider-mark {
331
+ position: absolute;
332
+ transform: translateX(-50%);
333
+ display: flex;
334
+ flex-direction: column;
335
+ align-items: center;
336
+ }
337
+
338
+ .mark-dot {
339
+ width: 6px;
340
+ height: 6px;
341
+ border-radius: 50%;
342
+ background: var(--pui-color-gray-400);
343
+ margin-bottom: var(--pui-spacing-1);
344
+ }
345
+
346
+ .mark-dot.active {
347
+ background: var(--slider-color, var(--pui-color-primary));
348
+ }
349
+
350
+ .mark-label {
351
+ font-size: var(--pui-font-size-xs);
352
+ color: var(--pui-color-gray-600);
353
+ }
354
+
355
+ :global(.dark) .mark-label {
356
+ color: var(--pui-color-gray-400);
357
+ }
358
+ </style>