@5voltfx/design-system 0.2.0 → 0.3.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/DialNav/DialNav.jsx","../src/components/DialNav/geometry.js","../src/components/DialNav/variants/Volvelle.jsx","../src/components/DialNav/variants/Concentric.jsx","../src/components/DialNav/variants/RatchetFan.jsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { NavLink } from \"react-router-dom\";\nimport { useDetentTravel } from \"../_shared/useDetentTravel.js\";\nimport { validateStationCount } from \"../_shared/validateStationCount.js\";\nimport { useReducedMotion } from \"../_shared/useReducedMotion.js\";\nimport {\n DIAL,\n pitchFor,\n stationAngle,\n rotationFor,\n uprightFlip,\n} from \"./geometry.js\";\nimport { Volvelle } from \"./variants/Volvelle.jsx\";\nimport { Concentric } from \"./variants/Concentric.jsx\";\nimport { RatchetFan } from \"./variants/RatchetFan.jsx\";\nimport \"./DialNav.css\";\n\n/**\n * @typedef {object} DialItem\n * @property {string} id\n * @property {import(\"react\").ReactNode} label\n * @property {string} [to] - Route path. Renders a NavLink; requires a Router.\n * @property {boolean} [end]\n * @property {() => void} [onSelect]\n */\n\n/**\n * Per-variant label placement.\n *\n * `railRotation` turns the whole rail; `flipOf` turns one label about its own\n * centre. C-I spins its rail under a fixed index. C-III holds its spokes still\n * and sweeps a pawl instead, righting only the indexed label. C-II is\n * two-level and lays out both of its rails itself.\n */\nconst VARIANTS = {\n volvelle: {\n spec: DIAL.volvelle,\n render: Volvelle,\n layout: (spec, count, pos) => {\n const theta = rotationFor(spec, count, pos);\n return {\n railRotation: theta,\n angleOf: (i) => stationAngle(spec, count, i),\n flipOf: (i) =>\n uprightFlip(stationAngle(spec, count, i) + theta) ? 180 : 0,\n };\n },\n },\n concentric: {\n spec: DIAL.concentric,\n render: Concentric,\n ownsStations: true,\n twoLevel: true,\n layout: (spec, count, pos) => ({\n railRotation: -(pos * (360 / Math.max(1, count))),\n angleOf: () => 0,\n flipOf: () => 0,\n }),\n },\n fan: {\n spec: DIAL.fan,\n render: RatchetFan,\n layout: (spec, count, pos, station) => ({\n railRotation: 0,\n angleOf: (i) => stationAngle(spec, count, i),\n // The indexed spoke's label rights itself; the rest stay radial.\n flipOf: (i) => (i === station ? -stationAngle(spec, count, i) : 0),\n bloom: true,\n }),\n },\n};\n\nconst isDev =\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\n/** Reports router-active state upward without making a Router mandatory. */\nfunction ActiveProbe({ isActive, index, onRouteActive, children }) {\n useEffect(() => {\n if (isActive) onRouteActive(index);\n }, [isActive, index, onRouteActive]);\n return children;\n}\n\n/**\n * Sidebar navigation built on a circular slide rule.\n *\n * At rest only a crescent of the disc breaks the edge — enough to read as an\n * instrument, not enough to cost layout. Approaching the rail swings the whole\n * rule out; spinning it brings a station to the fixed index, ratcheting\n * through quarter-pitch detents on the way.\n *\n * As with SlideRuleNav, the engraved chrome is an aria-hidden SVG and the\n * navigation is an ordinary list of links positioned over it, so the dial is\n * fully operable by keyboard and the spin is a progressive enhancement.\n *\n * @param {object} props\n * @param {\"volvelle\"|\"concentric\"|\"fan\"} [props.variant]\n * @param {DialItem[]} props.items\n * @param {string} [props.value] - Selected item id (controlled).\n * @param {string} [props.defaultValue]\n * @param {(id: string) => void} [props.onChange]\n * @param {boolean} [props.expanded] - Controlled extract state.\n * @param {boolean} [props.defaultExpanded]\n * @param {(expanded: boolean) => void} [props.onExpandedChange]\n * @param {string} [props.label] - Accessible name for the nav landmark.\n * @param {string} [props.className]\n * @returns {import(\"react\").ReactElement}\n */\nexport function DialNav({\n variant = \"volvelle\",\n items = [],\n value,\n defaultValue,\n onChange,\n expanded,\n defaultExpanded = false,\n onExpandedChange,\n label = \"Sections\",\n className = \"\",\n}) {\n const resolved = VARIANTS[variant]\n ? variant\n : (isDev &&\n console.warn(\n `[DialNav] variant \"${variant}\" is not implemented yet; ` +\n `falling back to \"volvelle\".`\n ),\n \"volvelle\");\n const { spec, render: Chrome, layout, ownsStations, twoLevel } =\n VARIANTS[resolved];\n\n const count = validateStationCount(items.length, \"DialNav\");\n const stations = useMemo(() => items.slice(0, count), [items, count]);\n const [vbW, vbH] = spec.viewBox;\n\n const indexOfId = useCallback(\n (id) => {\n const i = stations.findIndex((item) => item.id === id);\n return i < 0 ? null : i;\n },\n [stations]\n );\n\n const routerMode = stations.some((item) => item.to);\n const [routeIndex, setRouteIndex] = useState(null);\n const syncedOnce = useRef(false);\n\n const controlledIndex =\n value != null ? indexOfId(value) : routerMode ? routeIndex : undefined;\n\n const stageRef = useRef(null);\n const chromeRef = useRef(null);\n const linkRefs = useRef([]);\n const pageRefs = useRef([]);\n const draggingRef = useRef(false);\n const leftDuringDragRef = useRef(false);\n\n const handleCommit = useCallback(\n (index) => {\n const item = stations[index];\n if (!item) return;\n if (item.to && linkRefs.current[index]) linkRefs.current[index].click();\n item.onSelect?.();\n onChange?.(item.id);\n },\n [onChange, stations]\n );\n\n const travel = useDetentTravel({\n count,\n value: controlledIndex ?? undefined,\n defaultValue: indexOfId(defaultValue) ?? 0,\n onChange: handleCommit,\n settleMs: spec.settleMs,\n });\n\n /* C-II only: the inner ring re-cuts to the indexed section's pages. */\n const pages = twoLevel ? (stations[travel.station]?.pages ?? []) : [];\n const pageCount = Math.max(1, pages.length);\n const [pageIndex, setPageIndex] = useState(0);\n\n const handlePageCommit = useCallback(\n (k) => {\n const page = pages[k];\n if (!page) return;\n setPageIndex(k);\n if (page.to && pageRefs.current[k]) pageRefs.current[k].click();\n page.onSelect?.();\n onChange?.(page.id);\n },\n [onChange, pages]\n );\n\n const innerTravel = useDetentTravel({\n count: pageCount,\n defaultValue: 0,\n onChange: handlePageCommit,\n settleMs: spec.innerSettleMs ?? spec.settleMs,\n });\n\n const { goTo: innerGoTo } = innerTravel;\n const sectionKey = twoLevel ? stations[travel.station]?.id : null;\n useEffect(() => {\n // Re-cutting the inner ring resets it to the section's first page.\n if (twoLevel) innerGoTo(0, 0);\n }, [sectionKey, twoLevel, innerGoTo]);\n\n const { goTo } = travel;\n const onRouteActive = useCallback(\n (index) => {\n setRouteIndex(index);\n if (!syncedOnce.current) {\n syncedOnce.current = true;\n goTo(index, 0);\n }\n },\n [goTo]\n );\n\n /* ── extract state ─────────────────────────────────────────────────── */\n\n const isControlledOpen = expanded != null;\n const [internalOpen, setInternalOpen] = useState(defaultExpanded);\n const open = isControlledOpen ? expanded : internalOpen;\n\n const setOpen = useCallback(\n (next) => {\n if (!isControlledOpen) setInternalOpen(next);\n onExpandedChange?.(next);\n },\n [isControlledOpen, onExpandedChange]\n );\n\n const closeIfIdle = useCallback(() => {\n // Never retract out from under keyboard focus.\n const stage = stageRef.current;\n if (stage && stage.contains(document.activeElement)) return;\n // A drag that wanders outside the stage must not retract the instrument\n // mid-spin; remember the intent and honour it when the drag ends.\n if (draggingRef.current) {\n leftDuringDragRef.current = true;\n return;\n }\n setOpen(false);\n }, [setOpen]);\n\n const onDragStateChange = useCallback(\n (isDragging) => {\n draggingRef.current = isDragging;\n if (isDragging) {\n leftDuringDragRef.current = false;\n return;\n }\n // Only retract if the pointer actually left while dragging. Finishing a\n // spin with the pointer still on the dial must leave it out.\n if (leftDuringDragRef.current) {\n leftDuringDragRef.current = false;\n closeIfIdle();\n }\n },\n [closeIfIdle]\n );\n\n const reducedMotion = useReducedMotion();\n const pitch = twoLevel ? 360 / Math.max(1, count) : pitchFor(spec, count);\n const active = twoLevel\n ? ((travel.station % count) + count) % count\n : travel.station;\n const place = layout(spec, count, travel.pos, active);\n const theta = place.railRotation;\n\n function onKeyDown(event) {\n const { key } = event;\n if (key === \"ArrowDown\" || key === \"ArrowRight\") travel.step(1);\n else if (key === \"ArrowUp\" || key === \"ArrowLeft\") travel.step(-1);\n else if (key === \"Home\") travel.goTo(0);\n else if (key === \"End\") travel.goTo(count - 1);\n else if (key === \"Escape\") {\n setOpen(false);\n return;\n } else return;\n event.preventDefault();\n }\n\n const linkClass = (isActive) =>\n \"ds-dial__link\" + (isActive ? \" ds-dial__link--active\" : \"\");\n\n /** One station control, as a router link or a plain button (D3). */\n const station = (item, i, { refs, isActive, onPick, extraClass = \"\" }) =>\n item.to ? (\n <NavLink\n to={item.to}\n end={item.end}\n ref={(el) => (refs.current[i] = el)}\n className={({ isActive: routerActive }) =>\n linkClass(routerActive) + extraClass\n }\n >\n {({ isActive: routerActive }) => (\n <ActiveProbe\n isActive={routerActive}\n index={i}\n onRouteActive={onRouteActive}\n >\n {item.label}\n </ActiveProbe>\n )}\n </NavLink>\n ) : (\n <button\n type=\"button\"\n className={linkClass(isActive) + extraClass}\n aria-current={isActive ? \"true\" : undefined}\n onClick={onPick}\n >\n {item.label}\n </button>\n );\n\n const renderStation = (i) =>\n station(stations[i], i, {\n refs: linkRefs,\n isActive: i === active,\n onPick: () => travel.goTo(i),\n });\n\n const renderPage = (page, k) =>\n station(page, k, {\n refs: pageRefs,\n isActive: k === pageIndex,\n onPick: () => innerTravel.goTo(k),\n extraClass: \" ds-dial__link--page\",\n });\n\n return (\n <nav\n className={[\n \"ds-dial\",\n `ds-dial--${resolved}`,\n open ? \"is-out\" : \"\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n aria-label={label}\n onKeyDown={onKeyDown}\n >\n <div\n className=\"ds-dial__stage\"\n ref={stageRef}\n onPointerLeave={closeIfIdle}\n onFocus={() => setOpen(true)}\n style={{\n \"--dial-w\": `${vbW}px`,\n \"--dial-h\": `${vbH}px`,\n \"--dial-cx\": `${spec.cx}px`,\n \"--dial-cy\": `${spec.cy}px`,\n }}\n >\n <span className=\"ds-dial__peek\" aria-hidden=\"true\">\n {stations[active]?.label}\n </span>\n\n <div className=\"ds-dial__frame\">\n {/* Written from the spec rather than duplicated into CSS, so\n geometry.js stays the single source for the extraction\n distances — they are measured values that must not drift out of\n step with the radii they were derived from. */}\n <div\n className=\"ds-dial__dock\"\n style={\n spec.restClip != null\n ? {\n // C-III pivots at the edge, so it is unveiled by opening a\n // clip rather than by sliding sideways.\n clipPath: open\n ? \"inset(0 0 0 0)\"\n : `inset(0 ${spec.restClip}px 0 0)`,\n }\n : {\n transform: `translateX(${open ? spec.out : spec.rest}px)`,\n }\n }\n >\n <Chrome\n ref={chromeRef}\n spec={spec}\n count={count}\n travel={travel}\n theta={theta}\n pitch={pitch}\n onDragStateChange={onDragStateChange}\n reducedMotion={reducedMotion}\n pages={pages}\n innerTravel={innerTravel}\n renderStation={renderStation}\n renderPage={renderPage}\n />\n\n {!ownsStations && (\n <ul\n className=\"ds-dial__stations\"\n style={{ transform: `rotate(${theta}deg)` }}\n >\n {stations.map((item, index) => (\n <li\n key={item.id}\n className=\"ds-dial__station\"\n style={{\n \"--a\": `${place.angleOf(index)}deg`,\n \"--r\": `${spec.labelR}px`,\n \"--flip\": `${place.flipOf(index)}deg`,\n \"--bloom-delay\": place.bloom\n ? `${index * spec.bloomStaggerMs}ms`\n : \"0ms\",\n }}\n >\n {renderStation(index)}\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n\n <button\n type=\"button\"\n className=\"ds-dial__hotzone\"\n aria-expanded={open}\n aria-label={open ? `Close ${label}` : `Open ${label}`}\n onPointerEnter={(e) => {\n if (e.pointerType === \"mouse\") setOpen(true);\n }}\n onPointerDown={(e) => {\n // Touch and pen have no hover, so the rail is a toggle for them.\n if (e.pointerType !== \"mouse\") setOpen(!open);\n }}\n onClick={(e) => {\n // Keyboard activation reports pointerType \"\" with no coordinates.\n if (!e.detail) setOpen(!open);\n }}\n />\n </div>\n </nav>\n );\n}\n","/*\n Frozen geometry for the circular plates (C-I, C-II, C-III).\n\n As with the linear rules, the *arc* is the constant and pitch derives from\n the station count. Radii were measured against real clipping bounds in a\n browser; changing an arc, a label radius, or the label font invalidates the\n extraction distances and they must be re-measured.\n*/\n\nexport const DIAL = Object.freeze({\n /** C-I — a disc that swings out of the edge and spins to an index. */\n volvelle: Object.freeze({\n viewBox: Object.freeze([440, 420]),\n cx: 210,\n cy: 210,\n /** Disc face, and the hairline circle just inside it. */\n r: 200,\n rInner: 193,\n /** Decorative rim ticks run inward from rInner. */\n rRing: 179,\n /** Station band: quarter-detent ticks run inward from rBand. */\n rBand: 177,\n /** Radial centre of a station label — the pivot its flip turns about. */\n labelR: 129,\n /** Logarithmic ring at the hub, for the same reason the original had one. */\n rLogInner: 62,\n rLogOuter: 76,\n rLogPlate: 78,\n rLogNumeral: 52,\n rHub: 34,\n /** Total sweep the stations are spread across. */\n arc: 216,\n /** Fixed cursor arm, due east. */\n arm: Object.freeze({ x: 38, w: 166, h: 38, hairline: 208, index: 218 }),\n /**\n * Half the width of the widest station label, including its padding.\n * Labels are HTML, so this cannot be derived from the SVG — it is\n * measured, and it is what the extraction distance has to clear.\n */\n labelClearance: 60,\n rest: -376,\n /*\n * Far enough out that the hub sits at labelR + labelClearance from the\n * stage edge, so a label swung to due west still fits. The artboards used\n * -110, but their labels were SVG text with no padding; HTML labels run\n * off the edge at that distance.\n */\n out: -10,\n settleMs: 520,\n }),\n\n /** C-II — two concentric rings and a swept arm, after the E6B. */\n concentric: Object.freeze({\n /* Wider than tall: the fixed index chevron reaches cx + 232. */\n viewBox: Object.freeze([460, 440]),\n cx: 220,\n cy: 220,\n r: 208,\n /** Outer ring: sections, spread over a full turn. */\n rOuter: 200,\n rOuterInner: 146,\n labelR: 164,\n /* Measured: the widest section label renders 85px across at this ring's\n reduced size, so half of it is 43. */\n labelClearance: 44,\n /** Inner ring: the pages of whichever section is indexed. */\n rInnerPlate: 132,\n rHubPlate: 58,\n innerLabelR: 122,\n innerArc: 135,\n innerCount: 4,\n arm: Object.freeze({ x: 50, w: 106, h: 30, tip: 156, point: 172 }),\n index: Object.freeze({ from: 198, to: 226, chevron: 232, back: 214 }),\n rest: -396,\n /* cx - labelR - labelClearance leaves 12px; -6 keeps 6px of margin for a\n section label swung due west by the ring's full turn. */\n out: -6,\n settleMs: 480,\n innerSettleMs: 380,\n }),\n\n /** C-III — a quadrant that blooms out of the edge on a ratchet. */\n fan: Object.freeze({\n viewBox: Object.freeze([400, 420]),\n /** The pivot sits hard against the left edge. */\n cx: 46,\n cy: 210,\n /** Spoke length. With halfAngle 80°, ro·sin(80°) ≈ 193 — the most a\n 420-tall viewBox will take. Do not raise without re-measuring. */\n r: 192,\n labelR: 130,\n labelClearance: 60,\n arc: 150,\n wedge: Object.freeze({ halfAngle: 80, ri: 64, ro: 196 }),\n hub: Object.freeze({ outer: 64, inner: 52 }),\n /** Ratchet teeth ride just outside the spoke ends. */\n tooth: Object.freeze({ from: 3, to: 10, lead: 3.4 }),\n /** How far the clip is held closed at rest, hiding all but the hub. */\n restClip: 328,\n bloomStaggerMs: 34,\n settleMs: 440,\n }),\n});\n\n/** Cartesian point at `deg` around (cx, cy). 0° is due east. */\nexport const polar = (cx, cy, r, deg) => [\n cx + r * Math.cos((deg * Math.PI) / 180),\n cy + r * Math.sin((deg * Math.PI) / 180),\n];\n\n/**\n * Whether a label riding the rim at this absolute angle would read upside\n * down, and so must flip about its own radial centre.\n *\n * @param {number} absDeg\n * @returns {boolean}\n */\nexport function uprightFlip(absDeg) {\n const a = ((absDeg % 360) + 360) % 360;\n return a > 90 && a < 270;\n}\n\n/** Angular distance between adjacent stations. */\nexport const pitchFor = (spec, count) => spec.arc / Math.max(1, count - 1);\n\n/** Angle of the first station — the arc is centred on the index. */\nexport const startAngle = (spec) => -spec.arc / 2;\n\n/** Angle of station `pos` (fractional positions allowed) in disc space. */\nexport const stationAngle = (spec, count, pos) =>\n startAngle(spec) + pos * pitchFor(spec, count);\n\n/**\n * Disc rotation that brings `pos` to the index at 0°.\n *\n * @param {object} spec\n * @param {number} count\n * @param {number} pos\n * @returns {number} Degrees.\n */\nexport const rotationFor = (spec, count, pos) =>\n -stationAngle(spec, count, pos);\n\n/**\n * Shortest signed difference between two angles, in degrees.\n *\n * Dragging a disc crosses the ±180° seam constantly; without normalising, a\n * pointer moving a few degrees past the seam reads as a 350° jump.\n *\n * @param {number} to\n * @param {number} from\n * @returns {number} Degrees in (-180, 180].\n */\nexport function angleDelta(to, from) {\n let d = to - from;\n while (d > 180) d -= 360;\n while (d <= -180) d += 360;\n return d;\n}\n\n/**\n * Ticks for a log10 decade around the hub, at slide-rule gradations.\n *\n * Each band is walked with an integer counter rather than by accumulating a\n * float step: accumulating drifts off the gradations, and because the band\n * boundaries are themselves tested against the drifting value, the 5–10 band\n * starts half a step late and never lands on 6, 7, 8 or 9.\n */\nexport function logRingTicks() {\n const bands = [\n [1, 2, 0.05],\n [2, 5, 0.1],\n [5, 10, 0.2],\n ];\n const out = [];\n for (const [from, to, step] of bands) {\n const steps = Math.round((to - from) / step);\n for (let k = 0; k < steps; k++) {\n const v = Math.round((from + k * step) * 100) / 100;\n out.push({\n v,\n angle: Math.log10(v) * 360 - 90,\n major: Number.isInteger(v),\n });\n }\n }\n return out;\n}\n\n/**\n * Angle of an inner-ring page. The inner arc is centred on the index like the\n * outer one, but spans only `innerArc`.\n */\nexport const innerPitchFor = (spec, count) =>\n spec.innerArc / Math.max(1, count - 1);\n\nexport const innerStartAngle = (spec) => -spec.innerArc / 2;\n\nexport const innerAngle = (spec, count, pos) =>\n innerStartAngle(spec) + pos * innerPitchFor(spec, count);\n\n/**\n * Ratchet tooth lead, clamped so teeth never overlap.\n *\n * At eight stations the detent is only 5.36°, and a fixed 3.4° lead would\n * make each tooth run into the next.\n *\n * @param {object} spec\n * @param {number} detent - Degrees between detents.\n * @returns {number}\n */\nexport const toothLead = (spec, detent) =>\n Math.min(spec.tooth.lead, detent * 0.45);\n\n/**\n * The fan's backing plate: an annular sector, not a pie slice. Its inner\n * radius stops at the hub so the rest-state hint survives underneath it.\n *\n * @param {object} spec\n * @returns {string} SVG path data.\n */\nexport function wedgePath(spec) {\n const { cx, cy } = spec;\n const { halfAngle, ri, ro } = spec.wedge;\n const [ax, ay] = polar(cx, cy, ri, -halfAngle);\n const [bx, by] = polar(cx, cy, ro, -halfAngle);\n const [dx, dy] = polar(cx, cy, ro, halfAngle);\n const [ex, ey] = polar(cx, cy, ri, halfAngle);\n return (\n `M${ax},${ay} L${bx},${by} ` +\n `A${ro},${ro} 0 0 1 ${dx},${dy} ` +\n `L${ex},${ey} ` +\n `A${ri},${ri} 0 0 0 ${ax},${ay} Z`\n );\n}\n","import { forwardRef, useMemo, useRef } from \"react\";\nimport { usePointerDrag } from \"../../_shared/usePointerDrag.js\";\nimport {\n angleDelta,\n logRingTicks,\n polar,\n startAngle,\n uprightFlip,\n} from \"../geometry.js\";\n\n/**\n * C-I — Volvelle.\n *\n * A disc carrying its stations on a band, read against a fixed glass cursor\n * arm due east. Spinning it ratchets through quarter-pitch detents; releasing\n * settles a station onto the index.\n *\n * Decorative only — the navigation is the HTML list the parent renders over\n * this, which rotates by the same angle the disc does.\n */\nexport const Volvelle = forwardRef(function Volvelle(\n { spec, count, travel, theta, pitch, onDragStateChange },\n ref\n) {\n const [vbW, vbH] = spec.viewBox;\n const { cx, cy, arm } = spec;\n const a0 = startAngle(spec);\n\n const discRef = useRef(null);\n const grab = useRef({ angle: 0, pos: 0 });\n\n /** Pointer position as an angle around the disc centre, in disc space. */\n const angleAt = (event) => {\n const box = ref.current?.getBoundingClientRect();\n if (!box?.width) return null;\n const scale = vbW / box.width;\n const x = (event.clientX - box.left) * scale - cx;\n const y = (event.clientY - box.top) * scale - cy;\n return (Math.atan2(y, x) * 180) / Math.PI;\n };\n\n usePointerDrag(discRef, {\n onBegin: (event) => {\n const a = angleAt(event);\n if (a == null) return;\n grab.current = { angle: a, pos: travel.pos };\n travel.begin();\n onDragStateChange?.(true);\n },\n onMove: (event) => {\n const a = angleAt(event);\n if (a == null) return;\n // The disc turns the opposite way to the travel it reads.\n travel.track(grab.current.pos - angleDelta(a, grab.current.angle) / pitch);\n },\n onEnd: (_event, wasTap) => {\n if (!wasTap) travel.release();\n onDragStateChange?.(false);\n },\n });\n\n /* Decorative rim: a tick every 2°, longer every 5° and 10°. */\n const rim = useMemo(() => {\n const out = [];\n for (let a = 0; a < 360; a += 2) {\n const len = a % 10 === 0 ? 14 : a % 5 === 0 ? 9 : 5;\n out.push({\n a,\n len,\n faint: a % 10 !== 0,\n });\n }\n return out;\n }, []);\n\n /* Station band: a tick at every quarter-pitch detent. */\n const band = useMemo(() => {\n const out = [];\n for (let q = 0; q <= (count - 1) * 4; q++) {\n const major = q % 4 === 0;\n const half = q % 2 === 0;\n out.push({\n a: a0 + (q / 4) * pitch,\n len: major ? 22 : half ? 12 : 7,\n faint: !major,\n station: major,\n });\n }\n return out;\n }, [a0, count, pitch]);\n\n const logTicks = useMemo(logRingTicks, []);\n\n return (\n <svg\n ref={ref}\n className=\"ds-dial__chrome\"\n viewBox={`0 0 ${vbW} ${vbH}`}\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n {/* The disc face must be opaque, or it has no silhouette against the\n stage and reads as floating tick marks. */}\n <circle className=\"ds-dial__face\" cx={cx} cy={cy} r={spec.r} />\n <circle\n className=\"ds-dial__hairline-ring\"\n cx={cx}\n cy={cy}\n r={spec.rInner}\n />\n\n <g ref={discRef} className=\"ds-dial__disc\">\n {/* An invisible but hittable face, so the whole disc is a drag handle\n without the painted circle having to be inside the rotating group. */}\n <circle\n className=\"ds-dial__grab\"\n cx={cx}\n cy={cy}\n r={spec.rInner}\n />\n <g transform={`rotate(${theta} ${cx} ${cy})`}>\n {rim.map((tick, i) => {\n const [x1, y1] = polar(cx, cy, spec.rInner, tick.a);\n const [x2, y2] = polar(cx, cy, spec.rInner - tick.len, tick.a);\n return (\n <line\n key={i}\n className={\n \"ds-dial__tick\" + (tick.faint ? \" ds-dial__tick--faint\" : \"\")\n }\n x1={x1}\n y1={y1}\n x2={x2}\n y2={y2}\n />\n );\n })}\n <circle\n className=\"ds-dial__hairline-ring\"\n cx={cx}\n cy={cy}\n r={spec.rRing}\n />\n\n {band.map((tick, i) => {\n const [x1, y1] = polar(cx, cy, spec.rBand, tick.a);\n const [x2, y2] = polar(cx, cy, spec.rBand - tick.len, tick.a);\n return (\n <line\n key={`b${i}`}\n className={\n \"ds-dial__tick\" +\n (tick.faint ? \" ds-dial__tick--faint\" : \"\") +\n (tick.station ? \" ds-dial__tick--station\" : \"\")\n }\n x1={x1}\n y1={y1}\n x2={x2}\n y2={y2}\n />\n );\n })}\n\n {/* A true log10 ring at the hub, for the same reason the original\n instrument had one. */}\n <circle\n className=\"ds-dial__log-plate\"\n cx={cx}\n cy={cy}\n r={spec.rLogPlate}\n />\n {logTicks.map((tick, i) => {\n const outer = spec.rLogInner + (tick.major ? 14 : 6);\n const [x1, y1] = polar(cx, cy, spec.rLogInner, tick.angle);\n const [x2, y2] = polar(cx, cy, outer, tick.angle);\n const [tx, ty] = polar(cx, cy, spec.rLogNumeral, tick.angle);\n return (\n <g key={`l${i}`}>\n <line\n className={\n \"ds-dial__tick\" + (tick.major ? \"\" : \" ds-dial__tick--faint\")\n }\n x1={x1}\n y1={y1}\n x2={x2}\n y2={y2}\n />\n {tick.major && (\n <text\n className=\"ds-dial__numeral\"\n x={tx}\n y={ty + 3}\n textAnchor=\"middle\"\n transform={`rotate(${\n tick.angle + 90 + (uprightFlip(tick.angle + 90) ? 180 : 0)\n } ${tx} ${ty})`}\n >\n {Math.round(tick.v)}\n </text>\n )}\n </g>\n );\n })}\n </g>\n </g>\n\n <circle className=\"ds-dial__hub\" cx={cx} cy={cy} r={spec.rHub} />\n <circle className=\"ds-dial__rivet\" cx={cx} cy={cy} r={9} />\n <circle className=\"ds-dial__rivet-hi\" cx={cx} cy={cy} r={4} />\n\n {/* The cursor arm is part of the instrument, not the disc: it does not\n rotate, and it must not swallow drags aimed at the face beneath. */}\n <g className=\"ds-dial__arm\">\n <rect\n className=\"ds-dial__glass\"\n x={cx + arm.x}\n y={cy - arm.h / 2}\n width={arm.w}\n height={arm.h}\n rx={2}\n />\n <rect\n className=\"ds-dial__frame-line\"\n x={cx + arm.x}\n y={cy - arm.h / 2}\n width={arm.w}\n height={arm.h}\n rx={3}\n />\n <line\n className=\"ds-dial__hairline\"\n x1={cx + arm.x}\n y1={cy}\n x2={cx + arm.hairline}\n y2={cy}\n />\n <path\n className=\"ds-dial__index\"\n d={`M${cx + arm.index},${cy - 11} L${cx + arm.index},${cy + 11} L${\n cx + arm.index - 18\n },${cy} Z`}\n />\n </g>\n </svg>\n );\n});\n","import { forwardRef, useMemo, useRef } from \"react\";\nimport { usePointerDrag } from \"../../_shared/usePointerDrag.js\";\nimport {\n angleDelta,\n innerAngle,\n innerPitchFor,\n polar,\n uprightFlip,\n} from \"../geometry.js\";\n\n/**\n * C-II — Concentric Computer.\n *\n * After the E6B. The outer ring carries sections and turns a full circle; the\n * inner ring re-cuts itself to the pages of whichever section is indexed, and\n * a brass arm sweeps between them. The only two-level plate, so it renders\n * both label rails itself rather than using the shell's single rail.\n */\nexport const Concentric = forwardRef(function Concentric(\n {\n spec,\n count,\n travel,\n theta,\n pitch,\n onDragStateChange,\n pages,\n innerTravel,\n renderStation,\n renderPage,\n },\n ref\n) {\n const [vbW, vbH] = spec.viewBox;\n const { cx, cy, arm, index } = spec;\n\n const ringRef = useRef(null);\n const armRef = useRef(null);\n const grabRing = useRef({ angle: 0, pos: 0 });\n const grabArm = useRef({ angle: 0, pos: 0 });\n\n const angleAt = (event) => {\n const box = ref.current?.getBoundingClientRect();\n if (!box?.width) return null;\n const scale = vbW / box.width;\n const x = (event.clientX - box.left) * scale - cx;\n const y = (event.clientY - box.top) * scale - cy;\n return (Math.atan2(y, x) * 180) / Math.PI;\n };\n\n usePointerDrag(ringRef, {\n onBegin: (event) => {\n const a = angleAt(event);\n if (a == null) return;\n grabRing.current = { angle: a, pos: travel.pos };\n travel.begin();\n onDragStateChange?.(true);\n },\n onMove: (event) => {\n const a = angleAt(event);\n if (a == null) return;\n travel.track(\n grabRing.current.pos - angleDelta(a, grabRing.current.angle) / pitch\n );\n },\n onEnd: (_e, wasTap) => {\n if (!wasTap) travel.release();\n onDragStateChange?.(false);\n },\n });\n\n const innerPitch = innerPitchFor(spec, pages.length);\n usePointerDrag(armRef, {\n onBegin: (event) => {\n const a = angleAt(event);\n if (a == null) return;\n grabArm.current = { angle: a, pos: innerTravel.pos };\n innerTravel.begin();\n onDragStateChange?.(true);\n },\n onMove: (event) => {\n const a = angleAt(event);\n if (a == null) return;\n innerTravel.track(\n grabArm.current.pos + angleDelta(a, grabArm.current.angle) / innerPitch\n );\n },\n onEnd: (_e, wasTap) => {\n if (!wasTap) innerTravel.release();\n onDragStateChange?.(false);\n },\n });\n\n /* 96 ticks around the outer ring: majors every 60°, detents every 15°. */\n const ringTicks = useMemo(() => {\n const out = [];\n for (let q = 0; q < 96; q++) {\n const a = q * 3.75;\n out.push({\n a,\n len: q % 16 === 0 ? 18 : q % 4 === 0 ? 10 : 5,\n faint: q % 16 !== 0,\n });\n }\n return out;\n }, []);\n\n const innerTicks = useMemo(() => {\n const out = [];\n for (let q = 0; q <= (pages.length - 1) * 4; q++) {\n const major = q % 4 === 0;\n out.push({\n a: innerAngle(spec, pages.length, q / 4),\n len: major ? 16 : q % 2 === 0 ? 9 : 5,\n major,\n });\n }\n return out;\n }, [pages.length, spec]);\n\n const armAngle = innerAngle(spec, pages.length, innerTravel.pos);\n\n return (\n <>\n <svg\n ref={ref}\n className=\"ds-dial__chrome\"\n viewBox={`0 0 ${vbW} ${vbH}`}\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle className=\"ds-dial__face\" cx={cx} cy={cy} r={spec.r} />\n\n <g ref={ringRef} className=\"ds-dial__disc\">\n <circle\n className=\"ds-dial__grab\"\n cx={cx}\n cy={cy}\n r={spec.rOuter}\n />\n {/* Punch the inner plate out of the ring's hit area, so drags there\n belong to the arm rather than the ring. */}\n <circle\n className=\"ds-dial__grab-hole\"\n cx={cx}\n cy={cy}\n r={spec.rOuterInner}\n />\n <g transform={`rotate(${theta} ${cx} ${cy})`}>\n <circle\n className=\"ds-dial__hairline-ring\"\n cx={cx}\n cy={cy}\n r={spec.rOuter}\n />\n <circle\n className=\"ds-dial__hairline-ring\"\n cx={cx}\n cy={cy}\n r={spec.rOuterInner}\n />\n {ringTicks.map((tick, i) => {\n const [x1, y1] = polar(cx, cy, spec.rOuter, tick.a);\n const [x2, y2] = polar(cx, cy, spec.rOuter - tick.len, tick.a);\n return (\n <line\n key={i}\n className={\n \"ds-dial__tick\" + (tick.faint ? \" ds-dial__tick--faint\" : \"\")\n }\n x1={x1}\n y1={y1}\n x2={x2}\n y2={y2}\n />\n );\n })}\n </g>\n </g>\n\n <circle\n className=\"ds-dial__log-plate\"\n cx={cx}\n cy={cy}\n r={spec.rInnerPlate}\n />\n {innerTicks.map((tick, i) => {\n const [x1, y1] = polar(cx, cy, spec.rInnerPlate, tick.a);\n const [x2, y2] = polar(cx, cy, spec.rInnerPlate - tick.len, tick.a);\n return (\n <line\n key={`i${i}`}\n className={\n \"ds-dial__tick\" +\n (tick.major ? \" ds-dial__tick--station\" : \" ds-dial__tick--faint\")\n }\n x1={x1}\n y1={y1}\n x2={x2}\n y2={y2}\n />\n );\n })}\n <circle\n className=\"ds-dial__hub\"\n cx={cx}\n cy={cy}\n r={spec.rHubPlate}\n />\n\n {/* The arm is a cursor frame, not a spine: a solid centre line would\n bisect the page label underneath it. */}\n <g\n ref={armRef}\n className=\"ds-dial__arm-sweep\"\n transform={`rotate(${armAngle} ${cx} ${cy})`}\n >\n <rect\n className=\"ds-dial__glass\"\n x={cx + arm.x}\n y={cy - arm.h / 2}\n width={arm.w}\n height={arm.h}\n rx={2}\n />\n <line\n className=\"ds-dial__brass-rail\"\n x1={cx + arm.x}\n y1={cy - arm.h / 2}\n x2={cx + arm.tip}\n y2={cy - arm.h / 2}\n />\n <line\n className=\"ds-dial__brass-rail\"\n x1={cx + arm.x}\n y1={cy + arm.h / 2}\n x2={cx + arm.tip}\n y2={cy + arm.h / 2}\n />\n <line\n className=\"ds-dial__hairline\"\n x1={cx + arm.x}\n y1={cy}\n x2={cx + arm.tip}\n y2={cy}\n />\n <path\n className=\"ds-dial__brass-point\"\n d={`M${cx + arm.tip},${cy - 9} L${cx + arm.point},${cy} L${\n cx + arm.tip\n },${cy + 9} Z`}\n />\n </g>\n\n <circle className=\"ds-dial__rivet\" cx={cx} cy={cy} r={11} />\n <circle className=\"ds-dial__rivet-hi\" cx={cx} cy={cy} r={5} />\n\n {/* The index hairline stops outside the ring; run it inward and it\n draws straight through the selected label. */}\n <g className=\"ds-dial__arm\">\n <line\n className=\"ds-dial__hairline\"\n x1={cx + index.from}\n y1={cy}\n x2={cx + index.to}\n y2={cy}\n />\n <path\n className=\"ds-dial__index\"\n d={`M${cx + index.chevron},${cy - 12} L${cx + index.chevron},${\n cy + 12\n } L${cx + index.back},${cy} Z`}\n />\n </g>\n </svg>\n\n {/* Two rails: the outer one rides the ring, the inner one is fixed in\n disc space and is read by the sweeping arm. */}\n <ul className=\"ds-dial__stations\" style={{ transform: `rotate(${theta}deg)` }}>\n {Array.from({ length: count }, (_, i) => {\n const a = i * pitch;\n return (\n <li\n key={i}\n className=\"ds-dial__station ds-dial__station--outer\"\n style={{\n \"--a\": `${a}deg`,\n \"--r\": `${spec.labelR}px`,\n \"--flip\": uprightFlip(a + theta) ? \"180deg\" : \"0deg\",\n }}\n >\n {renderStation(i)}\n </li>\n );\n })}\n </ul>\n\n <ul className=\"ds-dial__stations ds-dial__stations--inner\">\n {pages.map((page, k) => {\n const a = innerAngle(spec, pages.length, k);\n return (\n <li\n key={page.id}\n className=\"ds-dial__station\"\n style={{\n \"--a\": `${a}deg`,\n \"--r\": `${spec.innerLabelR}px`,\n \"--flip\": \"0deg\",\n }}\n >\n {renderPage(page, k)}\n </li>\n );\n })}\n </ul>\n </>\n );\n});\n","import { forwardRef, useMemo, useRef } from \"react\";\nimport { usePointerDrag } from \"../../_shared/usePointerDrag.js\";\nimport {\n angleDelta,\n polar,\n startAngle,\n stationAngle,\n toothLead,\n wedgePath,\n} from \"../geometry.js\";\n\n/**\n * C-III — Ratchet Fan.\n *\n * The hint is a bare hub band at the edge. On approach the quadrant blooms and\n * the spokes deploy in sequence, each carrying a station outward. A sprung\n * pawl rides a real sawtooth, kicking against every quarter-detent it crosses.\n *\n * Decorative only — the navigation is the HTML list the parent renders over\n * this, one label per spoke.\n */\nexport const RatchetFan = forwardRef(function RatchetFan(\n { spec, count, travel, pitch, onDragStateChange },\n ref\n) {\n const [vbW, vbH] = spec.viewBox;\n const { cx, cy, r, hub } = spec;\n const a0 = startAngle(spec);\n const detent = pitch / 4;\n const lead = toothLead(spec, detent);\n\n const pawlRef = useRef(null);\n const grab = useRef({ angle: 0, pos: 0 });\n\n const angleAt = (event) => {\n const box = ref.current?.getBoundingClientRect();\n if (!box?.width) return null;\n const scale = vbW / box.width;\n const x = (event.clientX - box.left) * scale - cx;\n const y = (event.clientY - box.top) * scale - cy;\n return (Math.atan2(y, x) * 180) / Math.PI;\n };\n\n usePointerDrag(pawlRef, {\n onBegin: (event) => {\n const a = angleAt(event);\n if (a == null) return;\n grab.current = { angle: a, pos: travel.pos };\n travel.begin();\n onDragStateChange?.(true);\n },\n onMove: (event) => {\n const a = angleAt(event);\n if (a == null) return;\n // The pawl follows the pointer directly — unlike a disc, the fan is\n // fixed and only the arm sweeps.\n travel.track(grab.current.pos + angleDelta(a, grab.current.angle) / pitch);\n },\n onEnd: (_event, wasTap) => {\n if (!wasTap) travel.release();\n onDragStateChange?.(false);\n },\n });\n\n /* One tooth per quarter-detent, chained into a single sawtooth. */\n const ratchet = useMemo(() => {\n let d = \"\";\n for (let q = 0; q <= (count - 1) * 4; q++) {\n const a = a0 + (q / 4) * pitch;\n const [x1, y1] = polar(cx, cy, r + spec.tooth.from, a);\n const [x2, y2] = polar(cx, cy, r + spec.tooth.to, a + lead);\n d += `${q ? \"L\" : \"M\"}${x1},${y1} L${x2},${y2} `;\n }\n return d;\n }, [a0, count, cx, cy, lead, pitch, r, spec.tooth.from, spec.tooth.to]);\n\n const detents = useMemo(() => {\n const out = [];\n for (let q = 0; q <= (count - 1) * 4; q++) {\n const major = q % 4 === 0;\n const half = q % 2 === 0;\n out.push({\n a: a0 + (q / 4) * pitch,\n len: major ? 22 : half ? 11 : 6,\n major,\n });\n }\n return out;\n }, [a0, count, pitch]);\n\n const [arcX0, arcY0] = polar(cx, cy, r, a0);\n const [arcX1, arcY1] = polar(cx, cy, r, stationAngle(spec, count, count - 1));\n const pawlAngle = stationAngle(spec, count, travel.pos);\n\n // The pawl rides up out of its notch between detents and drops back in.\n const frac = Math.abs(travel.pos * 4 - Math.round(travel.pos * 4));\n\n return (\n <svg\n ref={ref}\n className=\"ds-dial__chrome\"\n viewBox={`0 0 ${vbW} ${vbH}`}\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n {/* The hub is the whole rest-state hint, so it is never faded out. */}\n <circle className=\"ds-dial__log-plate\" cx={cx} cy={cy} r={hub.outer} />\n <circle className=\"ds-dial__hub\" cx={cx} cy={cy} r={hub.inner} />\n\n <g className=\"ds-dial__fanchrome\">\n {/* Without a backing plate the spokes float over page content. */}\n <path className=\"ds-dial__wedge\" d={wedgePath(spec)} />\n <path className=\"ds-dial__ratchet\" d={ratchet} />\n <path\n className=\"ds-dial__hairline-ring\"\n d={`M${arcX0},${arcY0} A${r},${r} 0 0 1 ${arcX1},${arcY1}`}\n />\n {detents.map((tick, i) => {\n const [x1, y1] = polar(cx, cy, r - tick.len, tick.a);\n const [x2, y2] = polar(cx, cy, r, tick.a);\n return (\n <line\n key={i}\n className={\n \"ds-dial__tick\" +\n (tick.major ? \" ds-dial__tick--station\" : \" ds-dial__tick--faint\")\n }\n x1={x1}\n y1={y1}\n x2={x2}\n y2={y2}\n />\n );\n })}\n </g>\n\n {/* Spokes. The rotation is an SVG attribute on the outer group and the\n retract is a CSS transform on the inner one: they cannot share an\n element, because transform-origin would be applied on top of a\n rotate() that already carries its own centre. */}\n {Array.from({ length: count }, (_, i) => {\n const a = stationAngle(spec, count, i);\n return (\n <g key={i} transform={`rotate(${a} ${cx} ${cy})`}>\n <g\n className=\"ds-dial__spoke\"\n style={{\n transformOrigin: `${cx}px ${cy}px`,\n transitionDelay: `${i * spec.bloomStaggerMs}ms`,\n }}\n >\n <line\n className=\"ds-dial__tick ds-dial__tick--faint\"\n x1={cx + hub.outer - 6}\n y1={cy}\n x2={cx + r - 8}\n y2={cy}\n />\n </g>\n </g>\n );\n })}\n\n <g\n ref={pawlRef}\n className=\"ds-dial__pawl\"\n transform={`rotate(${pawlAngle} ${cx} ${cy})`}\n >\n <rect\n className=\"ds-dial__glass\"\n x={cx + 50}\n y={cy - 16}\n width={r - 38}\n height={32}\n rx={2}\n />\n <rect\n className=\"ds-dial__frame-line\"\n x={cx + 50}\n y={cy - 16}\n width={r - 38}\n height={32}\n rx={3}\n />\n <line\n className=\"ds-dial__hairline\"\n x1={cx + 50}\n y1={cy}\n x2={cx + r + 2}\n y2={cy}\n />\n <path\n className=\"ds-dial__index\"\n d={`M${cx + r + 2},${cy - 8} L${cx + r + 16},${cy} L${cx + r + 2},${\n cy + 8\n } Z`}\n transform={`translate(${-frac * 5} 0)`}\n />\n </g>\n\n <circle className=\"ds-dial__rivet\" cx={cx} cy={cy} r={9} />\n <text\n className=\"ds-dial__caption\"\n x={cx}\n y={cy + 30}\n textAnchor=\"middle\"\n >\n PIVOT\n </text>\n </svg>\n );\n});\n"],"mappings":"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","names":["useMemo","useRef","Volvelle","forwardRef","useMemo","useRef","jsx","jsxs","forwardRef","Concentric","useRef","useMemo","forwardRef","useMemo","useRef","jsx","jsxs","forwardRef","RatchetFan","useRef","useMemo","jsx","jsxs","useMemo","useRef"]}
@@ -0,0 +1,206 @@
1
+ // src/components/_shared/useReducedMotion.js
2
+ import { useSyncExternalStore } from "react";
3
+ var QUERY = "(prefers-reduced-motion: reduce)";
4
+ function subscribe(onChange) {
5
+ const mq = window.matchMedia(QUERY);
6
+ mq.addEventListener("change", onChange);
7
+ return () => mq.removeEventListener("change", onChange);
8
+ }
9
+ var getSnapshot = () => window.matchMedia(QUERY).matches;
10
+ var getServerSnapshot = () => false;
11
+ function useReducedMotion() {
12
+ return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
13
+ }
14
+
15
+ // src/components/_shared/useDetentTravel.js
16
+ import { useCallback, useEffect, useRef, useState } from "react";
17
+ function easeBack(x) {
18
+ const c1 = 1.02;
19
+ const c3 = c1 + 1;
20
+ return 1 + c3 * Math.pow(x - 1, 3) + c1 * Math.pow(x - 1, 2);
21
+ }
22
+ var clamp = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
23
+ function useDetentTravel({
24
+ count,
25
+ value,
26
+ defaultValue = 0,
27
+ onChange,
28
+ subdivisions = 4,
29
+ settleMs = 420,
30
+ onDetentCross
31
+ } = {}) {
32
+ const last = Math.max(0, count - 1);
33
+ const isControlled = value != null;
34
+ const [internalStation, setInternalStation] = useState(
35
+ () => clamp(Math.round(defaultValue), 0, last)
36
+ );
37
+ const station = clamp(
38
+ Math.round(isControlled ? value : internalStation),
39
+ 0,
40
+ last
41
+ );
42
+ const [pos, setPos] = useState(station);
43
+ const [dragging, setDragging] = useState(false);
44
+ const [settling, setSettling] = useState(false);
45
+ const reduced = useReducedMotion();
46
+ const posRef = useRef(pos);
47
+ const rafRef = useRef(0);
48
+ const targetRef = useRef(station);
49
+ const stationRef = useRef(station);
50
+ const detentRef = useRef(Math.round(station * subdivisions));
51
+ const onChangeRef = useRef(onChange);
52
+ const onDetentCrossRef = useRef(onDetentCross);
53
+ posRef.current = pos;
54
+ stationRef.current = station;
55
+ onChangeRef.current = onChange;
56
+ onDetentCrossRef.current = onDetentCross;
57
+ const cancel = useCallback(() => {
58
+ if (rafRef.current) {
59
+ cancelAnimationFrame(rafRef.current);
60
+ rafRef.current = 0;
61
+ }
62
+ }, []);
63
+ useEffect(() => cancel, [cancel]);
64
+ const writePos = useCallback((v) => {
65
+ posRef.current = v;
66
+ setPos(v);
67
+ }, []);
68
+ const animateTo = useCallback(
69
+ (target, ms, done) => {
70
+ cancel();
71
+ const from = posRef.current;
72
+ if (reduced || ms <= 0 || from === target) {
73
+ writePos(target);
74
+ setSettling(false);
75
+ done?.();
76
+ return;
77
+ }
78
+ setSettling(true);
79
+ const t0 = performance.now();
80
+ const frame = (now) => {
81
+ const k = Math.min(1, (now - t0) / ms);
82
+ if (k < 1) {
83
+ writePos(from + (target - from) * easeBack(k));
84
+ rafRef.current = requestAnimationFrame(frame);
85
+ return;
86
+ }
87
+ rafRef.current = 0;
88
+ writePos(target);
89
+ setSettling(false);
90
+ done?.();
91
+ };
92
+ rafRef.current = requestAnimationFrame(frame);
93
+ },
94
+ [cancel, reduced, writePos]
95
+ );
96
+ const goTo = useCallback(
97
+ (i, ms = settleMs) => {
98
+ const next = clamp(Math.round(i), 0, last);
99
+ targetRef.current = next;
100
+ detentRef.current = Math.round(next * subdivisions);
101
+ animateTo(next, ms, () => {
102
+ if (next === stationRef.current) return;
103
+ if (!isControlled) setInternalStation(next);
104
+ onChangeRef.current?.(next);
105
+ });
106
+ },
107
+ [animateTo, isControlled, last, settleMs, subdivisions]
108
+ );
109
+ useEffect(() => {
110
+ if (targetRef.current === station) return;
111
+ targetRef.current = station;
112
+ detentRef.current = Math.round(station * subdivisions);
113
+ animateTo(station, settleMs);
114
+ }, [station, animateTo, settleMs, subdivisions]);
115
+ const begin = useCallback(() => {
116
+ cancel();
117
+ setSettling(false);
118
+ setDragging(true);
119
+ }, [cancel]);
120
+ const track = useCallback(
121
+ (raw) => {
122
+ cancel();
123
+ const detent = Math.round(clamp(raw, 0, last) * subdivisions);
124
+ if (detent !== detentRef.current) {
125
+ detentRef.current = detent;
126
+ onDetentCrossRef.current?.();
127
+ }
128
+ writePos(detent / subdivisions);
129
+ },
130
+ [cancel, last, subdivisions, writePos]
131
+ );
132
+ const release = useCallback(() => {
133
+ setDragging(false);
134
+ goTo(Math.round(posRef.current));
135
+ }, [goTo]);
136
+ const step = useCallback(
137
+ (delta) => goTo(stationRef.current + delta),
138
+ [goTo]
139
+ );
140
+ return { pos, station, dragging, settling, goTo, step, track, begin, release };
141
+ }
142
+
143
+ // src/components/_shared/validateStationCount.js
144
+ var MIN_STATIONS = 2;
145
+ var MAX_STATIONS = 8;
146
+ var isDev = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
147
+ function validateStationCount(n, component) {
148
+ if (n > MAX_STATIONS) {
149
+ if (isDev) {
150
+ console.warn(
151
+ `[${component}] ${n} stations exceeds the supported maximum of ${MAX_STATIONS}; extra items are not rendered. Slide-rule navigations stay legible up to ${MAX_STATIONS} stations.`
152
+ );
153
+ }
154
+ return MAX_STATIONS;
155
+ }
156
+ if (n < MIN_STATIONS && isDev) {
157
+ console.warn(
158
+ `[${component}] needs at least ${MIN_STATIONS} stations; got ${n}.`
159
+ );
160
+ }
161
+ return n;
162
+ }
163
+
164
+ // src/components/_shared/usePointerDrag.js
165
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
166
+ function usePointerDrag(ref, { onBegin, onMove, onEnd, threshold = 3 } = {}) {
167
+ const latest = useRef2({ onBegin, onMove, onEnd, threshold });
168
+ latest.current = { onBegin, onMove, onEnd, threshold };
169
+ useEffect2(() => {
170
+ const node = ref.current;
171
+ if (!node) return void 0;
172
+ function onPointerDown(event) {
173
+ if (event.button) return;
174
+ const startX = event.clientX;
175
+ const startY = event.clientY;
176
+ let moved = false;
177
+ latest.current.onBegin?.(event);
178
+ function onPointerMove(moveEvent) {
179
+ if (!moved && Math.hypot(moveEvent.clientX - startX, moveEvent.clientY - startY) < latest.current.threshold) {
180
+ return;
181
+ }
182
+ moved = true;
183
+ latest.current.onMove?.(moveEvent);
184
+ }
185
+ function onPointerUp(upEvent) {
186
+ window.removeEventListener("pointermove", onPointerMove);
187
+ window.removeEventListener("pointerup", onPointerUp);
188
+ window.removeEventListener("pointercancel", onPointerUp);
189
+ latest.current.onEnd?.(upEvent, !moved);
190
+ }
191
+ window.addEventListener("pointermove", onPointerMove);
192
+ window.addEventListener("pointerup", onPointerUp);
193
+ window.addEventListener("pointercancel", onPointerUp);
194
+ }
195
+ node.addEventListener("pointerdown", onPointerDown);
196
+ return () => node.removeEventListener("pointerdown", onPointerDown);
197
+ }, [ref]);
198
+ }
199
+
200
+ export {
201
+ useReducedMotion,
202
+ useDetentTravel,
203
+ validateStationCount,
204
+ usePointerDrag
205
+ };
206
+ //# sourceMappingURL=chunk-UZW4E2UH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/_shared/useReducedMotion.js","../src/components/_shared/useDetentTravel.js","../src/components/_shared/validateStationCount.js","../src/components/_shared/usePointerDrag.js"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\n\nconst QUERY = \"(prefers-reduced-motion: reduce)\";\n\nfunction subscribe(onChange) {\n const mq = window.matchMedia(QUERY);\n mq.addEventListener(\"change\", onChange);\n return () => mq.removeEventListener(\"change\", onChange);\n}\n\nconst getSnapshot = () => window.matchMedia(QUERY).matches;\n// No window during SSR; assume motion is fine and let the client correct it.\nconst getServerSnapshot = () => false;\n\n/**\n * Tracks `prefers-reduced-motion: reduce`, live.\n *\n * @returns {boolean} True when the user has asked for reduced motion.\n */\nexport function useReducedMotion() {\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useReducedMotion } from \"./useReducedMotion.js\";\n\n/**\n * Ease-out-back with a deliberately low overshoot. The small bounce is what\n * reads as *mechanical* — a cursor dropping into a notch — rather than bouncy.\n * Copied from the design artboards; do not retune without redrawing them.\n *\n * @param {number} x - Normalized time, 0…1.\n * @returns {number}\n */\nexport function easeBack(x) {\n const c1 = 1.02;\n const c3 = c1 + 1;\n return 1 + c3 * Math.pow(x - 1, 3) + c1 * Math.pow(x - 1, 2);\n}\n\nconst clamp = (v, lo, hi) => (v < lo ? lo : v > hi ? hi : v);\n\n/**\n * @typedef {object} DetentTravel\n * @property {number} pos - Continuous travel, 0…count-1. Quantized to\n * quarter detents while dragging.\n * @property {number} station - Committed integer station index.\n * @property {boolean} dragging\n * @property {boolean} settling - True while the release animation runs.\n * @property {(i: number, ms?: number) => void} goTo - Animate to a station.\n * @property {(delta: number) => void} step - Move by whole stations.\n * @property {(raw: number) => void} track - Feed raw travel during a drag.\n * @property {() => void} begin - Start a drag.\n * @property {() => void} release - Settle to the nearest station.\n */\n\n/**\n * The detent state machine shared by every slide-rule navigation.\n *\n * Travel is quantized to quarter-pitch detents *while dragging*, so the\n * mechanism visibly ratchets between stations, but releasing always settles\n * onto a station — navigation never rests in a null state. `onChange` fires\n * once, on arrival, and never mid-drag.\n *\n * @param {object} options\n * @param {number} options.count - Number of stations.\n * @param {number} [options.value] - Controlled station index.\n * @param {number} [options.defaultValue] - Initial station (uncontrolled).\n * @param {(station: number) => void} [options.onChange] - Fires on commit.\n * @param {number} [options.subdivisions] - Detents per station gap.\n * @param {number} [options.settleMs] - Release animation duration.\n * @param {() => void} [options.onDetentCross] - Fires per detent crossed\n * while dragging; drives the pawl kick and any tick feedback.\n * @returns {DetentTravel}\n */\nexport function useDetentTravel({\n count,\n value,\n defaultValue = 0,\n onChange,\n subdivisions = 4,\n settleMs = 420,\n onDetentCross,\n} = {}) {\n const last = Math.max(0, count - 1);\n const isControlled = value != null;\n\n const [internalStation, setInternalStation] = useState(() =>\n clamp(Math.round(defaultValue), 0, last)\n );\n const station = clamp(\n Math.round(isControlled ? value : internalStation),\n 0,\n last\n );\n\n const [pos, setPos] = useState(station);\n const [dragging, setDragging] = useState(false);\n const [settling, setSettling] = useState(false);\n\n const reduced = useReducedMotion();\n\n // Refs keep the animation loop and event handlers off the dependency\n // treadmill — a settle in flight must not be cancelled by an unrelated\n // re-render.\n const posRef = useRef(pos);\n const rafRef = useRef(0);\n const targetRef = useRef(station);\n const stationRef = useRef(station);\n const detentRef = useRef(Math.round(station * subdivisions));\n const onChangeRef = useRef(onChange);\n const onDetentCrossRef = useRef(onDetentCross);\n\n posRef.current = pos;\n stationRef.current = station;\n onChangeRef.current = onChange;\n onDetentCrossRef.current = onDetentCross;\n\n const cancel = useCallback(() => {\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = 0;\n }\n }, []);\n\n useEffect(() => cancel, [cancel]);\n\n const writePos = useCallback((v) => {\n posRef.current = v;\n setPos(v);\n }, []);\n\n const animateTo = useCallback(\n (target, ms, done) => {\n cancel();\n const from = posRef.current;\n if (reduced || ms <= 0 || from === target) {\n writePos(target);\n setSettling(false);\n done?.();\n return;\n }\n setSettling(true);\n const t0 = performance.now();\n const frame = (now) => {\n const k = Math.min(1, (now - t0) / ms);\n if (k < 1) {\n writePos(from + (target - from) * easeBack(k));\n rafRef.current = requestAnimationFrame(frame);\n return;\n }\n rafRef.current = 0;\n writePos(target);\n setSettling(false);\n done?.();\n };\n rafRef.current = requestAnimationFrame(frame);\n },\n [cancel, reduced, writePos]\n );\n\n const goTo = useCallback(\n (i, ms = settleMs) => {\n const next = clamp(Math.round(i), 0, last);\n targetRef.current = next;\n detentRef.current = Math.round(next * subdivisions);\n animateTo(next, ms, () => {\n if (next === stationRef.current) return; // already there; stay quiet\n if (!isControlled) setInternalStation(next);\n onChangeRef.current?.(next);\n });\n },\n [animateTo, isControlled, last, settleMs, subdivisions]\n );\n\n // A controlled `value` change (or an external reset) drives the travel.\n useEffect(() => {\n if (targetRef.current === station) return;\n targetRef.current = station;\n detentRef.current = Math.round(station * subdivisions);\n animateTo(station, settleMs);\n }, [station, animateTo, settleMs, subdivisions]);\n\n const begin = useCallback(() => {\n cancel();\n setSettling(false);\n setDragging(true);\n }, [cancel]);\n\n const track = useCallback(\n (raw) => {\n cancel();\n const detent = Math.round(clamp(raw, 0, last) * subdivisions);\n if (detent !== detentRef.current) {\n detentRef.current = detent;\n onDetentCrossRef.current?.();\n }\n writePos(detent / subdivisions);\n },\n [cancel, last, subdivisions, writePos]\n );\n\n const release = useCallback(() => {\n setDragging(false);\n goTo(Math.round(posRef.current));\n }, [goTo]);\n\n const step = useCallback(\n (delta) => goTo(stationRef.current + delta),\n [goTo]\n );\n\n return { pos, station, dragging, settling, goTo, step, track, begin, release };\n}\n","export const MIN_STATIONS = 2;\nexport const MAX_STATIONS = 8;\n\n// Guarded so the bundle stays safe in a browser with no `process` shim.\nconst isDev =\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\n/**\n * Clamps a station count to the range the slide-rule navigations stay legible\n * in, warning once per render in development. Never throws — a nav that\n * renders too many items is a design problem, not a crash.\n *\n * @param {number} n - Requested station count.\n * @param {string} component - Component name, for the warning.\n * @returns {number} The count to actually render.\n */\nexport function validateStationCount(n, component) {\n if (n > MAX_STATIONS) {\n if (isDev) {\n console.warn(\n `[${component}] ${n} stations exceeds the supported maximum of ` +\n `${MAX_STATIONS}; extra items are not rendered. Slide-rule ` +\n `navigations stay legible up to ${MAX_STATIONS} stations.`\n );\n }\n return MAX_STATIONS;\n }\n if (n < MIN_STATIONS && isDev) {\n console.warn(\n `[${component}] needs at least ${MIN_STATIONS} stations; got ${n}.`\n );\n }\n return n;\n}\n","import { useEffect, useRef } from \"react\";\n\n/**\n * Pointer dragging that does not break clicks on nested elements.\n *\n * Deliberately avoids `setPointerCapture`: capturing on a container (the\n * slide, the disc) redirects the subsequent `click` away from the station link\n * inside it, so nav items stop responding. Window-level listeners plus a small\n * movement threshold give the same drag behaviour and leave `click` intact.\n * `pointerdown` is likewise never `preventDefault`ed, because that suppresses\n * focus.\n *\n * @param {import(\"react\").RefObject<Element>} ref - The drag handle.\n * @param {object} handlers\n * @param {(e: PointerEvent) => void} [handlers.onBegin]\n * @param {(e: PointerEvent) => void} [handlers.onMove] - Only after threshold.\n * @param {(e: PointerEvent, wasTap: boolean) => void} [handlers.onEnd]\n * @param {number} [handlers.threshold] - Pixels of travel before a drag starts.\n */\nexport function usePointerDrag(ref, { onBegin, onMove, onEnd, threshold = 3 } = {}) {\n const latest = useRef({ onBegin, onMove, onEnd, threshold });\n latest.current = { onBegin, onMove, onEnd, threshold };\n\n useEffect(() => {\n const node = ref.current;\n if (!node) return undefined;\n\n function onPointerDown(event) {\n if (event.button) return;\n const startX = event.clientX;\n const startY = event.clientY;\n let moved = false;\n\n latest.current.onBegin?.(event);\n\n function onPointerMove(moveEvent) {\n if (\n !moved &&\n Math.hypot(moveEvent.clientX - startX, moveEvent.clientY - startY) <\n latest.current.threshold\n ) {\n return;\n }\n moved = true;\n latest.current.onMove?.(moveEvent);\n }\n\n function onPointerUp(upEvent) {\n window.removeEventListener(\"pointermove\", onPointerMove);\n window.removeEventListener(\"pointerup\", onPointerUp);\n window.removeEventListener(\"pointercancel\", onPointerUp);\n latest.current.onEnd?.(upEvent, !moved);\n }\n\n window.addEventListener(\"pointermove\", onPointerMove);\n window.addEventListener(\"pointerup\", onPointerUp);\n window.addEventListener(\"pointercancel\", onPointerUp);\n }\n\n node.addEventListener(\"pointerdown\", onPointerDown);\n return () => node.removeEventListener(\"pointerdown\", onPointerDown);\n }, [ref]);\n}\n"],"mappings":"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","names":["useEffect","useRef"]}