@sit-onyx/headless 0.3.0-dev-20251027185548 → 0.3.0-dev-20251027213347
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/dist/composables/slider/DiscreteSlider.d.vue.ts +101 -0
- package/dist/composables/slider/RangeSlider.d.vue.ts +101 -0
- package/dist/composables/slider/SimpleSlider.d.vue.ts +101 -0
- package/dist/composables/slider/TestSlider.ct.d.ts +1 -0
- package/dist/composables/slider/createSlider.d.ts +262 -0
- package/dist/composables/slider/createSlider.testing.d.ts +49 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +617 -1
- package/dist/utils/FocusVisibleTest.d.vue.ts +4 -0
- package/dist/utils/TouchEventTest.d.vue.ts +4 -0
- package/dist/utils/array.d.ts +3 -0
- package/dist/utils/array.spec.d.ts +1 -0
- package/dist/utils/dom.ct.d.ts +1 -0
- package/dist/utils/dom.d.ts +16 -0
- package/dist/utils/math.d.ts +27 -0
- package/package.json +1 -1
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {
|
|
2
|
+
slider: import('../../index.js', { with: { "resolution-mode": "import" } }).HeadlessComposable<{
|
|
3
|
+
root: import('vue').ComputedRef<{
|
|
4
|
+
ref: import('../../index.js', { with: { "resolution-mode": "import" } }).HeadlessElRef<HTMLElement>;
|
|
5
|
+
style: {
|
|
6
|
+
touchAction: "pan-x" | "pan-y";
|
|
7
|
+
};
|
|
8
|
+
onMousedown: (event: MouseEvent) => void;
|
|
9
|
+
onTouchstart: (event: TouchEvent) => void;
|
|
10
|
+
}>;
|
|
11
|
+
thumbContainer: import('vue').ComputedRef<(data: {
|
|
12
|
+
index: number;
|
|
13
|
+
value: number;
|
|
14
|
+
}) => {
|
|
15
|
+
"data-index": number;
|
|
16
|
+
style: {
|
|
17
|
+
[x: string]: string;
|
|
18
|
+
};
|
|
19
|
+
}>;
|
|
20
|
+
thumbInput: import('vue').ComputedRef<(data: {
|
|
21
|
+
index: number;
|
|
22
|
+
value: number;
|
|
23
|
+
}) => {
|
|
24
|
+
min: number;
|
|
25
|
+
max: number;
|
|
26
|
+
value: number;
|
|
27
|
+
role: string;
|
|
28
|
+
type: string;
|
|
29
|
+
"aria-label": string;
|
|
30
|
+
"aria-valuemin": number;
|
|
31
|
+
"aria-valuemax": number;
|
|
32
|
+
"aria-valuenow": number;
|
|
33
|
+
"aria-orientation": import('./createSlider.js', { with: { "resolution-mode": "import" } }).SliderOrientation;
|
|
34
|
+
"data-index": number;
|
|
35
|
+
tabIndex: number;
|
|
36
|
+
step: string | number;
|
|
37
|
+
disabled: boolean;
|
|
38
|
+
onChange: (event: Event) => void;
|
|
39
|
+
onFocus: (event: FocusEvent) => void;
|
|
40
|
+
onBlur: (event: FocusEvent) => void;
|
|
41
|
+
onKeydown: (event: KeyboardEvent) => void;
|
|
42
|
+
}>;
|
|
43
|
+
mark: import('vue').ComputedRef<(data: {
|
|
44
|
+
value: number;
|
|
45
|
+
label?: string;
|
|
46
|
+
}) => {
|
|
47
|
+
"data-value": number;
|
|
48
|
+
"aria-hidden": true;
|
|
49
|
+
style: {
|
|
50
|
+
[x: string]: string;
|
|
51
|
+
};
|
|
52
|
+
}>;
|
|
53
|
+
markLabel: import('vue').ComputedRef<(data: {
|
|
54
|
+
value: number;
|
|
55
|
+
}) => {
|
|
56
|
+
"data-value": number;
|
|
57
|
+
style: {
|
|
58
|
+
[x: string]: string;
|
|
59
|
+
};
|
|
60
|
+
"aria-hidden": true;
|
|
61
|
+
}>;
|
|
62
|
+
track: import('vue').ComputedRef<{
|
|
63
|
+
role: string;
|
|
64
|
+
"aria-hidden": true;
|
|
65
|
+
style: {
|
|
66
|
+
[x: string]: string;
|
|
67
|
+
};
|
|
68
|
+
}>;
|
|
69
|
+
rail: import('vue').ComputedRef<{
|
|
70
|
+
role: string;
|
|
71
|
+
"aria-hidden": true;
|
|
72
|
+
}>;
|
|
73
|
+
}, {
|
|
74
|
+
isDragging: import('vue').Ref<boolean, boolean>;
|
|
75
|
+
activeThumbIndex: import('vue').Ref<number, number>;
|
|
76
|
+
focusedThumbIndex: import('vue').Ref<number, number>;
|
|
77
|
+
isRange: import('vue').ComputedRef<boolean>;
|
|
78
|
+
trackOffset: import('vue').ComputedRef<number>;
|
|
79
|
+
trackLength: import('vue').ComputedRef<number>;
|
|
80
|
+
marksList: import('vue').ComputedRef<{
|
|
81
|
+
value: number;
|
|
82
|
+
label?: string;
|
|
83
|
+
}[]>;
|
|
84
|
+
}, {
|
|
85
|
+
valueToPercent: import('vue').ComputedRef<(value: number) => number>;
|
|
86
|
+
isMarkActive: import('vue').ComputedRef<(markValue: number) => boolean>;
|
|
87
|
+
clampValue: import('vue').ComputedRef<(value: number) => number>;
|
|
88
|
+
axis: import('vue').ComputedRef<{
|
|
89
|
+
position: "bottom";
|
|
90
|
+
size: "height";
|
|
91
|
+
cross: "width";
|
|
92
|
+
} | {
|
|
93
|
+
position: "left";
|
|
94
|
+
size: "width";
|
|
95
|
+
cross: "height";
|
|
96
|
+
}>;
|
|
97
|
+
roundToStep: import('vue').ComputedRef<(value: number) => number | undefined>;
|
|
98
|
+
normalizeValues: import('vue').ComputedRef<(values: number[]) => number[]>;
|
|
99
|
+
}>;
|
|
100
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
|
|
101
|
+
export default _default;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {
|
|
2
|
+
slider: import('../../index.js', { with: { "resolution-mode": "import" } }).HeadlessComposable<{
|
|
3
|
+
root: import('vue').ComputedRef<{
|
|
4
|
+
ref: import('../../index.js', { with: { "resolution-mode": "import" } }).HeadlessElRef<HTMLElement>;
|
|
5
|
+
style: {
|
|
6
|
+
touchAction: "pan-x" | "pan-y";
|
|
7
|
+
};
|
|
8
|
+
onMousedown: (event: MouseEvent) => void;
|
|
9
|
+
onTouchstart: (event: TouchEvent) => void;
|
|
10
|
+
}>;
|
|
11
|
+
thumbContainer: import('vue').ComputedRef<(data: {
|
|
12
|
+
index: number;
|
|
13
|
+
value: number;
|
|
14
|
+
}) => {
|
|
15
|
+
"data-index": number;
|
|
16
|
+
style: {
|
|
17
|
+
[x: string]: string;
|
|
18
|
+
};
|
|
19
|
+
}>;
|
|
20
|
+
thumbInput: import('vue').ComputedRef<(data: {
|
|
21
|
+
index: number;
|
|
22
|
+
value: number;
|
|
23
|
+
}) => {
|
|
24
|
+
min: number;
|
|
25
|
+
max: number;
|
|
26
|
+
value: number;
|
|
27
|
+
role: string;
|
|
28
|
+
type: string;
|
|
29
|
+
"aria-label": string;
|
|
30
|
+
"aria-valuemin": number;
|
|
31
|
+
"aria-valuemax": number;
|
|
32
|
+
"aria-valuenow": number;
|
|
33
|
+
"aria-orientation": import('./createSlider.js', { with: { "resolution-mode": "import" } }).SliderOrientation;
|
|
34
|
+
"data-index": number;
|
|
35
|
+
tabIndex: number;
|
|
36
|
+
step: string | number;
|
|
37
|
+
disabled: boolean;
|
|
38
|
+
onChange: (event: Event) => void;
|
|
39
|
+
onFocus: (event: FocusEvent) => void;
|
|
40
|
+
onBlur: (event: FocusEvent) => void;
|
|
41
|
+
onKeydown: (event: KeyboardEvent) => void;
|
|
42
|
+
}>;
|
|
43
|
+
mark: import('vue').ComputedRef<(data: {
|
|
44
|
+
value: number;
|
|
45
|
+
label?: string;
|
|
46
|
+
}) => {
|
|
47
|
+
"data-value": number;
|
|
48
|
+
"aria-hidden": true;
|
|
49
|
+
style: {
|
|
50
|
+
[x: string]: string;
|
|
51
|
+
};
|
|
52
|
+
}>;
|
|
53
|
+
markLabel: import('vue').ComputedRef<(data: {
|
|
54
|
+
value: number;
|
|
55
|
+
}) => {
|
|
56
|
+
"data-value": number;
|
|
57
|
+
style: {
|
|
58
|
+
[x: string]: string;
|
|
59
|
+
};
|
|
60
|
+
"aria-hidden": true;
|
|
61
|
+
}>;
|
|
62
|
+
track: import('vue').ComputedRef<{
|
|
63
|
+
role: string;
|
|
64
|
+
"aria-hidden": true;
|
|
65
|
+
style: {
|
|
66
|
+
[x: string]: string;
|
|
67
|
+
};
|
|
68
|
+
}>;
|
|
69
|
+
rail: import('vue').ComputedRef<{
|
|
70
|
+
role: string;
|
|
71
|
+
"aria-hidden": true;
|
|
72
|
+
}>;
|
|
73
|
+
}, {
|
|
74
|
+
isDragging: import('vue').Ref<boolean, boolean>;
|
|
75
|
+
activeThumbIndex: import('vue').Ref<number, number>;
|
|
76
|
+
focusedThumbIndex: import('vue').Ref<number, number>;
|
|
77
|
+
isRange: import('vue').ComputedRef<boolean>;
|
|
78
|
+
trackOffset: import('vue').ComputedRef<number>;
|
|
79
|
+
trackLength: import('vue').ComputedRef<number>;
|
|
80
|
+
marksList: import('vue').ComputedRef<{
|
|
81
|
+
value: number;
|
|
82
|
+
label?: string;
|
|
83
|
+
}[]>;
|
|
84
|
+
}, {
|
|
85
|
+
valueToPercent: import('vue').ComputedRef<(value: number) => number>;
|
|
86
|
+
isMarkActive: import('vue').ComputedRef<(markValue: number) => boolean>;
|
|
87
|
+
clampValue: import('vue').ComputedRef<(value: number) => number>;
|
|
88
|
+
axis: import('vue').ComputedRef<{
|
|
89
|
+
position: "bottom";
|
|
90
|
+
size: "height";
|
|
91
|
+
cross: "width";
|
|
92
|
+
} | {
|
|
93
|
+
position: "left";
|
|
94
|
+
size: "width";
|
|
95
|
+
cross: "height";
|
|
96
|
+
}>;
|
|
97
|
+
roundToStep: import('vue').ComputedRef<(value: number) => number | undefined>;
|
|
98
|
+
normalizeValues: import('vue').ComputedRef<(values: number[]) => number[]>;
|
|
99
|
+
}>;
|
|
100
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
|
|
101
|
+
export default _default;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {
|
|
2
|
+
slider: import('../../index.js', { with: { "resolution-mode": "import" } }).HeadlessComposable<{
|
|
3
|
+
root: import('vue').ComputedRef<{
|
|
4
|
+
ref: import('../../index.js', { with: { "resolution-mode": "import" } }).HeadlessElRef<HTMLElement>;
|
|
5
|
+
style: {
|
|
6
|
+
touchAction: "pan-x" | "pan-y";
|
|
7
|
+
};
|
|
8
|
+
onMousedown: (event: MouseEvent) => void;
|
|
9
|
+
onTouchstart: (event: TouchEvent) => void;
|
|
10
|
+
}>;
|
|
11
|
+
thumbContainer: import('vue').ComputedRef<(data: {
|
|
12
|
+
index: number;
|
|
13
|
+
value: number;
|
|
14
|
+
}) => {
|
|
15
|
+
"data-index": number;
|
|
16
|
+
style: {
|
|
17
|
+
[x: string]: string;
|
|
18
|
+
};
|
|
19
|
+
}>;
|
|
20
|
+
thumbInput: import('vue').ComputedRef<(data: {
|
|
21
|
+
index: number;
|
|
22
|
+
value: number;
|
|
23
|
+
}) => {
|
|
24
|
+
min: number;
|
|
25
|
+
max: number;
|
|
26
|
+
value: number;
|
|
27
|
+
role: string;
|
|
28
|
+
type: string;
|
|
29
|
+
"aria-label": string;
|
|
30
|
+
"aria-valuemin": number;
|
|
31
|
+
"aria-valuemax": number;
|
|
32
|
+
"aria-valuenow": number;
|
|
33
|
+
"aria-orientation": import('./createSlider.js', { with: { "resolution-mode": "import" } }).SliderOrientation;
|
|
34
|
+
"data-index": number;
|
|
35
|
+
tabIndex: number;
|
|
36
|
+
step: string | number;
|
|
37
|
+
disabled: boolean;
|
|
38
|
+
onChange: (event: Event) => void;
|
|
39
|
+
onFocus: (event: FocusEvent) => void;
|
|
40
|
+
onBlur: (event: FocusEvent) => void;
|
|
41
|
+
onKeydown: (event: KeyboardEvent) => void;
|
|
42
|
+
}>;
|
|
43
|
+
mark: import('vue').ComputedRef<(data: {
|
|
44
|
+
value: number;
|
|
45
|
+
label?: string;
|
|
46
|
+
}) => {
|
|
47
|
+
"data-value": number;
|
|
48
|
+
"aria-hidden": true;
|
|
49
|
+
style: {
|
|
50
|
+
[x: string]: string;
|
|
51
|
+
};
|
|
52
|
+
}>;
|
|
53
|
+
markLabel: import('vue').ComputedRef<(data: {
|
|
54
|
+
value: number;
|
|
55
|
+
}) => {
|
|
56
|
+
"data-value": number;
|
|
57
|
+
style: {
|
|
58
|
+
[x: string]: string;
|
|
59
|
+
};
|
|
60
|
+
"aria-hidden": true;
|
|
61
|
+
}>;
|
|
62
|
+
track: import('vue').ComputedRef<{
|
|
63
|
+
role: string;
|
|
64
|
+
"aria-hidden": true;
|
|
65
|
+
style: {
|
|
66
|
+
[x: string]: string;
|
|
67
|
+
};
|
|
68
|
+
}>;
|
|
69
|
+
rail: import('vue').ComputedRef<{
|
|
70
|
+
role: string;
|
|
71
|
+
"aria-hidden": true;
|
|
72
|
+
}>;
|
|
73
|
+
}, {
|
|
74
|
+
isDragging: import('vue').Ref<boolean, boolean>;
|
|
75
|
+
activeThumbIndex: import('vue').Ref<number, number>;
|
|
76
|
+
focusedThumbIndex: import('vue').Ref<number, number>;
|
|
77
|
+
isRange: import('vue').ComputedRef<boolean>;
|
|
78
|
+
trackOffset: import('vue').ComputedRef<number>;
|
|
79
|
+
trackLength: import('vue').ComputedRef<number>;
|
|
80
|
+
marksList: import('vue').ComputedRef<{
|
|
81
|
+
value: number;
|
|
82
|
+
label?: string;
|
|
83
|
+
}[]>;
|
|
84
|
+
}, {
|
|
85
|
+
valueToPercent: import('vue').ComputedRef<(value: number) => number>;
|
|
86
|
+
isMarkActive: import('vue').ComputedRef<(markValue: number) => boolean>;
|
|
87
|
+
clampValue: import('vue').ComputedRef<(value: number) => number>;
|
|
88
|
+
axis: import('vue').ComputedRef<{
|
|
89
|
+
position: "bottom";
|
|
90
|
+
size: "height";
|
|
91
|
+
cross: "width";
|
|
92
|
+
} | {
|
|
93
|
+
position: "left";
|
|
94
|
+
size: "width";
|
|
95
|
+
cross: "height";
|
|
96
|
+
}>;
|
|
97
|
+
roundToStep: import('vue').ComputedRef<(value: number) => number | undefined>;
|
|
98
|
+
normalizeValues: import('vue').ComputedRef<(values: number[]) => number[]>;
|
|
99
|
+
}>;
|
|
100
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
|
|
101
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { MaybeRef, Ref } from 'vue';
|
|
2
|
+
import { Nullable } from '../../utils/types.js';
|
|
3
|
+
export type SliderMark = {
|
|
4
|
+
value: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
} | number;
|
|
7
|
+
export type SliderOrientation = "horizontal" | "vertical";
|
|
8
|
+
export type CreateSliderOptions<TValue extends number | number[] = number> = {
|
|
9
|
+
/**
|
|
10
|
+
* Current value(s) of the slider.
|
|
11
|
+
* Each value should be between min and max.
|
|
12
|
+
*
|
|
13
|
+
* @default [min]
|
|
14
|
+
*/
|
|
15
|
+
value: Ref<TValue>;
|
|
16
|
+
/**
|
|
17
|
+
* Minimum value of the slider.
|
|
18
|
+
*
|
|
19
|
+
* @default 0
|
|
20
|
+
*/
|
|
21
|
+
min?: MaybeRef<number>;
|
|
22
|
+
/**
|
|
23
|
+
* Maximum value of the slider.
|
|
24
|
+
*
|
|
25
|
+
* @default 100
|
|
26
|
+
*/
|
|
27
|
+
max?: MaybeRef<number>;
|
|
28
|
+
/**
|
|
29
|
+
* Step size for the slider.
|
|
30
|
+
*
|
|
31
|
+
* @default 1
|
|
32
|
+
*/
|
|
33
|
+
step?: MaybeRef<number>;
|
|
34
|
+
/**
|
|
35
|
+
* Whether to render the slider in discrete mode.
|
|
36
|
+
*
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
discrete?: MaybeRef<boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* Step size when holding shift key or using Page Up/Page Down keys.
|
|
42
|
+
*
|
|
43
|
+
* Defaults to 10% of the total range (max - min) multiplied by the step size.
|
|
44
|
+
* This provides intuitive behavior that automatically scales with different slider ranges.
|
|
45
|
+
*/
|
|
46
|
+
shiftStep?: MaybeRef<number>;
|
|
47
|
+
/**
|
|
48
|
+
* Whether the slider is disabled.
|
|
49
|
+
*
|
|
50
|
+
* @default false
|
|
51
|
+
*/
|
|
52
|
+
disabled?: MaybeRef<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Array of marks to display on the slider.
|
|
55
|
+
*
|
|
56
|
+
* @default false
|
|
57
|
+
*/
|
|
58
|
+
marks?: MaybeRef<Nullable<SliderMark[] | boolean>>;
|
|
59
|
+
/**
|
|
60
|
+
* Aria label for the slider.
|
|
61
|
+
*
|
|
62
|
+
* @default undefined
|
|
63
|
+
*/
|
|
64
|
+
label: MaybeRef<string>;
|
|
65
|
+
/**
|
|
66
|
+
* Orientation of the slider.
|
|
67
|
+
*
|
|
68
|
+
* @default "horizontal"
|
|
69
|
+
*/
|
|
70
|
+
orientation?: MaybeRef<SliderOrientation>;
|
|
71
|
+
/**
|
|
72
|
+
* Callback when the value changes during interaction.
|
|
73
|
+
* Note: This is called during interaction (dragging, key press, etc.).
|
|
74
|
+
*/
|
|
75
|
+
onChange?: (value: TValue) => void;
|
|
76
|
+
/**
|
|
77
|
+
* Callback when the value is committed (drag end, key press, etc.).
|
|
78
|
+
* Note: This is called when the user stops interacting with the slider.
|
|
79
|
+
*/
|
|
80
|
+
onCommit?: (value: TValue) => void;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Composable for creating an accessibility-compliant slider.
|
|
84
|
+
* For supported keyboard shortcuts, see: https://www.w3.org/WAI/ARIA/apg/patterns/slider/
|
|
85
|
+
*
|
|
86
|
+
* * @experimental
|
|
87
|
+
* @deprecated This component is still under active development and its API might change in patch releases.
|
|
88
|
+
*/
|
|
89
|
+
export declare const _unstableCreateSlider: <TValue extends number | number[] = number>(options: CreateSliderOptions<TValue>) => import('../../utils/builder.js').HeadlessComposable<{
|
|
90
|
+
/**
|
|
91
|
+
* Root slider container element
|
|
92
|
+
*/
|
|
93
|
+
root: import('vue').ComputedRef<{
|
|
94
|
+
ref: import('../../utils/builder.js').HeadlessElRef<HTMLElement>;
|
|
95
|
+
style: {
|
|
96
|
+
touchAction: "pan-x" | "pan-y";
|
|
97
|
+
};
|
|
98
|
+
onMousedown: (event: MouseEvent) => void;
|
|
99
|
+
onTouchstart: (event: TouchEvent) => void;
|
|
100
|
+
}>;
|
|
101
|
+
/**
|
|
102
|
+
* Individual thumb elements for each value (span)
|
|
103
|
+
*/
|
|
104
|
+
thumbContainer: import('vue').ComputedRef<(data: {
|
|
105
|
+
index: number;
|
|
106
|
+
value: number;
|
|
107
|
+
}) => {
|
|
108
|
+
"data-index": number;
|
|
109
|
+
style: {
|
|
110
|
+
[x: string]: string;
|
|
111
|
+
};
|
|
112
|
+
}>;
|
|
113
|
+
/**
|
|
114
|
+
* Visually hidden input inside each thumb for accessibility
|
|
115
|
+
*/
|
|
116
|
+
thumbInput: import('vue').ComputedRef<(data: {
|
|
117
|
+
index: number;
|
|
118
|
+
value: number;
|
|
119
|
+
}) => {
|
|
120
|
+
min: number;
|
|
121
|
+
max: number;
|
|
122
|
+
value: number;
|
|
123
|
+
role: string;
|
|
124
|
+
type: string;
|
|
125
|
+
"aria-label": string;
|
|
126
|
+
"aria-valuemin": number;
|
|
127
|
+
"aria-valuemax": number;
|
|
128
|
+
"aria-valuenow": number;
|
|
129
|
+
"aria-orientation": SliderOrientation;
|
|
130
|
+
"data-index": number;
|
|
131
|
+
tabIndex: number;
|
|
132
|
+
step: string | number;
|
|
133
|
+
disabled: boolean;
|
|
134
|
+
onChange: (event: Event) => void;
|
|
135
|
+
onFocus: (event: FocusEvent) => void;
|
|
136
|
+
onBlur: (event: FocusEvent) => void;
|
|
137
|
+
onKeydown: (event: KeyboardEvent) => void;
|
|
138
|
+
}>;
|
|
139
|
+
/**
|
|
140
|
+
* Mark elements
|
|
141
|
+
*/
|
|
142
|
+
mark: import('vue').ComputedRef<(data: {
|
|
143
|
+
value: number;
|
|
144
|
+
label?: string;
|
|
145
|
+
}) => {
|
|
146
|
+
"data-value": number;
|
|
147
|
+
"aria-hidden": true;
|
|
148
|
+
style: {
|
|
149
|
+
[x: string]: string;
|
|
150
|
+
};
|
|
151
|
+
}>;
|
|
152
|
+
/**
|
|
153
|
+
* Label for each mark
|
|
154
|
+
*/
|
|
155
|
+
markLabel: import('vue').ComputedRef<(data: {
|
|
156
|
+
value: number;
|
|
157
|
+
}) => {
|
|
158
|
+
"data-value": number;
|
|
159
|
+
style: {
|
|
160
|
+
[x: string]: string;
|
|
161
|
+
};
|
|
162
|
+
"aria-hidden": true;
|
|
163
|
+
}>;
|
|
164
|
+
/**
|
|
165
|
+
* Track element representing the selected range
|
|
166
|
+
*/
|
|
167
|
+
track: import('vue').ComputedRef<{
|
|
168
|
+
role: string;
|
|
169
|
+
"aria-hidden": true;
|
|
170
|
+
style: {
|
|
171
|
+
[x: string]: string;
|
|
172
|
+
};
|
|
173
|
+
}>;
|
|
174
|
+
/**
|
|
175
|
+
* Rail element representing the full slider range
|
|
176
|
+
*/
|
|
177
|
+
rail: import('vue').ComputedRef<{
|
|
178
|
+
role: string;
|
|
179
|
+
"aria-hidden": true;
|
|
180
|
+
}>;
|
|
181
|
+
}, {
|
|
182
|
+
/**
|
|
183
|
+
* True if the slider is currently being dragged.
|
|
184
|
+
*/
|
|
185
|
+
isDragging: Ref<boolean, boolean>;
|
|
186
|
+
/**
|
|
187
|
+
* Index of the currently active thumb.
|
|
188
|
+
* Thumb could be active even if not dragging (e.g. click on the rail to move the thumb there).
|
|
189
|
+
* `-1` if no thumb is active.
|
|
190
|
+
*/
|
|
191
|
+
activeThumbIndex: Ref<number, number>;
|
|
192
|
+
/**
|
|
193
|
+
* Index of the thumb that is currently focused.
|
|
194
|
+
* `-1` if no thumb is focused.
|
|
195
|
+
*/
|
|
196
|
+
focusedThumbIndex: Ref<number, number>;
|
|
197
|
+
/**
|
|
198
|
+
* `true` if the slider is a range slider (with two or more thumbs).
|
|
199
|
+
*/
|
|
200
|
+
isRange: import('vue').ComputedRef<boolean>;
|
|
201
|
+
/**
|
|
202
|
+
* Offset of the track as a percentage (0-100).
|
|
203
|
+
*/
|
|
204
|
+
trackOffset: import('vue').ComputedRef<number>;
|
|
205
|
+
/**
|
|
206
|
+
* Length of the track as a percentage (0-100).
|
|
207
|
+
*/
|
|
208
|
+
trackLength: import('vue').ComputedRef<number>;
|
|
209
|
+
/**
|
|
210
|
+
* List of marks to display on the slider.
|
|
211
|
+
* - If marks option is `true`, marks are generated based on the step value.
|
|
212
|
+
* - If marks option is an array of numbers or objects, it is used as provided (filtered to be within range).
|
|
213
|
+
* - If marks option is `false`, no marks are shown.
|
|
214
|
+
*/
|
|
215
|
+
marksList: import('vue').ComputedRef<{
|
|
216
|
+
value: number;
|
|
217
|
+
label?: string;
|
|
218
|
+
}[]>;
|
|
219
|
+
}, {
|
|
220
|
+
/**
|
|
221
|
+
* Converts a value from the slider's range to a percentage (0-100).
|
|
222
|
+
* @param value - value to convert
|
|
223
|
+
* @returns percentage representation of the value
|
|
224
|
+
*/
|
|
225
|
+
valueToPercent: import('vue').ComputedRef<(value: number) => number>;
|
|
226
|
+
/**
|
|
227
|
+
* Checks if a given mark value is active (i.e., within the selected range).
|
|
228
|
+
* Use case: when rendering marks, to determine if a mark is covered by the selected range.
|
|
229
|
+
*
|
|
230
|
+
* @param markValue - value of the mark to check
|
|
231
|
+
* @returns `true` if the mark is active, `false` otherwise
|
|
232
|
+
*/
|
|
233
|
+
isMarkActive: import('vue').ComputedRef<(markValue: number) => boolean>;
|
|
234
|
+
/**
|
|
235
|
+
* Clamps a value to the slider's range.
|
|
236
|
+
* @param value - value to clamp
|
|
237
|
+
* @returns clamped value
|
|
238
|
+
*/
|
|
239
|
+
clampValue: import('vue').ComputedRef<(value: number) => number>;
|
|
240
|
+
/**
|
|
241
|
+
* Main axis properties based on orientation.
|
|
242
|
+
*/
|
|
243
|
+
axis: import('vue').ComputedRef<{
|
|
244
|
+
position: "bottom";
|
|
245
|
+
size: "height";
|
|
246
|
+
cross: "width";
|
|
247
|
+
} | {
|
|
248
|
+
position: "left";
|
|
249
|
+
size: "width";
|
|
250
|
+
cross: "height";
|
|
251
|
+
}>;
|
|
252
|
+
/**
|
|
253
|
+
* Rounds a value to the nearest valid step.
|
|
254
|
+
* @param value - value to round
|
|
255
|
+
* @returns rounded value
|
|
256
|
+
*/
|
|
257
|
+
roundToStep: import('vue').ComputedRef<(value: number) => number | undefined>;
|
|
258
|
+
/**
|
|
259
|
+
* Normalizes an array of values to ensure they are within min/max bounds,
|
|
260
|
+
*/
|
|
261
|
+
normalizeValues: import('vue').ComputedRef<(values: number[]) => number[]>;
|
|
262
|
+
}>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Locator, Page } from '@playwright/test';
|
|
2
|
+
export type SliderTestingOptions = {
|
|
3
|
+
/**
|
|
4
|
+
* Playwright page.
|
|
5
|
+
*/
|
|
6
|
+
page: Page;
|
|
7
|
+
/**
|
|
8
|
+
* Locator for the slider element(s).
|
|
9
|
+
*/
|
|
10
|
+
slider: Locator;
|
|
11
|
+
/**
|
|
12
|
+
* Optional: Locator for the slider container/root.
|
|
13
|
+
*/
|
|
14
|
+
container?: Locator;
|
|
15
|
+
/**
|
|
16
|
+
* Expected initial value(s) for the slider.
|
|
17
|
+
*/
|
|
18
|
+
initialValues?: number[];
|
|
19
|
+
/**
|
|
20
|
+
* Expected min value.
|
|
21
|
+
*/
|
|
22
|
+
min?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Expected max value.
|
|
25
|
+
*/
|
|
26
|
+
max?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Expected step value.
|
|
29
|
+
*/
|
|
30
|
+
step?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Expected shift step value.
|
|
33
|
+
*/
|
|
34
|
+
shiftStep?: number;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Comprehensive testing for single-thumb slider implementation.
|
|
38
|
+
* Tests basic accessibility, keyboard navigation, and interaction patterns.
|
|
39
|
+
*/
|
|
40
|
+
export declare const singleThumbSliderTesting: ({ page, slider, container, initialValues, min, max, step, shiftStep, }: SliderTestingOptions) => Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Comprehensive testing for multi-thumb (range) slider implementation.
|
|
43
|
+
* Tests range-specific behaviors, thumb independence, and collision handling.
|
|
44
|
+
*/
|
|
45
|
+
export declare const multiThumbSliderTesting: ({ page, slider, container, initialValues, min, max, step, }: SliderTestingOptions) => Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Test slider with marks (discrete mode).
|
|
48
|
+
*/
|
|
49
|
+
export declare const discreteSliderTesting: ({ slider }: SliderTestingOptions) => Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from './composables/helpers/useOutsideClick.js';
|
|
|
5
5
|
export * from './composables/listbox/createListbox.js';
|
|
6
6
|
export * from './composables/menuButton/createMenuButton.js';
|
|
7
7
|
export * from './composables/navigationMenu/createMenu.js';
|
|
8
|
+
export * from './composables/slider/createSlider.js';
|
|
8
9
|
export * from './composables/tabs/createTabs.js';
|
|
9
10
|
export * from './composables/tooltip/createToggletip.js';
|
|
10
11
|
export * from './composables/tooltip/createTooltip.js';
|
package/dist/index.js
CHANGED
|
@@ -843,7 +843,34 @@ const MathUtils = {
|
|
|
843
843
|
/**
|
|
844
844
|
* Ensures that a given `number` is or is between a given `min` and `max`.
|
|
845
845
|
*/
|
|
846
|
-
clamp: (number, min, max) => Math.max(Math.min(number, max), min)
|
|
846
|
+
clamp: (number, min, max) => Math.max(Math.min(number, max), min),
|
|
847
|
+
/**
|
|
848
|
+
* Returns the count of decimal places in a number.
|
|
849
|
+
* @param number - The number to check.
|
|
850
|
+
* @returns The count of decimal places.
|
|
851
|
+
*
|
|
852
|
+
* decimals(1.23); // 2
|
|
853
|
+
* decimals(10); // 0
|
|
854
|
+
*/
|
|
855
|
+
decimalsCount: (number) => String(number).split(".")[1]?.length ?? 0,
|
|
856
|
+
/**
|
|
857
|
+
* Converts a value within a range to a percentage (0-100).
|
|
858
|
+
*
|
|
859
|
+
* @param value - The value to convert.
|
|
860
|
+
* @param min - The minimum allowed value.
|
|
861
|
+
* @param max - The maximum allowed value.
|
|
862
|
+
* @returns The percentage representation of the value.
|
|
863
|
+
*/
|
|
864
|
+
valueToPercent: (value, min, max) => (value - min) * 100 / (max - min),
|
|
865
|
+
/**
|
|
866
|
+
* Converts a percentage (0-100) to a value within a range.
|
|
867
|
+
*
|
|
868
|
+
* @param percent - The percentage to convert.
|
|
869
|
+
* @param min - The minimum allowed value.
|
|
870
|
+
* @param max - The maximum allowed value.
|
|
871
|
+
* @returns The value representation of the percentage.
|
|
872
|
+
*/
|
|
873
|
+
percentToValue: (percent, min, max) => (max - min) * percent + min
|
|
847
874
|
};
|
|
848
875
|
const createNavigationMenu = createBuilder(({ navigationName }) => {
|
|
849
876
|
const navId = useId();
|
|
@@ -882,6 +909,594 @@ const createNavigationMenu = createBuilder(({ navigationName }) => {
|
|
|
882
909
|
}
|
|
883
910
|
};
|
|
884
911
|
});
|
|
912
|
+
const areArraysEqual = (arrayA, arrayB, comparer = (a, b) => a === b) => arrayA.length === arrayB.length && arrayA.every((value, index) => comparer(value, arrayB[index]));
|
|
913
|
+
const isFocusVisible = (element) => {
|
|
914
|
+
try {
|
|
915
|
+
return element.matches(":focus-visible");
|
|
916
|
+
} catch {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
const isTouchEvent = (event) => "touches" in event || "changedTouches" in event || "targetTouches" in event;
|
|
921
|
+
const DRAG_MOVE_THRESHOLD = 2;
|
|
922
|
+
const KEY = {
|
|
923
|
+
Up: "ArrowUp",
|
|
924
|
+
Down: "ArrowDown",
|
|
925
|
+
Left: "ArrowLeft",
|
|
926
|
+
Right: "ArrowRight",
|
|
927
|
+
PageUp: "PageUp",
|
|
928
|
+
PageDown: "PageDown",
|
|
929
|
+
Home: "Home",
|
|
930
|
+
End: "End"
|
|
931
|
+
};
|
|
932
|
+
const NAVIGATION_KEYS = /* @__PURE__ */ new Set([
|
|
933
|
+
KEY.Up,
|
|
934
|
+
KEY.Down,
|
|
935
|
+
KEY.Left,
|
|
936
|
+
KEY.Right,
|
|
937
|
+
KEY.PageUp,
|
|
938
|
+
KEY.PageDown,
|
|
939
|
+
KEY.Home,
|
|
940
|
+
KEY.End
|
|
941
|
+
]);
|
|
942
|
+
const INCREMENT_KEYS = /* @__PURE__ */ new Set([KEY.Right, KEY.Up, KEY.PageUp]);
|
|
943
|
+
const DECREMENT_KEYS = /* @__PURE__ */ new Set([KEY.Left, KEY.Down, KEY.PageDown]);
|
|
944
|
+
const TRACK_CALCULATION_STRATEGIES = {
|
|
945
|
+
horizontal: (rect, coords) => MathUtils.clamp((coords.x - rect.left) / rect.width, 0, 1),
|
|
946
|
+
vertical: (rect, coords) => MathUtils.clamp((rect.bottom - coords.y) / rect.height, 0, 1)
|
|
947
|
+
};
|
|
948
|
+
const readThumbIndex = (event) => Number(event.currentTarget?.dataset.index ?? -1);
|
|
949
|
+
const roundToStep = (value, step, min) => Number((Math.round((value - min) / step) * step + min).toFixed(MathUtils.decimalsCount(step)));
|
|
950
|
+
const normalizeValues = (values, min, max, step) => {
|
|
951
|
+
if (!values.length) return [min];
|
|
952
|
+
return values.map((value) => {
|
|
953
|
+
const clamped = MathUtils.clamp(value, min, max);
|
|
954
|
+
return roundToStep(clamped, step, min);
|
|
955
|
+
}).sort((a, b) => a - b);
|
|
956
|
+
};
|
|
957
|
+
const findClosestIndex = (values, currentValue) => {
|
|
958
|
+
const result = values.reduce((acc, value, index) => {
|
|
959
|
+
const distance = Math.abs(currentValue - value);
|
|
960
|
+
if (!acc || distance <= acc.closestDistance) {
|
|
961
|
+
return {
|
|
962
|
+
closestIndex: index,
|
|
963
|
+
closestDistance: distance
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
return acc;
|
|
967
|
+
}, null);
|
|
968
|
+
return result.closestIndex;
|
|
969
|
+
};
|
|
970
|
+
const adjustValueByIndex = ({
|
|
971
|
+
values,
|
|
972
|
+
newValue,
|
|
973
|
+
index
|
|
974
|
+
}) => values.map((value, i) => i === index ? newValue : value).sort((a, b) => a - b);
|
|
975
|
+
const asc = (a, b) => a - b;
|
|
976
|
+
const valueToArray = (value) => Array.isArray(value) ? value : [value];
|
|
977
|
+
const _unstableCreateSlider = createBuilder(
|
|
978
|
+
(options) => {
|
|
979
|
+
const sliderRef = createElRef();
|
|
980
|
+
const min = computed(() => unref(options.min) ?? 0);
|
|
981
|
+
const max = computed(() => unref(options.max) ?? 100);
|
|
982
|
+
const step = computed(() => unref(options.step) ?? 1);
|
|
983
|
+
const values = computed(() => {
|
|
984
|
+
const rawValues = unref(options.value);
|
|
985
|
+
if (Array.isArray(rawValues)) {
|
|
986
|
+
if (!rawValues?.length) {
|
|
987
|
+
return [min.value];
|
|
988
|
+
}
|
|
989
|
+
return normalizeValues(rawValues, min.value, max.value, step.value);
|
|
990
|
+
} else {
|
|
991
|
+
if (typeof rawValues !== "number") {
|
|
992
|
+
return [min.value];
|
|
993
|
+
}
|
|
994
|
+
return normalizeValues([rawValues], min.value, max.value, step.value);
|
|
995
|
+
}
|
|
996
|
+
});
|
|
997
|
+
const shiftStep = computed(() => {
|
|
998
|
+
const shiftStep2 = unref(options.shiftStep);
|
|
999
|
+
if (typeof shiftStep2 !== "undefined") {
|
|
1000
|
+
return shiftStep2;
|
|
1001
|
+
}
|
|
1002
|
+
const stepMultiple = Math.max(1, Math.round((max.value - min.value) * 0.1 / step.value));
|
|
1003
|
+
return stepMultiple * step.value;
|
|
1004
|
+
});
|
|
1005
|
+
const isDisabled = computed(() => unref(options.disabled) ?? false);
|
|
1006
|
+
const marks = computed(() => unref(options.marks) ?? false);
|
|
1007
|
+
const label = computed(() => unref(options.label));
|
|
1008
|
+
const orientation = computed(() => unref(options.orientation) ?? "horizontal");
|
|
1009
|
+
const isDiscrete = computed(() => unref(options.discrete) ?? false);
|
|
1010
|
+
let touchId = null;
|
|
1011
|
+
let movesSinceStart = 0;
|
|
1012
|
+
let lastChangedValue = null;
|
|
1013
|
+
let previousActiveIndex = null;
|
|
1014
|
+
const isDragging = ref(false);
|
|
1015
|
+
const activeThumbIndex = ref(-1);
|
|
1016
|
+
const focusedThumbIndex = ref(-1);
|
|
1017
|
+
const isRange = computed(() => {
|
|
1018
|
+
const unrefValues = unref(options.value);
|
|
1019
|
+
return Array.isArray(unrefValues) && unrefValues.length > 1;
|
|
1020
|
+
});
|
|
1021
|
+
const marksList = computed(() => {
|
|
1022
|
+
if (marks.value === false) return [];
|
|
1023
|
+
if (marks.value && Array.isArray(marks.value)) {
|
|
1024
|
+
return marks.value.map((mark) => typeof mark === "number" ? { value: mark } : mark).filter((mark) => mark.value >= min.value && mark.value <= max.value).sort((a, b) => asc(a.value, b.value));
|
|
1025
|
+
}
|
|
1026
|
+
if (step.value && step.value > 0) {
|
|
1027
|
+
return [...Array(Math.floor((max.value - min.value) / step.value + 1))].map((_, index) => ({
|
|
1028
|
+
value: min.value + step.value * index
|
|
1029
|
+
}));
|
|
1030
|
+
}
|
|
1031
|
+
return [];
|
|
1032
|
+
});
|
|
1033
|
+
const axis = computed(
|
|
1034
|
+
() => orientation.value === "vertical" ? { position: "bottom", size: "height", cross: "width" } : { position: "left", size: "width", cross: "height" }
|
|
1035
|
+
);
|
|
1036
|
+
const marksValues = computed(() => marksList.value.map((mark) => mark.value));
|
|
1037
|
+
const emitChange = (next) => {
|
|
1038
|
+
if (!areArraysEqual(values.value, next)) {
|
|
1039
|
+
const nextValue = isRange.value ? next : next[0];
|
|
1040
|
+
if (typeof nextValue !== "undefined") {
|
|
1041
|
+
options.onChange?.(nextValue);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
lastChangedValue = next;
|
|
1045
|
+
};
|
|
1046
|
+
const emitCommit = (fallback) => {
|
|
1047
|
+
const valueWithFallback = lastChangedValue ?? fallback;
|
|
1048
|
+
const nextValue = isRange.value ? valueWithFallback : valueWithFallback[0];
|
|
1049
|
+
if (typeof nextValue !== "undefined") {
|
|
1050
|
+
options.onCommit?.(nextValue);
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
const ensureFocusOnThumb = (options2) => {
|
|
1054
|
+
const { index, shouldSetActive = false } = options2;
|
|
1055
|
+
const slider = sliderRef.value;
|
|
1056
|
+
if (!slider) return;
|
|
1057
|
+
if (slider.contains(document.activeElement) && Number(document.activeElement?.getAttribute("data-index")) !== index) {
|
|
1058
|
+
slider.querySelector(`[type="range"][data-index="${index}"]`)?.focus();
|
|
1059
|
+
}
|
|
1060
|
+
if (shouldSetActive) {
|
|
1061
|
+
activeThumbIndex.value = index;
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
const eventToCoords = (event, touchId2) => {
|
|
1065
|
+
if (touchId2 !== void 0 && isTouchEvent(event)) {
|
|
1066
|
+
for (let i = 0; i < event.changedTouches.length; i += 1) {
|
|
1067
|
+
const touch = event.changedTouches[i];
|
|
1068
|
+
if (touch && touch.identifier === touchId2) {
|
|
1069
|
+
return {
|
|
1070
|
+
x: touch.clientX,
|
|
1071
|
+
y: touch.clientY
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
return false;
|
|
1076
|
+
}
|
|
1077
|
+
const mouseEvent = event;
|
|
1078
|
+
return {
|
|
1079
|
+
x: mouseEvent.clientX,
|
|
1080
|
+
y: mouseEvent.clientY
|
|
1081
|
+
};
|
|
1082
|
+
};
|
|
1083
|
+
const getNextFromCoords = (opts) => {
|
|
1084
|
+
const { coords, isMoving = false } = opts;
|
|
1085
|
+
const slider = sliderRef.value;
|
|
1086
|
+
if (!slider) return null;
|
|
1087
|
+
const rect = slider.getBoundingClientRect();
|
|
1088
|
+
const mainSize = orientation.value === "vertical" ? rect.height : rect.width;
|
|
1089
|
+
if (mainSize <= 0) return null;
|
|
1090
|
+
const percent = TRACK_CALCULATION_STRATEGIES[orientation.value](rect, coords);
|
|
1091
|
+
const raw = MathUtils.percentToValue(percent, min.value, max.value);
|
|
1092
|
+
const snapped = !isDiscrete.value ? roundToStep(raw, step.value, min.value) : marksValues.value[findClosestIndex(marksValues.value, raw)];
|
|
1093
|
+
if (typeof snapped !== "number") return null;
|
|
1094
|
+
const candidate = MathUtils.clamp(snapped, min.value, max.value);
|
|
1095
|
+
if (!isRange.value) {
|
|
1096
|
+
return { newValue: candidate, activeIndex: 0 };
|
|
1097
|
+
}
|
|
1098
|
+
const closestIndex = findClosestIndex(values.value, candidate);
|
|
1099
|
+
const index = isMoving && previousActiveIndex != null ? previousActiveIndex : closestIndex;
|
|
1100
|
+
const adjustedValues = adjustValueByIndex({
|
|
1101
|
+
values: values.value,
|
|
1102
|
+
newValue: candidate,
|
|
1103
|
+
index
|
|
1104
|
+
});
|
|
1105
|
+
const adjustedIndex = findClosestIndex(adjustedValues, candidate);
|
|
1106
|
+
previousActiveIndex = adjustedIndex;
|
|
1107
|
+
return { newValue: adjustedValues, activeIndex: adjustedIndex };
|
|
1108
|
+
};
|
|
1109
|
+
const commitValueFromEvent = (event, input) => {
|
|
1110
|
+
const index = readThumbIndex(event);
|
|
1111
|
+
const current = values.value[index];
|
|
1112
|
+
if (typeof current !== "number") {
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
const useMarks = isDiscrete.value && marksList.value.length > 0;
|
|
1116
|
+
const snapByMarks = (candidate) => {
|
|
1117
|
+
const list = marksList.value;
|
|
1118
|
+
const first = list[0];
|
|
1119
|
+
const last = list.at(-1);
|
|
1120
|
+
if (!first || !last) {
|
|
1121
|
+
return current;
|
|
1122
|
+
}
|
|
1123
|
+
if (candidate <= first.value) {
|
|
1124
|
+
return first.value;
|
|
1125
|
+
}
|
|
1126
|
+
if (candidate >= last.value) {
|
|
1127
|
+
return last.value;
|
|
1128
|
+
}
|
|
1129
|
+
const pos = marksValues.value.indexOf(current);
|
|
1130
|
+
const neighbor = candidate < current ? list[pos - 1] : list[pos + 1];
|
|
1131
|
+
return neighbor?.value ?? current;
|
|
1132
|
+
};
|
|
1133
|
+
const scalar = MathUtils.clamp(useMarks ? snapByMarks(input) : input, min.value, max.value);
|
|
1134
|
+
const nextValues = isRange.value ? adjustValueByIndex({ values: values.value, newValue: scalar, index }) : [scalar];
|
|
1135
|
+
if (isRange.value) {
|
|
1136
|
+
const activeIndex = nextValues.indexOf(scalar);
|
|
1137
|
+
ensureFocusOnThumb({ index: activeIndex, shouldSetActive: true });
|
|
1138
|
+
}
|
|
1139
|
+
focusedThumbIndex.value = index;
|
|
1140
|
+
if (!areArraysEqual(values.value, nextValues)) {
|
|
1141
|
+
emitChange(nextValues);
|
|
1142
|
+
}
|
|
1143
|
+
emitCommit(nextValues);
|
|
1144
|
+
};
|
|
1145
|
+
const handlePointerEnd = (event) => {
|
|
1146
|
+
const coords = eventToCoords(event, touchId);
|
|
1147
|
+
isDragging.value = false;
|
|
1148
|
+
if (!coords) {
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
const next = getNextFromCoords({ coords, isMoving: true });
|
|
1152
|
+
if (!next) {
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
const { newValue } = next;
|
|
1156
|
+
activeThumbIndex.value = -1;
|
|
1157
|
+
emitCommit(valueToArray(newValue));
|
|
1158
|
+
movesSinceStart = 0;
|
|
1159
|
+
touchId = null;
|
|
1160
|
+
stopPointerListening();
|
|
1161
|
+
};
|
|
1162
|
+
const handlePointerMove = (event) => {
|
|
1163
|
+
const coords = eventToCoords(event, touchId);
|
|
1164
|
+
if (!coords) return;
|
|
1165
|
+
movesSinceStart += 1;
|
|
1166
|
+
if (event.type === "mousemove" && event.buttons === 0) {
|
|
1167
|
+
handlePointerEnd(event);
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
const nextState = getNextFromCoords({ coords, isMoving: true });
|
|
1171
|
+
if (!nextState) {
|
|
1172
|
+
handlePointerEnd(event);
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
const { newValue, activeIndex } = nextState;
|
|
1176
|
+
if (!isDragging.value && movesSinceStart > DRAG_MOVE_THRESHOLD) {
|
|
1177
|
+
isDragging.value = true;
|
|
1178
|
+
}
|
|
1179
|
+
ensureFocusOnThumb({ index: activeIndex, shouldSetActive: true });
|
|
1180
|
+
emitChange(valueToArray(newValue));
|
|
1181
|
+
isDragging.value = true;
|
|
1182
|
+
};
|
|
1183
|
+
const handlePointerStart = (event) => {
|
|
1184
|
+
if (isDisabled.value) {
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
const touch = event.changedTouches[0];
|
|
1188
|
+
if (touch !== null && touch !== void 0) {
|
|
1189
|
+
touchId = touch.identifier;
|
|
1190
|
+
}
|
|
1191
|
+
const coords = eventToCoords(event, touchId);
|
|
1192
|
+
if (coords) {
|
|
1193
|
+
const nextState = getNextFromCoords({ coords, isMoving: false });
|
|
1194
|
+
if (nextState) {
|
|
1195
|
+
const { newValue, activeIndex } = nextState;
|
|
1196
|
+
ensureFocusOnThumb({ index: activeIndex, shouldSetActive: true });
|
|
1197
|
+
emitChange(valueToArray(newValue));
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
movesSinceStart = 0;
|
|
1201
|
+
document.addEventListener("touchmove", handlePointerMove, {
|
|
1202
|
+
passive: true
|
|
1203
|
+
});
|
|
1204
|
+
document.addEventListener("touchend", handlePointerEnd);
|
|
1205
|
+
};
|
|
1206
|
+
const stopPointerListening = () => {
|
|
1207
|
+
document.removeEventListener("mousemove", handlePointerMove);
|
|
1208
|
+
document.removeEventListener("mouseup", handlePointerEnd);
|
|
1209
|
+
document.removeEventListener("touchmove", handlePointerMove);
|
|
1210
|
+
document.removeEventListener("touchend", handlePointerEnd);
|
|
1211
|
+
};
|
|
1212
|
+
const handleRootMousedown = (event) => {
|
|
1213
|
+
if (isDisabled.value) {
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1216
|
+
if (event.button !== 0) {
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
if (event.defaultPrevented) {
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
event.preventDefault();
|
|
1223
|
+
const coords = eventToCoords(event, touchId);
|
|
1224
|
+
if (coords) {
|
|
1225
|
+
const nextState = getNextFromCoords({ coords });
|
|
1226
|
+
if (nextState) {
|
|
1227
|
+
const { newValue, activeIndex } = nextState;
|
|
1228
|
+
ensureFocusOnThumb({ index: activeIndex, shouldSetActive: true });
|
|
1229
|
+
emitChange(valueToArray(newValue));
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
movesSinceStart = 0;
|
|
1233
|
+
document.addEventListener("mousemove", handlePointerMove, {
|
|
1234
|
+
passive: true
|
|
1235
|
+
});
|
|
1236
|
+
document.addEventListener("mouseup", handlePointerEnd);
|
|
1237
|
+
};
|
|
1238
|
+
const handleHiddenInputChange = (event) => {
|
|
1239
|
+
if (isDisabled.value) {
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
const value = event.target.valueAsNumber;
|
|
1243
|
+
commitValueFromEvent(event, value);
|
|
1244
|
+
};
|
|
1245
|
+
const handleHiddenInputFocus = (event) => {
|
|
1246
|
+
const index = readThumbIndex(event);
|
|
1247
|
+
if (isFocusVisible(event.target)) {
|
|
1248
|
+
focusedThumbIndex.value = index;
|
|
1249
|
+
activeThumbIndex.value = index;
|
|
1250
|
+
}
|
|
1251
|
+
};
|
|
1252
|
+
const handleHiddenInputBlur = (event) => {
|
|
1253
|
+
if (!isFocusVisible(event.target)) {
|
|
1254
|
+
focusedThumbIndex.value = -1;
|
|
1255
|
+
activeThumbIndex.value = -1;
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1258
|
+
const handleHiddenInputKeydown = (event) => {
|
|
1259
|
+
if (!NAVIGATION_KEYS.has(event.key)) return;
|
|
1260
|
+
event.preventDefault();
|
|
1261
|
+
const index = readThumbIndex(event);
|
|
1262
|
+
const value = values.value[index];
|
|
1263
|
+
if (typeof value !== "number") {
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
if (!isDiscrete.value) {
|
|
1267
|
+
const stepSize = event.shiftKey ? shiftStep.value : step.value;
|
|
1268
|
+
if (event.key === "Home") return commitValueFromEvent(event, min.value);
|
|
1269
|
+
if (event.key === "End") return commitValueFromEvent(event, max.value);
|
|
1270
|
+
if (INCREMENT_KEYS.has(event.key)) {
|
|
1271
|
+
const next = MathUtils.clamp(value + stepSize, min.value, max.value);
|
|
1272
|
+
if (next !== value) commitValueFromEvent(event, next);
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
if (DECREMENT_KEYS.has(event.key)) {
|
|
1276
|
+
const next = MathUtils.clamp(value - stepSize, min.value, max.value);
|
|
1277
|
+
if (next !== value) commitValueFromEvent(event, next);
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1280
|
+
return;
|
|
1281
|
+
} else {
|
|
1282
|
+
const values2 = marksValues.value;
|
|
1283
|
+
const lastIndex = values2.length - 1;
|
|
1284
|
+
const currentIndex = values2.indexOf(value);
|
|
1285
|
+
const first = values2[0];
|
|
1286
|
+
const last = values2[lastIndex];
|
|
1287
|
+
if (event.key === "Home" && typeof first === "number")
|
|
1288
|
+
return commitValueFromEvent(event, first);
|
|
1289
|
+
if (event.key === "End" && typeof last === "number")
|
|
1290
|
+
return commitValueFromEvent(event, last);
|
|
1291
|
+
if (INCREMENT_KEYS.has(event.key)) {
|
|
1292
|
+
const nextIdx = currentIndex < 0 ? 0 : Math.min(lastIndex, currentIndex + 1);
|
|
1293
|
+
const next = values2[nextIdx];
|
|
1294
|
+
if (next !== value && typeof next === "number") commitValueFromEvent(event, next);
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
if (DECREMENT_KEYS.has(event.key)) {
|
|
1298
|
+
const nextIdx = currentIndex < 0 ? 0 : Math.max(0, currentIndex - 1);
|
|
1299
|
+
const next = values2[nextIdx];
|
|
1300
|
+
if (next !== value && typeof next === "number") commitValueFromEvent(event, next);
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1305
|
+
const trackOffset = computed(
|
|
1306
|
+
() => MathUtils.valueToPercent(
|
|
1307
|
+
isRange.value && values.value[0] ? values.value[0] : min.value,
|
|
1308
|
+
min.value,
|
|
1309
|
+
max.value
|
|
1310
|
+
)
|
|
1311
|
+
);
|
|
1312
|
+
const trackLength = computed(
|
|
1313
|
+
() => MathUtils.valueToPercent(values.value.at(-1) ?? 0, min.value, max.value) - trackOffset.value
|
|
1314
|
+
);
|
|
1315
|
+
const trackStyle = computed(() => ({
|
|
1316
|
+
[axis.value.position]: `${trackOffset.value}%`,
|
|
1317
|
+
[axis.value.size]: `${trackLength.value}%`
|
|
1318
|
+
}));
|
|
1319
|
+
const isMarkActive = computed(() => (markValue) => {
|
|
1320
|
+
if (isRange.value) {
|
|
1321
|
+
const minValue = Math.min(...values.value);
|
|
1322
|
+
const maxValue = Math.max(...values.value);
|
|
1323
|
+
return markValue >= minValue && markValue <= maxValue;
|
|
1324
|
+
}
|
|
1325
|
+
const currentValue = values.value[0];
|
|
1326
|
+
return markValue <= currentValue;
|
|
1327
|
+
});
|
|
1328
|
+
onBeforeUnmount(stopPointerListening);
|
|
1329
|
+
watch(
|
|
1330
|
+
() => isDisabled.value,
|
|
1331
|
+
() => {
|
|
1332
|
+
if (isDisabled.value) {
|
|
1333
|
+
isDragging.value = false;
|
|
1334
|
+
activeThumbIndex.value = -1;
|
|
1335
|
+
focusedThumbIndex.value = -1;
|
|
1336
|
+
stopPointerListening();
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
);
|
|
1340
|
+
return {
|
|
1341
|
+
elements: {
|
|
1342
|
+
/**
|
|
1343
|
+
* Root slider container element
|
|
1344
|
+
*/
|
|
1345
|
+
root: computed(() => ({
|
|
1346
|
+
ref: sliderRef,
|
|
1347
|
+
style: { touchAction: orientation.value === "vertical" ? "pan-x" : "pan-y" },
|
|
1348
|
+
onMousedown: handleRootMousedown,
|
|
1349
|
+
onTouchstart: handlePointerStart
|
|
1350
|
+
})),
|
|
1351
|
+
/**
|
|
1352
|
+
* Individual thumb elements for each value (span)
|
|
1353
|
+
*/
|
|
1354
|
+
thumbContainer: computed(() => (data) => ({
|
|
1355
|
+
"data-index": data.index,
|
|
1356
|
+
style: {
|
|
1357
|
+
[axis.value.position]: `${MathUtils.valueToPercent(data.value, min.value, max.value)}%`
|
|
1358
|
+
}
|
|
1359
|
+
})),
|
|
1360
|
+
/**
|
|
1361
|
+
* Visually hidden input inside each thumb for accessibility
|
|
1362
|
+
*/
|
|
1363
|
+
thumbInput: computed(() => (data) => ({
|
|
1364
|
+
min: min.value,
|
|
1365
|
+
max: max.value,
|
|
1366
|
+
value: data.value,
|
|
1367
|
+
role: "slider",
|
|
1368
|
+
type: "range",
|
|
1369
|
+
"aria-label": label.value,
|
|
1370
|
+
"aria-valuemin": min.value,
|
|
1371
|
+
"aria-valuemax": max.value,
|
|
1372
|
+
"aria-valuenow": data.value,
|
|
1373
|
+
"aria-orientation": orientation.value,
|
|
1374
|
+
"data-index": data.index,
|
|
1375
|
+
tabIndex: isDisabled.value ? -1 : 0,
|
|
1376
|
+
step: isDiscrete.value && marks.value ? "any" : step.value ?? void 0,
|
|
1377
|
+
disabled: typeof isDisabled.value === "boolean" ? isDisabled.value : false,
|
|
1378
|
+
onChange: handleHiddenInputChange,
|
|
1379
|
+
onFocus: handleHiddenInputFocus,
|
|
1380
|
+
onBlur: handleHiddenInputBlur,
|
|
1381
|
+
onKeydown: handleHiddenInputKeydown
|
|
1382
|
+
})),
|
|
1383
|
+
/**
|
|
1384
|
+
* Mark elements
|
|
1385
|
+
*/
|
|
1386
|
+
mark: computed(() => (data) => ({
|
|
1387
|
+
"data-value": data.value,
|
|
1388
|
+
"aria-hidden": true,
|
|
1389
|
+
style: {
|
|
1390
|
+
[axis.value.position]: `${MathUtils.clamp(MathUtils.valueToPercent(data.value, min.value, max.value), 0, 100)}%`
|
|
1391
|
+
}
|
|
1392
|
+
})),
|
|
1393
|
+
/**
|
|
1394
|
+
* Label for each mark
|
|
1395
|
+
*/
|
|
1396
|
+
markLabel: computed(() => (data) => ({
|
|
1397
|
+
"data-value": data.value,
|
|
1398
|
+
style: {
|
|
1399
|
+
[axis.value.position]: `${MathUtils.valueToPercent(data.value, min.value, max.value)}%`
|
|
1400
|
+
},
|
|
1401
|
+
"aria-hidden": true
|
|
1402
|
+
})),
|
|
1403
|
+
/**
|
|
1404
|
+
* Track element representing the selected range
|
|
1405
|
+
*/
|
|
1406
|
+
track: computed(() => ({
|
|
1407
|
+
role: "presentation",
|
|
1408
|
+
"aria-hidden": true,
|
|
1409
|
+
style: trackStyle.value
|
|
1410
|
+
})),
|
|
1411
|
+
/**
|
|
1412
|
+
* Rail element representing the full slider range
|
|
1413
|
+
*/
|
|
1414
|
+
rail: computed(() => ({
|
|
1415
|
+
role: "presentation",
|
|
1416
|
+
"aria-hidden": true
|
|
1417
|
+
}))
|
|
1418
|
+
},
|
|
1419
|
+
state: {
|
|
1420
|
+
/**
|
|
1421
|
+
* True if the slider is currently being dragged.
|
|
1422
|
+
*/
|
|
1423
|
+
isDragging,
|
|
1424
|
+
/**
|
|
1425
|
+
* Index of the currently active thumb.
|
|
1426
|
+
* Thumb could be active even if not dragging (e.g. click on the rail to move the thumb there).
|
|
1427
|
+
* `-1` if no thumb is active.
|
|
1428
|
+
*/
|
|
1429
|
+
activeThumbIndex,
|
|
1430
|
+
/**
|
|
1431
|
+
* Index of the thumb that is currently focused.
|
|
1432
|
+
* `-1` if no thumb is focused.
|
|
1433
|
+
*/
|
|
1434
|
+
focusedThumbIndex,
|
|
1435
|
+
/**
|
|
1436
|
+
* `true` if the slider is a range slider (with two or more thumbs).
|
|
1437
|
+
*/
|
|
1438
|
+
isRange,
|
|
1439
|
+
/**
|
|
1440
|
+
* Offset of the track as a percentage (0-100).
|
|
1441
|
+
*/
|
|
1442
|
+
trackOffset,
|
|
1443
|
+
/**
|
|
1444
|
+
* Length of the track as a percentage (0-100).
|
|
1445
|
+
*/
|
|
1446
|
+
trackLength,
|
|
1447
|
+
/**
|
|
1448
|
+
* List of marks to display on the slider.
|
|
1449
|
+
* - If marks option is `true`, marks are generated based on the step value.
|
|
1450
|
+
* - If marks option is an array of numbers or objects, it is used as provided (filtered to be within range).
|
|
1451
|
+
* - If marks option is `false`, no marks are shown.
|
|
1452
|
+
*/
|
|
1453
|
+
marksList
|
|
1454
|
+
},
|
|
1455
|
+
internals: {
|
|
1456
|
+
/**
|
|
1457
|
+
* Converts a value from the slider's range to a percentage (0-100).
|
|
1458
|
+
* @param value - value to convert
|
|
1459
|
+
* @returns percentage representation of the value
|
|
1460
|
+
*/
|
|
1461
|
+
valueToPercent: computed(
|
|
1462
|
+
() => (value) => MathUtils.valueToPercent(value, min.value, max.value)
|
|
1463
|
+
),
|
|
1464
|
+
/**
|
|
1465
|
+
* Checks if a given mark value is active (i.e., within the selected range).
|
|
1466
|
+
* Use case: when rendering marks, to determine if a mark is covered by the selected range.
|
|
1467
|
+
*
|
|
1468
|
+
* @param markValue - value of the mark to check
|
|
1469
|
+
* @returns `true` if the mark is active, `false` otherwise
|
|
1470
|
+
*/
|
|
1471
|
+
isMarkActive,
|
|
1472
|
+
/**
|
|
1473
|
+
* Clamps a value to the slider's range.
|
|
1474
|
+
* @param value - value to clamp
|
|
1475
|
+
* @returns clamped value
|
|
1476
|
+
*/
|
|
1477
|
+
clampValue: computed(() => (value) => MathUtils.clamp(value, min.value, max.value)),
|
|
1478
|
+
/**
|
|
1479
|
+
* Main axis properties based on orientation.
|
|
1480
|
+
*/
|
|
1481
|
+
axis,
|
|
1482
|
+
/**
|
|
1483
|
+
* Rounds a value to the nearest valid step.
|
|
1484
|
+
* @param value - value to round
|
|
1485
|
+
* @returns rounded value
|
|
1486
|
+
*/
|
|
1487
|
+
roundToStep: computed(
|
|
1488
|
+
() => (value) => !isDiscrete.value ? roundToStep(value, step.value, min.value) : marksValues.value[findClosestIndex(marksValues.value, value)]
|
|
1489
|
+
),
|
|
1490
|
+
/**
|
|
1491
|
+
* Normalizes an array of values to ensure they are within min/max bounds,
|
|
1492
|
+
*/
|
|
1493
|
+
normalizeValues: computed(
|
|
1494
|
+
() => (values2) => normalizeValues(values2, min.value, max.value, step.value)
|
|
1495
|
+
)
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
);
|
|
885
1500
|
const createTabs = createBuilder((options) => {
|
|
886
1501
|
const idMap = /* @__PURE__ */ new Map();
|
|
887
1502
|
const getId = (value) => {
|
|
@@ -1066,6 +1681,7 @@ export {
|
|
|
1066
1681
|
CLOSING_KEYS,
|
|
1067
1682
|
OPENING_KEYS,
|
|
1068
1683
|
_unstableCreateCalendar,
|
|
1684
|
+
_unstableCreateSlider,
|
|
1069
1685
|
createBuilder,
|
|
1070
1686
|
createComboBox,
|
|
1071
1687
|
createElRef,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {
|
|
2
|
+
buttonRef: HTMLButtonElement;
|
|
3
|
+
}, HTMLDivElement>;
|
|
4
|
+
export default _default;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {
|
|
2
|
+
buttonRef: HTMLButtonElement;
|
|
3
|
+
}, HTMLDivElement>;
|
|
4
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if an element has focus-visible state (keyboard focus).
|
|
3
|
+
* Falls back to false if :focus-visible is not supported.
|
|
4
|
+
*/
|
|
5
|
+
export declare const isFocusVisible: (element: Element) => boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Determines whether a given event is a `TouchEvent`.
|
|
8
|
+
*
|
|
9
|
+
* This function uses property-based detection instead of `instanceof TouchEvent`,
|
|
10
|
+
* because Safari and other WebKit-based browsers may not expose the global
|
|
11
|
+
* `TouchEvent` constructor, causing `instanceof` checks to fail or throw errors.
|
|
12
|
+
*
|
|
13
|
+
* @param event - The event object to check.
|
|
14
|
+
* @returns `true` if the event is a touch event, otherwise `false`.
|
|
15
|
+
*/
|
|
16
|
+
export declare const isTouchEvent: (event: Event) => event is TouchEvent;
|
package/dist/utils/math.d.ts
CHANGED
|
@@ -3,4 +3,31 @@ export declare const MathUtils: {
|
|
|
3
3
|
* Ensures that a given `number` is or is between a given `min` and `max`.
|
|
4
4
|
*/
|
|
5
5
|
clamp: (number: number, min: number, max: number) => number;
|
|
6
|
+
/**
|
|
7
|
+
* Returns the count of decimal places in a number.
|
|
8
|
+
* @param number - The number to check.
|
|
9
|
+
* @returns The count of decimal places.
|
|
10
|
+
*
|
|
11
|
+
* decimals(1.23); // 2
|
|
12
|
+
* decimals(10); // 0
|
|
13
|
+
*/
|
|
14
|
+
decimalsCount: (number: number) => number;
|
|
15
|
+
/**
|
|
16
|
+
* Converts a value within a range to a percentage (0-100).
|
|
17
|
+
*
|
|
18
|
+
* @param value - The value to convert.
|
|
19
|
+
* @param min - The minimum allowed value.
|
|
20
|
+
* @param max - The maximum allowed value.
|
|
21
|
+
* @returns The percentage representation of the value.
|
|
22
|
+
*/
|
|
23
|
+
valueToPercent: (value: number, min: number, max: number) => number;
|
|
24
|
+
/**
|
|
25
|
+
* Converts a percentage (0-100) to a value within a range.
|
|
26
|
+
*
|
|
27
|
+
* @param percent - The percentage to convert.
|
|
28
|
+
* @param min - The minimum allowed value.
|
|
29
|
+
* @param max - The maximum allowed value.
|
|
30
|
+
* @returns The value representation of the percentage.
|
|
31
|
+
*/
|
|
32
|
+
percentToValue: (percent: number, min: number, max: number) => number;
|
|
6
33
|
};
|
package/package.json
CHANGED