poe-svelte-ui-lib 1.0.1 → 1.0.4

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 (61) hide show
  1. package/LICENSE +3 -3
  2. package/README.md +1 -0
  3. package/dist/Accordion/Accordion.svelte +53 -53
  4. package/dist/Button/Button.svelte +111 -144
  5. package/dist/Button/Button.svelte.d.ts +1 -34
  6. package/dist/ColorPicker/ColorPicker.svelte +205 -207
  7. package/dist/FileAttach/FileAttach.svelte +103 -103
  8. package/dist/Graph/Graph.svelte +270 -270
  9. package/dist/Input/Input.svelte +240 -239
  10. package/dist/Loader.svelte +12 -12
  11. package/dist/MessageModal.svelte +54 -54
  12. package/dist/ProgressBar/ProgressBar.svelte +48 -48
  13. package/dist/Select/Select.svelte +189 -191
  14. package/dist/Slider/Slider.svelte +260 -260
  15. package/dist/Switch/Switch.svelte +84 -83
  16. package/dist/Table/Table.svelte +275 -276
  17. package/dist/TextField/TextField.svelte +22 -22
  18. package/dist/index.d.ts +0 -11
  19. package/dist/index.js +0 -11
  20. package/dist/{appIcons → libIcons}/ButtonAdd.svelte +10 -10
  21. package/dist/{appIcons → libIcons}/ButtonDelete.svelte +13 -13
  22. package/dist/{appIcons → libIcons}/LoaderRotate.svelte +9 -9
  23. package/dist/options.d.ts +11 -11
  24. package/dist/options.js +27 -27
  25. package/dist/types.d.ts +1 -1
  26. package/package.json +48 -47
  27. package/dist/Accordion/AccordionProps.svelte +0 -70
  28. package/dist/Accordion/AccordionProps.svelte.d.ts +0 -10
  29. package/dist/Button/ButtonProps.svelte +0 -200
  30. package/dist/Button/ButtonProps.svelte.d.ts +0 -10
  31. package/dist/ColorPicker/ColorPickerProps.svelte +0 -100
  32. package/dist/ColorPicker/ColorPickerProps.svelte.d.ts +0 -10
  33. package/dist/Graph/GraphProps.svelte +0 -56
  34. package/dist/Graph/GraphProps.svelte.d.ts +0 -10
  35. package/dist/Input/InputProps.svelte +0 -221
  36. package/dist/Input/InputProps.svelte.d.ts +0 -10
  37. package/dist/ProgressBar/ProgressBarProps.svelte +0 -145
  38. package/dist/ProgressBar/ProgressBarProps.svelte.d.ts +0 -10
  39. package/dist/Select/SelectProps.svelte +0 -260
  40. package/dist/Select/SelectProps.svelte.d.ts +0 -10
  41. package/dist/Slider/SliderProps.svelte +0 -161
  42. package/dist/Slider/SliderProps.svelte.d.ts +0 -10
  43. package/dist/Switch/SwitchProps.svelte +0 -144
  44. package/dist/Switch/SwitchProps.svelte.d.ts +0 -10
  45. package/dist/Table/TableProps.svelte +0 -286
  46. package/dist/Table/TableProps.svelte.d.ts +0 -10
  47. package/dist/TextField/TextFieldProps.svelte +0 -92
  48. package/dist/TextField/TextFieldProps.svelte.d.ts +0 -10
  49. package/dist/locales/CircleFlagsEn.svelte +0 -14
  50. package/dist/locales/CircleFlagsEn.svelte.d.ts +0 -26
  51. package/dist/locales/CircleFlagsRu.svelte +0 -8
  52. package/dist/locales/CircleFlagsRu.svelte.d.ts +0 -26
  53. package/dist/locales/CircleFlagsZh.svelte +0 -8
  54. package/dist/locales/CircleFlagsZh.svelte.d.ts +0 -26
  55. package/dist/locales/i18n.d.ts +0 -10
  56. package/dist/locales/i18n.js +0 -36
  57. package/dist/locales/translations.d.ts +0 -7
  58. package/dist/locales/translations.js +0 -450
  59. /package/dist/{appIcons → libIcons}/ButtonAdd.svelte.d.ts +0 -0
  60. /package/dist/{appIcons → libIcons}/ButtonDelete.svelte.d.ts +0 -0
  61. /package/dist/{appIcons → libIcons}/LoaderRotate.svelte.d.ts +0 -0
