base-ui-vue 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -1
- package/dist/button/Button.cjs +53 -12
- package/dist/button/Button.cjs.map +1 -1
- package/dist/button/Button.js +26 -15
- package/dist/button/Button.js.map +1 -1
- package/dist/button/ToolbarButton.cjs +367 -0
- package/dist/button/ToolbarButton.cjs.map +1 -0
- package/dist/button/ToolbarButton.js +320 -0
- package/dist/button/ToolbarButton.js.map +1 -0
- package/dist/button/ToolbarButtonDataAttributes.cjs +27 -0
- package/dist/button/ToolbarButtonDataAttributes.cjs.map +1 -0
- package/dist/button/ToolbarButtonDataAttributes.js +21 -0
- package/dist/button/ToolbarButtonDataAttributes.js.map +1 -0
- package/dist/checkbox/index.cjs +1173 -0
- package/dist/checkbox/index.cjs.map +1 -0
- package/dist/checkbox/index.js +1048 -0
- package/dist/checkbox/index.js.map +1 -0
- package/dist/checkbox-group/CheckboxGroup.cjs +629 -0
- package/dist/checkbox-group/CheckboxGroup.cjs.map +1 -0
- package/dist/checkbox-group/CheckboxGroup.js +540 -0
- package/dist/checkbox-group/CheckboxGroup.js.map +1 -0
- package/dist/checkbox-group/CheckboxGroupDataAttributes.cjs +18 -0
- package/dist/checkbox-group/CheckboxGroupDataAttributes.cjs.map +1 -0
- package/dist/checkbox-group/CheckboxGroupDataAttributes.js +12 -0
- package/dist/checkbox-group/CheckboxGroupDataAttributes.js.map +1 -0
- package/dist/composite/composite.cjs +167 -0
- package/dist/composite/composite.cjs.map +1 -1
- package/dist/composite/composite.js +96 -1
- package/dist/composite/composite.js.map +1 -1
- package/dist/composite/constants.cjs +12 -0
- package/dist/composite/constants.cjs.map +1 -0
- package/dist/composite/constants.js +6 -0
- package/dist/composite/constants.js.map +1 -0
- package/dist/control/FieldControl.cjs +18 -343
- package/dist/control/FieldControl.cjs.map +1 -1
- package/dist/control/FieldControl.js +14 -285
- package/dist/control/FieldControl.js.map +1 -1
- package/dist/control/SliderControl.cjs +636 -0
- package/dist/control/SliderControl.cjs.map +1 -0
- package/dist/control/SliderControl.js +553 -0
- package/dist/control/SliderControl.js.map +1 -0
- package/dist/control/SliderControlDataAttributes.cjs +47 -0
- package/dist/control/SliderControlDataAttributes.cjs.map +1 -0
- package/dist/control/SliderControlDataAttributes.js +41 -0
- package/dist/control/SliderControlDataAttributes.js.map +1 -0
- package/dist/csp-provider/CSPContext.cjs +32 -0
- package/dist/csp-provider/CSPContext.cjs.map +1 -0
- package/dist/csp-provider/CSPContext.js +21 -0
- package/dist/csp-provider/CSPContext.js.map +1 -0
- package/dist/csp-provider/CSPProvider.cjs +46 -0
- package/dist/csp-provider/CSPProvider.cjs.map +1 -0
- package/dist/csp-provider/CSPProvider.js +41 -0
- package/dist/csp-provider/CSPProvider.js.map +1 -0
- package/dist/description/FieldDescription.cjs +5 -5
- package/dist/description/FieldDescription.cjs.map +1 -1
- package/dist/description/FieldDescription.js +1 -1
- package/dist/direction-provider/DirectionProvider.cjs +2 -2
- package/dist/direction-provider/DirectionProvider.cjs.map +1 -1
- package/dist/direction-provider/DirectionProvider.js +1 -1
- package/dist/error/FieldError.cjs +10 -288
- package/dist/error/FieldError.cjs.map +1 -1
- package/dist/error/FieldError.js +4 -246
- package/dist/error/FieldError.js.map +1 -1
- package/dist/form/Form.cjs +5 -4
- package/dist/form/Form.cjs.map +1 -1
- package/dist/form/Form.js +5 -4
- package/dist/form/Form.js.map +1 -1
- package/dist/group/ToolbarGroup.cjs +92 -0
- package/dist/group/ToolbarGroup.cjs.map +1 -0
- package/dist/group/ToolbarGroup.js +87 -0
- package/dist/group/ToolbarGroup.js.map +1 -0
- package/dist/group/ToolbarGroupDataAttributes.cjs +23 -0
- package/dist/group/ToolbarGroupDataAttributes.cjs.map +1 -0
- package/dist/group/ToolbarGroupDataAttributes.js +17 -0
- package/dist/group/ToolbarGroupDataAttributes.js.map +1 -0
- package/dist/header/AccordionHeader.cjs +2 -2
- package/dist/header/AccordionHeader.js +1 -1
- package/dist/image/AvatarImage.cjs +4 -4
- package/dist/image/AvatarImage.cjs.map +1 -1
- package/dist/image/AvatarImage.js +1 -1
- package/dist/index.cjs +80 -10
- package/dist/index.d.cts +2751 -612
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +2751 -612
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -5
- package/dist/index2.cjs +3651 -370
- package/dist/index2.cjs.map +1 -1
- package/dist/index2.js +3365 -270
- package/dist/index2.js.map +1 -1
- package/package.json +8 -4
- package/src/accordion/root/AccordionRoot.vue +2 -1
- package/src/checkbox/index.ts +23 -0
- package/src/checkbox/indicator/CheckboxIndicator.vue +102 -0
- package/src/checkbox/indicator/CheckboxIndicatorDataAttributes.ts +61 -0
- package/src/checkbox/root/CheckboxRoot.vue +632 -0
- package/src/checkbox/root/CheckboxRootContext.ts +22 -0
- package/src/checkbox/root/CheckboxRootDataAttributes.ts +54 -0
- package/src/checkbox/utils/useStateAttributesMapping.ts +30 -0
- package/src/checkbox-group/CheckboxGroup.vue +241 -0
- package/src/checkbox-group/CheckboxGroupContext.ts +39 -0
- package/src/checkbox-group/CheckboxGroupDataAttributes.ts +6 -0
- package/src/checkbox-group/index.ts +11 -0
- package/src/checkbox-group/useCheckboxGroupParent.ts +173 -0
- package/src/collapsible/panel/useCollapsiblePanel.ts +2 -1
- package/src/collapsible/root/useCollapsibleRoot.ts +3 -1
- package/src/composite/composite.ts +2 -0
- package/src/composite/item/CompositeItem.vue +7 -8
- package/src/composite/root/CompositeRoot.vue +12 -1
- package/src/csp-provider/CSPContext.ts +26 -0
- package/src/csp-provider/CSPProvider.vue +40 -0
- package/src/csp-provider/index.ts +5 -0
- package/src/field/item/FieldItem.vue +6 -1
- package/src/field/label/FieldLabel.vue +10 -51
- package/src/field/root/FieldRoot.vue +16 -3
- package/src/floating-ui-vue/types.ts +1 -4
- package/src/floating-ui-vue/utils/element.ts +12 -0
- package/src/floating-ui-vue/utils/shadowDom.ts +44 -0
- package/src/floating-ui-vue/utils.ts +3 -0
- package/src/form/Form.vue +5 -3
- package/src/index.ts +9 -0
- package/src/labelable-provider/LabelableContext.ts +2 -2
- package/src/labelable-provider/LabelableProvider.vue +21 -4
- package/src/labelable-provider/index.ts +2 -0
- package/src/labelable-provider/useAriaLabelledBy.ts +9 -9
- package/src/labelable-provider/useLabel.ts +115 -0
- package/src/labelable-provider/useLabelableId.ts +12 -10
- package/src/separator/Separator.vue +65 -0
- package/src/separator/SeparatorDataAttributes.ts +7 -0
- package/src/separator/index.ts +3 -0
- package/src/slider/control/SliderControl.vue +497 -0
- package/src/slider/control/SliderControlDataAttributes.ts +35 -0
- package/src/slider/index.ts +35 -0
- package/src/slider/indicator/SliderIndicator.vue +144 -0
- package/src/slider/indicator/SliderIndicatorDataAttributes.ts +35 -0
- package/src/slider/label/SliderLabel.vue +75 -0
- package/src/slider/root/SliderRoot.vue +557 -0
- package/src/slider/root/SliderRootContext.ts +126 -0
- package/src/slider/root/SliderRootDataAttributes.ts +35 -0
- package/src/slider/root/stateAttributesMapping.ts +13 -0
- package/src/slider/thumb/SliderThumb.vue +601 -0
- package/src/slider/thumb/SliderThumbDataAttributes.ts +39 -0
- package/src/slider/thumb/prehydrationScript.min.ts +5 -0
- package/src/slider/thumb/prehydrationScript.template.js +69 -0
- package/src/slider/track/SliderTrack.vue +48 -0
- package/src/slider/track/SliderTrackDataAttributes.ts +10 -0
- package/src/slider/utils/asc.ts +3 -0
- package/src/slider/utils/getMidpoint.ts +9 -0
- package/src/slider/utils/getPushedThumbValues.ts +68 -0
- package/src/slider/utils/getSliderValue.ts +25 -0
- package/src/slider/utils/replaceArrayItemAtIndex.ts +15 -0
- package/src/slider/utils/resolveThumbCollision.ts +177 -0
- package/src/slider/utils/roundValueToStep.ts +19 -0
- package/src/slider/utils/test-utils.ts +25 -0
- package/src/slider/utils/validateMinimumDistance.ts +20 -0
- package/src/slider/utils/valueArrayToPercentages.ts +10 -0
- package/src/slider/value/SliderValue.vue +90 -0
- package/src/slider/value/SliderValueDataAttributes.ts +35 -0
- package/src/switch/index.ts +14 -0
- package/src/switch/root/SwitchRoot.vue +448 -0
- package/src/switch/root/SwitchRootContext.ts +22 -0
- package/src/switch/root/SwitchRootDataAttributes.ts +46 -0
- package/src/switch/stateAttributesMapping.ts +23 -0
- package/src/switch/thumb/SwitchThumb.vue +59 -0
- package/src/switch/thumb/SwitchThumbDataAttributes.ts +46 -0
- package/src/toggle/Toggle.vue +211 -0
- package/src/toggle/ToggleDataAttributes.ts +6 -0
- package/src/toggle/index.ts +3 -0
- package/src/toggle-group/ToggleGroup.vue +224 -0
- package/src/toggle-group/ToggleGroupContext.ts +45 -0
- package/src/toggle-group/ToggleGroupDataAttributes.ts +15 -0
- package/src/toggle-group/index.ts +5 -0
- package/src/toolbar/button/ToolbarButton.vue +99 -0
- package/src/toolbar/button/ToolbarButtonDataAttributes.ts +15 -0
- package/src/toolbar/group/ToolbarGroup.vue +70 -0
- package/src/toolbar/group/ToolbarGroupContext.ts +23 -0
- package/src/toolbar/group/ToolbarGroupDataAttributes.ts +11 -0
- package/src/toolbar/index.ts +27 -0
- package/src/toolbar/input/ToolbarInput.vue +114 -0
- package/src/toolbar/input/ToolbarInputDataAttributes.ts +15 -0
- package/src/toolbar/link/ToolbarLink.vue +54 -0
- package/src/toolbar/link/ToolbarLinkDataAttributes.ts +7 -0
- package/src/toolbar/root/ToolbarRoot.vue +144 -0
- package/src/toolbar/root/ToolbarRootContext.ts +29 -0
- package/src/toolbar/root/ToolbarRootDataAttributes.ts +11 -0
- package/src/toolbar/separator/ToolbarSeparator.vue +41 -0
- package/src/toolbar/separator/ToolbarSeparatorDataAttributes.ts +7 -0
- package/src/use-button/useButton.ts +2 -1
- package/src/utils/areArraysEqual.ts +12 -0
- package/src/utils/clamp.ts +7 -0
- package/src/utils/createBaseUIEventDetails.ts +9 -0
- package/src/utils/formatNumber.ts +7 -0
- package/src/utils/owner.ts +5 -0
- package/src/utils/resolveAriaLabelledBy.ts +10 -0
- package/src/utils/useControllableState.ts +78 -14
- package/src/utils/useFocusableWhenDisabled.ts +6 -1
- package/src/utils/useMergedRefs.ts +26 -2
- package/src/utils/useRegisteredLabelId.ts +21 -0
- package/src/utils/valueToPercent.ts +7 -0
- package/src/utils/visuallyHidden.ts +24 -0
- package/dist/direction-provider/DirectionContext.cjs +0 -26
- package/dist/direction-provider/DirectionContext.cjs.map +0 -1
- package/dist/direction-provider/DirectionContext.js +0 -15
- package/dist/direction-provider/DirectionContext.js.map +0 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export enum SliderRootDataAttributes {
|
|
2
|
+
/**
|
|
3
|
+
* Present while the user is dragging.
|
|
4
|
+
*/
|
|
5
|
+
dragging = 'data-dragging',
|
|
6
|
+
/**
|
|
7
|
+
* Indicates the orientation of the slider.
|
|
8
|
+
* @type {'horizontal' | 'vertical'}
|
|
9
|
+
*/
|
|
10
|
+
orientation = 'data-orientation',
|
|
11
|
+
/**
|
|
12
|
+
* Present when the slider is disabled.
|
|
13
|
+
*/
|
|
14
|
+
disabled = 'data-disabled',
|
|
15
|
+
/**
|
|
16
|
+
* Present when the slider is in valid state (when wrapped in Field.Root).
|
|
17
|
+
*/
|
|
18
|
+
valid = 'data-valid',
|
|
19
|
+
/**
|
|
20
|
+
* Present when the slider is in invalid state (when wrapped in Field.Root).
|
|
21
|
+
*/
|
|
22
|
+
invalid = 'data-invalid',
|
|
23
|
+
/**
|
|
24
|
+
* Present when the slider has been touched (when wrapped in Field.Root).
|
|
25
|
+
*/
|
|
26
|
+
touched = 'data-touched',
|
|
27
|
+
/**
|
|
28
|
+
* Present when the slider's value has changed (when wrapped in Field.Root).
|
|
29
|
+
*/
|
|
30
|
+
dirty = 'data-dirty',
|
|
31
|
+
/**
|
|
32
|
+
* Present when the slider is focused (when wrapped in Field.Root).
|
|
33
|
+
*/
|
|
34
|
+
focused = 'data-focused',
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StateAttributesMapping } from '../../utils/getStateAttributesProps'
|
|
2
|
+
import type { SliderRootState } from './SliderRoot.vue'
|
|
3
|
+
import { fieldValidityMapping } from '../../field/utils/constants'
|
|
4
|
+
|
|
5
|
+
export const sliderStateAttributesMapping: StateAttributesMapping<SliderRootState> = {
|
|
6
|
+
activeThumbIndex: () => null,
|
|
7
|
+
max: () => null,
|
|
8
|
+
min: () => null,
|
|
9
|
+
minStepsBetweenValues: () => null,
|
|
10
|
+
step: () => null,
|
|
11
|
+
values: () => null,
|
|
12
|
+
...fieldValidityMapping,
|
|
13
|
+
}
|
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ComponentPublicInstance, CSSProperties, Ref } from 'vue'
|
|
3
|
+
import type { LabelableContext } from '../../labelable-provider/LabelableContext'
|
|
4
|
+
import type { BaseUIComponentProps } from '../../utils/types'
|
|
5
|
+
import type { SliderRootState } from '../root/SliderRoot.vue'
|
|
6
|
+
import { computed, onMounted, ref, useAttrs, watch, watchEffect } from 'vue'
|
|
7
|
+
import {
|
|
8
|
+
ARROW_DOWN,
|
|
9
|
+
ARROW_LEFT,
|
|
10
|
+
ARROW_RIGHT,
|
|
11
|
+
ARROW_UP,
|
|
12
|
+
COMPOSITE_KEYS,
|
|
13
|
+
END,
|
|
14
|
+
HOME,
|
|
15
|
+
PAGE_DOWN,
|
|
16
|
+
PAGE_UP,
|
|
17
|
+
} from '../../composite/composite'
|
|
18
|
+
import { useCompositeListItem } from '../../composite/list/useCompositeListItem'
|
|
19
|
+
import { useCSPContext } from '../../csp-provider/CSPContext'
|
|
20
|
+
import { useDirection } from '../../direction-provider'
|
|
21
|
+
import { useFieldRootContext } from '../../field/root/FieldRootContext'
|
|
22
|
+
import { matchesFocusVisible } from '../../floating-ui-vue/utils'
|
|
23
|
+
import { useLabelableId } from '../../labelable-provider/useLabelableId'
|
|
24
|
+
import { mergeProps } from '../../merge-props/mergeProps'
|
|
25
|
+
import { createGenericEventDetails } from '../../utils/createBaseUIEventDetails'
|
|
26
|
+
import { formatNumber } from '../../utils/formatNumber'
|
|
27
|
+
import { REASONS } from '../../utils/reasons'
|
|
28
|
+
import { useBaseUiId } from '../../utils/useBaseUiId'
|
|
29
|
+
import { useMergedRefs } from '../../utils/useMergedRefs'
|
|
30
|
+
import { useRenderElement } from '../../utils/useRenderElement'
|
|
31
|
+
import { valueToPercent } from '../../utils/valueToPercent'
|
|
32
|
+
import { visuallyHidden } from '../../utils/visuallyHidden'
|
|
33
|
+
import { useSliderRootContext } from '../root/SliderRootContext'
|
|
34
|
+
import { sliderStateAttributesMapping } from '../root/stateAttributesMapping'
|
|
35
|
+
import { getMidpoint } from '../utils/getMidpoint'
|
|
36
|
+
import { getSliderValue } from '../utils/getSliderValue'
|
|
37
|
+
import { roundValueToStep } from '../utils/roundValueToStep'
|
|
38
|
+
import { script as prehydrationScript } from './prehydrationScript.min'
|
|
39
|
+
import { SliderThumbDataAttributes } from './SliderThumbDataAttributes'
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The draggable part of the slider at the tip of the indicator.
|
|
43
|
+
* Renders a `<div>` element and a nested `<input type="range">`.
|
|
44
|
+
*
|
|
45
|
+
* Documentation: [Base UI Vue Slider](https://baseui-vue.com/docs/components/slider)
|
|
46
|
+
*/
|
|
47
|
+
defineOptions({
|
|
48
|
+
name: 'SliderThumb',
|
|
49
|
+
inheritAttrs: false,
|
|
50
|
+
})
|
|
51
|
+
const props = withDefaults(defineProps<SliderThumbProps>(), {
|
|
52
|
+
as: 'div',
|
|
53
|
+
disabled: false,
|
|
54
|
+
})
|
|
55
|
+
const ALL_KEYS = new Set([
|
|
56
|
+
ARROW_UP,
|
|
57
|
+
ARROW_DOWN,
|
|
58
|
+
ARROW_LEFT,
|
|
59
|
+
ARROW_RIGHT,
|
|
60
|
+
HOME,
|
|
61
|
+
END,
|
|
62
|
+
PAGE_UP,
|
|
63
|
+
PAGE_DOWN,
|
|
64
|
+
])
|
|
65
|
+
|
|
66
|
+
function getDefaultAriaValueText(
|
|
67
|
+
values: readonly number[],
|
|
68
|
+
index: number,
|
|
69
|
+
format: Intl.NumberFormatOptions | undefined,
|
|
70
|
+
locale: Intl.LocalesArgument | undefined,
|
|
71
|
+
): string | undefined {
|
|
72
|
+
if (index < 0) {
|
|
73
|
+
return undefined
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (values.length === 2) {
|
|
77
|
+
if (index === 0) {
|
|
78
|
+
return `${formatNumber(values[index], locale, format)} start range`
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return `${formatNumber(values[index], locale, format)} end range`
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return format ? formatNumber(values[index], locale, format) : undefined
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getNewValue(
|
|
88
|
+
thumbValue: number,
|
|
89
|
+
step: number,
|
|
90
|
+
direction: 1 | -1,
|
|
91
|
+
min: number,
|
|
92
|
+
max: number,
|
|
93
|
+
): number {
|
|
94
|
+
return direction === 1 ? Math.min(thumbValue + step, max) : Math.max(thumbValue - step, min)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface ThumbMetadata {
|
|
98
|
+
inputId: LabelableContext['controlId']
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface SliderThumbState extends SliderRootState {}
|
|
102
|
+
export interface SliderThumbProps extends Omit<BaseUIComponentProps<SliderThumbState>, 'style'> {
|
|
103
|
+
/**
|
|
104
|
+
* Whether the thumb should ignore user interaction.
|
|
105
|
+
* @default false
|
|
106
|
+
*/
|
|
107
|
+
disabled?: boolean
|
|
108
|
+
/**
|
|
109
|
+
* A function which returns a string value for the [`aria-label`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-label) attribute of the `input`.
|
|
110
|
+
*/
|
|
111
|
+
getAriaLabel?: ((index: number) => string) | null
|
|
112
|
+
/**
|
|
113
|
+
* A function which returns a string value for the [`aria-valuetext`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-valuetext) attribute of the `input`.
|
|
114
|
+
* This is important for screen reader users.
|
|
115
|
+
*/
|
|
116
|
+
getAriaValueText?: ((formattedValue: string, value: number, index: number) => string) | null
|
|
117
|
+
/**
|
|
118
|
+
* The index of the thumb which corresponds to the index of its value in the
|
|
119
|
+
* `modelValue` or `defaultValue` array.
|
|
120
|
+
* This prop is required to support server-side rendering for range sliders
|
|
121
|
+
* with multiple thumbs.
|
|
122
|
+
* @example
|
|
123
|
+
* ```vue
|
|
124
|
+
* <SliderRoot :default-value="[10, 20]">
|
|
125
|
+
* <SliderThumb :index="0" />
|
|
126
|
+
* <SliderThumb :index="1" />
|
|
127
|
+
* </SliderRoot>
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
index?: number
|
|
131
|
+
/**
|
|
132
|
+
* A ref to access the nested input element.
|
|
133
|
+
*/
|
|
134
|
+
inputRef?: ((el: HTMLInputElement | null) => void) | Ref<HTMLInputElement | null> | null
|
|
135
|
+
/**
|
|
136
|
+
* Optional tab index attribute forwarded to the `input`.
|
|
137
|
+
*/
|
|
138
|
+
tabIndex?: number
|
|
139
|
+
id?: string
|
|
140
|
+
ariaLabel?: string
|
|
141
|
+
ariaLabelledby?: string
|
|
142
|
+
ariaDescribedby?: string
|
|
143
|
+
style?: CSSProperties | ((state: SliderThumbState) => CSSProperties)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const attrs = useAttrs()
|
|
147
|
+
const { nonce } = useCSPContext()
|
|
148
|
+
const direction = useDirection()
|
|
149
|
+
const rootContext = useSliderRootContext()
|
|
150
|
+
const { setTouched, setFocused, validationMode, validation } = useFieldRootContext()
|
|
151
|
+
|
|
152
|
+
const id = useBaseUiId(props.id)
|
|
153
|
+
const disabled = computed(() => props.disabled || rootContext.disabled.value)
|
|
154
|
+
const range = computed(() => rootContext.values.value.length > 1)
|
|
155
|
+
const vertical = computed(() => rootContext.orientation.value === 'vertical')
|
|
156
|
+
const rtl = computed(() => direction.value === 'rtl')
|
|
157
|
+
|
|
158
|
+
const thumbRef = ref<HTMLElement | null>(null)
|
|
159
|
+
const inputRef = ref<HTMLInputElement | null>(null)
|
|
160
|
+
const restoringFocusVisibleRef = ref(false)
|
|
161
|
+
|
|
162
|
+
const defaultInputId = useBaseUiId()
|
|
163
|
+
const labelableId = useLabelableId()
|
|
164
|
+
const inputId = computed(() => (range.value ? defaultInputId : labelableId.value))
|
|
165
|
+
|
|
166
|
+
const { ref: listItemRef, index: compositeIndex } = useCompositeListItem<ThumbMetadata>({
|
|
167
|
+
metadata: () => ({
|
|
168
|
+
inputId,
|
|
169
|
+
}),
|
|
170
|
+
index: () => props.index,
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
const index = computed(() => (!range.value ? 0 : (props.index ?? compositeIndex.value)))
|
|
174
|
+
const last = computed(() => index.value === rootContext.values.value.length - 1)
|
|
175
|
+
const thumbValue = computed(() => rootContext.values.value[index.value])
|
|
176
|
+
const thumbValuePercent = computed(() => valueToPercent(thumbValue.value, rootContext.min.value, rootContext.max.value))
|
|
177
|
+
|
|
178
|
+
const isMounted = ref(false)
|
|
179
|
+
const positionPercent = ref<number | undefined>(undefined)
|
|
180
|
+
|
|
181
|
+
onMounted(() => {
|
|
182
|
+
isMounted.value = true
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
const safeLastUsedThumbIndex = computed(() =>
|
|
186
|
+
rootContext.lastUsedThumbIndex.value >= 0 && rootContext.lastUsedThumbIndex.value < rootContext.values.value.length
|
|
187
|
+
? rootContext.lastUsedThumbIndex.value
|
|
188
|
+
: -1)
|
|
189
|
+
|
|
190
|
+
function setIndicatorPositionForIndex(nextInsetPosition: number | undefined) {
|
|
191
|
+
rootContext.setIndicatorPosition((prevPosition) => {
|
|
192
|
+
const next = [...prevPosition]
|
|
193
|
+
if (index.value === 0) {
|
|
194
|
+
next[0] = nextInsetPosition
|
|
195
|
+
}
|
|
196
|
+
else if (last.value) {
|
|
197
|
+
next[1] = nextInsetPosition
|
|
198
|
+
}
|
|
199
|
+
return next
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function getInsetPosition() {
|
|
204
|
+
const control = rootContext.controlRef.value
|
|
205
|
+
const thumb = thumbRef.value
|
|
206
|
+
if (!control || !thumb) {
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const thumbRect = thumb.getBoundingClientRect()
|
|
211
|
+
const controlRect = control.getBoundingClientRect()
|
|
212
|
+
const side = vertical.value ? 'height' : 'width'
|
|
213
|
+
const controlSize = controlRect[side] - thumbRect[side]
|
|
214
|
+
const thumbOffsetFromControlEdge = thumbRect[side] / 2 + (controlSize * thumbValuePercent.value) / 100
|
|
215
|
+
const nextPositionPercent = (thumbOffsetFromControlEdge / controlRect[side]) * 100
|
|
216
|
+
const nextInsetPosition = Number.isFinite(nextPositionPercent) ? nextPositionPercent : undefined
|
|
217
|
+
|
|
218
|
+
positionPercent.value = nextInsetPosition
|
|
219
|
+
setIndicatorPositionForIndex(nextInsetPosition)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
watch(
|
|
223
|
+
() => [rootContext.inset.value, thumbValuePercent.value, isMounted.value],
|
|
224
|
+
() => {
|
|
225
|
+
if (rootContext.inset.value) {
|
|
226
|
+
queueMicrotask(getInsetPosition)
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
{ immediate: true },
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
watchEffect((onCleanup) => {
|
|
233
|
+
if (!rootContext.inset.value || typeof ResizeObserver !== 'function') {
|
|
234
|
+
return
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const control = rootContext.controlRef.value
|
|
238
|
+
const thumb = thumbRef.value
|
|
239
|
+
if (!control || !thumb) {
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const observer = new ResizeObserver(getInsetPosition)
|
|
244
|
+
observer.observe(control)
|
|
245
|
+
observer.observe(thumb)
|
|
246
|
+
|
|
247
|
+
onCleanup(() => {
|
|
248
|
+
observer.disconnect()
|
|
249
|
+
})
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
const thumbStyle = computed(() => {
|
|
253
|
+
const startEdge = vertical.value ? 'bottom' : 'insetInlineStart'
|
|
254
|
+
const crossOffsetProperty = vertical.value ? 'left' : 'top'
|
|
255
|
+
|
|
256
|
+
let zIndex: number | undefined
|
|
257
|
+
if (range.value) {
|
|
258
|
+
if (rootContext.active.value === index.value) {
|
|
259
|
+
zIndex = 2
|
|
260
|
+
}
|
|
261
|
+
else if (safeLastUsedThumbIndex.value === index.value) {
|
|
262
|
+
zIndex = 1
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
else if (rootContext.active.value === index.value) {
|
|
266
|
+
zIndex = 1
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (!rootContext.inset.value) {
|
|
270
|
+
if (!Number.isFinite(thumbValuePercent.value)) {
|
|
271
|
+
return visuallyHidden
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
position: 'absolute',
|
|
276
|
+
[startEdge]: `${thumbValuePercent.value}%`,
|
|
277
|
+
[crossOffsetProperty]: '50%',
|
|
278
|
+
translate: `${(vertical.value || !rtl.value ? -1 : 1) * 50}% ${(vertical.value ? 1 : -1) * 50}%`,
|
|
279
|
+
zIndex,
|
|
280
|
+
} satisfies CSSProperties
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return {
|
|
284
|
+
'--position': `${positionPercent.value ?? 0}%`,
|
|
285
|
+
'visibility':
|
|
286
|
+
(rootContext.renderBeforeHydration.value && !isMounted.value) || positionPercent.value === undefined
|
|
287
|
+
? 'hidden'
|
|
288
|
+
: undefined,
|
|
289
|
+
'position': 'absolute',
|
|
290
|
+
[startEdge]: 'var(--position)',
|
|
291
|
+
[crossOffsetProperty]: '50%',
|
|
292
|
+
'translate': `${(vertical.value || !rtl.value ? -1 : 1) * 50}% ${(vertical.value ? 1 : -1) * 50}%`,
|
|
293
|
+
zIndex,
|
|
294
|
+
} satisfies CSSProperties & Record<string, unknown>
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
const cssWritingMode = computed<CSSProperties['writingMode'] | undefined>(() => {
|
|
298
|
+
if (rootContext.orientation.value === 'vertical') {
|
|
299
|
+
return rtl.value ? 'vertical-rl' : 'vertical-lr'
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return undefined
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
const ariaLabel = computed(() =>
|
|
306
|
+
typeof props.getAriaLabel === 'function' ? props.getAriaLabel(index.value) : props.ariaLabel)
|
|
307
|
+
|
|
308
|
+
function setInputRef(node: HTMLInputElement | null) {
|
|
309
|
+
inputRef.value = node
|
|
310
|
+
validation.setInputRef(node)
|
|
311
|
+
|
|
312
|
+
const forwardedInputRef = props.inputRef
|
|
313
|
+
|
|
314
|
+
if (!forwardedInputRef) {
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (typeof forwardedInputRef === 'function') {
|
|
319
|
+
forwardedInputRef(node)
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
forwardedInputRef.value = node
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function setInputVNodeRef(node: Element | ComponentPublicInstance | null) {
|
|
327
|
+
setInputRef(node instanceof HTMLInputElement ? node : null)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function handleBlur(event: FocusEvent) {
|
|
331
|
+
if (restoringFocusVisibleRef.value) {
|
|
332
|
+
event.stopPropagation()
|
|
333
|
+
return
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (!thumbRef.value) {
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
rootContext.setActive(-1)
|
|
341
|
+
setTouched(true)
|
|
342
|
+
setFocused(false)
|
|
343
|
+
|
|
344
|
+
if (validationMode.value === 'onBlur') {
|
|
345
|
+
validation.commit(getSliderValue(
|
|
346
|
+
thumbValue.value,
|
|
347
|
+
index.value,
|
|
348
|
+
rootContext.min.value,
|
|
349
|
+
rootContext.max.value,
|
|
350
|
+
range.value,
|
|
351
|
+
rootContext.values.value,
|
|
352
|
+
))
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
357
|
+
if (!ALL_KEYS.has(event.key)) {
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (COMPOSITE_KEYS.has(event.key)) {
|
|
362
|
+
event.stopPropagation()
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
let newValue: number | null = null
|
|
366
|
+
const roundedValue = roundValueToStep(thumbValue.value, rootContext.step.value, rootContext.min.value)
|
|
367
|
+
switch (event.key) {
|
|
368
|
+
case ARROW_UP:
|
|
369
|
+
newValue = getNewValue(roundedValue, event.shiftKey ? rootContext.largeStep.value : rootContext.step.value, 1, rootContext.min.value, rootContext.max.value)
|
|
370
|
+
break
|
|
371
|
+
case ARROW_RIGHT:
|
|
372
|
+
newValue = getNewValue(
|
|
373
|
+
roundedValue,
|
|
374
|
+
event.shiftKey ? rootContext.largeStep.value : rootContext.step.value,
|
|
375
|
+
rtl.value ? -1 : 1,
|
|
376
|
+
rootContext.min.value,
|
|
377
|
+
rootContext.max.value,
|
|
378
|
+
)
|
|
379
|
+
break
|
|
380
|
+
case ARROW_DOWN:
|
|
381
|
+
newValue = getNewValue(roundedValue, event.shiftKey ? rootContext.largeStep.value : rootContext.step.value, -1, rootContext.min.value, rootContext.max.value)
|
|
382
|
+
break
|
|
383
|
+
case ARROW_LEFT:
|
|
384
|
+
newValue = getNewValue(
|
|
385
|
+
roundedValue,
|
|
386
|
+
event.shiftKey ? rootContext.largeStep.value : rootContext.step.value,
|
|
387
|
+
rtl.value ? 1 : -1,
|
|
388
|
+
rootContext.min.value,
|
|
389
|
+
rootContext.max.value,
|
|
390
|
+
)
|
|
391
|
+
break
|
|
392
|
+
case PAGE_UP:
|
|
393
|
+
newValue = getNewValue(roundedValue, rootContext.largeStep.value, 1, rootContext.min.value, rootContext.max.value)
|
|
394
|
+
break
|
|
395
|
+
case PAGE_DOWN:
|
|
396
|
+
newValue = getNewValue(roundedValue, rootContext.largeStep.value, -1, rootContext.min.value, rootContext.max.value)
|
|
397
|
+
break
|
|
398
|
+
case END:
|
|
399
|
+
newValue = rootContext.max.value
|
|
400
|
+
if (range.value) {
|
|
401
|
+
newValue = Number.isFinite(rootContext.values.value[index.value + 1])
|
|
402
|
+
? rootContext.values.value[index.value + 1] - rootContext.step.value * rootContext.minStepsBetweenValues.value
|
|
403
|
+
: rootContext.max.value
|
|
404
|
+
}
|
|
405
|
+
break
|
|
406
|
+
case HOME:
|
|
407
|
+
newValue = rootContext.min.value
|
|
408
|
+
if (range.value) {
|
|
409
|
+
newValue = Number.isFinite(rootContext.values.value[index.value - 1])
|
|
410
|
+
? rootContext.values.value[index.value - 1] + rootContext.step.value * rootContext.minStepsBetweenValues.value
|
|
411
|
+
: rootContext.min.value
|
|
412
|
+
}
|
|
413
|
+
break
|
|
414
|
+
default:
|
|
415
|
+
break
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (newValue !== null) {
|
|
419
|
+
const input = event.currentTarget as HTMLInputElement
|
|
420
|
+
if (!matchesFocusVisible(input)) {
|
|
421
|
+
restoringFocusVisibleRef.value = true
|
|
422
|
+
input.blur()
|
|
423
|
+
;(input as HTMLInputElement & { focusVisible?: boolean }).focus({
|
|
424
|
+
preventScroll: true,
|
|
425
|
+
focusVisible: true,
|
|
426
|
+
} as FocusOptions)
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
rootContext.handleInputChange(newValue, index.value, event)
|
|
430
|
+
rootContext.onValueCommitted(
|
|
431
|
+
rootContext.lastChangedValueRef.value ?? getSliderValue(
|
|
432
|
+
newValue,
|
|
433
|
+
index.value,
|
|
434
|
+
rootContext.min.value,
|
|
435
|
+
rootContext.max.value,
|
|
436
|
+
range.value,
|
|
437
|
+
rootContext.values.value,
|
|
438
|
+
),
|
|
439
|
+
createGenericEventDetails(REASONS.keyboard, event),
|
|
440
|
+
)
|
|
441
|
+
event.preventDefault()
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const inputStyle = computed(() => ({
|
|
446
|
+
...visuallyHidden,
|
|
447
|
+
width: '100%',
|
|
448
|
+
height: '100%',
|
|
449
|
+
writingMode: cssWritingMode.value,
|
|
450
|
+
}))
|
|
451
|
+
|
|
452
|
+
const inputValidationProps = computed(() => validation.getInputValidationProps())
|
|
453
|
+
const forwardedInputAttrs = computed(() => {
|
|
454
|
+
const attrsObject = attrs as Record<string, unknown>
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
onBlur: attrsObject.onBlur,
|
|
458
|
+
onFocus: attrsObject.onFocus,
|
|
459
|
+
onKeydown: attrsObject.onKeydown,
|
|
460
|
+
}
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
const thumbAttrs = computed(() => {
|
|
464
|
+
const {
|
|
465
|
+
onBlur: _onBlur,
|
|
466
|
+
onFocus: _onFocus,
|
|
467
|
+
onKeydown: _onKeydown,
|
|
468
|
+
...rest
|
|
469
|
+
} = attrs as Record<string, unknown>
|
|
470
|
+
|
|
471
|
+
return rest
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
const inputProps = computed(() => mergeProps(
|
|
475
|
+
inputValidationProps.value,
|
|
476
|
+
forwardedInputAttrs.value,
|
|
477
|
+
{
|
|
478
|
+
'aria-label': ariaLabel.value,
|
|
479
|
+
'aria-labelledby': props.ariaLabelledby ?? (ariaLabel.value == null ? rootContext.labelId.value : undefined),
|
|
480
|
+
'aria-describedby': props.ariaDescribedby ?? inputValidationProps.value['aria-describedby'],
|
|
481
|
+
'aria-orientation': rootContext.orientation.value,
|
|
482
|
+
'aria-valuenow': thumbValue.value,
|
|
483
|
+
'aria-valuetext':
|
|
484
|
+
typeof props.getAriaValueText === 'function'
|
|
485
|
+
? props.getAriaValueText(
|
|
486
|
+
formatNumber(
|
|
487
|
+
thumbValue.value,
|
|
488
|
+
rootContext.locale.value,
|
|
489
|
+
rootContext.formatOptionsRef.value,
|
|
490
|
+
),
|
|
491
|
+
thumbValue.value,
|
|
492
|
+
index.value,
|
|
493
|
+
)
|
|
494
|
+
: getDefaultAriaValueText(
|
|
495
|
+
rootContext.values.value,
|
|
496
|
+
index.value,
|
|
497
|
+
rootContext.formatOptionsRef.value,
|
|
498
|
+
rootContext.locale.value,
|
|
499
|
+
),
|
|
500
|
+
'disabled': disabled.value,
|
|
501
|
+
'form': rootContext.form.value,
|
|
502
|
+
'id': inputId.value,
|
|
503
|
+
'max': rootContext.max.value,
|
|
504
|
+
'min': rootContext.min.value,
|
|
505
|
+
'name': rootContext.name.value,
|
|
506
|
+
onChange(event: Event) {
|
|
507
|
+
rootContext.handleInputChange((event.currentTarget as HTMLInputElement).valueAsNumber, index.value, event)
|
|
508
|
+
},
|
|
509
|
+
onFocus(event: FocusEvent) {
|
|
510
|
+
const isRestoringFocusVisible = restoringFocusVisibleRef.value
|
|
511
|
+
restoringFocusVisibleRef.value = false
|
|
512
|
+
rootContext.setActive(index.value)
|
|
513
|
+
setFocused(true)
|
|
514
|
+
|
|
515
|
+
if (isRestoringFocusVisible) {
|
|
516
|
+
event.stopPropagation()
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
'onBlur': handleBlur,
|
|
520
|
+
'onKeydown': handleKeydown,
|
|
521
|
+
'step': rootContext.step.value,
|
|
522
|
+
'style': inputStyle.value,
|
|
523
|
+
'tabIndex': props.tabIndex ?? undefined,
|
|
524
|
+
'type': 'range',
|
|
525
|
+
'value': thumbValue.value ?? '',
|
|
526
|
+
},
|
|
527
|
+
))
|
|
528
|
+
|
|
529
|
+
const mergedRef = useMergedRefs(listItemRef, thumbRef)
|
|
530
|
+
const thumbProps = computed(() => mergeProps(
|
|
531
|
+
thumbAttrs.value,
|
|
532
|
+
{
|
|
533
|
+
[SliderThumbDataAttributes.index]: index.value,
|
|
534
|
+
id,
|
|
535
|
+
onPointerdown(event: PointerEvent) {
|
|
536
|
+
rootContext.pressedThumbIndexRef.value = index.value
|
|
537
|
+
|
|
538
|
+
if (thumbRef.value != null) {
|
|
539
|
+
const axis = rootContext.orientation.value === 'horizontal' ? 'x' : 'y'
|
|
540
|
+
const midpoint = getMidpoint(thumbRef.value)
|
|
541
|
+
const offset = (rootContext.orientation.value === 'horizontal' ? event.clientX : event.clientY) - midpoint[axis]
|
|
542
|
+
rootContext.pressedThumbCenterOffsetRef.value = offset
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (inputRef.value != null && rootContext.pressedInputRef.value !== inputRef.value) {
|
|
546
|
+
rootContext.pressedInputRef.value = inputRef.value
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
style: thumbStyle.value,
|
|
550
|
+
suppressHydrationWarning: rootContext.renderBeforeHydration.value || undefined,
|
|
551
|
+
},
|
|
552
|
+
))
|
|
553
|
+
|
|
554
|
+
const { tag, mergedProps, renderless, ref: renderRef } = useRenderElement({
|
|
555
|
+
componentProps: props,
|
|
556
|
+
state: rootContext.state,
|
|
557
|
+
props: thumbProps,
|
|
558
|
+
defaultTagName: 'div',
|
|
559
|
+
ref: mergedRef,
|
|
560
|
+
stateAttributesMapping: sliderStateAttributesMapping,
|
|
561
|
+
})
|
|
562
|
+
|
|
563
|
+
watch(
|
|
564
|
+
() => rootContext.active.value,
|
|
565
|
+
() => {
|
|
566
|
+
if (disabled.value && rootContext.active.value === index.value) {
|
|
567
|
+
rootContext.setActive(-1)
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
)
|
|
571
|
+
</script>
|
|
572
|
+
|
|
573
|
+
<template>
|
|
574
|
+
<slot
|
|
575
|
+
v-if="renderless"
|
|
576
|
+
:ref="renderRef"
|
|
577
|
+
:props="mergedProps"
|
|
578
|
+
:state="rootContext.state"
|
|
579
|
+
/>
|
|
580
|
+
<component
|
|
581
|
+
:is="tag"
|
|
582
|
+
v-else
|
|
583
|
+
:ref="renderRef"
|
|
584
|
+
v-bind="mergedProps"
|
|
585
|
+
>
|
|
586
|
+
<slot />
|
|
587
|
+
<input
|
|
588
|
+
:ref="setInputVNodeRef"
|
|
589
|
+
v-bind="inputProps"
|
|
590
|
+
>
|
|
591
|
+
<!-- eslint-disable-next-line vue/require-component-is -->
|
|
592
|
+
<component
|
|
593
|
+
is="script"
|
|
594
|
+
v-if="rootContext.inset.value && !isMounted && rootContext.renderBeforeHydration.value && last"
|
|
595
|
+
:nonce="nonce"
|
|
596
|
+
:suppress-hydration-warning="true"
|
|
597
|
+
>
|
|
598
|
+
{{ prehydrationScript }}
|
|
599
|
+
</component>
|
|
600
|
+
</component>
|
|
601
|
+
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export enum SliderThumbDataAttributes {
|
|
2
|
+
/**
|
|
3
|
+
* Indicates the index of the thumb in range sliders.
|
|
4
|
+
*/
|
|
5
|
+
index = 'data-index',
|
|
6
|
+
/**
|
|
7
|
+
* Present while the user is dragging.
|
|
8
|
+
*/
|
|
9
|
+
dragging = 'data-dragging',
|
|
10
|
+
/**
|
|
11
|
+
* Indicates the orientation of the slider.
|
|
12
|
+
* @type {'horizontal' | 'vertical'}
|
|
13
|
+
*/
|
|
14
|
+
orientation = 'data-orientation',
|
|
15
|
+
/**
|
|
16
|
+
* Present when the slider is disabled.
|
|
17
|
+
*/
|
|
18
|
+
disabled = 'data-disabled',
|
|
19
|
+
/**
|
|
20
|
+
* Present when the slider is in valid state (when wrapped in Field.Root).
|
|
21
|
+
*/
|
|
22
|
+
valid = 'data-valid',
|
|
23
|
+
/**
|
|
24
|
+
* Present when the slider is in invalid state (when wrapped in Field.Root).
|
|
25
|
+
*/
|
|
26
|
+
invalid = 'data-invalid',
|
|
27
|
+
/**
|
|
28
|
+
* Present when the slider has been touched (when wrapped in Field.Root).
|
|
29
|
+
*/
|
|
30
|
+
touched = 'data-touched',
|
|
31
|
+
/**
|
|
32
|
+
* Present when the slider's value has changed (when wrapped in Field.Root).
|
|
33
|
+
*/
|
|
34
|
+
dirty = 'data-dirty',
|
|
35
|
+
/**
|
|
36
|
+
* Present when the slider is focused (when wrapped in Field.Root).
|
|
37
|
+
*/
|
|
38
|
+
focused = 'data-focused',
|
|
39
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// This file is autogenerated. Do not edit it directly.
|
|
2
|
+
// To update it, modify the corresponding source file and run `pnpm inline-scripts`.
|
|
3
|
+
|
|
4
|
+
// prettier-ignore
|
|
5
|
+
export const script = "(function prehydration() {\n const firstThumb = document.currentScript?.parentElement\n if (!firstThumb) {\n return\n }\n\n const control = firstThumb.closest('[data-base-ui-slider-control]')\n if (!control) {\n return\n }\n\n const indicator = control.querySelector('[data-base-ui-slider-indicator]')\n const controlRect = control.getBoundingClientRect()\n const vertical = control.getAttribute('data-orientation') === 'vertical'\n const side = vertical ? 'height' : 'width'\n const inputElems = control.querySelectorAll('input[type=\"range\"]')\n const range = inputElems.length > 1\n const lastIndex = inputElems.length - 1\n\n let startPosition = null\n let relativeSize = null\n\n for (let i = 0; i < inputElems.length; i += 1) {\n const input = inputElems[i]\n\n const value = Number.parseFloat(input.getAttribute('value') ?? '')\n\n if (Number.isNaN(value)) {\n return\n }\n\n const thumb = input.parentElement\n if (!thumb) {\n return\n }\n\n const max = Number.parseFloat(input.getAttribute('max') ?? '100')\n const min = Number.parseFloat(input.getAttribute('min') ?? '0')\n\n const thumbRect = thumb?.getBoundingClientRect()\n\n const controlSize = controlRect[side] - thumbRect[side]\n const thumbValuePercent = max === min ? 0 : ((value - min) * 100) / (max - min)\n const thumbOffsetFromControlEdge\n = thumbRect[side] / 2 + (controlSize * thumbValuePercent) / 100\n const percent = (thumbOffsetFromControlEdge / controlRect[side]) * 100\n\n if (Number.isFinite(percent)) {\n thumb.style.setProperty(`--position`, `${percent}%`)\n thumb.style.removeProperty('visibility')\n\n if (indicator) {\n if (i === 0) {\n startPosition = percent\n indicator.style.setProperty('--start-position', `${percent}%`)\n if (!range) {\n indicator.style.removeProperty('visibility')\n }\n }\n else if (i === lastIndex) {\n relativeSize = percent - (startPosition ?? 0)\n indicator.style.setProperty('--end-position', `${percent}%`)\n indicator.style.setProperty('--relative-size', `${relativeSize}%`)\n indicator.style.removeProperty('visibility')\n }\n }\n }\n }\n})()";
|