@coreui/vue-pro 5.7.0 → 5.8.1

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 (77) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/date-picker/CDatePicker.d.ts +19 -0
  3. package/dist/cjs/components/date-picker/CDatePicker.js +9 -0
  4. package/dist/cjs/components/date-picker/CDatePicker.js.map +1 -1
  5. package/dist/cjs/components/date-range-picker/CDateRangePicker.d.ts +19 -0
  6. package/dist/cjs/components/date-range-picker/CDateRangePicker.js +26 -1
  7. package/dist/cjs/components/date-range-picker/CDateRangePicker.js.map +1 -1
  8. package/dist/cjs/components/index.d.ts +1 -0
  9. package/dist/cjs/components/index.js +28 -24
  10. package/dist/cjs/components/index.js.map +1 -1
  11. package/dist/cjs/components/nav/CNavItem.d.ts +2 -0
  12. package/dist/cjs/components/nav/CNavItem.js +8 -2
  13. package/dist/cjs/components/nav/CNavItem.js.map +1 -1
  14. package/dist/cjs/components/picker/CPicker.d.ts +19 -0
  15. package/dist/cjs/components/picker/CPicker.js +32 -7
  16. package/dist/cjs/components/picker/CPicker.js.map +1 -1
  17. package/dist/cjs/components/range-slider/CRangeSlider.d.ts +241 -0
  18. package/dist/cjs/components/range-slider/CRangeSlider.js +317 -0
  19. package/dist/cjs/components/range-slider/CRangeSlider.js.map +1 -0
  20. package/dist/cjs/components/range-slider/index.d.ts +6 -0
  21. package/dist/cjs/components/range-slider/index.js +13 -0
  22. package/dist/cjs/components/range-slider/index.js.map +1 -0
  23. package/dist/cjs/components/range-slider/types.d.ts +11 -0
  24. package/dist/cjs/components/range-slider/utils.d.ts +38 -0
  25. package/dist/cjs/components/range-slider/utils.js +172 -0
  26. package/dist/cjs/components/range-slider/utils.js.map +1 -0
  27. package/dist/cjs/components/sidebar/CSidebar.js +0 -1
  28. package/dist/cjs/components/sidebar/CSidebar.js.map +1 -1
  29. package/dist/cjs/components/time-picker/CTimePicker.d.ts +19 -0
  30. package/dist/cjs/components/time-picker/CTimePicker.js +26 -1
  31. package/dist/cjs/components/time-picker/CTimePicker.js.map +1 -1
  32. package/dist/cjs/index.js +34 -30
  33. package/dist/cjs/index.js.map +1 -1
  34. package/dist/esm/components/date-picker/CDatePicker.d.ts +19 -0
  35. package/dist/esm/components/date-picker/CDatePicker.js +9 -0
  36. package/dist/esm/components/date-picker/CDatePicker.js.map +1 -1
  37. package/dist/esm/components/date-range-picker/CDateRangePicker.d.ts +19 -0
  38. package/dist/esm/components/date-range-picker/CDateRangePicker.js +26 -1
  39. package/dist/esm/components/date-range-picker/CDateRangePicker.js.map +1 -1
  40. package/dist/esm/components/index.d.ts +1 -0
  41. package/dist/esm/components/index.js +2 -0
  42. package/dist/esm/components/index.js.map +1 -1
  43. package/dist/esm/components/nav/CNavItem.d.ts +2 -0
  44. package/dist/esm/components/nav/CNavItem.js +8 -2
  45. package/dist/esm/components/nav/CNavItem.js.map +1 -1
  46. package/dist/esm/components/picker/CPicker.d.ts +19 -0
  47. package/dist/esm/components/picker/CPicker.js +32 -7
  48. package/dist/esm/components/picker/CPicker.js.map +1 -1
  49. package/dist/esm/components/range-slider/CRangeSlider.d.ts +241 -0
  50. package/dist/esm/components/range-slider/CRangeSlider.js +315 -0
  51. package/dist/esm/components/range-slider/CRangeSlider.js.map +1 -0
  52. package/dist/esm/components/range-slider/index.d.ts +6 -0
  53. package/dist/esm/components/range-slider/index.js +10 -0
  54. package/dist/esm/components/range-slider/index.js.map +1 -0
  55. package/dist/esm/components/range-slider/types.d.ts +11 -0
  56. package/dist/esm/components/range-slider/utils.d.ts +38 -0
  57. package/dist/esm/components/range-slider/utils.js +157 -0
  58. package/dist/esm/components/range-slider/utils.js.map +1 -0
  59. package/dist/esm/components/sidebar/CSidebar.js +0 -1
  60. package/dist/esm/components/sidebar/CSidebar.js.map +1 -1
  61. package/dist/esm/components/time-picker/CTimePicker.d.ts +19 -0
  62. package/dist/esm/components/time-picker/CTimePicker.js +26 -1
  63. package/dist/esm/components/time-picker/CTimePicker.js.map +1 -1
  64. package/dist/esm/index.js +2 -0
  65. package/dist/esm/index.js.map +1 -1
  66. package/package.json +3 -3
  67. package/src/components/date-picker/CDatePicker.ts +9 -0
  68. package/src/components/date-range-picker/CDateRangePicker.ts +26 -2
  69. package/src/components/index.ts +1 -0
  70. package/src/components/nav/CNavItem.ts +9 -2
  71. package/src/components/picker/CPicker.ts +43 -7
  72. package/src/components/range-slider/CRangeSlider.ts +432 -0
  73. package/src/components/range-slider/index.ts +10 -0
  74. package/src/components/range-slider/types.ts +16 -0
  75. package/src/components/range-slider/utils.ts +247 -0
  76. package/src/components/sidebar/CSidebar.ts +0 -1
  77. package/src/components/time-picker/CTimePicker.ts +26 -1
