From c21249905c4ddd434c4cde21cc9e2c2e9b0bfce5 Mon Sep 17 00:00:00 2001 From: dev-rb Date: Fri, 20 Oct 2023 19:33:05 -0400 Subject: [PATCH 1/4] fix(slider): fix bugs with thumbs Fixed issue with thumbs moving too fast which was caused by the `Track` receiving pointer events. Fixed by adding `stopPropagation`. Fixed issue with the wrong thumb being selected when thumb values are 0 and they overlap. Changed onSlideStart to take in an index and a value. Thumbs pass in their own index and track will use `getClosestValueIndex` method to calculate the thumb that needs to be moved. --- packages/core/src/slider/slider-context.tsx | 2 +- packages/core/src/slider/slider-root.tsx | 13 +++++-------- packages/core/src/slider/slider-thumb.tsx | 21 ++++++++++++++++----- packages/core/src/slider/slider-track.tsx | 5 +++-- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/core/src/slider/slider-context.tsx b/packages/core/src/slider/slider-context.tsx index 01c11f1f..9876d220 100644 --- a/packages/core/src/slider/slider-context.tsx +++ b/packages/core/src/slider/slider-context.tsx @@ -16,7 +16,7 @@ export interface SliderContextValue { state: SliderState; thumbs: Accessor; setThumbs: Setter; - onSlideStart: ((value: number) => void) | undefined; + onSlideStart: ((index: number, value: number) => void) | undefined; onSlideMove: ((deltas: { deltaX: number; deltaY: number }) => void) | undefined; onSlideEnd: (() => void) | undefined; onStepKeyDown: (event: KeyboardEvent, index: number) => void; diff --git a/packages/core/src/slider/slider-root.tsx b/packages/core/src/slider/slider-root.tsx index adfa5287..c99c3dc3 100644 --- a/packages/core/src/slider/slider-root.tsx +++ b/packages/core/src/slider/slider-root.tsx @@ -205,14 +205,11 @@ export function SliderRoot(props: SliderRootProps) { const [trackRef, setTrackRef] = createSignal(); let currentPosition: number | null = null; - const onSlideStart = (value: number) => { - const closestIndex = getClosestValueIndex(state.values(), value); - if (closestIndex >= 0) { - state.setFocusedThumb(closestIndex); - state.setThumbDragging(closestIndex, true); - state.setThumbValue(closestIndex, value); - currentPosition = null; - } + const onSlideStart = (index: number, value: number) => { + state.setFocusedThumb(index); + state.setThumbDragging(index, true); + state.setThumbValue(index, value); + currentPosition = null; }; const onSlideMove = ({ deltaX, deltaY }: { deltaX: number; deltaY: number }) => { diff --git a/packages/core/src/slider/slider-thumb.tsx b/packages/core/src/slider/slider-thumb.tsx index d23c8c2d..f62d3d1e 100644 --- a/packages/core/src/slider/slider-thumb.tsx +++ b/packages/core/src/slider/slider-thumb.tsx @@ -13,7 +13,15 @@ */ import { callHandler, mergeDefaultProps, mergeRefs, OverrideComponentProps } from "@kobalte/utils"; -import { Accessor, createContext, JSX, onMount, splitProps, useContext } from "solid-js"; +import { + Accessor, + createContext, + createUniqueId, + JSX, + onMount, + splitProps, + useContext, +} from "solid-js"; import { createFormControlField, FORM_CONTROL_FIELD_PROP_NAMES } from "../form-control"; import { AsChildProp, Polymorphic } from "../polymorphic"; @@ -33,7 +41,7 @@ export function SliderThumb(props: SliderThumbProps) { props = mergeDefaultProps( { - id: context.generateId("thumb"), + id: context.generateId(`thumb-${createUniqueId()}`), }, props, ); @@ -101,18 +109,20 @@ export function SliderThumb(props: SliderThumbProps) { const target = e.currentTarget as HTMLElement; - target.setPointerCapture(e.pointerId); e.preventDefault(); + e.stopPropagation(); + target.setPointerCapture(e.pointerId); target.focus(); startPosition = context.state.orientation() === "horizontal" ? e.clientX : e.clientY; - if (value()) { - context.onSlideStart?.(value()!); + if (value() !== undefined) { + context.onSlideStart?.(index(), value()!); } }; const onPointerMove: JSX.EventHandlerUnion = e => { + e.stopPropagation(); callHandler(e, local.onPointerMove); const target = e.currentTarget as HTMLElement; @@ -129,6 +139,7 @@ export function SliderThumb(props: SliderThumbProps) { }; const onPointerUp: JSX.EventHandlerUnion = e => { + e.stopPropagation(); callHandler(e, local.onPointerUp); const target = e.currentTarget as HTMLElement; diff --git a/packages/core/src/slider/slider-track.tsx b/packages/core/src/slider/slider-track.tsx index f3b39920..0197da44 100644 --- a/packages/core/src/slider/slider-track.tsx +++ b/packages/core/src/slider/slider-track.tsx @@ -3,7 +3,7 @@ import { createSignal, JSX, splitProps } from "solid-js"; import { AsChildProp, Polymorphic } from "../polymorphic"; import { useSliderContext } from "./slider-context"; -import { linearScale } from "./utils"; +import { getClosestValueIndex, linearScale } from "./utils"; export interface SliderTrackProps extends OverrideComponentProps<"div", AsChildProp> {} @@ -58,7 +58,8 @@ export function SliderTrack(props: SliderTrackProps) { context.state.orientation() === "horizontal" ? e.clientX : e.clientY, ); startPosition = context.state.orientation() === "horizontal" ? e.clientX : e.clientY; - context.onSlideStart?.(value); + const closestIndex = getClosestValueIndex(context.state.values(), value); + context.onSlideStart?.(closestIndex, value); }; const onPointerMove: JSX.EventHandlerUnion = e => { From 29663c75828273eb950db2e33b0f6011adc94b9a Mon Sep 17 00:00:00 2001 From: dev-rb Date: Fri, 20 Oct 2023 23:50:24 -0400 Subject: [PATCH 2/4] docs(slider): init slider docs. --- apps/docs/src/examples/slider.module.css | 0 apps/docs/src/examples/slider.tsx | 22 + apps/docs/src/routes/docs/core.tsx | 5 + .../routes/docs/core/components/slider.mdx | 399 ++++++++++++++++++ 4 files changed, 426 insertions(+) create mode 100644 apps/docs/src/examples/slider.module.css create mode 100644 apps/docs/src/examples/slider.tsx create mode 100644 apps/docs/src/routes/docs/core/components/slider.mdx diff --git a/apps/docs/src/examples/slider.module.css b/apps/docs/src/examples/slider.module.css new file mode 100644 index 00000000..e69de29b diff --git a/apps/docs/src/examples/slider.tsx b/apps/docs/src/examples/slider.tsx new file mode 100644 index 00000000..1e7c04ef --- /dev/null +++ b/apps/docs/src/examples/slider.tsx @@ -0,0 +1,22 @@ +import { Slider } from "@kobalte/core"; +import style from "./slider.module.css"; + +export function BasicExample() { + return ( + +
+ Label + +
+ + + + + + + + + +
+ ); +} diff --git a/apps/docs/src/routes/docs/core.tsx b/apps/docs/src/routes/docs/core.tsx index 40eb8ee0..1e6571dd 100644 --- a/apps/docs/src/routes/docs/core.tsx +++ b/apps/docs/src/routes/docs/core.tsx @@ -122,6 +122,11 @@ const CORE_NAV_SECTIONS: NavSection[] = [ href: "/docs/core/components/skeleton", status: "new", }, + { + title: "Slider", + href: "/docs/core/components/slider", + status: "new", + }, { title: "Switch", href: "/docs/core/components/switch", diff --git a/apps/docs/src/routes/docs/core/components/slider.mdx b/apps/docs/src/routes/docs/core/components/slider.mdx new file mode 100644 index 00000000..ef5c0221 --- /dev/null +++ b/apps/docs/src/routes/docs/core/components/slider.mdx @@ -0,0 +1,399 @@ +import { Preview, TabsSnippets, Kbd } from "../../../../components"; +import { + BasicExample, + MultipleSkeletonsExample, + ToggleExample, +} from "../../../../examples/skeleton"; + +# Slider + +An input where the user selects a value from within a given range. + +## Import + +```ts +import { Slider } from "@kobalte/core"; +``` + +## Features + +- Follow the [WAI ARIA Slider](https://www.w3.org/WAI/ARIA/apg/patterns/slider-multithumb/) design pattern. +- Can be controlled or uncontrolled. +- Support for multiple thumbs. +- Support a minimum value between thumbs. +- Support click or touch on track to change value. +- Support right or left direction. + +## Anatomy + +The slider consists of: + +- **Slider.Root:** The root container for the slider. +- **Slider.Track:** The component that visually represents the slider track. +- **Slider.Fill:** The component that visually represents the slider value. +- **Slider.Thumb:** The thumb that is used to visually indicate a value in the slider. +- **Slider.Input:** The native html input that is visually hidden in the slider thumb. +- **Slider.ValueLabel:** The accessible label text representing the current value in a human-readable format. + +```tsx + +``` + +## Example + + + + + + + + index.tsx + style.css + +{/* */} + + ```tsx + import { Skeleton } from "@kobalte/core"; + import "./style.css"; + + function App() { + return ( + +

+ A UI toolkit for building accessible web apps and design systems with SolidJS. +

+
+ ); + } + ``` + +
+ + ```css + @keyframes skeleton-fade { + 0%, + 100% { + opacity: 0.4; + } + + 50% { + opacity: 1; + } + } + + .skeleton { + height: auto; + width: 100%; + position: relative; + transform: translateZ(0); + -webkit-transform: translateZ(0); + } + .skeleton[data-animate="true"]::after { + animation: skeleton-fade 1500ms linear infinite; + } + + .skeleton[data-visible="true"] { + overflow: hidden; + } + .skeleton[data-visible="true"]::before { + position: absolute; + content: ""; + inset: 0; + z-index: 10; + background-color: white; + } + + .skeleton[data-visible="true"]::after { + position: absolute; + content: ""; + inset: 0; + z-index: 11; + background-color: gray; + } + ``` + + +{/* */} +
+ +## Usage + +### Multiple skeletons + + + + + + + + index.tsx + style.css + +{/* */} + + ```tsx + import { Skeleton, Image } from "@kobalte/core"; + import "./style.css"; + + function App() { + return ( +
+
+ + + + + + + Kobalte + +
+ +

+ A UI toolkit for building accessible web apps and design systems with SolidJS. +

+
+
+ ); + } + ``` + +
+ + ```css + @keyframes skeleton-fade { + 0%, + 100% { + opacity: 0.4; + } + + 50% { + opacity: 1; + } + } + + .skeleton { + height: auto; + width: 100%; + position: relative; + transform: translateZ(0); + -webkit-transform: translateZ(0); + } + .skeleton[data-animate="true"]::after { + animation: skeleton-fade 1500ms linear infinite; + } + + .skeleton[data-visible="true"] { + overflow: hidden; + } + .skeleton[data-visible="true"]::before { + position: absolute; + content: ""; + inset: 0; + z-index: 10; + background-color: white; + } + + .skeleton[data-visible="true"]::after { + position: absolute; + content: ""; + inset: 0; + z-index: 11; + background-color: gray; + } + + .multiple-root { + display: flex; + flex-direction: column; + gap: 10px; + } + + .multiple-profile { + display: flex; + gap: 10px; + align-items: center; + } + ``` + + +{/* */} +
+ +### Toggle example + + + + + + + + index.tsx + style.css + +{/* */} + + ```tsx + import { Skeleton, ToggleButton } from "@kobalte/core"; + import "./style.css"; + + function App() { + const [visible, setVisible] = createSignal(true); + return ( +
+ + Skeleton {visible() ? "Visible" : "Not Visible"} + + +

+ A UI toolkit for building accessible web apps and design systems with SolidJS. +

+
+
+ ); + } + ``` + +
+ + ```css + @keyframes skeleton-fade { + 0%, + 100% { + opacity: 0.4; + } + + 50% { + opacity: 1; + } + } + + .skeleton { + height: auto; + width: 100%; + position: relative; + transform: translateZ(0); + -webkit-transform: translateZ(0); + } + .skeleton[data-animate="true"]::after { + animation: skeleton-fade 1500ms linear infinite; + } + + .skeleton[data-visible="true"] { + overflow: hidden; + } + .skeleton[data-visible="true"]::before { + position: absolute; + content: ""; + inset: 0; + z-index: 10; + background-color: white; + } + + .skeleton[data-visible="true"]::after { + position: absolute; + content: ""; + inset: 0; + z-index: 11; + background-color: gray; + } + + .toggle-root { + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + } + + .toggle-button { + appearance: none; + display: inline-flex; + justify-content: center; + align-items: center; + height: 40px; + width: 50%; + outline: none; + border-radius: 6px; + background-color: hsl(200 98% 39%); + color: white; + font-size: 16px; + line-height: 0; + } + + .toggle-button:focus-visible { + outline: 2px solid hsl(200 98% 39%); + outline-offset: 2px; + } + + .toggle-button[data-pressed] { + background-color: hsl(0 72% 51%); + } + ``` + + +{/* */} +
+ +## API Reference + +### Slider.Root + +| Prop | Description | +| :------- | :--------------------------------------------------------------------------------------------------- | +| value | `number[]`
The controlled values of the slider. Must be used in conjunction with `onChange`. | +| defaultValue | `number[]`
The value of the slider when initially rendered. Use when you do not need to control the state of the slider. | +| onChange | `(value: number[]) => void`
Event handler called when the value changes. | +| onChangeEnd | `(value: number[]) => void`
Event handler called when the value changes at the end of an interaction. | +| inverted | `boolean`
Whether the slider is visually inverted. Defaults to false. | +| minValue | `number`
The minimum slider value. Defaults to 0| +| maxValue | `number`
The maximum slider value. Defaults to 100| +| step | `number`
The stepping interval. Defaults to 1| +| minStepsBetweenThumbs | `number`
The minimum permitted steps between thumbs. Defaults to 0| +| getValueLabel | `(params: GetValueLabelParams) => string`
A function to get the accessible label text representing the current value in a human-readable format. If not provided, the value label will be read as a percentage of the max value.| +| orientation | `'horizontal' \| 'vertical'`
The orientation of the slider.| +| name | `string`
The name of the slider, used when submitting an HTML form.| +| validationState | `'valid' \| 'invalid'`
Whether the slider should display its "valid" or "invalid" visual styling.| +| required | `boolean`
Whether the user must check a radio group item before the owning form can be submitted. | +| disabled | `boolean`
Whether the radio group is disabled. | +| readOnly | `boolean`
Whether the radio group items can be selected but not changed by the user. | + +| Data attribute | Description | +| :------------- | :------------------------------------- | +| data-orientation='horizontal' | Present when the slider has horizontal orientation. | +| data-orientation='vertical' | Present when the slider has vertical orientation. | +| data-valid | Present when the slider is valid according to the validation rules. | +| data-invalid | Present when the slider is invalid according to the validation rules. | +| data-required | Present when the user must slider an item before the owning form can be submitted. | +| data-disabled | Present when the slider is disabled. | +| data-readonly | Present when the slider is read only. | + +`Slider.ValueLabel`, `Slider.Fill`, `Slider.Input`, `Slider.Thumb` and `Slider.Track` share the same data-attributes. + +## Rendered elements + +| Component | Default rendered element | +| :-------------- | :----------------------- | +| `Slider.Root` | `div` | +| `Slider.Track` | `div` | +| `Slider.Fill` | `div` | +| `Slider.Thumb` | `span` | +| `Slider.Input` | `input` | +| `Slider.ValueLabel` | `div` | + +## Accessibility + +### Keyboard Interactions + +| Key | Description | +| :-------------------- | :---------------------------------------------------------------------------------------------------------------------------- | +| PageUp | Increases the value of the focused thumb by a larger `step`. | +| PageDown | Decreases the value of the focused thumb by a larger `step`. | +| ArrowDown | Decreases the value of the focused thumb by the `step` amount. | +| ArrowUp | Increases the value of the focused thumb by the `step` amount. | +| ArrowRight | Increments/decrements by the `step` value depending on `orientation`. | +| ArrowLeft | Increments/decrements by the `step` value depending on `orientation`. | +| Home | Sets the value of the first thumb to the minimum value. +| End | Sets the value of the last thumb to the maximum value. From 13c89d43bfe45ab5d54de9957549f4fe46dae371 Mon Sep 17 00:00:00 2001 From: dev-rb Date: Sat, 21 Oct 2023 15:32:19 -0400 Subject: [PATCH 3/4] docs(slider): add examples and anatomy --- apps/docs/src/examples/slider.module.css | 73 ++ apps/docs/src/examples/slider.tsx | 156 +++- .../routes/docs/core/components/slider.mdx | 760 ++++++++++++++---- 3 files changed, 824 insertions(+), 165 deletions(-) diff --git a/apps/docs/src/examples/slider.module.css b/apps/docs/src/examples/slider.module.css index e69de29b..29456a0c 100644 --- a/apps/docs/src/examples/slider.module.css +++ b/apps/docs/src/examples/slider.module.css @@ -0,0 +1,73 @@ +.SliderRoot { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + user-select: none; + touch-action: none; + width: 200px; +} + +.SliderRoot[data-orientation="vertical"] { + height: 200px; +} + +.SliderTrack { + background-color: rgba(0, 0, 0, 0.5); + position: relative; + border-radius: 9999px; + height: 8px; + width: 100%; +} + +.SliderTrack[data-orientation="vertical"] { + width: 8px; + height: 100%; +} +.SliderRange { + position: absolute; + background-color: white; + border-radius: 9999px; + height: 100%; +} + +.SliderRange[data-orientation="vertical"] { + width: 100%; + height: unset; +} +.SliderThumb { + display: block; + width: 16px; + height: 16px; + background-color: #0090ff; + border-radius: 9999px; + top: -4px; +} +.SliderThumb[data-orientation="vertical"] { + left: -4px; + top: unset; +} +.SliderThumb:hover { + box-shadow: 0 0 0 5px #2a91fe98; +} +.SliderThumb:focus { + outline: none; + box-shadow: 0 0 0 5px #2a91fe98; +} +.SliderLabel { + width: 100%; + display: flex; + justify-content: space-between; +} + +.SecondThumb { + background-color: #30a46c; +} + +.SecondThumb:hover { + box-shadow: 0 0 0 5px #50fdac5e; +} + +.SecondThumb:focus { + box-shadow: 0 0 0 5px #50fdac5e; +} diff --git a/apps/docs/src/examples/slider.tsx b/apps/docs/src/examples/slider.tsx index 1e7c04ef..3d25c6de 100644 --- a/apps/docs/src/examples/slider.tsx +++ b/apps/docs/src/examples/slider.tsx @@ -1,19 +1,161 @@ import { Slider } from "@kobalte/core"; +import { createSignal } from "solid-js"; import style from "./slider.module.css"; export function BasicExample() { return ( - -
+ +
Label - +
- - - + + + - + +
+ ); +} + +export function MultipleThumbsExample() { + return ( + +
+ Label + +
+ + + + + + + + + +
+ ); +} + +export function StepExample() { + return ( + <> + +
+ Step size 8 + +
+ + + + + + +
+ +
+ Step size 10 + +
+ + + + + + +
+ +
+ Step size 20 + +
+ + + + + + +
+ + ); +} + +export function MinStepsBetweenExample() { + return ( + +
+ Label + +
+ + + + + + + + + +
+ ); +} + +export function VerticalSliderExample() { + return ( + +
+ Label + +
+ + + + + + +
+ ); +} + +export function CustomValueLabelExample() { + return ( + `$${params.values[0]} - $${params.values[1]}`} + > +
+ Money + +
+ + + + + + + + + +
+ ); +} + +export function ControlledExample() { + const [values, setValues] = createSignal([40]); + return ( + +
+ Label + +
+ + + diff --git a/apps/docs/src/routes/docs/core/components/slider.mdx b/apps/docs/src/routes/docs/core/components/slider.mdx index ef5c0221..8d57e5a6 100644 --- a/apps/docs/src/routes/docs/core/components/slider.mdx +++ b/apps/docs/src/routes/docs/core/components/slider.mdx @@ -1,9 +1,13 @@ import { Preview, TabsSnippets, Kbd } from "../../../../components"; import { BasicExample, - MultipleSkeletonsExample, - ToggleExample, -} from "../../../../examples/skeleton"; + MultipleThumbsExample, + StepExample, + MinStepsBetweenExample, + VerticalSliderExample, + CustomValueLabelExample, + ControlledExample, +} from "../../../../examples/slider"; # Slider @@ -20,9 +24,10 @@ import { Slider } from "@kobalte/core"; - Follow the [WAI ARIA Slider](https://www.w3.org/WAI/ARIA/apg/patterns/slider-multithumb/) design pattern. - Can be controlled or uncontrolled. - Support for multiple thumbs. -- Support a minimum value between thumbs. +- Support a minimum step between thumbs. - Support click or touch on track to change value. - Support right or left direction. +- Support for custom value label. ## Anatomy @@ -33,10 +38,20 @@ The slider consists of: - **Slider.Fill:** The component that visually represents the slider value. - **Slider.Thumb:** The thumb that is used to visually indicate a value in the slider. - **Slider.Input:** The native html input that is visually hidden in the slider thumb. +- **Slider.Label:** The label that gives the user information on the slider. - **Slider.ValueLabel:** The accessible label text representing the current value in a human-readable format. ```tsx - + + + + + + + + + + ``` ## Example @@ -53,16 +68,23 @@ The slider consists of: {/* */} ```tsx - import { Skeleton } from "@kobalte/core"; + import { Slider } from "@kobalte/core"; import "./style.css"; function App() { return ( - -

- A UI toolkit for building accessible web apps and design systems with SolidJS. -

-
+ +
+ Label + +
+ + + + + + +
); } ``` @@ -70,45 +92,53 @@ The slider consists of:
```css - @keyframes skeleton-fade { - 0%, - 100% { - opacity: 0.4; - } - - 50% { - opacity: 1; - } + .SliderRoot { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + user-select: none; + touch-action: none; + width: 200px; } - .skeleton { - height: auto; - width: 100%; + .SliderTrack { + background-color: rgba(0, 0, 0, 0.5); position: relative; - transform: translateZ(0); - -webkit-transform: translateZ(0); - } - .skeleton[data-animate="true"]::after { - animation: skeleton-fade 1500ms linear infinite; + border-radius: 9999px; + height: 8px; + width: 100%; } - .skeleton[data-visible="true"] { - overflow: hidden; - } - .skeleton[data-visible="true"]::before { + .SliderRange { position: absolute; - content: ""; - inset: 0; - z-index: 10; background-color: white; + border-radius: 9999px; + height: 100%; } - .skeleton[data-visible="true"]::after { - position: absolute; - content: ""; - inset: 0; - z-index: 11; - background-color: gray; + .SliderThumb { + display: block; + width: 16px; + height: 16px; + background-color: #0090ff; + border-radius: 9999px; + top: -4px; + } + + .SliderThumb:hover { + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderThumb:focus { + outline: none; + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderLabel { + width: 100%; + display: flex; + justify-content: space-between; } ``` @@ -118,10 +148,10 @@ The slider consists of: ## Usage -### Multiple skeletons +### Multiple Thumbs - + @@ -132,32 +162,26 @@ The slider consists of: {/* */} ```tsx - import { Skeleton, Image } from "@kobalte/core"; + import { Slider } from "@kobalte/core"; import "./style.css"; function App() { return ( -
-
- - - - - - - Kobalte - + +
+ Label +
- -

- A UI toolkit for building accessible web apps and design systems with SolidJS. -

-
-
+ + + + + + + + + + ); } ``` @@ -165,57 +189,192 @@ The slider consists of: ```css - @keyframes skeleton-fade { - 0%, - 100% { - opacity: 0.4; - } + .SliderRoot { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + user-select: none; + touch-action: none; + width: 200px; + } + + .SliderTrack { + background-color: rgba(0, 0, 0, 0.5); + position: relative; + border-radius: 9999px; + height: 8px; + width: 100%; + } + + .SliderRange { + position: absolute; + background-color: white; + border-radius: 9999px; + height: 100%; + } - 50% { - opacity: 1; - } + .SliderThumb { + display: block; + width: 16px; + height: 16px; + background-color: #0090ff; + border-radius: 9999px; + top: -4px; } - .skeleton { - height: auto; + .SliderThumb:hover { + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderThumb:focus { + outline: none; + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderLabel { width: 100%; - position: relative; - transform: translateZ(0); - -webkit-transform: translateZ(0); + display: flex; + justify-content: space-between; } - .skeleton[data-animate="true"]::after { - animation: skeleton-fade 1500ms linear infinite; + + .SecondThumb{ + background-color: #30A46C; } - .skeleton[data-visible="true"] { - overflow: hidden; + .SecondThumb:hover{ + box-shadow: 0 0 0 5px #50FDAC5E; } - .skeleton[data-visible="true"]::before { - position: absolute; - content: ""; - inset: 0; - z-index: 10; - background-color: white; + + .SecondThumb:focus{ + box-shadow: 0 0 0 5px #50FDAC5E; } + ``` - .skeleton[data-visible="true"]::after { - position: absolute; - content: ""; - inset: 0; - z-index: 11; - background-color: gray; + +{/* */} + + +### Modify step size + + + + + + + + index.tsx + style.css + +{/* */} + + ```tsx + import { Slider } from "@kobalte/core"; + import "./style.css"; + + function App() { + return ( + <> + +
+ Step size 8 + +
+ + + + + + + + + +
+ +
+ Step size 10 + +
+ + + + + + + + + +
+ +
+ Step size 20 + +
+ + + + + + + + + +
+ + ); } + ``` - .multiple-root { +
+ + ```css + .SliderRoot { + position: relative; display: flex; flex-direction: column; - gap: 10px; + align-items: center; + user-select: none; + touch-action: none; + width: 200px; + } + + .SliderTrack { + background-color: rgba(0, 0, 0, 0.5); + position: relative; + border-radius: 9999px; + height: 8px; + width: 100%; } - .multiple-profile { + .SliderRange { + position: absolute; + background-color: white; + border-radius: 9999px; + height: 100%; + } + + .SliderThumb { + display: block; + width: 16px; + height: 16px; + background-color: #0090ff; + border-radius: 9999px; + top: -4px; + } + + .SliderThumb:hover { + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderThumb:focus { + outline: none; + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderLabel { + width: 100%; display: flex; - gap: 10px; - align-items: center; + justify-content: space-between; } ``` @@ -223,10 +382,10 @@ The slider consists of: {/* */}
-### Toggle example +### Steps between thumbs - + @@ -237,22 +396,26 @@ The slider consists of: {/* */} ```tsx - import { Skeleton, ToggleButton } from "@kobalte/core"; + import { Slider } from "@kobalte/core"; import "./style.css"; function App() { - const [visible, setVisible] = createSignal(true); return ( -
- - Skeleton {visible() ? "Visible" : "Not Visible"} - - -

- A UI toolkit for building accessible web apps and design systems with SolidJS. -

-
-
+ +
+ Label + +
+ + + + + + + + + +
); } ``` @@ -260,76 +423,264 @@ The slider consists of:
```css - @keyframes skeleton-fade { - 0%, - 100% { - opacity: 0.4; - } + .SliderRoot { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + user-select: none; + touch-action: none; + width: 200px; + } - 50% { - opacity: 1; - } + .SliderTrack { + background-color: rgba(0, 0, 0, 0.5); + position: relative; + border-radius: 9999px; + height: 8px; + width: 100%; } - .skeleton { - height: auto; + .SliderRange { + position: absolute; + background-color: white; + border-radius: 9999px; + height: 100%; + } + + .SliderThumb { + display: block; + width: 16px; + height: 16px; + background-color: #0090ff; + border-radius: 9999px; + top: -4px; + } + + .SliderThumb:hover { + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderThumb:focus { + outline: none; + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderLabel { width: 100%; - position: relative; - transform: translateZ(0); - -webkit-transform: translateZ(0); + display: flex; + justify-content: space-between; + } + + .SecondThumb{ + background-color: #30A46C; + } + + .SecondThumb:hover{ + box-shadow: 0 0 0 5px #50FDAC5E; + } + + .SecondThumb:focus{ + box-shadow: 0 0 0 5px #50FDAC5E; + } + ``` + + +{/* */} +
+ +### Vertical Slider + + + + + + + + index.tsx + style.css + +{/* */} + + ```tsx + import { Slider } from "@kobalte/core"; + import "./style.css"; + + function App() { + return ( + +
+ Label + +
+ + + + + + +
+ ); } - .skeleton[data-animate="true"]::after { - animation: skeleton-fade 1500ms linear infinite; + ``` + +
+ + ```css + .SliderRoot { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + user-select: none; + touch-action: none; + height: 200px; } - .skeleton[data-visible="true"] { - overflow: hidden; + .SliderTrack { + background-color: rgba(0, 0, 0, 0.5); + position: relative; + border-radius: 9999px; + width: 8px; + height: 100%; } - .skeleton[data-visible="true"]::before { + + .SliderRange { position: absolute; - content: ""; - inset: 0; - z-index: 10; background-color: white; + border-radius: 9999px; + width: 100%; } - .skeleton[data-visible="true"]::after { - position: absolute; - content: ""; - inset: 0; - z-index: 11; - background-color: gray; + .SliderThumb { + display: block; + width: 16px; + height: 16px; + background-color: #0090ff; + border-radius: 9999px; + left: -4px; + } + + .SliderThumb:hover { + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderThumb:focus { + outline: none; + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderLabel { + width: 100%; + display: flex; + justify-content: space-between; } + ``` - .toggle-root { + +{/* */} +
+ +### Custom Value Label + + + + + + + index.tsx + style.css + +{/* */} + + ```tsx + import { Slider } from "@kobalte/core"; + import "./style.css"; + + function App() { + return ( + `$${params.values[0]} - $${params.values[1]}`} + > +
+ Money + +
+ + + + + + + + + +
+ ); + } + ``` + +
+ + ```css + .SliderRoot { + position: relative; display: flex; flex-direction: column; align-items: center; - gap: 10px; + user-select: none; + touch-action: none; + width: 200px; } - .toggle-button { - appearance: none; - display: inline-flex; - justify-content: center; - align-items: center; - height: 40px; - width: 50%; + .SliderTrack { + background-color: rgba(0, 0, 0, 0.5); + position: relative; + border-radius: 9999px; + height: 8px; + width: 100%; + } + + .SliderRange { + position: absolute; + background-color: white; + border-radius: 9999px; + height: 100%; + } + + .SliderThumb { + display: block; + width: 16px; + height: 16px; + background-color: #0090ff; + border-radius: 9999px; + top: -4px; + } + .SliderThumb:hover { + box-shadow: 0 0 0 5px #2a91fe98; + } + .SliderThumb:focus { outline: none; - border-radius: 6px; - background-color: hsl(200 98% 39%); - color: white; - font-size: 16px; - line-height: 0; + box-shadow: 0 0 0 5px #2a91fe98; + } + .SliderLabel { + width: 100%; + display: flex; + justify-content: space-between; + } + .SecondThumb{ + background-color: #30A46C; } - .toggle-button:focus-visible { - outline: 2px solid hsl(200 98% 39%); - outline-offset: 2px; + .SecondThumb:hover{ + box-shadow: 0 0 0 5px #50FDAC5E; } - .toggle-button[data-pressed] { - background-color: hsl(0 72% 51%); + .SecondThumb:focus{ + box-shadow: 0 0 0 5px #50FDAC5E; } ``` @@ -337,6 +688,99 @@ The slider consists of: {/* */}
+### Controlled Value + + + + + + + index.tsx + style.css + +{/* */} + + ```tsx + import { createSignal } from 'solid-js' + import { Slider } from "@kobalte/core"; + import "./style.css"; + + function App() { + const [values, setValues] = createSignal([40]) + + return ( + +
+ Label + +
+ + + + + + +
+ ); + } + ``` + +
+ + ```css + .SliderRoot { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + user-select: none; + touch-action: none; + width: 200px; + } + + .SliderTrack { + background-color: rgba(0, 0, 0, 0.5); + position: relative; + border-radius: 9999px; + height: 8px; + width: 100%; + } + + .SliderRange { + position: absolute; + background-color: white; + border-radius: 9999px; + height: 100%; + } + + .SliderThumb { + display: block; + width: 16px; + height: 16px; + background-color: #0090ff; + border-radius: 9999px; + top: -4px; + } + + .SliderThumb:hover { + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderThumb:focus { + outline: none; + box-shadow: 0 0 0 5px #2a91fe98; + } + + .SliderLabel { + width: 100%; + display: flex; + justify-content: space-between; + } + ``` + + +{/* */} +
## API Reference ### Slider.Root From 677f256e2acdc9b8a256dbeabb9af1147cef5780 Mon Sep 17 00:00:00 2001 From: Fabien MARIE-LOUISE Date: Sat, 21 Oct 2023 22:06:11 +0200 Subject: [PATCH 4/4] chore: changeset 0.11.2 --- .changeset/mighty-timers-cough.md | 5 + apps/docs/src/VERSIONS.ts | 2 +- apps/docs/src/examples/slider.module.css | 24 ++- apps/docs/src/examples/slider.tsx | 10 +- .../docs/src/routes/docs/changelog/0-11-x.mdx | 10 + apps/docs/src/routes/docs/core.tsx | 1 - .../routes/docs/core/components/slider.mdx | 178 ++++++++---------- 7 files changed, 106 insertions(+), 124 deletions(-) create mode 100644 .changeset/mighty-timers-cough.md diff --git a/.changeset/mighty-timers-cough.md b/.changeset/mighty-timers-cough.md new file mode 100644 index 00000000..0465ff11 --- /dev/null +++ b/.changeset/mighty-timers-cough.md @@ -0,0 +1,5 @@ +--- +"@kobalte/core": patch +--- + +added `Slider` component diff --git a/apps/docs/src/VERSIONS.ts b/apps/docs/src/VERSIONS.ts index 43c3db55..86f3ef15 100644 --- a/apps/docs/src/VERSIONS.ts +++ b/apps/docs/src/VERSIONS.ts @@ -14,4 +14,4 @@ export const CORE_VERSIONS = [ export const LATEST_CORE_CHANGELOG_URL = `/docs/changelog/${CORE_VERSIONS[0].replaceAll(".", "-")}`; -export const LATEST_CORE_VERSION_NAME = "v0.11.1"; +export const LATEST_CORE_VERSION_NAME = "v0.11.2"; diff --git a/apps/docs/src/examples/slider.module.css b/apps/docs/src/examples/slider.module.css index 29456a0c..a28a6bbc 100644 --- a/apps/docs/src/examples/slider.module.css +++ b/apps/docs/src/examples/slider.module.css @@ -13,7 +13,7 @@ } .SliderTrack { - background-color: rgba(0, 0, 0, 0.5); + background-color: hsl(240 6% 90%); position: relative; border-radius: 9999px; height: 8px; @@ -24,9 +24,10 @@ width: 8px; height: 100%; } + .SliderRange { position: absolute; - background-color: white; + background-color: hsl(200 98% 39%); border-radius: 9999px; height: 100%; } @@ -35,39 +36,36 @@ width: 100%; height: unset; } + .SliderThumb { display: block; width: 16px; height: 16px; - background-color: #0090ff; + background-color: hsl(200 98% 39%); border-radius: 9999px; top: -4px; } + .SliderThumb[data-orientation="vertical"] { left: -4px; top: unset; } + .SliderThumb:hover { box-shadow: 0 0 0 5px #2a91fe98; } + .SliderThumb:focus { outline: none; box-shadow: 0 0 0 5px #2a91fe98; } + .SliderLabel { width: 100%; display: flex; justify-content: space-between; } -.SecondThumb { - background-color: #30a46c; -} - -.SecondThumb:hover { - box-shadow: 0 0 0 5px #50fdac5e; -} - -.SecondThumb:focus { - box-shadow: 0 0 0 5px #50fdac5e; +[data-kb-theme="dark"] .SliderTrack { + background-color: hsl(240 5% 26%); } diff --git a/apps/docs/src/examples/slider.tsx b/apps/docs/src/examples/slider.tsx index 3d25c6de..4feb80a0 100644 --- a/apps/docs/src/examples/slider.tsx +++ b/apps/docs/src/examples/slider.tsx @@ -31,7 +31,7 @@ export function MultipleThumbsExample() { - + @@ -41,7 +41,7 @@ export function MultipleThumbsExample() { export function StepExample() { return ( - <> +
Step size 8 @@ -78,7 +78,7 @@ export function StepExample() { - +
); } @@ -94,7 +94,7 @@ export function MinStepsBetweenExample() { - + @@ -137,7 +137,7 @@ export function CustomValueLabelExample() { - + diff --git a/apps/docs/src/routes/docs/changelog/0-11-x.mdx b/apps/docs/src/routes/docs/changelog/0-11-x.mdx index 61a501d1..3e7ca2c1 100644 --- a/apps/docs/src/routes/docs/changelog/0-11-x.mdx +++ b/apps/docs/src/routes/docs/changelog/0-11-x.mdx @@ -1,5 +1,15 @@ # v0.11.x +## v0.11.2 (October 21, 2023) + +**New features** + +- Added `Slider` component. + +**Bug fixes** + +- [#278](https://github.com/kobaltedev/kobalte/pull/278) + ## v0.11.1 (October 20, 2023) **New features** diff --git a/apps/docs/src/routes/docs/core.tsx b/apps/docs/src/routes/docs/core.tsx index 1e6571dd..efab4157 100644 --- a/apps/docs/src/routes/docs/core.tsx +++ b/apps/docs/src/routes/docs/core.tsx @@ -67,7 +67,6 @@ const CORE_NAV_SECTIONS: NavSection[] = [ { title: "Combobox", href: "/docs/core/components/combobox", - status: "updated", }, { title: "Context Menu", diff --git a/apps/docs/src/routes/docs/core/components/slider.mdx b/apps/docs/src/routes/docs/core/components/slider.mdx index 8d57e5a6..98f1e899 100644 --- a/apps/docs/src/routes/docs/core/components/slider.mdx +++ b/apps/docs/src/routes/docs/core/components/slider.mdx @@ -103,7 +103,7 @@ The slider consists of: } .SliderTrack { - background-color: rgba(0, 0, 0, 0.5); + background-color: hsl(240 6% 90%); position: relative; border-radius: 9999px; height: 8px; @@ -112,7 +112,7 @@ The slider consists of: .SliderRange { position: absolute; - background-color: white; + background-color: hsl(200 98% 39%); border-radius: 9999px; height: 100%; } @@ -121,7 +121,7 @@ The slider consists of: display: block; width: 16px; height: 16px; - background-color: #0090ff; + background-color: hsl(200 98% 39%); border-radius: 9999px; top: -4px; } @@ -177,7 +177,7 @@ The slider consists of: - + @@ -200,7 +200,7 @@ The slider consists of: } .SliderTrack { - background-color: rgba(0, 0, 0, 0.5); + background-color: hsl(240 6% 90%); position: relative; border-radius: 9999px; height: 8px; @@ -209,7 +209,7 @@ The slider consists of: .SliderRange { position: absolute; - background-color: white; + background-color: hsl(200 98% 39%); border-radius: 9999px; height: 100%; } @@ -218,7 +218,7 @@ The slider consists of: display: block; width: 16px; height: 16px; - background-color: #0090ff; + background-color: hsl(200 98% 39%); border-radius: 9999px; top: -4px; } @@ -237,18 +237,6 @@ The slider consists of: display: flex; justify-content: space-between; } - - .SecondThumb{ - background-color: #30A46C; - } - - .SecondThumb:hover{ - box-shadow: 0 0 0 5px #50FDAC5E; - } - - .SecondThumb:focus{ - box-shadow: 0 0 0 5px #50FDAC5E; - } ``` @@ -339,7 +327,7 @@ The slider consists of: } .SliderTrack { - background-color: rgba(0, 0, 0, 0.5); + background-color: hsl(240 6% 90%); position: relative; border-radius: 9999px; height: 8px; @@ -348,7 +336,7 @@ The slider consists of: .SliderRange { position: absolute; - background-color: white; + background-color: hsl(200 98% 39%); border-radius: 9999px; height: 100%; } @@ -357,7 +345,7 @@ The slider consists of: display: block; width: 16px; height: 16px; - background-color: #0090ff; + background-color: hsl(200 98% 39%); border-radius: 9999px; top: -4px; } @@ -411,7 +399,7 @@ The slider consists of: - + @@ -434,7 +422,7 @@ The slider consists of: } .SliderTrack { - background-color: rgba(0, 0, 0, 0.5); + background-color: hsl(240 6% 90%); position: relative; border-radius: 9999px; height: 8px; @@ -443,7 +431,7 @@ The slider consists of: .SliderRange { position: absolute; - background-color: white; + background-color: hsl(200 98% 39%); border-radius: 9999px; height: 100%; } @@ -452,7 +440,7 @@ The slider consists of: display: block; width: 16px; height: 16px; - background-color: #0090ff; + background-color: hsl(200 98% 39%); border-radius: 9999px; top: -4px; } @@ -471,18 +459,6 @@ The slider consists of: display: flex; justify-content: space-between; } - - .SecondThumb{ - background-color: #30A46C; - } - - .SecondThumb:hover{ - box-shadow: 0 0 0 5px #50FDAC5E; - } - - .SecondThumb:focus{ - box-shadow: 0 0 0 5px #50FDAC5E; - } ``` @@ -538,7 +514,7 @@ The slider consists of: } .SliderTrack { - background-color: rgba(0, 0, 0, 0.5); + background-color: hsl(240 6% 90%); position: relative; border-radius: 9999px; width: 8px; @@ -547,7 +523,7 @@ The slider consists of: .SliderRange { position: absolute; - background-color: white; + background-color: hsl(200 98% 39%); border-radius: 9999px; width: 100%; } @@ -556,7 +532,7 @@ The slider consists of: display: block; width: 16px; height: 16px; - background-color: #0090ff; + background-color: hsl(200 98% 39%); border-radius: 9999px; left: -4px; } @@ -582,6 +558,7 @@ The slider consists of: ### Custom Value Label + @@ -614,7 +591,7 @@ The slider consists of: - + @@ -637,7 +614,7 @@ The slider consists of: } .SliderTrack { - background-color: rgba(0, 0, 0, 0.5); + background-color: hsl(240 6% 90%); position: relative; border-radius: 9999px; height: 8px; @@ -646,7 +623,7 @@ The slider consists of: .SliderRange { position: absolute; - background-color: white; + background-color: hsl(200 98% 39%); border-radius: 9999px; height: 100%; } @@ -655,33 +632,25 @@ The slider consists of: display: block; width: 16px; height: 16px; - background-color: #0090ff; + background-color: hsl(200 98% 39%); border-radius: 9999px; top: -4px; } + .SliderThumb:hover { box-shadow: 0 0 0 5px #2a91fe98; } + .SliderThumb:focus { outline: none; box-shadow: 0 0 0 5px #2a91fe98; } + .SliderLabel { width: 100%; display: flex; justify-content: space-between; } - .SecondThumb{ - background-color: #30A46C; - } - - .SecondThumb:hover{ - box-shadow: 0 0 0 5px #50FDAC5E; - } - - .SecondThumb:focus{ - box-shadow: 0 0 0 5px #50FDAC5E; - } ``` @@ -689,6 +658,7 @@ The slider consists of: ### Controlled Value + @@ -739,7 +709,7 @@ The slider consists of: } .SliderTrack { - background-color: rgba(0, 0, 0, 0.5); + background-color: hsl(240 6% 90%); position: relative; border-radius: 9999px; height: 8px; @@ -748,7 +718,7 @@ The slider consists of: .SliderRange { position: absolute; - background-color: white; + background-color: hsl(200 98% 39%); border-radius: 9999px; height: 100%; } @@ -757,7 +727,7 @@ The slider consists of: display: block; width: 16px; height: 16px; - background-color: #0090ff; + background-color: hsl(200 98% 39%); border-radius: 9999px; top: -4px; } @@ -785,59 +755,59 @@ The slider consists of: ### Slider.Root -| Prop | Description | -| :------- | :--------------------------------------------------------------------------------------------------- | -| value | `number[]`
The controlled values of the slider. Must be used in conjunction with `onChange`. | -| defaultValue | `number[]`
The value of the slider when initially rendered. Use when you do not need to control the state of the slider. | -| onChange | `(value: number[]) => void`
Event handler called when the value changes. | -| onChangeEnd | `(value: number[]) => void`
Event handler called when the value changes at the end of an interaction. | -| inverted | `boolean`
Whether the slider is visually inverted. Defaults to false. | -| minValue | `number`
The minimum slider value. Defaults to 0| -| maxValue | `number`
The maximum slider value. Defaults to 100| -| step | `number`
The stepping interval. Defaults to 1| -| minStepsBetweenThumbs | `number`
The minimum permitted steps between thumbs. Defaults to 0| -| getValueLabel | `(params: GetValueLabelParams) => string`
A function to get the accessible label text representing the current value in a human-readable format. If not provided, the value label will be read as a percentage of the max value.| -| orientation | `'horizontal' \| 'vertical'`
The orientation of the slider.| -| name | `string`
The name of the slider, used when submitting an HTML form.| -| validationState | `'valid' \| 'invalid'`
Whether the slider should display its "valid" or "invalid" visual styling.| -| required | `boolean`
Whether the user must check a radio group item before the owning form can be submitted. | -| disabled | `boolean`
Whether the radio group is disabled. | -| readOnly | `boolean`
Whether the radio group items can be selected but not changed by the user. | - -| Data attribute | Description | -| :------------- | :------------------------------------- | -| data-orientation='horizontal' | Present when the slider has horizontal orientation. | -| data-orientation='vertical' | Present when the slider has vertical orientation. | -| data-valid | Present when the slider is valid according to the validation rules. | -| data-invalid | Present when the slider is invalid according to the validation rules. | -| data-required | Present when the user must slider an item before the owning form can be submitted. | -| data-disabled | Present when the slider is disabled. | -| data-readonly | Present when the slider is read only. | +| Prop | Description | +| :-------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| value | `number[]`
The controlled values of the slider. Must be used in conjunction with `onChange`. | +| defaultValue | `number[]`
The value of the slider when initially rendered. Use when you do not need to control the state of the slider. | +| onChange | `(value: number[]) => void`
Event handler called when the value changes. | +| onChangeEnd | `(value: number[]) => void`
Event handler called when the value changes at the end of an interaction. | +| inverted | `boolean`
Whether the slider is visually inverted. Defaults to false. | +| minValue | `number`
The minimum slider value. Defaults to 0 | +| maxValue | `number`
The maximum slider value. Defaults to 100 | +| step | `number`
The stepping interval. Defaults to 1 | +| minStepsBetweenThumbs | `number`
The minimum permitted steps between thumbs. Defaults to 0 | +| getValueLabel | `(params: GetValueLabelParams) => string`
A function to get the accessible label text representing the current value in a human-readable format. If not provided, the value label will be read as a percentage of the max value. | +| orientation | `'horizontal' \| 'vertical'`
The orientation of the slider. | +| name | `string`
The name of the slider, used when submitting an HTML form. | +| validationState | `'valid' \| 'invalid'`
Whether the slider should display its "valid" or "invalid" visual styling. | +| required | `boolean`
Whether the user must check a radio group item before the owning form can be submitted. | +| disabled | `boolean`
Whether the radio group is disabled. | +| readOnly | `boolean`
Whether the radio group items can be selected but not changed by the user. | + +| Data attribute | Description | +| :---------------------------- | :--------------------------------------------------------------------------------- | +| data-orientation='horizontal' | Present when the slider has horizontal orientation. | +| data-orientation='vertical' | Present when the slider has vertical orientation. | +| data-valid | Present when the slider is valid according to the validation rules. | +| data-invalid | Present when the slider is invalid according to the validation rules. | +| data-required | Present when the user must slider an item before the owning form can be submitted. | +| data-disabled | Present when the slider is disabled. | +| data-readonly | Present when the slider is read only. | `Slider.ValueLabel`, `Slider.Fill`, `Slider.Input`, `Slider.Thumb` and `Slider.Track` share the same data-attributes. ## Rendered elements -| Component | Default rendered element | -| :-------------- | :----------------------- | -| `Slider.Root` | `div` | -| `Slider.Track` | `div` | -| `Slider.Fill` | `div` | -| `Slider.Thumb` | `span` | -| `Slider.Input` | `input` | +| Component | Default rendered element | +| :------------------ | :----------------------- | +| `Slider.Root` | `div` | +| `Slider.Track` | `div` | +| `Slider.Fill` | `div` | +| `Slider.Thumb` | `span` | +| `Slider.Input` | `input` | | `Slider.ValueLabel` | `div` | ## Accessibility ### Keyboard Interactions -| Key | Description | -| :-------------------- | :---------------------------------------------------------------------------------------------------------------------------- | -| PageUp | Increases the value of the focused thumb by a larger `step`. | -| PageDown | Decreases the value of the focused thumb by a larger `step`. | -| ArrowDown | Decreases the value of the focused thumb by the `step` amount. | -| ArrowUp | Increases the value of the focused thumb by the `step` amount. | -| ArrowRight | Increments/decrements by the `step` value depending on `orientation`. | -| ArrowLeft | Increments/decrements by the `step` value depending on `orientation`. | -| Home | Sets the value of the first thumb to the minimum value. -| End | Sets the value of the last thumb to the maximum value. +| Key | Description | +| :-------------------- | :-------------------------------------------------------------------- | +| PageUp | Increases the value of the focused thumb by a larger `step`. | +| PageDown | Decreases the value of the focused thumb by a larger `step`. | +| ArrowDown | Decreases the value of the focused thumb by the `step` amount. | +| ArrowUp | Increases the value of the focused thumb by the `step` amount. | +| ArrowRight | Increments/decrements by the `step` value depending on `orientation`. | +| ArrowLeft | Increments/decrements by the `step` value depending on `orientation`. | +| Home | Sets the value of the first thumb to the minimum value. | +| End | Sets the value of the last thumb to the maximum value. |