@@ -1,260 +1,260 @@
1
- <!-- $lib/ElementsUI/Slider.svelte -->
2
- <script lang="ts">
3
- import type { ISliderProps } from '../types'
4
-
5
- let {
6
- id = { name: '', value: crypto.randomUUID() },
7
- wrapperClass = '',
8
- label = { name: '', class: '' },
9
- type = 'single',
10
- value = 0,
11
- number = { minNum: 0, maxNum: 10, step: 1 },
12
- disabled = false,
13
- onUpdate = () => {},
14
- }: ISliderProps = $props()
15
-
16
- const isRange = $derived(type === 'range' || (Array.isArray(value) && value.length === 2))
17
-
18
- const maxDigits = String(number.maxNum ?? 100).length
19
- const valueWidth = `${maxDigits + 1}ch` /* +1 на запас */
20
-
21
- /* Инициализация значений с проверкой типа */
22
- let singleValue = $derived(!isRange && typeof value === 'number' ? value : number.minNum)
23
- let lowerValue = $derived(isRange && Array.isArray(value) ? value[0] : number.minNum)
24
- let upperValue = $derived(isRange && Array.isArray(value) ? value[1] : number.maxNum)
25
-
26
- /* Расчет позиций */
27
- const singlePosition = $derived(((singleValue - number.minNum) / (number.maxNum - number.minNum)) * 100)
28
- const lowerPosition = $derived(((lowerValue - number.minNum) / (number.maxNum - number.minNum)) * 100)
29
- const upperPosition = $derived(((upperValue - number.minNum) / (number.maxNum - number.minNum)) * 100)
30
-
31
- $effect(() => {
32
- if (value === undefined || value === null) {
33
- if (type === 'single' && !value) value = number.minNum
34
- if (type === 'range' && !value) value = [number.minNum, number.maxNum]
35
- }
36
- })
37
-
38
- const adjustValue = (target: 'lower' | 'upper' | 'single', direction: 'increment' | 'decrement') => {
39
- const stepValue = direction === 'increment' ? number.step : -number.step
40
- if (isRange && target !== 'single') {
41
- if (target === 'lower') {
42
- lowerValue = Math.max(number.minNum, Math.min(lowerValue + stepValue, upperValue))
43
- } else {
44
- upperValue = Math.min(number.maxNum, Math.max(upperValue + stepValue, lowerValue))
45
- }
46
- onUpdate([lowerValue, upperValue])
47
- } else {
48
- singleValue = Math.max(number.minNum, Math.min(singleValue + stepValue, number.maxNum))
49
- onUpdate(singleValue)
50
- }
51
- }
52
-
53
- $effect(() => {
54
- if (Array.isArray(value)) {
55
- lowerValue = value[0]
56
- upperValue = value[1]
57
- } else if (typeof value === 'number') {
58
- singleValue = value
59
- }
60
- })
61
-
62
- let activeThumb = $state<'lower' | 'upper'>('lower')
63
- const handleTrackClick = (e: MouseEvent) => {
64
- e.stopPropagation()
65
- const track = e.currentTarget as HTMLElement
66
- const rect = track.getBoundingClientRect()
67
- const clickPercent = ((e.clientX - rect.left) / rect.width) * 100
68
- const rawValue = number.minNum + (clickPercent / 100) * (number.maxNum - number.minNum)
69
- const clickValue = Math.round((rawValue - number.minNum) / number.step) * number.step + number.minNum
70
-
71
- if (isRange) {
72
- const lowerDiff = Math.abs(clickValue - lowerValue)
73
- const upperDiff = Math.abs(clickValue - upperValue)
74
-
75
- activeThumb = lowerDiff < upperDiff ? 'lower' : 'upper'
76
-
77
- if (activeThumb === 'lower') {
78
- lowerValue = Math.max(number.minNum, Math.min(clickValue, upperValue))
79
- } else {
80
- upperValue = Math.min(number.maxNum, Math.max(clickValue, lowerValue))
81
- }
82
-
83
- onUpdate([lowerValue, upperValue])
84
- } else {
85
- singleValue = Math.max(number.minNum, Math.min(clickValue, number.maxNum))
86
- onUpdate(singleValue)
87
- }
88
- }
89
- </script>
90
-
91
- <div class={`relative flex w-full flex-col items-center gap-2 ${wrapperClass}`}>
92
- {#if label.name}
93
- <h5 class={`w-full px-4 text-center ${label.class}`}>{label.name}</h5>
94
- {/if}
95
-
96
- <!-- Слайдер -->
97
- <div class="relative flex h-2 w-full justify-center {disabled ? 'opacity-50' : ''}" id={id.value}>
98
- {#if isRange}
99
- <!-- Трек и активная зона -->
100
- <div
101
- class={`absolute h-full w-full rounded bg-gray-400 ${disabled ? '' : 'cursor-pointer'}`}
102
- role="button"
103
- tabindex={null}
104
- onkeydown={null}
105
- onclick={disabled ? undefined : handleTrackClick}
106
- >
107
- <div class="absolute h-full rounded" style={`left: ${lowerPosition}%; right: ${100 - upperPosition}%; background-color: var(--bg-color)`}></div>
108
- </div>
109
-
110
- <!-- Ползунки -->
111
- <input
112
- type="range"
113
- min={number.minNum}
114
- max={number.maxNum}
115
- step={number.step}
116
- bind:value={lowerValue}
117
- oninput={disabled
118
- ? undefined
119
- : (e) => {
120
- const newValue = Math.min(Number((e.target as HTMLInputElement).value), upperValue)
121
- lowerValue = newValue
122
- activeThumb = 'lower'
123
- }}
124
- onmouseup={disabled ? undefined : () => onUpdate([lowerValue, upperValue])}
125
- {disabled}
126
- class={`absolute h-full w-full appearance-none bg-transparent ${activeThumb === 'lower' ? 'z-30' : 'z-20'}`}
127
- />
128
-
129
- <input
130
- type="range"
131
- min={number.minNum}
132
- max={number.maxNum}
133
- step={number.step}
134
- bind:value={upperValue}
135
- oninput={disabled
136
- ? undefined
137
- : (e) => {
138
- const newValue = Math.max(Number((e.target as HTMLInputElement).value), lowerValue)
139
- upperValue = newValue
140
- activeThumb = 'upper'
141
- }}
142
- onmouseup={disabled ? undefined : () => onUpdate([lowerValue, upperValue])}
143
- {disabled}
144
- class={`absolute h-full w-full appearance-none bg-transparent ${activeThumb === 'upper' ? 'z-30' : 'z-20'}`}
145
- />
146
- {:else}
147
- <!-- Одиночный слайдер -->
148
- <div
149
- class={`absolute h-full w-full rounded bg-gray-400 ${disabled ? '' : 'cursor-pointer'}`}
150
- role="button"
151
- tabindex={null}
152
- onkeydown={null}
153
- onclick={disabled ? undefined : handleTrackClick}
154
- >
155
- <div class="absolute h-full rounded" style={`width: ${singlePosition}%; background-color: var(--bg-color)`}></div>
156
- </div>
157
-
158
- <input
159
- type="range"
160
- min={number.minNum}
161
- max={number.maxNum}
162
- step={number.step}
163
- bind:value={singleValue}
164
- oninput={disabled
165
- ? undefined
166
- : (e) => {
167
- singleValue = Number((e.target as HTMLInputElement).value)
168
- }}
169
- onmouseup={disabled ? undefined : () => onUpdate(singleValue)}
170
- {disabled}
171
- class="absolute z-30 h-full w-full appearance-none bg-transparent"
172
- />
173
- {/if}
174
- </div>
175
-
176
- <!-- Кнопки управления -->
177
- <div class={`flex w-full ${isRange ? 'justify-between' : 'justify-center'} gap-2`}>
178
- {#if isRange}
179
- {#each ['lower', 'upper'] as type (type)}
180
- <div class={`flex items-center justify-center gap-2 rounded-full px-2 ${disabled ? 'opacity-70' : ''}`} style="background-color: var(--bg-color)">
181
- <button
182
- class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
183
- onclick={disabled ? undefined : () => adjustValue(type as 'lower' | 'upper', 'decrement')}
184
- disabled={disabled || (type === 'lower' ? lowerValue <= number.minNum : upperValue <= lowerValue)}>−</button
185
- >
186
- <span class="inline-block text-center tabular-nums" style={`width: ${valueWidth}`}>
187
- {type === 'lower' ? lowerValue : upperValue}
188
- </span>
189
- <button
190
- class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
191
- onclick={disabled ? undefined : () => adjustValue(type as 'lower' | 'upper', 'increment')}
192
- disabled={disabled || (type === 'lower' ? lowerValue >= upperValue : upperValue >= number.maxNum)}>+</button
193
- >
194
- </div>
195
- {/each}
196
- {:else}
197
- <div class={`flex items-center justify-center gap-2 rounded-full px-2 ${disabled ? 'opacity-70' : ''}`} style="background-color: var(--bg-color)">
198
- <button
199
- class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
200
- onclick={disabled ? undefined : () => adjustValue('single', 'decrement')}
201
- disabled={disabled || singleValue <= number.minNum}>−</button
202
- >
203
- <span class="inline-block text-center tabular-nums" style={`width: ${valueWidth}`}>
204
- {singleValue}
205
- </span>
206
- <button
207
- class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
208
- onclick={disabled ? undefined : () => adjustValue('single', 'increment')}
209
- disabled={disabled || singleValue >= number.maxNum}>+</button
210
- >
211
- </div>
212
- {/if}
213
- </div>
214
- </div>
215
-
216
- <!-- <style>
217
- input[type='range'] {
218
- -webkit-appearance: none;
219
- appearance: none;
220
- margin: 0;
221
- padding: 0;
222
- pointer-events: none;
223
- }
224
-
225
- input[type='range']:disabled::-webkit-slider-thumb {
226
- cursor: auto;
227
- }
228
-
229
- input[type='range']::-webkit-slider-thumb {
230
- -webkit-appearance: none;
231
- appearance: none;
232
- width: 1rem;
233
- height: 1rem;
234
- border-radius: 50%;
235
- background: var(--border-color);
236
- cursor: pointer;
237
- pointer-events: auto;
238
- transition: all 0.2s ease;
239
- }
240
-
241
- input[type='range']:disabled::-webkit-slider-thumb {
242
- background: var(--gray-color);
243
- }
244
-
245
- input[type='range']::-moz-range-thumb {
246
- width: 1rem;
247
- height: 1rem;
248
- border-radius: 50%;
249
- background: var(--border-color);
250
- cursor: pointer;
251
- pointer-events: auto;
252
- border: none;
253
- transition: all 0.2s ease;
254
- }
255
-
256
- input[type='range']:disabled::-moz-range-thumb {
257
- background: var(--gray-color);
258
- cursor: not-allowed;
259
- }
260
- </style> -->
1
+ <!-- $lib/ElementsUI/Slider.svelte -->
2
+ <script lang="ts">
3
+ import type { ISliderProps } from '../types'
4
+
5
+ let {
6
+ id = { name: '', value: crypto.randomUUID() },
7
+ wrapperClass = '',
8
+ label = { name: '', class: '' },
9
+ type = 'single',
10
+ value = 0,
11
+ number = { minNum: 0, maxNum: 10, step: 1 },
12
+ disabled = false,
13
+ onUpdate = () => {},
14
+ }: ISliderProps = $props()
15
+
16
+ const isRange = $derived(type === 'range' || (Array.isArray(value) && value.length === 2))
17
+
18
+ const maxDigits = String(number.maxNum ?? 100).length
19
+ const valueWidth = `${maxDigits + 1}ch` /* +1 на запас */
20
+
21
+ /* Инициализация значений с проверкой типа */
22
+ let singleValue = $derived(!isRange && typeof value === 'number' ? value : number.minNum)
23
+ let lowerValue = $derived(isRange && Array.isArray(value) ? value[0] : number.minNum)
24
+ let upperValue = $derived(isRange && Array.isArray(value) ? value[1] : number.maxNum)
25
+
26
+ /* Расчет позиций */
27
+ const singlePosition = $derived(((singleValue - number.minNum) / (number.maxNum - number.minNum)) * 100)
28
+ const lowerPosition = $derived(((lowerValue - number.minNum) / (number.maxNum - number.minNum)) * 100)
29
+ const upperPosition = $derived(((upperValue - number.minNum) / (number.maxNum - number.minNum)) * 100)
30
+
31
+ $effect(() => {
32
+ if (value === undefined || value === null) {
33
+ if (type === 'single' && !value) value = number.minNum
34
+ if (type === 'range' && !value) value = [number.minNum, number.maxNum]
35
+ }
36
+ })
37
+
38
+ const adjustValue = (target: 'lower' | 'upper' | 'single', direction: 'increment' | 'decrement') => {
39
+ const stepValue = direction === 'increment' ? number.step : -number.step
40
+ if (isRange && target !== 'single') {
41
+ if (target === 'lower') {
42
+ lowerValue = Math.max(number.minNum, Math.min(lowerValue + stepValue, upperValue))
43
+ } else {
44
+ upperValue = Math.min(number.maxNum, Math.max(upperValue + stepValue, lowerValue))
45
+ }
46
+ onUpdate([lowerValue, upperValue])
47
+ } else {
48
+ singleValue = Math.max(number.minNum, Math.min(singleValue + stepValue, number.maxNum))
49
+ onUpdate(singleValue)
50
+ }
51
+ }
52
+
53
+ $effect(() => {
54
+ if (Array.isArray(value)) {
55
+ lowerValue = value[0]
56
+ upperValue = value[1]
57
+ } else if (typeof value === 'number') {
58
+ singleValue = value
59
+ }
60
+ })
61
+
62
+ let activeThumb = $state<'lower' | 'upper'>('lower')
63
+ const handleTrackClick = (e: MouseEvent) => {
64
+ e.stopPropagation()
65
+ const track = e.currentTarget as HTMLElement
66
+ const rect = track.getBoundingClientRect()
67
+ const clickPercent = ((e.clientX - rect.left) / rect.width) * 100
68
+ const rawValue = number.minNum + (clickPercent / 100) * (number.maxNum - number.minNum)
69
+ const clickValue = Math.round((rawValue - number.minNum) / number.step) * number.step + number.minNum
70
+
71
+ if (isRange) {
72
+ const lowerDiff = Math.abs(clickValue - lowerValue)
73
+ const upperDiff = Math.abs(clickValue - upperValue)
74
+
75
+ activeThumb = lowerDiff < upperDiff ? 'lower' : 'upper'
76
+
77
+ if (activeThumb === 'lower') {
78
+ lowerValue = Math.max(number.minNum, Math.min(clickValue, upperValue))
79
+ } else {
80
+ upperValue = Math.min(number.maxNum, Math.max(clickValue, lowerValue))
81
+ }
82
+
83
+ onUpdate([lowerValue, upperValue])
84
+ } else {
85
+ singleValue = Math.max(number.minNum, Math.min(clickValue, number.maxNum))
86
+ onUpdate(singleValue)
87
+ }
88
+ }
89
+ </script>
90
+
91
+ <div class={`relative flex w-full flex-col items-center gap-2 ${wrapperClass}`}>
92
+ {#if label.name}
93
+ <h5 class={`w-full px-4 text-center ${label.class}`}>{label.name}</h5>
94
+ {/if}
95
+
96
+ <!-- Слайдер -->
97
+ <div class="relative flex h-2 w-full justify-center {disabled ? 'opacity-50' : ''}" id={id.value}>
98
+ {#if isRange}
99
+ <!-- Трек и активная зона -->
100
+ <div
101
+ class={`absolute h-full w-full rounded bg-gray-400 ${disabled ? '' : 'cursor-pointer'}`}
102
+ role="button"
103
+ tabindex={null}
104
+ onkeydown={null}
105
+ onclick={disabled ? undefined : handleTrackClick}
106
+ >
107
+ <div class="absolute h-full rounded" style={`left: ${lowerPosition}%; right: ${100 - upperPosition}%; background-color: var(--bg-color)`}></div>
108
+ </div>
109
+
110
+ <!-- Ползунки -->
111
+ <input
112
+ type="range"
113
+ min={number.minNum}
114
+ max={number.maxNum}
115
+ step={number.step}
116
+ bind:value={lowerValue}
117
+ oninput={disabled
118
+ ? undefined
119
+ : (e) => {
120
+ const newValue = Math.min(Number((e.target as HTMLInputElement).value), upperValue)
121
+ lowerValue = newValue
122
+ activeThumb = 'lower'
123
+ }}
124
+ onmouseup={disabled ? undefined : () => onUpdate([lowerValue, upperValue])}
125
+ {disabled}
126
+ class={`absolute h-full w-full appearance-none bg-transparent ${activeThumb === 'lower' ? 'z-30' : 'z-20'}`}
127
+ />
128
+
129
+ <input
130
+ type="range"
131
+ min={number.minNum}
132
+ max={number.maxNum}
133
+ step={number.step}
134
+ bind:value={upperValue}
135
+ oninput={disabled
136
+ ? undefined
137
+ : (e) => {
138
+ const newValue = Math.max(Number((e.target as HTMLInputElement).value), lowerValue)
139
+ upperValue = newValue
140
+ activeThumb = 'upper'
141
+ }}
142
+ onmouseup={disabled ? undefined : () => onUpdate([lowerValue, upperValue])}
143
+ {disabled}
144
+ class={`absolute h-full w-full appearance-none bg-transparent ${activeThumb === 'upper' ? 'z-30' : 'z-20'}`}
145
+ />
146
+ {:else}
147
+ <!-- Одиночный слайдер -->
148
+ <div
149
+ class={`absolute h-full w-full rounded bg-gray-400 ${disabled ? '' : 'cursor-pointer'}`}
150
+ role="button"
151
+ tabindex={null}
152
+ onkeydown={null}
153
+ onclick={disabled ? undefined : handleTrackClick}
154
+ >
155
+ <div class="absolute h-full rounded" style={`width: ${singlePosition}%; background-color: var(--bg-color)`}></div>
156
+ </div>
157
+
158
+ <input
159
+ type="range"
160
+ min={number.minNum}
161
+ max={number.maxNum}
162
+ step={number.step}
163
+ bind:value={singleValue}
164
+ oninput={disabled
165
+ ? undefined
166
+ : (e) => {
167
+ singleValue = Number((e.target as HTMLInputElement).value)
168
+ }}
169
+ onmouseup={disabled ? undefined : () => onUpdate(singleValue)}
170
+ {disabled}
171
+ class="absolute z-30 h-full w-full appearance-none bg-transparent"
172
+ />
173
+ {/if}
174
+ </div>
175
+
176
+ <!-- Кнопки управления -->
177
+ <div class={`flex w-full ${isRange ? 'justify-between' : 'justify-center'} gap-2`}>
178
+ {#if isRange}
179
+ {#each ['lower', 'upper'] as type (type)}
180
+ <div class={`flex items-center justify-center gap-2 rounded-full px-2 ${disabled ? 'opacity-70' : ''}`} style="background-color: var(--bg-color)">
181
+ <button
182
+ class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
183
+ onclick={disabled ? undefined : () => adjustValue(type as 'lower' | 'upper', 'decrement')}
184
+ disabled={disabled || (type === 'lower' ? lowerValue <= number.minNum : upperValue <= lowerValue)}>−</button
185
+ >
186
+ <span class="inline-block text-center tabular-nums" style={`width: ${valueWidth}`}>
187
+ {type === 'lower' ? lowerValue : upperValue}
188
+ </span>
189
+ <button
190
+ class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
191
+ onclick={disabled ? undefined : () => adjustValue(type as 'lower' | 'upper', 'increment')}
192
+ disabled={disabled || (type === 'lower' ? lowerValue >= upperValue : upperValue >= number.maxNum)}>+</button
193
+ >
194
+ </div>
195
+ {/each}
196
+ {:else}
197
+ <div class={`flex items-center justify-center gap-2 rounded-full px-2 ${disabled ? 'opacity-70' : ''}`} style="background-color: var(--bg-color)">
198
+ <button
199
+ class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
200
+ onclick={disabled ? undefined : () => adjustValue('single', 'decrement')}
201
+ disabled={disabled || singleValue <= number.minNum}>−</button
202
+ >
203
+ <span class="inline-block text-center tabular-nums" style={`width: ${valueWidth}`}>
204
+ {singleValue}
205
+ </span>
206
+ <button
207
+ class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
208
+ onclick={disabled ? undefined : () => adjustValue('single', 'increment')}
209
+ disabled={disabled || singleValue >= number.maxNum}>+</button
210
+ >
211
+ </div>
212
+ {/if}
213
+ </div>
214
+ </div>
215
+
216
+ <style>
217
+ input[type='range'] {
218
+ -webkit-appearance: none;
219
+ appearance: none;
220
+ margin: 0;
221
+ padding: 0;
222
+ pointer-events: none;
223
+ }
224
+
225
+ input[type='range']:disabled::-webkit-slider-thumb {
226
+ cursor: auto;
227
+ }
228
+
229
+ input[type='range']::-webkit-slider-thumb {
230
+ -webkit-appearance: none;
231
+ appearance: none;
232
+ width: 1rem;
233
+ height: 1rem;
234
+ border-radius: 50%;
235
+ background: var(--border-color);
236
+ cursor: pointer;
237
+ pointer-events: auto;
238
+ transition: all 0.2s ease;
239
+ }
240
+
241
+ input[type='range']:disabled::-webkit-slider-thumb {
242
+ background: var(--gray-color);
243
+ }
244
+
245
+ input[type='range']::-moz-range-thumb {
246
+ width: 1rem;
247
+ height: 1rem;
248
+ border-radius: 50%;
249
+ background: var(--border-color);
250
+ cursor: pointer;
251
+ pointer-events: auto;
252
+ border: none;
253
+ transition: all 0.2s ease;
254
+ }
255
+
256
+ input[type='range']:disabled::-moz-range-thumb {
257
+ background: var(--gray-color);
258
+ cursor: not-allowed;
259
+ }
260
+ </style>