@5voltfx/design-system 0.1.1 → 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.
- package/dist/chunk-2KHDM6UP.js +58 -0
- package/dist/chunk-2KHDM6UP.js.map +1 -0
- package/dist/chunk-45346SXP.js +65 -0
- package/dist/chunk-45346SXP.js.map +1 -0
- package/dist/chunk-BAISLPWP.js +14 -0
- package/dist/chunk-BAISLPWP.js.map +1 -0
- package/dist/chunk-CT2TMR44.js +1 -0
- package/dist/chunk-CT2TMR44.js.map +1 -0
- package/dist/chunk-DD5VKG3L.js +22 -0
- package/dist/chunk-DD5VKG3L.js.map +1 -0
- package/dist/chunk-HLP2MPQ6.js +110 -0
- package/dist/chunk-HLP2MPQ6.js.map +1 -0
- package/dist/chunk-HPOL5NKF.js +22 -0
- package/dist/chunk-HPOL5NKF.js.map +1 -0
- package/dist/chunk-I3NS5MAC.js +23 -0
- package/dist/chunk-I3NS5MAC.js.map +1 -0
- package/dist/chunk-LPEUQ2DE.js +48 -0
- package/dist/chunk-LPEUQ2DE.js.map +1 -0
- package/dist/chunk-LY5MPGW2.js +129 -0
- package/dist/chunk-LY5MPGW2.js.map +1 -0
- package/dist/chunk-NJ2SBQYA.js +1208 -0
- package/dist/chunk-NJ2SBQYA.js.map +1 -0
- package/dist/chunk-R42A3ZCY.js +16 -0
- package/dist/chunk-R42A3ZCY.js.map +1 -0
- package/dist/chunk-UZW4E2UH.js +206 -0
- package/dist/chunk-UZW4E2UH.js.map +1 -0
- package/dist/chunk-VRGTUKSJ.js +20 -0
- package/dist/chunk-VRGTUKSJ.js.map +1 -0
- package/dist/chunk-YLUQANAI.js +1023 -0
- package/dist/chunk-YLUQANAI.js.map +1 -0
- package/dist/chunk-ZVUDPTFZ.js +76 -0
- package/dist/chunk-ZVUDPTFZ.js.map +1 -0
- package/dist/components/Accordion/Accordion.d.ts +29 -0
- package/dist/components/Accordion/Accordion.d.ts.map +1 -0
- package/dist/components/Accordion/index.css +58 -0
- package/dist/components/Accordion/index.css.map +1 -0
- package/dist/components/Accordion/index.d.ts +2 -0
- package/dist/components/Accordion/index.d.ts.map +1 -0
- package/dist/components/Accordion/index.js +7 -0
- package/dist/components/Accordion/index.js.map +1 -0
- package/dist/components/Button/Button.d.ts +8 -0
- package/dist/components/Button/Button.d.ts.map +1 -0
- package/dist/components/Button/index.d.ts +2 -0
- package/dist/components/Button/index.d.ts.map +1 -0
- package/dist/components/Card/Card.d.ts +6 -0
- package/dist/components/Card/Card.d.ts.map +1 -0
- package/dist/components/Card/index.d.ts +2 -0
- package/dist/components/Card/index.d.ts.map +1 -0
- package/dist/components/Checkbox/Checkbox.d.ts +15 -0
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -0
- package/dist/components/Checkbox/index.css +57 -0
- package/dist/components/Checkbox/index.css.map +1 -0
- package/dist/components/Checkbox/index.d.ts +2 -0
- package/dist/components/Checkbox/index.d.ts.map +1 -0
- package/dist/components/Checkbox/index.js +7 -0
- package/dist/components/Checkbox/index.js.map +1 -0
- package/dist/components/DialNav/DialNav.d.ts +48 -0
- package/dist/components/DialNav/DialNav.d.ts.map +1 -0
- package/dist/components/DialNav/geometry.d.ts +159 -0
- package/dist/components/DialNav/geometry.d.ts.map +1 -0
- package/dist/components/DialNav/index.css +321 -0
- package/dist/components/DialNav/index.css.map +1 -0
- package/dist/components/DialNav/index.d.ts +2 -0
- package/dist/components/DialNav/index.d.ts.map +1 -0
- package/dist/components/DialNav/index.js +8 -0
- package/dist/components/DialNav/index.js.map +1 -0
- package/dist/components/DialNav/variants/Concentric.d.ts +10 -0
- package/dist/components/DialNav/variants/Concentric.d.ts.map +1 -0
- package/dist/components/DialNav/variants/RatchetFan.d.ts +12 -0
- package/dist/components/DialNav/variants/RatchetFan.d.ts.map +1 -0
- package/dist/components/DialNav/variants/Volvelle.d.ts +12 -0
- package/dist/components/DialNav/variants/Volvelle.d.ts.map +1 -0
- package/dist/components/Footer/Footer.d.ts +15 -0
- package/dist/components/Footer/Footer.d.ts.map +1 -0
- package/dist/components/Footer/index.d.ts +2 -0
- package/dist/components/Footer/index.d.ts.map +1 -0
- package/dist/components/FormField/FormField.d.ts +27 -0
- package/dist/components/FormField/FormField.d.ts.map +1 -0
- package/dist/components/FormField/index.css +31 -0
- package/dist/components/FormField/index.css.map +1 -0
- package/dist/components/FormField/index.d.ts +2 -0
- package/dist/components/FormField/index.d.ts.map +1 -0
- package/dist/components/FormField/index.js +8 -0
- package/dist/components/FormField/index.js.map +1 -0
- package/dist/components/Header/Header.d.ts +15 -0
- package/dist/components/Header/Header.d.ts.map +1 -0
- package/dist/components/Header/index.d.ts +2 -0
- package/dist/components/Header/index.d.ts.map +1 -0
- package/dist/components/Input/Input.d.ts +16 -0
- package/dist/components/Input/Input.d.ts.map +1 -0
- package/dist/components/Input/index.css +45 -0
- package/dist/components/Input/index.css.map +1 -0
- package/dist/components/Input/index.d.ts +2 -0
- package/dist/components/Input/index.d.ts.map +1 -0
- package/dist/components/Input/index.js +7 -0
- package/dist/components/Input/index.js.map +1 -0
- package/dist/components/Label/Label.d.ts +15 -0
- package/dist/components/Label/Label.d.ts.map +1 -0
- package/dist/components/Label/index.css +14 -0
- package/dist/components/Label/index.css.map +1 -0
- package/dist/components/Label/index.d.ts +2 -0
- package/dist/components/Label/index.d.ts.map +1 -0
- package/dist/components/Label/index.js +8 -0
- package/dist/components/Label/index.js.map +1 -0
- package/dist/components/Layout/Container.d.ts +6 -0
- package/dist/components/Layout/Container.d.ts.map +1 -0
- package/dist/components/Layout/Grid.d.ts +9 -0
- package/dist/components/Layout/Grid.d.ts.map +1 -0
- package/dist/components/Layout/Stack.d.ts +10 -0
- package/dist/components/Layout/Stack.d.ts.map +1 -0
- package/dist/components/Layout/index.d.ts +4 -0
- package/dist/components/Layout/index.d.ts.map +1 -0
- package/dist/components/Menu/Menu.d.ts +30 -0
- package/dist/components/Menu/Menu.d.ts.map +1 -0
- package/dist/components/Menu/index.css +77 -0
- package/dist/components/Menu/index.css.map +1 -0
- package/dist/components/Menu/index.d.ts +2 -0
- package/dist/components/Menu/index.d.ts.map +1 -0
- package/dist/components/Menu/index.js +7 -0
- package/dist/components/Menu/index.js.map +1 -0
- package/dist/components/Modal/Modal.d.ts +24 -0
- package/dist/components/Modal/Modal.d.ts.map +1 -0
- package/dist/components/Modal/index.css +101 -0
- package/dist/components/Modal/index.css.map +1 -0
- package/dist/components/Modal/index.d.ts +2 -0
- package/dist/components/Modal/index.d.ts.map +1 -0
- package/dist/components/Modal/index.js +7 -0
- package/dist/components/Modal/index.js.map +1 -0
- package/dist/components/Nav/Nav.d.ts +10 -0
- package/dist/components/Nav/Nav.d.ts.map +1 -0
- package/dist/components/Nav/index.d.ts +2 -0
- package/dist/components/Nav/index.d.ts.map +1 -0
- package/dist/components/Radio/Radio.d.ts +17 -0
- package/dist/components/Radio/Radio.d.ts.map +1 -0
- package/dist/components/Radio/RadioGroup.d.ts +25 -0
- package/dist/components/Radio/RadioGroup.d.ts.map +1 -0
- package/dist/components/Radio/RadioGroupContext.d.ts +7 -0
- package/dist/components/Radio/RadioGroupContext.d.ts.map +1 -0
- package/dist/components/Radio/index.css +57 -0
- package/dist/components/Radio/index.css.map +1 -0
- package/dist/components/Radio/index.d.ts +3 -0
- package/dist/components/Radio/index.d.ts.map +1 -0
- package/dist/components/Radio/index.js +9 -0
- package/dist/components/Radio/index.js.map +1 -0
- package/dist/components/Select/Select.d.ts +18 -0
- package/dist/components/Select/Select.d.ts.map +1 -0
- package/dist/components/Select/index.css +52 -0
- package/dist/components/Select/index.css.map +1 -0
- package/dist/components/Select/index.d.ts +2 -0
- package/dist/components/Select/index.d.ts.map +1 -0
- package/dist/components/Select/index.js +7 -0
- package/dist/components/Select/index.js.map +1 -0
- package/dist/components/SlideRuleNav/SlideRuleNav.d.ts +54 -0
- package/dist/components/SlideRuleNav/SlideRuleNav.d.ts.map +1 -0
- package/dist/components/SlideRuleNav/geometry.d.ts +168 -0
- package/dist/components/SlideRuleNav/geometry.d.ts.map +1 -0
- package/dist/components/SlideRuleNav/index.css +196 -0
- package/dist/components/SlideRuleNav/index.css.map +1 -0
- package/dist/components/SlideRuleNav/index.d.ts +2 -0
- package/dist/components/SlideRuleNav/index.d.ts.map +1 -0
- package/dist/components/SlideRuleNav/index.js +8 -0
- package/dist/components/SlideRuleNav/index.js.map +1 -0
- package/dist/components/SlideRuleNav/variants/CursorRule.d.ts +11 -0
- package/dist/components/SlideRuleNav/variants/CursorRule.d.ts.map +1 -0
- package/dist/components/SlideRuleNav/variants/SlideStator.d.ts +13 -0
- package/dist/components/SlideRuleNav/variants/SlideStator.d.ts.map +1 -0
- package/dist/components/SlideRuleNav/variants/VernierCarriage.d.ts +13 -0
- package/dist/components/SlideRuleNav/variants/VernierCarriage.d.ts.map +1 -0
- package/dist/components/Switch/Switch.d.ts +15 -0
- package/dist/components/Switch/Switch.d.ts.map +1 -0
- package/dist/components/Switch/index.css +49 -0
- package/dist/components/Switch/index.css.map +1 -0
- package/dist/components/Switch/index.d.ts +2 -0
- package/dist/components/Switch/index.d.ts.map +1 -0
- package/dist/components/Switch/index.js +7 -0
- package/dist/components/Switch/index.js.map +1 -0
- package/dist/components/Tabs/Tabs.d.ts +34 -0
- package/dist/components/Tabs/Tabs.d.ts.map +1 -0
- package/dist/components/Tabs/index.css +54 -0
- package/dist/components/Tabs/index.css.map +1 -0
- package/dist/components/Tabs/index.d.ts +2 -0
- package/dist/components/Tabs/index.d.ts.map +1 -0
- package/dist/components/Tabs/index.js +7 -0
- package/dist/components/Tabs/index.js.map +1 -0
- package/dist/components/Textarea/Textarea.d.ts +16 -0
- package/dist/components/Textarea/Textarea.d.ts.map +1 -0
- package/dist/components/Textarea/index.css +36 -0
- package/dist/components/Textarea/index.css.map +1 -0
- package/dist/components/Textarea/index.d.ts +2 -0
- package/dist/components/Textarea/index.d.ts.map +1 -0
- package/dist/components/Textarea/index.js +7 -0
- package/dist/components/Textarea/index.js.map +1 -0
- package/dist/components/ThemeSwitcher/ThemeSwitcher.d.ts +4 -0
- package/dist/components/ThemeSwitcher/ThemeSwitcher.d.ts.map +1 -0
- package/dist/components/ThemeSwitcher/index.d.ts +2 -0
- package/dist/components/ThemeSwitcher/index.d.ts.map +1 -0
- package/dist/components/Typography/Heading.d.ts +9 -0
- package/dist/components/Typography/Heading.d.ts.map +1 -0
- package/dist/components/Typography/Text.d.ts +9 -0
- package/dist/components/Typography/Text.d.ts.map +1 -0
- package/dist/components/Typography/index.d.ts +3 -0
- package/dist/components/Typography/index.d.ts.map +1 -0
- package/dist/components/_shared/useDetentTravel.d.ts +87 -0
- package/dist/components/_shared/useDetentTravel.d.ts.map +1 -0
- package/dist/components/_shared/usePointerDrag.d.ts +24 -0
- package/dist/components/_shared/usePointerDrag.d.ts.map +1 -0
- package/dist/components/_shared/useReducedMotion.d.ts +7 -0
- package/dist/components/_shared/useReducedMotion.d.ts.map +1 -0
- package/dist/components/_shared/validateStationCount.d.ts +13 -0
- package/dist/components/_shared/validateStationCount.d.ts.map +1 -0
- package/dist/index.css +1175 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -10
- package/dist/index.js.map +1 -1
- package/dist/theme/ThemeContext.d.ts +2 -0
- package/dist/theme/ThemeContext.d.ts.map +1 -0
- package/dist/theme/ThemeProvider.d.ts +12 -0
- package/dist/theme/ThemeProvider.d.ts.map +1 -0
- package/dist/theme/themeConstants.d.ts +8 -0
- package/dist/theme/themeConstants.d.ts.map +1 -0
- package/dist/theme/useTheme.d.ts +2 -0
- package/dist/theme/useTheme.d.ts.map +1 -0
- package/package.json +21 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/SlideRuleNav/SlideRuleNav.jsx","../src/components/SlideRuleNav/geometry.js","../src/components/SlideRuleNav/variants/CursorRule.jsx","../src/components/SlideRuleNav/variants/SlideStator.jsx","../src/components/SlideRuleNav/variants/VernierCarriage.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 { LINEAR, pitchFor, pct, logStops, localAt } from \"./geometry.js\";\nimport { CursorRule } from \"./variants/CursorRule.jsx\";\nimport { SlideStator } from \"./variants/SlideStator.jsx\";\nimport { VernierCarriage } from \"./variants/VernierCarriage.jsx\";\nimport \"./SlideRuleNav.css\";\n\n/**\n * @typedef {object} SlideRuleItem\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] - Passed to NavLink for exact matching.\n * @property {() => void} [onSelect] - Used when the item has no `to`.\n * @property {string} [value] - Scarlet scale numeral. Defaults to `i.toFixed(2)`.\n */\n\n/**\n * Where each station label sits, and how far the whole label rail is shifted.\n *\n * L-I and L-III hold a fixed scale and move a cursor over it, so the labels\n * never move. L-II inverts that: the index is fixed and the *slide* travels,\n * carrying its stations with it — so the labels ride the same offset the\n * engraved slide does.\n */\nconst fixedLayout = (spec, count) => ({\n stationX: (i) => spec.x0 + i * pitchFor(spec, count),\n offset: 0,\n});\n\nconst slideLayout = (spec, count, pos) => {\n const stops = logStops(spec, count);\n return {\n stationX: (i) => stops[i],\n offset: spec.index - localAt(stops, pos),\n };\n};\n\nconst VARIANTS = {\n cursor: { spec: LINEAR.cursor, render: CursorRule, layout: fixedLayout },\n slide: { spec: LINEAR.slide, render: SlideStator, layout: slideLayout },\n vernier: {\n spec: LINEAR.vernier,\n render: VernierCarriage,\n layout: fixedLayout,\n },\n};\n\nconst isDev =\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\n/**\n * Reports its own router-active state upward. NavLink already knows which link\n * matches the location, so the rule reads activeness from it rather than\n * calling useLocation — which would make a Router mandatory even for items\n * that only use `onSelect`.\n */\nfunction ActiveProbe({ isActive, index, onRouteActive, children }) {\n useEffect(() => {\n if (isActive) onRouteActive(index);\n }, [isActive, index, onRouteActive]);\n return children;\n}\n\n/**\n * Navigation built on a linear slide rule. Travel is quantized to quarter-tick\n * detents: the mechanism ratchets between stations while you drag it and\n * settles onto one when you let go.\n *\n * Items carrying `to` render as NavLinks and the router drives the cursor;\n * items without one render as buttons and the component tracks its own\n * selection. Both forms may be mixed.\n *\n * The engraved chrome is decorative and hidden from assistive technology — the\n * navigation itself is an ordinary list of links, fully operable by keyboard.\n *\n * @param {object} props\n * @param {\"cursor\"|\"slide\"|\"vernier\"} [props.variant]\n * @param {SlideRuleItem[]} props.items\n * @param {string} [props.value] - Selected item id (controlled).\n * @param {string} [props.defaultValue] - Initial item id (uncontrolled).\n * @param {(id: string) => void} [props.onChange]\n * @param {boolean} [props.readout] - Show the instrument readout strip.\n * @param {string} [props.label] - Accessible name for the nav landmark.\n * @param {string} [props.className]\n * @returns {import(\"react\").ReactElement}\n */\nexport function SlideRuleNav({\n variant = \"vernier\",\n items = [],\n value,\n defaultValue,\n onChange,\n readout = false,\n label = \"Main\",\n className = \"\",\n}) {\n const resolved = VARIANTS[variant]\n ? variant\n : (isDev &&\n console.warn(\n `[SlideRuleNav] variant \"${variant}\" is not implemented yet; ` +\n `falling back to \"vernier\".`\n ),\n \"vernier\");\n const { spec, render: Chrome, layout } = VARIANTS[resolved];\n\n const count = validateStationCount(items.length, \"SlideRuleNav\");\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 // In router mode the router is the controller: releasing the carriage clicks\n // the target link, the location changes, and the travel follows.\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 chromeRef = useRef(null);\n const navRef = useRef(null);\n const linkRefs = useRef([]);\n const stationRefs = useRef([]);\n const reducedMotion = useReducedMotion();\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 const { goTo } = travel;\n const onRouteActive = useCallback(\n (index) => {\n setRouteIndex(index);\n // Land on the current route without a settle animation on first paint.\n if (!syncedOnce.current) {\n syncedOnce.current = true;\n goTo(index, 0);\n }\n },\n [goTo]\n );\n\n /**\n * Pointer x (client space) to a viewBox x. Each variant turns that into\n * travel itself, because a fixed scale and a moving slide read it\n * differently.\n */\n const toViewBoxX = useCallback(\n (clientX) => {\n const box = chromeRef.current?.getBoundingClientRect();\n if (!box?.width) return null;\n return ((clientX - box.left) / box.width) * vbW;\n },\n [vbW]\n );\n\n const active = travel.station;\n\n // A rule too long for the viewport scrolls; keep the selected station in\n // view so the carriage never settles off-screen. Scrolls the nav's own\n // container, never the page.\n useEffect(() => {\n const nav = navRef.current;\n if (!nav) return undefined;\n\n const centre = (behavior) => {\n const station = stationRefs.current[active];\n if (!station || nav.scrollWidth <= nav.clientWidth) return;\n nav.scrollTo({\n left: Math.max(0, station.offsetLeft - nav.clientWidth / 2),\n behavior,\n });\n };\n\n centre(reducedMotion ? \"auto\" : \"smooth\");\n\n // The rule may start out fitting and only overflow once the viewport\n // narrows — on rotation, say — so re-centre when the container resizes.\n if (typeof ResizeObserver === \"undefined\") return undefined;\n const observer = new ResizeObserver(() => centre(\"auto\"));\n observer.observe(nav);\n return () => observer.disconnect();\n }, [active, reducedMotion]);\n\n function onKeyDown(event) {\n if (event.key === \"ArrowRight\") travel.step(1);\n else if (event.key === \"ArrowLeft\") travel.step(-1);\n else if (event.key === \"Home\") travel.goTo(0);\n else if (event.key === \"End\") travel.goTo(count - 1);\n else return;\n event.preventDefault();\n }\n\n const place = layout(spec, count, travel.pos);\n const linkClass = (isActive) =>\n \"ds-rule__link\" + (isActive ? \" ds-rule__link--active\" : \"\");\n\n return (\n <nav\n ref={navRef}\n className={[\"ds-rule\", `ds-rule--${resolved}`, className]\n .filter(Boolean)\n .join(\" \")}\n aria-label={label}\n onKeyDown={onKeyDown}\n >\n <div className=\"ds-rule__stage\">\n <Chrome\n ref={chromeRef}\n spec={spec}\n count={count}\n stations={stations}\n travel={travel}\n toViewBoxX={toViewBoxX}\n />\n\n <ul\n className=\"ds-rule__stations\"\n style={{ transform: `translateX(${pct(place.offset, vbW)})` }}\n >\n {stations.map((item, index) => (\n <li\n key={item.id}\n ref={(el) => (stationRefs.current[index] = el)}\n className=\"ds-rule__station\"\n style={{\n \"--station-x\": pct(place.stationX(index), vbW),\n \"--station-y\": pct(spec.labelY, vbH),\n }}\n >\n {item.to ? (\n <NavLink\n to={item.to}\n end={item.end}\n ref={(el) => (linkRefs.current[index] = el)}\n className={({ isActive }) => linkClass(isActive)}\n >\n {({ isActive }) => (\n <ActiveProbe\n isActive={isActive}\n index={index}\n onRouteActive={onRouteActive}\n >\n {item.label}\n </ActiveProbe>\n )}\n </NavLink>\n ) : (\n <button\n type=\"button\"\n className={linkClass(index === active)}\n aria-current={index === active ? \"true\" : undefined}\n onClick={() => travel.goTo(index)}\n >\n {item.label}\n </button>\n )}\n </li>\n ))}\n </ul>\n </div>\n\n {readout && (\n <div className=\"ds-rule__readout\">\n <span aria-hidden=\"true\">\n <span className=\"ds-rule__readout-key\">Carriage</span>{\" \"}\n <span className=\"ds-rule__readout-val\">\n {travel.dragging ? \"——\" : stations[active]?.label}\n </span>{\" \"}\n <span className=\"ds-rule__readout-key\">Vernier</span>{\" \"}\n <span className=\"ds-rule__readout-num\">\n {travel.pos.toFixed(2)}\n </span>\n </span>\n {/* Announce only committed changes, never every drag frame. */}\n <span className=\"ds-rule__sr-only\" aria-live=\"polite\">\n {travel.dragging || travel.settling\n ? \"\"\n : `${stations[active]?.label ?? \"\"} selected`}\n </span>\n </div>\n )}\n </nav>\n );\n}\n","/*\n Frozen geometry for the linear plates (L-I, L-II, L-III).\n\n These numbers come from the design artboards and were tuned against real\n clipping bounds in a browser. Treat the *span* as constant and derive pitch\n from the station count — the artboards were drawn with 6 stations, but the\n first integration (5voltfx.com, L-III) has 3.\n*/\n\n/** Preferred main-scale minor division, in viewBox units. */\nexport const MINOR_TARGET = 38;\n\nexport const LINEAR = Object.freeze({\n /**\n * L-I — fixed scale, cursor travels.\n *\n * The stock runs from `x0 - cursorBox.w / 2` to `x1 + cursorBox.w / 2` for\n * the same reason as L-III: the cursor is centred on the station it reads,\n * so the stock has to extend past the end graduations for it to sit on the\n * instrument at station 0 and at the last station.\n */\n cursor: Object.freeze({\n viewBox: Object.freeze([900, 136]),\n x0: 62,\n x1: 838,\n railX0: 30,\n railX1: 870,\n top: 40,\n bot: 112,\n labelY: 24,\n cursorBox: Object.freeze({ w: 60, h: 100, y: 28 }),\n settleMs: 420,\n }),\n /** L-II — fixed index, slide travels, true log10 station spacing. */\n slide: Object.freeze({\n viewBox: Object.freeze([900, 150]),\n l0: 60,\n lw: 1400,\n index: 450,\n clip: Object.freeze([30, 870]),\n statorL0: 40,\n statorLw: 800,\n slideY: 46,\n slideH: 58,\n labelY: 88,\n settleMs: 460,\n }),\n /**\n * L-III — notched rail, vernier carriage. Reference plate.\n *\n * The station span is 772 units, exactly as drawn in the artboards, but it\n * is inset 124 units from the left rather than 64. The carriage is centred\n * on the station it reads, and its widest form (5 stations) is 224 units\n * across — so at station 0 a 64-unit inset put half the vernier off the end\n * of the rule. The artboards never showed it because they opened on station\n * 2. Keeping the span identical preserves every derived division.\n *\n * The rail then runs from `x0 - maxCarriageHalf` to `x1 + maxCarriageHalf`,\n * because a real stock extends past its scale far enough for the cursor to\n * reach the end graduations without hanging off the instrument.\n */\n vernier: Object.freeze({\n viewBox: Object.freeze([1020, 160]),\n x0: 124,\n x1: 896,\n railX0: 12,\n railX1: 1008,\n railY: 46,\n railH: 42,\n labelY: 26,\n vernierDivisions: 5,\n mainDivisionsSpanned: 4,\n /** Widest half-carriage across all supported counts; the inset floor. */\n maxCarriageHalf: 112,\n settleMs: 380,\n }),\n});\n\n/**\n * Station scale values for L-II, per station count.\n *\n * The point of L-II is that the gaps are *uneven* — stations sit at true\n * log10 positions, so travel compresses toward the right of the rule. Spacing\n * values evenly in log space would make the gaps equal and collapse L-II into\n * L-I, so each count gets a hand-picked set of slide-rule gradations. The\n * six-station row is the artboards', unchanged.\n */\nexport const SLIDE_VALUES = Object.freeze({\n 2: Object.freeze([1, 8]),\n 3: Object.freeze([1, 2, 8]),\n 4: Object.freeze([1, 2, 3, 8]),\n 5: Object.freeze([1, 1.5, 2, 3, 8]),\n 6: Object.freeze([1, 1.5, 2, 3, 5, 8]),\n 7: Object.freeze([1, 1.5, 2, 3, 4, 6, 8]),\n 8: Object.freeze([1, 1.5, 2, 2.5, 3, 4, 6, 8]),\n});\n\n/** CSS percentage for a viewBox coordinate, for HTML overlaid on the SVG. */\nexport const pct = (v, extent) => `${(v / extent) * 100}%`;\n\nconst clamp = (v, lo, hi) => (v < lo ? lo : v > hi ? hi : v);\n\n/**\n * Distance between adjacent stations, in viewBox units.\n *\n * @param {{x0: number, x1: number}} spec\n * @param {number} count\n * @returns {number}\n */\nexport function pitchFor(spec, count) {\n return (spec.x1 - spec.x0) / Math.max(1, count - 1);\n}\n\n/** Travel position (0…count-1) to a viewBox x. */\nexport const travelX = (spec, count, pos) =>\n spec.x0 + pos * pitchFor(spec, count);\n\n/**\n * How many main-scale minor divisions fill one station gap.\n *\n * Always a multiple of 4, so a quarter-pitch detent is always a whole number\n * of minor divisions and the vernier's zero line coincides exactly when the\n * pawl seats. Without this the carriage scales with pitch: at 3 stations a\n * naive `pitch / 4` gives a vernier half the width of the rule.\n *\n * @param {number} pitch\n * @returns {{minorsPerPitch: number, minor: number, vdiv: number,\n * minorsPerDetent: number}}\n */\nexport function minorDivisions(pitch) {\n const minorsPerPitch =\n 4 * Math.max(1, Math.round(pitch / (4 * MINOR_TARGET)));\n const minor = pitch / minorsPerPitch;\n return {\n minorsPerPitch,\n minor,\n vdiv: (minor * 4) / 5,\n minorsPerDetent: minorsPerPitch / 4,\n };\n}\n\n/**\n * Which vernier line currently coincides with a main-scale line — the whole\n * trick of L-III. Five carriage divisions span four rail divisions, so at any\n * offset exactly one line pair lines up, and which one gives the fraction.\n *\n * @param {object} options\n * @param {number} options.pos - Travel, 0…count-1.\n * @param {number} options.count\n * @param {{x0: number, x1: number}} [options.spec]\n * @returns {{k: number, d: number, lit: boolean}} Coinciding line index, its\n * distance from the main line, and whether it is close enough to light.\n */\nexport function coincidence({ pos, count, spec = LINEAR.vernier }) {\n const pitch = pitchFor(spec, count);\n const { minor, vdiv } = minorDivisions(pitch);\n const cx = spec.x0 + pos * pitch;\n\n // Six lines are drawn but only five are readable: the closing line sits\n // exactly four minor divisions from the zero line, so both always coincide\n // together. Searching 0…4 keeps the reading unambiguous, and the epsilon\n // stops floating-point noise from picking a later line on an exact tie.\n let k = 0;\n let d = Infinity;\n for (let i = 0; i < LINEAR.vernier.vernierDivisions; i++) {\n const vx = cx + (i - 2.5) * vdiv;\n const off = vx - spec.x0;\n const dist = Math.abs(off - Math.round(off / minor) * minor);\n if (dist < d - 1e-9) {\n d = dist;\n k = i;\n }\n }\n return { k, d, lit: d < vdiv * 0.34 };\n}\n\n/* ── L-II: true log10 station spacing ─────────────────────────────────── */\n\n/** Slide-local x for a scale value. */\nexport const logX = (spec, v) => spec.l0 + Math.log10(v) * spec.lw;\n\n/** The scale values a slide of `count` stations is engraved with. */\nexport const slideValues = (count) =>\n SLIDE_VALUES[count] ?? SLIDE_VALUES[6];\n\n/** Slide-local x of every station. */\nexport const logStops = (spec, count) =>\n slideValues(count).map((v) => logX(spec, v));\n\n/** Static stator scale x — the whole decade, sized to the window. */\nexport const statorX = (spec, v) =>\n spec.statorL0 + Math.log10(v) * spec.statorLw;\n\n/**\n * Slide-local x for continuous travel. Linear *between* stops, so each gap's\n * quarter-detents inherit that gap's own width — wide at the left of the rule,\n * tight at the right. The unevenness is the point.\n *\n * @param {number[]} stops\n * @param {number} pos\n * @returns {number}\n */\nexport function localAt(stops, pos) {\n const last = stops.length - 1;\n const i = clamp(Math.floor(pos), 0, last - 1);\n const f = clamp(pos - i, 0, 1);\n return stops[i] + (stops[i + 1] - stops[i]) * f;\n}\n\n/**\n * Inverse of {@link localAt} — needed to turn a pointer position back into\n * travel while dragging the slide.\n *\n * @param {number[]} stops\n * @param {number} want - Slide-local x.\n * @returns {number}\n */\nexport function posFromLocal(stops, want) {\n const last = stops.length - 1;\n if (want <= stops[0]) return 0;\n if (want >= stops[last]) return last;\n for (let i = 0; i < last; i++) {\n if (want <= stops[i + 1]) {\n return i + (want - stops[i]) / (stops[i + 1] - stops[i]);\n }\n }\n return last;\n}\n","import { forwardRef, useMemo, useRef } from \"react\";\nimport { usePointerDrag } from \"../../_shared/usePointerDrag.js\";\nimport { minorDivisions, pitchFor } from \"../geometry.js\";\n\n/**\n * L-I — Cursor Rule.\n *\n * The scale is fixed and the cursor travels: a glass runner with a scarlet\n * hairline, brass shoes at each end. Mechanically the simplest of the three\n * linear plates, and a strict subset of L-III.\n *\n * Decorative only — the navigation is the HTML list the parent renders above.\n */\nexport const CursorRule = forwardRef(function CursorRule(\n { spec, count, stations, travel, toViewBoxX },\n ref\n) {\n const [vbW, vbH] = spec.viewBox;\n const { x0, railX0, railX1, top, bot, cursorBox } = spec;\n const pitch = pitchFor(spec, count);\n const { minorsPerPitch, minorsPerDetent } = minorDivisions(pitch);\n\n const cursorRef = useRef(null);\n usePointerDrag(cursorRef, {\n onBegin: () => travel.begin(),\n onMove: (event) => {\n const x = toViewBoxX(event.clientX);\n if (x != null) travel.track((x - x0) / pitch);\n },\n onEnd: (_event, wasTap) => {\n if (!wasTap) travel.release();\n },\n });\n\n // Tick density follows L-III's minor divisions, so a three-station rule is\n // engraved as finely as a six-station one instead of showing three lonely\n // quarter marks per gap.\n const ticks = useMemo(() => {\n const out = [];\n for (let q = 0; q <= (count - 1) * minorsPerPitch; q++) {\n const isStation = q % minorsPerPitch === 0;\n const isDetent = q % minorsPerDetent === 0;\n out.push({\n x: x0 + (q / minorsPerPitch) * pitch,\n kind: isStation ? \"major\" : isDetent ? \"half\" : \"quarter\",\n down: isStation ? 22 : isDetent ? 13 : 8,\n up: isStation ? 18 : isDetent ? 11 : 7,\n station: isStation ? q / minorsPerPitch : null,\n });\n }\n return out;\n }, [count, minorsPerDetent, minorsPerPitch, pitch, x0]);\n\n const cursorX = x0 + travel.pos * pitch;\n const half = cursorBox.w / 2;\n const cursorTop = cursorBox.y;\n const cursorBottom = cursorBox.y + cursorBox.h;\n\n return (\n <svg\n ref={ref}\n className=\"ds-rule__chrome\"\n viewBox={`0 0 ${vbW} ${vbH}`}\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <rect\n className=\"ds-rule__rail\"\n x={railX0}\n y={top}\n width={railX1 - railX0}\n height={bot - top}\n rx={2}\n />\n <line\n className=\"ds-rule__tick ds-rule__tick--quarter\"\n x1={railX0}\n y1={(top + bot) / 2}\n x2={railX1}\n y2={(top + bot) / 2}\n />\n {[\n [railX0 + 10, top + 10],\n [railX1 - 10, top + 10],\n [railX0 + 10, bot - 10],\n [railX1 - 10, bot - 10],\n ].map(([cx, cy], i) => (\n <circle key={i} className=\"ds-rule__rivet\" cx={cx} cy={cy} r={3} />\n ))}\n\n {ticks.map((tick, i) => (\n <g key={i}>\n <line\n className={`ds-rule__tick ds-rule__tick--${tick.kind}`}\n x1={tick.x}\n y1={top}\n x2={tick.x}\n y2={top + tick.down}\n />\n <line\n className={`ds-rule__tick ds-rule__tick--${tick.kind}`}\n x1={tick.x}\n y1={bot}\n x2={tick.x}\n y2={bot - tick.up}\n />\n </g>\n ))}\n\n {/* Two number rows, one meaning each: the station's own scale value\n above, and the travel position below. */}\n {ticks\n .filter((tick) => tick.station != null)\n .map((tick) => (\n <g key={`n${tick.station}`}>\n <text\n className=\"ds-rule__numeral ds-rule__numeral--accent\"\n x={tick.x}\n y={top + 34}\n textAnchor=\"middle\"\n >\n {stations[tick.station]?.value ?? tick.station.toFixed(2)}\n </text>\n <text\n className=\"ds-rule__numeral\"\n x={tick.x}\n y={bot - 22}\n textAnchor=\"middle\"\n >\n {tick.station.toFixed(2)}\n </text>\n </g>\n ))}\n\n <g\n ref={cursorRef}\n className=\"ds-rule__carriage\"\n transform={`translate(${cursorX},0)`}\n >\n <rect\n className=\"ds-rule__glass\"\n x={-half}\n y={cursorTop}\n width={cursorBox.w}\n height={cursorBox.h}\n rx={2}\n />\n <rect\n className=\"ds-rule__frame\"\n x={-half}\n y={cursorTop}\n width={cursorBox.w}\n height={cursorBox.h}\n rx={3}\n />\n <rect\n className=\"ds-rule__shoe\"\n x={-half - 2}\n y={cursorTop}\n width={cursorBox.w + 4}\n height={7}\n rx={2}\n />\n <rect\n className=\"ds-rule__shoe\"\n x={-half - 2}\n y={cursorBottom - 7}\n width={cursorBox.w + 4}\n height={7}\n rx={2}\n />\n {[\n [-24, cursorTop + 3.5],\n [24, cursorTop + 3.5],\n [-24, cursorBottom - 3.5],\n [24, cursorBottom - 3.5],\n ].map(([cx, cy], i) => (\n <circle key={i} className=\"ds-rule__rivet\" cx={cx} cy={cy} r={2.2} />\n ))}\n <line\n className=\"ds-rule__hairline\"\n x1={0}\n y1={cursorTop}\n x2={0}\n y2={cursorBottom}\n />\n </g>\n </svg>\n );\n});\n","import { forwardRef, useId, useMemo, useRef } from \"react\";\nimport { usePointerDrag } from \"../../_shared/usePointerDrag.js\";\nimport {\n logStops,\n localAt,\n posFromLocal,\n slideValues,\n statorX,\n} from \"../geometry.js\";\n\n/** Ticks for a full log10 decade, at slide-rule gradations. */\nfunction decadeTicks(mapX) {\n const bands = [\n [1, 2, 0.02, 0.1],\n [2, 5, 0.05, 0.5],\n [5, 10, 0.1, 1],\n ];\n const out = [];\n for (const [a, b, step, major] of bands) {\n for (let v = a; v < b + 1e-9; v += step) {\n const isMajor = Math.abs(v / major - Math.round(v / major)) < 1e-6;\n const half = Math.abs(v / (major / 2) - Math.round(v / (major / 2))) < 1e-6;\n out.push({\n x: mapX(v),\n v,\n len: isMajor ? 12 : half ? 8 : 5,\n kind: isMajor ? \"major\" : half ? \"half\" : \"quarter\",\n label: isMajor ? String(Math.round(v * 10) / 10) : null,\n });\n }\n }\n return out;\n}\n\n/**\n * L-II — Slide & Stator.\n *\n * Inverted from L-I: the index stays put and the slide travels beneath it.\n * Stations sit at true log10 positions, so the gaps compress toward the right\n * of the rule and each quarter-detent inherits that compression — the\n * mechanism genuinely tightens at the far end. The unevenness is the point.\n *\n * Decorative only — the navigation is the HTML list the parent renders above,\n * which rides the same offset this slide does.\n */\nexport const SlideStator = forwardRef(function SlideStator(\n { spec, count, stations, travel, toViewBoxX },\n ref\n) {\n const [vbW, vbH] = spec.viewBox;\n const { index, slideY, slideH, clip } = spec;\n const clipId = useId();\n\n const stops = useMemo(() => logStops(spec, count), [spec, count]);\n const values = slideValues(count);\n const offset = index - localAt(stops, travel.pos);\n\n const grabbed = useRef(0);\n const slideRef = useRef(null);\n usePointerDrag(slideRef, {\n onBegin: (event) => {\n travel.begin();\n const x = toViewBoxX(event.clientX);\n grabbed.current = localAt(stops, travel.pos) + (x == null ? 0 : x - index);\n },\n onMove: (event) => {\n const x = toViewBoxX(event.clientX);\n if (x == null) return;\n travel.track(posFromLocal(stops, grabbed.current - (x - index)));\n },\n onEnd: (_event, wasTap) => {\n if (!wasTap) travel.release();\n },\n });\n\n const statorTicks = useMemo(\n () => decadeTicks((v) => statorX(spec, v)),\n [spec]\n );\n\n // Quarter-detent marks on the slide, unevenly spaced by construction.\n const detents = useMemo(() => {\n const out = [];\n for (let q = 0; q <= (count - 1) * 4; q++) {\n if (q % 4 === 0) continue;\n out.push({ x: localAt(stops, q / 4), half: q % 2 === 0 });\n }\n return out;\n }, [count, stops]);\n\n const slideBottom = slideY + slideH;\n\n return (\n <svg\n ref={ref}\n className=\"ds-rule__chrome\"\n viewBox={`0 0 ${vbW} ${vbH}`}\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <defs>\n <clipPath id={clipId}>\n <rect x={clip[0]} y={0} width={clip[1] - clip[0]} height={vbH} />\n </clipPath>\n </defs>\n\n {/* Fixed stators, above and below the slide. */}\n <rect\n className=\"ds-rule__rail\"\n x={clip[0]}\n y={6}\n width={clip[1] - clip[0]}\n height={40}\n />\n <rect\n className=\"ds-rule__rail\"\n x={clip[0]}\n y={slideBottom}\n width={clip[1] - clip[0]}\n height={40}\n />\n {statorTicks.map((tick, i) => (\n <g key={i}>\n <line\n className={`ds-rule__tick ds-rule__tick--${tick.kind}`}\n x1={tick.x}\n y1={46}\n x2={tick.x}\n y2={46 - tick.len}\n />\n <line\n className={`ds-rule__tick ds-rule__tick--${tick.kind}`}\n x1={tick.x}\n y1={slideBottom}\n x2={tick.x}\n y2={slideBottom + tick.len}\n />\n {tick.label && (\n <>\n <text\n className=\"ds-rule__numeral\"\n x={tick.x}\n y={46 - tick.len - 3}\n textAnchor=\"middle\"\n >\n {tick.label}\n </text>\n <text\n className=\"ds-rule__numeral\"\n x={tick.x}\n y={slideBottom + tick.len + 9}\n textAnchor=\"middle\"\n >\n {tick.label}\n </text>\n </>\n )}\n </g>\n ))}\n <text className=\"ds-rule__caption\" x={clip[0] + 6} y={44}>\n C\n </text>\n <text className=\"ds-rule__caption\" x={clip[0] + 6} y={slideBottom + 12}>\n D\n </text>\n\n {/* The slide itself, clipped to the window. */}\n <g clipPath={`url(#${clipId})`}>\n <g\n ref={slideRef}\n className=\"ds-rule__carriage\"\n transform={`translate(${offset},0)`}\n >\n <rect\n className=\"ds-rule__slide\"\n x={stops[0] - 400}\n y={slideY}\n width={stops[stops.length - 1] - stops[0] + 800}\n height={slideH}\n />\n {detents.map((d, i) => (\n <g key={i}>\n <line\n className=\"ds-rule__tick ds-rule__tick--quarter\"\n x1={d.x}\n y1={slideY}\n x2={d.x}\n y2={slideY + (d.half ? 10 : 6)}\n />\n <line\n className=\"ds-rule__tick ds-rule__tick--quarter\"\n x1={d.x}\n y1={slideBottom}\n x2={d.x}\n y2={slideBottom - (d.half ? 10 : 6)}\n />\n </g>\n ))}\n {stops.map((x, i) => (\n <g key={i}>\n <line\n className=\"ds-rule__tick ds-rule__tick--major\"\n x1={x}\n y1={slideY}\n x2={x}\n y2={slideY + 14}\n />\n <line\n className=\"ds-rule__tick ds-rule__tick--major\"\n x1={x}\n y1={slideBottom}\n x2={x}\n y2={slideBottom - 14}\n />\n <text\n className=\"ds-rule__numeral ds-rule__numeral--accent\"\n x={x}\n y={slideBottom - 4}\n textAnchor=\"middle\"\n >\n {stations[i]?.value ?? values[i].toFixed(2)}\n </text>\n </g>\n ))}\n </g>\n </g>\n\n {/* Fixed index and glass window. */}\n <g className=\"ds-rule__window\">\n <rect\n className=\"ds-rule__glass\"\n x={index - 58}\n y={2}\n width={116}\n height={vbH - 4}\n rx={2}\n />\n <rect\n className=\"ds-rule__frame\"\n x={index - 58}\n y={2}\n width={116}\n height={vbH - 4}\n rx={3}\n />\n <line\n className=\"ds-rule__hairline\"\n x1={index}\n y1={2}\n x2={index}\n y2={vbH - 2}\n />\n <path\n className=\"ds-rule__index\"\n d={`M${index - 7},2 L${index + 7},2 L${index},13 Z`}\n />\n <path\n className=\"ds-rule__index\"\n d={`M${index - 7},${vbH - 2} L${index + 7},${vbH - 2} L${index},${\n vbH - 13\n } Z`}\n />\n <text\n className=\"ds-rule__caption ds-rule__caption--accent\"\n x={index + 64}\n y={12}\n >\n INDEX\n </text>\n </g>\n </svg>\n );\n});\n","import { forwardRef, useMemo, useRef } from \"react\";\nimport { usePointerDrag } from \"../../_shared/usePointerDrag.js\";\nimport { minorDivisions, pitchFor, coincidence } from \"../geometry.js\";\n\n/**\n * L-III — Vernier Carriage.\n *\n * A notched rail with a sprung pawl and a working vernier: five carriage\n * divisions span four rail divisions, so at any offset exactly one line pair\n * coincides and its index gives the fraction. Release and the pawl seats, the\n * zero lines coincide, and the reading goes whole.\n *\n * Everything here is decorative and hidden from assistive technology; the\n * navigation is the HTML list the parent renders over it.\n */\nexport const VernierCarriage = forwardRef(function VernierCarriage(\n { spec, count, stations, travel, toViewBoxX },\n ref\n) {\n const [vbW, vbH] = spec.viewBox;\n const { x0, railX0, railX1, railY, railH } = spec;\n const bot = railY + railH;\n const pitch = pitchFor(spec, count);\n const { minor, vdiv, minorsPerPitch, minorsPerDetent } =\n minorDivisions(pitch);\n\n const carriageRef = useRef(null);\n usePointerDrag(carriageRef, {\n onBegin: () => travel.begin(),\n onMove: (event) => {\n const x = toViewBoxX(event.clientX);\n if (x != null) travel.track((x - x0) / pitch);\n },\n onEnd: (_event, wasTap) => {\n if (!wasTap) travel.release();\n },\n });\n\n const totalMinors = (count - 1) * minorsPerPitch;\n\n /* Rail outline: the notches are cut geometry, so they survive the fill. */\n const rail = useMemo(() => {\n let d = `M${railX0},${bot} L${railX0},${railY} `;\n for (let q = 0; q <= totalMinors; q++) {\n const tx = x0 + (q / minorsPerPitch) * pitch;\n const deep = q % minorsPerDetent === 0;\n const w = deep ? 7 : 4;\n const dep = deep ? 9 : 5;\n d += `L${tx - w},${railY} L${tx},${railY + dep} L${tx + w},${railY} `;\n }\n return `${d}L${railX1},${railY} L${railX1},${bot} Z`;\n }, [bot, minorsPerDetent, minorsPerPitch, pitch, railX0, railX1, railY, totalMinors, x0]);\n\n const ticks = useMemo(() => {\n const out = [];\n for (let q = 0; q <= totalMinors; q++) {\n const tx = x0 + (q / minorsPerPitch) * pitch;\n const isStation = q % minorsPerPitch === 0;\n const isDetent = q % minorsPerDetent === 0;\n out.push({\n x: tx,\n len: isStation ? 20 : isDetent ? 13 : 8,\n kind: isStation ? \"major\" : isDetent ? \"half\" : \"quarter\",\n station: isStation ? q / minorsPerPitch : null,\n });\n }\n return out;\n }, [minorsPerDetent, minorsPerPitch, pitch, totalMinors, x0]);\n\n const { pos } = travel;\n const carriageX = x0 + pos * pitch;\n const lit = coincidence({ pos, count, spec });\n\n // The pawl rides up out of its notch between detents and drops back in.\n const frac = Math.abs(pos * minorsPerPitch - Math.round(pos * minorsPerPitch));\n const pawlY = railY + 2 - frac * 13;\n\n const glassW = vdiv * 5.8;\n const captionLeft = carriageX + glassW / 2 + 60 > railX1;\n\n return (\n <svg\n ref={ref}\n className=\"ds-rule__chrome\"\n viewBox={`0 0 ${vbW} ${vbH}`}\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path className=\"ds-rule__rail\" d={rail} />\n <circle className=\"ds-rule__rivet\" cx={railX0 + 10} cy={bot - 8} r={3} />\n <circle className=\"ds-rule__rivet\" cx={railX1 - 10} cy={bot - 8} r={3} />\n\n {ticks.map((tick, i) => (\n <line\n key={i}\n className={`ds-rule__tick ds-rule__tick--${tick.kind}`}\n x1={tick.x}\n y1={bot}\n x2={tick.x}\n y2={bot - tick.len}\n />\n ))}\n\n {ticks\n .filter((tick) => tick.station != null)\n .map((tick) => (\n <text\n key={`n${tick.station}`}\n className=\"ds-rule__numeral ds-rule__numeral--accent\"\n x={tick.x}\n y={bot - 24}\n textAnchor=\"middle\"\n >\n {stations[tick.station]?.value ?? tick.station.toFixed(2)}\n </text>\n ))}\n\n <text className=\"ds-rule__caption\" x={railX0 + 6} y={railY - 8}>\n MAIN\n </text>\n\n {/* Leader ticks up to the HTML station labels. */}\n {ticks\n .filter((tick) => tick.station != null)\n .map((tick) => (\n <line\n key={`l${tick.station}`}\n className=\"ds-rule__tick ds-rule__tick--quarter\"\n x1={tick.x}\n y1={railY - 16}\n x2={tick.x}\n y2={railY - 9}\n />\n ))}\n\n <g\n ref={carriageRef}\n className=\"ds-rule__carriage\"\n transform={`translate(${carriageX},0)`}\n >\n <rect\n className=\"ds-rule__pawl-spring\"\n x={-2}\n y={pawlY - 24}\n width={4}\n height={11}\n />\n <path\n className=\"ds-rule__pawl\"\n d=\"M-6,-11 L6,-11 L0,2 Z\"\n transform={`translate(0,${pawlY})`}\n />\n <rect\n className=\"ds-rule__glass\"\n x={-glassW / 2}\n y={railY - 2}\n width={glassW}\n height={railH + 50}\n rx={2}\n />\n <rect\n className=\"ds-rule__frame\"\n x={-glassW / 2}\n y={railY - 2}\n width={glassW}\n height={railH + 50}\n rx={3}\n />\n <line\n className=\"ds-rule__hairline\"\n x1={0}\n y1={railY - 2}\n x2={0}\n y2={bot + 48}\n />\n {Array.from({ length: 6 }, (_, k) => {\n const vx = (k - 2.5) * vdiv;\n const on = k === lit.k && lit.lit;\n return (\n <g key={k}>\n <line\n className={\n \"ds-rule__vernier-line\" +\n (on ? \" ds-rule__vernier-line--lit\" : \"\")\n }\n x1={vx}\n y1={bot + 2}\n x2={vx}\n y2={bot + 18}\n />\n {k < 5 && (\n <text\n className=\"ds-rule__numeral\"\n x={vx}\n y={bot + 28}\n textAnchor=\"middle\"\n >\n {k}\n </text>\n )}\n </g>\n );\n })}\n {/* Flip the caption inboard once the carriage nears the right end. */}\n <text\n className=\"ds-rule__caption\"\n x={captionLeft ? -glassW / 2 - 6 : glassW / 2 + 6}\n y={bot + 18}\n textAnchor={captionLeft ? \"end\" : \"start\"}\n >\n VERNIER\n </text>\n </g>\n </svg>\n );\n});\n"],"mappings":";;;;;;;;AAAA,SAAS,aAAa,WAAW,WAAAA,UAAS,UAAAC,SAAQ,gBAAgB;AAClE,SAAS,eAAe;;;ACSjB,IAAM,eAAe;AAErB,IAAM,SAAS,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASlC,QAAQ,OAAO,OAAO;AAAA,IACpB,SAAS,OAAO,OAAO,CAAC,KAAK,GAAG,CAAC;AAAA,IACjC,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,WAAW,OAAO,OAAO,EAAE,GAAG,IAAI,GAAG,KAAK,GAAG,GAAG,CAAC;AAAA,IACjD,UAAU;AAAA,EACZ,CAAC;AAAA;AAAA,EAED,OAAO,OAAO,OAAO;AAAA,IACnB,SAAS,OAAO,OAAO,CAAC,KAAK,GAAG,CAAC;AAAA,IACjC,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,MAAM,OAAO,OAAO,CAAC,IAAI,GAAG,CAAC;AAAA,IAC7B,UAAU;AAAA,IACV,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeD,SAAS,OAAO,OAAO;AAAA,IACrB,SAAS,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC;AAAA,IAClC,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,sBAAsB;AAAA;AAAA,IAEtB,iBAAiB;AAAA,IACjB,UAAU;AAAA,EACZ,CAAC;AACH,CAAC;AAWM,IAAM,eAAe,OAAO,OAAO;AAAA,EACxC,GAAG,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;AAAA,EACvB,GAAG,OAAO,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;AAAA,EAC1B,GAAG,OAAO,OAAO,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;AAAA,EAC7B,GAAG,OAAO,OAAO,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;AAAA,EAClC,GAAG,OAAO,OAAO,CAAC,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC;AAAA,EACrC,GAAG,OAAO,OAAO,CAAC,GAAG,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;AAAA,EACxC,GAAG,OAAO,OAAO,CAAC,GAAG,KAAK,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC;AAC/C,CAAC;AAGM,IAAM,MAAM,CAAC,GAAG,WAAW,GAAI,IAAI,SAAU,GAAG;AAEvD,IAAM,QAAQ,CAAC,GAAG,IAAI,OAAQ,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK;AASnD,SAAS,SAAS,MAAM,OAAO;AACpC,UAAQ,KAAK,KAAK,KAAK,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC;AACpD;AAkBO,SAAS,eAAe,OAAO;AACpC,QAAM,iBACJ,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,IAAI,aAAa,CAAC;AACxD,QAAM,QAAQ,QAAQ;AACtB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAO,QAAQ,IAAK;AAAA,IACpB,iBAAiB,iBAAiB;AAAA,EACpC;AACF;AAcO,SAAS,YAAY,EAAE,KAAK,OAAO,OAAO,OAAO,QAAQ,GAAG;AACjE,QAAM,QAAQ,SAAS,MAAM,KAAK;AAClC,QAAM,EAAE,OAAO,KAAK,IAAI,eAAe,KAAK;AAC5C,QAAM,KAAK,KAAK,KAAK,MAAM;AAM3B,MAAI,IAAI;AACR,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,kBAAkB,KAAK;AACxD,UAAM,KAAK,MAAM,IAAI,OAAO;AAC5B,UAAM,MAAM,KAAK,KAAK;AACtB,UAAM,OAAO,KAAK,IAAI,MAAM,KAAK,MAAM,MAAM,KAAK,IAAI,KAAK;AAC3D,QAAI,OAAO,IAAI,MAAM;AACnB,UAAI;AACJ,UAAI;AAAA,IACN;AAAA,EACF;AACA,SAAO,EAAE,GAAG,GAAG,KAAK,IAAI,OAAO,KAAK;AACtC;AAKO,IAAM,OAAO,CAAC,MAAM,MAAM,KAAK,KAAK,KAAK,MAAM,CAAC,IAAI,KAAK;AAGzD,IAAM,cAAc,CAAC,UAC1B,aAAa,KAAK,KAAK,aAAa,CAAC;AAGhC,IAAM,WAAW,CAAC,MAAM,UAC7B,YAAY,KAAK,EAAE,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;AAGtC,IAAM,UAAU,CAAC,MAAM,MAC5B,KAAK,WAAW,KAAK,MAAM,CAAC,IAAI,KAAK;AAWhC,SAAS,QAAQ,OAAO,KAAK;AAClC,QAAM,OAAO,MAAM,SAAS;AAC5B,QAAM,IAAI,MAAM,KAAK,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC;AAC5C,QAAM,IAAI,MAAM,MAAM,GAAG,GAAG,CAAC;AAC7B,SAAO,MAAM,CAAC,KAAK,MAAM,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK;AAChD;AAUO,SAAS,aAAa,OAAO,MAAM;AACxC,QAAM,OAAO,MAAM,SAAS;AAC5B,MAAI,QAAQ,MAAM,CAAC,EAAG,QAAO;AAC7B,MAAI,QAAQ,MAAM,IAAI,EAAG,QAAO;AAChC,WAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC7B,QAAI,QAAQ,MAAM,IAAI,CAAC,GAAG;AACxB,aAAO,KAAK,OAAO,MAAM,CAAC,MAAM,MAAM,IAAI,CAAC,IAAI,MAAM,CAAC;AAAA,IACxD;AAAA,EACF;AACA,SAAO;AACT;;;ACnOA,SAAS,YAAY,SAAS,cAAc;AAkEtC,cAyBE,YAzBF;AArDC,IAAM,aAAa,WAAW,SAASC,YAC5C,EAAE,MAAM,OAAO,UAAU,QAAQ,WAAW,GAC5C,KACA;AACA,QAAM,CAAC,KAAK,GAAG,IAAI,KAAK;AACxB,QAAM,EAAE,IAAI,QAAQ,QAAQ,KAAK,KAAK,UAAU,IAAI;AACpD,QAAM,QAAQ,SAAS,MAAM,KAAK;AAClC,QAAM,EAAE,gBAAgB,gBAAgB,IAAI,eAAe,KAAK;AAEhE,QAAM,YAAY,OAAO,IAAI;AAC7B,iBAAe,WAAW;AAAA,IACxB,SAAS,MAAM,OAAO,MAAM;AAAA,IAC5B,QAAQ,CAAC,UAAU;AACjB,YAAM,IAAI,WAAW,MAAM,OAAO;AAClC,UAAI,KAAK,KAAM,QAAO,OAAO,IAAI,MAAM,KAAK;AAAA,IAC9C;AAAA,IACA,OAAO,CAAC,QAAQ,WAAW;AACzB,UAAI,CAAC,OAAQ,QAAO,QAAQ;AAAA,IAC9B;AAAA,EACF,CAAC;AAKD,QAAM,QAAQ,QAAQ,MAAM;AAC1B,UAAM,MAAM,CAAC;AACb,aAAS,IAAI,GAAG,MAAM,QAAQ,KAAK,gBAAgB,KAAK;AACtD,YAAM,YAAY,IAAI,mBAAmB;AACzC,YAAM,WAAW,IAAI,oBAAoB;AACzC,UAAI,KAAK;AAAA,QACP,GAAG,KAAM,IAAI,iBAAkB;AAAA,QAC/B,MAAM,YAAY,UAAU,WAAW,SAAS;AAAA,QAChD,MAAM,YAAY,KAAK,WAAW,KAAK;AAAA,QACvC,IAAI,YAAY,KAAK,WAAW,KAAK;AAAA,QACrC,SAAS,YAAY,IAAI,iBAAiB;AAAA,MAC5C,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,iBAAiB,gBAAgB,OAAO,EAAE,CAAC;AAEtD,QAAM,UAAU,KAAK,OAAO,MAAM;AAClC,QAAM,OAAO,UAAU,IAAI;AAC3B,QAAM,YAAY,UAAU;AAC5B,QAAM,eAAe,UAAU,IAAI,UAAU;AAE7C,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MACV,SAAS,OAAO,GAAG,IAAI,GAAG;AAAA,MAC1B,eAAY;AAAA,MACZ,WAAU;AAAA,MAEV;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,GAAG;AAAA,YACH,GAAG;AAAA,YACH,OAAO,SAAS;AAAA,YAChB,QAAQ,MAAM;AAAA,YACd,IAAI;AAAA;AAAA,QACN;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,IAAI;AAAA,YACJ,KAAK,MAAM,OAAO;AAAA,YAClB,IAAI;AAAA,YACJ,KAAK,MAAM,OAAO;AAAA;AAAA,QACpB;AAAA,QACC;AAAA,UACC,CAAC,SAAS,IAAI,MAAM,EAAE;AAAA,UACtB,CAAC,SAAS,IAAI,MAAM,EAAE;AAAA,UACtB,CAAC,SAAS,IAAI,MAAM,EAAE;AAAA,UACtB,CAAC,SAAS,IAAI,MAAM,EAAE;AAAA,QACxB,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,GAAG,MACf,oBAAC,YAAe,WAAU,kBAAiB,IAAQ,IAAQ,GAAG,KAAjD,CAAoD,CAClE;AAAA,QAEA,MAAM,IAAI,CAAC,MAAM,MAChB,qBAAC,OACC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,gCAAgC,KAAK,IAAI;AAAA,cACpD,IAAI,KAAK;AAAA,cACT,IAAI;AAAA,cACJ,IAAI,KAAK;AAAA,cACT,IAAI,MAAM,KAAK;AAAA;AAAA,UACjB;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,gCAAgC,KAAK,IAAI;AAAA,cACpD,IAAI,KAAK;AAAA,cACT,IAAI;AAAA,cACJ,IAAI,KAAK;AAAA,cACT,IAAI,MAAM,KAAK;AAAA;AAAA,UACjB;AAAA,aAdM,CAeR,CACD;AAAA,QAIA,MACE,OAAO,CAAC,SAAS,KAAK,WAAW,IAAI,EACrC,IAAI,CAAC,SACJ,qBAAC,OACC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,GAAG,KAAK;AAAA,cACR,GAAG,MAAM;AAAA,cACT,YAAW;AAAA,cAEV,mBAAS,KAAK,OAAO,GAAG,SAAS,KAAK,QAAQ,QAAQ,CAAC;AAAA;AAAA,UAC1D;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,GAAG,KAAK;AAAA,cACR,GAAG,MAAM;AAAA,cACT,YAAW;AAAA,cAEV,eAAK,QAAQ,QAAQ,CAAC;AAAA;AAAA,UACzB;AAAA,aAhBM,IAAI,KAAK,OAAO,EAiBxB,CACD;AAAA,QAEH;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,WAAU;AAAA,YACV,WAAW,aAAa,OAAO;AAAA,YAE/B;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,GAAG,CAAC;AAAA,kBACJ,GAAG;AAAA,kBACH,OAAO,UAAU;AAAA,kBACjB,QAAQ,UAAU;AAAA,kBAClB,IAAI;AAAA;AAAA,cACN;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,GAAG,CAAC;AAAA,kBACJ,GAAG;AAAA,kBACH,OAAO,UAAU;AAAA,kBACjB,QAAQ,UAAU;AAAA,kBAClB,IAAI;AAAA;AAAA,cACN;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,GAAG,CAAC,OAAO;AAAA,kBACX,GAAG;AAAA,kBACH,OAAO,UAAU,IAAI;AAAA,kBACrB,QAAQ;AAAA,kBACR,IAAI;AAAA;AAAA,cACN;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,GAAG,CAAC,OAAO;AAAA,kBACX,GAAG,eAAe;AAAA,kBAClB,OAAO,UAAU,IAAI;AAAA,kBACrB,QAAQ;AAAA,kBACR,IAAI;AAAA;AAAA,cACN;AAAA,cACC;AAAA,gBACC,CAAC,KAAK,YAAY,GAAG;AAAA,gBACrB,CAAC,IAAI,YAAY,GAAG;AAAA,gBACpB,CAAC,KAAK,eAAe,GAAG;AAAA,gBACxB,CAAC,IAAI,eAAe,GAAG;AAAA,cACzB,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,GAAG,MACf,oBAAC,YAAe,WAAU,kBAAiB,IAAQ,IAAQ,GAAG,OAAjD,CAAsD,CACpE;AAAA,cACD;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,IAAI;AAAA,kBACJ,IAAI;AAAA,kBACJ,IAAI;AAAA,kBACJ,IAAI;AAAA;AAAA,cACN;AAAA;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ,CAAC;;;AC7LD,SAAS,cAAAC,aAAY,OAAO,WAAAC,UAAS,UAAAC,eAAc;AAsGzC,SAoCE,UApCF,OAAAC,MAoCE,QAAAC,aApCF;AA3FV,SAAS,YAAY,MAAM;AACzB,QAAM,QAAQ;AAAA,IACZ,CAAC,GAAG,GAAG,MAAM,GAAG;AAAA,IAChB,CAAC,GAAG,GAAG,MAAM,GAAG;AAAA,IAChB,CAAC,GAAG,IAAI,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,MAAM,CAAC;AACb,aAAW,CAAC,GAAG,GAAG,MAAM,KAAK,KAAK,OAAO;AACvC,aAAS,IAAI,GAAG,IAAI,IAAI,MAAM,KAAK,MAAM;AACvC,YAAM,UAAU,KAAK,IAAI,IAAI,QAAQ,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI;AAC9D,YAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,KAAK,KAAK,MAAM,KAAK,QAAQ,EAAE,CAAC,IAAI;AACvE,UAAI,KAAK;AAAA,QACP,GAAG,KAAK,CAAC;AAAA,QACT;AAAA,QACA,KAAK,UAAU,KAAK,OAAO,IAAI;AAAA,QAC/B,MAAM,UAAU,UAAU,OAAO,SAAS;AAAA,QAC1C,OAAO,UAAU,OAAO,KAAK,MAAM,IAAI,EAAE,IAAI,EAAE,IAAI;AAAA,MACrD,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAaO,IAAM,cAAcC,YAAW,SAASC,aAC7C,EAAE,MAAM,OAAO,UAAU,QAAQ,WAAW,GAC5C,KACA;AACA,QAAM,CAAC,KAAK,GAAG,IAAI,KAAK;AACxB,QAAM,EAAE,OAAO,QAAQ,QAAQ,KAAK,IAAI;AACxC,QAAM,SAAS,MAAM;AAErB,QAAM,QAAQC,SAAQ,MAAM,SAAS,MAAM,KAAK,GAAG,CAAC,MAAM,KAAK,CAAC;AAChE,QAAM,SAAS,YAAY,KAAK;AAChC,QAAM,SAAS,QAAQ,QAAQ,OAAO,OAAO,GAAG;AAEhD,QAAM,UAAUC,QAAO,CAAC;AACxB,QAAM,WAAWA,QAAO,IAAI;AAC5B,iBAAe,UAAU;AAAA,IACvB,SAAS,CAAC,UAAU;AAClB,aAAO,MAAM;AACb,YAAM,IAAI,WAAW,MAAM,OAAO;AAClC,cAAQ,UAAU,QAAQ,OAAO,OAAO,GAAG,KAAK,KAAK,OAAO,IAAI,IAAI;AAAA,IACtE;AAAA,IACA,QAAQ,CAAC,UAAU;AACjB,YAAM,IAAI,WAAW,MAAM,OAAO;AAClC,UAAI,KAAK,KAAM;AACf,aAAO,MAAM,aAAa,OAAO,QAAQ,WAAW,IAAI,MAAM,CAAC;AAAA,IACjE;AAAA,IACA,OAAO,CAAC,QAAQ,WAAW;AACzB,UAAI,CAAC,OAAQ,QAAO,QAAQ;AAAA,IAC9B;AAAA,EACF,CAAC;AAED,QAAM,cAAcD;AAAA,IAClB,MAAM,YAAY,CAAC,MAAM,QAAQ,MAAM,CAAC,CAAC;AAAA,IACzC,CAAC,IAAI;AAAA,EACP;AAGA,QAAM,UAAUA,SAAQ,MAAM;AAC5B,UAAM,MAAM,CAAC;AACb,aAAS,IAAI,GAAG,MAAM,QAAQ,KAAK,GAAG,KAAK;AACzC,UAAI,IAAI,MAAM,EAAG;AACjB,UAAI,KAAK,EAAE,GAAG,QAAQ,OAAO,IAAI,CAAC,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;AAAA,IAC1D;AACA,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,KAAK,CAAC;AAEjB,QAAM,cAAc,SAAS;AAE7B,SACE,gBAAAH;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MACV,SAAS,OAAO,GAAG,IAAI,GAAG;AAAA,MAC1B,eAAY;AAAA,MACZ,WAAU;AAAA,MAEV;AAAA,wBAAAD,KAAC,UACC,0BAAAA,KAAC,cAAS,IAAI,QACZ,0BAAAA,KAAC,UAAK,GAAG,KAAK,CAAC,GAAG,GAAG,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,QAAQ,KAAK,GACjE,GACF;AAAA,QAGA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,GAAG,KAAK,CAAC;AAAA,YACT,GAAG;AAAA,YACH,OAAO,KAAK,CAAC,IAAI,KAAK,CAAC;AAAA,YACvB,QAAQ;AAAA;AAAA,QACV;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,GAAG,KAAK,CAAC;AAAA,YACT,GAAG;AAAA,YACH,OAAO,KAAK,CAAC,IAAI,KAAK,CAAC;AAAA,YACvB,QAAQ;AAAA;AAAA,QACV;AAAA,QACC,YAAY,IAAI,CAAC,MAAM,MACtB,gBAAAC,MAAC,OACC;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,gCAAgC,KAAK,IAAI;AAAA,cACpD,IAAI,KAAK;AAAA,cACT,IAAI;AAAA,cACJ,IAAI,KAAK;AAAA,cACT,IAAI,KAAK,KAAK;AAAA;AAAA,UAChB;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,gCAAgC,KAAK,IAAI;AAAA,cACpD,IAAI,KAAK;AAAA,cACT,IAAI;AAAA,cACJ,IAAI,KAAK;AAAA,cACT,IAAI,cAAc,KAAK;AAAA;AAAA,UACzB;AAAA,UACC,KAAK,SACJ,gBAAAC,MAAA,YACE;AAAA,4BAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,GAAG,KAAK;AAAA,gBACR,GAAG,KAAK,KAAK,MAAM;AAAA,gBACnB,YAAW;AAAA,gBAEV,eAAK;AAAA;AAAA,YACR;AAAA,YACA,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,GAAG,KAAK;AAAA,gBACR,GAAG,cAAc,KAAK,MAAM;AAAA,gBAC5B,YAAW;AAAA,gBAEV,eAAK;AAAA;AAAA,YACR;AAAA,aACF;AAAA,aAjCI,CAmCR,CACD;AAAA,QACD,gBAAAA,KAAC,UAAK,WAAU,oBAAmB,GAAG,KAAK,CAAC,IAAI,GAAG,GAAG,IAAI,eAE1D;AAAA,QACA,gBAAAA,KAAC,UAAK,WAAU,oBAAmB,GAAG,KAAK,CAAC,IAAI,GAAG,GAAG,cAAc,IAAI,eAExE;AAAA,QAGA,gBAAAA,KAAC,OAAE,UAAU,QAAQ,MAAM,KACzB,0BAAAC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,WAAU;AAAA,YACV,WAAW,aAAa,MAAM;AAAA,YAE9B;AAAA,8BAAAD;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,GAAG,MAAM,CAAC,IAAI;AAAA,kBACd,GAAG;AAAA,kBACH,OAAO,MAAM,MAAM,SAAS,CAAC,IAAI,MAAM,CAAC,IAAI;AAAA,kBAC5C,QAAQ;AAAA;AAAA,cACV;AAAA,cACC,QAAQ,IAAI,CAAC,GAAG,MACf,gBAAAC,MAAC,OACC;AAAA,gCAAAD;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,IAAI,EAAE;AAAA,oBACN,IAAI;AAAA,oBACJ,IAAI,EAAE;AAAA,oBACN,IAAI,UAAU,EAAE,OAAO,KAAK;AAAA;AAAA,gBAC9B;AAAA,gBACA,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,IAAI,EAAE;AAAA,oBACN,IAAI;AAAA,oBACJ,IAAI,EAAE;AAAA,oBACN,IAAI,eAAe,EAAE,OAAO,KAAK;AAAA;AAAA,gBACnC;AAAA,mBAdM,CAeR,CACD;AAAA,cACA,MAAM,IAAI,CAAC,GAAG,MACb,gBAAAC,MAAC,OACC;AAAA,gCAAAD;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,IAAI;AAAA,oBACJ,IAAI;AAAA,oBACJ,IAAI;AAAA,oBACJ,IAAI,SAAS;AAAA;AAAA,gBACf;AAAA,gBACA,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,IAAI;AAAA,oBACJ,IAAI;AAAA,oBACJ,IAAI;AAAA,oBACJ,IAAI,cAAc;AAAA;AAAA,gBACpB;AAAA,gBACA,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV;AAAA,oBACA,GAAG,cAAc;AAAA,oBACjB,YAAW;AAAA,oBAEV,mBAAS,CAAC,GAAG,SAAS,OAAO,CAAC,EAAE,QAAQ,CAAC;AAAA;AAAA,gBAC5C;AAAA,mBAtBM,CAuBR,CACD;AAAA;AAAA;AAAA,QACH,GACF;AAAA,QAGA,gBAAAC,MAAC,OAAE,WAAU,mBACX;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,GAAG,QAAQ;AAAA,cACX,GAAG;AAAA,cACH,OAAO;AAAA,cACP,QAAQ,MAAM;AAAA,cACd,IAAI;AAAA;AAAA,UACN;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,GAAG,QAAQ;AAAA,cACX,GAAG;AAAA,cACH,OAAO;AAAA,cACP,QAAQ,MAAM;AAAA,cACd,IAAI;AAAA;AAAA,UACN;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,IAAI;AAAA,cACJ,IAAI;AAAA,cACJ,IAAI;AAAA,cACJ,IAAI,MAAM;AAAA;AAAA,UACZ;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,GAAG,IAAI,QAAQ,CAAC,OAAO,QAAQ,CAAC,OAAO,KAAK;AAAA;AAAA,UAC9C;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,GAAG,IAAI,QAAQ,CAAC,IAAI,MAAM,CAAC,KAAK,QAAQ,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,IAC5D,MAAM,EACR;AAAA;AAAA,UACF;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,GAAG,QAAQ;AAAA,cACX,GAAG;AAAA,cACJ;AAAA;AAAA,UAED;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ,CAAC;;;AChRD,SAAS,cAAAM,aAAY,WAAAC,UAAS,UAAAC,eAAc;AAwFtC,gBAAAC,MA2FM,QAAAC,aA3FN;AAzEC,IAAM,kBAAkBC,YAAW,SAASC,iBACjD,EAAE,MAAM,OAAO,UAAU,QAAQ,WAAW,GAC5C,KACA;AACA,QAAM,CAAC,KAAK,GAAG,IAAI,KAAK;AACxB,QAAM,EAAE,IAAI,QAAQ,QAAQ,OAAO,MAAM,IAAI;AAC7C,QAAM,MAAM,QAAQ;AACpB,QAAM,QAAQ,SAAS,MAAM,KAAK;AAClC,QAAM,EAAE,OAAO,MAAM,gBAAgB,gBAAgB,IACnD,eAAe,KAAK;AAEtB,QAAM,cAAcC,QAAO,IAAI;AAC/B,iBAAe,aAAa;AAAA,IAC1B,SAAS,MAAM,OAAO,MAAM;AAAA,IAC5B,QAAQ,CAAC,UAAU;AACjB,YAAM,IAAI,WAAW,MAAM,OAAO;AAClC,UAAI,KAAK,KAAM,QAAO,OAAO,IAAI,MAAM,KAAK;AAAA,IAC9C;AAAA,IACA,OAAO,CAAC,QAAQ,WAAW;AACzB,UAAI,CAAC,OAAQ,QAAO,QAAQ;AAAA,IAC9B;AAAA,EACF,CAAC;AAED,QAAM,eAAe,QAAQ,KAAK;AAGlC,QAAM,OAAOC,SAAQ,MAAM;AACzB,QAAI,IAAI,IAAI,MAAM,IAAI,GAAG,KAAK,MAAM,IAAI,KAAK;AAC7C,aAAS,IAAI,GAAG,KAAK,aAAa,KAAK;AACrC,YAAM,KAAK,KAAM,IAAI,iBAAkB;AACvC,YAAM,OAAO,IAAI,oBAAoB;AACrC,YAAM,IAAI,OAAO,IAAI;AACrB,YAAM,MAAM,OAAO,IAAI;AACvB,WAAK,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,IAAI,QAAQ,GAAG,KAAK,KAAK,CAAC,IAAI,KAAK;AAAA,IACpE;AACA,WAAO,GAAG,CAAC,IAAI,MAAM,IAAI,KAAK,KAAK,MAAM,IAAI,GAAG;AAAA,EAClD,GAAG,CAAC,KAAK,iBAAiB,gBAAgB,OAAO,QAAQ,QAAQ,OAAO,aAAa,EAAE,CAAC;AAExF,QAAM,QAAQA,SAAQ,MAAM;AAC1B,UAAM,MAAM,CAAC;AACb,aAAS,IAAI,GAAG,KAAK,aAAa,KAAK;AACrC,YAAM,KAAK,KAAM,IAAI,iBAAkB;AACvC,YAAM,YAAY,IAAI,mBAAmB;AACzC,YAAM,WAAW,IAAI,oBAAoB;AACzC,UAAI,KAAK;AAAA,QACP,GAAG;AAAA,QACH,KAAK,YAAY,KAAK,WAAW,KAAK;AAAA,QACtC,MAAM,YAAY,UAAU,WAAW,SAAS;AAAA,QAChD,SAAS,YAAY,IAAI,iBAAiB;AAAA,MAC5C,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT,GAAG,CAAC,iBAAiB,gBAAgB,OAAO,aAAa,EAAE,CAAC;AAE5D,QAAM,EAAE,IAAI,IAAI;AAChB,QAAM,YAAY,KAAK,MAAM;AAC7B,QAAM,MAAM,YAAY,EAAE,KAAK,OAAO,KAAK,CAAC;AAG5C,QAAM,OAAO,KAAK,IAAI,MAAM,iBAAiB,KAAK,MAAM,MAAM,cAAc,CAAC;AAC7E,QAAM,QAAQ,QAAQ,IAAI,OAAO;AAEjC,QAAM,SAAS,OAAO;AACtB,QAAM,cAAc,YAAY,SAAS,IAAI,KAAK;AAElD,SACE,gBAAAJ;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MACV,SAAS,OAAO,GAAG,IAAI,GAAG;AAAA,MAC1B,eAAY;AAAA,MACZ,WAAU;AAAA,MAEV;AAAA,wBAAAD,KAAC,UAAK,WAAU,iBAAgB,GAAG,MAAM;AAAA,QACzC,gBAAAA,KAAC,YAAO,WAAU,kBAAiB,IAAI,SAAS,IAAI,IAAI,MAAM,GAAG,GAAG,GAAG;AAAA,QACvE,gBAAAA,KAAC,YAAO,WAAU,kBAAiB,IAAI,SAAS,IAAI,IAAI,MAAM,GAAG,GAAG,GAAG;AAAA,QAEtE,MAAM,IAAI,CAAC,MAAM,MAChB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAEC,WAAW,gCAAgC,KAAK,IAAI;AAAA,YACpD,IAAI,KAAK;AAAA,YACT,IAAI;AAAA,YACJ,IAAI,KAAK;AAAA,YACT,IAAI,MAAM,KAAK;AAAA;AAAA,UALV;AAAA,QAMP,CACD;AAAA,QAEA,MACE,OAAO,CAAC,SAAS,KAAK,WAAW,IAAI,EACrC,IAAI,CAAC,SACJ,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAEC,WAAU;AAAA,YACV,GAAG,KAAK;AAAA,YACR,GAAG,MAAM;AAAA,YACT,YAAW;AAAA,YAEV,mBAAS,KAAK,OAAO,GAAG,SAAS,KAAK,QAAQ,QAAQ,CAAC;AAAA;AAAA,UANnD,IAAI,KAAK,OAAO;AAAA,QAOvB,CACD;AAAA,QAEH,gBAAAA,KAAC,UAAK,WAAU,oBAAmB,GAAG,SAAS,GAAG,GAAG,QAAQ,GAAG,kBAEhE;AAAA,QAGC,MACE,OAAO,CAAC,SAAS,KAAK,WAAW,IAAI,EACrC,IAAI,CAAC,SACJ,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAEC,WAAU;AAAA,YACV,IAAI,KAAK;AAAA,YACT,IAAI,QAAQ;AAAA,YACZ,IAAI,KAAK;AAAA,YACT,IAAI,QAAQ;AAAA;AAAA,UALP,IAAI,KAAK,OAAO;AAAA,QAMvB,CACD;AAAA,QAEH,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,WAAU;AAAA,YACV,WAAW,aAAa,SAAS;AAAA,YAEjC;AAAA,8BAAAD;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,GAAG;AAAA,kBACH,GAAG,QAAQ;AAAA,kBACX,OAAO;AAAA,kBACP,QAAQ;AAAA;AAAA,cACV;AAAA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,GAAE;AAAA,kBACF,WAAW,eAAe,KAAK;AAAA;AAAA,cACjC;AAAA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,GAAG,CAAC,SAAS;AAAA,kBACb,GAAG,QAAQ;AAAA,kBACX,OAAO;AAAA,kBACP,QAAQ,QAAQ;AAAA,kBAChB,IAAI;AAAA;AAAA,cACN;AAAA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,GAAG,CAAC,SAAS;AAAA,kBACb,GAAG,QAAQ;AAAA,kBACX,OAAO;AAAA,kBACP,QAAQ,QAAQ;AAAA,kBAChB,IAAI;AAAA;AAAA,cACN;AAAA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,IAAI;AAAA,kBACJ,IAAI,QAAQ;AAAA,kBACZ,IAAI;AAAA,kBACJ,IAAI,MAAM;AAAA;AAAA,cACZ;AAAA,cACC,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,MAAM;AACnC,sBAAM,MAAM,IAAI,OAAO;AACvB,sBAAM,KAAK,MAAM,IAAI,KAAK,IAAI;AAC9B,uBACE,gBAAAC,MAAC,OACC;AAAA,kCAAAD;AAAA,oBAAC;AAAA;AAAA,sBACC,WACE,2BACC,KAAK,gCAAgC;AAAA,sBAExC,IAAI;AAAA,sBACJ,IAAI,MAAM;AAAA,sBACV,IAAI;AAAA,sBACJ,IAAI,MAAM;AAAA;AAAA,kBACZ;AAAA,kBACC,IAAI,KACH,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,GAAG;AAAA,sBACH,GAAG,MAAM;AAAA,sBACT,YAAW;AAAA,sBAEV;AAAA;AAAA,kBACH;AAAA,qBAnBI,CAqBR;AAAA,cAEJ,CAAC;AAAA,cAED,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,GAAG,cAAc,CAAC,SAAS,IAAI,IAAI,SAAS,IAAI;AAAA,kBAChD,GAAG,MAAM;AAAA,kBACT,YAAY,cAAc,QAAQ;AAAA,kBACnC;AAAA;AAAA,cAED;AAAA;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ,CAAC;;;AJmBK,SACE,OAAAM,MADF,QAAAC,aAAA;AA7MN,IAAM,cAAc,CAAC,MAAM,WAAW;AAAA,EACpC,UAAU,CAAC,MAAM,KAAK,KAAK,IAAI,SAAS,MAAM,KAAK;AAAA,EACnD,QAAQ;AACV;AAEA,IAAM,cAAc,CAAC,MAAM,OAAO,QAAQ;AACxC,QAAM,QAAQ,SAAS,MAAM,KAAK;AAClC,SAAO;AAAA,IACL,UAAU,CAAC,MAAM,MAAM,CAAC;AAAA,IACxB,QAAQ,KAAK,QAAQ,QAAQ,OAAO,GAAG;AAAA,EACzC;AACF;AAEA,IAAM,WAAW;AAAA,EACf,QAAQ,EAAE,MAAM,OAAO,QAAQ,QAAQ,YAAY,QAAQ,YAAY;AAAA,EACvE,OAAO,EAAE,MAAM,OAAO,OAAO,QAAQ,aAAa,QAAQ,YAAY;AAAA,EACtE,SAAS;AAAA,IACP,MAAM,OAAO;AAAA,IACb,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;AAEA,IAAM,QACJ,OAAO,YAAY,eAAe,QAAQ,KAAK,aAAa;AAQ9D,SAAS,YAAY,EAAE,UAAU,OAAO,eAAe,SAAS,GAAG;AACjE,YAAU,MAAM;AACd,QAAI,SAAU,eAAc,KAAK;AAAA,EACnC,GAAG,CAAC,UAAU,OAAO,aAAa,CAAC;AACnC,SAAO;AACT;AAyBO,SAAS,aAAa;AAAA,EAC3B,UAAU;AAAA,EACV,QAAQ,CAAC;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,YAAY;AACd,GAAG;AACD,QAAM,WAAW,SAAS,OAAO,IAC7B,WACC,SACC,QAAQ;AAAA,IACN,2BAA2B,OAAO;AAAA,EAEpC,GACF;AACJ,QAAM,EAAE,MAAM,QAAQ,QAAQ,OAAO,IAAI,SAAS,QAAQ;AAE1D,QAAM,QAAQ,qBAAqB,MAAM,QAAQ,cAAc;AAC/D,QAAM,WAAWC,SAAQ,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,CAAC,OAAO,KAAK,CAAC;AACpE,QAAM,CAAC,KAAK,GAAG,IAAI,KAAK;AAExB,QAAM,YAAY;AAAA,IAChB,CAAC,OAAO;AACN,YAAM,IAAI,SAAS,UAAU,CAAC,SAAS,KAAK,OAAO,EAAE;AACrD,aAAO,IAAI,IAAI,OAAO;AAAA,IACxB;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAIA,QAAM,aAAa,SAAS,KAAK,CAAC,SAAS,KAAK,EAAE;AAClD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,IAAI;AACjD,QAAM,aAAaC,QAAO,KAAK;AAE/B,QAAM,kBACJ,SAAS,OAAO,UAAU,KAAK,IAAI,aAAa,aAAa;AAE/D,QAAM,YAAYA,QAAO,IAAI;AAC7B,QAAM,SAASA,QAAO,IAAI;AAC1B,QAAM,WAAWA,QAAO,CAAC,CAAC;AAC1B,QAAM,cAAcA,QAAO,CAAC,CAAC;AAC7B,QAAM,gBAAgB,iBAAiB;AAEvC,QAAM,eAAe;AAAA,IACnB,CAAC,UAAU;AACT,YAAM,OAAO,SAAS,KAAK;AAC3B,UAAI,CAAC,KAAM;AACX,UAAI,KAAK,MAAM,SAAS,QAAQ,KAAK,EAAG,UAAS,QAAQ,KAAK,EAAE,MAAM;AACtE,WAAK,WAAW;AAChB,iBAAW,KAAK,EAAE;AAAA,IACpB;AAAA,IACA,CAAC,UAAU,QAAQ;AAAA,EACrB;AAEA,QAAM,SAAS,gBAAgB;AAAA,IAC7B;AAAA,IACA,OAAO,mBAAmB;AAAA,IAC1B,cAAc,UAAU,YAAY,KAAK;AAAA,IACzC,UAAU;AAAA,IACV,UAAU,KAAK;AAAA,EACjB,CAAC;AAED,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,gBAAgB;AAAA,IACpB,CAAC,UAAU;AACT,oBAAc,KAAK;AAEnB,UAAI,CAAC,WAAW,SAAS;AACvB,mBAAW,UAAU;AACrB,aAAK,OAAO,CAAC;AAAA,MACf;AAAA,IACF;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AAOA,QAAM,aAAa;AAAA,IACjB,CAAC,YAAY;AACX,YAAM,MAAM,UAAU,SAAS,sBAAsB;AACrD,UAAI,CAAC,KAAK,MAAO,QAAO;AACxB,cAAS,UAAU,IAAI,QAAQ,IAAI,QAAS;AAAA,IAC9C;AAAA,IACA,CAAC,GAAG;AAAA,EACN;AAEA,QAAM,SAAS,OAAO;AAKtB,YAAU,MAAM;AACd,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,IAAK,QAAO;AAEjB,UAAM,SAAS,CAAC,aAAa;AAC3B,YAAM,UAAU,YAAY,QAAQ,MAAM;AAC1C,UAAI,CAAC,WAAW,IAAI,eAAe,IAAI,YAAa;AACpD,UAAI,SAAS;AAAA,QACX,MAAM,KAAK,IAAI,GAAG,QAAQ,aAAa,IAAI,cAAc,CAAC;AAAA,QAC1D;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO,gBAAgB,SAAS,QAAQ;AAIxC,QAAI,OAAO,mBAAmB,YAAa,QAAO;AAClD,UAAM,WAAW,IAAI,eAAe,MAAM,OAAO,MAAM,CAAC;AACxD,aAAS,QAAQ,GAAG;AACpB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,QAAQ,aAAa,CAAC;AAE1B,WAAS,UAAU,OAAO;AACxB,QAAI,MAAM,QAAQ,aAAc,QAAO,KAAK,CAAC;AAAA,aACpC,MAAM,QAAQ,YAAa,QAAO,KAAK,EAAE;AAAA,aACzC,MAAM,QAAQ,OAAQ,QAAO,KAAK,CAAC;AAAA,aACnC,MAAM,QAAQ,MAAO,QAAO,KAAK,QAAQ,CAAC;AAAA,QAC9C;AACL,UAAM,eAAe;AAAA,EACvB;AAEA,QAAM,QAAQ,OAAO,MAAM,OAAO,OAAO,GAAG;AAC5C,QAAM,YAAY,CAAC,aACjB,mBAAmB,WAAW,2BAA2B;AAE3D,SACE,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,CAAC,WAAW,YAAY,QAAQ,IAAI,SAAS,EACrD,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,MACX,cAAY;AAAA,MACZ;AAAA,MAEA;AAAA,wBAAAA,MAAC,SAAI,WAAU,kBACb;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA;AAAA,UACF;AAAA,UAEA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO,EAAE,WAAW,cAAc,IAAI,MAAM,QAAQ,GAAG,CAAC,IAAI;AAAA,cAE3D,mBAAS,IAAI,CAAC,MAAM,UACnB,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBAEC,KAAK,CAAC,OAAQ,YAAY,QAAQ,KAAK,IAAI;AAAA,kBAC3C,WAAU;AAAA,kBACV,OAAO;AAAA,oBACL,eAAe,IAAI,MAAM,SAAS,KAAK,GAAG,GAAG;AAAA,oBAC7C,eAAe,IAAI,KAAK,QAAQ,GAAG;AAAA,kBACrC;AAAA,kBAEC,eAAK,KACJ,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,IAAI,KAAK;AAAA,sBACT,KAAK,KAAK;AAAA,sBACV,KAAK,CAAC,OAAQ,SAAS,QAAQ,KAAK,IAAI;AAAA,sBACxC,WAAW,CAAC,EAAE,SAAS,MAAM,UAAU,QAAQ;AAAA,sBAE9C,WAAC,EAAE,SAAS,MACX,gBAAAA;AAAA,wBAAC;AAAA;AAAA,0BACC;AAAA,0BACA;AAAA,0BACA;AAAA,0BAEC,eAAK;AAAA;AAAA,sBACR;AAAA;AAAA,kBAEJ,IAEA,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,WAAW,UAAU,UAAU,MAAM;AAAA,sBACrC,gBAAc,UAAU,SAAS,SAAS;AAAA,sBAC1C,SAAS,MAAM,OAAO,KAAK,KAAK;AAAA,sBAE/B,eAAK;AAAA;AAAA,kBACR;AAAA;AAAA,gBAjCG,KAAK;AAAA,cAmCZ,CACD;AAAA;AAAA,UACH;AAAA,WACF;AAAA,QAEC,WACC,gBAAAC,MAAC,SAAI,WAAU,oBACb;AAAA,0BAAAA,MAAC,UAAK,eAAY,QAChB;AAAA,4BAAAD,KAAC,UAAK,WAAU,wBAAuB,sBAAQ;AAAA,YAAQ;AAAA,YACvD,gBAAAA,KAAC,UAAK,WAAU,wBACb,iBAAO,WAAW,iBAAO,SAAS,MAAM,GAAG,OAC9C;AAAA,YAAQ;AAAA,YACR,gBAAAA,KAAC,UAAK,WAAU,wBAAuB,qBAAO;AAAA,YAAQ;AAAA,YACtD,gBAAAA,KAAC,UAAK,WAAU,wBACb,iBAAO,IAAI,QAAQ,CAAC,GACvB;AAAA,aACF;AAAA,UAEA,gBAAAA,KAAC,UAAK,WAAU,oBAAmB,aAAU,UAC1C,iBAAO,YAAY,OAAO,WACvB,KACA,GAAG,SAAS,MAAM,GAAG,SAAS,EAAE,aACtC;AAAA,WACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":["useMemo","useRef","CursorRule","forwardRef","useMemo","useRef","jsx","jsxs","forwardRef","SlideStator","useMemo","useRef","forwardRef","useMemo","useRef","jsx","jsxs","forwardRef","VernierCarriage","useRef","useMemo","jsx","jsxs","useMemo","useRef"]}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// src/components/Tabs/Tabs.jsx
|
|
2
|
+
import { useRef, useState } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
function Tabs({
|
|
5
|
+
items = [],
|
|
6
|
+
value,
|
|
7
|
+
defaultValue,
|
|
8
|
+
onChange,
|
|
9
|
+
className = ""
|
|
10
|
+
}) {
|
|
11
|
+
const isControlled = value != null;
|
|
12
|
+
const [internal, setInternal] = useState(
|
|
13
|
+
defaultValue ?? items[0]?.id
|
|
14
|
+
);
|
|
15
|
+
const selected = isControlled ? value : internal;
|
|
16
|
+
const tabRefs = useRef([]);
|
|
17
|
+
function selectId(id) {
|
|
18
|
+
if (!isControlled) setInternal(id);
|
|
19
|
+
onChange?.(id);
|
|
20
|
+
}
|
|
21
|
+
function onKeyDown(event) {
|
|
22
|
+
const enabled = items.map((it, i) => ({ it, i })).filter(({ it }) => !it.disabled);
|
|
23
|
+
const pos = enabled.findIndex(({ it }) => it.id === selected);
|
|
24
|
+
if (pos < 0) return;
|
|
25
|
+
let nextPos = null;
|
|
26
|
+
if (event.key === "ArrowRight") nextPos = (pos + 1) % enabled.length;
|
|
27
|
+
else if (event.key === "ArrowLeft")
|
|
28
|
+
nextPos = (pos - 1 + enabled.length) % enabled.length;
|
|
29
|
+
else if (event.key === "Home") nextPos = 0;
|
|
30
|
+
else if (event.key === "End") nextPos = enabled.length - 1;
|
|
31
|
+
if (nextPos == null) return;
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
const target = enabled[nextPos];
|
|
34
|
+
selectId(target.it.id);
|
|
35
|
+
tabRefs.current[target.i]?.focus();
|
|
36
|
+
}
|
|
37
|
+
const active = items.find((it) => it.id === selected);
|
|
38
|
+
return /* @__PURE__ */ jsxs("div", { className: ["ds-tabs", className].filter(Boolean).join(" "), children: [
|
|
39
|
+
/* @__PURE__ */ jsx("div", { className: "ds-tabs__list", role: "tablist", onKeyDown, children: items.map((item, index) => {
|
|
40
|
+
const isSelected = item.id === selected;
|
|
41
|
+
return /* @__PURE__ */ jsx(
|
|
42
|
+
"button",
|
|
43
|
+
{
|
|
44
|
+
type: "button",
|
|
45
|
+
role: "tab",
|
|
46
|
+
id: `ds-tab-${item.id}`,
|
|
47
|
+
ref: (el) => tabRefs.current[index] = el,
|
|
48
|
+
className: "ds-tabs__tab" + (isSelected ? " ds-tabs__tab--active" : ""),
|
|
49
|
+
"aria-selected": isSelected,
|
|
50
|
+
"aria-controls": `ds-tabpanel-${item.id}`,
|
|
51
|
+
tabIndex: isSelected ? 0 : -1,
|
|
52
|
+
disabled: item.disabled,
|
|
53
|
+
onClick: () => selectId(item.id),
|
|
54
|
+
children: item.label
|
|
55
|
+
},
|
|
56
|
+
item.id
|
|
57
|
+
);
|
|
58
|
+
}) }),
|
|
59
|
+
active && /* @__PURE__ */ jsx(
|
|
60
|
+
"div",
|
|
61
|
+
{
|
|
62
|
+
className: "ds-tabs__panel",
|
|
63
|
+
role: "tabpanel",
|
|
64
|
+
id: `ds-tabpanel-${active.id}`,
|
|
65
|
+
"aria-labelledby": `ds-tab-${active.id}`,
|
|
66
|
+
tabIndex: 0,
|
|
67
|
+
children: active.content
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
] });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
Tabs
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=chunk-ZVUDPTFZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Tabs/Tabs.jsx"],"sourcesContent":["import { useRef, useState } from \"react\";\nimport \"./Tabs.css\";\n\n/**\n * @typedef {object} TabItem\n * @property {string} id\n * @property {import(\"react\").ReactNode} label\n * @property {import(\"react\").ReactNode} content\n * @property {boolean} [disabled]\n */\n\n/**\n * Accessible tabs. Uncontrolled by default (tracks its own selection); pass\n * `value` + `onChange` to control it. Left/Right arrows move between tabs with\n * roving tabindex; Home/End jump to first/last. role=tablist/tab/tabpanel.\n *\n * @param {object} props\n * @param {TabItem[]} props.items\n * @param {string} [props.value] - Selected tab id (controlled).\n * @param {string} [props.defaultValue] - Initial tab id (uncontrolled).\n * @param {(id: string) => void} [props.onChange]\n * @param {string} [props.className]\n * @returns {import(\"react\").ReactElement}\n */\nexport function Tabs({\n items = [],\n value,\n defaultValue,\n onChange,\n className = \"\",\n}) {\n const isControlled = value != null;\n const [internal, setInternal] = useState(\n defaultValue ?? items[0]?.id\n );\n const selected = isControlled ? value : internal;\n const tabRefs = useRef([]);\n\n function selectId(id) {\n if (!isControlled) setInternal(id);\n onChange?.(id);\n }\n\n function onKeyDown(event) {\n const enabled = items\n .map((it, i) => ({ it, i }))\n .filter(({ it }) => !it.disabled);\n const pos = enabled.findIndex(({ it }) => it.id === selected);\n if (pos < 0) return;\n\n let nextPos = null;\n if (event.key === \"ArrowRight\") nextPos = (pos + 1) % enabled.length;\n else if (event.key === \"ArrowLeft\")\n nextPos = (pos - 1 + enabled.length) % enabled.length;\n else if (event.key === \"Home\") nextPos = 0;\n else if (event.key === \"End\") nextPos = enabled.length - 1;\n if (nextPos == null) return;\n\n event.preventDefault();\n const target = enabled[nextPos];\n selectId(target.it.id);\n tabRefs.current[target.i]?.focus();\n }\n\n const active = items.find((it) => it.id === selected);\n\n return (\n <div className={[\"ds-tabs\", className].filter(Boolean).join(\" \")}>\n <div className=\"ds-tabs__list\" role=\"tablist\" onKeyDown={onKeyDown}>\n {items.map((item, index) => {\n const isSelected = item.id === selected;\n return (\n <button\n key={item.id}\n type=\"button\"\n role=\"tab\"\n id={`ds-tab-${item.id}`}\n ref={(el) => (tabRefs.current[index] = el)}\n className={\n \"ds-tabs__tab\" +\n (isSelected ? \" ds-tabs__tab--active\" : \"\")\n }\n aria-selected={isSelected}\n aria-controls={`ds-tabpanel-${item.id}`}\n tabIndex={isSelected ? 0 : -1}\n disabled={item.disabled}\n onClick={() => selectId(item.id)}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n {active && (\n <div\n className=\"ds-tabs__panel\"\n role=\"tabpanel\"\n id={`ds-tabpanel-${active.id}`}\n aria-labelledby={`ds-tab-${active.id}`}\n tabIndex={0}\n >\n {active.content}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";AAAA,SAAS,QAAQ,gBAAgB;AAmE7B,SAKQ,KALR;AA3CG,SAAS,KAAK;AAAA,EACnB,QAAQ,CAAC;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,GAAG;AACD,QAAM,eAAe,SAAS;AAC9B,QAAM,CAAC,UAAU,WAAW,IAAI;AAAA,IAC9B,gBAAgB,MAAM,CAAC,GAAG;AAAA,EAC5B;AACA,QAAM,WAAW,eAAe,QAAQ;AACxC,QAAM,UAAU,OAAO,CAAC,CAAC;AAEzB,WAAS,SAAS,IAAI;AACpB,QAAI,CAAC,aAAc,aAAY,EAAE;AACjC,eAAW,EAAE;AAAA,EACf;AAEA,WAAS,UAAU,OAAO;AACxB,UAAM,UAAU,MACb,IAAI,CAAC,IAAI,OAAO,EAAE,IAAI,EAAE,EAAE,EAC1B,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,QAAQ;AAClC,UAAM,MAAM,QAAQ,UAAU,CAAC,EAAE,GAAG,MAAM,GAAG,OAAO,QAAQ;AAC5D,QAAI,MAAM,EAAG;AAEb,QAAI,UAAU;AACd,QAAI,MAAM,QAAQ,aAAc,YAAW,MAAM,KAAK,QAAQ;AAAA,aACrD,MAAM,QAAQ;AACrB,iBAAW,MAAM,IAAI,QAAQ,UAAU,QAAQ;AAAA,aACxC,MAAM,QAAQ,OAAQ,WAAU;AAAA,aAChC,MAAM,QAAQ,MAAO,WAAU,QAAQ,SAAS;AACzD,QAAI,WAAW,KAAM;AAErB,UAAM,eAAe;AACrB,UAAM,SAAS,QAAQ,OAAO;AAC9B,aAAS,OAAO,GAAG,EAAE;AACrB,YAAQ,QAAQ,OAAO,CAAC,GAAG,MAAM;AAAA,EACnC;AAEA,QAAM,SAAS,MAAM,KAAK,CAAC,OAAO,GAAG,OAAO,QAAQ;AAEpD,SACE,qBAAC,SAAI,WAAW,CAAC,WAAW,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAC7D;AAAA,wBAAC,SAAI,WAAU,iBAAgB,MAAK,WAAU,WAC3C,gBAAM,IAAI,CAAC,MAAM,UAAU;AAC1B,YAAM,aAAa,KAAK,OAAO;AAC/B,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,IAAI,UAAU,KAAK,EAAE;AAAA,UACrB,KAAK,CAAC,OAAQ,QAAQ,QAAQ,KAAK,IAAI;AAAA,UACvC,WACE,kBACC,aAAa,0BAA0B;AAAA,UAE1C,iBAAe;AAAA,UACf,iBAAe,eAAe,KAAK,EAAE;AAAA,UACrC,UAAU,aAAa,IAAI;AAAA,UAC3B,UAAU,KAAK;AAAA,UACf,SAAS,MAAM,SAAS,KAAK,EAAE;AAAA,UAE9B,eAAK;AAAA;AAAA,QAfD,KAAK;AAAA,MAgBZ;AAAA,IAEJ,CAAC,GACH;AAAA,IACC,UACC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,MAAK;AAAA,QACL,IAAI,eAAe,OAAO,EAAE;AAAA,QAC5B,mBAAiB,UAAU,OAAO,EAAE;AAAA,QACpC,UAAU;AAAA,QAET,iBAAO;AAAA;AAAA,IACV;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} AccordionItem
|
|
3
|
+
* @property {string} id
|
|
4
|
+
* @property {import("react").ReactNode} title
|
|
5
|
+
* @property {import("react").ReactNode} content
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Disclosure list built on native <button aria-expanded> + a region panel.
|
|
9
|
+
* Single-open by default; set `multiple` to allow several panels open at once.
|
|
10
|
+
*
|
|
11
|
+
* @param {object} props
|
|
12
|
+
* @param {AccordionItem[]} props.items
|
|
13
|
+
* @param {boolean} [props.multiple] - Allow multiple panels open. Default false.
|
|
14
|
+
* @param {string[]} [props.defaultOpen] - Item ids open initially.
|
|
15
|
+
* @param {string} [props.className]
|
|
16
|
+
* @returns {import("react").ReactElement}
|
|
17
|
+
*/
|
|
18
|
+
export function Accordion({ items, multiple, defaultOpen, className, }: {
|
|
19
|
+
items: AccordionItem[];
|
|
20
|
+
multiple?: boolean | undefined;
|
|
21
|
+
defaultOpen?: string[] | undefined;
|
|
22
|
+
className?: string | undefined;
|
|
23
|
+
}): import("react").ReactElement;
|
|
24
|
+
export type AccordionItem = {
|
|
25
|
+
id: string;
|
|
26
|
+
title: import("react").ReactNode;
|
|
27
|
+
content: import("react").ReactNode;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=Accordion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Accordion.d.ts","sourceRoot":"","sources":["../../../src/components/Accordion/Accordion.jsx"],"names":[],"mappings":"AAGA;;;;;GAKG;AAEH;;;;;;;;;;GAUG;AACH,wEANG;IAA+B,KAAK,EAA5B,aAAa,EAAE;IACC,QAAQ;IACP,WAAW;IACb,SAAS;CAChC,GAAU,OAAO,OAAO,EAAE,YAAY,CAuDxC;;QArEa,MAAM;WACN,OAAO,OAAO,EAAE,SAAS;aACzB,OAAO,OAAO,EAAE,SAAS"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* src/components/Accordion/Accordion.css */
|
|
2
|
+
.ds-accordion {
|
|
3
|
+
border: 1px solid var(--ds-color-bw-1);
|
|
4
|
+
border-radius: var(--ds-radius-md);
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
}
|
|
7
|
+
.ds-accordion__item + .ds-accordion__item {
|
|
8
|
+
border-top: 1px solid var(--ds-color-bw-1);
|
|
9
|
+
}
|
|
10
|
+
.ds-accordion__heading {
|
|
11
|
+
margin: 0;
|
|
12
|
+
}
|
|
13
|
+
.ds-accordion__trigger {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
gap: var(--ds-space-4);
|
|
18
|
+
width: 100%;
|
|
19
|
+
padding: var(--ds-space-4) var(--ds-space-5);
|
|
20
|
+
font-family: var(--ds-font-body);
|
|
21
|
+
font-size: var(--ds-font-size-200);
|
|
22
|
+
font-weight: var(--ds-font-weight-medium);
|
|
23
|
+
text-align: left;
|
|
24
|
+
color: var(--ds-color-font-0);
|
|
25
|
+
background: transparent;
|
|
26
|
+
border: none;
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
transition: background-color var(--ds-motion-duration-fast) var(--ds-motion-ease-standard);
|
|
29
|
+
}
|
|
30
|
+
.ds-accordion__trigger:hover {
|
|
31
|
+
background-color: var(--ds-color-bw-1);
|
|
32
|
+
}
|
|
33
|
+
.ds-accordion__trigger:focus-visible {
|
|
34
|
+
outline: 2px solid var(--ds-color-focus-ring);
|
|
35
|
+
outline-offset: -2px;
|
|
36
|
+
}
|
|
37
|
+
.ds-accordion__icon {
|
|
38
|
+
width: 0.6rem;
|
|
39
|
+
height: 0.6rem;
|
|
40
|
+
flex-shrink: 0;
|
|
41
|
+
border-right: 2px solid var(--ds-color-font-1);
|
|
42
|
+
border-bottom: 2px solid var(--ds-color-font-1);
|
|
43
|
+
transform: rotate(45deg);
|
|
44
|
+
transition: transform var(--ds-motion-duration-base) var(--ds-motion-ease-standard);
|
|
45
|
+
}
|
|
46
|
+
.ds-accordion__trigger[aria-expanded=true] .ds-accordion__icon {
|
|
47
|
+
transform: rotate(-135deg);
|
|
48
|
+
}
|
|
49
|
+
.ds-accordion__content {
|
|
50
|
+
padding: 0 var(--ds-space-5) var(--ds-space-5);
|
|
51
|
+
color: var(--ds-color-font-0);
|
|
52
|
+
}
|
|
53
|
+
@media (prefers-reduced-motion: reduce) {
|
|
54
|
+
.ds-accordion__icon {
|
|
55
|
+
transition: none;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Accordion/Accordion.css"],"sourcesContent":[".ds-accordion {\n border: 1px solid var(--ds-color-bw-1);\n border-radius: var(--ds-radius-md);\n overflow: hidden;\n}\n\n.ds-accordion__item + .ds-accordion__item {\n border-top: 1px solid var(--ds-color-bw-1);\n}\n\n.ds-accordion__heading {\n margin: 0;\n}\n\n.ds-accordion__trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--ds-space-4);\n width: 100%;\n padding: var(--ds-space-4) var(--ds-space-5);\n font-family: var(--ds-font-body);\n font-size: var(--ds-font-size-200);\n font-weight: var(--ds-font-weight-medium);\n text-align: left;\n color: var(--ds-color-font-0);\n background: transparent;\n border: none;\n cursor: pointer;\n transition: background-color var(--ds-motion-duration-fast)\n var(--ds-motion-ease-standard);\n}\n\n.ds-accordion__trigger:hover {\n background-color: var(--ds-color-bw-1);\n}\n\n.ds-accordion__trigger:focus-visible {\n outline: 2px solid var(--ds-color-focus-ring);\n outline-offset: -2px;\n}\n\n.ds-accordion__icon {\n width: 0.6rem;\n height: 0.6rem;\n flex-shrink: 0;\n border-right: 2px solid var(--ds-color-font-1);\n border-bottom: 2px solid var(--ds-color-font-1);\n transform: rotate(45deg);\n transition: transform var(--ds-motion-duration-base)\n var(--ds-motion-ease-standard);\n}\n\n.ds-accordion__trigger[aria-expanded=\"true\"] .ds-accordion__icon {\n transform: rotate(-135deg);\n}\n\n.ds-accordion__content {\n padding: 0 var(--ds-space-5) var(--ds-space-5);\n color: var(--ds-color-font-0);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ds-accordion__icon {\n transition: none;\n }\n}\n"],"mappings":";AAAA,CAAC;AACC,UAAQ,IAAI,MAAM,IAAI;AACtB,iBAAe,IAAI;AACnB,YAAU;AACZ;AAEA,CAAC,mBAAmB,EAAE,CAArB;AACC,cAAY,IAAI,MAAM,IAAI;AAC5B;AAEA,CAAC;AACC,UAAQ;AACV;AAEA,CAAC;AACC,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,OAAK,IAAI;AACT,SAAO;AACP,WAAS,IAAI,cAAc,IAAI;AAC/B,eAAa,IAAI;AACjB,aAAW,IAAI;AACf,eAAa,IAAI;AACjB,cAAY;AACZ,SAAO,IAAI;AACX,cAAY;AACZ,UAAQ;AACR,UAAQ;AACR,cAAY,iBAAiB,IAAI,2BAC/B,IAAI;AACR;AAEA,CAnBC,qBAmBqB;AACpB,oBAAkB,IAAI;AACxB;AAEA,CAvBC,qBAuBqB;AACpB,WAAS,IAAI,MAAM,IAAI;AACvB,kBAAgB;AAClB;AAEA,CAAC;AACC,SAAO;AACP,UAAQ;AACR,eAAa;AACb,gBAAc,IAAI,MAAM,IAAI;AAC5B,iBAAe,IAAI,MAAM,IAAI;AAC7B,aAAW,OAAO;AAClB,cAAY,UAAU,IAAI,2BACxB,IAAI;AACR;AAEA,CAvCC,qBAuCqB,CAAC,oBAAsB,CAX5C;AAYC,aAAW,OAAO;AACpB;AAEA,CAAC;AACC,WAAS,EAAE,IAAI,cAAc,IAAI;AACjC,SAAO,IAAI;AACb;AAEA,QAAO,wBAAyB;AAC9B,GArBD;AAsBG,gBAAY;AACd;AACF;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Accordion/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function Button({ as: Component, variant, size, className, ...rest }: {
|
|
2
|
+
[x: string]: any;
|
|
3
|
+
as?: string | undefined;
|
|
4
|
+
variant?: string | undefined;
|
|
5
|
+
size?: string | undefined;
|
|
6
|
+
className?: string | undefined;
|
|
7
|
+
}): import("react").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=Button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.jsx"],"names":[],"mappings":"AAEA;;;;;;gCAiBC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Button/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../../src/components/Card/Card.jsx"],"names":[],"mappings":"AAEA;;;;gCAGC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Card/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkbox with a styled indicator over a native <input type="checkbox">, so
|
|
3
|
+
* keyboard/focus/toggle behavior stays native. Controlled or uncontrolled via
|
|
4
|
+
* `...rest` (checked/defaultChecked, onChange).
|
|
5
|
+
*
|
|
6
|
+
* @param {object} props
|
|
7
|
+
* @param {import("react").ReactNode} [props.label] - Visible label text.
|
|
8
|
+
* @param {string} [props.className]
|
|
9
|
+
* @returns {import("react").ReactElement}
|
|
10
|
+
*/
|
|
11
|
+
export function Checkbox({ label, className, ...rest }: {
|
|
12
|
+
label?: import("react").ReactNode;
|
|
13
|
+
className?: string | undefined;
|
|
14
|
+
}): import("react").ReactElement;
|
|
15
|
+
//# sourceMappingURL=Checkbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Checkbox.d.ts","sourceRoot":"","sources":["../../../src/components/Checkbox/Checkbox.jsx"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,wDAJG;IAA0C,KAAK,GAAvC,OAAO,OAAO,EAAE,SAAS;IACV,SAAS;CAChC,GAAU,OAAO,OAAO,EAAE,YAAY,CAUxC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* src/components/Checkbox/Checkbox.css */
|
|
2
|
+
.ds-checkbox {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: var(--ds-space-2);
|
|
6
|
+
font-family: var(--ds-font-body);
|
|
7
|
+
font-size: var(--ds-font-size-200);
|
|
8
|
+
color: var(--ds-color-font-0);
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
}
|
|
11
|
+
.ds-checkbox__input {
|
|
12
|
+
position: absolute;
|
|
13
|
+
width: 1px;
|
|
14
|
+
height: 1px;
|
|
15
|
+
opacity: 0;
|
|
16
|
+
margin: 0;
|
|
17
|
+
}
|
|
18
|
+
.ds-checkbox__box {
|
|
19
|
+
display: inline-flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
width: 1.15rem;
|
|
23
|
+
height: 1.15rem;
|
|
24
|
+
flex-shrink: 0;
|
|
25
|
+
border: 1px solid var(--ds-color-field-border);
|
|
26
|
+
border-radius: var(--ds-radius-sm);
|
|
27
|
+
background-color: var(--ds-color-field-bg);
|
|
28
|
+
transition: background-color var(--ds-motion-duration-fast) var(--ds-motion-ease-standard), border-color var(--ds-motion-duration-fast) var(--ds-motion-ease-standard);
|
|
29
|
+
}
|
|
30
|
+
.ds-checkbox__box::after {
|
|
31
|
+
content: "";
|
|
32
|
+
width: 0.3rem;
|
|
33
|
+
height: 0.55rem;
|
|
34
|
+
border: solid var(--ds-color-on-info);
|
|
35
|
+
border-width: 0 2px 2px 0;
|
|
36
|
+
transform: rotate(45deg) scale(0);
|
|
37
|
+
transition: transform var(--ds-motion-duration-fast) var(--ds-motion-ease-standard);
|
|
38
|
+
margin-top: -2px;
|
|
39
|
+
}
|
|
40
|
+
.ds-checkbox__input:checked + .ds-checkbox__box {
|
|
41
|
+
background-color: var(--ds-color-bg-2);
|
|
42
|
+
border-color: var(--ds-color-bg-2);
|
|
43
|
+
}
|
|
44
|
+
.ds-checkbox__input:checked + .ds-checkbox__box::after {
|
|
45
|
+
transform: rotate(45deg) scale(1);
|
|
46
|
+
}
|
|
47
|
+
.ds-checkbox__input:focus-visible + .ds-checkbox__box {
|
|
48
|
+
outline: 2px solid var(--ds-color-focus-ring);
|
|
49
|
+
outline-offset: 2px;
|
|
50
|
+
}
|
|
51
|
+
.ds-checkbox__input:disabled ~ * {
|
|
52
|
+
opacity: 0.5;
|
|
53
|
+
}
|
|
54
|
+
.ds-checkbox:has(.ds-checkbox__input:disabled) {
|
|
55
|
+
cursor: not-allowed;
|
|
56
|
+
}
|
|
57
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Checkbox/Checkbox.css"],"sourcesContent":[".ds-checkbox {\n display: inline-flex;\n align-items: center;\n gap: var(--ds-space-2);\n font-family: var(--ds-font-body);\n font-size: var(--ds-font-size-200);\n color: var(--ds-color-font-0);\n cursor: pointer;\n}\n\n/* Native input kept in the DOM (accessibility) but visually replaced */\n.ds-checkbox__input {\n position: absolute;\n width: 1px;\n height: 1px;\n opacity: 0;\n margin: 0;\n}\n\n.ds-checkbox__box {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.15rem;\n height: 1.15rem;\n flex-shrink: 0;\n border: 1px solid var(--ds-color-field-border);\n border-radius: var(--ds-radius-sm);\n background-color: var(--ds-color-field-bg);\n transition:\n background-color var(--ds-motion-duration-fast) var(--ds-motion-ease-standard),\n border-color var(--ds-motion-duration-fast) var(--ds-motion-ease-standard);\n}\n\n.ds-checkbox__box::after {\n content: \"\";\n width: 0.3rem;\n height: 0.55rem;\n border: solid var(--ds-color-on-info);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg) scale(0);\n transition: transform var(--ds-motion-duration-fast) var(--ds-motion-ease-standard);\n margin-top: -2px;\n}\n\n.ds-checkbox__input:checked + .ds-checkbox__box {\n background-color: var(--ds-color-bg-2);\n border-color: var(--ds-color-bg-2);\n}\n\n.ds-checkbox__input:checked + .ds-checkbox__box::after {\n transform: rotate(45deg) scale(1);\n}\n\n.ds-checkbox__input:focus-visible + .ds-checkbox__box {\n outline: 2px solid var(--ds-color-focus-ring);\n outline-offset: 2px;\n}\n\n.ds-checkbox__input:disabled ~ * {\n opacity: 0.5;\n}\n\n.ds-checkbox:has(.ds-checkbox__input:disabled) {\n cursor: not-allowed;\n}\n"],"mappings":";AAAA,CAAC;AACC,WAAS;AACT,eAAa;AACb,OAAK,IAAI;AACT,eAAa,IAAI;AACjB,aAAW,IAAI;AACf,SAAO,IAAI;AACX,UAAQ;AACV;AAGA,CAAC;AACC,YAAU;AACV,SAAO;AACP,UAAQ;AACR,WAAS;AACT,UAAQ;AACV;AAEA,CAAC;AACC,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,SAAO;AACP,UAAQ;AACR,eAAa;AACb,UAAQ,IAAI,MAAM,IAAI;AACtB,iBAAe,IAAI;AACnB,oBAAkB,IAAI;AACtB,cACE,iBAAiB,IAAI,2BAA2B,IAAI,0BAA0B,EAC9E,aAAa,IAAI,2BAA2B,IAAI;AACpD;AAEA,CAfC,gBAegB;AACf,WAAS;AACT,SAAO;AACP,UAAQ;AACR,UAAQ,MAAM,IAAI;AAClB,gBAAc,EAAE,IAAI,IAAI;AACxB,aAAW,OAAO,OAAO,MAAM;AAC/B,cAAY,UAAU,IAAI,2BAA2B,IAAI;AACzD,cAAY;AACd;AAEA,CAlCC,kBAkCkB,SAAS,EAAE,CA1B7B;AA2BC,oBAAkB,IAAI;AACtB,gBAAc,IAAI;AACpB;AAEA,CAvCC,kBAuCkB,SAAS,EAAE,CA/B7B,gBA+B8C;AAC7C,aAAW,OAAO,OAAO,MAAM;AACjC;AAEA,CA3CC,kBA2CkB,eAAe,EAAE,CAnCnC;AAoCC,WAAS,IAAI,MAAM,IAAI;AACvB,kBAAgB;AAClB;AAEA,CAhDC,kBAgDkB,UAAU,EAAE;AAC7B,WAAS;AACX;AAEA,CA/DC,WA+DW,KAAK,CApDhB,kBAoDmC;AAClC,UAAQ;AACV;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Checkbox/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidebar navigation built on a circular slide rule.
|
|
3
|
+
*
|
|
4
|
+
* At rest only a crescent of the disc breaks the edge — enough to read as an
|
|
5
|
+
* instrument, not enough to cost layout. Approaching the rail swings the whole
|
|
6
|
+
* rule out; spinning it brings a station to the fixed index, ratcheting
|
|
7
|
+
* through quarter-pitch detents on the way.
|
|
8
|
+
*
|
|
9
|
+
* As with SlideRuleNav, the engraved chrome is an aria-hidden SVG and the
|
|
10
|
+
* navigation is an ordinary list of links positioned over it, so the dial is
|
|
11
|
+
* fully operable by keyboard and the spin is a progressive enhancement.
|
|
12
|
+
*
|
|
13
|
+
* @param {object} props
|
|
14
|
+
* @param {"volvelle"|"concentric"|"fan"} [props.variant]
|
|
15
|
+
* @param {DialItem[]} props.items
|
|
16
|
+
* @param {string} [props.value] - Selected item id (controlled).
|
|
17
|
+
* @param {string} [props.defaultValue]
|
|
18
|
+
* @param {(id: string) => void} [props.onChange]
|
|
19
|
+
* @param {boolean} [props.expanded] - Controlled extract state.
|
|
20
|
+
* @param {boolean} [props.defaultExpanded]
|
|
21
|
+
* @param {(expanded: boolean) => void} [props.onExpandedChange]
|
|
22
|
+
* @param {string} [props.label] - Accessible name for the nav landmark.
|
|
23
|
+
* @param {string} [props.className]
|
|
24
|
+
* @returns {import("react").ReactElement}
|
|
25
|
+
*/
|
|
26
|
+
export function DialNav({ variant, items, value, defaultValue, onChange, expanded, defaultExpanded, onExpandedChange, label, className, }: {
|
|
27
|
+
variant?: "volvelle" | "concentric" | "fan" | undefined;
|
|
28
|
+
items: DialItem[];
|
|
29
|
+
value?: string | undefined;
|
|
30
|
+
defaultValue?: string | undefined;
|
|
31
|
+
onChange?: ((id: string) => void) | undefined;
|
|
32
|
+
expanded?: boolean | undefined;
|
|
33
|
+
defaultExpanded?: boolean | undefined;
|
|
34
|
+
onExpandedChange?: ((expanded: boolean) => void) | undefined;
|
|
35
|
+
label?: string | undefined;
|
|
36
|
+
className?: string | undefined;
|
|
37
|
+
}): import("react").ReactElement;
|
|
38
|
+
export type DialItem = {
|
|
39
|
+
id: string;
|
|
40
|
+
label: import("react").ReactNode;
|
|
41
|
+
/**
|
|
42
|
+
* - Route path. Renders a NavLink; requires a Router.
|
|
43
|
+
*/
|
|
44
|
+
to?: string | undefined;
|
|
45
|
+
end?: boolean | undefined;
|
|
46
|
+
onSelect?: (() => void) | undefined;
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=DialNav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DialNav.d.ts","sourceRoot":"","sources":["../../../src/components/DialNav/DialNav.jsx"],"names":[],"mappings":"AAmFA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,2IAZG;IAA8C,OAAO;IAC3B,KAAK,EAAvB,QAAQ,EAAE;IACK,KAAK;IACL,YAAY;IACE,QAAQ,SAAhC,MAAM,KAAK,IAAI;IACJ,QAAQ;IACR,eAAe;IACK,gBAAgB,eAAzC,OAAO,KAAK,IAAI;IACZ,KAAK;IACL,SAAS;CAChC,GAAU,OAAO,OAAO,EAAE,YAAY,CAmVxC;;QA1aa,MAAM;WACN,OAAO,OAAO,EAAE,SAAS;;;;;;sBAGnB,IAAI"}
|