diff --git a/docs/app/experiments/slider-marks.tsx b/docs/app/experiments/slider-marks.tsx index e7c65bb90e..dbb3d0eb13 100644 --- a/docs/app/experiments/slider-marks.tsx +++ b/docs/app/experiments/slider-marks.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import * as Slider from '@base_ui/react/Slider'; -import { useSliderContext } from '../../../packages/mui-base/src/Slider/Root/SliderContext'; +import { useSliderRootContext } from '../../../packages/mui-base/src/Slider/Root/SliderRootContext'; const STOPS = [ { @@ -33,7 +33,7 @@ function getSliderThumbAriaValueText(value: number) { // for "inverted track", the track/rail can be styled with CSS but a prop is needed to flip the "mark active" state function MarkWithLabel(props: { index: number; value: number; label: string; inverted?: boolean }) { const { index, value, label, inverted = false } = props; - const { direction, values } = useSliderContext(); + const { direction, values } = useSliderRootContext(); const isRtl = direction === 'rtl'; const isFilled = inverted ? value >= values[0] : values[0] >= value; return ( diff --git a/docs/app/experiments/slider-tooltip.tsx b/docs/app/experiments/slider-tooltip.tsx index ba5c06cb69..6b73a2d2dd 100644 --- a/docs/app/experiments/slider-tooltip.tsx +++ b/docs/app/experiments/slider-tooltip.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import { useTheme } from '@mui/system'; import * as Slider from '@base_ui/react/Slider'; import * as Tooltip from '@base_ui/react/Tooltip'; -import { useSliderContext } from '../../../packages/mui-base/src/Slider/Root/SliderContext'; +import { useSliderRootContext } from '../../../packages/mui-base/src/Slider/Root/SliderRootContext'; function useIsDarkMode() { const theme = useTheme(); @@ -74,7 +74,7 @@ export default function App() { const SliderMark = React.forwardRef(function SliderMark(props: any, ref: React.ForwardedRef) { const { index, style, ...otherProps } = props; - const { percentageValues } = useSliderContext(); + const { percentageValues } = useSliderRootContext(); const isFilled = percentageValues[0] >= index * 10; return ( | node" } } }, "name": "SliderThumb", diff --git a/docs/data/components/slider/styles.module.css b/docs/data/components/slider/styles.module.css index 99aecc36a3..7cb1c12185 100644 --- a/docs/data/components/slider/styles.module.css +++ b/docs/data/components/slider/styles.module.css @@ -12,8 +12,8 @@ gap: 1rem; } -.output { - text-align: right; +[dir='rtl'] .output { + text-align: left; } .control { diff --git a/docs/data/translations/api-docs/slider-thumb/slider-thumb.json b/docs/data/translations/api-docs/slider-thumb/slider-thumb.json index fdff1c0d4e..ce97476995 100644 --- a/docs/data/translations/api-docs/slider-thumb/slider-thumb.json +++ b/docs/data/translations/api-docs/slider-thumb/slider-thumb.json @@ -19,6 +19,9 @@ "index": "The thumb label's index to format." } }, + "inputId": { + "description": "An optional id attribute for the underlying <input> element that can be used together with the for/htmlFor attribute of a custom label" + }, "render": { "description": "A function to customize rendering of the component." } }, "classDescriptions": {} diff --git a/packages/mui-base/src/Slider/Control/SliderControl.test.tsx b/packages/mui-base/src/Slider/Control/SliderControl.test.tsx index 3177338e04..12fc30502b 100644 --- a/packages/mui-base/src/Slider/Control/SliderControl.test.tsx +++ b/packages/mui-base/src/Slider/Control/SliderControl.test.tsx @@ -1,11 +1,10 @@ import * as React from 'react'; import * as Slider from '@base_ui/react/Slider'; import { createRenderer, describeConformance } from '#test-utils'; -import { SliderContext } from '../Root/SliderContext'; -import type { SliderRoot } from '../Root/SliderRoot'; +import { SliderRootContext } from '../Root/SliderRootContext'; import { NOOP } from '../../utils/noop'; -const testRootContext: SliderRoot.Context = { +const testRootContext: SliderRootContext = { active: -1, areValuesEqual: () => true, axis: 'horizontal', @@ -59,7 +58,7 @@ describe('', () => { describeConformance(, () => ({ render: (node) => { return render( - {node}, + {node}, ); }, refInstanceof: window.HTMLSpanElement, diff --git a/packages/mui-base/src/Slider/Control/SliderControl.tsx b/packages/mui-base/src/Slider/Control/SliderControl.tsx index 3622e16921..bfc4d52cd8 100644 --- a/packages/mui-base/src/Slider/Control/SliderControl.tsx +++ b/packages/mui-base/src/Slider/Control/SliderControl.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import type { BaseUIComponentProps } from '../../utils/types'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; -import { useSliderContext } from '../Root/SliderContext'; +import { useSliderRootContext } from '../Root/SliderRootContext'; import { sliderStyleHookMapping } from '../Root/styleHooks'; import type { SliderRoot } from '../Root/SliderRoot'; import { useSliderControl } from './useSliderControl'; @@ -39,7 +39,7 @@ const SliderControl = React.forwardRef(function SliderControl( setValueState, step, thumbRefs, - } = useSliderContext(); + } = useSliderRootContext(); const { getRootProps } = useSliderControl({ areValuesEqual, @@ -72,7 +72,9 @@ const SliderControl = React.forwardRef(function SliderControl( }); export namespace SliderControl { - export interface Props extends BaseUIComponentProps<'span', SliderRoot.OwnerState> {} + export interface OwnerState extends SliderRoot.OwnerState {} + + export interface Props extends BaseUIComponentProps<'span', OwnerState> {} } export { SliderControl }; diff --git a/packages/mui-base/src/Slider/Indicator/SliderIndicator.test.tsx b/packages/mui-base/src/Slider/Indicator/SliderIndicator.test.tsx index 5799e60c50..29d12759c6 100644 --- a/packages/mui-base/src/Slider/Indicator/SliderIndicator.test.tsx +++ b/packages/mui-base/src/Slider/Indicator/SliderIndicator.test.tsx @@ -1,11 +1,10 @@ import * as React from 'react'; import * as Slider from '@base_ui/react/Slider'; import { createRenderer, describeConformance } from '#test-utils'; -import { SliderContext } from '../Root/SliderContext'; -import type { SliderRoot } from '../Root/SliderRoot'; +import { SliderRootContext } from '../Root/SliderRootContext'; import { NOOP } from '../../utils/noop'; -const testRootContext: SliderRoot.Context = { +const testRootContext: SliderRootContext = { active: -1, areValuesEqual: () => true, axis: 'horizontal', @@ -59,7 +58,7 @@ describe('', () => { describeConformance(, () => ({ render: (node) => { return render( - {node}, + {node}, ); }, refInstanceof: window.HTMLSpanElement, diff --git a/packages/mui-base/src/Slider/Indicator/SliderIndicator.tsx b/packages/mui-base/src/Slider/Indicator/SliderIndicator.tsx index e28914e3f1..0a9912ac02 100644 --- a/packages/mui-base/src/Slider/Indicator/SliderIndicator.tsx +++ b/packages/mui-base/src/Slider/Indicator/SliderIndicator.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import type { BaseUIComponentProps } from '../../utils/types'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; -import { useSliderContext } from '../Root/SliderContext'; +import { useSliderRootContext } from '../Root/SliderRootContext'; import { sliderStyleHookMapping } from '../Root/styleHooks'; import type { SliderRoot } from '../Root/SliderRoot'; import { useSliderIndicator } from './useSliderIndicator'; @@ -24,7 +24,7 @@ const SliderIndicator = React.forwardRef(function SliderIndicator( const { render, className, ...otherProps } = props; const { axis, direction, disabled, orientation, ownerState, percentageValues } = - useSliderContext(); + useSliderRootContext(); const { getRootProps } = useSliderIndicator({ axis, @@ -48,7 +48,9 @@ const SliderIndicator = React.forwardRef(function SliderIndicator( }); export namespace SliderIndicator { - export interface Props extends BaseUIComponentProps<'span', SliderRoot.OwnerState> {} + export interface OwnerState extends SliderRoot.OwnerState {} + + export interface Props extends BaseUIComponentProps<'span', OwnerState> {} } export { SliderIndicator }; diff --git a/packages/mui-base/src/Slider/Indicator/useSliderIndicator.ts b/packages/mui-base/src/Slider/Indicator/useSliderIndicator.ts index 0c0255c767..c4b10fc92e 100644 --- a/packages/mui-base/src/Slider/Indicator/useSliderIndicator.ts +++ b/packages/mui-base/src/Slider/Indicator/useSliderIndicator.ts @@ -19,16 +19,6 @@ const axisProps = { }, }; -/** - * - * Demos: - * - * - [Slider](https://mui.com/base-ui/react-slider/#hooks) - * - * API: - * - * - [useSliderIndicator API](https://mui.com/base-ui/react-slider/hooks-api/#use-slider-indicator) - */ export function useSliderIndicator( parameters: useSliderIndicator.Parameters, ): useSliderIndicator.ReturnValue { diff --git a/packages/mui-base/src/Slider/Output/SliderOutput.test.tsx b/packages/mui-base/src/Slider/Output/SliderOutput.test.tsx index 34f4378064..bf9b52d02f 100644 --- a/packages/mui-base/src/Slider/Output/SliderOutput.test.tsx +++ b/packages/mui-base/src/Slider/Output/SliderOutput.test.tsx @@ -2,11 +2,10 @@ import * as React from 'react'; import { expect } from 'chai'; import * as Slider from '@base_ui/react/Slider'; import { createRenderer, describeConformance } from '#test-utils'; -import { SliderContext } from '../Root/SliderContext'; +import { SliderRootContext } from '../Root/SliderRootContext'; import { NOOP } from '../../utils/noop'; -import type { SliderRoot } from '../Root/SliderRoot'; -const testRootContext: SliderRoot.Context = { +const testRootContext: SliderRootContext = { active: -1, areValuesEqual: () => true, axis: 'horizontal', @@ -60,7 +59,7 @@ describe('', () => { describeConformance(, () => ({ render: (node) => { return render( - {node}, + {node}, ); }, refInstanceof: window.HTMLOutputElement, diff --git a/packages/mui-base/src/Slider/Output/SliderOutput.tsx b/packages/mui-base/src/Slider/Output/SliderOutput.tsx index a2d80a44ee..532e9a091b 100644 --- a/packages/mui-base/src/Slider/Output/SliderOutput.tsx +++ b/packages/mui-base/src/Slider/Output/SliderOutput.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import type { BaseUIComponentProps } from '../../utils/types'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; -import { useSliderContext } from '../Root/SliderContext'; +import { useSliderRootContext } from '../Root/SliderRootContext'; import { sliderStyleHookMapping } from '../Root/styleHooks'; import type { SliderRoot } from '../Root/SliderRoot'; import { useSliderOutput } from './useSliderOutput'; @@ -23,7 +23,7 @@ const SliderOutput = React.forwardRef(function SliderOutput( ) { const { render, className, ...otherProps } = props; - const { inputIdMap, ownerState, values } = useSliderContext(); + const { inputIdMap, ownerState, values } = useSliderRootContext(); const { getRootProps } = useSliderOutput({ inputIdMap, @@ -46,7 +46,9 @@ const SliderOutput = React.forwardRef(function SliderOutput( }); export namespace SliderOutput { - export interface Props extends BaseUIComponentProps<'output', SliderRoot.OwnerState> {} + export interface OwnerState extends SliderRoot.OwnerState {} + + export interface Props extends BaseUIComponentProps<'output', OwnerState> {} } export { SliderOutput }; diff --git a/packages/mui-base/src/Slider/Root/SliderContext.tsx b/packages/mui-base/src/Slider/Root/SliderContext.tsx deleted file mode 100644 index 33cb14bfe7..0000000000 --- a/packages/mui-base/src/Slider/Root/SliderContext.tsx +++ /dev/null @@ -1,20 +0,0 @@ -'use client'; -import * as React from 'react'; -import type { SliderRoot } from './SliderRoot'; - -/** - * @ignore - internal component. - */ -export const SliderContext = React.createContext(undefined); - -if (process.env.NODE_ENV !== 'production') { - SliderContext.displayName = 'SliderContext'; -} - -export function useSliderContext() { - const context = React.useContext(SliderContext); - if (context === undefined) { - throw new Error('useSliderContext must be used inside a Slider component'); - } - return context; -} diff --git a/packages/mui-base/src/Slider/Root/SliderRoot.tsx b/packages/mui-base/src/Slider/Root/SliderRoot.tsx index 274855b2a3..94e0041fee 100644 --- a/packages/mui-base/src/Slider/Root/SliderRoot.tsx +++ b/packages/mui-base/src/Slider/Root/SliderRoot.tsx @@ -7,7 +7,7 @@ import type { FieldRoot } from '../../Field/Root/FieldRoot'; import { CompositeList } from '../../Composite/List/CompositeList'; import { sliderStyleHookMapping } from './styleHooks'; import { useSliderRoot } from './useSliderRoot'; -import { SliderContext } from './SliderContext'; +import { SliderRootContext } from './SliderRootContext'; import { useFieldRootContext } from '../../Field/Root/FieldRootContext'; /** * @@ -104,9 +104,9 @@ const SliderRoot = React.forwardRef(function SliderRoot( }); return ( - + {renderElement()} - + ); }); diff --git a/packages/mui-base/src/Slider/Root/SliderRootContext.tsx b/packages/mui-base/src/Slider/Root/SliderRootContext.tsx new file mode 100644 index 0000000000..8bd6442146 --- /dev/null +++ b/packages/mui-base/src/Slider/Root/SliderRootContext.tsx @@ -0,0 +1,25 @@ +'use client'; +import * as React from 'react'; +import type { SliderRoot } from './SliderRoot'; +import type { useSliderRoot } from './useSliderRoot'; + +export interface SliderRootContext extends Omit { + ownerState: SliderRoot.OwnerState; +} + +/** + * @ignore - internal component. + */ +export const SliderRootContext = React.createContext(undefined); + +if (process.env.NODE_ENV !== 'production') { + SliderRootContext.displayName = 'SliderRootContext'; +} + +export function useSliderRootContext() { + const context = React.useContext(SliderRootContext); + if (context === undefined) { + throw new Error('useSliderRootContext must be used inside a Slider component'); + } + return context; +} diff --git a/packages/mui-base/src/Slider/Root/useSliderRoot.ts b/packages/mui-base/src/Slider/Root/useSliderRoot.ts index 1984aa5ac4..73f5251aff 100644 --- a/packages/mui-base/src/Slider/Root/useSliderRoot.ts +++ b/packages/mui-base/src/Slider/Root/useSliderRoot.ts @@ -108,16 +108,6 @@ export function trackFinger( }; } -/** - * - * Demos: - * - * - [Slider](https://mui.com/base-ui/react-slider/#hooks) - * - * API: - * - * - [useSliderRoot API](https://mui.com/base-ui/react-slider/hooks-api/#use-slider-root) - */ export function useSliderRoot(parameters: useSliderRoot.Parameters): useSliderRoot.ReturnValue { const { 'aria-labelledby': ariaLabelledby, diff --git a/packages/mui-base/src/Slider/Thumb/SliderThumb.test.tsx b/packages/mui-base/src/Slider/Thumb/SliderThumb.test.tsx index b57465bffa..fb144387b1 100644 --- a/packages/mui-base/src/Slider/Thumb/SliderThumb.test.tsx +++ b/packages/mui-base/src/Slider/Thumb/SliderThumb.test.tsx @@ -1,11 +1,10 @@ import * as React from 'react'; import * as Slider from '@base_ui/react/Slider'; import { createRenderer, describeConformance } from '#test-utils'; -import { SliderContext } from '../Root/SliderContext'; +import { SliderRootContext } from '../Root/SliderRootContext'; import { NOOP } from '../../utils/noop'; -import type { SliderRoot } from '../Root/SliderRoot'; -const testRootContext: SliderRoot.Context = { +const testRootContext: SliderRootContext = { active: -1, areValuesEqual: () => true, axis: 'horizontal', @@ -59,7 +58,7 @@ describe('', () => { describeConformance(, () => ({ render: (node) => { return render( - {node}, + {node}, ); }, refInstanceof: window.HTMLSpanElement, diff --git a/packages/mui-base/src/Slider/Thumb/SliderThumb.tsx b/packages/mui-base/src/Slider/Thumb/SliderThumb.tsx index c9dc22214e..07306236ae 100644 --- a/packages/mui-base/src/Slider/Thumb/SliderThumb.tsx +++ b/packages/mui-base/src/Slider/Thumb/SliderThumb.tsx @@ -7,7 +7,7 @@ import { resolveClassName } from '../../utils/resolveClassName'; import { BaseUIComponentProps } from '../../utils/types'; import { useForkRef } from '../../utils/useForkRef'; import type { SliderRoot } from '../Root/SliderRoot'; -import { useSliderContext } from '../Root/SliderContext'; +import { useSliderRootContext } from '../Root/SliderRootContext'; import { useSliderThumb } from './useSliderThumb'; import { isReactVersionAtLeast } from '../../utils/reactVersion'; @@ -46,6 +46,7 @@ const SliderThumb = React.forwardRef(function SliderThumb( getAriaLabel, getAriaValueText, id, + inputId, ...otherProps } = props; @@ -70,7 +71,7 @@ const SliderThumb = React.forwardRef(function SliderThumb( step, tabIndex, values, - } = useSliderContext(); + } = useSliderRootContext(); let renderPropRef = null; if (typeof render !== 'function') { @@ -91,6 +92,7 @@ const SliderThumb = React.forwardRef(function SliderThumb( getAriaLabel, getAriaValueText, id, + inputId, largeStep, max, min, @@ -212,6 +214,11 @@ SliderThumb.propTypes /* remove-proptypes */ = { * @ignore */ id: PropTypes.string, + /** + * An optional `id` attribute for the underlying `` element that + * can be used together with the `for`/`htmlFor` attribute of a custom label + */ + inputId: PropTypes.string, /** * @ignore */ diff --git a/packages/mui-base/src/Slider/Thumb/useSliderThumb.ts b/packages/mui-base/src/Slider/Thumb/useSliderThumb.ts index e1bc15ee48..bcccb56e53 100644 --- a/packages/mui-base/src/Slider/Thumb/useSliderThumb.ts +++ b/packages/mui-base/src/Slider/Thumb/useSliderThumb.ts @@ -351,6 +351,10 @@ export namespace useSliderThumb { */ getAriaValueText?: (value: number, index: number) => string; id?: React.HTMLAttributes['id']; + /** + * An optional `id` attribute for the underlying `` element that + * can be used together with the `for`/`htmlFor` attribute of a custom label + */ inputId?: React.HTMLAttributes['id']; disabled: boolean; onBlur?: React.FocusEventHandler; diff --git a/packages/mui-base/src/Slider/Track/SliderTrack.test.tsx b/packages/mui-base/src/Slider/Track/SliderTrack.test.tsx index 911e6bc63c..b74942f0da 100644 --- a/packages/mui-base/src/Slider/Track/SliderTrack.test.tsx +++ b/packages/mui-base/src/Slider/Track/SliderTrack.test.tsx @@ -1,11 +1,10 @@ import * as React from 'react'; import * as Slider from '@base_ui/react/Slider'; import { createRenderer, describeConformance } from '#test-utils'; -import { SliderContext } from '../Root/SliderContext'; +import { SliderRootContext } from '../Root/SliderRootContext'; import { NOOP } from '../../utils/noop'; -import type { SliderRoot } from '../Root/SliderRoot'; -const testRootContext: SliderRoot.Context = { +const testRootContext: SliderRootContext = { active: -1, areValuesEqual: () => true, axis: 'horizontal', @@ -59,7 +58,7 @@ describe('', () => { describeConformance(, () => ({ render: (node) => { return render( - {node}, + {node}, ); }, refInstanceof: window.HTMLSpanElement, diff --git a/packages/mui-base/src/Slider/Track/SliderTrack.tsx b/packages/mui-base/src/Slider/Track/SliderTrack.tsx index 7fa0de2216..704fd99810 100644 --- a/packages/mui-base/src/Slider/Track/SliderTrack.tsx +++ b/packages/mui-base/src/Slider/Track/SliderTrack.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { BaseUIComponentProps } from '../../utils/types'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; -import { useSliderContext } from '../Root/SliderContext'; +import { useSliderRootContext } from '../Root/SliderRootContext'; import type { SliderRoot } from '../Root/SliderRoot'; import { sliderStyleHookMapping } from '../Root/styleHooks'; /** @@ -22,7 +22,7 @@ const SliderTrack = React.forwardRef(function SliderTrack( ) { const { render, className, ...otherProps } = props; - const { ownerState } = useSliderContext(); + const { ownerState } = useSliderRootContext(); const { renderElement } = useComponentRenderer({ render: render ?? 'span', @@ -37,7 +37,9 @@ const SliderTrack = React.forwardRef(function SliderTrack( }); export namespace SliderTrack { - export interface Props extends BaseUIComponentProps<'span', SliderRoot.OwnerState> {} + export interface OwnerState extends SliderRoot.OwnerState {} + + export interface Props extends BaseUIComponentProps<'span', OwnerState> {} } export { SliderTrack };