diff --git a/docs/pages/base-ui/api/use-slider-thumb.json b/docs/pages/base-ui/api/use-slider-thumb.json index 7361dcf81..02c1fffb5 100644 --- a/docs/pages/base-ui/api/use-slider-thumb.json +++ b/docs/pages/base-ui/api/use-slider-thumb.json @@ -1,6 +1,52 @@ { "parameters": { + "active": { "type": { "name": "number", "description": "number" }, "required": true }, + "axis": { "type": { "name": "Axis", "description": "Axis" }, "required": true }, + "changeValue": { + "type": { + "name": "(valueInput: number, index: number, event: React.KeyboardEvent | React.ChangeEvent) => void", + "description": "(valueInput: number, index: number, event: React.KeyboardEvent | React.ChangeEvent) => void" + }, + "required": true + }, + "isRtl": { "type": { "name": "boolean", "description": "boolean" }, "required": true }, + "largeStep": { + "type": { "name": "number", "description": "number" }, + "default": "10", + "required": true + }, + "max": { "type": { "name": "number", "description": "number" }, "required": true }, + "min": { "type": { "name": "number", "description": "number" }, "required": true }, + "orientation": { + "type": { + "name": "'horizontal' | 'vertical'", + "description": "'horizontal' | 'vertical'" + }, + "default": "'horizontal'", + "required": true + }, + "scale": { + "type": { + "name": "(value: number) => number", + "description": "(value: number) => number" + }, + "required": true + }, + "setOpen": { + "type": { "name": "(index: number) => void", "description": "(index: number) => void" }, + "required": true + }, + "step": { + "type": { "name": "number | null", "description": "number | null" }, + "default": "1", + "required": true + }, + "values": { + "type": { "name": "readonly number[]", "description": "readonly number[]" }, + "required": true + }, "aria-label": { "type": { "name": "string", "description": "string" } }, + "aria-labelledby": { "type": { "name": "string", "description": "string" } }, "aria-valuetext": { "type": { "name": "string", "description": "string" } }, "disabled": { "type": { "name": "boolean", "description": "boolean" } }, "getAriaLabel": { @@ -16,6 +62,7 @@ } }, "id": { "type": { "name": "string", "description": "string" } }, + "name": { "type": { "name": "string", "description": "string" } }, "onBlur": { "type": { "name": "React.FocusEventHandler", "description": "React.FocusEventHandler" } }, @@ -27,7 +74,8 @@ }, "rootRef": { "type": { "name": "React.Ref<Element>", "description": "React.Ref<Element>" } - } + }, + "tabIndex": { "type": { "name": "number", "description": "number" } } }, "returnValue": { "getRootProps": { diff --git a/docs/pages/base-ui/api/use-slider.json b/docs/pages/base-ui/api/use-slider.json index a7e70ff0b..c706e85ce 100644 --- a/docs/pages/base-ui/api/use-slider.json +++ b/docs/pages/base-ui/api/use-slider.json @@ -166,8 +166,8 @@ }, "subitems": { "type": { - "name": "Map<any, SliderThumbMetadata>", - "description": "Map<any, SliderThumbMetadata>" + "name": "Map<string, SliderThumbMetadata>", + "description": "Map<string, SliderThumbMetadata>" }, "required": true }, diff --git a/docs/translations/api-docs/use-slider-thumb/use-slider-thumb.json b/docs/translations/api-docs/use-slider-thumb/use-slider-thumb.json index bebcf95c3..bdc80bbdb 100644 --- a/docs/translations/api-docs/use-slider-thumb/use-slider-thumb.json +++ b/docs/translations/api-docs/use-slider-thumb/use-slider-thumb.json @@ -1,16 +1,28 @@ { "hookDescription": "", "parametersDescriptions": { + "active": { "description": "The index of the active thumb." }, "aria-label": { "description": "The label for the input element." }, "aria-valuetext": { "description": "A string value that provides a user-friendly name for the current value of the slider." }, + "axis": { "description": "The orientation of the slider." }, "getAriaLabel": { "description": "Accepts a function which returns a string value that provides a user-friendly name for the input associated with the thumb" }, "getAriaValueText": { "description": "Accepts a function which returns a string value that provides a user-friendly name for the current value of the slider. This is important for screen reader users." - } + }, + "largeStep": { + "description": "The large step value of the slider when incrementing or decrementing while the shift key is held, or when using Page-Up or Page-Down keys. Snaps to multiples of this value." + }, + "max": { "description": "The maximum allowed value of the slider." }, + "min": { "description": "The minimum allowed value of the slider." }, + "orientation": { "description": "The component orientation." }, + "step": { + "description": "The step value of the slider when incrementing or decrementing. It will snap to multiples of this value. Decimal values are supported." + }, + "values": { "description": "The value(s) of the slider" } }, "returnValueDescriptions": { "getThumbStyle": { "description": "Resolver for the thumb slot's style prop." } diff --git a/docs/translations/api-docs/use-slider/use-slider.json b/docs/translations/api-docs/use-slider/use-slider.json index a91be526e..b82e56a43 100644 --- a/docs/translations/api-docs/use-slider/use-slider.json +++ b/docs/translations/api-docs/use-slider/use-slider.json @@ -63,6 +63,9 @@ "step": { "description": "The step value of the slider when incrementing or decrementing. It will snap to multiples of this value. Decimal values are supported." }, + "subitems": { + "description": "A map containing all the Thumb components registered to the slider" + }, "values": { "description": "The value(s) of the slider" } } } diff --git a/packages/mui-base/src/Slider/Root/SliderRoot.types.ts b/packages/mui-base/src/Slider/Root/SliderRoot.types.ts index 7143a4589..042cba0c9 100644 --- a/packages/mui-base/src/Slider/Root/SliderRoot.types.ts +++ b/packages/mui-base/src/Slider/Root/SliderRoot.types.ts @@ -275,7 +275,10 @@ export interface UseSliderReturnValue { * @default 1 */ step: number | null; - subitems: Map; + /** + * A map containing all the Thumb components registered to the slider + */ + subitems: Map; tabIndex?: number; /** * The value(s) of the slider diff --git a/packages/mui-base/src/Slider/SliderOutput/SliderOutput.tsx b/packages/mui-base/src/Slider/SliderOutput/SliderOutput.tsx index 82fe923d5..b9a896e97 100644 --- a/packages/mui-base/src/Slider/SliderOutput/SliderOutput.tsx +++ b/packages/mui-base/src/Slider/SliderOutput/SliderOutput.tsx @@ -21,11 +21,12 @@ const SliderOutput = React.forwardRef(function SliderOutput( const render = renderProp ?? defaultRender; - const { disabled, dragging, ownerState, values } = useSliderContext(); + const { disabled, dragging, ownerState, subitems, values } = useSliderContext(); const mergedRef = useRenderPropForkRef(render, forwardedRef); const { getRootProps } = useSliderOutput({ + subitems, rootRef: mergedRef, }); diff --git a/packages/mui-base/src/Slider/SliderOutput/SliderOutput.types.ts b/packages/mui-base/src/Slider/SliderOutput/SliderOutput.types.ts index 9719c2a1c..4f1085659 100644 --- a/packages/mui-base/src/Slider/SliderOutput/SliderOutput.types.ts +++ b/packages/mui-base/src/Slider/SliderOutput/SliderOutput.types.ts @@ -1,9 +1,9 @@ import { BaseUIComponentProps } from '../../utils/BaseUI.types'; -import { SliderRootOwnerState } from '../Root/SliderRoot.types'; +import { SliderRootOwnerState, UseSliderReturnValue } from '../Root/SliderRoot.types'; export interface SliderOutputProps extends BaseUIComponentProps<'output', SliderRootOwnerState> {} -export interface UseSliderOutputParameters { +export interface UseSliderOutputParameters extends Pick { 'aria-live'?: React.AriaAttributes['aria-live']; /** * Ref to the root slot's DOM element. diff --git a/packages/mui-base/src/Slider/SliderOutput/useSliderOutput.ts b/packages/mui-base/src/Slider/SliderOutput/useSliderOutput.ts index d590b96ea..b6f1b1b38 100644 --- a/packages/mui-base/src/Slider/SliderOutput/useSliderOutput.ts +++ b/packages/mui-base/src/Slider/SliderOutput/useSliderOutput.ts @@ -1,7 +1,6 @@ 'use client'; import * as React from 'react'; import { mergeReactProps } from '../../utils/mergeReactProps'; -import { useSliderContext } from '../Root/SliderProvider'; import { UseSliderOutputParameters, UseSliderOutputReturnValue } from './SliderOutput.types'; /** * @@ -10,9 +9,7 @@ import { UseSliderOutputParameters, UseSliderOutputReturnValue } from './SliderO * - [useSliderOutput API](https://mui.com/base-ui/api/use-slider-output/) */ function useSliderOutput(parameters: UseSliderOutputParameters): UseSliderOutputReturnValue { - const { 'aria-live': ariaLive = 'off', rootRef } = parameters; - - const { subitems } = useSliderContext(); + const { 'aria-live': ariaLive = 'off', rootRef, subitems } = parameters; const outputFor = Array.from(subitems.values()).reduce((acc, item) => { return `${acc} ${item.inputId}`; diff --git a/packages/mui-base/src/Slider/SliderThumb/SliderThumb.tsx b/packages/mui-base/src/Slider/SliderThumb/SliderThumb.tsx index fa2e18cc4..61bac8ddb 100644 --- a/packages/mui-base/src/Slider/SliderThumb/SliderThumb.tsx +++ b/packages/mui-base/src/Slider/SliderThumb/SliderThumb.tsx @@ -34,15 +34,48 @@ const SliderThumb = React.forwardRef(function SliderThumb( const mergedRef = useRenderPropForkRef(render, forwardedRef); - const { ownerState, active: activeIndex } = useSliderContext(); + const { + active: activeIndex, + 'aria-labelledby': ariaLabelledby, + axis, + changeValue, + disabled: contextDisabled, + isRtl, + largeStep, + max, + min, + name, + orientation, + ownerState, + scale, + setOpen, + step, + tabIndex, + values, + } = useSliderContext(); const { getRootProps, getThumbInputProps, disabled, index } = useSliderThumb({ - disabled: disabledProp, + 'aria-labelledby': ariaLabelledby, + active: activeIndex, + axis, + changeValue, + disabled: disabledProp || contextDisabled, id, - onFocus, + isRtl, + largeStep, + max, + min, + name, onBlur, + onFocus, onKeyDown, + orientation, rootRef: mergedRef, + scale, + setOpen, + step, + tabIndex, + values, }); const styleHooks = React.useMemo( diff --git a/packages/mui-base/src/Slider/SliderThumb/SliderThumb.types.ts b/packages/mui-base/src/Slider/SliderThumb/SliderThumb.types.ts index de522d26b..73664df29 100644 --- a/packages/mui-base/src/Slider/SliderThumb/SliderThumb.types.ts +++ b/packages/mui-base/src/Slider/SliderThumb/SliderThumb.types.ts @@ -1,10 +1,10 @@ import { BaseUIComponentProps } from '../../utils/BaseUI.types'; -import { SliderRootOwnerState } from '../Root/SliderRoot.types'; +import { SliderRootOwnerState, UseSliderReturnValue } from '../Root/SliderRoot.types'; export interface SliderThumbOwnerState extends SliderRootOwnerState {} export interface SliderThumbProps - extends Omit, + extends Partial>, BaseUIComponentProps<'span', SliderThumbOwnerState> { onPointerLeave?: React.PointerEventHandler; onPointerOver?: React.PointerEventHandler; @@ -13,7 +13,25 @@ export interface SliderThumbProps onKeyDown?: React.KeyboardEventHandler; } -export interface UseSliderThumbParameters { +export interface UseSliderThumbParameters + extends Pick< + UseSliderReturnValue, + | 'active' + | 'aria-labelledby' + | 'axis' + | 'changeValue' + | 'isRtl' + | 'largeStep' + | 'max' + | 'min' + | 'name' + | 'orientation' + | 'scale' + | 'setOpen' + | 'step' + | 'tabIndex' + | 'values' + > { /** * The label for the input element. */ diff --git a/packages/mui-base/src/Slider/SliderThumb/useSliderThumb.ts b/packages/mui-base/src/Slider/SliderThumb/useSliderThumb.ts index b3996f766..e6c885f1e 100644 --- a/packages/mui-base/src/Slider/SliderThumb/useSliderThumb.ts +++ b/packages/mui-base/src/Slider/SliderThumb/useSliderThumb.ts @@ -5,7 +5,6 @@ import { useId } from '../../utils/useId'; import { visuallyHidden } from '../../utils/visuallyHidden'; import { useCompoundItem } from '../../useCompound'; import { valueToPercent } from '../utils'; -import { useSliderContext } from '../Root/SliderProvider'; import { SliderThumbMetadata } from '../Root/SliderRoot.types'; import { UseSliderThumbParameters, UseSliderThumbReturnValue } from './SliderThumb.types'; @@ -30,35 +29,29 @@ function getNewValue( */ export function useSliderThumb(parameters: UseSliderThumbParameters) { const { + active: activeIndex, 'aria-label': ariaLabel, 'aria-valuetext': ariaValuetext, - disabled: disabledProp = false, - getAriaLabel, - getAriaValueText, - id: idParam, - rootRef: externalRef, - } = parameters; - - const { - active: activeIndex, 'aria-labelledby': ariaLabelledby, axis, changeValue, disabled, + getAriaLabel, + getAriaValueText, + id: idParam, isRtl, largeStep, max, min, name, orientation, + rootRef: externalRef, scale, setOpen, step, tabIndex, values: sliderValues, - } = useSliderContext(); - - const isThumbDisabled = disabledProp || disabled; + } = parameters; const thumbId = useId(idParam); const thumbRef = React.useRef(null); @@ -159,7 +152,7 @@ export function useSliderThumb(parameters: UseSliderThumbParameters) { style: { ...getThumbStyle(), }, - tabIndex: tabIndex ?? (isThumbDisabled ? undefined : 0), + tabIndex: tabIndex ?? (disabled ? undefined : 0), }); }, [ @@ -169,7 +162,7 @@ export function useSliderThumb(parameters: UseSliderThumbParameters) { idParam, index, isRtl, - isThumbDisabled, + disabled, largeStep, max, min, @@ -242,8 +235,8 @@ export function useSliderThumb(parameters: UseSliderThumbParameters) { getRootProps, getThumbInputProps, index, - disabled: isThumbDisabled, + disabled, }), - [getRootProps, getThumbInputProps, index, isThumbDisabled], + [getRootProps, getThumbInputProps, index, disabled], ); } diff --git a/packages/mui-base/src/Slider/SliderTrack/SliderTrack.tsx b/packages/mui-base/src/Slider/SliderTrack/SliderTrack.tsx index 589c75f97..ffd20aa47 100644 --- a/packages/mui-base/src/Slider/SliderTrack/SliderTrack.tsx +++ b/packages/mui-base/src/Slider/SliderTrack/SliderTrack.tsx @@ -23,9 +23,39 @@ const SliderTrack = React.forwardRef(function SliderTrack( const mergedRef = useRenderPropForkRef(render, forwardedRef); - const { disabled, dragging, ownerState } = useSliderContext(); + const { + areValuesEqual, + disabled, + dragging, + getFingerNewValue, + handleValueChange, + onValueCommitted, + max, + min, + ownerState, + setActive, + setDragging, + setOpen, + setValueState, + subitems, + values, + } = useSliderContext(); const { getRootProps } = useSliderTrack({ + areValuesEqual, + disabled, + dragging, + getFingerNewValue, + handleValueChange, + onValueCommitted, + max, + min, + setActive, + setDragging, + setOpen, + setValueState, + subitems, + values, rootRef: mergedRef, }); diff --git a/packages/mui-base/src/Slider/SliderTrack/SliderTrack.types.ts b/packages/mui-base/src/Slider/SliderTrack/SliderTrack.types.ts index b21f540fd..e854ce549 100644 --- a/packages/mui-base/src/Slider/SliderTrack/SliderTrack.types.ts +++ b/packages/mui-base/src/Slider/SliderTrack/SliderTrack.types.ts @@ -1,9 +1,26 @@ import { BaseUIComponentProps } from '../../utils/BaseUI.types'; -import { SliderRootOwnerState } from '../Root/SliderRoot.types'; +import { SliderRootOwnerState, UseSliderReturnValue } from '../Root/SliderRoot.types'; export interface SliderTrackProps extends BaseUIComponentProps<'span', SliderRootOwnerState> {} -export interface UseSliderTrackParameters { +export interface UseSliderTrackParameters + extends Pick< + UseSliderReturnValue, + | 'areValuesEqual' + | 'disabled' + | 'dragging' + | 'getFingerNewValue' + | 'handleValueChange' + | 'onValueCommitted' + | 'max' + | 'min' + | 'setActive' + | 'setDragging' + | 'setOpen' + | 'setValueState' + | 'subitems' + | 'values' + > { /** * The ref attached to the track of the Slider. */ diff --git a/packages/mui-base/src/Slider/SliderTrack/useSliderTrack.ts b/packages/mui-base/src/Slider/SliderTrack/useSliderTrack.ts index 62c1e574b..2be69d26e 100644 --- a/packages/mui-base/src/Slider/SliderTrack/useSliderTrack.ts +++ b/packages/mui-base/src/Slider/SliderTrack/useSliderTrack.ts @@ -2,7 +2,6 @@ import * as React from 'react'; import { mergeReactProps } from '../../utils/mergeReactProps'; import { ownerDocument } from '../../utils/owner'; import { useForkRef } from '../../utils/useForkRef'; -import { useSliderContext } from '../Root/SliderProvider'; import { useEventCallback } from '../../utils/useEventCallback'; import { roundValueToStep, valueToPercent } from '../utils'; import { focusThumb, trackFinger } from '../Root/useSliderRoot'; @@ -16,22 +15,6 @@ const INTENTIONAL_DRAG_COUNT_THRESHOLD = 2; * - [useSliderTrack API](https://mui.com/base-ui/api/use-slider-track/) */ export function useSliderTrack(parameters: UseSliderTrackParameters): UseSliderTrackReturnValue { - const { rootRef: externalRef } = parameters; - - const trackRef = React.useRef(null); - - const handleRootRef = useForkRef(externalRef, trackRef); - - // A number that uniquely identifies the current finger in the touch session. - const touchId = React.useRef(); - - const moveCount = React.useRef(0); - - // offset distance between: - // 1. pointerDown coordinates and - // 2. the exact intersection of the center of the thumb and the track - const offsetRef = React.useRef(0); - const { areValuesEqual, disabled, @@ -41,13 +24,28 @@ export function useSliderTrack(parameters: UseSliderTrackParameters): UseSliderT onValueCommitted, max, min, + rootRef: externalRef, setActive, setDragging, setOpen, setValueState, subitems, values, - } = useSliderContext(); + } = parameters; + + const trackRef = React.useRef(null); + + const handleRootRef = useForkRef(externalRef, trackRef); + + // A number that uniquely identifies the current finger in the touch session. + const touchId = React.useRef(); + + const moveCount = React.useRef(0); + + // offset distance between: + // 1. pointerDown coordinates and + // 2. the exact intersection of the center of the thumb and the track + const offsetRef = React.useRef(0); const thumbRefs = React.useMemo(() => { return Array.from(subitems).map((subitem) => {