@krizaka/ui 3.37.0 → 3.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/blocks.css +36 -36
  2. package/dist/chip-link.js +1 -1
  3. package/dist/chip-row.js +1 -1
  4. package/dist/{chunk-IANSFIVC.js → chunk-7JFHTPI3.js} +13 -3
  5. package/dist/chunk-7JFHTPI3.js.map +1 -0
  6. package/dist/{chunk-RE5WJ4QP.js → chunk-ADRUEPYC.js} +4 -4
  7. package/dist/chunk-ADRUEPYC.js.map +1 -0
  8. package/dist/{chunk-BTTDIVVJ.js → chunk-F2UZ2WWL.js} +2 -2
  9. package/dist/chunk-F2UZ2WWL.js.map +1 -0
  10. package/dist/image-cropper.js +1 -1
  11. package/dist/kanban.js +1 -1
  12. package/dist/kanban.js.map +1 -1
  13. package/dist/landing-page.js +1 -6
  14. package/dist/landing-page.js.map +1 -1
  15. package/dist/map.js +2 -2
  16. package/dist/map.js.map +1 -1
  17. package/dist/motion.css +3 -3
  18. package/dist/native/vertical-video.js +1 -1
  19. package/dist/native/vertical-video.js.map +1 -1
  20. package/dist/native.d.ts +1 -1
  21. package/dist/native.js +11 -11
  22. package/dist/native.js.map +1 -1
  23. package/dist/nav-bar.d.ts +1 -1
  24. package/dist/nav-bar.js +1 -1
  25. package/dist/photo-grid.js +1 -1
  26. package/dist/photo-grid.js.map +1 -1
  27. package/dist/product-page.js +1 -6
  28. package/dist/product-page.js.map +1 -1
  29. package/dist/site-footer.d.ts +5 -17
  30. package/dist/site-footer.js +33 -29
  31. package/dist/site-footer.js.map +1 -1
  32. package/dist/{sites-B4sYlfPQ.d.ts → sites-inztN_Bv.d.ts} +8 -0
  33. package/dist/sites.d.ts +11 -1
  34. package/dist/sites.js +12 -2
  35. package/dist/sites.js.map +1 -1
  36. package/dist/slider.js +3 -3
  37. package/dist/slider.js.map +1 -1
  38. package/dist/step-showcase.js +1 -1
  39. package/dist/step-showcase.js.map +1 -1
  40. package/dist/story.css +3 -3
  41. package/dist/video-player.js +1 -1
  42. package/dist/video-trimmer.js +1 -1
  43. package/dist/video-trimmer.js.map +1 -1
  44. package/package.json +3 -3
  45. package/registry/chip-link.json +1 -1
  46. package/registry/examples/site-footer/company.js +0 -4
  47. package/registry/examples/site-footer/company.tsx +3 -7
  48. package/registry/index.json +7 -7
  49. package/registry/kanban.json +1 -1
  50. package/registry/landing-page.json +1 -1
  51. package/registry/map.json +2 -2
  52. package/registry/nav-bar.json +1 -1
  53. package/registry/photo-grid.json +1 -1
  54. package/registry/product-page.json +1 -1
  55. package/registry/rail-nav.json +1 -1
  56. package/registry/site-footer.json +10 -10
  57. package/registry/sites.json +2 -2
  58. package/registry/slider.json +1 -1
  59. package/registry/step-showcase.json +1 -1
  60. package/registry/video-trimmer.json +1 -1
  61. package/dist/chunk-BTTDIVVJ.js.map +0 -1
  62. package/dist/chunk-IANSFIVC.js.map +0 -1
  63. package/dist/chunk-RE5WJ4QP.js.map +0 -1
@@ -251,7 +251,7 @@
251
251
  },
