@funstack/ui 0.1.0-alpha.1 → 0.1.0-alpha.3
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/accordion/accordion-context.mjs.map +1 -1
- package/dist/accordion/accordion-item.mjs +18 -4
- package/dist/accordion/accordion-item.mjs.map +1 -1
- package/dist/accordion/accordion-panel.mjs +2 -3
- package/dist/accordion/accordion-panel.mjs.map +1 -1
- package/dist/accordion/accordion-root.d.mts.map +1 -1
- package/dist/accordion/accordion-root.mjs +32 -14
- package/dist/accordion/accordion-root.mjs.map +1 -1
- package/dist/accordion/accordion-trigger.mjs +4 -5
- package/dist/accordion/accordion-trigger.mjs.map +1 -1
- package/dist/checkbox/checkbox.d.mts +5 -3
- package/dist/checkbox/checkbox.d.mts.map +1 -1
- package/dist/checkbox/checkbox.mjs +25 -9
- package/dist/checkbox/checkbox.mjs.map +1 -1
- package/dist/checkbox-group/checkbox-group-context.mjs.map +1 -1
- package/dist/checkbox-group/checkbox-group-item.d.mts +2 -1
- package/dist/checkbox-group/checkbox-group-item.d.mts.map +1 -1
- package/dist/checkbox-group/checkbox-group-item.mjs +3 -1
- package/dist/checkbox-group/checkbox-group-item.mjs.map +1 -1
- package/dist/checkbox-group/checkbox-group-root.d.mts +5 -2
- package/dist/checkbox-group/checkbox-group-root.d.mts.map +1 -1
- package/dist/checkbox-group/checkbox-group-root.mjs +24 -5
- package/dist/checkbox-group/checkbox-group-root.mjs.map +1 -1
- package/dist/combobox/combobox-clear.d.mts +34 -0
- package/dist/combobox/combobox-clear.d.mts.map +1 -0
- package/dist/combobox/combobox-clear.mjs +58 -0
- package/dist/combobox/combobox-clear.mjs.map +1 -0
- package/dist/combobox/combobox-context.mjs +23 -0
- package/dist/combobox/combobox-context.mjs.map +1 -0
- package/dist/combobox/combobox-group.d.mts +72 -0
- package/dist/combobox/combobox-group.d.mts.map +1 -0
- package/dist/combobox/combobox-group.mjs +104 -0
- package/dist/combobox/combobox-group.mjs.map +1 -0
- package/dist/combobox/combobox-input.d.mts +42 -0
- package/dist/combobox/combobox-input.d.mts.map +1 -0
- package/dist/combobox/combobox-input.mjs +102 -0
- package/dist/combobox/combobox-input.mjs.map +1 -0
- package/dist/combobox/combobox-label.d.mts +22 -0
- package/dist/combobox/combobox-label.d.mts.map +1 -0
- package/dist/combobox/combobox-label.mjs +32 -0
- package/dist/combobox/combobox-label.mjs.map +1 -0
- package/dist/combobox/combobox-list.d.mts +37 -0
- package/dist/combobox/combobox-list.d.mts.map +1 -0
- package/dist/combobox/combobox-list.mjs +70 -0
- package/dist/combobox/combobox-list.mjs.map +1 -0
- package/dist/combobox/combobox-option.d.mts +45 -0
- package/dist/combobox/combobox-option.d.mts.map +1 -0
- package/dist/combobox/combobox-option.mjs +88 -0
- package/dist/combobox/combobox-option.mjs.map +1 -0
- package/dist/combobox/combobox-popup.d.mts +49 -0
- package/dist/combobox/combobox-popup.d.mts.map +1 -0
- package/dist/combobox/combobox-popup.mjs +86 -0
- package/dist/combobox/combobox-popup.mjs.map +1 -0
- package/dist/combobox/combobox-root.d.mts +135 -0
- package/dist/combobox/combobox-root.d.mts.map +1 -0
- package/dist/combobox/combobox-root.mjs +523 -0
- package/dist/combobox/combobox-root.mjs.map +1 -0
- package/dist/combobox/combobox-trigger.d.mts +36 -0
- package/dist/combobox/combobox-trigger.d.mts.map +1 -0
- package/dist/combobox/combobox-trigger.mjs +92 -0
- package/dist/combobox/combobox-trigger.mjs.map +1 -0
- package/dist/combobox/index.d.mts +36 -0
- package/dist/combobox/index.d.mts.map +1 -0
- package/dist/combobox/index.mjs +36 -0
- package/dist/combobox/index.mjs.map +1 -0
- package/dist/dialog/dialog-close.d.mts +17 -10
- package/dist/dialog/dialog-close.d.mts.map +1 -1
- package/dist/dialog/dialog-close.mjs +31 -20
- package/dist/dialog/dialog-close.mjs.map +1 -1
- package/dist/dialog/dialog-context.mjs.map +1 -1
- package/dist/dialog/dialog-form.d.mts +12 -5
- package/dist/dialog/dialog-form.d.mts.map +1 -1
- package/dist/dialog/dialog-form.mjs +16 -28
- package/dist/dialog/dialog-form.mjs.map +1 -1
- package/dist/dialog/dialog-popup.d.mts +10 -4
- package/dist/dialog/dialog-popup.d.mts.map +1 -1
- package/dist/dialog/dialog-popup.mjs +106 -41
- package/dist/dialog/dialog-popup.mjs.map +1 -1
- package/dist/dialog/dialog-root.d.mts +14 -8
- package/dist/dialog/dialog-root.d.mts.map +1 -1
- package/dist/dialog/dialog-root.mjs +66 -11
- package/dist/dialog/dialog-root.mjs.map +1 -1
- package/dist/dialog/dialog-trigger.d.mts +3 -2
- package/dist/dialog/dialog-trigger.d.mts.map +1 -1
- package/dist/dialog/dialog-trigger.mjs.map +1 -1
- package/dist/dialog/index.d.mts +4 -2
- package/dist/dialog/index.d.mts.map +1 -1
- package/dist/dialog/index.mjs +4 -2
- package/dist/dialog/index.mjs.map +1 -1
- package/dist/field/field-control.d.mts +33 -0
- package/dist/field/field-control.d.mts.map +1 -0
- package/dist/field/field-control.mjs +68 -0
- package/dist/field/field-control.mjs.map +1 -0
- package/dist/field/field-description.d.mts +24 -0
- package/dist/field/field-description.d.mts.map +1 -0
- package/dist/field/field-description.mjs +34 -0
- package/dist/field/field-description.mjs.map +1 -0
- package/dist/field/field-error.d.mts +30 -0
- package/dist/field/field-error.d.mts.map +1 -0
- package/dist/field/field-error.mjs +42 -0
- package/dist/field/field-error.mjs.map +1 -0
- package/dist/field/field-label.d.mts +25 -0
- package/dist/field/field-label.d.mts.map +1 -0
- package/dist/field/field-label.mjs +46 -0
- package/dist/field/field-label.mjs.map +1 -0
- package/dist/field/field-root.d.mts +53 -0
- package/dist/field/field-root.d.mts.map +1 -0
- package/dist/field/field-root.mjs +317 -0
- package/dist/field/field-root.mjs.map +1 -0
- package/dist/field/index.d.mts +18 -0
- package/dist/field/index.d.mts.map +1 -0
- package/dist/field/index.mjs +17 -0
- package/dist/field/index.mjs.map +1 -0
- package/dist/form/form-root.d.mts +58 -0
- package/dist/form/form-root.d.mts.map +1 -0
- package/dist/form/form-root.mjs +146 -0
- package/dist/form/form-root.mjs.map +1 -0
- package/dist/form/form-submit.d.mts +31 -0
- package/dist/form/form-submit.d.mts.map +1 -0
- package/dist/form/form-submit.mjs +52 -0
- package/dist/form/form-submit.mjs.map +1 -0
- package/dist/form/index.d.mts +11 -0
- package/dist/form/index.d.mts.map +1 -0
- package/dist/form/index.mjs +11 -0
- package/dist/form/index.mjs.map +1 -0
- package/dist/index.d.mts +46 -2
- package/dist/index.mjs +8 -1
- package/dist/internal/content-focus-probe.mjs +42 -0
- package/dist/internal/content-focus-probe.mjs.map +1 -0
- package/dist/internal/field-context.d.mts +19 -0
- package/dist/internal/field-context.d.mts.map +1 -0
- package/dist/internal/field-context.mjs +14 -0
- package/dist/internal/field-context.mjs.map +1 -0
- package/dist/internal/focus-first-invalid.mjs +67 -0
- package/dist/internal/focus-first-invalid.mjs.map +1 -0
- package/dist/internal/form-status-watcher.mjs +31 -0
- package/dist/internal/form-status-watcher.mjs.map +1 -0
- package/dist/internal/modal-registry.mjs +39 -0
- package/dist/internal/modal-registry.mjs.map +1 -0
- package/dist/internal/platform-attributes.d.mts +12 -1
- package/dist/internal/platform-attributes.d.mts.map +1 -1
- package/dist/internal/types.d.mts +11 -1
- package/dist/internal/types.d.mts.map +1 -1
- package/dist/internal/use-controllable-action.mjs +35 -13
- package/dist/internal/use-controllable-action.mjs.map +1 -1
- package/dist/internal/use-field-control.mjs +107 -0
- package/dist/internal/use-field-control.mjs.map +1 -0
- package/dist/internal/use-form-owner-event.mjs +44 -0
- package/dist/internal/use-form-owner-event.mjs.map +1 -0
- package/dist/internal/use-form-reset.mjs +12 -31
- package/dist/internal/use-form-reset.mjs.map +1 -1
- package/dist/internal/use-hydrated-mount.mjs +21 -0
- package/dist/internal/use-hydrated-mount.mjs.map +1 -0
- package/dist/internal/use-latest.mjs +32 -0
- package/dist/internal/use-latest.mjs.map +1 -0
- package/dist/internal/use-modal-registration.mjs +47 -0
- package/dist/internal/use-modal-registration.mjs.map +1 -0
- package/dist/internal/use-native-group-reconciliation.mjs +6 -5
- package/dist/internal/use-native-group-reconciliation.mjs.map +1 -1
- package/dist/internal/use-native-select-value.mjs +184 -0
- package/dist/internal/use-native-select-value.mjs.map +1 -0
- package/dist/internal/use-popover-popup.mjs +8 -22
- package/dist/internal/use-popover-popup.mjs.map +1 -1
- package/dist/internal/use-popover-root.mjs +58 -23
- package/dist/internal/use-popover-root.mjs.map +1 -1
- package/dist/internal/validity.d.mts +24 -0
- package/dist/internal/validity.d.mts.map +1 -0
- package/dist/internal/validity.mjs +108 -0
- package/dist/internal/validity.mjs.map +1 -0
- package/dist/menu/menu-group.d.mts.map +1 -1
- package/dist/menu/menu-group.mjs +3 -2
- package/dist/menu/menu-group.mjs.map +1 -1
- package/dist/menu/menu-radio-group.mjs +9 -4
- package/dist/menu/menu-radio-group.mjs.map +1 -1
- package/dist/menu/menu-root.mjs.map +1 -1
- package/dist/radio-group/radio-group-root.d.mts +4 -2
- package/dist/radio-group/radio-group-root.d.mts.map +1 -1
- package/dist/radio-group/radio-group-root.mjs +34 -8
- package/dist/radio-group/radio-group-root.mjs.map +1 -1
- package/dist/select/index.d.mts +30 -0
- package/dist/select/index.d.mts.map +1 -0
- package/dist/select/index.mjs +30 -0
- package/dist/select/index.mjs.map +1 -0
- package/dist/select/select-context.mjs +13 -0
- package/dist/select/select-context.mjs.map +1 -0
- package/dist/select/select-dom.mjs +44 -0
- package/dist/select/select-dom.mjs.map +1 -0
- package/dist/select/select-group-label.d.mts +22 -0
- package/dist/select/select-group-label.d.mts.map +1 -0
- package/dist/select/select-group-label.mjs +39 -0
- package/dist/select/select-group-label.mjs.map +1 -0
- package/dist/select/select-group.d.mts +28 -0
- package/dist/select/select-group.d.mts.map +1 -0
- package/dist/select/select-group.mjs +47 -0
- package/dist/select/select-group.mjs.map +1 -0
- package/dist/select/select-option.d.mts +42 -0
- package/dist/select/select-option.d.mts.map +1 -0
- package/dist/select/select-option.mjs +65 -0
- package/dist/select/select-option.mjs.map +1 -0
- package/dist/select/select-root.d.mts +68 -0
- package/dist/select/select-root.d.mts.map +1 -0
- package/dist/select/select-root.mjs +114 -0
- package/dist/select/select-root.mjs.map +1 -0
- package/dist/select/select-separator.d.mts +20 -0
- package/dist/select/select-separator.d.mts.map +1 -0
- package/dist/select/select-separator.mjs +30 -0
- package/dist/select/select-separator.mjs.map +1 -0
- package/dist/select/select-trigger.d.mts +29 -0
- package/dist/select/select-trigger.d.mts.map +1 -0
- package/dist/select/select-trigger.mjs +48 -0
- package/dist/select/select-trigger.mjs.map +1 -0
- package/dist/select/select-value.d.mts +31 -0
- package/dist/select/select-value.d.mts.map +1 -0
- package/dist/select/select-value.mjs +101 -0
- package/dist/select/select-value.mjs.map +1 -0
- package/dist/slider/index.d.mts +32 -0
- package/dist/slider/index.d.mts.map +1 -0
- package/dist/slider/index.mjs +27 -0
- package/dist/slider/index.mjs.map +1 -0
- package/dist/slider/slider-arithmetic.mjs +120 -0
- package/dist/slider/slider-arithmetic.mjs.map +1 -0
- package/dist/slider/slider-context.mjs +13 -0
- package/dist/slider/slider-context.mjs.map +1 -0
- package/dist/slider/slider-indicator.d.mts +22 -0
- package/dist/slider/slider-indicator.d.mts.map +1 -0
- package/dist/slider/slider-indicator.mjs +36 -0
- package/dist/slider/slider-indicator.mjs.map +1 -0
- package/dist/slider/slider-label.d.mts +23 -0
- package/dist/slider/slider-label.d.mts.map +1 -0
- package/dist/slider/slider-label.mjs +44 -0
- package/dist/slider/slider-label.mjs.map +1 -0
- package/dist/slider/slider-root.d.mts +111 -0
- package/dist/slider/slider-root.d.mts.map +1 -0
- package/dist/slider/slider-root.mjs +582 -0
- package/dist/slider/slider-root.mjs.map +1 -0
- package/dist/slider/slider-thumb.d.mts +58 -0
- package/dist/slider/slider-thumb.d.mts.map +1 -0
- package/dist/slider/slider-thumb.mjs +145 -0
- package/dist/slider/slider-thumb.mjs.map +1 -0
- package/dist/slider/slider-track.d.mts +29 -0
- package/dist/slider/slider-track.d.mts.map +1 -0
- package/dist/slider/slider-track.mjs +54 -0
- package/dist/slider/slider-track.mjs.map +1 -0
- package/dist/slider/slider-value.d.mts +34 -0
- package/dist/slider/slider-value.d.mts.map +1 -0
- package/dist/slider/slider-value.mjs +38 -0
- package/dist/slider/slider-value.mjs.map +1 -0
- package/dist/switch/switch.d.mts +5 -3
- package/dist/switch/switch.d.mts.map +1 -1
- package/dist/switch/switch.mjs +24 -8
- package/dist/switch/switch.mjs.map +1 -1
- package/dist/tabs/tabs-root.mjs +13 -3
- package/dist/tabs/tabs-root.mjs.map +1 -1
- package/dist/toast/index.d.mts +25 -0
- package/dist/toast/index.d.mts.map +1 -0
- package/dist/toast/index.mjs +26 -0
- package/dist/toast/index.mjs.map +1 -0
- package/dist/toast/toast-action.d.mts +39 -0
- package/dist/toast/toast-action.d.mts.map +1 -0
- package/dist/toast/toast-action.mjs +64 -0
- package/dist/toast/toast-action.mjs.map +1 -0
- package/dist/toast/toast-close.d.mts +25 -0
- package/dist/toast/toast-close.d.mts.map +1 -0
- package/dist/toast/toast-close.mjs +46 -0
- package/dist/toast/toast-close.mjs.map +1 -0
- package/dist/toast/toast-context.mjs +19 -0
- package/dist/toast/toast-context.mjs.map +1 -0
- package/dist/toast/toast-description.d.mts +24 -0
- package/dist/toast/toast-description.d.mts.map +1 -0
- package/dist/toast/toast-description.mjs +35 -0
- package/dist/toast/toast-description.mjs.map +1 -0
- package/dist/toast/toast-root.d.mts +43 -0
- package/dist/toast/toast-root.d.mts.map +1 -0
- package/dist/toast/toast-root.mjs +204 -0
- package/dist/toast/toast-root.mjs.map +1 -0
- package/dist/toast/toast-title.d.mts +24 -0
- package/dist/toast/toast-title.d.mts.map +1 -0
- package/dist/toast/toast-title.mjs +33 -0
- package/dist/toast/toast-title.mjs.map +1 -0
- package/dist/toast/toast-viewport.d.mts +52 -0
- package/dist/toast/toast-viewport.d.mts.map +1 -0
- package/dist/toast/toast-viewport.mjs +621 -0
- package/dist/toast/toast-viewport.mjs.map +1 -0
- package/dist/toast/toast.d.mts +119 -0
- package/dist/toast/toast.d.mts.map +1 -0
- package/dist/toast/toast.mjs +153 -0
- package/dist/toast/toast.mjs.map +1 -0
- package/package.json +7 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-root.mjs","names":[],"sources":["../../src/slider/slider-root.tsx"],"sourcesContent":["\"use client\";\nimport {\n addTransitionType,\n use,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode, RefObject } from \"react\";\nimport { createActionDetails } from \"../internal/action-details.js\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport { FieldContext } from \"../internal/field-context.js\";\nimport { mergeTokenLists } from \"../internal/merge-props.js\";\nimport { transitionTypes } from \"../internal/transition-types.js\";\nimport type {\n ActionDetails,\n ChangeAction,\n ChangeReason,\n RenderProp,\n StateValue,\n} from \"../internal/types.js\";\nimport { useActionTrigger } from \"../internal/use-action-trigger.js\";\nimport { useControllableAction } from \"../internal/use-controllable-action.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport {\n useFieldControl,\n useFieldValueChange,\n useMergedRef,\n} from \"../internal/use-field-control.js\";\nimport type { FormAssociatedElement } from \"../internal/use-form-reset.js\";\nimport { useLatest } from \"../internal/use-latest.js\";\nimport { useNativeGroupReconciliation } from \"../internal/use-native-group-reconciliation.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport {\n clampToNeighbours,\n equalValues,\n isMaxReachable,\n isOnGrid,\n nearestThumb,\n percent,\n platformDefault,\n sanitize,\n} from \"./slider-arithmetic.js\";\nimport { SliderContext } from \"./slider-context.js\";\nimport type { SliderContextValue, SliderFieldWiring } from \"./slider-context.js\";\n\n/** One number (one thumb) or one number per thumb, in ascending order. */\nexport type SliderValue = number | readonly number[];\n\nexport type SliderOrientation = \"horizontal\" | \"vertical\";\n\n/** Details passed as the second argument of `Slider.Root`'s `valueChangeAction` (each step). */\nexport interface SliderValueChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: the user moved a thumb (`details.event` is the native `input` event for a key\n * press, the `pointerdown` / `pointermove` / `pointerup` for a drag, the `keydown` for a\n * JS-normalised key).\n * `\"platform\"`: a form reset (the `reset` event) or a value found in the inputs at mount\n * (`undefined`).\n * `\"dismiss\"`: the commit action rejected and the slider reverted to the committed value\n * (uncontrolled mode; `undefined`).\n */\n readonly reason: ChangeReason;\n /** Index of the thumb that moved; `null` on a platform path or a revert, where several may change. */\n readonly thumb: number | null;\n}\n\n/** Details passed as the second argument of `Slider.Root`'s `valueCommitAction` (each gesture). */\nexport interface SliderValueCommitDetails extends ActionDetails {\n /**\n * `\"activate\"`: a gesture ended (`details.event` is the native `change` event for a key press,\n * the `pointerup` / `pointercancel` / `lostpointercapture` for a drag, the `keydown` for a\n * JS-normalised key). `\"platform\"`: a form reset (the `reset` event) or mount reconciliation\n * (`undefined`). Never `\"dismiss\"`.\n */\n readonly reason: ChangeReason;\n /** Index of the thumb the gesture moved; `null` on a platform path. */\n readonly thumb: number | null;\n}\n\nexport interface SliderRootState<T extends SliderValue = number> {\n /**\n * The value the thumbs show: the value a gesture has reached while a pointer is captured or a\n * step or commit is in flight, else the optimistic value. Content rendered from it must not\n * suspend.\n */\n readonly value: T;\n /** `value` as an array, one entry per thumb, in thumb order. */\n readonly values: readonly number[];\n /** A step or commit dispatched through this Slider is in flight. */\n readonly pending: boolean;\n /** A pointer is captured on a thumb. */\n readonly dragging: boolean;\n readonly orientation: SliderOrientation;\n readonly disabled: boolean;\n readonly min: number;\n readonly max: number;\n readonly step: number;\n}\n\nexport interface SliderRootProps<T extends SliderValue = number> extends Omit<\n ComponentPropsWithRef<\"div\">,\n | \"defaultValue\"\n | \"role\"\n | \"className\"\n | \"style\"\n | \"children\"\n // The value attributes are the native inputs' (design 8): never authored.\n | \"aria-valuemin\"\n | \"aria-valuemax\"\n | \"aria-valuenow\"\n | \"aria-valuetext\"\n | \"aria-orientation\"\n> {\n /** Controlled value: one number, or one per thumb in ascending order. `undefined`: uncontrolled. */\n value?: T;\n /**\n * Initial value in uncontrolled mode; also the form-reset target (latest value). Default: the\n * platform's midpoint, `min + (max - min) / 2`, snapped to `step`.\n */\n defaultValue?: T;\n /**\n * Runs inside the Root's step transition on every step: each pointer move, each key press,\n * each platform change, and the revert after a rejected commit (`reason: \"dismiss\"`,\n * uncontrolled). Awaited; `data-pending` meanwhile (without this action a step starts no\n * transition and is never pending). Adopt the value here in a controlled\n * parent (`setValue(next)` in the sync prefix is a transition update). Not the place for a\n * save: a pending async action entangles every transition in the app, and a drag is many\n * steps. A `setState` after your own `await` needs `startTransition`.\n */\n valueChangeAction?: ChangeAction<T, SliderValueChangeDetails>;\n /**\n * Runs inside the Root's commit transition once per gesture: pointer release, each key press,\n * a form reset, a value found at mount. Awaited; the thumb keeps the gesture's value and shows\n * `data-pending` until it settles; in uncontrolled mode the value is committed when it\n * resolves and reverts to the previous value if it rejects. May be a Server Function.\n */\n valueCommitAction?: ChangeAction<T, SliderValueCommitDetails>;\n /** Default `0`. */\n min?: number;\n /**\n * Default `100`. A `max` that is not on the step grid from `min` is unreachable, as on a\n * native range (dev warning).\n */\n max?: number;\n /** Default `1`. Must be positive. Values snap to `min + n × step`. */\n step?: number;\n /** Minimum number of steps between two adjacent thumbs. Default `0` (thumbs may share a value). */\n minStepsBetweenThumbs?: number;\n /** Default `\"horizontal\"`. Vertical sliders have `min` at the bottom. */\n orientation?: SliderOrientation;\n /**\n * `aria-valuetext` for a thumb, from the value it shows. Set it when the number alone is not\n * meaningful (\"3 of 5 stars\", \"Tuesday\"). Default: none (the number is announced).\n */\n getAriaValueText?: (value: number, index: number) => string;\n /**\n * Form field name for every thumb's input (a Thumb's own `name` wins). With several thumbs,\n * read with `FormData.getAll()`.\n */\n name?: string;\n /** The `form` attribute for every thumb's input (a Thumb's own `form` wins). */\n form?: string;\n /** Disables every input (native `disabled`; not submitted) and the pointer. Never set while pending. */\n disabled?: boolean;\n className?: StateValue<string | undefined, SliderRootState<T>>;\n style?: StateValue<CSSProperties | undefined, SliderRootState<T>>;\n children?: StateValue<ReactNode, SliderRootState<T>>;\n render?: RenderProp<ComponentPropsWithRef<\"div\">, SliderRootState<T>>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nconst STEP_TYPES = transitionTypes(\"slider\", \"change\");\nconst COMMIT_TYPES = transitionTypes(\"slider\", \"commit\");\n\nfunction toArray(value: SliderValue): readonly number[] {\n return typeof value === \"number\" ? [value] : value;\n}\n\nfunction shapeOf(value: SliderValue | undefined): \"number\" | \"array\" | undefined {\n if (value === undefined) return undefined;\n return typeof value === \"number\" ? \"number\" : \"array\";\n}\n\nfunction replaceAt(values: readonly number[], index: number, value: number): readonly number[] {\n return values.map((v, i) => (i === index ? value : v));\n}\n\n/** Writes each registered input's `defaultValue` (the attribute a form reset restores). */\nfunction writeDefaults(\n registry: ReadonlyMap<number, HTMLInputElement>,\n target: readonly number[],\n): void {\n for (const [index, input] of registry) {\n const entry = target[index];\n if (entry !== undefined) input.defaultValue = String(entry);\n }\n}\n\n/** A pointer captured on a Thumb or the Track (design 4.1). */\ninterface ActiveGesture {\n readonly pointerId: number;\n /** Detaches the gesture's listeners. */\n readonly detach: () => void;\n}\n\n/**\n * Owns the slider's state (design/components/slider.md 2): the committed value through\n * `useControllableAction` with `valueCommitAction` (once per gesture), each step through its own\n * transition (`valueChangeAction`), and the value a gesture has reached in the urgent lane\n * (`live`), which the thumbs show while a pointer is captured or anything is in flight. Also the\n * pointer gesture, the Thumb registry, mount reconciliation and form reset, and the geometry\n * custom properties `--slider-start`, `--slider-end` and `--slider-value-<i>`.\n *\n * Owned keys (conventions 1.2): `role` (`\"group\"` with several thumbs), `aria-labelledby` (the\n * Label's id while a Label is mounted and there are several thumbs; token-merged with the\n * consumer's), `data-pending`, `data-dragging`, `data-orientation`, `data-disabled`. The custom\n * properties are merged into `style`, where the consumer's entries win.\n *\n * Inside a `Field.Root` (design 9.4) the Root calls `useFieldControl`: with one thumb, Thumb 0's\n * input is the Field's labelable control; with several, the Root registers itself as the group\n * and also owns the Field label in `aria-labelledby`, the Field's `aria-describedby` and\n * `data-invalid`. `name` / `disabled` default from the Field.\n */\nfunction SliderRootImpl<T extends SliderValue = number>(props: SliderRootProps<T>) {\n const {\n value,\n defaultValue,\n valueChangeAction,\n valueCommitAction,\n min = 0,\n max = 100,\n step: stepProp = 1,\n minStepsBetweenThumbs = 0,\n orientation = \"horizontal\",\n getAriaValueText,\n name: nameProp,\n form,\n disabled: disabledProp = false,\n className,\n style,\n children,\n render,\n ...rest\n } = props;\n\n const stepValid = Number.isFinite(stepProp) && stepProp > 0;\n const step = stepValid ? stepProp : 1;\n const gap = Math.max(0, minStepsBetweenThumbs) * step;\n\n const id = useId();\n const labelId = `${id}-label`;\n\n // The shape (one number or an array) is fixed at mount (design 3.1).\n const [shape] = useState<\"number\" | \"array\">(() => shapeOf(value ?? defaultValue) ?? \"number\");\n const fromArray = useCallback(\n (values: readonly number[]): T => (shape === \"number\" ? values[0] : values) as T,\n [shape],\n );\n\n // --- State (design 2) ----------------------------------------------------------------------\n\n const [live, setLive] = useState<readonly number[] | null>(null);\n const [gestureThumb, setGestureThumb] = useState<number | null>(null);\n /**\n * A step was taken and its gesture's commit has not been dispatched yet. Holds `live` on\n * screen between a key's native `input` and `change` when no step transition runs (no\n * `valueChangeAction`): otherwise react-dom restores the controlled input to the old value\n * after `input`, and Firefox then fires no `change`.\n */\n const [stepHeld, setStepHeld] = useState(false);\n const [pendingThumb, setPendingThumb] = useState<number | null>(null);\n\n /** The value of the latest step, read by the commit in the same or a later event. */\n const liveRef = useRef<readonly number[] | null>(null);\n /** The shown value when the open gesture began; `null` when no gesture is open. */\n const gestureStart = useRef<readonly number[] | null>(null);\n const activeGesture = useRef<ActiveGesture | null>(null);\n const commitSeq = useRef(0);\n const trackRef = useRef<HTMLElement | null>(null);\n\n const runCommit = async (next: T, details: SliderValueCommitDetails): Promise<void> => {\n const seq = ++commitSeq.current;\n try {\n await valueCommitAction?.(next, details);\n } catch (error) {\n // Design 2.4: in uncontrolled mode, tell the preview channel about the rollback, for the\n // latest commit only. Yield once to leave the commit's transition (conventions 2.6).\n if (value === undefined && seq === commitSeq.current) {\n await undefined;\n // `stepTo` and `committedRef` are declared below; this runs long after the render.\n stepTo(toArray(committedRef.current), null, \"dismiss\", undefined);\n }\n throw error;\n }\n };\n\n const commitState = useControllableAction<T, SliderValueCommitDetails>({\n controlled: value,\n defaultValue,\n initialValue: platformDefault(min, max, step) as T,\n action: runCommit,\n transitionTypes: () => COMMIT_TYPES,\n warn: { component: \"Slider.Root\", prop: \"value\" },\n });\n const { optimistic, committed, dispatch } = commitState;\n const committedRef = useLatest(committed);\n\n const { pending: stepPending, run: runStep } = useActionTrigger();\n\n const optimisticValues = useMemo(() => toArray(optimistic), [optimistic]);\n const held = gestureThumb !== null || stepHeld || stepPending || commitState.pending;\n const shown = held && live !== null ? live : optimisticValues;\n const pending = stepPending || commitState.pending;\n\n // --- Inside a Field.Root (design 9.4) ------------------------------------------------------\n\n // One thumb: its input is the Field's labelable control. Several: the Root (`role=\"group\"`)\n // registers, `Field.Label` drops `for` and names the group through `aria-labelledby`.\n const thumbCount = shown.length;\n const field = useFieldControl({\n labelable: thumbCount === 1,\n name: nameProp,\n disabled: disabledProp,\n component: \"Slider.Root\",\n });\n const fieldName = use(FieldContext)?.name;\n const name = field.name;\n const disabled = field.disabled;\n const fieldId = field.id;\n const thumbId = useCallback(\n (index: number) => (index === 0 && fieldId !== undefined ? fieldId : `${id}-thumb-${index}`),\n [id, fieldId],\n );\n const rootRef = useMergedRef<HTMLElement>(undefined, thumbCount > 1 ? field.ref : undefined);\n useDevWarning(\n field.inField && field.required,\n \"Slider.Root: a range is never empty, so `required` on the enclosing Field.Root has no \" +\n \"effect on the slider.\",\n );\n /**\n * The reason of the latest change the user or the platform made, consumed by the Field\n * notification below: `\"activate\"` dismisses a shown server error, a rollback does not.\n */\n const lastReason = useRef<ChangeReason | null>(null);\n // A pointer gesture and the JS-normalised keys fire no `input` / `change` the Field hears:\n // tell it at the commit, when the optimistic value changes (design 9.4.4).\n useFieldValueChange(optimisticValues.join(\"\\u0000\"), () => {\n const edit = lastReason.current === \"activate\";\n lastReason.current = null;\n return edit;\n });\n const {\n \"aria-labelledby\": fieldLabelledBy,\n \"aria-describedby\": fieldDescribedBy,\n \"aria-invalid\": fieldInvalid,\n \"data-invalid\": fieldDataInvalid,\n } = field.attributes;\n const inField = field.inField;\n const fieldRef = field.ref;\n const fieldWiring = useMemo<SliderFieldWiring | null>(() => {\n if (!inField) return null;\n const single = thumbCount === 1;\n return {\n inputRef: single ? fieldRef : undefined,\n describedBy: single ? fieldDescribedBy : undefined,\n invalid: fieldInvalid,\n dataInvalid: fieldDataInvalid,\n name: fieldName,\n };\n }, [inField, fieldRef, thumbCount, fieldDescribedBy, fieldInvalid, fieldDataInvalid, fieldName]);\n\n /** What the thumbs show, for handlers; also written by `stepTo` ahead of the render. */\n const shownRef = useLatest(shown);\n\n const latest = useLatest({\n valueChangeAction,\n fromArray,\n runStep,\n min,\n max,\n step,\n gap,\n orientation,\n disabled,\n });\n\n // --- Step and commit (design 2.4) ---------------------------------------------------------\n\n const stepTo = useCallback(\n (\n next: readonly number[],\n thumb: number | null,\n reason: ChangeReason,\n event: Event | undefined,\n ): boolean => {\n // No-op against what the user sees (conventions 2.3 item 8).\n if (equalValues(next, shownRef.current)) return false;\n liveRef.current = next;\n shownRef.current = next;\n // A controlled parent that adopts steps changes the optimistic value per step.\n lastReason.current = reason;\n setLive(next);\n setPendingThumb(thumb);\n // A revert has no commit after it: the optimistic value already shows the committed one.\n if (reason !== \"dismiss\") setStepHeld(true);\n const { valueChangeAction: action, fromArray: toValue, runStep: run } = latest.current;\n // Without a step action there is nothing to run and no consumer update to keep\n // interruptible: no transition, so `data-pending` does not blink on every pointer move.\n if (action === undefined) return true;\n run(() => {\n for (const type of STEP_TYPES) addTransitionType(type);\n return action?.(toValue(next), createActionDetails(event, { reason, thumb }));\n });\n return true;\n },\n [latest, shownRef],\n );\n\n const commitGesture = useCallback(\n (thumb: number | null, reason: ChangeReason, event: Event | undefined): void => {\n const start = gestureStart.current;\n gestureStart.current = null;\n // The commit's own pending state holds `live` from here (set in this same batch).\n setStepHeld(false);\n const next = liveRef.current;\n // Nothing changed since the gesture began (a drag out and back, a trailing `change`).\n if (start === null || next === null || equalValues(next, start)) return;\n lastReason.current = reason;\n setPendingThumb(thumb);\n dispatch(latest.current.fromArray(next), createActionDetails(event, { reason, thumb }));\n },\n [dispatch, latest],\n );\n\n // --- Thumb registry ------------------------------------------------------------------------\n\n const [registry] = useState(() => new Map<number, HTMLInputElement>());\n const warnedDuplicate = useRef(false);\n const warnedForm = useRef(false);\n const registerThumb = useCallback(\n (index: number, input: HTMLInputElement) => {\n const existing = registry.get(index);\n if (isDev && existing !== undefined && existing !== input && !warnedDuplicate.current) {\n warnedDuplicate.current = true;\n console.error(\n `Slider.Thumb: two Thumbs have \\`index={${index}}\\`. Each value needs exactly one ` +\n `Thumb; give every Thumb a distinct index.`,\n );\n }\n if (isDev && !warnedForm.current) {\n for (const other of registry.values()) {\n if (other !== input && other.form !== input.form) {\n warnedForm.current = true;\n console.error(\n \"Slider.Thumb: the thumbs of one Slider belong to different forms (a Thumb's \" +\n \"`form` prop). A form reset is followed through the first thumb's form only; \" +\n \"keep every thumb in one form.\",\n );\n break;\n }\n }\n }\n registry.set(index, input);\n return () => {\n if (registry.get(index) === input) registry.delete(index);\n };\n },\n [registry],\n );\n\n /** The first registered input: the form-associated element the reset subscription follows. */\n const formElement = useMemo<RefObject<FormAssociatedElement | null>>(\n () => ({\n get current() {\n let first: HTMLInputElement | null = null;\n let firstIndex = Number.POSITIVE_INFINITY;\n for (const [index, input] of registry) {\n if (index < firstIndex) {\n firstIndex = index;\n first = input;\n }\n }\n return first;\n },\n set current(_ignored) {},\n }),\n [registry],\n );\n\n // --- Labels --------------------------------------------------------------------------------\n\n const [labelCount, setLabelCount] = useState(0);\n // The same count for the dev warning, which can run before the re-render the registration\n // scheduled.\n const labelCountRef = useRef(0);\n const registerLabel = useCallback(() => {\n labelCountRef.current += 1;\n setLabelCount((count) => count + 1);\n return () => {\n labelCountRef.current -= 1;\n setLabelCount((count) => count - 1);\n };\n }, []);\n\n // --- Residual browser paths: mount reconciliation and form reset (design 9.2, 9.3) --------\n\n const [mountValue] = useState(value);\n const resetTarget = (): readonly number[] =>\n value !== undefined\n ? toArray(mountValue ?? value)\n : toArray(defaultValue ?? platformDefault(min, max, step));\n\n const readCurrent = (): readonly number[] =>\n shownRef.current.map((v, index) => {\n const input = registry.get(index);\n if (input === undefined) return v;\n const read = Number(input.value);\n return Number.isFinite(read) ? read : v;\n });\n\n const { onItemMounted } = useNativeGroupReconciliation<readonly number[]>({\n element: formElement,\n readCurrent,\n readDefault: resetTarget,\n base: () => shownRef.current,\n // Compare as the DOM would hold the values: a consumer's off-grid value is sanitised by the\n // browser (not by jsdom), and that is not a platform change.\n equals: (a, b) => {\n const reference = shownRef.current;\n return equalValues(\n sanitize(a, reference, min, max, step, gap),\n sanitize(b, reference, min, max, step, gap),\n );\n },\n onPlatformChange: (next, event) => {\n if (next.length !== shownRef.current.length) return;\n const before = shownRef.current;\n gestureStart.current = before;\n liveRef.current = before;\n stepTo(next, null, \"platform\", event);\n commitGesture(null, \"platform\", event);\n },\n onResetEvent: () => {\n // react-dom writes `defaultValue = value` after every update of a controlled input, so the\n // reset target is written here, right before the browser's reset algorithm reads it.\n writeDefaults(registry, resetTarget());\n },\n });\n\n // --- Keyboard (design 4.2) -----------------------------------------------------------------\n\n const inputStep = useCallback(\n (index: number, raw: number, event: Event) => {\n if (!Number.isFinite(raw)) return;\n const before = shownRef.current;\n if (index >= before.length) return;\n // A key press is a one-step gesture: it starts at the value shown before it.\n if (stepTo(replaceAt(before, index, raw), index, \"activate\", event)) {\n if (gestureStart.current === null) gestureStart.current = before;\n }\n },\n [shownRef, stepTo],\n );\n\n const inputCommit = useCallback(\n (index: number, event: Event) => {\n // A pointer gesture commits at its release.\n if (activeGesture.current !== null) return;\n commitGesture(index, \"activate\", event);\n },\n [commitGesture],\n );\n\n const inputKeyDown = useCallback(\n (index: number, event: KeyboardEvent) => {\n const {\n orientation: axis,\n disabled: off,\n min: lo,\n max: hi,\n step: inc,\n gap: g,\n } = latest.current;\n if (off) return;\n if (event.key !== \"ArrowLeft\" && event.key !== \"ArrowRight\") return;\n if (event.altKey || event.ctrlKey || event.metaKey) return;\n // Vertical: Firefox decreases a vertical range on ArrowRight; the APG says increase.\n // Horizontal RTL: the track is mirrored (min on the right), so ArrowLeft increases;\n // Chromium and Firefox mirror a native range, WebKit does not (design 7). LTR stays native.\n let increaseKey: \"ArrowLeft\" | \"ArrowRight\";\n if (axis === \"vertical\") {\n increaseKey = \"ArrowRight\";\n } else {\n // Read at the keydown: the direction may come from any ancestor and change at any time.\n const input = event.currentTarget as Element | null;\n if (input === null || getComputedStyle(input).direction !== \"rtl\") return;\n increaseKey = \"ArrowLeft\";\n }\n event.preventDefault();\n const before = shownRef.current;\n const current = before[index];\n if (current === undefined) return;\n const delta = event.key === increaseKey ? inc : -inc;\n const next = replaceAt(\n before,\n index,\n clampToNeighbours(before, index, current + delta, lo, hi, inc, g),\n );\n if (activeGesture.current !== null) {\n stepTo(next, index, \"activate\", event);\n return;\n }\n gestureStart.current = before;\n liveRef.current = before;\n stepTo(next, index, \"activate\", event);\n commitGesture(index, \"activate\", event);\n },\n [commitGesture, latest, shownRef, stepTo],\n );\n\n // --- Pointer (design 4.1) ------------------------------------------------------------------\n\n const warnedNoTrack = useRef(false);\n const beginGesture = useCallback(\n (index: number | null, event: PointerEvent, element: HTMLElement) => {\n const { disabled: off } = latest.current;\n if (off || event.button !== 0 || activeGesture.current !== null) return;\n const track = trackRef.current;\n if (track === null) {\n if (isDev && !warnedNoTrack.current) {\n warnedNoTrack.current = true;\n console.error(\n \"Slider.Thumb: a pointer press needs a Slider.Track to map the pointer to a value. \" +\n \"Without a Track the slider is keyboard-only.\",\n );\n }\n return;\n }\n // No text selection, no focus change through the compatibility `mousedown`.\n event.preventDefault();\n const rtl = getComputedStyle(track).direction === \"rtl\";\n\n const valueAt = (clientX: number, clientY: number): number => {\n const { min: lo, max: hi, orientation: axis } = latest.current;\n const rect = (trackRef.current ?? track).getBoundingClientRect();\n let fraction: number;\n if (axis === \"vertical\") {\n fraction = rect.height > 0 ? (rect.bottom - clientY) / rect.height : 0;\n } else {\n fraction = rect.width > 0 ? (clientX - rect.left) / rect.width : 0;\n if (rtl) fraction = 1 - fraction;\n }\n fraction = Math.min(1, Math.max(0, fraction));\n return lo + fraction * (hi - lo);\n };\n const moveTo = (thumb: number, raw: number, cause: Event): void => {\n const { min: lo, max: hi, step: inc, gap: g } = latest.current;\n const before = shownRef.current;\n if (thumb >= before.length) return;\n stepTo(\n replaceAt(before, thumb, clampToNeighbours(before, thumb, raw, lo, hi, inc, g)),\n thumb,\n \"activate\",\n cause,\n );\n };\n\n const start = valueAt(event.clientX, event.clientY);\n const startValues = shownRef.current;\n // A press on a Thumb that shares its value with a neighbour (stacked thumbs) moves the one\n // that can go toward the pointer, the Track's tie rule; when the press is exactly on the\n // value, the first move decides. Otherwise a Thumb press moves that Thumb.\n let tied: { readonly first: number; readonly last: number; readonly at: number } | null =\n null;\n if (index !== null) {\n const at = startValues[index];\n if (at !== undefined) {\n let first = index;\n let last = index;\n while (first > 0 && equalValues([startValues[first - 1] as number], [at])) first -= 1;\n while (\n last < startValues.length - 1 &&\n equalValues([startValues[last + 1] as number], [at])\n ) {\n last += 1;\n }\n if (first !== last) tied = { first, last, at };\n }\n }\n const resolveTie = (raw: number): number | null => {\n if (tied === null) return null;\n if (raw > tied.at) return tied.last;\n if (raw < tied.at) return tied.first;\n return null;\n };\n /** The thumb the gesture moves; `null` while a press on stacked thumbs is undecided. */\n let decided: number | null =\n index === null ? nearestThumb(startValues, start) : tied ? resolveTie(start) : index;\n /** The thumb shown as dragging and focused meanwhile. */\n let thumb = decided ?? index ?? 0;\n const pointerId = event.pointerId;\n try {\n element.setPointerCapture(pointerId);\n } catch {\n // An inactive pointer id (a synthetic event): the gesture still follows the element.\n }\n\n const decide = (raw: number): boolean => {\n if (decided !== null) return true;\n decided = resolveTie(raw);\n if (decided === null) return false;\n if (decided !== thumb) {\n thumb = decided;\n setGestureThumb(thumb);\n registry.get(thumb)?.focus({ focusVisible: false } as FocusOptions);\n }\n return true;\n };\n const follow = (pointerEvent: PointerEvent): void => {\n const raw = valueAt(pointerEvent.clientX, pointerEvent.clientY);\n if (decide(raw)) moveTo(thumb, raw, pointerEvent);\n };\n\n const onMove = (moveEvent: PointerEvent): void => {\n if (moveEvent.pointerId !== pointerId) return;\n follow(moveEvent);\n };\n const onEnd = (endEvent: PointerEvent): void => {\n if (endEvent.pointerId !== pointerId) return;\n detach();\n // The release position is the gesture's last (an engine may coalesce the final move\n // into the `pointerup`); a cancel or a lost capture keeps the last move's value.\n if (endEvent.type === \"pointerup\") follow(endEvent);\n activeGesture.current = null;\n setGestureThumb(null);\n commitGesture(thumb, \"activate\", endEvent);\n };\n const detach = (): void => {\n element.removeEventListener(\"pointermove\", onMove);\n element.removeEventListener(\"pointerup\", onEnd);\n element.removeEventListener(\"pointercancel\", onEnd);\n element.removeEventListener(\"lostpointercapture\", onEnd);\n };\n element.addEventListener(\"pointermove\", onMove);\n element.addEventListener(\"pointerup\", onEnd);\n element.addEventListener(\"pointercancel\", onEnd);\n element.addEventListener(\"lostpointercapture\", onEnd);\n\n activeGesture.current = { pointerId, detach };\n setGestureThumb(thumb);\n gestureStart.current = shownRef.current;\n liveRef.current = shownRef.current;\n // A capture alone holds `live` on screen: start it from what is shown, not from the value\n // an earlier gesture left behind (a press exactly on the current value steps nothing).\n setLive(shownRef.current);\n // `:focus-visible` does not match after a pointer press, as on a native range.\n registry.get(thumb)?.focus({ focusVisible: false } as FocusOptions);\n if (decided !== null) moveTo(thumb, start, event);\n },\n [commitGesture, latest, registry, shownRef, stepTo],\n );\n\n // An unmount mid-gesture leaves no listener behind.\n useEffect(\n () => () => {\n activeGesture.current?.detach();\n activeGesture.current = null;\n },\n [],\n );\n\n // --- Development warnings ------------------------------------------------------------------\n\n useDevWarning(\n !stepValid,\n `Slider.Root: \\`step\\` must be a positive number (got ${String(stepProp)}); using 1.`,\n );\n useDevWarning(\n stepValid && !isMaxReachable(min, max, step),\n `Slider.Root: \\`max\\` (${max}) is not on the step grid from \\`min\\` (${min}) with \\`step\\` ` +\n `${step}: it is unreachable, as on a native range. The last reachable value is the last ` +\n `step below \\`max\\`.`,\n );\n const given = value ?? defaultValue;\n const givenValues = given === undefined ? [] : toArray(given);\n useDevWarning(\n givenValues.some((v) => !isOnGrid(v, min, max, step)),\n `Slider.Root: the ${value !== undefined ? \"`value`\" : \"`defaultValue`\"} ` +\n `(${givenValues.join(\", \")}) is off the step grid or outside \\`min\\` / \\`max\\`. It is ` +\n `rendered as given and the browser sanitises it; the first user step snaps it.`,\n );\n useDevWarning(\n givenValues.some((v, i) => i > 0 && v < (givenValues[i - 1] as number)),\n `Slider.Root: the values (${givenValues.join(\", \")}) must be in ascending order; the thumbs ` +\n `would be rendered crossed.`,\n );\n const currentShape = shapeOf(given);\n useDevWarning(\n currentShape !== undefined && currentShape !== shape,\n `Slider.Root: the value changed shape between a number and an array after mount. The shape ` +\n `is fixed at mount; remount the Slider (a \\`key\\`) to change the number of thumbs.`,\n );\n // Inside a Field, `Field.Label` names the group (design 9.4.2).\n const unnamedGroup =\n shown.length > 1 &&\n !inField &&\n rest[\"aria-label\"] === undefined &&\n rest[\"aria-labelledby\"] === undefined;\n const warnedGroupName = useRef(false);\n useEffect(() => {\n if (!isDev || warnedGroupName.current || !unnamedGroup || labelCountRef.current > 0) return;\n warnedGroupName.current = true;\n console.error(\n \"Slider.Root: a slider with several thumbs is a `group` and needs a name: render a \" +\n \"Slider.Label, or pass `aria-label` / `aria-labelledby` to the Root.\",\n );\n }, [unnamedGroup]);\n\n // --- Render --------------------------------------------------------------------------------\n\n const count = shown.length;\n const percents = shown.map((v) => percent(v, min, max));\n const geometry: Record<string, string> = {\n \"--slider-start\": count > 1 ? `${percents[0] ?? 0}%` : \"0%\",\n \"--slider-end\": `${percents[count - 1] ?? 0}%`,\n };\n percents.forEach((p, index) => {\n geometry[`--slider-value-${index}`] = `${p}%`;\n });\n\n const shownValue = fromArray(shown);\n const dragging = gestureThumb !== null;\n const state = useMemo<SliderRootState<T>>(\n () => ({\n value: shownValue,\n values: shown,\n pending,\n dragging,\n orientation,\n disabled,\n min,\n max,\n step,\n }),\n [shownValue, shown, pending, dragging, orientation, disabled, min, max, step],\n );\n\n // Memoised (#48): the functions are stable, so this changes only with the state below.\n const context = useMemo<SliderContextValue>(\n () => ({\n state: state as SliderRootState<SliderValue>,\n shown,\n shownValue: shownValue as SliderValue,\n min,\n max,\n step,\n gap,\n orientation,\n disabled,\n pending,\n draggingThumb: gestureThumb,\n pendingThumb,\n name,\n form,\n getAriaValueText,\n labelId,\n thumbId,\n trackRef,\n inputStep,\n inputCommit,\n inputKeyDown,\n beginGesture,\n registerThumb,\n registerLabel,\n onItemMounted,\n field: fieldWiring,\n }),\n [\n state,\n shown,\n shownValue,\n min,\n max,\n step,\n gap,\n orientation,\n disabled,\n pending,\n gestureThumb,\n pendingThumb,\n name,\n form,\n getAriaValueText,\n labelId,\n thumbId,\n inputStep,\n inputCommit,\n inputKeyDown,\n beginGesture,\n registerThumb,\n registerLabel,\n onItemMounted,\n fieldWiring,\n ],\n );\n\n // Several thumbs: the Field's label, then `Slider.Label` while one is mounted (the consumer's\n // tokens come first through the merge). Only when there is one: an owned `undefined` would\n // remove the consumer's own tokens.\n const labelledBy =\n count > 1 ? mergeTokenLists(fieldLabelledBy, labelCount > 0 ? labelId : undefined) : \"\";\n const libraryProps: Partial<ComponentPropsWithRef<\"div\">> & DataAttributes = {\n role: count > 1 ? \"group\" : undefined,\n ...(labelledBy !== \"\" ? { \"aria-labelledby\": labelledBy } : {}),\n // The group element is described (read when focus enters it); one thumb: its input is.\n ...(count > 1 && fieldDescribedBy !== undefined\n ? { \"aria-describedby\": fieldDescribedBy }\n : {}),\n // Inside a Field only (`aria-invalid` goes on the inputs, never on the group).\n ...(inField ? { \"data-invalid\": fieldDataInvalid } : {}),\n \"data-pending\": dataAttr(pending),\n \"data-dragging\": dataAttr(dragging),\n \"data-orientation\": orientation,\n \"data-disabled\": dataAttr(disabled),\n };\n\n const element = useRender<ComponentPropsWithRef<\"div\">, SliderRootState<T>>({\n defaultElement: \"div\",\n render,\n state,\n className,\n // The geometry properties lose to the consumer's own entries (design 3.1).\n style: (s) => ({ ...(geometry as CSSProperties), ...resolveStateValue(style, s) }),\n children,\n props: rest,\n libraryProps,\n ref: rootRef,\n });\n\n return <SliderContext value={context}>{element}</SliderContext>;\n}\n\nSliderRootImpl.displayName = \"SliderRoot\";\n\n/**\n * `Slider.Root`. Overloaded so that the value's shape is inferred from `value` / `defaultValue`\n * as `number` or `readonly number[]` (an array literal would otherwise infer a mutable\n * `number[]`), and every action and state function receives that shape (design 3.1).\n */\nexport const SliderRoot = SliderRootImpl as {\n (props: SliderRootProps<number>): ReactNode;\n (props: SliderRootProps<readonly number[]>): ReactNode;\n (props: SliderRootProps<SliderValue>): ReactNode;\n displayName?: string;\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { RenderProp, StateValue } from "../internal/types.mjs";
|
|
2
|
+
import { SliderOrientation } from "./slider-root.mjs";
|
|
3
|
+
import { CSSProperties, ComponentPropsWithRef, ReactNode, Ref } from "react";
|
|
4
|
+
//#region src/slider/slider-thumb.d.ts
|
|
5
|
+
export interface SliderThumbState {
|
|
6
|
+
readonly index: number;
|
|
7
|
+
/** The value this thumb shows. */
|
|
8
|
+
readonly value: number;
|
|
9
|
+
/** The Root is pending and this thumb is the one the latest step or commit moved. */
|
|
10
|
+
readonly pending: boolean;
|
|
11
|
+
/** A pointer is captured on this thumb. */
|
|
12
|
+
readonly dragging: boolean;
|
|
13
|
+
readonly orientation: SliderOrientation;
|
|
14
|
+
readonly disabled: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface SliderThumbProps extends Omit<ComponentPropsWithRef<"span">, "onPointerDown" | "aria-label" | "aria-labelledby" | "aria-describedby" | "aria-valuemin" | "aria-valuemax" | "aria-valuenow" | "aria-valuetext" | "aria-orientation" | "className" | "style" | "children"> {
|
|
17
|
+
/** Which value this thumb edits. Default `0`. */
|
|
18
|
+
index?: number;
|
|
19
|
+
/** Form field name of this thumb's input; overrides the Root's `name`. */
|
|
20
|
+
name?: string;
|
|
21
|
+
/** The `form` attribute of this thumb's input; overrides the Root's. */
|
|
22
|
+
form?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Forwarded to the input (the element with role `slider`), not the styled element. Required
|
|
25
|
+
* for every thumb of a multi-thumb slider unless `aria-labelledby` is given (dev warning).
|
|
26
|
+
*/
|
|
27
|
+
"aria-label"?: string;
|
|
28
|
+
/** Forwarded to the input. */
|
|
29
|
+
"aria-labelledby"?: string;
|
|
30
|
+
/** Forwarded to the input. */
|
|
31
|
+
"aria-describedby"?: string;
|
|
32
|
+
/** The native `<input type="range">` inside the thumb. */
|
|
33
|
+
inputRef?: Ref<HTMLInputElement>;
|
|
34
|
+
/** Forwarded to the input. */
|
|
35
|
+
autoFocus?: boolean;
|
|
36
|
+
className?: StateValue<string | undefined, SliderThumbState>;
|
|
37
|
+
style?: StateValue<CSSProperties | undefined, SliderThumbState>;
|
|
38
|
+
/** Rendered inside the styled element, next to the input (an icon, a value bubble). */
|
|
39
|
+
children?: StateValue<ReactNode, SliderThumbState>;
|
|
40
|
+
render?: RenderProp<ComponentPropsWithRef<"span">, SliderThumbState>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* One value handle: a styled element (`span`) **containing** a visually hidden native
|
|
44
|
+
* `<input type="range">`, which is the focusable, labelled, form-participating `slider` with the
|
|
45
|
+
* native keyboard (conventions 1.1 exception). `ref` goes to the styled element, `inputRef` to the
|
|
46
|
+
* input. The input's native `min` / `max` are the neighbours' values, so thumbs cannot cross.
|
|
47
|
+
*
|
|
48
|
+
* Owned keys on the styled element: `onPointerDown`, `data-index`, `data-orientation`,
|
|
49
|
+
* `data-dragging`, `data-pending`, `data-disabled`, and `--slider-value` / `touch-action` in
|
|
50
|
+
* `style` (the consumer's entries win). `aria-label`, `aria-labelledby`, `aria-describedby`,
|
|
51
|
+
* `name`, `form` and `autoFocus` go to the input; every other input attribute is the library's.
|
|
52
|
+
*/
|
|
53
|
+
export declare function SliderThumb({ index, name, form, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, inputRef: consumerInputRef, autoFocus, className, style, children, render, ...rest }: SliderThumbProps): ReactNode;
|
|
54
|
+
export declare namespace SliderThumb {
|
|
55
|
+
var displayName: string;
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
//# sourceMappingURL=slider-thumb.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-thumb.d.mts","names":[],"sources":["../../src/slider/slider-thumb.tsx"],"mappings":";;;;iBAoBiB;WACN;;WAEA;;WAEA;;WAEA;WACA,aAAa;WACb;;iBAGM,yBAAyB,KACxC;;EAgBA;;EAEA;;EAEA;;;;;EAKA;;EAEA;;EAEA;;EAEA,WAAW,IAAI;;EAEf;EACA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;;EAE9C,WAAW,WAAW,WAAW;EACjC,SAAS,WAAW,+BAA+B;;;;;;;;;;;;;wBAgCrC,cACd,OACA,MACA,oBACc,8BACK,oCACC,iBACpB,UAAU,kBACV,WACA,WACA,OACA,UACA,WACG,QACF,mBAAgB;yBAdH"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { dataAttr } from "../internal/data-attr.mjs";
|
|
3
|
+
import { mergeRefs, mergeTokenLists } from "../internal/merge-props.mjs";
|
|
4
|
+
import { resolveStateValue, useRender } from "../internal/use-render.mjs";
|
|
5
|
+
import { useDevWarning } from "../internal/use-dev-warning.mjs";
|
|
6
|
+
import { useSliderContext } from "./slider-context.mjs";
|
|
7
|
+
import { percent, thumbBounds } from "./slider-arithmetic.mjs";
|
|
8
|
+
import { useEffectEvent, useLayoutEffect, useMemo, useRef } from "react";
|
|
9
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
//#region src/slider/slider-thumb.tsx
|
|
11
|
+
/** Visually hidden, sized to the thumb so an assistive-technology focus ring lands on it. */
|
|
12
|
+
const HIDDEN_INPUT_STYLE = {
|
|
13
|
+
position: "absolute",
|
|
14
|
+
inset: 0,
|
|
15
|
+
width: "100%",
|
|
16
|
+
height: "100%",
|
|
17
|
+
margin: 0,
|
|
18
|
+
opacity: 0,
|
|
19
|
+
pointerEvents: "none"
|
|
20
|
+
};
|
|
21
|
+
/** Chromium derives the accessibility orientation from `writing-mode`; `rtl` puts `min` at the bottom. */
|
|
22
|
+
const VERTICAL_INPUT_STYLE = {
|
|
23
|
+
...HIDDEN_INPUT_STYLE,
|
|
24
|
+
writingMode: "vertical-lr",
|
|
25
|
+
direction: "rtl"
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* One value handle: a styled element (`span`) **containing** a visually hidden native
|
|
29
|
+
* `<input type="range">`, which is the focusable, labelled, form-participating `slider` with the
|
|
30
|
+
* native keyboard (conventions 1.1 exception). `ref` goes to the styled element, `inputRef` to the
|
|
31
|
+
* input. The input's native `min` / `max` are the neighbours' values, so thumbs cannot cross.
|
|
32
|
+
*
|
|
33
|
+
* Owned keys on the styled element: `onPointerDown`, `data-index`, `data-orientation`,
|
|
34
|
+
* `data-dragging`, `data-pending`, `data-disabled`, and `--slider-value` / `touch-action` in
|
|
35
|
+
* `style` (the consumer's entries win). `aria-label`, `aria-labelledby`, `aria-describedby`,
|
|
36
|
+
* `name`, `form` and `autoFocus` go to the input; every other input attribute is the library's.
|
|
37
|
+
*/
|
|
38
|
+
function SliderThumb({ index = 0, name, form, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, inputRef: consumerInputRef, autoFocus, className, style, children, render, ...rest }) {
|
|
39
|
+
const ctx = useSliderContext("Slider.Thumb");
|
|
40
|
+
const value = ctx.shown[index];
|
|
41
|
+
const inRange = value !== void 0;
|
|
42
|
+
const shownValue = value ?? ctx.min;
|
|
43
|
+
const inputRef = useRef(null);
|
|
44
|
+
const fieldInputRef = index === 0 ? ctx.field?.inputRef : void 0;
|
|
45
|
+
const mergedInputRef = useMemo(() => mergeRefs(inputRef, consumerInputRef, fieldInputRef), [consumerInputRef, fieldInputRef]);
|
|
46
|
+
const { registerThumb, onItemMounted } = ctx;
|
|
47
|
+
useLayoutEffect(() => {
|
|
48
|
+
const input = inputRef.current;
|
|
49
|
+
if (input === null) return;
|
|
50
|
+
const unregister = registerThumb(index, input);
|
|
51
|
+
onItemMounted();
|
|
52
|
+
return unregister;
|
|
53
|
+
}, [
|
|
54
|
+
index,
|
|
55
|
+
registerThumb,
|
|
56
|
+
onItemMounted
|
|
57
|
+
]);
|
|
58
|
+
const onNativeChange = useEffectEvent((event) => {
|
|
59
|
+
ctx.inputCommit(index, event);
|
|
60
|
+
});
|
|
61
|
+
const onNativeKeyDown = useEffectEvent((event) => {
|
|
62
|
+
ctx.inputKeyDown(index, event);
|
|
63
|
+
});
|
|
64
|
+
useLayoutEffect(() => {
|
|
65
|
+
const input = inputRef.current;
|
|
66
|
+
if (input === null) return;
|
|
67
|
+
input.addEventListener("change", onNativeChange);
|
|
68
|
+
input.addEventListener("keydown", onNativeKeyDown);
|
|
69
|
+
return () => {
|
|
70
|
+
input.removeEventListener("change", onNativeChange);
|
|
71
|
+
input.removeEventListener("keydown", onNativeKeyDown);
|
|
72
|
+
};
|
|
73
|
+
}, [inRange]);
|
|
74
|
+
useDevWarning(!inRange, `Slider.Thumb: \`index={${index}}\` is outside the value (${ctx.shown.length} ${ctx.shown.length === 1 ? "value" : "values"}). The Thumb renders nothing.`);
|
|
75
|
+
useDevWarning(inRange && ctx.shown.length > 1 && ariaLabel === void 0 && ariaLabelledBy === void 0, `Slider.Thumb: each thumb of a multi-thumb slider needs its own name (\`aria-label\` or \`aria-labelledby\`), e.g. "Minimum price"; the thumb at index ${index} has none.`);
|
|
76
|
+
const fieldName = ctx.field?.name;
|
|
77
|
+
useDevWarning(inRange && name !== void 0 && fieldName !== void 0 && name !== fieldName, `Slider.Thumb: its \`name\` ("${name}") differs from the Field.Root's ("${fieldName}"). The Field reads server errors and \`validate\`'s value by the Field's name.`);
|
|
78
|
+
const pending = ctx.pending && ctx.pendingThumb === index;
|
|
79
|
+
const dragging = ctx.draggingThumb === index;
|
|
80
|
+
const state = {
|
|
81
|
+
index,
|
|
82
|
+
value: shownValue,
|
|
83
|
+
pending,
|
|
84
|
+
dragging,
|
|
85
|
+
orientation: ctx.orientation,
|
|
86
|
+
disabled: ctx.disabled
|
|
87
|
+
};
|
|
88
|
+
const { lower, upper } = thumbBounds(ctx.shown, index, ctx.min, ctx.max, ctx.gap);
|
|
89
|
+
const input = inRange ? /* @__PURE__ */ jsx("input", {
|
|
90
|
+
ref: mergedInputRef,
|
|
91
|
+
type: "range",
|
|
92
|
+
id: ctx.thumbId(index),
|
|
93
|
+
name: name ?? ctx.name,
|
|
94
|
+
form: form ?? ctx.form,
|
|
95
|
+
min: lower,
|
|
96
|
+
max: upper,
|
|
97
|
+
step: ctx.step,
|
|
98
|
+
value: shownValue,
|
|
99
|
+
disabled: ctx.disabled,
|
|
100
|
+
autoFocus,
|
|
101
|
+
"aria-label": ariaLabel,
|
|
102
|
+
"aria-labelledby": ariaLabelledBy,
|
|
103
|
+
"aria-describedby": mergeTokenLists(ariaDescribedBy, index === 0 ? ctx.field?.describedBy : void 0) || void 0,
|
|
104
|
+
"aria-invalid": ctx.field?.invalid,
|
|
105
|
+
"aria-valuetext": ctx.getAriaValueText?.(shownValue, index),
|
|
106
|
+
style: ctx.orientation === "vertical" ? VERTICAL_INPUT_STYLE : HIDDEN_INPUT_STYLE,
|
|
107
|
+
onChange: (event) => {
|
|
108
|
+
ctx.inputStep(index, Number(event.target.value), event.nativeEvent);
|
|
109
|
+
}
|
|
110
|
+
}) : null;
|
|
111
|
+
const geometry = {
|
|
112
|
+
"--slider-value": `${percent(shownValue, ctx.min, ctx.max)}%`,
|
|
113
|
+
touchAction: ctx.orientation === "vertical" ? "pan-x" : "pan-y"
|
|
114
|
+
};
|
|
115
|
+
const element = useRender({
|
|
116
|
+
defaultElement: "span",
|
|
117
|
+
render,
|
|
118
|
+
state,
|
|
119
|
+
className,
|
|
120
|
+
style: (s) => ({
|
|
121
|
+
...geometry,
|
|
122
|
+
...resolveStateValue(style, s)
|
|
123
|
+
}),
|
|
124
|
+
children: void 0,
|
|
125
|
+
props: rest,
|
|
126
|
+
libraryProps: {
|
|
127
|
+
"data-index": String(index),
|
|
128
|
+
"data-orientation": ctx.orientation,
|
|
129
|
+
"data-dragging": dataAttr(dragging),
|
|
130
|
+
"data-pending": dataAttr(pending),
|
|
131
|
+
"data-disabled": dataAttr(ctx.disabled),
|
|
132
|
+
...ctx.field !== null ? { "data-invalid": ctx.field.dataInvalid } : {},
|
|
133
|
+
onPointerDown: (event) => {
|
|
134
|
+
ctx.beginGesture(index, event.nativeEvent, event.currentTarget);
|
|
135
|
+
},
|
|
136
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [input, resolveStateValue(children, state)] })
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
return inRange ? element : null;
|
|
140
|
+
}
|
|
141
|
+
SliderThumb.displayName = "SliderThumb";
|
|
142
|
+
//#endregion
|
|
143
|
+
export { SliderThumb };
|
|
144
|
+
|
|
145
|
+
//# sourceMappingURL=slider-thumb.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-thumb.mjs","names":[],"sources":["../../src/slider/slider-thumb.tsx"],"sourcesContent":["\"use client\";\nimport { useEffectEvent, useLayoutEffect, useMemo, useRef } from \"react\";\nimport type {\n ChangeEvent,\n ComponentPropsWithRef,\n CSSProperties,\n PointerEvent as ReactPointerEvent,\n ReactNode,\n Ref,\n} from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport { mergeRefs, mergeTokenLists } from \"../internal/merge-props.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport { percent, thumbBounds } from \"./slider-arithmetic.js\";\nimport { useSliderContext } from \"./slider-context.js\";\nimport type { SliderOrientation } from \"./slider-root.js\";\n\nexport interface SliderThumbState {\n readonly index: number;\n /** The value this thumb shows. */\n readonly value: number;\n /** The Root is pending and this thumb is the one the latest step or commit moved. */\n readonly pending: boolean;\n /** A pointer is captured on this thumb. */\n readonly dragging: boolean;\n readonly orientation: SliderOrientation;\n readonly disabled: boolean;\n}\n\nexport interface SliderThumbProps extends Omit<\n ComponentPropsWithRef<\"span\">,\n | \"onPointerDown\"\n | \"aria-label\"\n | \"aria-labelledby\"\n | \"aria-describedby\"\n // The value attributes are the native input's (design 8): never authored.\n | \"aria-valuemin\"\n | \"aria-valuemax\"\n | \"aria-valuenow\"\n | \"aria-valuetext\"\n | \"aria-orientation\"\n | \"className\"\n | \"style\"\n | \"children\"\n> {\n /** Which value this thumb edits. Default `0`. */\n index?: number;\n /** Form field name of this thumb's input; overrides the Root's `name`. */\n name?: string;\n /** The `form` attribute of this thumb's input; overrides the Root's. */\n form?: string;\n /**\n * Forwarded to the input (the element with role `slider`), not the styled element. Required\n * for every thumb of a multi-thumb slider unless `aria-labelledby` is given (dev warning).\n */\n \"aria-label\"?: string;\n /** Forwarded to the input. */\n \"aria-labelledby\"?: string;\n /** Forwarded to the input. */\n \"aria-describedby\"?: string;\n /** The native `<input type=\"range\">` inside the thumb. */\n inputRef?: Ref<HTMLInputElement>;\n /** Forwarded to the input. */\n autoFocus?: boolean;\n className?: StateValue<string | undefined, SliderThumbState>;\n style?: StateValue<CSSProperties | undefined, SliderThumbState>;\n /** Rendered inside the styled element, next to the input (an icon, a value bubble). */\n children?: StateValue<ReactNode, SliderThumbState>;\n render?: RenderProp<ComponentPropsWithRef<\"span\">, SliderThumbState>;\n}\n\n/** Visually hidden, sized to the thumb so an assistive-technology focus ring lands on it. */\nconst HIDDEN_INPUT_STYLE: CSSProperties = {\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n margin: 0,\n opacity: 0,\n pointerEvents: \"none\",\n};\n\n/** Chromium derives the accessibility orientation from `writing-mode`; `rtl` puts `min` at the bottom. */\nconst VERTICAL_INPUT_STYLE: CSSProperties = {\n ...HIDDEN_INPUT_STYLE,\n writingMode: \"vertical-lr\",\n direction: \"rtl\",\n};\n\n/**\n * One value handle: a styled element (`span`) **containing** a visually hidden native\n * `<input type=\"range\">`, which is the focusable, labelled, form-participating `slider` with the\n * native keyboard (conventions 1.1 exception). `ref` goes to the styled element, `inputRef` to the\n * input. The input's native `min` / `max` are the neighbours' values, so thumbs cannot cross.\n *\n * Owned keys on the styled element: `onPointerDown`, `data-index`, `data-orientation`,\n * `data-dragging`, `data-pending`, `data-disabled`, and `--slider-value` / `touch-action` in\n * `style` (the consumer's entries win). `aria-label`, `aria-labelledby`, `aria-describedby`,\n * `name`, `form` and `autoFocus` go to the input; every other input attribute is the library's.\n */\nexport function SliderThumb({\n index = 0,\n name,\n form,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n inputRef: consumerInputRef,\n autoFocus,\n className,\n style,\n children,\n render,\n ...rest\n}: SliderThumbProps) {\n const ctx = useSliderContext(\"Slider.Thumb\");\n const value = ctx.shown[index];\n const inRange = value !== undefined;\n const shownValue = value ?? ctx.min;\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n // Inside a Field with one thumb, Thumb 0's input is the Field's control (design 9.4.1).\n const fieldInputRef = index === 0 ? ctx.field?.inputRef : undefined;\n const mergedInputRef = useMemo(\n () =>\n mergeRefs<HTMLInputElement | null>(\n inputRef,\n consumerInputRef,\n fieldInputRef as Ref<HTMLInputElement | null> | undefined,\n ),\n [consumerInputRef, fieldInputRef],\n );\n\n // Registration with the Root (pointer focus, reconciliation, reset), from a layout effect so\n // the Root's mount reconciliation, which runs after its children's, sees every input.\n const { registerThumb, onItemMounted } = ctx;\n useLayoutEffect(() => {\n const input = inputRef.current;\n if (input === null) return;\n const unregister = registerThumb(index, input);\n onItemMounted();\n return unregister;\n }, [index, registerThumb, onItemMounted]);\n\n // React surfaces no `onChange` for the native `change` (design 4.2), and the vertical\n // ArrowLeft / ArrowRight normalisation needs the `keydown` before the browser acts on it.\n const onNativeChange = useEffectEvent((event: Event) => {\n ctx.inputCommit(index, event);\n });\n const onNativeKeyDown = useEffectEvent((event: KeyboardEvent) => {\n ctx.inputKeyDown(index, event);\n });\n useLayoutEffect(() => {\n const input = inputRef.current;\n if (input === null) return;\n input.addEventListener(\"change\", onNativeChange);\n input.addEventListener(\"keydown\", onNativeKeyDown);\n return () => {\n input.removeEventListener(\"change\", onNativeChange);\n input.removeEventListener(\"keydown\", onNativeKeyDown);\n };\n }, [inRange]);\n\n useDevWarning(\n !inRange,\n `Slider.Thumb: \\`index={${index}}\\` is outside the value (${ctx.shown.length} ` +\n `${ctx.shown.length === 1 ? \"value\" : \"values\"}). The Thumb renders nothing.`,\n );\n useDevWarning(\n inRange && ctx.shown.length > 1 && ariaLabel === undefined && ariaLabelledBy === undefined,\n `Slider.Thumb: each thumb of a multi-thumb slider needs its own name (\\`aria-label\\` or ` +\n `\\`aria-labelledby\\`), e.g. \"Minimum price\"; the thumb at index ${index} has none.`,\n );\n\n const fieldName = ctx.field?.name;\n useDevWarning(\n inRange && name !== undefined && fieldName !== undefined && name !== fieldName,\n `Slider.Thumb: its \\`name\\` (\"${name}\") differs from the Field.Root's (\"${fieldName}\"). ` +\n \"The Field reads server errors and `validate`'s value by the Field's name.\",\n );\n\n const pending = ctx.pending && ctx.pendingThumb === index;\n const dragging = ctx.draggingThumb === index;\n const state: SliderThumbState = {\n index,\n value: shownValue,\n pending,\n dragging,\n orientation: ctx.orientation,\n disabled: ctx.disabled,\n };\n\n const { lower, upper } = thumbBounds(ctx.shown, index, ctx.min, ctx.max, ctx.gap);\n const input = inRange ? (\n <input\n ref={mergedInputRef}\n type=\"range\"\n id={ctx.thumbId(index)}\n name={name ?? ctx.name}\n form={form ?? ctx.form}\n min={lower}\n max={upper}\n step={ctx.step}\n value={shownValue}\n disabled={ctx.disabled}\n autoFocus={autoFocus}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={\n mergeTokenLists(ariaDescribedBy, index === 0 ? ctx.field?.describedBy : undefined) ||\n undefined\n }\n aria-invalid={ctx.field?.invalid}\n aria-valuetext={ctx.getAriaValueText?.(shownValue, index)}\n style={ctx.orientation === \"vertical\" ? VERTICAL_INPUT_STYLE : HIDDEN_INPUT_STYLE}\n onChange={(event: ChangeEvent<HTMLInputElement>) => {\n ctx.inputStep(index, Number(event.target.value), event.nativeEvent);\n }}\n />\n ) : null;\n\n const geometry = {\n \"--slider-value\": `${percent(shownValue, ctx.min, ctx.max)}%`,\n touchAction: ctx.orientation === \"vertical\" ? \"pan-x\" : \"pan-y\",\n } as CSSProperties;\n\n const element = useRender<ComponentPropsWithRef<\"span\">, SliderThumbState>({\n defaultElement: \"span\",\n render,\n state,\n className,\n // The library's entries lose to the consumer's own (design 3.2).\n style: (s) => ({ ...geometry, ...resolveStateValue(style, s) }),\n children: undefined,\n props: rest,\n libraryProps: {\n \"data-index\": String(index),\n \"data-orientation\": ctx.orientation,\n \"data-dragging\": dataAttr(dragging),\n \"data-pending\": dataAttr(pending),\n \"data-disabled\": dataAttr(ctx.disabled),\n ...(ctx.field !== null ? { \"data-invalid\": ctx.field.dataInvalid } : {}),\n onPointerDown: (event: ReactPointerEvent<HTMLSpanElement>) => {\n ctx.beginGesture(index, event.nativeEvent, event.currentTarget);\n },\n // Owned, so a `render` element's own children can never drop the input.\n children: (\n <>\n {input}\n {resolveStateValue(children, state)}\n </>\n ),\n // `children` is not in the library layer's type (useRender resolves it), but an owned\n // key wins over a `render` element's own children, which is what keeps the input.\n } as Partial<ComponentPropsWithRef<\"span\">> & DataAttributes,\n });\n\n return inRange ? element : null;\n}\n\nSliderThumb.displayName = \"SliderThumb\";\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RenderProp, StateValue } from "../internal/types.mjs";
|
|
2
|
+
import { SliderOrientation } from "./slider-root.mjs";
|
|
3
|
+
import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
|
|
4
|
+
//#region src/slider/slider-track.d.ts
|
|
5
|
+
export interface SliderTrackState {
|
|
6
|
+
readonly orientation: SliderOrientation;
|
|
7
|
+
/** A pointer is captured on a thumb. */
|
|
8
|
+
readonly dragging: boolean;
|
|
9
|
+
readonly disabled: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface SliderTrackProps extends Omit<ComponentPropsWithRef<"div">, "onPointerDown" | "className" | "style" | "children"> {
|
|
12
|
+
className?: StateValue<string | undefined, SliderTrackState>;
|
|
13
|
+
style?: StateValue<CSSProperties | undefined, SliderTrackState>;
|
|
14
|
+
children?: StateValue<ReactNode, SliderTrackState>;
|
|
15
|
+
render?: RenderProp<ComponentPropsWithRef<"div">, SliderTrackState>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The rail the thumbs move along. A press moves the nearest thumb, focuses its input and starts
|
|
19
|
+
* its drag; its box is the geometry reference for the pointer math (its computed `direction`
|
|
20
|
+
* mirrors a horizontal slider). Owned keys: `onPointerDown`, `data-orientation`,
|
|
21
|
+
* `data-disabled`, and `touch-action` in `style` (`pan-y` horizontal, `pan-x` vertical; the
|
|
22
|
+
* consumer's entry wins).
|
|
23
|
+
*/
|
|
24
|
+
export declare function SliderTrack({ className, style, children, render, ...rest }: SliderTrackProps): ReactNode;
|
|
25
|
+
export declare namespace SliderTrack {
|
|
26
|
+
var displayName: string;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
//# sourceMappingURL=slider-track.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-track.d.mts","names":[],"sources":["../../src/slider/slider-track.tsx"],"mappings":";;;;iBAciB;WACN,aAAa;;WAEb;WACA;;iBAGM,yBAAyB,KACxC;EAGA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,WAAW,WAAW,WAAW;EACjC,SAAS,WAAW,8BAA8B;;;;;;;;;wBAUpC,cAAc,WAAW,OAAO,UAAU,WAAW,QAAQ,mBAAgB;yBAA7E"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { dataAttr } from "../internal/data-attr.mjs";
|
|
3
|
+
import { resolveStateValue, useRender } from "../internal/use-render.mjs";
|
|
4
|
+
import { useSliderContext } from "./slider-context.mjs";
|
|
5
|
+
import { useCallback } from "react";
|
|
6
|
+
//#region src/slider/slider-track.tsx
|
|
7
|
+
/**
|
|
8
|
+
* The rail the thumbs move along. A press moves the nearest thumb, focuses its input and starts
|
|
9
|
+
* its drag; its box is the geometry reference for the pointer math (its computed `direction`
|
|
10
|
+
* mirrors a horizontal slider). Owned keys: `onPointerDown`, `data-orientation`,
|
|
11
|
+
* `data-disabled`, and `touch-action` in `style` (`pan-y` horizontal, `pan-x` vertical; the
|
|
12
|
+
* consumer's entry wins).
|
|
13
|
+
*/
|
|
14
|
+
function SliderTrack({ className, style, children, render, ...rest }) {
|
|
15
|
+
const ctx = useSliderContext("Slider.Track");
|
|
16
|
+
const { trackRef } = ctx;
|
|
17
|
+
const libraryRef = useCallback((element) => {
|
|
18
|
+
trackRef.current = element;
|
|
19
|
+
return () => {
|
|
20
|
+
if (trackRef.current === element) trackRef.current = null;
|
|
21
|
+
};
|
|
22
|
+
}, [trackRef]);
|
|
23
|
+
const state = {
|
|
24
|
+
orientation: ctx.orientation,
|
|
25
|
+
dragging: ctx.draggingThumb !== null,
|
|
26
|
+
disabled: ctx.disabled
|
|
27
|
+
};
|
|
28
|
+
const touchAction = { touchAction: ctx.orientation === "vertical" ? "pan-x" : "pan-y" };
|
|
29
|
+
return useRender({
|
|
30
|
+
defaultElement: "div",
|
|
31
|
+
render,
|
|
32
|
+
state,
|
|
33
|
+
className,
|
|
34
|
+
style: (s) => ({
|
|
35
|
+
...touchAction,
|
|
36
|
+
...resolveStateValue(style, s)
|
|
37
|
+
}),
|
|
38
|
+
children,
|
|
39
|
+
props: rest,
|
|
40
|
+
ref: libraryRef,
|
|
41
|
+
libraryProps: {
|
|
42
|
+
"data-orientation": ctx.orientation,
|
|
43
|
+
"data-disabled": dataAttr(ctx.disabled),
|
|
44
|
+
onPointerDown: (event) => {
|
|
45
|
+
ctx.beginGesture(null, event.nativeEvent, event.currentTarget);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
SliderTrack.displayName = "SliderTrack";
|
|
51
|
+
//#endregion
|
|
52
|
+
export { SliderTrack };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=slider-track.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-track.mjs","names":[],"sources":["../../src/slider/slider-track.tsx"],"sourcesContent":["\"use client\";\nimport { useCallback } from \"react\";\nimport type {\n ComponentPropsWithRef,\n CSSProperties,\n PointerEvent as ReactPointerEvent,\n ReactNode,\n} from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport { useSliderContext } from \"./slider-context.js\";\nimport type { SliderOrientation } from \"./slider-root.js\";\n\nexport interface SliderTrackState {\n readonly orientation: SliderOrientation;\n /** A pointer is captured on a thumb. */\n readonly dragging: boolean;\n readonly disabled: boolean;\n}\n\nexport interface SliderTrackProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"onPointerDown\" | \"className\" | \"style\" | \"children\"\n> {\n className?: StateValue<string | undefined, SliderTrackState>;\n style?: StateValue<CSSProperties | undefined, SliderTrackState>;\n children?: StateValue<ReactNode, SliderTrackState>;\n render?: RenderProp<ComponentPropsWithRef<\"div\">, SliderTrackState>;\n}\n\n/**\n * The rail the thumbs move along. A press moves the nearest thumb, focuses its input and starts\n * its drag; its box is the geometry reference for the pointer math (its computed `direction`\n * mirrors a horizontal slider). Owned keys: `onPointerDown`, `data-orientation`,\n * `data-disabled`, and `touch-action` in `style` (`pan-y` horizontal, `pan-x` vertical; the\n * consumer's entry wins).\n */\nexport function SliderTrack({ className, style, children, render, ...rest }: SliderTrackProps) {\n const ctx = useSliderContext(\"Slider.Track\");\n const { trackRef } = ctx;\n const libraryRef = useCallback(\n (element: HTMLDivElement) => {\n trackRef.current = element;\n return () => {\n if (trackRef.current === element) trackRef.current = null;\n };\n },\n [trackRef],\n );\n\n const state: SliderTrackState = {\n orientation: ctx.orientation,\n dragging: ctx.draggingThumb !== null,\n disabled: ctx.disabled,\n };\n const touchAction: CSSProperties = {\n touchAction: ctx.orientation === \"vertical\" ? \"pan-x\" : \"pan-y\",\n };\n\n return useRender<ComponentPropsWithRef<\"div\">, SliderTrackState>({\n defaultElement: \"div\",\n render,\n state,\n className,\n style: (s) => ({ ...touchAction, ...resolveStateValue(style, s) }),\n children,\n props: rest,\n ref: libraryRef,\n libraryProps: {\n \"data-orientation\": ctx.orientation,\n \"data-disabled\": dataAttr(ctx.disabled),\n onPointerDown: (event: ReactPointerEvent<HTMLDivElement>) => {\n // A press on a Thumb bubbles here after the Thumb began its gesture; the Root ignores it.\n ctx.beginGesture(null, event.nativeEvent, event.currentTarget);\n },\n },\n });\n}\n\nSliderTrack.displayName = \"SliderTrack\";\n"],"mappings":";;;;;;;;;;;;;AAsCA,SAAgB,YAAY,EAAE,WAAW,OAAO,UAAU,QAAQ,GAAG,QAA0B;CAC7F,MAAM,MAAM,iBAAiB,cAAc;CAC3C,MAAM,EAAE,aAAa;CACrB,MAAM,aAAa,aAChB,YAA4B;EAC3B,SAAS,UAAU;EACnB,aAAa;GACX,IAAI,SAAS,YAAY,SAAS,SAAS,UAAU;EACvD;CACF,GACA,CAAC,QAAQ,CACX;CAEA,MAAM,QAA0B;EAC9B,aAAa,IAAI;EACjB,UAAU,IAAI,kBAAkB;EAChC,UAAU,IAAI;CAChB;CACA,MAAM,cAA6B,EACjC,aAAa,IAAI,gBAAgB,aAAa,UAAU,QAC1D;CAEA,OAAO,UAA0D;EAC/D,gBAAgB;EAChB;EACA;EACA;EACA,QAAQ,OAAO;GAAE,GAAG;GAAa,GAAG,kBAAkB,OAAO,CAAC;EAAE;EAChE;EACA,OAAO;EACP,KAAK;EACL,cAAc;GACZ,oBAAoB,IAAI;GACxB,iBAAiB,SAAS,IAAI,QAAQ;GACtC,gBAAgB,UAA6C;IAE3D,IAAI,aAAa,MAAM,MAAM,aAAa,MAAM,aAAa;GAC/D;EACF;CACF,CAAC;AACH;AAEA,YAAY,cAAc"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { RenderProp, StateValue } from "../internal/types.mjs";
|
|
2
|
+
import { SliderRootState, SliderValue } from "./slider-root.mjs";
|
|
3
|
+
import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
|
|
4
|
+
//#region src/slider/slider-value.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* `T` defaults to `SliderValue` (a number or an array): a part is not connected to its Root's
|
|
7
|
+
* value type. Pass it to narrow, `<Slider.Value<number>>`, or read `values`.
|
|
8
|
+
*/
|
|
9
|
+
export interface SliderValueState<T extends SliderValue = SliderValue> extends SliderRootState<T> {
|
|
10
|
+
/** The `index` prop, or `null`. */
|
|
11
|
+
readonly index: number | null;
|
|
12
|
+
}
|
|
13
|
+
export interface SliderValueProps<T extends SliderValue = SliderValue> extends Omit<ComponentPropsWithRef<"span">, "className" | "style" | "children"> {
|
|
14
|
+
/**
|
|
15
|
+
* Show one thumb's value. Without it a single-thumb slider shows its value; a multi-thumb
|
|
16
|
+
* slider needs `children` (dev warning otherwise, renders nothing).
|
|
17
|
+
*/
|
|
18
|
+
index?: number;
|
|
19
|
+
className?: StateValue<string | undefined, SliderValueState<T>>;
|
|
20
|
+
style?: StateValue<CSSProperties | undefined, SliderValueState<T>>;
|
|
21
|
+
children?: StateValue<ReactNode, SliderValueState<T>>;
|
|
22
|
+
render?: RenderProp<ComponentPropsWithRef<"span">, SliderValueState<T>>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Displays the shown value: `children(state)`, or the thumb at `index`, or the single value as
|
|
26
|
+
* text. A plain `span`, not `<output>`: a `status` live region updating on every step would
|
|
27
|
+
* chatter (the slider itself exposes its value). No owned keys.
|
|
28
|
+
*/
|
|
29
|
+
export declare function SliderValuePart<T extends SliderValue = SliderValue>({ index, className, style, children, render, ...rest }: SliderValueProps<T>): ReactNode;
|
|
30
|
+
export declare namespace SliderValuePart {
|
|
31
|
+
var displayName: string;
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//# sourceMappingURL=slider-value.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-value.d.mts","names":[],"sources":["../../src/slider/slider-value.tsx"],"mappings":";;;;;;;;iBAYiB,iBAAiB,UAAU,cAAc,qBAAqB,gBAAgB;;WAEpF;;iBAGM,iBAAiB,UAAU,cAAc,qBAAqB,KAC7E;;;;;EAOA;EACA,YAAY,+BAA+B,iBAAiB;EAC5D,QAAQ,WAAW,2BAA2B,iBAAiB;EAC/D,WAAW,WAAW,WAAW,iBAAiB;EAClD,SAAS,WAAW,+BAA+B,iBAAiB;;;;;;;wBAQtD,gBAAgB,UAAU,cAAc,eACtD,OACA,WACA,OACA,UACA,WACG,QACF,iBAAiB,KAAE;yBAPN"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
3
|
+
import { useDevWarning } from "../internal/use-dev-warning.mjs";
|
|
4
|
+
import { useSliderContext } from "./slider-context.mjs";
|
|
5
|
+
//#region src/slider/slider-value.tsx
|
|
6
|
+
/**
|
|
7
|
+
* Displays the shown value: `children(state)`, or the thumb at `index`, or the single value as
|
|
8
|
+
* text. A plain `span`, not `<output>`: a `status` live region updating on every step would
|
|
9
|
+
* chatter (the slider itself exposes its value). No owned keys.
|
|
10
|
+
*/
|
|
11
|
+
function SliderValuePart({ index, className, style, children, render, ...rest }) {
|
|
12
|
+
const ctx = useSliderContext("Slider.Value");
|
|
13
|
+
const state = {
|
|
14
|
+
...ctx.state,
|
|
15
|
+
index: index ?? null
|
|
16
|
+
};
|
|
17
|
+
const missing = children === void 0 && index === void 0 && ctx.shown.length > 1;
|
|
18
|
+
useDevWarning(missing, "Slider.Value: a multi-thumb slider has no single value to show. Pass `index` to show one thumb's value, or `children` (a function of the state) to format them all.");
|
|
19
|
+
let fallback = null;
|
|
20
|
+
if (index !== void 0) {
|
|
21
|
+
const value = ctx.shown[index];
|
|
22
|
+
fallback = value === void 0 ? null : String(value);
|
|
23
|
+
} else if (ctx.shown.length === 1) fallback = String(ctx.shown[0]);
|
|
24
|
+
return useRender({
|
|
25
|
+
defaultElement: "span",
|
|
26
|
+
render,
|
|
27
|
+
state,
|
|
28
|
+
className,
|
|
29
|
+
style,
|
|
30
|
+
children: children ?? fallback,
|
|
31
|
+
props: rest
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
SliderValuePart.displayName = "SliderValue";
|
|
35
|
+
//#endregion
|
|
36
|
+
export { SliderValuePart };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=slider-value.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-value.mjs","names":[],"sources":["../../src/slider/slider-value.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport { useSliderContext } from \"./slider-context.js\";\nimport type { SliderRootState, SliderValue } from \"./slider-root.js\";\n\n/**\n * `T` defaults to `SliderValue` (a number or an array): a part is not connected to its Root's\n * value type. Pass it to narrow, `<Slider.Value<number>>`, or read `values`.\n */\nexport interface SliderValueState<T extends SliderValue = SliderValue> extends SliderRootState<T> {\n /** The `index` prop, or `null`. */\n readonly index: number | null;\n}\n\nexport interface SliderValueProps<T extends SliderValue = SliderValue> extends Omit<\n ComponentPropsWithRef<\"span\">,\n \"className\" | \"style\" | \"children\"\n> {\n /**\n * Show one thumb's value. Without it a single-thumb slider shows its value; a multi-thumb\n * slider needs `children` (dev warning otherwise, renders nothing).\n */\n index?: number;\n className?: StateValue<string | undefined, SliderValueState<T>>;\n style?: StateValue<CSSProperties | undefined, SliderValueState<T>>;\n children?: StateValue<ReactNode, SliderValueState<T>>;\n render?: RenderProp<ComponentPropsWithRef<\"span\">, SliderValueState<T>>;\n}\n\n/**\n * Displays the shown value: `children(state)`, or the thumb at `index`, or the single value as\n * text. A plain `span`, not `<output>`: a `status` live region updating on every step would\n * chatter (the slider itself exposes its value). No owned keys.\n */\nexport function SliderValuePart<T extends SliderValue = SliderValue>({\n index,\n className,\n style,\n children,\n render,\n ...rest\n}: SliderValueProps<T>) {\n const ctx = useSliderContext(\"Slider.Value\");\n const state: SliderValueState<T> = {\n ...(ctx.state as SliderRootState<T>),\n index: index ?? null,\n };\n\n const missing = children === undefined && index === undefined && ctx.shown.length > 1;\n useDevWarning(\n missing,\n \"Slider.Value: a multi-thumb slider has no single value to show. Pass `index` to show one \" +\n \"thumb's value, or `children` (a function of the state) to format them all.\",\n );\n\n let fallback: ReactNode = null;\n if (index !== undefined) {\n const value = ctx.shown[index];\n fallback = value === undefined ? null : String(value);\n } else if (ctx.shown.length === 1) {\n fallback = String(ctx.shown[0]);\n }\n\n return useRender<ComponentPropsWithRef<\"span\">, SliderValueState<T>>({\n defaultElement: \"span\",\n render,\n state,\n className,\n style,\n children: children ?? fallback,\n props: rest,\n });\n}\n\nSliderValuePart.displayName = \"SliderValue\";\n"],"mappings":";;;;;;;;;;AAqCA,SAAgB,gBAAqD,EACnE,OACA,WACA,OACA,UACA,QACA,GAAG,QACmB;CACtB,MAAM,MAAM,iBAAiB,cAAc;CAC3C,MAAM,QAA6B;EACjC,GAAI,IAAI;EACR,OAAO,SAAS;CAClB;CAEA,MAAM,UAAU,aAAa,KAAA,KAAa,UAAU,KAAA,KAAa,IAAI,MAAM,SAAS;CACpF,cACE,SACA,qKAEF;CAEA,IAAI,WAAsB;CAC1B,IAAI,UAAU,KAAA,GAAW;EACvB,MAAM,QAAQ,IAAI,MAAM;EACxB,WAAW,UAAU,KAAA,IAAY,OAAO,OAAO,KAAK;CACtD,OAAO,IAAI,IAAI,MAAM,WAAW,GAC9B,WAAW,OAAO,IAAI,MAAM,EAAE;CAGhC,OAAO,UAA8D;EACnE,gBAAgB;EAChB;EACA;EACA;EACA;EACA,UAAU,YAAY;EACtB,OAAO;CACT,CAAC;AACH;AAEA,gBAAgB,cAAc"}
|
package/dist/switch/switch.d.mts
CHANGED
|
@@ -6,7 +6,7 @@ export interface SwitchState {
|
|
|
6
6
|
readonly checked: boolean;
|
|
7
7
|
/** An action dispatched by this Switch is in flight (including the resulting render). */
|
|
8
8
|
readonly pending: boolean;
|
|
9
|
-
/** The `disabled` prop. */
|
|
9
|
+
/** The `disabled` prop (or the enclosing `Field.Root`'s). */
|
|
10
10
|
readonly disabled: boolean;
|
|
11
11
|
}
|
|
12
12
|
/** Details passed as the second argument of `checkedChangeAction`. */
|
|
@@ -66,11 +66,13 @@ export interface SwitchProps extends Omit<ComponentPropsWithRef<"input">, "type"
|
|
|
66
66
|
*
|
|
67
67
|
* Owned keys (a `render` element's value is overridden): `type`, `role`, `checked`,
|
|
68
68
|
* `defaultChecked`, `aria-checked` (always removed), `disabled`, `data-checked`, `data-pending`,
|
|
69
|
-
* `data-disabled
|
|
69
|
+
* `data-disabled`; inside a `Field.Root` also `id`, `name`, `required`, `aria-invalid`,
|
|
70
|
+
* `aria-describedby` (token-merged) and `data-invalid`, and `disabled` / `name` / `required`
|
|
71
|
+
* default from the Field. Event handlers are merged rather than owned: a `render` element's own
|
|
70
72
|
* `onChange` (or `onClick`) runs first, then the library's; an `onClick` that calls
|
|
71
73
|
* `preventDefault()` cancels the change (nothing is dispatched).
|
|
72
74
|
*/
|
|
73
|
-
export declare function Switch({ checked, defaultChecked, checkedChangeAction, disabled, transition, className, style, render, ...rest }: SwitchProps): import("react").ReactNode;
|
|
75
|
+
export declare function Switch({ checked, defaultChecked, checkedChangeAction, disabled: disabledProp, transition, className, style, render, ...rest }: SwitchProps): import("react").ReactNode;
|
|
74
76
|
export declare namespace Switch {
|
|
75
77
|
var displayName: string;
|
|
76
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"switch.d.mts","names":[],"sources":["../../src/switch/switch.tsx"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"switch.d.mts","names":[],"sources":["../../src/switch/switch.tsx"],"mappings":";;;iBAuBiB;;WAEN;;WAEA;;WAEA;;;iBAIM,mCAAmC;;;;;;;WAOzC,QAAQ;;iBAGF,oBAAoB,KACnC;;EAYA;;;;;EAKA;;;;;;;;;;EAUA,sBAAsB,sBAAsB;;EAE5C;;EAEA;;;;;;;;;;EAUA,aAAa;EACb,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;;;;;EAK9C,SAAS,WAAW,gCAAgC;;;;;;;;;;;;;;;wBAgBtC,SACd,SACA,gBACA,qBACA,UAAU,cACV,YACA,WACA,OACA,WACG,QACF,8BAAW;yBAVE"}
|