@evinvest/uikit 0.29.4 → 0.31.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/README.md +294 -90
- package/dist/{chunk-3IPB4QQJ.js → chunk-35SPIU4U.js} +10 -6
- package/dist/chunk-35SPIU4U.js.map +1 -0
- package/dist/components/account-list.js +128 -0
- package/dist/components/account-list.js.map +1 -0
- package/dist/components/account-menu-profile.js +114 -0
- package/dist/components/account-menu-profile.js.map +1 -0
- package/dist/components/account-menu.js +50 -23
- package/dist/components/account-menu.js.map +1 -1
- package/dist/components/account-settings-dialog.js +84 -0
- package/dist/components/account-settings-dialog.js.map +1 -0
- package/dist/components/alert-dialog.js +3 -2
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/animated-number-columns.js +105 -0
- package/dist/components/animated-number-columns.js.map +1 -0
- package/dist/components/animated-number.js +157 -0
- package/dist/components/animated-number.js.map +1 -0
- package/dist/components/app-shell.js +9 -0
- package/dist/components/app-shell.js.map +1 -1
- package/dist/components/aside.js +140 -0
- package/dist/components/aside.js.map +1 -0
- package/dist/components/badge.js +1 -1
- package/dist/components/badge.js.map +1 -1
- package/dist/components/button.js +3 -11
- package/dist/components/button.js.map +1 -1
- package/dist/components/chat-composer.js +141 -0
- package/dist/components/chat-composer.js.map +1 -0
- package/dist/components/chat-message.js +195 -0
- package/dist/components/chat-message.js.map +1 -0
- package/dist/components/chat-panel.js +137 -0
- package/dist/components/chat-panel.js.map +1 -0
- package/dist/components/chat-stream-text.js +69 -0
- package/dist/components/chat-stream-text.js.map +1 -0
- package/dist/components/chat-typing.js +26 -0
- package/dist/components/chat-typing.js.map +1 -0
- package/dist/components/command-palette.js +119 -0
- package/dist/components/command-palette.js.map +1 -0
- package/dist/components/command.js +3 -1
- package/dist/components/command.js.map +1 -1
- package/dist/components/confirm-dialog.js +123 -0
- package/dist/components/confirm-dialog.js.map +1 -0
- package/dist/components/context-menu.js +53 -5
- package/dist/components/context-menu.js.map +1 -1
- package/dist/components/dialog.js +3 -2
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/drawer.js +3 -1
- package/dist/components/drawer.js.map +1 -1
- package/dist/components/dropdown-menu.js +64 -5
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/form-row.js +51 -0
- package/dist/components/form-row.js.map +1 -0
- package/dist/components/header-controls.js +149 -0
- package/dist/components/header-controls.js.map +1 -0
- package/dist/components/icon-button.js +35 -0
- package/dist/components/icon-button.js.map +1 -0
- package/dist/components/key-value.js +68 -0
- package/dist/components/key-value.js.map +1 -0
- package/dist/components/menubar.js +39 -5
- package/dist/components/menubar.js.map +1 -1
- package/dist/components/native-select.js +3 -4
- package/dist/components/native-select.js.map +1 -1
- package/dist/components/nav-collapse.js +142 -0
- package/dist/components/nav-collapse.js.map +1 -0
- package/dist/components/nav-model.js.map +1 -1
- package/dist/components/navigation-menu.js +4 -5
- package/dist/components/navigation-menu.js.map +1 -1
- package/dist/components/page-frame.js +2 -5
- package/dist/components/page-frame.js.map +1 -1
- package/dist/components/popover-form.js +60 -0
- package/dist/components/popover-form.js.map +1 -0
- package/dist/components/resource-error.js +1 -1
- package/dist/components/resource-error.js.map +1 -1
- package/dist/components/section-nav.js +73 -20
- package/dist/components/section-nav.js.map +1 -1
- package/dist/components/select.js +16 -6
- package/dist/components/select.js.map +1 -1
- package/dist/components/settings.js +94 -0
- package/dist/components/settings.js.map +1 -0
- package/dist/components/sheet.js +3 -2
- package/dist/components/sheet.js.map +1 -1
- package/dist/components/shell-nav.js +80 -38
- package/dist/components/shell-nav.js.map +1 -1
- package/dist/components/smart-header.js +53 -0
- package/dist/components/smart-header.js.map +1 -0
- package/dist/components/status-item.js +42 -0
- package/dist/components/status-item.js.map +1 -0
- package/dist/components/system-banner.js +22 -12
- package/dist/components/system-banner.js.map +1 -1
- package/dist/components/top-bar.js +4 -3
- package/dist/components/top-bar.js.map +1 -1
- package/dist/components/ui-icons.js +77 -0
- package/dist/components/ui-icons.js.map +1 -0
- package/dist/components/use-count-tween.js +42 -0
- package/dist/components/use-count-tween.js.map +1 -0
- package/dist/components/workspace-tab.js +140 -0
- package/dist/components/workspace-tab.js.map +1 -0
- package/dist/generated/accent.js +2 -2
- package/dist/generated/accent.js.map +1 -1
- package/dist/generated/account-list.js +35 -0
- package/dist/generated/account-list.js.map +1 -0
- package/dist/generated/account-settings-dialog.js +27 -0
- package/dist/generated/account-settings-dialog.js.map +1 -0
- package/dist/generated/alert-dialog.js +1 -1
- package/dist/generated/alert-dialog.js.map +1 -1
- package/dist/generated/alert.js +2 -2
- package/dist/generated/alert.js.map +1 -1
- package/dist/generated/aside.js +36 -0
- package/dist/generated/aside.js.map +1 -0
- package/dist/generated/badge.js +7 -6
- package/dist/generated/badge.js.map +1 -1
- package/dist/generated/band.js +1 -1
- package/dist/generated/band.js.map +1 -1
- package/dist/generated/breadcrumb.js +2 -2
- package/dist/generated/breadcrumb.js.map +1 -1
- package/dist/generated/button-group.js +2 -2
- package/dist/generated/button-group.js.map +1 -1
- package/dist/generated/button.js +4 -4
- package/dist/generated/button.js.map +1 -1
- package/dist/generated/card.js +6 -6
- package/dist/generated/card.js.map +1 -1
- package/dist/generated/chat-composer.js +21 -0
- package/dist/generated/chat-composer.js.map +1 -0
- package/dist/generated/chat-message.js +86 -0
- package/dist/generated/chat-message.js.map +1 -0
- package/dist/generated/chat-typing.js +9 -0
- package/dist/generated/chat-typing.js.map +1 -0
- package/dist/generated/command-palette.js +17 -0
- package/dist/generated/command-palette.js.map +1 -0
- package/dist/generated/command.js +3 -3
- package/dist/generated/command.js.map +1 -1
- package/dist/generated/confirm-dialog.js +28 -0
- package/dist/generated/confirm-dialog.js.map +1 -0
- package/dist/generated/context-menu.js +1 -1
- package/dist/generated/context-menu.js.map +1 -1
- package/dist/generated/date-time-picker.js +1 -1
- package/dist/generated/date-time-picker.js.map +1 -1
- package/dist/generated/dialog.js +1 -1
- package/dist/generated/dialog.js.map +1 -1
- package/dist/generated/drawer.js +1 -1
- package/dist/generated/drawer.js.map +1 -1
- package/dist/generated/dropdown-menu.js +1 -1
- package/dist/generated/dropdown-menu.js.map +1 -1
- package/dist/generated/form-row.js +17 -0
- package/dist/generated/form-row.js.map +1 -0
- package/dist/generated/header-controls.js +56 -0
- package/dist/generated/header-controls.js.map +1 -0
- package/dist/generated/icon-button.js +13 -0
- package/dist/generated/icon-button.js.map +1 -0
- package/dist/generated/key-value.js +15 -0
- package/dist/generated/key-value.js.map +1 -0
- package/dist/generated/menubar.js +1 -1
- package/dist/generated/menubar.js.map +1 -1
- package/dist/generated/navigation-menu.js +1 -1
- package/dist/generated/navigation-menu.js.map +1 -1
- package/dist/generated/popover-form.js +13 -0
- package/dist/generated/popover-form.js.map +1 -0
- package/dist/generated/section-label.js +10 -0
- package/dist/generated/section-label.js.map +1 -0
- package/dist/generated/select.js +15 -3
- package/dist/generated/select.js.map +1 -1
- package/dist/generated/settings.js +36 -0
- package/dist/generated/settings.js.map +1 -0
- package/dist/generated/sheet.js +1 -1
- package/dist/generated/sheet.js.map +1 -1
- package/dist/generated/slider.js +1 -1
- package/dist/generated/slider.js.map +1 -1
- package/dist/generated/smart-header.js +11 -0
- package/dist/generated/smart-header.js.map +1 -0
- package/dist/generated/sonner.js +4 -4
- package/dist/generated/sonner.js.map +1 -1
- package/dist/generated/status-item.js +17 -0
- package/dist/generated/status-item.js.map +1 -0
- package/dist/generated/system-banner.js +33 -0
- package/dist/generated/system-banner.js.map +1 -0
- package/dist/generated/top-bar.js +9 -0
- package/dist/generated/top-bar.js.map +1 -0
- package/dist/generated/workspace-tab.js +17 -0
- package/dist/generated/workspace-tab.js.map +1 -0
- package/dist/index.d.ts +852 -156
- package/dist/index.js +21 -1
- package/dist/lib/cn.js +8 -1
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/number-parts.js +90 -0
- package/dist/lib/number-parts.js.map +1 -0
- package/dist/palette-cli.js +1 -1
- package/dist/palette.d.ts +6 -4
- package/dist/palette.js +3 -1
- package/dist/primitives/dismissable-layer.js +76 -4
- package/dist/primitives/dismissable-layer.js.map +1 -1
- package/dist/primitives/focus-scope.js +20 -5
- package/dist/primitives/focus-scope.js.map +1 -1
- package/dist/primitives/use-floating.js +16 -1
- package/dist/primitives/use-floating.js.map +1 -1
- package/dist/primitives/use-reduced-motion.js +20 -0
- package/dist/primitives/use-reduced-motion.js.map +1 -0
- package/package.json +1 -1
- package/styles/ev.css +281 -49
- package/styles/theme.css +335 -39
- package/styles/tokens.css +643 -103
- package/dist/chunk-3IPB4QQJ.js.map +0 -1
- package/dist/components/terminal.js +0 -206
- package/dist/components/terminal.js.map +0 -1
- package/dist/generated/terminal.js +0 -70
- package/dist/generated/terminal.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/primitives/use-floating.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nexport type Side = \"top\" | \"right\" | \"bottom\" | \"left\";\nexport type Align = \"start\" | \"center\" | \"end\";\n\nexport interface FloatingResult {\n floatingRef: React.RefObject<HTMLElement | null>;\n style: React.CSSProperties;\n side: Side;\n align: Align;\n}\n\n// The element sits at its containing block's origin and is moved with the\n// `translate` property, never with `top`/`left`: an absolute box's\n// shrink-to-fit width is \"containing block minus `left`\", so a `w-fit` surface\n// pushed past the viewport's right edge (horizontal scroll, a nested scroller)\n// would collapse to one word per line. `translate` composes with `transform`,\n// so the enter animations (which animate `transform`) are unaffected. The\n// offset never goes through React: `place()` / `sync()` write it straight to\n// the element, so this style prop stays one frozen object.\nconst ABSOLUTE: React.CSSProperties = Object.freeze({ position: \"absolute\", top: 0, left: 0 });\n\nconst POSITIONED = new Set([\"relative\", \"absolute\", \"fixed\", \"sticky\"]);\n\n/**\n * Converts a viewport-relative point into the coordinate space of the\n * floating element's containing block, i.e. the numbers `position: absolute`\n * expects. floating-ui's `strategy: \"absolute\"` does the same walk.\n */\nfunction toContainingBlock(\n floating: HTMLElement,\n x: number,\n y: number,\n): { x: number; y: number; root: boolean } {\n const parent = floating.offsetParent;\n const doc = floating.ownerDocument;\n const root = parent === doc.body || parent === doc.documentElement || parent === null;\n // `offsetParent` reports `body` even when nothing is positioned; only a\n // positioned body/html really forms a containing block.\n const positioned =\n parent instanceof HTMLElement &&\n (!root || POSITIONED.has(doc.defaultView?.getComputedStyle(parent).position ?? \"\"));\n if (!positioned) {\n const win = doc.defaultView;\n return { x: x + (win?.scrollX ?? 0), y: y + (win?.scrollY ?? 0), root: true };\n }\n const p = parent.getBoundingClientRect();\n return {\n x: x - p.left - parent.clientLeft + parent.scrollLeft,\n y: y - p.top - parent.clientTop + parent.scrollTop,\n root: false,\n };\n}\n\ninterface Size2D {\n width: number;\n height: number;\n}\n\n// The layout box, not `getBoundingClientRect()`: the latter reports the box\n// mid-animation (`zoom-in-95` scales it to 0.95 on the first frame), which\n// placed a top-side popover 5 % of its height too low, over the anchor.\nfunction layoutSize(el: HTMLElement): Size2D {\n return { width: el.offsetWidth, height: el.offsetHeight };\n}\n\nfunction viewport(): { vw: number; vh: number } {\n // `clientWidth` excludes the scrollbar, which the floating element cannot\n // sit under anyway; jsdom reports 0 there, hence the fallback.\n const el = document.documentElement;\n return {\n vw: el.clientWidth || window.innerWidth,\n vh: el.clientHeight || window.innerHeight,\n };\n}\n\n/**\n * Positions a floating element against an anchor with `position: absolute` in\n * the coordinate space of its containing block (the `Portal` puts it in\n * `document.body`, so normally document coordinates) — the dep-light stand-in\n * for `@radix-ui/react-popper` / floating-ui. Supports a preferred\n * `side`/`align`, an `offset`, and a single collision flip onto the opposite\n * side when the preferred side overflows the viewport.\n *\n * Two update modes:\n * - `place()` — full pass (flip + clamp into the viewport) on open, on window\n * `resize`, and whenever the anchor or the floating element changes size.\n * - `sync()` — re-derives the coordinates from the anchor with the side and\n * the clamp shift already chosen; runs on every `scroll` (captured on\n * `window`, so nested scroll containers count too).\n *\n * Because the element is absolutely positioned in the document, a document\n * scroll moves it natively with the page — `sync()` then computes the same\n * numbers and is a no-op — so the overlay never lags behind the compositor.\n * Only a nested scroll container changes the coordinates, and there a frame\n * of lag is acceptable. The side is never revisited on scroll: no jumping.\n * A page that scrolls `body` instead of the document (`html { overflow:\n * hidden } body { overflow: auto }`) is such a nested scroller: correct, but\n * with the frame of lag the `fixed` strategy had.\n *\n * Rust's overlays use CSS-only placement (`data-side`) and do not measure; see\n * the README \"Limitations\".\n */\nexport function useFloating(opts: {\n anchorRef: React.RefObject<Element | null>;\n open: boolean;\n side?: Side;\n align?: Align;\n offset?: number;\n}): FloatingResult {\n const { anchorRef, open, side = \"bottom\", align = \"center\", offset = 4 } = opts;\n const floatingRef = React.useRef<HTMLElement | null>(null);\n const [placedSide, setPlacedSide] = React.useState<Side>(side);\n // The last full placement: the side that won the flip and how far the\n // viewport clamp pushed the element off its ideal spot. `sync()` reuses both\n // instead of measuring against the viewport again.\n const placement = React.useRef<{ side: Side; shiftX: number; shiftY: number }>({\n side,\n shiftX: 0,\n shiftY: 0,\n });\n\n React.useLayoutEffect(() => {\n if (!open) return;\n\n function ideal(a: DOMRect, f: Size2D, placed: Side): { top: number; left: number } {\n let top = 0;\n let left = 0;\n const vertical = placed === \"top\" || placed === \"bottom\";\n\n if (placed === \"bottom\") top = a.bottom + offset;\n else if (placed === \"top\") top = a.top - offset - f.height;\n else if (placed === \"right\") left = a.right + offset;\n else left = a.left - offset - f.width;\n\n if (vertical) {\n if (align === \"start\") left = a.left;\n else if (align === \"end\") left = a.right - f.width;\n else left = a.left + a.width / 2 - f.width / 2;\n } else {\n if (align === \"start\") top = a.top;\n else if (align === \"end\") top = a.bottom - f.height;\n else top = a.top + a.height / 2 - f.height / 2;\n }\n return { top, left };\n }\n\n // `contain` keeps the box inside the initial containing block: a box past\n // the document's edge grows the page (a scrollbar shows for as long as the\n // overlay is open). `place()` already clamps against the viewport;\n // `sync()` follows a nested scroller's anchor and only needs this bound.\n function write(floating: HTMLElement, f: Size2D, top: number, left: number, contain: boolean) {\n const p = toContainingBlock(floating, left, top);\n let { x, y } = p;\n if (contain && p.root) {\n const icbWidth = floating.ownerDocument.documentElement.clientWidth || window.innerWidth;\n x = Math.max(0, Math.min(x, icbWidth - f.width));\n y = Math.max(0, y);\n }\n floating.style.translate = `${Math.round(x)}px ${Math.round(y)}px`;\n }\n\n function place() {\n const anchor = anchorRef.current;\n const floating = floatingRef.current;\n if (!anchor || !floating) return;\n\n const a = anchor.getBoundingClientRect();\n const f = layoutSize(floating);\n const { vw, vh } = viewport();\n\n let placed: Side = side;\n if (side === \"bottom\" && a.bottom + offset + f.height > vh && a.top - offset - f.height > 0)\n placed = \"top\";\n else if (side === \"top\" && a.top - offset - f.height < 0 && a.bottom + offset + f.height < vh)\n placed = \"bottom\";\n else if (side === \"right\" && a.right + offset + f.width > vw && a.left - offset - f.width > 0)\n placed = \"left\";\n else if (side === \"left\" && a.left - offset - f.width < 0 && a.right + offset + f.width < vw)\n placed = \"right\";\n\n const { top, left } = ideal(a, f, placed);\n const clampedLeft = Math.max(offset, Math.min(left, vw - f.width - offset));\n const clampedTop = Math.max(offset, Math.min(top, vh - f.height - offset));\n\n placement.current = {\n side: placed,\n shiftX: clampedLeft - left,\n shiftY: clampedTop - top,\n };\n write(floating, f, clampedTop, clampedLeft, false);\n // Only a real change may re-render: this runs on every resize tick.\n setPlacedSide(prev => (prev === placed ? prev : placed));\n }\n\n function sync() {\n const anchor = anchorRef.current;\n const floating = floatingRef.current;\n if (!anchor || !floating) return;\n\n const a = anchor.getBoundingClientRect();\n const f = layoutSize(floating);\n const { side: placed, shiftX, shiftY } = placement.current;\n const { top, left } = ideal(a, f, placed);\n write(floating, f, top + shiftY, left + shiftX, true);\n }\n\n place();\n // No rAF: `scroll` already fires at most once per frame, and a synchronous\n // DOM write from the handler lands in that same frame — rAF would cost one.\n window.addEventListener(\"scroll\", sync, true);\n window.addEventListener(\"resize\", place);\n\n let observer: ResizeObserver | undefined;\n if (typeof ResizeObserver !== \"undefined\") {\n observer = new ResizeObserver(place);\n if (anchorRef.current) observer.observe(anchorRef.current);\n if (floatingRef.current) observer.observe(floatingRef.current);\n }\n\n return () => {\n window.removeEventListener(\"scroll\", sync, true);\n window.removeEventListener(\"resize\", place);\n observer?.disconnect();\n };\n }, [open, side, align, offset, anchorRef]);\n\n return { floatingRef, style: ABSOLUTE, side: placedSide, align };\n}\n"],"mappings":";AAEA,YAAY,WAAW;AAoBvB,MAAM,WAAgC,OAAO,OAAO,EAAE,UAAU,YAAY,KAAK,GAAG,MAAM,EAAE,CAAC;AAE7F,MAAM,aAAa,oBAAI,IAAI,CAAC,YAAY,YAAY,SAAS,QAAQ,CAAC;AAOtE,SAAS,kBACP,UACA,GACA,GACyC;AACzC,QAAM,SAAS,SAAS;AACxB,QAAM,MAAM,SAAS;AACrB,QAAM,OAAO,WAAW,IAAI,QAAQ,WAAW,IAAI,mBAAmB,WAAW;AAGjF,QAAM,aACJ,kBAAkB,gBACjB,CAAC,QAAQ,WAAW,IAAI,IAAI,aAAa,iBAAiB,MAAM,EAAE,YAAY,EAAE;AACnF,MAAI,CAAC,YAAY;AACf,UAAM,MAAM,IAAI;AAChB,WAAO,EAAE,GAAG,KAAK,KAAK,WAAW,IAAI,GAAG,KAAK,KAAK,WAAW,IAAI,MAAM,KAAK;AAAA,EAC9E;AACA,QAAM,IAAI,OAAO,sBAAsB;AACvC,SAAO;AAAA,IACL,GAAG,IAAI,EAAE,OAAO,OAAO,aAAa,OAAO;AAAA,IAC3C,GAAG,IAAI,EAAE,MAAM,OAAO,YAAY,OAAO;AAAA,IACzC,MAAM;AAAA,EACR;AACF;AAUA,SAAS,WAAW,IAAyB;AAC3C,SAAO,EAAE,OAAO,GAAG,aAAa,QAAQ,GAAG,aAAa;AAC1D;AAEA,SAAS,WAAuC;AAG9C,QAAM,KAAK,SAAS;AACpB,SAAO;AAAA,IACL,IAAI,GAAG,eAAe,OAAO;AAAA,IAC7B,IAAI,GAAG,gBAAgB,OAAO;AAAA,EAChC;AACF;AA6BO,SAAS,YAAY,MAMT;AACjB,QAAM,EAAE,WAAW,MAAM,OAAO,UAAU,QAAQ,UAAU,SAAS,EAAE,IAAI;AAC3E,QAAM,cAAc,MAAM,OAA2B,IAAI;AACzD,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAe,IAAI;AAI7D,QAAM,YAAY,MAAM,OAAuD;AAAA,IAC7E;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,gBAAgB,MAAM;AAC1B,QAAI,CAAC,KAAM;AAEX,aAAS,MAAM,GAAY,GAAW,QAA6C;AACjF,UAAI,MAAM;AACV,UAAI,OAAO;AACX,YAAM,WAAW,WAAW,SAAS,WAAW;AAEhD,UAAI,WAAW,SAAU,OAAM,EAAE,SAAS;AAAA,eACjC,WAAW,MAAO,OAAM,EAAE,MAAM,SAAS,EAAE;AAAA,eAC3C,WAAW,QAAS,QAAO,EAAE,QAAQ;AAAA,UACzC,QAAO,EAAE,OAAO,SAAS,EAAE;AAEhC,UAAI,UAAU;AACZ,YAAI,UAAU,QAAS,QAAO,EAAE;AAAA,iBACvB,UAAU,MAAO,QAAO,EAAE,QAAQ,EAAE;AAAA,YACxC,QAAO,EAAE,OAAO,EAAE,QAAQ,IAAI,EAAE,QAAQ;AAAA,MAC/C,OAAO;AACL,YAAI,UAAU,QAAS,OAAM,EAAE;AAAA,iBACtB,UAAU,MAAO,OAAM,EAAE,SAAS,EAAE;AAAA,YACxC,OAAM,EAAE,MAAM,EAAE,SAAS,IAAI,EAAE,SAAS;AAAA,MAC/C;AACA,aAAO,EAAE,KAAK,KAAK;AAAA,IACrB;AAMA,aAAS,MAAM,UAAuB,GAAW,KAAa,MAAc,SAAkB;AAC5F,YAAM,IAAI,kBAAkB,UAAU,MAAM,GAAG;AAC/C,UAAI,EAAE,GAAG,EAAE,IAAI;AACf,UAAI,WAAW,EAAE,MAAM;AACrB,cAAM,WAAW,SAAS,cAAc,gBAAgB,eAAe,OAAO;AAC9E,YAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,WAAW,EAAE,KAAK,CAAC;AAC/C,YAAI,KAAK,IAAI,GAAG,CAAC;AAAA,MACnB;AACA,eAAS,MAAM,YAAY,GAAG,KAAK,MAAM,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;AAAA,IAChE;AAEA,aAAS,QAAQ;AACf,YAAM,SAAS,UAAU;AACzB,YAAM,WAAW,YAAY;AAC7B,UAAI,CAAC,UAAU,CAAC,SAAU;AAE1B,YAAM,IAAI,OAAO,sBAAsB;AACvC,YAAM,IAAI,WAAW,QAAQ;AAC7B,YAAM,EAAE,IAAI,GAAG,IAAI,SAAS;AAE5B,UAAI,SAAe;AACnB,UAAI,SAAS,YAAY,EAAE,SAAS,SAAS,EAAE,SAAS,MAAM,EAAE,MAAM,SAAS,EAAE,SAAS;AACxF,iBAAS;AAAA,eACF,SAAS,SAAS,EAAE,MAAM,SAAS,EAAE,SAAS,KAAK,EAAE,SAAS,SAAS,EAAE,SAAS;AACzF,iBAAS;AAAA,eACF,SAAS,WAAW,EAAE,QAAQ,SAAS,EAAE,QAAQ,MAAM,EAAE,OAAO,SAAS,EAAE,QAAQ;AAC1F,iBAAS;AAAA,eACF,SAAS,UAAU,EAAE,OAAO,SAAS,EAAE,QAAQ,KAAK,EAAE,QAAQ,SAAS,EAAE,QAAQ;AACxF,iBAAS;AAEX,YAAM,EAAE,KAAK,KAAK,IAAI,MAAM,GAAG,GAAG,MAAM;AACxC,YAAM,cAAc,KAAK,IAAI,QAAQ,KAAK,IAAI,MAAM,KAAK,EAAE,QAAQ,MAAM,CAAC;AAC1E,YAAM,aAAa,KAAK,IAAI,QAAQ,KAAK,IAAI,KAAK,KAAK,EAAE,SAAS,MAAM,CAAC;AAEzE,gBAAU,UAAU;AAAA,QAClB,MAAM;AAAA,QACN,QAAQ,cAAc;AAAA,QACtB,QAAQ,aAAa;AAAA,MACvB;AACA,YAAM,UAAU,GAAG,YAAY,aAAa,KAAK;AAEjD,oBAAc,UAAS,SAAS,SAAS,OAAO,MAAO;AAAA,IACzD;AAEA,aAAS,OAAO;AACd,YAAM,SAAS,UAAU;AACzB,YAAM,WAAW,YAAY;AAC7B,UAAI,CAAC,UAAU,CAAC,SAAU;AAE1B,YAAM,IAAI,OAAO,sBAAsB;AACvC,YAAM,IAAI,WAAW,QAAQ;AAC7B,YAAM,EAAE,MAAM,QAAQ,QAAQ,OAAO,IAAI,UAAU;AACnD,YAAM,EAAE,KAAK,KAAK,IAAI,MAAM,GAAG,GAAG,MAAM;AACxC,YAAM,UAAU,GAAG,MAAM,QAAQ,OAAO,QAAQ,IAAI;AAAA,IACtD;AAEA,UAAM;AAGN,WAAO,iBAAiB,UAAU,MAAM,IAAI;AAC5C,WAAO,iBAAiB,UAAU,KAAK;AAEvC,QAAI;AACJ,QAAI,OAAO,mBAAmB,aAAa;AACzC,iBAAW,IAAI,eAAe,KAAK;AACnC,UAAI,UAAU,QAAS,UAAS,QAAQ,UAAU,OAAO;AACzD,UAAI,YAAY,QAAS,UAAS,QAAQ,YAAY,OAAO;AAAA,IAC/D;AAEA,WAAO,MAAM;AACX,aAAO,oBAAoB,UAAU,MAAM,IAAI;AAC/C,aAAO,oBAAoB,UAAU,KAAK;AAC1C,gBAAU,WAAW;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,MAAM,MAAM,OAAO,QAAQ,SAAS,CAAC;AAEzC,SAAO,EAAE,aAAa,OAAO,UAAU,MAAM,YAAY,MAAM;AACjE;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/primitives/use-floating.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nexport type Side = \"top\" | \"right\" | \"bottom\" | \"left\";\nexport type Align = \"start\" | \"center\" | \"end\";\n\nexport interface FloatingResult {\n floatingRef: React.RefObject<HTMLElement | null>;\n style: React.CSSProperties;\n side: Side;\n align: Align;\n}\n\n// The element sits at its containing block's origin and is moved with the\n// `translate` property, never with `top`/`left`: an absolute box's\n// shrink-to-fit width is \"containing block minus `left`\", so a `w-fit` surface\n// pushed past the viewport's right edge (horizontal scroll, a nested scroller)\n// would collapse to one word per line. `translate` composes with `transform`,\n// so the enter animations (which animate `transform`) are unaffected. The\n// offset never goes through React: `place()` / `sync()` write it straight to\n// the element, so this style prop stays one frozen object.\nconst ABSOLUTE: React.CSSProperties = Object.freeze({ position: \"absolute\", top: 0, left: 0 });\n\nconst POSITIONED = new Set([\"relative\", \"absolute\", \"fixed\", \"sticky\"]);\n\n/**\n * Converts a viewport-relative point into the coordinate space of the\n * floating element's containing block, i.e. the numbers `position: absolute`\n * expects. floating-ui's `strategy: \"absolute\"` does the same walk.\n */\nfunction toContainingBlock(\n floating: HTMLElement,\n x: number,\n y: number,\n): { x: number; y: number; root: boolean } {\n const parent = floating.offsetParent;\n const doc = floating.ownerDocument;\n const root = parent === doc.body || parent === doc.documentElement || parent === null;\n // `offsetParent` reports `body` even when nothing is positioned; only a\n // positioned body/html really forms a containing block.\n const positioned =\n parent instanceof HTMLElement &&\n (!root || POSITIONED.has(doc.defaultView?.getComputedStyle(parent).position ?? \"\"));\n if (!positioned) {\n const win = doc.defaultView;\n return { x: x + (win?.scrollX ?? 0), y: y + (win?.scrollY ?? 0), root: true };\n }\n const p = parent.getBoundingClientRect();\n return {\n x: x - p.left - parent.clientLeft + parent.scrollLeft,\n y: y - p.top - parent.clientTop + parent.scrollTop,\n root: false,\n };\n}\n\ninterface Size2D {\n width: number;\n height: number;\n}\n\n// The layout box, not `getBoundingClientRect()`: the latter reports the box\n// mid-animation (`zoom-in-95` scales it to 0.95 on the first frame), which\n// placed a top-side popover 5 % of its height too low, over the anchor.\nfunction layoutSize(el: HTMLElement): Size2D {\n return { width: el.offsetWidth, height: el.offsetHeight };\n}\n\n// jsdom has no `getAnimations`; there nothing animates.\nfunction hasRunningAnimationAbove(el: Element): boolean {\n for (let node = el.parentElement; node; node = node.parentElement) {\n if (node.getAnimations?.().some((a) => a.playState === \"running\")) return true;\n }\n return false;\n}\n\nfunction viewport(): { vw: number; vh: number } {\n // `clientWidth` excludes the scrollbar, which the floating element cannot\n // sit under anyway; jsdom reports 0 there, hence the fallback.\n const el = document.documentElement;\n return {\n vw: el.clientWidth || window.innerWidth,\n vh: el.clientHeight || window.innerHeight,\n };\n}\n\n/**\n * Positions a floating element against an anchor with `position: absolute` in\n * the coordinate space of its containing block (the `Portal` puts it in\n * `document.body`, so normally document coordinates) — the dep-light stand-in\n * for `@radix-ui/react-popper` / floating-ui. Supports a preferred\n * `side`/`align`, an `offset`, and a single collision flip onto the opposite\n * side when the preferred side overflows the viewport.\n *\n * Two update modes:\n * - `place()` — full pass (flip + clamp into the viewport) on open, on window\n * `resize`, and whenever the anchor or the floating element changes size.\n * - `sync()` — re-derives the coordinates from the anchor with the side and\n * the clamp shift already chosen; runs on every `scroll` (captured on\n * `window`, so nested scroll containers count too).\n *\n * Because the element is absolutely positioned in the document, a document\n * scroll moves it natively with the page — `sync()` then computes the same\n * numbers and is a no-op — so the overlay never lags behind the compositor.\n * Only a nested scroll container changes the coordinates, and there a frame\n * of lag is acceptable. The side is never revisited on scroll: no jumping.\n * A page that scrolls `body` instead of the document (`html { overflow:\n * hidden } body { overflow: auto }`) is such a nested scroller: correct, but\n * with the frame of lag the `fixed` strategy had.\n *\n * Rust's overlays use CSS-only placement (`data-side`) and do not measure; see\n * the README \"Limitations\".\n */\nexport function useFloating(opts: {\n anchorRef: React.RefObject<Element | null>;\n open: boolean;\n side?: Side;\n align?: Align;\n offset?: number;\n}): FloatingResult {\n const { anchorRef, open, side = \"bottom\", align = \"center\", offset = 4 } = opts;\n const floatingRef = React.useRef<HTMLElement | null>(null);\n const [placedSide, setPlacedSide] = React.useState<Side>(side);\n // The last full placement: the side that won the flip and how far the\n // viewport clamp pushed the element off its ideal spot. `sync()` reuses both\n // instead of measuring against the viewport again.\n const placement = React.useRef<{ side: Side; shiftX: number; shiftY: number }>({\n side,\n shiftX: 0,\n shiftY: 0,\n });\n\n React.useLayoutEffect(() => {\n if (!open) return;\n\n function ideal(a: DOMRect, f: Size2D, placed: Side): { top: number; left: number } {\n let top = 0;\n let left = 0;\n const vertical = placed === \"top\" || placed === \"bottom\";\n\n if (placed === \"bottom\") top = a.bottom + offset;\n else if (placed === \"top\") top = a.top - offset - f.height;\n else if (placed === \"right\") left = a.right + offset;\n else left = a.left - offset - f.width;\n\n if (vertical) {\n if (align === \"start\") left = a.left;\n else if (align === \"end\") left = a.right - f.width;\n else left = a.left + a.width / 2 - f.width / 2;\n } else {\n if (align === \"start\") top = a.top;\n else if (align === \"end\") top = a.bottom - f.height;\n else top = a.top + a.height / 2 - f.height / 2;\n }\n return { top, left };\n }\n\n // `contain` keeps the box inside the initial containing block: a box past\n // the document's edge grows the page (a scrollbar shows for as long as the\n // overlay is open). `place()` already clamps against the viewport;\n // `sync()` follows a nested scroller's anchor and only needs this bound.\n function write(floating: HTMLElement, f: Size2D, top: number, left: number, contain: boolean) {\n const p = toContainingBlock(floating, left, top);\n let { x, y } = p;\n if (contain && p.root) {\n const icbWidth = floating.ownerDocument.documentElement.clientWidth || window.innerWidth;\n x = Math.max(0, Math.min(x, icbWidth - f.width));\n y = Math.max(0, y);\n }\n floating.style.translate = `${Math.round(x)}px ${Math.round(y)}px`;\n }\n\n function place() {\n const anchor = anchorRef.current;\n const floating = floatingRef.current;\n if (!anchor || !floating) return;\n\n const a = anchor.getBoundingClientRect();\n const f = layoutSize(floating);\n const { vw, vh } = viewport();\n\n let placed: Side = side;\n if (side === \"bottom\" && a.bottom + offset + f.height > vh && a.top - offset - f.height > 0)\n placed = \"top\";\n else if (side === \"top\" && a.top - offset - f.height < 0 && a.bottom + offset + f.height < vh)\n placed = \"bottom\";\n else if (side === \"right\" && a.right + offset + f.width > vw && a.left - offset - f.width > 0)\n placed = \"left\";\n else if (side === \"left\" && a.left - offset - f.width < 0 && a.right + offset + f.width < vw)\n placed = \"right\";\n\n const { top, left } = ideal(a, f, placed);\n const clampedLeft = Math.max(offset, Math.min(left, vw - f.width - offset));\n const clampedTop = Math.max(offset, Math.min(top, vh - f.height - offset));\n\n placement.current = {\n side: placed,\n shiftX: clampedLeft - left,\n shiftY: clampedTop - top,\n };\n write(floating, f, clampedTop, clampedLeft, false);\n // Only a real change may re-render: this runs on every resize tick.\n setPlacedSide(prev => (prev === placed ? prev : placed));\n }\n\n function sync() {\n const anchor = anchorRef.current;\n const floating = floatingRef.current;\n if (!anchor || !floating) return;\n\n const a = anchor.getBoundingClientRect();\n const f = layoutSize(floating);\n const { side: placed, shiftX, shiftY } = placement.current;\n const { top, left } = ideal(a, f, placed);\n write(floating, f, top + shiftY, left + shiftX, true);\n }\n\n // An anchor inside an entering dialog is measured scaled and shifted by the\n // dialog's animation (`zoom-in-95`), which places the floating element off\n // its anchor for good: no resize or scroll follows the animation's end. So\n // keep re-placing, a frame at a time, until no ancestor animates.\n let frame = 0;\n function follow() {\n frame = 0;\n place();\n if (anchorRef.current && hasRunningAnimationAbove(anchorRef.current)) {\n frame = requestAnimationFrame(follow);\n }\n }\n follow();\n // No rAF: `scroll` already fires at most once per frame, and a synchronous\n // DOM write from the handler lands in that same frame — rAF would cost one.\n window.addEventListener(\"scroll\", sync, true);\n window.addEventListener(\"resize\", place);\n\n let observer: ResizeObserver | undefined;\n if (typeof ResizeObserver !== \"undefined\") {\n observer = new ResizeObserver(place);\n if (anchorRef.current) observer.observe(anchorRef.current);\n if (floatingRef.current) observer.observe(floatingRef.current);\n }\n\n return () => {\n if (frame) cancelAnimationFrame(frame);\n window.removeEventListener(\"scroll\", sync, true);\n window.removeEventListener(\"resize\", place);\n observer?.disconnect();\n };\n }, [open, side, align, offset, anchorRef]);\n\n return { floatingRef, style: ABSOLUTE, side: placedSide, align };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
const QUERY = "(prefers-reduced-motion: reduce)";
|
|
4
|
+
function subscribe(notify) {
|
|
5
|
+
if (typeof window.matchMedia !== "function") return () => {
|
|
6
|
+
};
|
|
7
|
+
const mq = window.matchMedia(QUERY);
|
|
8
|
+
mq.addEventListener("change", notify);
|
|
9
|
+
return () => mq.removeEventListener("change", notify);
|
|
10
|
+
}
|
|
11
|
+
function snapshot() {
|
|
12
|
+
return typeof window.matchMedia === "function" && window.matchMedia(QUERY).matches;
|
|
13
|
+
}
|
|
14
|
+
function useReducedMotion() {
|
|
15
|
+
return React.useSyncExternalStore(subscribe, snapshot, () => false);
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
useReducedMotion
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=use-reduced-motion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/primitives/use-reduced-motion.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nconst QUERY = \"(prefers-reduced-motion: reduce)\";\n\nfunction subscribe(notify: () => void): () => void {\n if (typeof window.matchMedia !== \"function\") return () => {};\n const mq = window.matchMedia(QUERY);\n mq.addEventListener(\"change\", notify);\n return () => mq.removeEventListener(\"change\", notify);\n}\n\nfunction snapshot(): boolean {\n return typeof window.matchMedia === \"function\" && window.matchMedia(QUERY).matches;\n}\n\n/**\n * True when the user asked for less motion. The server and the hydration pass\n * answer false, so markup matches; a reduced-motion client corrects it on the\n * first commit, before anything has animated.\n */\nexport function useReducedMotion(): boolean {\n return React.useSyncExternalStore(subscribe, snapshot, () => false);\n}\n"],"mappings":";AAEA,YAAY,WAAW;AAEvB,MAAM,QAAQ;AAEd,SAAS,UAAU,QAAgC;AACjD,MAAI,OAAO,OAAO,eAAe,WAAY,QAAO,MAAM;AAAA,EAAC;AAC3D,QAAM,KAAK,OAAO,WAAW,KAAK;AAClC,KAAG,iBAAiB,UAAU,MAAM;AACpC,SAAO,MAAM,GAAG,oBAAoB,UAAU,MAAM;AACtD;AAEA,SAAS,WAAoB;AAC3B,SAAO,OAAO,OAAO,eAAe,cAAc,OAAO,WAAW,KAAK,EAAE;AAC7E;AAOO,SAAS,mBAA4B;AAC1C,SAAO,MAAM,qBAAqB,WAAW,UAAU,MAAM,KAAK;AACpE;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evinvest/uikit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "Dep-light React UI kit: shadcn-semantics components with zero @radix-ui / cva, mirroring the ev_lib::uikit Rust feature. Ships the shared design tokens.",
|
|
5
5
|
"license": "BlueOak-1.0.0",
|
|
6
6
|
"publishConfig": {
|
package/styles/ev.css
CHANGED
|
@@ -1,75 +1,307 @@
|
|
|
1
1
|
/* AUTO-GENERATED by `nix run .#gen` from the repo-root ev.css — do not edit. */
|
|
2
2
|
/* ═══ PALETTE: EV ════════════════════════════════════════════════
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
4
|
+
* Three themes, each a zero-specificity rule: a brand scope overrides them
|
|
5
|
+
* whatever order the sheets are imported in, and later rules here win over
|
|
6
|
+
* earlier ones on the same element (so the order below is load-bearing).
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
8
|
+
* u2 Dark the default: `:root`, `[data-brand="ev"]`, or a `.dark` wrapper
|
|
9
|
+
* u2 Light a `.light` wrapper (on <html> or on any section)
|
|
10
|
+
* Oldschool `[data-theme="oldschool"]`: the navy look the kit shipped before
|
|
11
|
+
* 1.0, single-polarity, rounder, with shadows
|
|
12
|
+
*
|
|
13
|
+
* Each rule pins every EV-specific token, so a wrapper of one theme nested in
|
|
14
|
+
* another replaces all of it and leaks nothing. A brand scope is not EV: the
|
|
15
|
+
* `:not(…)` guard keeps these pins out of a `[data-brand]` subtree (and off the
|
|
16
|
+
* brand's own element), where the brand's palette and the derived formulas in
|
|
17
|
+
* theme.css apply instead. Without it a brand's `.light` would inherit EV
|
|
18
|
+
* Light's hover and borders.
|
|
19
|
+
*
|
|
20
|
+
* Surface ladder — the u2 planes sit 1.04–1.14:1 apart, which is the design
|
|
21
|
+
* (flat, no tinted fills) and under the ~1.2 floor in AGENTS.md. Planes are
|
|
22
|
+
* separated by a `--border` hairline instead: 1.37–1.46:1 on Dark and 1.35:1 on
|
|
23
|
+
* Light, measured with the alpha composited onto the plane. Do not lift a plane
|
|
24
|
+
* to chase the ratio; retune the hairline, and tokens.test.ts will measure it.
|
|
25
|
+
* Oldschool keeps its own, wider ladder: #070d18 → card #16233c (1.24:1) →
|
|
26
|
+
* popover #1d2c49 (1.13:1), with --primary held at 3:1 against the popover.
|
|
27
|
+
*
|
|
28
|
+
* Where a Figma value failed a floor the nearest passing one is pinned
|
|
29
|
+
* instead; the comment beside each says which.
|
|
14
30
|
*/
|
|
15
|
-
|
|
31
|
+
|
|
32
|
+
/* ── u2 Dark ─────────────────────────────────────────────────── */
|
|
33
|
+
:where(:is(:root, [data-brand="ev"], .dark):not([data-brand]:not([data-brand="ev"]), [data-brand]:not([data-brand="ev"]) *)) {
|
|
16
34
|
/* the polarity, for what the platform draws itself (a native <select>'s
|
|
17
35
|
* popup); a custom property so nothing but the kit's opt-ins reads it */
|
|
18
36
|
--scheme: dark;
|
|
19
37
|
|
|
20
|
-
/*
|
|
38
|
+
/* surfaces */
|
|
39
|
+
--background: #0d0d0f;
|
|
40
|
+
--card: #151518;
|
|
41
|
+
--secondary: #1c1c20;
|
|
42
|
+
--on-secondary: var(--ink);
|
|
43
|
+
--popover: #252529;
|
|
44
|
+
--muted: #070709;
|
|
45
|
+
--hover: #e6e1d30f;
|
|
46
|
+
--active: #e6e1d31a;
|
|
47
|
+
--selected: #e6e1d31a;
|
|
48
|
+
--scrim: #000000a8;
|
|
49
|
+
|
|
50
|
+
/* ink: the Figma steps, opaque, so the text floor is measured on the value
|
|
51
|
+
* that paints (tertiary is 4.53:1 on the popover, the tightest plane) */
|
|
52
|
+
--ink: #e6e1d3;
|
|
53
|
+
--ink-mid: #bebab1;
|
|
54
|
+
--ink-soft: #8d8c87;
|
|
55
|
+
--ink-faint: #5e5e5b;
|
|
56
|
+
|
|
57
|
+
/* lines. --input stays the derived 48 % ink: the control edge owes 3:1 and
|
|
58
|
+
* Figma has no variable for it. */
|
|
59
|
+
--border-subtle: #e6e1d314;
|
|
60
|
+
--border: #e6e1d324;
|
|
61
|
+
--border-strong: #e6e1d342;
|
|
62
|
+
--ring: #35a395;
|
|
63
|
+
|
|
64
|
+
/* brand and primary. A fill and an ink are different jobs (docs/spec/accents.md):
|
|
65
|
+
* --primary carries white at 4.62:1 and reads as a shape on every plane (3.30:1
|
|
66
|
+
* on the popover); --primary-ink is the teal that reads as text (4.96:1 there).
|
|
67
|
+
* Figma's hover #18998b is 3.52:1 under white, so #127c71 (5.06:1) is pinned. */
|
|
68
|
+
--brand: #0d1627;
|
|
69
|
+
--primary: #138377;
|
|
70
|
+
--on-primary: #ffffff;
|
|
71
|
+
--primary-ink: #35a395;
|
|
72
|
+
--primary-hover: #127c71;
|
|
73
|
+
--primary-border: #35a3958c;
|
|
74
|
+
|
|
75
|
+
/* status. Fills carry the dark label (white fails 3:1–3.4:1 on these); the
|
|
76
|
+
* *-ink values are the ones to use as text. */
|
|
77
|
+
--positive: #2e9e5c;
|
|
78
|
+
--on-positive: #0d0d0f;
|
|
79
|
+
--positive-ink: #4abf76;
|
|
80
|
+
--accent-trace: #6b7fa0;
|
|
81
|
+
--on-accent-trace: #0d0d0f;
|
|
82
|
+
--accent-debug: #35a395;
|
|
83
|
+
--on-accent-debug: #0d0d0f;
|
|
84
|
+
--accent-info: #4990d8;
|
|
85
|
+
--on-accent-info: #0d0d0f;
|
|
86
|
+
--accent-info-ink: #6ca6e4;
|
|
87
|
+
--accent-warn: #f5c84e;
|
|
88
|
+
--on-accent-warn: #0d0d0f;
|
|
89
|
+
--accent-error: #f05b52;
|
|
90
|
+
--on-accent-error: #0d0d0f;
|
|
91
|
+
|
|
92
|
+
--chart-1: #35a395;
|
|
93
|
+
--chart-2: #4990d8;
|
|
94
|
+
--chart-3: #f5c84e;
|
|
95
|
+
--chart-4: #e68aaf;
|
|
96
|
+
--chart-5: #2e9e5c;
|
|
97
|
+
--chart-6: #988eef;
|
|
98
|
+
|
|
99
|
+
--button-primary-bg: #e6e1d300;
|
|
100
|
+
--button-primary-hover: #e6e1d314;
|
|
101
|
+
--button-primary-border: #e6e1d399;
|
|
102
|
+
--button-primary-ink: #e6e1d3;
|
|
103
|
+
--button-danger-bg: #f05b5200;
|
|
104
|
+
--button-danger-hover: #f05b521a;
|
|
105
|
+
--button-danger-border: #f05b52;
|
|
106
|
+
--button-danger-ink: var(--accent-error);
|
|
107
|
+
|
|
108
|
+
/* chips are outlines: a transparent fill and the label's hue at 50 % */
|
|
109
|
+
--chip-neutral-bg: var(--hover);
|
|
110
|
+
--chip-neutral-border: var(--border);
|
|
111
|
+
--chip-primary-bg: #35a39500;
|
|
112
|
+
--chip-primary-border: #35a3958c;
|
|
113
|
+
--chip-positive-bg: #2e9e5c00;
|
|
114
|
+
--chip-positive-border: #4abf7680;
|
|
115
|
+
--chip-info-bg: #4990d800;
|
|
116
|
+
--chip-info-border: #6ca6e480;
|
|
117
|
+
--chip-warn-bg: #f5c84e00;
|
|
118
|
+
--chip-warn-border: #f5c84e80;
|
|
119
|
+
--chip-error-bg: #f05b5200;
|
|
120
|
+
--chip-error-border: #f05b5280;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* ── u2 Light ────────────────────────────────────────────────── */
|
|
124
|
+
:where(.light:not([data-brand]:not([data-brand="ev"]), [data-brand]:not([data-brand="ev"]) *)) {
|
|
125
|
+
--scheme: light;
|
|
126
|
+
|
|
127
|
+
--background: #efebdf;
|
|
128
|
+
--card: #f6f3eb;
|
|
129
|
+
--secondary: #fbfaf6;
|
|
130
|
+
--on-secondary: var(--ink);
|
|
131
|
+
--popover: #ffffff;
|
|
132
|
+
--muted: #e6e1d3;
|
|
133
|
+
--hover: #0d0d0f0d;
|
|
134
|
+
--active: #0d0d0f17;
|
|
135
|
+
--selected: #0d0d0f14;
|
|
136
|
+
--scrim: #00000066;
|
|
137
|
+
|
|
138
|
+
--ink: #0d0d0f;
|
|
139
|
+
--ink-mid: #3d3d41;
|
|
140
|
+
--ink-soft: #67696c;
|
|
141
|
+
--ink-faint: #9a9b9e;
|
|
142
|
+
|
|
143
|
+
--border-subtle: #0d0d0f14;
|
|
144
|
+
--border: #0d0d0f24;
|
|
145
|
+
--border-strong: #0d0d0f47;
|
|
146
|
+
--ring: #138377;
|
|
147
|
+
|
|
148
|
+
--brand: #080e1a;
|
|
149
|
+
--primary: #138377;
|
|
150
|
+
--on-primary: #ffffff;
|
|
151
|
+
--primary-ink: #116f65;
|
|
152
|
+
--primary-hover: #116f65;
|
|
153
|
+
--primary-border: #116f658c;
|
|
154
|
+
|
|
155
|
+
/* Figma's positive #228a4e carries neither label at 4.5:1 (white 4.36, dark
|
|
156
|
+
* 4.45), so the fill is one step darker: white reads at 5.01:1. */
|
|
157
|
+
--positive: #1f7f48;
|
|
158
|
+
--on-positive: #ffffff;
|
|
159
|
+
--positive-ink: #1b7943;
|
|
160
|
+
--accent-trace: #5a6b7c;
|
|
161
|
+
--on-accent-trace: #ffffff;
|
|
162
|
+
--accent-debug: #116f65;
|
|
163
|
+
--on-accent-debug: #ffffff;
|
|
164
|
+
--accent-info: #2d79c2;
|
|
165
|
+
--on-accent-info: #ffffff;
|
|
166
|
+
--accent-info-ink: #25639f;
|
|
167
|
+
/* Figma's #d8a523 is 1.89:1 on the page plane; warn is text in its own
|
|
168
|
+
* colour, so it is darkened toward Figma's warn text #846305 until it clears
|
|
169
|
+
* the non-text 3:1 (3.10:1) */
|
|
170
|
+
--accent-warn: #a77f12;
|
|
171
|
+
--on-accent-warn: #0d0d0f;
|
|
172
|
+
--accent-error: #db3834;
|
|
173
|
+
--on-accent-error: #ffffff;
|
|
174
|
+
|
|
175
|
+
--chart-1: #116f65;
|
|
176
|
+
--chart-2: #2d79c2;
|
|
177
|
+
--chart-3: #d8a523;
|
|
178
|
+
--chart-4: #b74679;
|
|
179
|
+
--chart-5: #228a4e;
|
|
180
|
+
--chart-6: #6d5acc;
|
|
181
|
+
|
|
182
|
+
--button-primary-bg: #0d0d0f00;
|
|
183
|
+
--button-primary-hover: #0d0d0f0f;
|
|
184
|
+
--button-primary-border: #0d0d0fa6;
|
|
185
|
+
--button-primary-ink: #080e1a;
|
|
186
|
+
--button-danger-bg: #db383400;
|
|
187
|
+
--button-danger-hover: #db383414;
|
|
188
|
+
--button-danger-border: #db3834;
|
|
189
|
+
--button-danger-ink: var(--accent-error);
|
|
190
|
+
|
|
191
|
+
/* the solid hue at 50 % (warning 60 %), where Dark uses the ink's */
|
|
192
|
+
--chip-neutral-bg: var(--hover);
|
|
193
|
+
--chip-neutral-border: var(--border);
|
|
194
|
+
--chip-primary-bg: #13837700;
|
|
195
|
+
--chip-primary-border: #116f658c;
|
|
196
|
+
--chip-positive-bg: #228a4e00;
|
|
197
|
+
--chip-positive-border: #228a4e80;
|
|
198
|
+
--chip-info-bg: #2d79c200;
|
|
199
|
+
--chip-info-border: #2d79c280;
|
|
200
|
+
--chip-warn-bg: #a77f1200;
|
|
201
|
+
--chip-warn-border: #a77f1299;
|
|
202
|
+
--chip-error-bg: #db383400;
|
|
203
|
+
--chip-error-border: #db383480;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* ── Oldschool ───────────────────────────────────────────────── *
|
|
207
|
+
* Opt-in. Dark-only, so a `.light` or `.dark` inside it takes these values
|
|
208
|
+
* too. The surfaces are the ones the kit shipped (they pass every floor in
|
|
209
|
+
* tokens.test.ts); Figma's raised/overlay #1f2d4b measured 2.96:1 for the fill
|
|
210
|
+
* and 4.06:1 for tertiary text, so the popover stays #1d2c49. Its ink steps and
|
|
211
|
+
* --border are the derived formulas for the same reason: Figma's opaque
|
|
212
|
+
* border #1b2843 is 1.1:1 on the card and would leave the planes unseparated.
|
|
213
|
+
*/
|
|
214
|
+
:where([data-theme="oldschool"], [data-theme="oldschool"] :is(.light, .dark)) {
|
|
215
|
+
--scheme: dark;
|
|
216
|
+
|
|
217
|
+
--brand-font-serif: var(--font-playfair, "Playfair Display");
|
|
218
|
+
--brand-font-mono: var(--font-inter, "Inter");
|
|
219
|
+
|
|
21
220
|
--background: #070d18;
|
|
22
221
|
--card: #16233c;
|
|
222
|
+
--secondary: #0d1526;
|
|
223
|
+
--on-secondary: var(--ink);
|
|
23
224
|
--popover: #1d2c49;
|
|
24
225
|
--muted: #26375c;
|
|
226
|
+
--hover: #e6e1d312;
|
|
227
|
+
--active: #e6e1d31f;
|
|
228
|
+
--selected: #35a3952e;
|
|
229
|
+
--scrim: #02050ea3;
|
|
25
230
|
|
|
26
|
-
/* ── ink ─────────────────────────────────────────────────────── */
|
|
27
231
|
--ink: #e6e1d3;
|
|
232
|
+
--ink-mid: color-mix(in srgb, var(--ink) 82%, transparent);
|
|
233
|
+
--ink-soft: color-mix(in srgb, var(--ink) 60%, transparent);
|
|
234
|
+
--ink-faint: color-mix(in srgb, var(--ink) 38%, transparent);
|
|
28
235
|
|
|
29
|
-
|
|
30
|
-
--
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
* values (docs/spec/accents.md). --primary-ink is the teal that reads on the
|
|
37
|
-
* surfaces: 5.85:1 on background, 4.72:1 on card. --primary is the same hue
|
|
38
|
-
* and chroma one step down in lightness — OKLCH L 0.550 C 0.094 H 183°
|
|
39
|
-
* against the ink's L 0.630 C 0.101 H 183° — so the CTA carries white:
|
|
40
|
-
* --on-primary reads on it at 4.63:1, and the fill clears the 3:1 non-text
|
|
41
|
-
* floor against background (4.20:1), secondary (3.94:1), card (3.39:1) and
|
|
42
|
-
* popover (3.01:1), so a checked Switch on a Card still reads as one. Muted
|
|
43
|
-
* is the one surface under the floor (2.54:1); the controls that fill there
|
|
44
|
-
* carry an on-primary mark, see the spec. Darkening the single value instead
|
|
45
|
-
* would have dropped every teal label below AA. */
|
|
46
|
-
--primary: #128377;
|
|
236
|
+
--border-subtle: #e6e1d312;
|
|
237
|
+
--border: color-mix(in srgb, var(--ink) 14%, transparent);
|
|
238
|
+
--border-strong: #2e3e64;
|
|
239
|
+
--ring: #35a395;
|
|
240
|
+
|
|
241
|
+
--brand: #080e1a;
|
|
242
|
+
--primary: #138377;
|
|
47
243
|
--on-primary: #ffffff;
|
|
48
|
-
--primary-ink: #
|
|
49
|
-
--
|
|
50
|
-
--
|
|
51
|
-
|
|
52
|
-
--positive: #
|
|
244
|
+
--primary-ink: #35a395;
|
|
245
|
+
--primary-hover: #127c71;
|
|
246
|
+
--primary-border: #35a39500;
|
|
247
|
+
|
|
248
|
+
--positive: #2e9e5c;
|
|
53
249
|
--on-positive: #070d18;
|
|
250
|
+
--positive-ink: #4abf76;
|
|
54
251
|
--accent-trace: #6b7fa0;
|
|
55
252
|
--on-accent-trace: #070d18;
|
|
56
|
-
--accent-debug: #
|
|
253
|
+
--accent-debug: #35a395;
|
|
57
254
|
--on-accent-debug: #070d18;
|
|
58
|
-
--accent-info: #
|
|
255
|
+
--accent-info: #4990d8;
|
|
59
256
|
--on-accent-info: #070d18;
|
|
60
|
-
--accent-
|
|
257
|
+
--accent-info-ink: #6ca6e4;
|
|
258
|
+
--accent-warn: #f5c84e;
|
|
61
259
|
--on-accent-warn: #070d18;
|
|
62
|
-
|
|
63
|
-
* is the fill and the text on a bare surface; on its own 10 % tint (a
|
|
64
|
-
* destructive menu row) the text is the derived --accent-error-ink, which
|
|
65
|
-
* EV leaves to the contract: #ec8379, 4.83:1 on that tint over popover. The
|
|
66
|
-
* vivid brand red is a gitops constant, not a UI token. */
|
|
67
|
-
--accent-error: #ef5b52;
|
|
260
|
+
--accent-error: #f05b52;
|
|
68
261
|
--on-accent-error: #070d18;
|
|
69
262
|
|
|
70
|
-
--chart-1: #
|
|
71
|
-
--chart-2: #
|
|
72
|
-
--chart-3: #
|
|
73
|
-
--chart-4: #
|
|
74
|
-
--chart-5: #
|
|
263
|
+
--chart-1: #35a395;
|
|
264
|
+
--chart-2: #4990d8;
|
|
265
|
+
--chart-3: #f5c84e;
|
|
266
|
+
--chart-4: #e68aaf;
|
|
267
|
+
--chart-5: #2e9e5c;
|
|
268
|
+
--chart-6: #988eef;
|
|
269
|
+
|
|
270
|
+
/* filled buttons. The danger label stays dark: white on #f05b52 is 3.32:1. */
|
|
271
|
+
--button-primary-bg: #138377;
|
|
272
|
+
--button-primary-hover: #127c71;
|
|
273
|
+
--button-primary-border: #138377;
|
|
274
|
+
--button-primary-ink: #ffffff;
|
|
275
|
+
--button-danger-bg: #f05b52;
|
|
276
|
+
--button-danger-hover: #f06c61;
|
|
277
|
+
--button-danger-border: #f05b52;
|
|
278
|
+
--button-danger-ink: #070d18;
|
|
279
|
+
|
|
280
|
+
/* chips are tinted pills with no edge */
|
|
281
|
+
--chip-neutral-bg: var(--hover);
|
|
282
|
+
--chip-neutral-border: #e6e1d300;
|
|
283
|
+
/* Figma tints the accent chip 16 %, which leaves its teal label at 4.03:1 on
|
|
284
|
+
* the card; 8 % holds 4.56:1 */
|
|
285
|
+
--chip-primary-bg: #35a39514;
|
|
286
|
+
--chip-primary-border: #35a39500;
|
|
287
|
+
--chip-positive-bg: #2e9e5c2e;
|
|
288
|
+
--chip-positive-border: #4abf7600;
|
|
289
|
+
--chip-info-bg: #4990d82e;
|
|
290
|
+
--chip-info-border: #6ca6e400;
|
|
291
|
+
--chip-warn-bg: #f5c84e29;
|
|
292
|
+
--chip-warn-border: #f5c84e00;
|
|
293
|
+
--chip-error-bg: #f05b522e;
|
|
294
|
+
--chip-error-border: #f06c6100;
|
|
295
|
+
|
|
296
|
+
--radius: 0.5rem;
|
|
297
|
+
--control-radius: 0.375rem;
|
|
298
|
+
--chip-radius: 9999px;
|
|
299
|
+
/* the ladder is three tiers, not one drop shadow: on a dark theme the value
|
|
300
|
+
* steps alone are too close to separate a resting card from a menu from a
|
|
301
|
+
* modal, so each tier gets its own spread and opacity */
|
|
302
|
+
--depth-card: 0 1px 2px 0 rgb(0 0 0 / 0.3);
|
|
303
|
+
--depth-elevated:
|
|
304
|
+
0 4px 12px -2px rgb(0 0 0 / 0.4),
|
|
305
|
+
0 2px 4px -2px rgb(0 0 0 / 0.3);
|
|
306
|
+
--depth-overlay: 0 16px 48px -12px rgb(0 0 0 / 0.6);
|
|
75
307
|
}
|