@@ -0,0 +1,432 @@
1
+ import { defineComponent, ref, watch, onMounted, h, PropType, VNode } from 'vue'
2
+
3
+ import {
4
+ calculateClickValue,
5
+ calculateLabelPosition,
6
+ calculateMoveValue,
7
+ calculateTooltipPosition,
8
+ getLabelValue,
9
+ getNearestValueIndex,
10
+ getThumbSize,
11
+ updateGradient,
12
+ updateValue,
13
+ validateValue,
14
+ } from './utils'
15
+
16
+ import type { Label, ThumbSize } from './types'
17
+
18
+ import { isRTL } from '../../utils'
19
+
20
+ const CRangeSlider = defineComponent({
21
+ name: 'CRangeSlider',
22
+ props: {
23
+ /**
24
+ * Enable or disable clickable labels in the Vue Range Slider.
25
+ * When set to `true`, users can click on labels to adjust the slider's value directly, enhancing interactivity and user experience.
26
+ */
27
+ clickableLabels: {
28
+ type: Boolean,
29
+ default: true,
30
+ },
31
+ /**
32
+ * Control the interactive state of the Vue Range Slider with the `disabled` prop.
33
+ * Setting it to `true` will disable all slider functionalities, preventing user interaction and visually indicating a non-interactive state.
34
+ */
35
+ disabled: {
36
+ type: Boolean,
37
+ default: false,
38
+ },
39
+ /**
40
+ * Define the minimum distance between slider handles using the `distance` prop in the Vue Range Slider.
41
+ * This ensures that the handles maintain a specified separation, preventing overlap and maintaining clear value distinctions.
42
+ */
43
+ distance: {
44
+ type: Number,
45
+ default: 0,
46
+ },
47
+ /**
48
+ * Add descriptive labels to your Vue Range Slider by providing an array of `labels`.
49
+ * These labels enhance the slider's usability by clearly indicating key values and providing contextual information to users.
50
+ */
51
+ labels: {
52
+ type: Array as PropType<Label[]>,
53
+ default: () => [],
54
+ },
55
+ /**
56
+ * Specify the maximum value for the Vue Range Slider with the `max` prop.
57
+ * This determines the upper limit of the slider's range, enabling precise control over the highest selectable value.
58
+ */
59
+ max: {
60
+ type: Number,
61
+ default: 100,
62
+ },
63
+ /**
64
+ * Set the minimum value for the Vue Range Slider using the `min` prop.
65
+ * This defines the lower bound of the slider's range, allowing you to control the starting point of user selection.
66
+ */
67
+ min: {
68
+ type: Number,
69
+ default: 0,
70
+ },
71
+ /**
72
+ * The default name for a value passed using v-model.
73
+ */
74
+ modelValue: [Number, Array] as PropType<number | number[]>,
75
+ /**
76
+ * Assign a `name` to the Vue Range Slider for form integration.
77
+ * Whether using a single string or an array of strings, this prop ensures that the slider's values are correctly identified when submitting forms.
78
+ */
79
+ name: {
80
+ type: [String, Array] as PropType<string | string[]>,
81
+ default: '',
82
+ },
83
+ /**
84
+ * Control the granularity of the Vue Range Slider by setting the `step` prop.
85
+ * This defines the increment intervals between selectable values, allowing for precise adjustments based on your application's requirements.
86
+ */
87
+ step: {
88
+ type: Number,
89
+ default: 1,
90
+ },
91
+ /**
92
+ * Toggle the visibility of tooltips in the Vue Range Slider with the `tooltips` prop.
93
+ * When enabled, tooltips display the current value of the slider handles, providing real-time feedback to users.
94
+ */
95
+ tooltips: {
96
+ type: Boolean,
97
+ default: true,
98
+ },
99
+ /**
100
+ * Customize the display format of tooltips in the Vue Range Slider using the `tooltipsFormat` function.
101
+ * This allows you to format the tooltip values according to your specific requirements, enhancing the clarity and presentation of information.
102
+ */
103
+ tooltipsFormat: {
104
+ type: Function as PropType<(value: number) => string | VNode>,
105
+ default: null,
106
+ },
107
+ /**
108
+ * Controls the visual representation of the slider's track. When set to `'fill'`, the track is dynamically filled based on the slider's value(s). Setting it to `false` disables the filled track.
109
+ */
110
+ track: {
111
+ type: [Boolean, String],
112
+ default: 'fill',
113
+ validator: (value: boolean | string) => {
114
+ return typeof value === 'boolean' || value === 'fill'
115
+ },
116
+ },
117
+ /**
118
+ * Set the current value(s) of the Vue Range Slider using the `value` prop.
119
+ * Whether you're using a single value or an array for multi-handle sliders, this prop controls the slider's position and ensures it reflects the desired state.
120
+ */
121
+ value: {
122
+ type: [Number, Array] as PropType<number | number[]>,
123
+ default: () => [0],
124
+ },
125
+ /**
126
+ * Orient the Vue Range Slider vertically by setting the `vertical` prop to `true`.
127
+ * This changes the slider's layout from horizontal to vertical, providing a different aesthetic and fitting various UI designs.
128
+ */
129
+ vertical: {
130
+ type: Boolean,
131
+ default: false,
132
+ },
133
+ },
134
+ emits: [
135
+ 'change',
136
+ /**
137
+ * Emit the new value whenever there’s a change event.
138
+ */
139
+ 'update:modelValue',
140
+ ],
141
+ setup(props, { emit }) {
142
+ const rangeSliderRef = ref<HTMLDivElement | null>(null)
143
+ const inputsRef = ref<HTMLInputElement[]>([])
144
+ const labelsContainerRef = ref<HTMLDivElement | null>(null)
145
+ const labelsRef = ref<HTMLDivElement[]>([])
146
+ const trackRef = ref<HTMLDivElement | null>(null)
147
+
148
+ const currentValue = ref<number[]>(
149
+ props.modelValue
150
+ ? Array.isArray(props.modelValue)
151
+ ? props.modelValue
152
+ : [props.modelValue]
153
+ : Array.isArray(props.value)
154
+ ? props.value
155
+ : [props.value],
156
+ )
157
+ const isDragging = ref(false)
158
+ const _isRTL = ref(false)
159
+ const dragIndex = ref(0)
160
+ const thumbSize = ref<ThumbSize | null>()
161
+
162
+ watch(
163
+ () => props.value,
164
+ (newVal) => {
165
+ currentValue.value = Array.isArray(newVal) ? newVal : [newVal]
166
+ },
167
+ )
168
+
169
+ watch(
170
+ () => props.modelValue,
171
+ (newVal) => {
172
+ if (newVal !== undefined) {
173
+ currentValue.value = Array.isArray(newVal) ? newVal : [newVal]
174
+ }
175
+ },
176
+ )
177
+
178
+ // Adjust labels container size based on labels
179
+ onMounted(() => {
180
+ const maxSize = Math.max(
181
+ ...labelsRef.value.map((label) =>
182
+ props.vertical ? label.offsetWidth : label.offsetHeight,
183
+ ),
184
+ )
185
+
186
+ if (labelsContainerRef.value) {
187
+ labelsContainerRef.value.style[props.vertical ? 'width' : 'height'] = `${maxSize}px`
188
+ }
189
+
190
+ if (rangeSliderRef.value) {
191
+ _isRTL.value = isRTL(rangeSliderRef.value)
192
+ thumbSize.value = getThumbSize(rangeSliderRef.value, props.vertical)
193
+ }
194
+ })
195
+
196
+ watch(isDragging, (newVal) => {
197
+ if (newVal) {
198
+ globalThis.addEventListener('mousemove', handleMouseMove)
199
+ globalThis.addEventListener('mouseup', handleMouseUp)
200
+ } else {
201
+ globalThis.removeEventListener('mousemove', handleMouseMove)
202
+ globalThis.removeEventListener('mouseup', handleMouseUp)
203
+ }
204
+ })
205
+
206
+ const updateNearestValue = (value: number) => {
207
+ const nearestIndex = getNearestValueIndex(value, currentValue.value)
208
+ const newCurrentValue = [...currentValue.value]
209
+ newCurrentValue[nearestIndex] = validateValue(
210
+ value,
211
+ currentValue.value,
212
+ props.distance,
213
+ nearestIndex,
214
+ )
215
+
216
+ setTimeout(() => {
217
+ if (inputsRef.value[nearestIndex]) {
218
+ inputsRef.value[nearestIndex].focus()
219
+ }
220
+ }, 0)
221
+
222
+ currentValue.value = newCurrentValue
223
+
224
+ emit('change', newCurrentValue)
225
+ emit('update:modelValue', newCurrentValue)
226
+ }
227
+
228
+ const handleInputChange = (event: Event, index: number) => {
229
+ if (props.disabled) return
230
+
231
+ const target = event.target as HTMLInputElement
232
+ const value = Number(target.value)
233
+
234
+ const newCurrentValue = updateValue(value, currentValue.value, props.distance, index)
235
+
236
+ currentValue.value = newCurrentValue
237
+
238
+ emit('change', newCurrentValue)
239
+ emit('update:modelValue', newCurrentValue)
240
+ }
241
+
242
+ const handleInputsContainerMouseDown = (event: MouseEvent) => {
243
+ if (!trackRef.value || event.button !== 0) return
244
+
245
+ const clickValue = calculateClickValue(
246
+ event,
247
+ trackRef.value,
248
+ props.min,
249
+ props.max,
250
+ props.step,
251
+ props.vertical,
252
+ _isRTL.value,
253
+ )
254
+
255
+ const index = getNearestValueIndex(clickValue, currentValue.value)
256
+
257
+ isDragging.value = true
258
+ dragIndex.value = index
259
+ updateNearestValue(clickValue)
260
+ }
261
+
262
+ const handleLabelClick = (event: MouseEvent, value: number) => {
263
+ if (!props.clickableLabels || props.disabled || event.button !== 0) return
264
+
265
+ updateNearestValue(value)
266
+ }
267
+
268
+ const handleMouseMove = (event: MouseEvent) => {
269
+ if (!isDragging.value || !trackRef.value) return
270
+
271
+ const moveValue = calculateMoveValue(
272
+ event,
273
+ trackRef.value,
274
+ props.min,
275
+ props.max,
276
+ props.step,
277
+ props.vertical,
278
+ _isRTL.value,
279
+ )
280
+
281
+ const newCurrentValue = updateValue(
282
+ moveValue,
283
+ currentValue.value,
284
+ props.distance,
285
+ dragIndex.value,
286
+ )
287
+
288
+ currentValue.value = newCurrentValue
289
+
290
+ emit('change', newCurrentValue)
291
+ emit('update:modelValue', newCurrentValue)
292
+ }
293
+
294
+ const handleMouseUp = () => {
295
+ isDragging.value = false
296
+ }
297
+
298
+ return () =>
299
+ h(
300
+ 'div',
301
+ {
302
+ class: [
303
+ 'range-slider',
304
+ {
305
+ 'range-slider-vertical': props.vertical,
306
+ disabled: props.disabled,
307
+ },
308
+ ],
309
+ ref: rangeSliderRef,
310
+ },
311
+ [
312
+ h(
313
+ 'div',
314
+ {
315
+ class: 'range-slider-inputs-container',
316
+ onMousedown: handleInputsContainerMouseDown,
317
+ },
318
+ [
319
+ currentValue.value.map((value, index) => [
320
+ h('input', {
321
+ class: 'range-slider-input',
322
+ type: 'range',
323
+ min: props.min,
324
+ max: props.max,
325
+ step: props.step,
326
+ value: value,
327
+ name: Array.isArray(props.name)
328
+ ? props.name[index]
329
+ : `${props.name || ''}-${index}`,
330
+ role: 'slider',
331
+ 'aria-valuemin': props.min,
332
+ 'aria-valuemax': props.max,
333
+ 'aria-valuenow': value,
334
+ 'aria-orientation': props.vertical ? 'vertical' : 'horizontal',
335
+ disabled: props.disabled,
336
+ onInput: (e: Event) => handleInputChange(e, index),
337
+ ref: (el) => {
338
+ inputsRef.value[index] = el as HTMLInputElement
339
+ },
340
+ }),
341
+ props.tooltips &&
342
+ h(
343
+ 'div',
344
+ {
345
+ class: 'range-slider-tooltip',
346
+ ...(thumbSize.value && {
347
+ style: calculateTooltipPosition(
348
+ props.min,
349
+ props.max,
350
+ value,
351
+ thumbSize.value,
352
+ props.vertical,
353
+ _isRTL.value,
354
+ ),
355
+ }),
356
+ },
357
+ [
358
+ h('div', { class: 'range-slider-tooltip-inner' }, [
359
+ props.tooltipsFormat ? props.tooltipsFormat(value) : value,
360
+ ]),
361
+ h('div', { class: 'range-slider-tooltip-arrow' }),
362
+ ],
363
+ ),
364
+ ]),
365
+ h('div', {
366
+ class: 'range-slider-track',
367
+ ...(props.track && {
368
+ style: updateGradient(
369
+ props.min,
370
+ props.max,
371
+ currentValue.value,
372
+ props.vertical,
373
+ _isRTL.value,
374
+ ),
375
+ }),
376
+ ref: trackRef,
377
+ }),
378
+ ],
379
+ ),
380
+ Array.isArray(props.labels) &&
381
+ props.labels.length > 0 &&
382
+ h(
383
+ 'div',
384
+ {
385
+ class: 'range-slider-labels-container',
386
+ ref: labelsContainerRef,
387
+ },
388
+ props.labels.map((label, index) => {
389
+ const labelPosition = calculateLabelPosition(
390
+ props.min,
391
+ props.max,
392
+ props.labels,
393
+ label,
394
+ index,
395
+ )
396
+ const labelValue = getLabelValue(props.min, props.max, props.labels, label, index)
397
+ const labelStyle = {
398
+ ...(props.vertical
399
+ ? { bottom: labelPosition }
400
+ : _isRTL.value
401
+ ? { right: labelPosition }
402
+ : { left: labelPosition }),
403
+ ...(typeof label === 'object' && 'style' in label ? label.style : {}),
404
+ }
405
+
406
+ return h(
407
+ 'div',
408
+ {
409
+ class: [
410
+ 'range-slider-label',
411
+ {
412
+ clickable: props.clickableLabels,
413
+ },
414
+ typeof label === 'object' && 'className' in label ? label.className : '',
415
+ ],
416
+ style: labelStyle,
417
+ onMousedown: (event) => handleLabelClick(event, labelValue),
418
+ key: index,
419
+ ref: (el) => {
420
+ labelsRef.value[index] = el as HTMLDivElement
421
+ },
422
+ },
423
+ typeof label === 'object' && 'label' in label ? label.label : label,
424
+ )
425
+ }),
426
+ ),
427
+ ],
428
+ )
429
+ },
430
+ })
431
+
432
+ export { CRangeSlider }
@@ -0,0 +1,10 @@
1
+ import { App } from 'vue'
2
+ import { CRangeSlider } from './CRangeSlider'
3
+
4
+ const CRangeSliderPlugin = {
5
+ install: (app: App): void => {
6
+ app.component(CRangeSlider.name as string, CRangeSlider)
7
+ },
8
+ }
9
+
10
+ export { CRangeSliderPlugin, CRangeSlider }
@@ -0,0 +1,16 @@
1
+ import type { VNode } from 'vue'
2
+
3
+ export type Label =
4
+ | {
5
+ label: number | string | VNode
6
+ value: number
7
+ className?: string | string[] | Record<string, boolean>
8
+ style?: Record<string, any> // Alternatively, you can use `CSSProperties` from Vue
9
+ }
10
+ | VNode
11
+ | string
12
+
13
+ export type ThumbSize = {
14
+ value: number
15
+ unit: string | null
16
+ }
@@ -0,0 +1,247 @@
1
+ import type { Label, ThumbSize } from './types'
2
+
3
+ export const calculateClickValue = (
4
+ event: MouseEvent,
5
+ container: HTMLDivElement,
6
+ min: number,
7
+ max: number,
8
+ step: number,
9
+ vertical: boolean,
10
+ rtl: boolean,
11
+ ) => {
12
+ const clickPosition = getClickPosition(event, container, vertical, rtl)
13
+ const value = min + clickPosition * (max - min)
14
+ return roundToStep(value, step)
15
+ }
16
+
17
+ export const calculateMoveValue = (
18
+ event: MouseEvent,
19
+ container: HTMLDivElement,
20
+ min: number,
21
+ max: number,
22
+ step: number,
23
+ vertical: boolean,
24
+ rtl: boolean,
25
+ ) => {
26
+ const rect = container.getBoundingClientRect()
27
+ const position = vertical
28
+ ? calculateVerticalPosition(event.clientY, rect)
29
+ : calculateHorizontalPosition(event.clientX, rect, rtl)
30
+
31
+ if (typeof position === 'string') {
32
+ return position === 'max' ? max : min
33
+ }
34
+
35
+ const value = min + position * (max - min)
36
+
37
+ return roundToStep(value, step)
38
+ }
39
+
40
+ export const calculateVerticalPosition = (mouseY: number, rect: DOMRect) => {
41
+ if (mouseY < rect.top) {
42
+ return 'max'
43
+ }
44
+
45
+ if (mouseY > rect.bottom) {
46
+ return 'min'
47
+ }
48
+
49
+ return Math.min(Math.max((rect.bottom - mouseY) / rect.height, 0), 1)
50
+ }
51
+
52
+ export const calculateHorizontalPosition = (mouseX: number, rect: DOMRect, rtl: boolean) => {
53
+ if (mouseX < rect.left) {
54
+ return rtl ? 'max' : 'min'
55
+ }
56
+
57
+ if (mouseX > rect.right) {
58
+ return rtl ? 'min' : 'max'
59
+ }
60
+
61
+ const relativeX = rtl ? rect.right - mouseX : mouseX - rect.left
62
+ return Math.min(Math.max(relativeX / rect.width, 0), 1)
63
+ }
64
+
65
+ export const calculateLabelPosition = (
66
+ min: number,
67
+ max: number,
68
+ labels: Label[],
69
+ label: Label,
70
+ index: number,
71
+ ) => {
72
+ if (typeof label === 'object' && 'value' in label) {
73
+ return `${((label.value - min) / (max - min)) * 100}%`
74
+ }
75
+
76
+ return `${(index / (labels.length - 1)) * 100}%`
77
+ }
78
+
79
+ export const calculateTooltipPosition = (
80
+ min: number,
81
+ max: number,
82
+ value: number,
83
+ thumbSize: ThumbSize,
84
+ vertical: boolean,
85
+ rtl: boolean,
86
+ ) => {
87
+ const percent = (value - min) / (max - min)
88
+ const margin =
89
+ percent > 0.5
90
+ ? `-${(percent - 0.5) * thumbSize.value}${thumbSize.unit}`
91
+ : `${(0.5 - percent) * thumbSize.value}${thumbSize.unit}`
92
+
93
+ if (vertical) {
94
+ return {
95
+ bottom: `${percent * 100}%`,
96
+ marginBottom: margin,
97
+ }
98
+ }
99
+
100
+ return rtl
101
+ ? { right: `${percent * 100}%`, marginRight: margin }
102
+ : { left: `${percent * 100}%`, marginLeft: margin }
103
+ }
104
+
105
+ export const getClickPosition = (
106
+ event: MouseEvent,
107
+ container: HTMLDivElement,
108
+ vertical: boolean,
109
+ rtl: boolean,
110
+ ) => {
111
+ const { offsetX, offsetY } = event
112
+ const { offsetWidth, offsetHeight } = container
113
+
114
+ if (vertical) {
115
+ return 1 - offsetY / offsetHeight
116
+ }
117
+
118
+ return rtl ? 1 - offsetX / offsetWidth : offsetX / offsetWidth
119
+ }
120
+
121
+ export const getLabelValue = (
122
+ min: number,
123
+ max: number,
124
+ labels: Label[],
125
+ label: Label,
126
+ index: number,
127
+ ) =>
128
+ typeof label === 'object' && 'value' in label
129
+ ? label.value
130
+ : min + (index / (labels.length - 1)) * (max - min)
131
+
132
+ export const getNearestValueIndex = (value: number, values: number[]) => {
133
+ const valuesLength = values.length
134
+
135
+ if (value < values[0]) {
136
+ return 0
137
+ }
138
+
139
+ if (value > values[valuesLength - 1]) {
140
+ return valuesLength - 1
141
+ }
142
+
143
+ const distances = values.map((v) => Math.abs(v - value))
144
+ const min = Math.min(...distances)
145
+ const firstIndex = distances.indexOf(min)
146
+
147
+ return value < values[firstIndex] ? firstIndex : distances.lastIndexOf(min)
148
+ }
149
+
150
+ export const getThumbSize = (element: HTMLDivElement, vertical: boolean): ThumbSize | null => {
151
+ const value = globalThis
152
+ .getComputedStyle(element, null)
153
+ .getPropertyValue(
154
+ vertical ? '--cui-range-slider-thumb-height' : '--cui-range-slider-thumb-width',
155
+ )
156
+
157
+ const regex = /^(\d+\.?\d*)([%a-z]*)$/i
158
+ const match = value.match(regex)
159
+
160
+ if (match) {
161
+ return {
162
+ value: Number.parseFloat(match[1]),
163
+ unit: match[2] || null,
164
+ }
165
+ }
166
+
167
+ return null
168
+ }
169
+
170
+ export const roundToStep = (number: number, step: number) => {
171
+ const _step = step === 0 ? 1 : step
172
+ return Math.round(number / _step) * _step
173
+ }
174
+
175
+ export const updateGradient = (
176
+ min: number,
177
+ max: number,
178
+ values: number[],
179
+ vertical: boolean,
180
+ rtl: boolean,
181
+ ) => {
182
+ const minVal = Math.min(...values)
183
+ const maxVal = Math.max(...values)
184
+
185
+ const from = ((minVal - min) / (max - min)) * 100
186
+ const to = ((maxVal - min) / (max - min)) * 100
187
+
188
+ const direction = vertical ? 'to top' : rtl ? 'to left' : 'to right'
189
+
190
+ return {
191
+ backgroundImage:
192
+ values.length === 1
193
+ ? `linear-gradient(
194
+ ${direction},
195
+ var(--cui-range-slider-track-in-range-bg) 0%,
196
+ var(--cui-range-slider-track-in-range-bg) ${to}%,
197
+ transparent ${to}%,
198
+ transparent 100%
199
+ )`
200
+ : `linear-gradient(
201
+ ${direction},
202
+ transparent 0%,
203
+ transparent ${from}%,
204
+ var(--cui-range-slider-track-in-range-bg) ${from}%,
205
+ var(--cui-range-slider-track-in-range-bg) ${to}%,
206
+ transparent ${to}%,
207
+ transparent 100%
208
+ )`,
209
+ }
210
+ }
211
+
212
+ export const updateValue = (value: number, values: number[], distance: number, index: number) => {
213
+ const newValue = [...values]
214
+ newValue[index] = validateValue(value, values, distance, index)
215
+ return newValue
216
+ }
217
+
218
+ export const validateValue = (value: number, values: number[], distance: number, index: number) => {
219
+ // If there's only one value, return it as is
220
+ if (values.length === 1) {
221
+ return value
222
+ }
223
+
224
+ // Determine previous and next values if they exist
225
+ const prevValue: number | undefined = index > 0 ? values[index - 1] : undefined
226
+ const nextValue: number | undefined = index < values.length - 1 ? values[index + 1] : undefined
227
+
228
+ // If it's the first element, ensure it's not too close to the next value
229
+ if (index === 0 && nextValue !== undefined) {
230
+ return Math.min(value, nextValue - distance)
231
+ }
232
+
233
+ // If it's the last element, ensure it's not too close to the previous value
234
+ if (index === values.length - 1 && prevValue !== undefined) {
235
+ return Math.max(value, prevValue + distance)
236
+ }
237
+
238
+ // For middle elements, ensure the value is within the allowed distance from both neighbors
239
+ if (prevValue !== undefined && nextValue !== undefined) {
240
+ const minVal = prevValue + distance
241
+ const maxVal = nextValue - distance
242
+ return Math.min(Math.max(value, minVal), maxVal)
243
+ }
244
+
245
+ // Fallback: If for some reason prevValue or nextValue is undefined, return the original value
246
+ return value
247
+ }
@@ -111,7 +111,6 @@ const CSidebar = defineComponent({
111
111
 
112
112
  watch(mobile, () => {
113
113
  if (mobile.value) {
114
- console.log('mobile')
115
114
  visibleMobile.value = false
116
115
  }
117
116
  })