@zag-js/range-slider
Version:
Core logic for the range-slider widget implemented as a state machine
275 lines (258 loc) • 6.89 kB
text/typescript
import type { StateMachine as S } from "@zag-js/core"
import type { CommonProperties, Context, DirectionProperty, PropTypes, RequiredBy } from "@zag-js/types"
/* -----------------------------------------------------------------------------
* Callback details
* -----------------------------------------------------------------------------*/
export interface ValueChangeDetails {
value: number[]
}
export interface FocusChangeDetails {
focusedIndex: number
value: number[]
}
/* -----------------------------------------------------------------------------
* Machine context
* -----------------------------------------------------------------------------*/
type ElementIds = Partial<{
root: string
thumb(index: number): string
control: string
track: string
range: string
label: string
output: string
marker(index: number): string
}>
interface PublicContext extends DirectionProperty, CommonProperties {
/**
* The ids of the elements in the range slider. Useful for composition.
*/
ids?: ElementIds
/**
* The aria-label of each slider thumb. Useful for providing an accessible name to the slider
*/
"aria-label"?: string[]
/**
* The `id` of the elements that labels each slider thumb. Useful for providing an accessible name to the slider
*/
"aria-labelledby"?: string[]
/**
* The name associated with each slider thumb (when used in a form)
*/
name?: string
/**
* The associate form of the underlying input element.
*/
form?: string
/**
* The value of the range slider
*/
value: number[]
/**
* Whether the slider is disabled
*/
disabled?: boolean
/**
* Whether the slider is read-only
*/
readOnly?: boolean
/**
* Whether the slider is invalid
*/
invalid?: boolean
/**
* Function invoked when the value of the slider changes
*/
onValueChange?(details: ValueChangeDetails): void
/**
* Function invoked when the slider value change is started
*/
onValueChangeStart?(details: ValueChangeDetails): void
/**
* Function invoked when the slider value change is done
*/
onValueChangeEnd?(details: ValueChangeDetails): void
/**
* Function invoked when the slider's focused index changes
*/
onFocusChange?(details: FocusChangeDetails): void
/**
* Function that returns a human readable value for the slider thumb
*/
getAriaValueText?(value: number, index: number): string
/**
* The minimum value of the slider
*/
min: number
/**
* The maximum value of the slider
*/
max: number
/**
* The step value of the slider
*/
step: number
/**
* The minimum permitted steps between multiple thumbs.
*/
minStepsBetweenThumbs: number
/**
* The orientation of the slider
*/
orientation: "vertical" | "horizontal"
/**
* The alignment of the slider thumb relative to the track
* - `center`: the thumb will extend beyond the bounds of the slider track.
* - `contain`: the thumb will be contained within the bounds of the track.
*/
thumbAlignment?: "contain" | "center"
/**
* The slider thumbs dimensions
*/
thumbSize: { width: number; height: number } | null
}
export type UserDefinedContext = RequiredBy<PublicContext, "id">
type ComputedContext = Readonly<{
/**
* @computed
* Whether the slider thumb has been measured
*/
hasMeasuredThumbSize: boolean
/**
* @computed
* Whether the slider is interactive
*/
isInteractive: boolean
/**
* @computed
* The raw value of the space between each thumb
*/
spacing: number
/**
* @computed
* Whether the slider is vertical
*/
isVertical: boolean
/**
* @computed
* Whether the slider is horizontal
*/
isHorizontal: boolean
/**
* @computed
* Whether the slider is in RTL mode
*/
isRtl: boolean
/**
* @computed
* The percentage of the slider value relative to the slider min/max
*/
valuePercent: number[]
/**
* @computed
* Whether the slider is disabled
*/
isDisabled: boolean
}>
type PrivateContext = Context<{
/**
* @internal
* The active index of the range slider. This represents
* the currently dragged/focused thumb.
*/
focusedIndex: number
/**
* @internal
* The move threshold of the slider thumb before it is considered to be moved
*/
threshold: number
/**
* @internal
* Whether the slider fieldset is disabled
*/
fieldsetDisabled: boolean
}>
export interface MachineContext extends PublicContext, ComputedContext, PrivateContext {}
export interface MachineState {
value: "idle" | "dragging" | "focus"
}
export type State = S.State<MachineContext, MachineState>
export type Send = S.Send<S.AnyEventObject>
/* -----------------------------------------------------------------------------
* Component API
* -----------------------------------------------------------------------------*/
export interface MarkerProps {
value: number
}
export interface MachineApi<T extends PropTypes = PropTypes> {
/**
* The value of the slider.
*/
value: number[]
/**
* Whether the slider is being dragged.
*/
isDragging: boolean
/**
* Whether the slider is focused.
*/
isFocused: boolean
/**
* Function to set the value of the slider.
*/
setValue(value: number[]): void
/**
* Returns the value of the thumb at the given index.
*/
getThumbValue(index: number): number
/**
* Sets the value of the thumb at the given index.
*/
setThumbValue(index: number, value: number): void
/**
* Returns the percent of the thumb at the given index.
*/
getValuePercent: (value: number) => number
/**
* Returns the value of the thumb at the given percent.
*/
getPercentValue: (percent: number) => number
/**
* Returns the percent of the thumb at the given index.
*/
getThumbPercent(index: number): number
/**
* Sets the percent of the thumb at the given index.
*/
setThumbPercent(index: number, percent: number): void
/**
* Returns the min value of the thumb at the given index.
*/
getThumbMin(index: number): number
/**
* Returns the max value of the thumb at the given index.
*/
getThumbMax(index: number): number
/**
* Function to increment the value of the slider at the given index.
*/
increment(index: number): void
/**
* Function to decrement the value of the slider at the given index.
*/
decrement(index: number): void
/**
* Function to focus the slider. This focuses the first thumb.
*/
focus(): void
labelProps: T["label"]
rootProps: T["element"]
outputProps: T["output"]
trackProps: T["element"]
getThumbProps(index: number): T["element"]
getHiddenInputProps(index: number): T["input"]
rangeProps: T["element"]
controlProps: T["element"]
markerGroupProps: T["element"]
getMarkerProps(props: MarkerProps): T["element"]
}