import { useState, type ReactNode } from "react"
import type { Meta, StoryObj } from "@storybook/react-vite"
import { Slider } from "@hm-design/ui"
import { StateBoard } from "@/components/story-board"
import { STORY_KICKER, StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
// The representative Story shows each Slider mode with real, draggable controls; the same specimens also exist as Stories tagged
// `verification` (hidden from the sidebar). The value label is the Story's composition (Slider has no built-in label).
// Names (`aria-label`) are provided by the consumer.
function Labeled({ label, children, valueText }: { label: string; children: ReactNode; valueText: string }) {
return (
{label}
{valueText}
{children}
)
}
function Single() {
const [value, setValue] = useState([40])
return (
)
}
function Range() {
const [value, setValue] = useState([25, 75])
return (
)
}
function Step() {
const [value, setValue] = useState([50])
return (
)
}
function Disabled() {
return
}
function Vertical() {
return (
)
}
const sections = [
{ id: "single", label: "Single", node: },
{ id: "range", label: "Range (two thumbs)", node: },
{ id: "step", label: "Step", node: },
{ id: "disabled", label: "Disabled", node: },
{ id: "vertical", label: "Vertical", node: },
]
const meta = { title: "Components/Form/Slider", component: Slider, parameters: { layout: "padded" } } satisfies Meta
export default meta
type Story = StoryObj
const board = (...ids: string[]) => (
ids.includes(s.id)).map((s) => ({ id: s.id, label: s.label, children: s.node }))} />
)
// Representative Story: the common Story page; the sections group the same specimens.
export const All: Story = {
name: "Slider",
parameters: { layout: "fullscreen", controls: { disable: true } },
render: () => (
{board("single")}
{board("range", "step", "vertical")}
{board("disabled")}
),
}
export const SingleValue: Story = { tags: ["verification"], name: "Single", render: () => }
export const RangeValue: Story = { tags: ["verification"], name: "Range", render: () => }
export const DisabledSlider: Story = { tags: ["verification"], name: "Disabled", render: () => }
export const Focus: Story = {
tags: ["verification"],
render: () => (
),
play: async ({ canvasElement }) => {
const thumb = canvasElement.querySelector('[data-slot="slider-thumb"]')!
const disabled = canvasElement.querySelector('[data-disabled] [data-slot="slider-thumb"]')!
const result = canvasElement.querySelector('[data-testid="slider-focus-result"]')!
const states: Record = {}
const read = (name: string, element = thumb) => { states[name] = getComputedStyle(element).boxShadow }
const assert = (condition: boolean, message: string) => { if (!condition) throw Error(message) }
thumb.blur()
read("Default")
// Existing Storybook pseudo-state mirroring preserves production selector order/specificity.
thumb.setAttribute("data-sb-hover", "")
read("Hover")
thumb.setAttribute("data-sb-active", "")
read("Drag")
thumb.removeAttribute("data-sb-hover")
thumb.removeAttribute("data-sb-active")
thumb.focus()
assert(thumb.matches(":focus-visible"), "Keyboard focus must be visible")
read("Focus")
thumb.setAttribute("data-sb-hover", "")
read("Focus + Hover")
thumb.setAttribute("data-sb-active", "")
read("Focus + Drag")
disabled.setAttribute("data-sb-hover", "")
disabled.setAttribute("data-sb-active", "")
disabled.focus()
read("Disabled", disabled)
assert(document.activeElement !== disabled, "Disabled thumb cannot receive focus")
assert(states.Default === "none" && states.Disabled === "none", "Default/Disabled have no halo")
assert(states.Hover.includes("4px") && states.Drag === states.Hover.replace("4px", "6px"), "Interaction keeps 4/6px and its color")
assert(states.Focus.includes("4px") && states["Focus + Hover"] === states.Focus, "Hover cannot mask Focus")
assert(states["Focus + Drag"] === states.Focus.replace("4px", "6px"), "Drag keeps 6px without masking Focus color")
for (const element of [thumb, disabled]) {
element.removeAttribute("data-sb-hover")
element.removeAttribute("data-sb-active")
}
thumb.focus()
result.textContent = JSON.stringify(states)
},
}