Skip to content

Commit

Permalink
refactor(slider): ♻️ update slider state handling for UI (#282)
Browse files Browse the repository at this point in the history
  • Loading branch information
navin-moorthy authored Dec 1, 2021
1 parent 6670d08 commit acd4c1b
Show file tree
Hide file tree
Showing 16 changed files with 214 additions and 268 deletions.
2 changes: 2 additions & 0 deletions .storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module.exports = {
core: { builder: "webpack5" },
framework: "@storybook/react",
features: { babelModeV7: true },
stories: ["../src/**/*.stories.@(js|jsx|ts|tsx)"],
addons: [
"storybook-addon-preview",
Expand Down
2 changes: 1 addition & 1 deletion src/number-input/__keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ export const USE_NUMBERINPUT_STATE_KEYS = [
"isDisabled",
"isReadOnly",
"value",
"step",
"min",
"max",
"keepWithinRange",
"step",
"precision",
"isInvalid",
"isRequired",
Expand Down
43 changes: 4 additions & 39 deletions src/slider/SliderBaseState.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useNumberFormatter } from "@react-aria/i18n";
import { useSliderState } from "@react-stately/slider";
import { SliderProps } from "@react-types/slider";

export interface SliderBaseState {
/**
Expand All @@ -17,9 +18,6 @@ export interface SliderBaseState {
* @default 1
*/
step: number;

/** Whether the whole Slider is disabled. */
isDisabled: boolean;
}

export interface SliderBaseAction {
Expand Down Expand Up @@ -120,35 +118,7 @@ export interface SliderBaseAction {
setThumbEditable(index: number, editable: boolean): void;
}

export type SliderBaseInitialState = Partial<
Pick<SliderBaseState, "step" | "isDisabled">
> & {
/** The current value (controlled). */
value?: number[];

/**
* The slider's minimum value.
* @default 0
*/
minValue?: number;

/**
* The slider's maximum value.
* @default 100
*/
maxValue?: number;

/** The default value (uncontrolled). */
defaultValue?: number[];

/** Handler that is called when the value changes. */
onChange?: (value: number[]) => void;

/**
* Get the value when dragging has ended.
*/
onChangeEnd?: (value: number[]) => void;

export type SliderBaseInitialState = SliderProps & {
/**
* The display format of the value label.
*/
Expand All @@ -160,13 +130,8 @@ export type SliderBaseStateReturn = SliderBaseState & SliderBaseAction;
export function useSliderBaseState(
props: SliderBaseInitialState = {},
): SliderBaseStateReturn {
const { isDisabled = false } = props;

const numberFormatter = useNumberFormatter(props.formatOptions);
const state = useSliderState({ ...props, isDisabled, numberFormatter });
const state = useSliderState({ ...props, numberFormatter });

return {
...state,
isDisabled,
};
return state;
}
41 changes: 10 additions & 31 deletions src/slider/SliderState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import * as React from "react";
import { useSlider } from "@react-aria/slider";
import { AriaSliderProps } from "@react-types/slider";

import {
SliderBaseInitialState,
SliderBaseStateReturn,
useSliderBaseState,
} from "./index";
import { SliderBaseStateReturn } from "./index";

export type SliderState = {
/**
Expand All @@ -17,17 +13,6 @@ export type SliderState = {
*/
trackRef: React.RefObject<HTMLElement>;

/**
* Sliders BaseState.
*/
baseState: SliderBaseStateReturn;

/**
* The orientation of the Slider.
* @default 'horizontal'
*/
orientation: "horizontal" | "vertical";

/** Props for the label element. */
labelProps: React.LabelHTMLAttributes<HTMLLabelElement>;

Expand All @@ -41,24 +26,18 @@ export type SliderState = {
outputProps: React.OutputHTMLAttributes<HTMLOutputElement>;
};

export type SliderAction = {};
export type SliderActions = {};

export type SliderInitialState = AriaSliderProps & SliderBaseInitialState & {};
export type SliderStateReturn = SliderState & SliderActions & {};

export type SliderStateReturn = SliderState & SliderAction & {};
export type SliderInitialState = AriaSliderProps & {
state: SliderBaseStateReturn;
};

export function useSliderState(
props: SliderInitialState = {},
): SliderStateReturn {
const { orientation = "horizontal" } = props;
const baseState = useSliderBaseState(props);
export function useSliderState(props: SliderInitialState): SliderStateReturn {
const { state, ...rest } = props;
const trackRef = React.useRef<HTMLElement>(null);
const sliderProps = useSlider({ ...props, orientation }, baseState, trackRef);
const sliderProps = useSlider(rest, state, trackRef);

return {
baseState,
orientation,
trackRef,
...sliderProps,
};
return { ...sliderProps, trackRef };
}
35 changes: 13 additions & 22 deletions src/slider/SliderThumbState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,9 @@ import * as React from "react";
import { useSliderThumb } from "@react-aria/slider";
import { AriaSliderThumbProps } from "@react-types/slider";

import { SliderStateReturn } from "./SliderState";
import {} from ".";
import { SliderBaseStateReturn } from "./SliderBaseState";

export type SliderThumbState = {
/**
* Slider state, created via `useSliderState`.
*/
sliderState: SliderStateReturn;

/** A ref to the thumb input element. */
inputRef: React.RefObject<HTMLInputElement>;

Expand All @@ -26,31 +20,28 @@ export type SliderThumbState = {

export type SliderThumbActions = {};

export type SliderThumbInitialState = Pick<SliderThumbState, "sliderState"> &
AriaSliderThumbProps & {};

export type SliderThumbStateReturn = SliderThumbState & SliderThumbActions;

export type SliderThumbInitialState = AriaSliderThumbProps & {
/** A ref to the track element. */
trackRef: React.RefObject<HTMLElement>;

state: SliderBaseStateReturn;
};

export function useSliderThumbState(
props: SliderThumbInitialState,
): SliderThumbStateReturn {
const { sliderState, ...restProps } = props;
const { trackRef, baseState, orientation } = sliderState;
const { state, trackRef, ...thumbProps } = props;
const inputRef = React.useRef<HTMLInputElement>(null);
const sliderThumbProps = useSliderThumb(
{
trackRef,
inputRef,
isDisabled: baseState.isDisabled,
orientation,
...restProps,
trackRef,
...thumbProps,
},
baseState,
state,
);

return {
sliderState,
inputRef,
...sliderThumbProps,
};
return { ...sliderThumbProps, inputRef };
}
47 changes: 27 additions & 20 deletions src/slider/__keys.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
// Automatically generated
export const USE_SLIDER_BASE_STATE_KEYS = [
"orientation",
"isDisabled",
"step",
"value",
"onChangeEnd",
"minValue",
"maxValue",
"step",
"value",
"defaultValue",
"onChange",
"onChangeEnd",
"label",
"formatOptions",
] as const;
export const SLIDER_BASE_STATE_KEYS = [
"values",
"focusedThumb",
"step",
"isDisabled",
"getThumbValue",
"setThumbValue",
"setThumbPercent",
Expand All @@ -31,27 +32,38 @@ export const SLIDER_BASE_STATE_KEYS = [
"isThumbEditable",
"setThumbEditable",
] as const;
export const SLIDER_STATE_KEYS = [
"trackRef",
"labelProps",
"groupProps",
"trackProps",
"outputProps",
] as const;
export const USE_SLIDER_STATE_KEYS = [
...USE_SLIDER_BASE_STATE_KEYS,
"orientation",
"isDisabled",
"onChangeEnd",
"minValue",
"maxValue",
"step",
"value",
"defaultValue",
"onChange",
"label",
"id",
"aria-label",
"aria-labelledby",
"aria-describedby",
"aria-details",
"state",
] as const;
export const SLIDER_STATE_KEYS = [
"trackRef",
"baseState",
"orientation",
export const SLIDER_THUMB_STATE_KEYS = [
"inputRef",
"thumbProps",
"inputProps",
"labelProps",
"groupProps",
"trackProps",
"outputProps",
] as const;
export const USE_SLIDER_THUMB_STATE_KEYS = [
"sliderState",
"orientation",
"isDisabled",
"index",
Expand All @@ -71,13 +83,8 @@ export const USE_SLIDER_THUMB_STATE_KEYS = [
"aria-describedby",
"aria-details",
"aria-errormessage",
] as const;
export const SLIDER_THUMB_STATE_KEYS = [
"sliderState",
"inputRef",
"thumbProps",
"inputProps",
"labelProps",
"trackRef",
"state",
] as const;
export const SLIDER_GROUP_KEYS = [
...SLIDER_BASE_STATE_KEYS,
Expand Down
33 changes: 21 additions & 12 deletions src/slider/__tests__/Slider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,27 @@ import { cleanup, screen } from "@testing-library/react";

import { installMouseEvent } from "../../utils/test-utils";
import {
SliderBaseInitialState,
SliderGroup,
SliderInput,
SliderLabel,
SliderOutput,
SliderThumb,
SliderThumbInitialState,
SliderTrack,
useSliderBaseState,
useSliderState,
useSliderThumbState,
} from "../index";
import { SliderInitialState } from "../SliderState";

export type SliderComponentProps = SliderInitialState & { origin?: number };
export type SliderComponentProps = SliderBaseInitialState & { origin?: number };

export const SliderComponent = (props: SliderComponentProps) => {
const state = useSliderState(props);
const label = "Minimal slider";
const state = useSliderBaseState(props);
const slider = useSliderState({ ...props, label: "Minimal slider", state });
const originProp = props.origin ?? props.minValue ?? 0;
const { values, getValuePercent, getThumbValueLabel } = state.baseState;
const { values, getValuePercent, getThumbValueLabel } = state;

const trackWidth = `${
(getValuePercent(Math.max(values[0], originProp)) -
Expand All @@ -73,22 +76,22 @@ export const SliderComponent = (props: SliderComponentProps) => {
const labelValue = getThumbValueLabel(0);

return (
<SliderGroup className="chakra-slider-group">
<SliderGroup className="chakra-slider-group" {...slider}>
<div className="slider-label">
<SliderLabel className="label" {...state}>
Minimal slider
<SliderLabel className="label" {...slider}>
{label}
</SliderLabel>
<SliderOutput
data-testid="testid-slider-value"
className="value"
{...state}
{...slider}
>
{labelValue}
</SliderOutput>
</div>

<div className={`slider`}>
<SliderTrack {...state} className="slider-track-container">
<SliderTrack {...slider} className="slider-track-container">
<div className="slider-track" />
<div
className="slider-filled-track"
Expand All @@ -99,7 +102,14 @@ export const SliderComponent = (props: SliderComponentProps) => {
/>
</SliderTrack>

<Thumb index={0} sliderState={state} aria-label="Thumb" />
<Thumb
index={0}
orientation={props.orientation}
isDisabled={props.isDisabled}
trackRef={slider.trackRef}
state={state}
aria-label="Thumb"
/>
</div>
</SliderGroup>
);
Expand All @@ -109,8 +119,7 @@ export type SliderThumbProps = SliderThumbInitialState & {};

export const Thumb: React.FC<SliderThumbProps> = props => {
const sliderThumb = useSliderThumbState(props);
const { sliderState } = props;
const { getThumbPercent } = sliderState.baseState;
const { getThumbPercent } = props.state;

return (
<div
Expand Down
Loading

1 comment on commit acd4c1b

@vercel
Copy link

@vercel vercel bot commented on acd4c1b Dec 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.