Skip to content

Commit

Permalink
restrict slider type
Browse files Browse the repository at this point in the history
  • Loading branch information
seloner committed Dec 28, 2024
1 parent 38f77b6 commit 7f7d189
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 12 deletions.
4 changes: 2 additions & 2 deletions packages/react/src/slider/root/SliderRoot.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function createTouches(touches: Touches) {
};
}

function TestSlider(props: SliderRoot.Props) {
function TestSlider(props: SliderRoot.Props<number>) {
return (
<Slider.Root data-testid="root" {...props}>
<Slider.Value data-testid="value" />
Expand All @@ -49,7 +49,7 @@ function TestSlider(props: SliderRoot.Props) {
);
}

function TestRangeSlider(props: SliderRoot.Props) {
function TestRangeSlider(props: SliderRoot.Props<number[]>) {
return (
<Slider.Root data-testid="root" {...props}>
<Slider.Value data-testid="value" />
Expand Down
40 changes: 30 additions & 10 deletions packages/react/src/slider/root/SliderRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ import { sliderStyleHookMapping } from './styleHooks';
import { useSliderRoot } from './useSliderRoot';
import { SliderRootContext } from './SliderRootContext';
import { useFieldRootContext } from '../../field/root/FieldRootContext';
import { fixedForwardRef } from '../utils';

/**
* Groups all parts of the slider.
* Renders a `<div>` element.
*
* Documentation: [Base UI Slider](https://base-ui.com/react/components/slider)
*/
const SliderRoot = React.forwardRef(function SliderRoot(
props: SliderRoot.Props,
const SliderRoot = fixedForwardRef(function SliderRoot<TValue extends number | number[]>(
props: SliderRoot.Props<TValue>,
forwardedRef: React.ForwardedRef<HTMLDivElement>,
) {
const {
Expand Down Expand Up @@ -59,8 +60,8 @@ const SliderRoot = React.forwardRef(function SliderRoot(
min,
minStepsBetweenValues,
name,
onValueChange,
onValueCommitted,
onValueChange: onValueChange as useSliderRoot.Parameters['onValueChange'],
onValueCommitted: onValueCommitted as useSliderRoot.Parameters['onValueCommitted'],
orientation,
rootRef: forwardedRef,
step,
Expand Down Expand Up @@ -157,28 +158,25 @@ export namespace SliderRoot {
values: ReadonlyArray<number>;
}

export interface Props
export interface Props<TValue extends number | number[]>
extends Pick<
useSliderRoot.Parameters,
| 'disabled'
| 'max'
| 'min'
| 'minStepsBetweenValues'
| 'name'
| 'onValueChange'
| 'onValueCommitted'
| 'orientation'
| 'largeStep'
| 'step'
| 'value'
>,
Omit<BaseUIComponentProps<'div', State>, 'defaultValue' | 'onChange' | 'values'> {
/**
* The uncontrolled value of the slider when it’s initially rendered.
*
* To render a controlled slider, use the `value` prop instead.
*/
defaultValue?: number | ReadonlyArray<number>;
defaultValue?: TValue;
/**
* Whether the component should ignore user interaction.
* @default false
Expand All @@ -192,12 +190,34 @@ export namespace SliderRoot {
* The value of the slider.
* For ranged sliders, provide an array with two values.
*/
value?: number | ReadonlyArray<number>;
value?: TValue;
/**
* Callback function that is fired when the slider's value changed.
*
* @param {number | number[]} value The new value.
* @param {Event} event The corresponding event that initiated the change.
* You can pull out the new value by accessing `event.target.value` (any).
* @param {number} activeThumbIndex Index of the currently moved thumb.
*/
onValueChange?: (value: TValue, event: Event, activeThumbIndex: number) => void;
/**
* Callback function that is fired when the `pointerup` is triggered.
*
* @param {number | number[]} value The new value.
* @param {Event} event The corresponding event that initiated the change.
* **Warning**: This is a generic event not a change event.
*/
onValueCommitted?: (value: TValue, event: Event) => void;
/**
* The component orientation.
* @default 'horizontal'
*/
}
}

export { SliderRoot };

// @ts-expect-error
SliderRoot.propTypes /* remove-proptypes */ = {
// ┌────────────────────────────── Warning ──────────────────────────────┐
// │ These PropTypes are generated from the TypeScript type definitions. │
Expand Down
8 changes: 8 additions & 0 deletions packages/react/src/slider/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as React from 'react';

function getDecimalPrecision(num: number) {
// This handles the case when num is very small (0.00000001), js will turn this into 1e-8.
// When num is bigger than 1 or less than -1 it won't get converted to this notation so it's fine.
Expand All @@ -19,3 +21,9 @@ export function roundValueToStep(value: number, step: number, min: number) {
const nearest = Math.round((value - min) / step) * step + min;
return Number(nearest.toFixed(getDecimalPrecision(step)));
}

export function fixedForwardRef<T, P = {}>(
render: (props: P, ref: React.Ref<T>) => React.ReactNode,
): (props: P & React.RefAttributes<T>) => React.ReactNode {
return React.forwardRef(render) as any;
}

0 comments on commit 7f7d189

Please sign in to comment.