252
252
  {
253
253
  "path": "video-trimmer/video-trimmer.tsx",
254
- "content": "// Client. The trim timeline of a video editor: the clip as a filmstrip (or any track content), the part kept framed\n// between two edge handles — each a `slider` named by a prop, its value read as a time, never past the other one —\n// the outside dimmed, and a playhead to scrub. The handles sit on their value by their outer edge (the start handle\n// to the right of its value, the end handle to its left), so the frame encloses exactly what is kept. Every part\n// takes its own classes (`classNames`) and the handles their own content (`renderHandle`).\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { clamp, formatClock } from \"../media\";\n\nexport const videoTrimmer = tv({\n slots: {\n root: \"w-full select-none\",\n header: \"mb-2 flex items-center justify-between font-mono text-[11px] tabular-nums text-fg-secondary\",\n kept: \"rounded-full bg-accent-soft px-2.5 py-0.5 font-sans text-xs font-semibold text-fg\",\n track: \"relative h-16 touch-none rounded-xl bg-surface-2 data-[disabled]:opacity-50\",\n strip: \"pointer-events-none absolute inset-0 flex overflow-hidden rounded-xl\",\n frame: \"h-full min-w-0 flex-1 object-cover\",\n shade: \"pointer-events-none absolute inset-y-0 bg-scrim-strong\",\n range: \"pointer-events-none absolute inset-y-0 border-y-[3px] border-accent\",\n handle:\n \"absolute inset-y-0 z-10 flex w-6 cursor-ew-resize items-center justify-center bg-accent text-on-accent shadow-md \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"data-[edge=start]:rounded-l-xl data-[edge=end]:-translate-x-full data-[edge=end]:rounded-r-xl\",\n grip: \"flex gap-[3px] [&>span]:h-5 [&>span]:w-[2px] [&>span]:rounded-sm [&>span]:bg-on-accent/70\",\n playhead:\n \"absolute -inset-y-1.5 z-20 w-[3px] -translate-x-1/2 cursor-ew-resize rounded-full bg-fg shadow-md \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n },\n});\n\ntype Part = keyof ReturnType<typeof videoTrimmer>;\n\nexport type VideoTrimmerLabels = {\n /** The start handle (\"Start\"). */\n start: string;\n /** The end handle (\"End\"). */\n end: string;\n /** The playhead (\"Playhead\"). */\n playhead: string;\n /** The length kept, above the track: `(length) => length + \" kept\"` (the length already formatted). */\n kept: (length: string) => string;\n};\n\nexport const videoTrimmerLabels: VideoTrimmerLabels = {\n start: \"Start\",\n end: \"End\",\n playhead: \"Playhead\",\n kept: (length) => `${length} kept`,\n};\n\nexport type VideoTrimmerProps = {\n /** The length of the clip, in seconds. */\n duration: number;\n /** The part kept, `[start, end]` in seconds (controlled). */\n value?: readonly [number, number];\n /** The part kept at first, uncontrolled. Default: the whole clip. */\n defaultValue?: readonly [number, number];\n /** Called on every move of a handle. */\n onValueChange?: (value: [number, number]) => void;\n /** Called once a drag or a key press ends: render a preview, save. */\n onValueCommit?: (value: [number, number]) => void;\n /** The time played, in seconds: shows the playhead. */\n time?: number;\n /** Called when the playhead is moved (a drag on the track, the arrows on the playhead). */\n onSeek?: (time: number) => void;\n /** The shortest part that can be kept, in seconds. Default 0.5. */\n minLength?: number;\n /** One arrow press, in seconds. Default 0.1. */\n step?: number;\n /** Shift + arrow, Page Up / Page Down, in seconds. Default 1. */\n largeStep?: number;\n /** Pictures of the clip, in order: the filmstrip. */\n frames?: readonly string[];\n /** Track content instead of the filmstrip (a waveform, a coloured band). */\n children?: React.ReactNode;\n /** A time as read and shown. Default `m:ss` with tenths. */\n formatTime?: (seconds: number) => string;\n /** Shows the times and the length kept above the track. Default `true`. */\n showHeader?: boolean;\n /** Not available (a render is running). */\n disabled?: boolean;\n /** Classes per part: `root`, `header`, `kept`, `track`, `strip`, `frame`, `shade`, `range`, `handle`, `grip`, `playhead`. */\n classNames?: Partial<Record<Part, string>>;\n /** The content of a handle (default: two grip lines). */\n renderHandle?: (edge: \"start\" | \"end\") => React.ReactNode;\n /** The words, passed translated; English by default. */\n labels?: Partial<VideoTrimmerLabels>;\n};\n\nconst tenths = (seconds: number) => `${formatClock(seconds)}.${Math.floor((Math.max(0, seconds) % 1) * 10)}`;\n\ntype Grip = \"start\" | \"end\" | \"playhead\";\n\n/** Keeps a part of a clip between two handles over its filmstrip, with a playhead to scrub — the keyboard included. */\nexport function VideoTrimmer({\n duration,\n value: valueProp,\n defaultValue,\n onValueChange,\n onValueCommit,\n time,\n onSeek,\n minLength = 0.5,\n step = 0.1,\n largeStep = 1,\n frames,\n children,\n formatTime = tenths,\n showHeader = true,\n disabled,\n classNames = {},\n renderHandle,\n labels: given,\n}: VideoTrimmerProps) {\n const labels = { ...videoTrimmerLabels, ...given };\n const s = videoTrimmer();\n const track = React.useRef<HTMLDivElement>(null);\n const grip = React.useRef<Grip | null>(null);\n const [inner, setInner] = React.useState<[number, number]>(() => [defaultValue?.[0] ?? 0, defaultValue?.[1] ?? duration]);\n const [start, end] = valueProp ?? inner;\n const total = duration > 0 ? duration : 1;\n const pct = (seconds: number) => (clamp(seconds, 0, total) / total) * 100;\n\n const set = (next: [number, number], commit = false) => {\n if (!valueProp) setInner(next);\n onValueChange?.(next);\n if (commit) onValueCommit?.(next);\n };\n const move = (edge: \"start\" | \"end\", to: number, commit = false) => {\n const next: [number, number] =\n edge === \"start\" ? [clamp(to, 0, end - minLength), end] : [start, clamp(to, start + minLength, duration)];\n set([Math.round(next[0] * 1000) / 1000, Math.round(next[1] * 1000) / 1000], commit);\n };\n const seek = (to: number) => onSeek?.(clamp(to, start, Math.max(start, end - 0.05)));\n\n const at = (clientX: number) => {\n const box = track.current?.getBoundingClientRect();\n if (!box || box.width === 0) return 0;\n return clamp(((clientX - box.left) / box.width) * duration, 0, duration);\n };\n\n const keys = (which: Grip) => (event: React.KeyboardEvent) => {\n const current = which === \"start\" ? start : which === \"end\" ? end : (time ?? start);\n const big = largeStep;\n const small = event.shiftKey ? largeStep : step;\n const target: Record<string, number> = {\n ArrowLeft: current - small,\n ArrowDown: current - small,\n ArrowRight: current + small,\n ArrowUp: current + small,\n PageDown: current - big,\n PageUp: current + big,\n Home: 0,\n End: duration,\n };\n const to = target[event.key];\n if (to === undefined || disabled) return;\n event.preventDefault();\n if (which === \"playhead\") seek(to);\n else move(which, to, true);\n };\n\n const handle = (edge: \"start\" | \"end\") => {\n const own = edge === \"start\" ? start : end;\n return (\n <div\n key={edge}\n role=\"slider\"\n tabIndex={disabled ? -1 : 0}\n aria-label={edge === \"start\" ? labels.start : labels.end}\n aria-valuemin={edge === \"start\" ? 0 : Math.round((start + minLength) * 10) / 10}\n aria-valuemax={edge === \"start\" ? Math.round((end - minLength) * 10) / 10 : Math.round(duration * 10) / 10}\n aria-valuenow={Math.round(own * 10) / 10}\n aria-valuetext={formatTime(own)}\n aria-disabled={disabled || undefined}\n data-edge={edge}\n className={s.handle({ className: classNames.handle })}\n style={{ left: `${pct(own)}%` }}\n onPointerDown={(event) => {\n if (disabled) return;\n event.stopPropagation();\n track.current?.setPointerCapture?.(event.pointerId);\n grip.current = edge;\n }}\n onKeyDown={keys(edge)}\n >\n {renderHandle ? (\n renderHandle(edge)\n ) : (\n <span className={s.grip({ className: classNames.grip })}>\n <span />\n <span />\n </span>\n )}\n </div>\n );\n };\n\n return (\n <div className={s.root({ className: classNames.root })}>\n {showHeader && (\n <div className={s.header({ className: classNames.header })}>\n <span>{formatTime(start)}</span>\n <span className={s.kept({ className: classNames.kept })}>{labels.kept(formatTime(end - start))}</span>\n <span>{formatTime(end)}</span>\n </div>\n )}\n <div\n ref={track}\n className={s.track({ className: classNames.track })}\n data-disabled={disabled ? \"\" : undefined}\n onPointerDown={(event) => {\n if (disabled) return;\n track.current?.setPointerCapture?.(event.pointerId);\n const t = at(event.clientX);\n grip.current = onSeek ? \"playhead\" : Math.abs(t - start) < Math.abs(t - end) ? \"start\" : \"end\";\n if (grip.current === \"playhead\") seek(t);\n else move(grip.current, t);\n }}\n onPointerMove={(event) => {\n if (!grip.current) return;\n const t = at(event.clientX);\n if (grip.current === \"playhead\") seek(t);\n else move(grip.current, t);\n }}\n onPointerUp={() => {\n if (grip.current && grip.current !== \"playhead\") onValueCommit?.([start, end]);\n grip.current = null;\n }}\n onPointerCancel={() => {\n grip.current = null;\n }}\n >\n <div className={s.strip({ className: classNames.strip })}>\n {children ?? frames?.map((src, i) => <img key={`${i}-${src}`} src={src} alt=\"\" draggable={false} className={s.frame({ className: classNames.frame })} />)}\n </div>\n <div className={s.shade({ className: classNames.shade })} style={{ left: 0, width: `${pct(start)}%`, borderRadius: \"0.75rem 0 0 0.75rem\" }} />\n <div className={s.shade({ className: classNames.shade })} style={{ right: 0, width: `${100 - pct(end)}%`, borderRadius: \"0 0.75rem 0.75rem 0\" }} />\n <div className={s.range({ className: classNames.range })} style={{ left: `${pct(start)}%`, right: `${100 - pct(end)}%` }} />\n {time !== undefined && (\n <div\n role=\"slider\"\n tabIndex={disabled || !onSeek ? -1 : 0}\n aria-label={labels.playhead}\n aria-valuemin={Math.round(start * 10) / 10}\n aria-valuemax={Math.round(end * 10) / 10}\n aria-valuenow={Math.round(time * 10) / 10}\n aria-valuetext={formatTime(time)}\n aria-readonly={!onSeek || undefined}\n className={s.playhead({ className: classNames.playhead })}\n style={{ left: `${pct(time)}%` }}\n onKeyDown={onSeek ? keys(\"playhead\") : undefined}\n />\n )}\n {handle(\"start\")}\n {handle(\"end\")}\n </div>\n </div>\n );\n}\n"
254
+ "content": "// Client. The trim timeline of a video editor: the clip as a filmstrip (or any track content), the part kept framed\n// between two edge handles — each a `slider` named by a prop, its value read as a time, never past the other one —\n// the outside dimmed, and a playhead to scrub. The handles sit on their value by their outer edge (the start handle\n// to the right of its value, the end handle to its left), so the frame encloses exactly what is kept. Every part\n// takes its own classes (`classNames`) and the handles their own content (`renderHandle`).\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { clamp, formatClock } from \"../media\";\n\nexport const videoTrimmer = tv({\n slots: {\n root: \"w-full select-none\",\n header: \"mb-2 flex items-center justify-between font-mono text-[11px] tabular-nums text-fg-secondary\",\n kept: \"rounded-sm bg-accent-soft px-2.5 py-0.5 font-sans text-xs font-semibold text-fg\",\n track: \"relative h-16 touch-none rounded-xl bg-surface-2 data-[disabled]:opacity-50\",\n strip: \"pointer-events-none absolute inset-0 flex overflow-hidden rounded-xl\",\n frame: \"h-full min-w-0 flex-1 object-cover\",\n shade: \"pointer-events-none absolute inset-y-0 bg-scrim-strong\",\n range: \"pointer-events-none absolute inset-y-0 border-y-[3px] border-accent\",\n handle:\n \"absolute inset-y-0 z-10 flex w-6 cursor-ew-resize items-center justify-center bg-accent text-on-accent shadow-md \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"data-[edge=start]:rounded-l-xl data-[edge=end]:-translate-x-full data-[edge=end]:rounded-r-xl\",\n grip: \"flex gap-[3px] [&>span]:h-5 [&>span]:w-[2px] [&>span]:rounded-sm [&>span]:bg-on-accent/70\",\n playhead:\n \"absolute -inset-y-1.5 z-20 w-[3px] -translate-x-1/2 cursor-ew-resize rounded-full bg-fg shadow-md \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n },\n});\n\ntype Part = keyof ReturnType<typeof videoTrimmer>;\n\nexport type VideoTrimmerLabels = {\n /** The start handle (\"Start\"). */\n start: string;\n /** The end handle (\"End\"). */\n end: string;\n /** The playhead (\"Playhead\"). */\n playhead: string;\n /** The length kept, above the track: `(length) => length + \" kept\"` (the length already formatted). */\n kept: (length: string) => string;\n};\n\nexport const videoTrimmerLabels: VideoTrimmerLabels = {\n start: \"Start\",\n end: \"End\",\n playhead: \"Playhead\",\n kept: (length) => `${length} kept`,\n};\n\nexport type VideoTrimmerProps = {\n /** The length of the clip, in seconds. */\n duration: number;\n /** The part kept, `[start, end]` in seconds (controlled). */\n value?: readonly [number, number];\n /** The part kept at first, uncontrolled. Default: the whole clip. */\n defaultValue?: readonly [number, number];\n /** Called on every move of a handle. */\n onValueChange?: (value: [number, number]) => void;\n /** Called once a drag or a key press ends: render a preview, save. */\n onValueCommit?: (value: [number, number]) => void;\n /** The time played, in seconds: shows the playhead. */\n time?: number;\n /** Called when the playhead is moved (a drag on the track, the arrows on the playhead). */\n onSeek?: (time: number) => void;\n /** The shortest part that can be kept, in seconds. Default 0.5. */\n minLength?: number;\n /** One arrow press, in seconds. Default 0.1. */\n step?: number;\n /** Shift + arrow, Page Up / Page Down, in seconds. Default 1. */\n largeStep?: number;\n /** Pictures of the clip, in order: the filmstrip. */\n frames?: readonly string[];\n /** Track content instead of the filmstrip (a waveform, a coloured band). */\n children?: React.ReactNode;\n /** A time as read and shown. Default `m:ss` with tenths. */\n formatTime?: (seconds: number) => string;\n /** Shows the times and the length kept above the track. Default `true`. */\n showHeader?: boolean;\n /** Not available (a render is running). */\n disabled?: boolean;\n /** Classes per part: `root`, `header`, `kept`, `track`, `strip`, `frame`, `shade`, `range`, `handle`, `grip`, `playhead`. */\n classNames?: Partial<Record<Part, string>>;\n /** The content of a handle (default: two grip lines). */\n renderHandle?: (edge: \"start\" | \"end\") => React.ReactNode;\n /** The words, passed translated; English by default. */\n labels?: Partial<VideoTrimmerLabels>;\n};\n\nconst tenths = (seconds: number) => `${formatClock(seconds)}.${Math.floor((Math.max(0, seconds) % 1) * 10)}`;\n\ntype Grip = \"start\" | \"end\" | \"playhead\";\n\n/** Keeps a part of a clip between two handles over its filmstrip, with a playhead to scrub — the keyboard included. */\nexport function VideoTrimmer({\n duration,\n value: valueProp,\n defaultValue,\n onValueChange,\n onValueCommit,\n time,\n onSeek,\n minLength = 0.5,\n step = 0.1,\n largeStep = 1,\n frames,\n children,\n formatTime = tenths,\n showHeader = true,\n disabled,\n classNames = {},\n renderHandle,\n labels: given,\n}: VideoTrimmerProps) {\n const labels = { ...videoTrimmerLabels, ...given };\n const s = videoTrimmer();\n const track = React.useRef<HTMLDivElement>(null);\n const grip = React.useRef<Grip | null>(null);\n const [inner, setInner] = React.useState<[number, number]>(() => [defaultValue?.[0] ?? 0, defaultValue?.[1] ?? duration]);\n const [start, end] = valueProp ?? inner;\n const total = duration > 0 ? duration : 1;\n const pct = (seconds: number) => (clamp(seconds, 0, total) / total) * 100;\n\n const set = (next: [number, number], commit = false) => {\n if (!valueProp) setInner(next);\n onValueChange?.(next);\n if (commit) onValueCommit?.(next);\n };\n const move = (edge: \"start\" | \"end\", to: number, commit = false) => {\n const next: [number, number] =\n edge === \"start\" ? [clamp(to, 0, end - minLength), end] : [start, clamp(to, start + minLength, duration)];\n set([Math.round(next[0] * 1000) / 1000, Math.round(next[1] * 1000) / 1000], commit);\n };\n const seek = (to: number) => onSeek?.(clamp(to, start, Math.max(start, end - 0.05)));\n\n const at = (clientX: number) => {\n const box = track.current?.getBoundingClientRect();\n if (!box || box.width === 0) return 0;\n return clamp(((clientX - box.left) / box.width) * duration, 0, duration);\n };\n\n const keys = (which: Grip) => (event: React.KeyboardEvent) => {\n const current = which === \"start\" ? start : which === \"end\" ? end : (time ?? start);\n const big = largeStep;\n const small = event.shiftKey ? largeStep : step;\n const target: Record<string, number> = {\n ArrowLeft: current - small,\n ArrowDown: current - small,\n ArrowRight: current + small,\n ArrowUp: current + small,\n PageDown: current - big,\n PageUp: current + big,\n Home: 0,\n End: duration,\n };\n const to = target[event.key];\n if (to === undefined || disabled) return;\n event.preventDefault();\n if (which === \"playhead\") seek(to);\n else move(which, to, true);\n };\n\n const handle = (edge: \"start\" | \"end\") => {\n const own = edge === \"start\" ? start : end;\n return (\n <div\n key={edge}\n role=\"slider\"\n tabIndex={disabled ? -1 : 0}\n aria-label={edge === \"start\" ? labels.start : labels.end}\n aria-valuemin={edge === \"start\" ? 0 : Math.round((start + minLength) * 10) / 10}\n aria-valuemax={edge === \"start\" ? Math.round((end - minLength) * 10) / 10 : Math.round(duration * 10) / 10}\n aria-valuenow={Math.round(own * 10) / 10}\n aria-valuetext={formatTime(own)}\n aria-disabled={disabled || undefined}\n data-edge={edge}\n className={s.handle({ className: classNames.handle })}\n style={{ left: `${pct(own)}%` }}\n onPointerDown={(event) => {\n if (disabled) return;\n event.stopPropagation();\n track.current?.setPointerCapture?.(event.pointerId);\n grip.current = edge;\n }}\n onKeyDown={keys(edge)}\n >\n {renderHandle ? (\n renderHandle(edge)\n ) : (\n <span className={s.grip({ className: classNames.grip })}>\n <span />\n <span />\n </span>\n )}\n </div>\n );\n };\n\n return (\n <div className={s.root({ className: classNames.root })}>\n {showHeader && (\n <div className={s.header({ className: classNames.header })}>\n <span>{formatTime(start)}</span>\n <span className={s.kept({ className: classNames.kept })}>{labels.kept(formatTime(end - start))}</span>\n <span>{formatTime(end)}</span>\n </div>\n )}\n <div\n ref={track}\n className={s.track({ className: classNames.track })}\n data-disabled={disabled ? \"\" : undefined}\n onPointerDown={(event) => {\n if (disabled) return;\n track.current?.setPointerCapture?.(event.pointerId);\n const t = at(event.clientX);\n grip.current = onSeek ? \"playhead\" : Math.abs(t - start) < Math.abs(t - end) ? \"start\" : \"end\";\n if (grip.current === \"playhead\") seek(t);\n else move(grip.current, t);\n }}\n onPointerMove={(event) => {\n if (!grip.current) return;\n const t = at(event.clientX);\n if (grip.current === \"playhead\") seek(t);\n else move(grip.current, t);\n }}\n onPointerUp={() => {\n if (grip.current && grip.current !== \"playhead\") onValueCommit?.([start, end]);\n grip.current = null;\n }}\n onPointerCancel={() => {\n grip.current = null;\n }}\n >\n <div className={s.strip({ className: classNames.strip })}>\n {children ?? frames?.map((src, i) => <img key={`${i}-${src}`} src={src} alt=\"\" draggable={false} className={s.frame({ className: classNames.frame })} />)}\n </div>\n <div className={s.shade({ className: classNames.shade })} style={{ left: 0, width: `${pct(start)}%`, borderRadius: \"0.75rem 0 0 0.75rem\" }} />\n <div className={s.shade({ className: classNames.shade })} style={{ right: 0, width: `${100 - pct(end)}%`, borderRadius: \"0 0.75rem 0.75rem 0\" }} />\n <div className={s.range({ className: classNames.range })} style={{ left: `${pct(start)}%`, right: `${100 - pct(end)}%` }} />\n {time !== undefined && (\n <div\n role=\"slider\"\n tabIndex={disabled || !onSeek ? -1 : 0}\n aria-label={labels.playhead}\n aria-valuemin={Math.round(start * 10) / 10}\n aria-valuemax={Math.round(end * 10) / 10}\n aria-valuenow={Math.round(time * 10) / 10}\n aria-valuetext={formatTime(time)}\n aria-readonly={!onSeek || undefined}\n className={s.playhead({ className: classNames.playhead })}\n style={{ left: `${pct(time)}%` }}\n onKeyDown={onSeek ? keys(\"playhead\") : undefined}\n />\n )}\n {handle(\"start\")}\n {handle(\"end\")}\n </div>\n </div>\n );\n}\n"
255
255
  }
