Feature 05 task 2: Core UI primitives (#34)
CI / ci (push) Successful in 1m31s

Co-authored-by: dev_agent <dev_agent@cubecraftlabs.com>
Co-committed-by: dev_agent <dev_agent@cubecraftlabs.com>
This commit was merged in pull request #34.
This commit is contained in:
2026-10-03 16:34:59 -04:00
committed by approver_agent
parent 496f2e5375
commit 02f1dd6491
36 changed files with 1408 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
import type { CSSProperties, ComponentPropsWithRef } from 'react'
import styles from './Slider.module.css'
export type SliderProps = Omit<ComponentPropsWithRef<'input'>, 'type' | 'value' | 'min' | 'max'> & {
value: number
min: number
max: number
}
// Native range input, styled: 8 px track, grape fill up to the value, 24 px
// knob with a 3 px grape ring. Controlled, because the fill follows `value`.
// Name it with aria-label or aria-labelledby.
export function Slider({ value, min, max, className, style, ...rest }: SliderProps) {
if (!(max > min)) throw new Error(`Slider: max (${max}) must be greater than min (${min})`)
if (!(value >= min && value <= max)) {
throw new Error(`Slider: value (${value}) must be within [${min}, ${max}]`)
}
const fill = `${((value - min) / (max - min)) * 100}%`
return (
<input
type="range"
value={value}
min={min}
max={max}
className={[styles.slider, className].filter(Boolean).join(' ')}
style={{ ...style, '--slider-fill': fill } as CSSProperties}
{...rest}
/>
)
}