256
256
  ],
257
257
  "dependencies": [
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/chip-link/chip-link.tsx"],"sourcesContent":["// Server-safe: no hook, no context. A chip that is a link — a filter that is an address (`/explore?tag=night`): the look\n// of `Chip`, the current filter marked by `selected` (`aria-current`, the accent), usable in a Server Component.\n// `chipVariants` styles anything else (a router link you render yourself).\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const chipVariants = tv({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-full border font-semibold no-underline transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n variants: {\n size: { sm: \"h-7 px-3 text-xs\", md: \"h-9 px-3.5 text-xs\" },\n selected: {\n false: \"border-border-default bg-surface-1 text-fg-secondary hover:border-border-strong hover:text-fg\",\n true: \"border-accent bg-accent-soft text-fg\",\n },\n },\n defaultVariants: { size: \"md\", selected: false },\n});\n\nexport type ChipVariantsProps = VariantProps<typeof chipVariants>;\n\nexport type ChipLinkProps = React.ComponentProps<\"a\"> & {\n /**\n * sm · md.\n * @default \"md\"\n */\n size?: ChipVariantsProps[\"size\"];\n /** The current filter: the accent, `aria-current` (`page` by default) and `data-state=\"on\"`. */\n selected?: boolean;\n /**\n * What `aria-current` says when selected: `page` (a filter that is a page) or `true`.\n * @default \"page\"\n */\n current?: \"page\" | \"true\";\n /** Renders your router's `<Link>` with the chip's look. */\n asChild?: boolean;\n};\n\n/** A filter that is a link, with the look of `Chip`. */\nexport function ChipLink({ size, selected = false, current = \"page\", asChild, className, ...props }: ChipLinkProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return (\n <Comp\n data-state={selected ? \"on\" : \"off\"}\n aria-current={selected ? current : undefined}\n className={chipVariants({ size, selected, className })}\n {...props}\n />\n );\n}\n"],"mappings":";AAGA,SAAS,YAAY;AAErB,SAAS,UAA6B;AAuClC;AArCG,IAAM,eAAe,GAAG;AAAA,EAC7B,MACE;AAAA,EAEF,UAAU;AAAA,IACR,MAAM,EAAE,IAAI,oBAAoB,IAAI,qBAAqB;AAAA,IACzD,UAAU;AAAA,MACR,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,MAAM,MAAM,UAAU,MAAM;AACjD,CAAC;AAsBM,SAAS,SAAS,EAAE,MAAM,WAAW,OAAO,UAAU,QAAQ,SAAS,WAAW,GAAG,MAAM,GAAkB;AAClH,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAY,WAAW,OAAO;AAAA,MAC9B,gBAAc,WAAW,UAAU;AAAA,MACnC,WAAW,aAAa,EAAE,MAAM,UAAU,UAAU,CAAC;AAAA,MACpD,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/family-mark.tsx","../src/sites/sites.ts"],"sourcesContent":["// The mark of a site of the family (`@krizaka/ui/sites`): its brand's `ProductLogo`, still (a list of marks never\n// moves), or GitHub's, in the text colour. Shared by `NavBar.Family` and `SiteFooter` — not an entry of its own.\nimport type * as React from \"react\";\n\nimport { ProductLogo } from \"./marks/ProductLogo\";\nimport type { SiteMark } from \"./sites/sites\";\n\n/** GitHub's mark, in the text colour (both themes). */\nexport function GitHubGlyph({ size = 16, className }: { size?: number; className?: string }) {\n return (\n <svg viewBox=\"0 0 16 16\" width={size} height={size} fill=\"currentColor\" aria-hidden className={className}>\n <path d=\"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8Z\" />\n </svg>\n );\n}\n\n/** A site's mark, decorative (its name is always written beside it). */\nexport function FamilyMark({ mark, size }: { mark: SiteMark; size: number }): React.ReactElement {\n if (mark === \"github\") return <GitHubGlyph size={Math.round(size * 0.8)} />;\n return <ProductLogo id={mark} size={size} animated={false} />;\n}\n","// Server-safe: plain data. The Krizaka family — every site Krizaka runs, once. The family switcher of the bar\n// (`NavBar.Family`) and the common footer (`SiteFooter`) both read it, so adding a site is one release of this package:\n// every bar and every footer of the family follow.\n//\n// The words of the family (a site's one line, the groups, the statuses, the footer's signature) are brand data, written\n// here in English and French (`familyLabels`) — a site passes the set of its locale, or its own translation.\n\n/** A site of the family. */\nexport type SiteId = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\" | \"ui\" | \"java\" | \"motion\" | \"github\";\n\n/** What a site is: the company, a product, or an open-source project. It chooses the footer's signature line. */\nexport type SiteKind = \"company\" | \"product\" | \"open-source\";\n\n/**\n * `released`: open to visit. `upcoming`: announced, not released yet (said \"Coming soon\"). `construction`: under\n * construction — nothing offered (a QA-only app may run; the public page says so). `development`: being built in the\n * open, with a dev site (said \"In development\"). A site with none yet would use its repository as its address.\n */\nexport type SiteStatus = \"released\" | \"upcoming\" | \"construction\" | \"development\";\n\n/** The groups of the family, in reading order: Krizaka · Products · Open source · GitHub. */\nexport type SiteGroup = \"krizaka\" | \"products\" | \"open-source\" | \"github\";\n\n/** The mark a site wears: a brand of `ProductLogo` (Krizaka UI and Krizaka Java wear Krizaka's), or GitHub's. */\nexport type SiteMark = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\" | \"github\";\n\nexport interface Site {\n readonly id: SiteId;\n /** The name, never translated. */\n readonly name: string;\n /** The address of the site (its home). */\n readonly url: string;\n /** The address without the scheme, as people say it (`ui.krizaka.com`). */\n readonly host: string;\n readonly kind: SiteKind;\n readonly group: SiteGroup;\n readonly status: SiteStatus;\n readonly mark: SiteMark;\n /** The repository the site is built from. */\n readonly repo: string;\n}\n\nconst site = (s: Omit<Site, \"host\">): Site => ({ ...s, host: s.url.replace(/^https?:\\/\\//, \"\").replace(/\\/$/, \"\") });\n\n/** Every site of the family, in reading order (the group order, then the order inside each group). */\nexport const sites: readonly Site[] = [\n site({ id: \"krizaka\", name: \"Krizaka\", url: \"https://www.krizaka.com\", kind: \"company\", group: \"krizaka\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-com\" }),\n site({ id: \"orazaka\", name: \"Orazaka\", url: \"https://dev.orazaka.com\", kind: \"product\", group: \"products\", status: \"released\", mark: \"orazaka\", repo: \"https://github.com/krizaka/orazaka\" }),\n site({ id: \"orochia\", name: \"Orochia\", url: \"https://dev.orochia.com\", kind: \"product\", group: \"products\", status: \"released\", mark: \"orochia\", repo: \"https://github.com/krizaka/orochia\" }),\n site({ id: \"yasakia\", name: \"Yasakia\", url: \"https://dev.yasakia.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"yasakia\", repo: \"https://github.com/krizaka/yasakia\" }),\n site({ id: \"yororis\", name: \"Yororis\", url: \"https://dev.yororis.com\", kind: \"product\", group: \"products\", status: \"construction\", mark: \"yororis\", repo: \"https://github.com/krizaka/yororis\" }),\n site({ id: \"yomizaka\", name: \"Yomizaka\", url: \"https://dev.yomizaka.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"yomizaka\", repo: \"https://github.com/krizaka/yomizaka\" }),\n site({ id: \"kachizaka\", name: \"Kachizaka\", url: \"https://dev.kachizaka.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"kachizaka\", repo: \"https://github.com/krizaka/kachizaka\" }),\n site({ id: \"akinaza\", name: \"Akinaza\", url: \"https://dev.akinaza.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"akinaza\", repo: \"https://github.com/krizaka/akinaza\" }),\n site({ id: \"ui\", name: \"Krizaka UI\", url: \"https://ui.krizaka.com\", kind: \"open-source\", group: \"open-source\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-ui\" }),\n site({ id: \"java\", name: \"Krizaka Java\", url: \"https://java.krizaka.com\", kind: \"open-source\", group: \"open-source\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-build\" }),\n // The motion lab: built in the open on GitHub Pages; what proves itself there moves into Krizaka UI.\n site({ id: \"motion\", name: \"Krizaka Motion\", url: \"https://krizaka.github.io/krizaka-motion\", kind: \"open-source\", group: \"open-source\", status: \"development\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-motion\" }),\n site({ id: \"github\", name: \"GitHub\", url: \"https://github.com/krizaka\", kind: \"open-source\", group: \"github\", status: \"released\", mark: \"github\", repo: \"https://github.com/krizaka\" }),\n];\n\n/** The groups, in reading order. */\nexport const siteGroups: readonly SiteGroup[] = [\"krizaka\", \"products\", \"open-source\", \"github\"];\n\n/** A site by id. */\nexport function siteById(id: SiteId): Site {\n const found = sites.find((s) => s.id === id);\n if (!found) throw new Error(`Unknown Krizaka site \"${id}\".`);\n return found;\n}\n\n/** The family grouped, in reading order: `[{ group, sites }]`, empty groups left out. */\nexport function sitesByGroup(): { group: SiteGroup; sites: Site[] }[] {\n return siteGroups.map((group) => ({ group, sites: sites.filter((s) => s.group === group) })).filter((g) => g.sites.length > 0);\n}\n\n/** The languages the family's words are written in. */\nexport type SiteLocale = \"en\" | \"fr\";\n\n/** The words of the family: the switcher, the footer, each site's one line. */\nexport interface FamilyLabels {\n /** The family's name: the switcher's navigation and its button, the footer's navigation (“Krizaka family”). */\n family: string;\n /** The heading of each group. */\n groups: Record<SiteGroup, string>;\n /** The badge of a site that is not released. */\n status: Record<Exclude<SiteStatus, \"released\">, string>;\n /** Says which site is the current one (“You are here”). */\n current: string;\n /** One line per site: what it is. */\n descriptions: Record<SiteId, string>;\n /** The footer's signature, by the kind of the current site (“A Krizaka product”). */\n signature: Record<SiteKind, string>;\n /** The footer's place line (“Made in Montréal”). */\n place: string;\n /** The accessible name of the version (“Version”). */\n version: string;\n}\n\n/** The family's words in English and French. Pass `familyLabels[locale]`, or your own translation of the same shape. */\nexport const familyLabels: Record<SiteLocale, FamilyLabels> = {\n en: {\n family: \"Krizaka family\",\n groups: { krizaka: \"Krizaka\", products: \"Products\", \"open-source\": \"Open source\", github: \"GitHub\" },\n status: { upcoming: \"Coming soon\", construction: \"Under construction\", development: \"In development\" },\n current: \"You are here\",\n descriptions: {\n krizaka: \"The company: our products, our open source, our story.\",\n orazaka: \"Sovereign AI on your own servers: chat, documents, images and video — and the engine under the other products.\",\n orochia: \"A video platform for creators.\",\n yasakia: \"Meet real people: introductions, and photos checked before you see them.\",\n yororis: \"A listening space with a face and a voice.\",\n yomizaka: \"Yomizaka reads your leases, contracts and invoices.\",\n kachizaka: \"Predictions among friends — live data, in real time.\",\n akinaza: \"Running a shop in Québec, for less — Loi 25 by design.\",\n ui: \"Components, tokens, icons and charts — web and React Native.\",\n java: \"Spring Boot building blocks on Maven Central.\",\n motion: \"The motion lab: the kit's motion, played live with its knobs.\",\n github: \"Every repository, in the open.\",\n },\n signature: { company: \"A Krizaka company\", product: \"A Krizaka product\", \"open-source\": \"A Krizaka open-source project\" },\n place: \"Made in Montréal\",\n version: \"Version\",\n },\n fr: {\n family: \"Famille Krizaka\",\n groups: { krizaka: \"Krizaka\", products: \"Produits\", \"open-source\": \"Open source\", github: \"GitHub\" },\n status: { upcoming: \"Bientôt\", construction: \"En construction\", development: \"En développement\" },\n current: \"Vous êtes ici\",\n descriptions: {\n krizaka: \"La compagnie : nos produits, notre open source, notre histoire.\",\n orazaka: \"L’IA souveraine sur vos propres serveurs : conversation, documents, images et vidéo — et le moteur des autres produits.\",\n orochia: \"Une plateforme vidéo pour les créateurs.\",\n yasakia: \"Rencontrez de vraies personnes : des présentations, et des photos vérifiées avant que vous les voyiez.\",\n yororis: \"Un espace d’écoute avec un visage et une voix.\",\n yomizaka: \"Yomizaka lit vos baux, contrats et factures.\",\n kachizaka: \"Les pronostics entre amis — des données en direct.\",\n akinaza: \"Tenir une boutique au Québec, pour moins cher — Loi 25 dès la conception.\",\n ui: \"Composants, jetons, icônes et graphiques — web et React Native.\",\n java: \"Des briques Spring Boot sur Maven Central.\",\n motion: \"Le labo du mouvement : le mouvement du kit, joué en direct, avec ses réglages.\",\n github: \"Tous les dépôts, au grand jour.\",\n },\n signature: { company: \"Une compagnie Krizaka\", product: \"Un produit Krizaka\", \"open-source\": \"Un projet open source de Krizaka\" },\n place: \"Fait à Montréal\",\n version: \"Version\",\n },\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/slider/slider.tsx"],"sourcesContent":["// Client. Radix Slider: role=\"slider\" on each thumb, arrows / Page Up / Page Down / Home / End, a range with two\n// thumbs, horizontal or vertical. The words arrive as props: `label` names the thumb(s), `formatValue` gives the\n// aria-valuetext and the value shown (above the track, or floating over the thumb while it is touched). `ticks` draws the\n// graduations of the steps (and `marks` their words under the track); `tone` fills with the brand's gradient or its\n// accent alone.\nimport { Slider as SliderPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { tv } from \"../tv\";\n\nexport const slider = tv({\n slots: {\n root: \"flex flex-col gap-2 data-[orientation=vertical]:h-full data-[orientation=vertical]:items-center\",\n header: \"flex items-baseline justify-between gap-3 text-xs font-semibold text-fg-secondary\",\n value: \"font-mono text-[11px] tabular-nums text-fg-secondary\",\n control:\n \"relative flex touch-none select-none items-center data-disabled:cursor-not-allowed data-disabled:opacity-40 \" +\n \"data-[orientation=horizontal]:h-6 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-40 data-[orientation=vertical]:w-6 data-[orientation=vertical]:flex-col\",\n track:\n \"relative grow overflow-hidden rounded-full bg-surface-3 inset-shadow-well \" +\n \"data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5\",\n range: \"absolute rounded-full data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full\",\n thumb:\n \"group/thumb relative block h-5 w-5 cursor-grab rounded-full border-2 border-accent bg-fg-on-media shadow-raised transition-[box-shadow,scale] duration-150 \" +\n \"hover:ring-4 hover:ring-accent/15 focus-visible:outline-hidden focus-visible:focus-ring active:scale-110 active:cursor-grabbing motion-reduce:transition-none motion-reduce:active:scale-100\",\n // The value over the thumb: shown while the thumb is hovered, focused or held.\n bubble:\n \"pointer-events-none absolute bottom-full left-1/2 mb-2.5 -translate-x-1/2 whitespace-nowrap rounded-lg bg-fg px-2 py-1 font-mono text-[11px] font-semibold tabular-nums text-surface-0 opacity-0 shadow-floating \" +\n \"transition-opacity duration-150 after:absolute after:left-1/2 after:top-full after:-translate-x-1/2 after:border-4 after:border-transparent after:border-t-fg \" +\n \"group-hover/thumb:opacity-100 group-focus-visible/thumb:opacity-100 group-active/thumb:opacity-100 data-[always]:opacity-100 motion-reduce:transition-none\",\n bubbleVertical: \"bottom-auto left-full top-1/2 mb-0 ml-3 -translate-x-0 -translate-y-1/2 after:hidden\",\n ticks: \"pointer-events-none absolute inset-0\",\n tick: \"absolute rounded-full bg-border-strong data-[on]:bg-on-accent/70 data-[orientation=horizontal]:top-1/2 data-[orientation=horizontal]:h-1 data-[orientation=horizontal]:w-px data-[orientation=horizontal]:-translate-x-1/2 data-[orientation=horizontal]:-translate-y-1/2 data-[orientation=vertical]:left-1/2 data-[orientation=vertical]:h-px data-[orientation=vertical]:w-1 data-[orientation=vertical]:-translate-x-1/2 data-[orientation=vertical]:translate-y-1/2\",\n marks: \"relative h-4 w-full text-[11px] font-medium tabular-nums text-fg-secondary\",\n mark: \"absolute top-0 -translate-x-1/2 whitespace-nowrap first:translate-x-0 last:-translate-x-full\",\n },\n variants: {\n tone: {\n /** The brand's signature: accent → accent-2, a glow under it. */\n gradient: { range: \"bg-linear-to-r from-accent to-accent-2 shadow-glow data-[orientation=vertical]:bg-linear-to-t\" },\n /** The accent alone. */\n solid: { range: \"bg-accent\" },\n },\n size: {\n md: {},\n lg: {\n track: \"data-[orientation=horizontal]:h-2.5 data-[orientation=vertical]:w-2.5\",\n thumb: \"h-6 w-6\",\n control: \"data-[orientation=horizontal]:h-8 data-[orientation=vertical]:w-8\",\n },\n },\n },\n defaultVariants: { tone: \"gradient\", size: \"md\" },\n});\n\nexport type SliderValue = number | [number, number];\n\nexport type SliderMark = {\n /** Where the mark stands. */\n value: number;\n /** Its words under the track (\"0\", \"50 %\", \"Max\"), passed translated. */\n label: string;\n};\n\nexport type SliderProps<V extends SliderValue = number> = Omit<\n React.ComponentProps<typeof SliderPrimitive.Root>,\n \"value\" | \"defaultValue\" | \"onValueChange\" | \"onValueCommit\" | \"children\"\n> & {\n /** One number (a thumb) or two (a range). Controlled with `onValueChange`. */\n value?: V;\n /** The value at first, uncontrolled: one number, or two for a range. */\n defaultValue?: V;\n /** Called on every move, with one number or two. */\n onValueChange?: (value: V) => void;\n /** Called once the drag or the key press ends. */\n onValueCommit?: (value: V) => void;\n /** The accessible name — of the thumb, or of both thumbs of a range — passed translated. */\n label: string;\n /** For a range: each thumb's own name ([\"Minimum\", \"Maximum\"]), passed translated. */\n thumbLabels?: [string, string];\n /** The value as words (aria-valuetext) and as shown: \"1.5×\", \"−12 %\", \"3 min\". */\n formatValue?: (value: number) => string;\n /** Shows the label and the value above the track. Without it, `label` only names the thumb. */\n showLabel?: boolean;\n /** Shows the value floating over the thumb while it is hovered, focused or held (`\"always\"`: at all times). */\n floatingValue?: boolean | \"always\";\n /** Fills from this value instead of the minimum (a ±range from 0: brightness, balance). One horizontal thumb only. */\n origin?: number;\n /** Draws a graduation at every step (`true`, up to 40 of them) or at the values given. */\n ticks?: boolean | readonly number[];\n /** Words under the track at some values (`[{ value: 0, label: \"0\" }, { value: 100, label: \"100\" }]`). Horizontal only. */\n marks?: readonly SliderMark[];\n /**\n * `gradient` (the brand's accent → accent-2, a glow) or `solid` (the accent alone).\n * @default \"gradient\"\n */\n tone?: \"gradient\" | \"solid\";\n /**\n * md · lg (a thicker track and thumb: a hero control, a touch screen).\n * @default \"md\"\n */\n size?: \"md\" | \"lg\";\n};\n\nconst toArray = (v: SliderValue | undefined) => (v === undefined ? undefined : typeof v === \"number\" ? [v] : v);\n\n/** A slider on one value or a range: `value`/`defaultValue` + `onValueChange`, `min`, `max`, `step`, `orientation`. */\nexport function Slider<V extends SliderValue = number>({\n value,\n defaultValue,\n onValueChange,\n onValueCommit,\n label,\n thumbLabels,\n formatValue = String,\n showLabel,\n floatingValue,\n origin,\n ticks,\n marks,\n tone,\n size,\n min = 0,\n max = 100,\n step = 1,\n orientation = \"horizontal\",\n className,\n ...props\n}: SliderProps<V>) {\n const s = slider({ tone, size });\n const range = Array.isArray(value ?? defaultValue);\n const vertical = orientation === \"vertical\";\n const [inner, setInner] = React.useState(() => toArray(defaultValue) ?? [min]);\n const current = toArray(value) ?? inner;\n const out = (next: number[]) => (range ? next : next[0]) as V;\n const pct = (v: number) => ((v - min) / (max - min || 1)) * 100;\n const fill =\n origin !== undefined && !range && !vertical\n ? { left: `${Math.min(pct(origin), pct(current[0]!))}%`, right: `${100 - Math.max(pct(origin), pct(current[0]!))}%` }\n : undefined;\n const lo = range ? Math.min(...current) : (origin ?? min);\n const hi = range ? Math.max(...current) : current[0]!;\n const tickValues = ticks === true ? (max - min) / step <= 40 ? Array.from({ length: Math.round((max - min) / step) + 1 }, (_, i) => min + i * step) : [] : ticks ? [...ticks] : [];\n const id = React.useId();\n return (\n <div className={s.root({ className })} data-range={range ? \"\" : undefined} data-orientation={orientation}>\n {showLabel && (\n <div className={s.header()}>\n <span id={`${id}-label`}>{label}</span>\n <span className={s.value()} aria-hidden>\n {current.map(formatValue).join(\" – \")}\n </span>\n </div>\n )}\n <SliderPrimitive.Root\n min={min}\n max={max}\n step={step}\n orientation={orientation}\n value={current}\n onValueChange={(next) => {\n if (value === undefined) setInner(next);\n onValueChange?.(out(next));\n }}\n onValueCommit={onValueCommit && ((next) => onValueCommit(out(next)))}\n className={s.control()}\n {...props}\n >\n <SliderPrimitive.Track className={s.track()}>\n {fill ? <span data-origin=\"\" data-orientation={orientation} className={s.range()} style={fill} /> : <SliderPrimitive.Range className={s.range()} />}\n {tickValues.length ? (\n <span aria-hidden className={s.ticks()}>\n {tickValues.map((t) => (\n <span\n key={t}\n data-orientation={orientation}\n data-on={t > lo && t < hi ? \"\" : undefined}\n className={s.tick()}\n style={vertical ? { bottom: `${pct(t)}%` } : { left: `${pct(t)}%` }}\n />\n ))}\n </span>\n ) : null}\n </SliderPrimitive.Track>\n {current.map((v, i) => (\n <SliderPrimitive.Thumb\n key={i}\n aria-label={range ? (thumbLabels?.[i] ?? label) : showLabel ? undefined : label}\n aria-labelledby={!range && showLabel ? `${id}-label` : undefined}\n aria-valuetext={formatValue(v)}\n className={s.thumb()}\n >\n {floatingValue ? (\n <span aria-hidden data-always={floatingValue === \"always\" ? \"\" : undefined} className={s.bubble({ className: vertical ? s.bubbleVertical() : undefined })}>\n {formatValue(v)}\n </span>\n ) : null}\n </SliderPrimitive.Thumb>\n ))}\n </SliderPrimitive.Root>\n {marks?.length && !vertical ? (\n <div aria-hidden className={s.marks()}>\n {marks.map((m) => (\n <span key={m.value} className={s.mark()} style={{ left: `${pct(m.value)}%` }}>\n {m.label}\n </span>\n ))}\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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","names":[]}