@evinvest/uikit 0.32.0 → 0.33.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 +21 -10
- package/dist/components/atomic/accordion.js +2 -1
- package/dist/components/atomic/accordion.js.map +1 -1
- package/dist/components/atomic/alert.js +4 -4
- package/dist/components/atomic/alert.js.map +1 -1
- package/dist/components/atomic/badge.js +4 -3
- package/dist/components/atomic/badge.js.map +1 -1
- package/dist/components/atomic/breadcrumb.js +7 -9
- package/dist/components/atomic/breadcrumb.js.map +1 -1
- package/dist/components/atomic/button.js +4 -3
- package/dist/components/atomic/button.js.map +1 -1
- package/dist/components/atomic/calendar.js +10 -25
- package/dist/components/atomic/calendar.js.map +1 -1
- package/dist/components/atomic/checkbox.js +2 -1
- package/dist/components/atomic/checkbox.js.map +1 -1
- package/dist/components/atomic/command.js +5 -20
- package/dist/components/atomic/command.js.map +1 -1
- package/dist/components/atomic/context-menu.js +6 -13
- package/dist/components/atomic/context-menu.js.map +1 -1
- package/dist/components/atomic/dialog.js +4 -2
- package/dist/components/atomic/dialog.js.map +1 -1
- package/dist/components/atomic/dropdown-menu.js +6 -14
- package/dist/components/atomic/dropdown-menu.js.map +1 -1
- package/dist/components/atomic/hover-card.js.map +1 -1
- package/dist/components/atomic/info-tip.js +8 -9
- package/dist/components/atomic/info-tip.js.map +1 -1
- package/dist/components/atomic/input-otp.js +2 -1
- package/dist/components/atomic/input-otp.js.map +1 -1
- package/dist/components/atomic/key-value.js +5 -4
- package/dist/components/atomic/key-value.js.map +1 -1
- package/dist/components/atomic/menubar.js +7 -18
- package/dist/components/atomic/menubar.js.map +1 -1
- package/dist/components/atomic/native-select.js +1 -1
- package/dist/components/atomic/native-select.js.map +1 -1
- package/dist/components/atomic/navigation-menu.js +6 -14
- package/dist/components/atomic/navigation-menu.js.map +1 -1
- package/dist/components/atomic/pagination.js +18 -19
- package/dist/components/atomic/pagination.js.map +1 -1
- package/dist/components/atomic/popover.js.map +1 -1
- package/dist/components/atomic/radio-group.js +5 -4
- package/dist/components/atomic/radio-group.js.map +1 -1
- package/dist/components/atomic/section-descriptor.js +5 -8
- package/dist/components/atomic/section-descriptor.js.map +1 -1
- package/dist/components/atomic/select-listbox.js +2 -2
- package/dist/components/atomic/select-listbox.js.map +1 -1
- package/dist/components/atomic/select.js +5 -13
- package/dist/components/atomic/select.js.map +1 -1
- package/dist/components/atomic/sheet.js +4 -2
- package/dist/components/atomic/sheet.js.map +1 -1
- package/dist/components/atomic/sidebar.js +7 -26
- package/dist/components/atomic/sidebar.js.map +1 -1
- package/dist/components/atomic/slider.js.map +1 -1
- package/dist/components/atomic/sonner.js +20 -18
- package/dist/components/atomic/sonner.js.map +1 -1
- package/dist/components/atomic/spinner.js +6 -3
- package/dist/components/atomic/spinner.js.map +1 -1
- package/dist/components/atomic/tabs.js.map +1 -1
- package/dist/components/atomic/toggle-group.js +2 -2
- package/dist/components/atomic/toggle-group.js.map +1 -1
- package/dist/components/atomic/toggle.js +3 -6
- package/dist/components/atomic/toggle.js.map +1 -1
- package/dist/components/atomic/tooltip.js.map +1 -1
- package/dist/components/derived/carousel.js +6 -6
- package/dist/components/derived/carousel.js.map +1 -1
- package/dist/components/derived/command-palette.js +8 -7
- package/dist/components/derived/command-palette.js.map +1 -1
- package/dist/components/derived/confirm-dialog.js +8 -13
- package/dist/components/derived/confirm-dialog.js.map +1 -1
- package/dist/components/derived/date-time-picker.js +10 -14
- package/dist/components/derived/date-time-picker.js.map +1 -1
- package/dist/components/derived/field.js.map +1 -1
- package/dist/components/derived/form.js +0 -1
- package/dist/components/derived/form.js.map +1 -1
- package/dist/components/derived/icon-button.js.map +1 -1
- package/dist/components/derived/item.js +0 -1
- package/dist/components/derived/item.js.map +1 -1
- package/dist/components/derived/popover-form.js +4 -3
- package/dist/components/derived/popover-form.js.map +1 -1
- package/dist/components/derived/settings.js +4 -4
- package/dist/components/derived/settings.js.map +1 -1
- package/dist/components/shell/account-menu-profile.js +1 -1
- package/dist/components/shell/account-menu-profile.js.map +1 -1
- package/dist/components/shell/account-settings-dialog.js +3 -2
- package/dist/components/shell/account-settings-dialog.js.map +1 -1
- package/dist/components/shell/aside.js +6 -4
- package/dist/components/shell/aside.js.map +1 -1
- package/dist/components/shell/auth-wall.js +3 -5
- package/dist/components/shell/auth-wall.js.map +1 -1
- package/dist/components/shell/bottom-tab-bar.js +3 -3
- package/dist/components/shell/bottom-tab-bar.js.map +1 -1
- package/dist/components/shell/chat-composer.js +9 -7
- package/dist/components/shell/chat-composer.js.map +1 -1
- package/dist/components/shell/chat-message.js.map +1 -1
- package/dist/components/shell/chat-typing.js +2 -1
- package/dist/components/shell/chat-typing.js.map +1 -1
- package/dist/components/shell/footer.js +26 -24
- package/dist/components/shell/footer.js.map +1 -1
- package/dist/components/shell/header-controls.js +17 -15
- package/dist/components/shell/header-controls.js.map +1 -1
- package/dist/components/shell/hotbar.js +158 -0
- package/dist/components/shell/hotbar.js.map +1 -0
- package/dist/components/shell/logo.js +3 -2
- package/dist/components/shell/logo.js.map +1 -1
- package/dist/components/shell/mobile-app-bar.js +4 -4
- package/dist/components/shell/mobile-app-bar.js.map +1 -1
- package/dist/components/shell/nav-collapse.js +6 -5
- package/dist/components/shell/nav-collapse.js.map +1 -1
- package/dist/components/shell/resource-error.js +2 -2
- package/dist/components/shell/resource-error.js.map +1 -1
- package/dist/components/shell/section-nav.js +3 -3
- package/dist/components/shell/section-nav.js.map +1 -1
- package/dist/components/shell/shell-icons.js +7 -22
- package/dist/components/shell/shell-icons.js.map +1 -1
- package/dist/components/shell/shell-nav.js +4 -4
- package/dist/components/shell/shell-nav.js.map +1 -1
- package/dist/components/shell/smart-header.js.map +1 -1
- package/dist/components/shell/status-screen.js +35 -35
- package/dist/components/shell/status-screen.js.map +1 -1
- package/dist/components/shell/system-banner.js +6 -6
- package/dist/components/shell/system-banner.js.map +1 -1
- package/dist/components/shell/workspace-tab.js +2 -1
- package/dist/components/shell/workspace-tab.js.map +1 -1
- package/dist/generated/accent.js +10 -10
- package/dist/generated/accent.js.map +1 -1
- package/dist/generated/accordion.js +6 -2
- package/dist/generated/accordion.js.map +1 -1
- package/dist/generated/account-list.js +4 -4
- package/dist/generated/account-list.js.map +1 -1
- package/dist/generated/account-settings-dialog.js +6 -2
- package/dist/generated/account-settings-dialog.js.map +1 -1
- package/dist/generated/alert-dialog.js +1 -1
- package/dist/generated/alert-dialog.js.map +1 -1
- package/dist/generated/alert.js +3 -10
- package/dist/generated/alert.js.map +1 -1
- package/dist/generated/aside.js +7 -0
- package/dist/generated/aside.js.map +1 -1
- package/dist/generated/badge.js +2 -11
- package/dist/generated/badge.js.map +1 -1
- package/dist/generated/band.js +10 -10
- package/dist/generated/band.js.map +1 -1
- package/dist/generated/breadcrumb.js +1 -1
- package/dist/generated/breadcrumb.js.map +1 -1
- package/dist/generated/button-group.js +3 -3
- package/dist/generated/button-group.js.map +1 -1
- package/dist/generated/button.js +4 -20
- package/dist/generated/button.js.map +1 -1
- package/dist/generated/calendar.js +5 -5
- package/dist/generated/calendar.js.map +1 -1
- package/dist/generated/card.js +1 -1
- package/dist/generated/card.js.map +1 -1
- package/dist/generated/carousel.js +1 -1
- package/dist/generated/carousel.js.map +1 -1
- package/dist/generated/chat-composer.js +9 -2
- package/dist/generated/chat-composer.js.map +1 -1
- package/dist/generated/chat-message.js +25 -19
- package/dist/generated/chat-message.js.map +1 -1
- package/dist/generated/checkbox.js +1 -1
- package/dist/generated/checkbox.js.map +1 -1
- package/dist/generated/command-palette.js +10 -1
- package/dist/generated/command-palette.js.map +1 -1
- package/dist/generated/command.js +8 -6
- package/dist/generated/command.js.map +1 -1
- package/dist/generated/confirm-dialog.js +8 -8
- package/dist/generated/confirm-dialog.js.map +1 -1
- package/dist/generated/context-menu.js +7 -5
- package/dist/generated/context-menu.js.map +1 -1
- package/dist/generated/copy.js +97 -0
- package/dist/generated/copy.js.map +1 -0
- package/dist/generated/date-time-picker.js +10 -0
- package/dist/generated/date-time-picker.js.map +1 -1
- package/dist/generated/dialog.js +2 -2
- package/dist/generated/dialog.js.map +1 -1
- package/dist/generated/drawer.js +6 -6
- package/dist/generated/drawer.js.map +1 -1
- package/dist/generated/dropdown-menu.js +7 -5
- package/dist/generated/dropdown-menu.js.map +1 -1
- package/dist/generated/empty.js +5 -5
- package/dist/generated/empty.js.map +1 -1
- package/dist/generated/field.js +9 -7
- package/dist/generated/field.js.map +1 -1
- package/dist/generated/footer.js +45 -0
- package/dist/generated/footer.js.map +1 -0
- package/dist/generated/header-controls.js +5 -10
- package/dist/generated/header-controls.js.map +1 -1
- package/dist/generated/hover-card.js +1 -1
- package/dist/generated/hover-card.js.map +1 -1
- package/dist/generated/icon-button.js +4 -2
- package/dist/generated/icon-button.js.map +1 -1
- package/dist/generated/icons.js +36 -0
- package/dist/generated/icons.js.map +1 -0
- package/dist/generated/info-tip.js +5 -0
- package/dist/generated/info-tip.js.map +1 -0
- package/dist/generated/input-group.js +10 -10
- package/dist/generated/input-group.js.map +1 -1
- package/dist/generated/input-otp.js +2 -2
- package/dist/generated/input-otp.js.map +1 -1
- package/dist/generated/input.js +4 -4
- package/dist/generated/input.js.map +1 -1
- package/dist/generated/item.js +11 -11
- package/dist/generated/item.js.map +1 -1
- package/dist/generated/kbd.js +1 -1
- package/dist/generated/kbd.js.map +1 -1
- package/dist/generated/key-value.js +7 -1
- package/dist/generated/key-value.js.map +1 -1
- package/dist/generated/label.js +1 -1
- package/dist/generated/label.js.map +1 -1
- package/dist/generated/logo.js +9 -0
- package/dist/generated/logo.js.map +1 -0
- package/dist/generated/menu.js +7 -0
- package/dist/generated/menu.js.map +1 -0
- package/dist/generated/menubar.js +10 -8
- package/dist/generated/menubar.js.map +1 -1
- package/dist/generated/navigation-menu.js +11 -5
- package/dist/generated/navigation-menu.js.map +1 -1
- package/dist/generated/orientation.js +5 -0
- package/dist/generated/orientation.js.map +1 -0
- package/dist/generated/pagination.js +15 -0
- package/dist/generated/pagination.js.map +1 -0
- package/dist/generated/popover-form.js +5 -0
- package/dist/generated/popover-form.js.map +1 -1
- package/dist/generated/popover.js +1 -1
- package/dist/generated/popover.js.map +1 -1
- package/dist/generated/primitives.js +7 -0
- package/dist/generated/primitives.js.map +1 -0
- package/dist/generated/radio-group.js +5 -1
- package/dist/generated/radio-group.js.map +1 -1
- package/dist/generated/section-descriptor.js +7 -0
- package/dist/generated/section-descriptor.js.map +1 -0
- package/dist/generated/select.js +16 -10
- package/dist/generated/select.js.map +1 -1
- package/dist/generated/settings.js +2 -7
- package/dist/generated/settings.js.map +1 -1
- package/dist/generated/sheet.js +1 -1
- package/dist/generated/sheet.js.map +1 -1
- package/dist/generated/sidebar.js +24 -12
- package/dist/generated/sidebar.js.map +1 -1
- package/dist/generated/size.js +12 -0
- package/dist/generated/size.js.map +1 -0
- package/dist/generated/skeleton.js +1 -1
- package/dist/generated/skeleton.js.map +1 -1
- package/dist/generated/slider.js +2 -2
- package/dist/generated/slider.js.map +1 -1
- package/dist/generated/slot.js +5 -0
- package/dist/generated/slot.js.map +1 -0
- package/dist/generated/smart-header.js +2 -0
- package/dist/generated/smart-header.js.map +1 -1
- package/dist/generated/sonner.js +11 -13
- package/dist/generated/sonner.js.map +1 -1
- package/dist/generated/spinner.js +5 -0
- package/dist/generated/spinner.js.map +1 -0
- package/dist/generated/status-screen.js +27 -0
- package/dist/generated/status-screen.js.map +1 -0
- package/dist/generated/switch.js +2 -2
- package/dist/generated/switch.js.map +1 -1
- package/dist/generated/system-banner.js +6 -16
- package/dist/generated/system-banner.js.map +1 -1
- package/dist/generated/table.js +9 -9
- package/dist/generated/table.js.map +1 -1
- package/dist/generated/tabs.js +2 -2
- package/dist/generated/tabs.js.map +1 -1
- package/dist/generated/textarea.js +1 -1
- package/dist/generated/textarea.js.map +1 -1
- package/dist/generated/toggle-group.js +9 -0
- package/dist/generated/toggle-group.js.map +1 -0
- package/dist/generated/toggle.js +1 -9
- package/dist/generated/toggle.js.map +1 -1
- package/dist/generated/tone.js +12 -0
- package/dist/generated/tone.js.map +1 -0
- package/dist/generated/tooltip.js +1 -1
- package/dist/generated/tooltip.js.map +1 -1
- package/dist/generated/workspace-tab.js +3 -3
- package/dist/generated/workspace-tab.js.map +1 -1
- package/dist/icons/icon-shapes.js +10 -0
- package/dist/icons/icon-shapes.js.map +1 -0
- package/dist/icons/select-chevron.js +2 -1
- package/dist/icons/select-chevron.js.map +1 -1
- package/dist/icons/ui-icons.js +3 -57
- package/dist/icons/ui-icons.js.map +1 -1
- package/dist/index.d.ts +203 -155
- package/dist/index.js +1 -0
- package/dist/lib/cn.js +1 -0
- package/dist/lib/cn.js.map +1 -1
- package/dist/primitives/use-floating.js.map +1 -1
- package/dist/primitives/use-roving-focus.js.map +1 -1
- package/package.json +1 -1
- package/styles/ev.css +13 -76
- package/styles/theme.css +133 -66
- package/styles/tokens.css +157 -149
package/dist/index.js
CHANGED
|
@@ -76,6 +76,7 @@ export { usePendingNavigation } from "./components/shell/use-shell-nav.js";
|
|
|
76
76
|
export { ShellNav } from "./components/shell/shell-nav.js";
|
|
77
77
|
export { NavBadge, NavDot } from "./components/shell/nav-badge.js";
|
|
78
78
|
export { BottomTabBar } from "./components/shell/bottom-tab-bar.js";
|
|
79
|
+
export { Hotbar } from "./components/shell/hotbar.js";
|
|
79
80
|
export { TopBar } from "./components/shell/top-bar.js";
|
|
80
81
|
export { AccountMenu } from "./components/shell/account-menu.js";
|
|
81
82
|
export { MobileAppBar } from "./components/shell/mobile-app-bar.js";
|
package/dist/lib/cn.js
CHANGED
|
@@ -2,6 +2,7 @@ import { clsx } from "clsx";
|
|
|
2
2
|
import { extendTailwindMerge } from "tailwind-merge";
|
|
3
3
|
const twMerge = extendTailwindMerge({
|
|
4
4
|
extend: {
|
|
5
|
+
theme: { radius: ["control", "panel", "chip", "row"] },
|
|
5
6
|
classGroups: {
|
|
6
7
|
"font-size": [{ text: ["caption", "body-s", "body", "body-l", "h3", "h2", "h1", "figure-m", "figure-l"] }]
|
|
7
8
|
}
|
package/dist/lib/cn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/cn.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\n// The kit's own type scale (theme.css `--text-*`). tailwind-merge only knows\n// t-shirt sizes as font sizes, so `text-body` would be filed under text colour\n// and dropped by a later `text-ink`. The Rust mirror is `fuse` in ev_lib_classes.\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n \"font-size\": [{ text: [\"caption\", \"body-s\", \"body\", \"body-l\", \"h3\", \"h2\", \"h1\", \"figure-m\", \"figure-l\"] }],\n },\n },\n});\n\n/**\n * Fuses class fragments into one string with real Tailwind conflict resolution:\n * `clsx` drops falsy fragments and joins the rest, `tailwind-merge` resolves\n * conflicting utilities so the rightmost wins (`cn(\"p-4\", \"p-2\") === \"p-2\"`). A\n * caller's `className` override, passed last, therefore beats the base classes.\n *\n * `twMerge` parses every utility on every render, and the overwhelmingly common\n * call is one kit constant plus a `className` override that is absent — so that\n * call returns the constant untouched.\n *\n * The Rust mirror is the `cn!` macro in `ev_lib::uikit` (`tailwind_fuse::tw_merge!`).\n */\nexport function cn(...inputs: ClassValue[]): string {\n if (inputs.length === 2 && typeof inputs[0] === \"string\" && !inputs[1]) {\n return inputs[0];\n }\n return twMerge(clsx(inputs));\n}\n"],"mappings":"AAAA,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAKpC,MAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa,CAAC,EAAE,MAAM,CAAC,WAAW,UAAU,QAAQ,UAAU,MAAM,MAAM,MAAM,YAAY,UAAU,EAAE,CAAC;AAAA,IAC3G;AAAA,EACF;AACF,CAAC;AAcM,SAAS,MAAM,QAA8B;AAClD,MAAI,OAAO,WAAW,KAAK,OAAO,OAAO,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,GAAG;AACtE,WAAO,OAAO,CAAC;AAAA,EACjB;AACA,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/cn.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\n// The kit's own type scale (theme.css `--text-*`). tailwind-merge only knows\n// t-shirt sizes as font sizes, so `text-body` would be filed under text colour\n// and dropped by a later `text-ink`. The Rust mirror is `fuse` in ev_lib_classes.\nconst twMerge = extendTailwindMerge({\n extend: {\n theme: { radius: [\"control\", \"panel\", \"chip\", \"row\"] },\n classGroups: {\n \"font-size\": [{ text: [\"caption\", \"body-s\", \"body\", \"body-l\", \"h3\", \"h2\", \"h1\", \"figure-m\", \"figure-l\"] }],\n },\n },\n});\n\n/**\n * Fuses class fragments into one string with real Tailwind conflict resolution:\n * `clsx` drops falsy fragments and joins the rest, `tailwind-merge` resolves\n * conflicting utilities so the rightmost wins (`cn(\"p-4\", \"p-2\") === \"p-2\"`). A\n * caller's `className` override, passed last, therefore beats the base classes.\n *\n * `twMerge` parses every utility on every render, and the overwhelmingly common\n * call is one kit constant plus a `className` override that is absent — so that\n * call returns the constant untouched.\n *\n * The Rust mirror is the `cn!` macro in `ev_lib::uikit` (`tailwind_fuse::tw_merge!`).\n */\nexport function cn(...inputs: ClassValue[]): string {\n if (inputs.length === 2 && typeof inputs[0] === \"string\" && !inputs[1]) {\n return inputs[0];\n }\n return twMerge(clsx(inputs));\n}\n"],"mappings":"AAAA,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAKpC,MAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,OAAO,EAAE,QAAQ,CAAC,WAAW,SAAS,QAAQ,KAAK,EAAE;AAAA,IACrD,aAAa;AAAA,MACX,aAAa,CAAC,EAAE,MAAM,CAAC,WAAW,UAAU,QAAQ,UAAU,MAAM,MAAM,MAAM,YAAY,UAAU,EAAE,CAAC;AAAA,IAC3G;AAAA,EACF;AACF,CAAC;AAcM,SAAS,MAAM,QAA8B;AAClD,MAAI,OAAO,WAAW,KAAK,OAAO,OAAO,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,GAAG;AACtE,WAAO,OAAO,CAAC;AAAA,EACjB;AACA,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;","names":[]}
|
|
@@ -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\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":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/primitives/use-floating.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport type { Side } from \"../generated/primitives\";\n\nexport type { Side };\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":";AAEA,YAAY,WAAW;AAqBvB,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;AAGA,SAAS,yBAAyB,IAAsB;AACtD,WAAS,OAAO,GAAG,eAAe,MAAM,OAAO,KAAK,eAAe;AACjE,QAAI,KAAK,gBAAgB,EAAE,KAAK,CAAC,MAAM,EAAE,cAAc,SAAS,EAAG,QAAO;AAAA,EAC5E;AACA,SAAO;AACT;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;AAMA,QAAI,QAAQ;AACZ,aAAS,SAAS;AAChB,cAAQ;AACR,YAAM;AACN,UAAI,UAAU,WAAW,yBAAyB,UAAU,OAAO,GAAG;AACpE,gBAAQ,sBAAsB,MAAM;AAAA,MACtC;AAAA,IACF;AACA,WAAO;AAGP,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,UAAI,MAAO,sBAAqB,KAAK;AACrC,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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/primitives/use-roving-focus.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\n/**\n * Arrow-key roving focus over a set of items — the dep-light core of menus,\n * tabs, radio-groups and toolbars (replacing `@radix-ui/react-roving-focus`).\n * Returns an `onKeyDown` to spread on the container and the active index; items\n * should set `tabIndex={index === activeIndex ? 0 : -1}`.\n *\n * `count` may be a getter: containers whose items are only known from the DOM\n * (menus with conditionally rendered or disabled items, inline sub-menus) pass\n * one so the bound is read at keydown time — never during render, which keeps\n * the hook safe under SSR.\n *\n * Mirrors the keyboard navigation Rust drives with a focused-index signal.\n */\nexport function useRovingFocus(opts: {\n count: number | (() => number);\n orientation?:
|
|
1
|
+
{"version":3,"sources":["../../src/primitives/use-roving-focus.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport type { RovingOrientation } from \"../generated/primitives\";\n\n/**\n * Arrow-key roving focus over a set of items — the dep-light core of menus,\n * tabs, radio-groups and toolbars (replacing `@radix-ui/react-roving-focus`).\n * Returns an `onKeyDown` to spread on the container and the active index; items\n * should set `tabIndex={index === activeIndex ? 0 : -1}`.\n *\n * `count` may be a getter: containers whose items are only known from the DOM\n * (menus with conditionally rendered or disabled items, inline sub-menus) pass\n * one so the bound is read at keydown time — never during render, which keeps\n * the hook safe under SSR.\n *\n * Mirrors the keyboard navigation Rust drives with a focused-index signal.\n */\nexport function useRovingFocus(opts: {\n count: number | (() => number);\n orientation?: RovingOrientation;\n loop?: boolean;\n initial?: number;\n}): {\n activeIndex: number;\n setActiveIndex: (i: number) => void;\n onKeyDown: (event: React.KeyboardEvent) => void;\n} {\n const { count, orientation = \"vertical\", loop = true, initial = 0 } = opts;\n const [activeIndex, setActiveIndex] = React.useState(initial);\n\n const resolveCount = () => (typeof count === \"function\" ? count() : count);\n\n const next = (dir: 1 | -1) => {\n const total = resolveCount();\n if (total <= 0) return;\n setActiveIndex((i) => {\n // Clamp first: the item set may have shrunk since the index was set.\n let n = Math.min(Math.max(i, 0), total - 1) + dir;\n if (n < 0) n = loop ? total - 1 : 0;\n else if (n >= total) n = loop ? 0 : total - 1;\n return n;\n });\n };\n\n const onKeyDown = (event: React.KeyboardEvent) => {\n const horiz = orientation === \"horizontal\" || orientation === \"both\";\n const vert = orientation === \"vertical\" || orientation === \"both\";\n if (vert && event.key === \"ArrowDown\") {\n event.preventDefault();\n next(1);\n } else if (vert && event.key === \"ArrowUp\") {\n event.preventDefault();\n next(-1);\n } else if (horiz && event.key === \"ArrowRight\") {\n event.preventDefault();\n next(1);\n } else if (horiz && event.key === \"ArrowLeft\") {\n event.preventDefault();\n next(-1);\n } else if (event.key === \"Home\") {\n event.preventDefault();\n setActiveIndex(0);\n } else if (event.key === \"End\") {\n event.preventDefault();\n const total = resolveCount();\n if (total > 0) setActiveIndex(total - 1);\n }\n };\n\n return { activeIndex, setActiveIndex, onKeyDown };\n}\n"],"mappings":";AAEA,YAAY,WAAW;AAgBhB,SAAS,eAAe,MAS7B;AACA,QAAM,EAAE,OAAO,cAAc,YAAY,OAAO,MAAM,UAAU,EAAE,IAAI;AACtE,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAS,OAAO;AAE5D,QAAM,eAAe,MAAO,OAAO,UAAU,aAAa,MAAM,IAAI;AAEpE,QAAM,OAAO,CAAC,QAAgB;AAC5B,UAAM,QAAQ,aAAa;AAC3B,QAAI,SAAS,EAAG;AAChB,mBAAe,CAAC,MAAM;AAEpB,UAAI,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAC,IAAI;AAC9C,UAAI,IAAI,EAAG,KAAI,OAAO,QAAQ,IAAI;AAAA,eACzB,KAAK,MAAO,KAAI,OAAO,IAAI,QAAQ;AAC5C,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,QAAM,YAAY,CAAC,UAA+B;AAChD,UAAM,QAAQ,gBAAgB,gBAAgB,gBAAgB;AAC9D,UAAM,OAAO,gBAAgB,cAAc,gBAAgB;AAC3D,QAAI,QAAQ,MAAM,QAAQ,aAAa;AACrC,YAAM,eAAe;AACrB,WAAK,CAAC;AAAA,IACR,WAAW,QAAQ,MAAM,QAAQ,WAAW;AAC1C,YAAM,eAAe;AACrB,WAAK,EAAE;AAAA,IACT,WAAW,SAAS,MAAM,QAAQ,cAAc;AAC9C,YAAM,eAAe;AACrB,WAAK,CAAC;AAAA,IACR,WAAW,SAAS,MAAM,QAAQ,aAAa;AAC7C,YAAM,eAAe;AACrB,WAAK,EAAE;AAAA,IACT,WAAW,MAAM,QAAQ,QAAQ;AAC/B,YAAM,eAAe;AACrB,qBAAe,CAAC;AAAA,IAClB,WAAW,MAAM,QAAQ,OAAO;AAC9B,YAAM,eAAe;AACrB,YAAM,QAAQ,aAAa;AAC3B,UAAI,QAAQ,EAAG,gBAAe,QAAQ,CAAC;AAAA,IACzC;AAAA,EACF;AAEA,SAAO,EAAE,aAAa,gBAAgB,UAAU;AAClD;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evinvest/uikit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.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
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
--background: #0d0d0f;
|
|
40
40
|
--card: #151518;
|
|
41
41
|
--secondary: #1c1c20;
|
|
42
|
-
--on-secondary: var(--ink);
|
|
43
42
|
--popover: #252529;
|
|
44
43
|
--muted: #070709;
|
|
45
44
|
--hover: #e6e1d30f;
|
|
@@ -63,13 +62,11 @@
|
|
|
63
62
|
|
|
64
63
|
/* brand and primary. A fill and an ink are different jobs (docs/spec/accents.md):
|
|
65
64
|
* --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. */
|
|
65
|
+
* on the popover); --primary-ink is the teal that reads as text (4.96:1 there). */
|
|
68
66
|
--brand: #0d1627;
|
|
69
67
|
--primary: #138377;
|
|
70
68
|
--on-primary: #ffffff;
|
|
71
69
|
--primary-ink: #35a395;
|
|
72
|
-
--primary-hover: #127c71;
|
|
73
70
|
--primary-border: #35a3958c;
|
|
74
71
|
|
|
75
72
|
/* status. Fills carry the dark label (white fails 3:1–3.4:1 on these); the
|
|
@@ -95,29 +92,6 @@
|
|
|
95
92
|
--chart-4: #e68aaf;
|
|
96
93
|
--chart-5: #2e9e5c;
|
|
97
94
|
--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
95
|
}
|
|
122
96
|
|
|
123
97
|
/* ── u2 Light ────────────────────────────────────────────────── */
|
|
@@ -127,7 +101,6 @@
|
|
|
127
101
|
--background: #efebdf;
|
|
128
102
|
--card: #f6f3eb;
|
|
129
103
|
--secondary: #fbfaf6;
|
|
130
|
-
--on-secondary: var(--ink);
|
|
131
104
|
--popover: #ffffff;
|
|
132
105
|
--muted: #e6e1d3;
|
|
133
106
|
--hover: #0d0d0f0d;
|
|
@@ -149,7 +122,6 @@
|
|
|
149
122
|
--primary: #138377;
|
|
150
123
|
--on-primary: #ffffff;
|
|
151
124
|
--primary-ink: #116f65;
|
|
152
|
-
--primary-hover: #116f65;
|
|
153
125
|
--primary-border: #116f658c;
|
|
154
126
|
|
|
155
127
|
/* Figma's positive #228a4e carries neither label at 4.5:1 (white 4.36, dark
|
|
@@ -178,29 +150,6 @@
|
|
|
178
150
|
--chart-4: #b74679;
|
|
179
151
|
--chart-5: #228a4e;
|
|
180
152
|
--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
153
|
}
|
|
205
154
|
|
|
206
155
|
/* ── Oldschool ───────────────────────────────────────────────── *
|
|
@@ -220,7 +169,6 @@
|
|
|
220
169
|
--background: #070d18;
|
|
221
170
|
--card: #16233c;
|
|
222
171
|
--secondary: #0d1526;
|
|
223
|
-
--on-secondary: var(--ink);
|
|
224
172
|
--popover: #1d2c49;
|
|
225
173
|
--muted: #26375c;
|
|
226
174
|
--hover: #e6e1d312;
|
|
@@ -242,7 +190,6 @@
|
|
|
242
190
|
--primary: #138377;
|
|
243
191
|
--on-primary: #ffffff;
|
|
244
192
|
--primary-ink: #35a395;
|
|
245
|
-
--primary-hover: #127c71;
|
|
246
193
|
--primary-border: #35a39500;
|
|
247
194
|
|
|
248
195
|
--positive: #2e9e5c;
|
|
@@ -267,31 +214,21 @@
|
|
|
267
214
|
--chart-5: #2e9e5c;
|
|
268
215
|
--chart-6: #988eef;
|
|
269
216
|
|
|
270
|
-
/*
|
|
271
|
-
--button-
|
|
272
|
-
--button-
|
|
273
|
-
--button-
|
|
274
|
-
--button-
|
|
275
|
-
--button-danger-bg: #f05b52;
|
|
276
|
-
--button-danger-hover: #f06c61;
|
|
277
|
-
--button-danger-border: #f05b52;
|
|
278
|
-
--button-danger-ink: #070d18;
|
|
217
|
+
/* danger is a fill */
|
|
218
|
+
--button-danger-bg: var(--accent-error);
|
|
219
|
+
--button-danger-hover: var(--accent-error-hover);
|
|
220
|
+
--button-danger-border: var(--accent-error);
|
|
221
|
+
--button-danger-ink: var(--on-accent-error);
|
|
279
222
|
|
|
280
|
-
/*
|
|
281
|
-
--
|
|
282
|
-
--
|
|
223
|
+
/* tints are pills with no edge */
|
|
224
|
+
--tint-fill: 18%;
|
|
225
|
+
--tint-edge: 0%;
|
|
226
|
+
--tint-neutral-edge: transparent;
|
|
283
227
|
/* Figma tints the accent chip 16 %, which leaves its teal label at 4.03:1 on
|
|
284
228
|
* the card; 8 % holds 4.56:1 */
|
|
285
|
-
--
|
|
286
|
-
|
|
287
|
-
--
|
|
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;
|
|
229
|
+
--tint-primary-fill: color-mix(in srgb, var(--primary-ink) 8%, transparent);
|
|
230
|
+
/* at 18 % the info label reads 4.43:1 on its fill; 16 % clears 4.5:1 */
|
|
231
|
+
--tint-info-fill: color-mix(in srgb, var(--accent-info-ink) 16%, transparent);
|
|
295
232
|
|
|
296
233
|
--radius: 0.5rem;
|
|
297
234
|
--control-radius: 0.375rem;
|
package/styles/theme.css
CHANGED
|
@@ -664,6 +664,11 @@
|
|
|
664
664
|
--radius-lg: var(--radius);
|
|
665
665
|
--radius-xl: calc(var(--radius) + 4px);
|
|
666
666
|
--radius-2xl: calc(var(--radius) + 8px);
|
|
667
|
+
/* the roles the kit's tables name; the steps above are the consumer's */
|
|
668
|
+
--radius-control: var(--control-radius);
|
|
669
|
+
--radius-panel: var(--radius);
|
|
670
|
+
--radius-chip: var(--chip-radius);
|
|
671
|
+
--radius-row: calc(var(--radius) - 4px); /* concentric inside a panel's p-1 */
|
|
667
672
|
|
|
668
673
|
/* The names stay, the values are per theme: u2 is flat (`--depth-*` is a
|
|
669
674
|
* zero shadow), Oldschool brings the ladder back in ev.css. */
|
|
@@ -671,25 +676,25 @@
|
|
|
671
676
|
--shadow-elevated: var(--depth-elevated);
|
|
672
677
|
--shadow-overlay: var(--depth-overlay);
|
|
673
678
|
|
|
674
|
-
/* Type scale:
|
|
675
|
-
--text-caption:
|
|
676
|
-
--text-caption--line-height:
|
|
677
|
-
--text-body-s:
|
|
678
|
-
--text-body-s--line-height:
|
|
679
|
-
--text-body:
|
|
680
|
-
--text-body--line-height:
|
|
681
|
-
--text-body-l:
|
|
682
|
-
--text-body-l--line-height:
|
|
683
|
-
--text-h3:
|
|
684
|
-
--text-h3--line-height:
|
|
685
|
-
--text-h2:
|
|
686
|
-
--text-h2--line-height:
|
|
687
|
-
--text-h1:
|
|
688
|
-
--text-h1--line-height:
|
|
689
|
-
--text-figure-m:
|
|
690
|
-
--text-figure-m--line-height:
|
|
691
|
-
--text-figure-l:
|
|
692
|
-
--text-figure-l--line-height:
|
|
679
|
+
/* Type scale: two even-step ramps off the geometry rule's inputs (docs/spec/roles.md). */
|
|
680
|
+
--text-caption: calc(var(--body-size) - 2 * var(--body-step));
|
|
681
|
+
--text-caption--line-height: calc(var(--body-leading) - 4 * var(--body-step));
|
|
682
|
+
--text-body-s: calc(var(--body-size) - var(--body-step));
|
|
683
|
+
--text-body-s--line-height: calc(var(--body-leading) - 2 * var(--body-step));
|
|
684
|
+
--text-body: var(--body-size);
|
|
685
|
+
--text-body--line-height: var(--body-leading);
|
|
686
|
+
--text-body-l: calc(var(--body-size) + var(--body-step));
|
|
687
|
+
--text-body-l--line-height: calc(var(--body-leading) + 2 * var(--body-step));
|
|
688
|
+
--text-h3: calc(var(--body-size) + var(--body-step));
|
|
689
|
+
--text-h3--line-height: calc(var(--body-leading) + 2 * var(--body-step));
|
|
690
|
+
--text-h2: calc((var(--display-base) + 2 * var(--display-step)) * var(--display-scale));
|
|
691
|
+
--text-h2--line-height: calc((var(--display-base) + 2 * var(--display-step) + var(--display-leading)) * var(--display-scale));
|
|
692
|
+
--text-h1: calc((var(--display-base) + 4 * var(--display-step)) * var(--display-scale));
|
|
693
|
+
--text-h1--line-height: calc((var(--display-base) + 4 * var(--display-step) + var(--display-leading)) * var(--display-scale));
|
|
694
|
+
--text-figure-m: calc((var(--display-base) + var(--display-step)) * var(--display-scale));
|
|
695
|
+
--text-figure-m--line-height: calc((var(--display-base) + var(--display-step) + var(--figure-leading)) * var(--display-scale));
|
|
696
|
+
--text-figure-l: calc((var(--display-base) + 3 * var(--display-step)) * var(--display-scale));
|
|
697
|
+
--text-figure-l--line-height: calc((var(--display-base) + 3 * var(--display-step) + var(--figure-leading)) * var(--display-scale));
|
|
693
698
|
|
|
694
699
|
/* The families are parameters, apart from the colour contract: a brand scope
|
|
695
700
|
* sets `--brand-font-sans`, `--brand-font-serif` and `--brand-font-mono`
|
|
@@ -748,38 +753,51 @@
|
|
|
748
753
|
--color-positive-ink: var(--positive-ink);
|
|
749
754
|
--color-accent-trace: var(--accent-trace);
|
|
750
755
|
--color-on-accent-trace: var(--on-accent-trace);
|
|
756
|
+
--color-accent-trace-hover: var(--accent-trace-hover);
|
|
751
757
|
--color-accent-debug: var(--accent-debug);
|
|
752
758
|
--color-on-accent-debug: var(--on-accent-debug);
|
|
759
|
+
--color-accent-debug-hover: var(--accent-debug-hover);
|
|
753
760
|
--color-accent-info: var(--accent-info);
|
|
754
761
|
--color-on-accent-info: var(--on-accent-info);
|
|
762
|
+
--color-accent-info-hover: var(--accent-info-hover);
|
|
755
763
|
--color-accent-info-ink: var(--accent-info-ink);
|
|
756
764
|
--color-accent-warn: var(--accent-warn);
|
|
757
765
|
--color-on-accent-warn: var(--on-accent-warn);
|
|
766
|
+
--color-accent-warn-hover: var(--accent-warn-hover);
|
|
758
767
|
--color-accent-error: var(--accent-error);
|
|
759
768
|
--color-on-accent-error: var(--on-accent-error);
|
|
769
|
+
--color-accent-error-hover: var(--accent-error-hover);
|
|
760
770
|
|
|
761
|
-
/* component faces: derived below, pinned per theme by EV, so `bg-button-
|
|
762
|
-
* and `border-
|
|
763
|
-
--color-button-primary-bg: var(--button-primary-bg);
|
|
764
|
-
--color-button-primary-hover: var(--button-primary-hover);
|
|
765
|
-
--color-button-primary-border: var(--button-primary-border);
|
|
766
|
-
--color-button-primary-ink: var(--button-primary-ink);
|
|
771
|
+
/* component faces: derived below, pinned per theme by EV, so `bg-button-danger-bg`
|
|
772
|
+
* and `border-tint-error-edge` are real utilities the class merge understands */
|
|
767
773
|
--color-button-danger-bg: var(--button-danger-bg);
|
|
768
774
|
--color-button-danger-hover: var(--button-danger-hover);
|
|
769
775
|
--color-button-danger-border: var(--button-danger-border);
|
|
770
776
|
--color-button-danger-ink: var(--button-danger-ink);
|
|
771
|
-
--color-
|
|
772
|
-
--color-
|
|
773
|
-
--color-
|
|
774
|
-
--color-
|
|
775
|
-
--color-
|
|
776
|
-
--color-
|
|
777
|
-
--color-
|
|
778
|
-
--color-
|
|
779
|
-
--color-
|
|
780
|
-
--color-
|
|
781
|
-
--color-
|
|
782
|
-
--color-
|
|
777
|
+
--color-tint-neutral-fill: var(--tint-neutral-fill);
|
|
778
|
+
--color-tint-neutral-edge: var(--tint-neutral-edge);
|
|
779
|
+
--color-tint-neutral-wash: var(--tint-neutral-wash);
|
|
780
|
+
--color-tint-primary-fill: var(--tint-primary-fill);
|
|
781
|
+
--color-tint-primary-edge: var(--tint-primary-edge);
|
|
782
|
+
--color-tint-primary-wash: var(--tint-primary-wash);
|
|
783
|
+
--color-tint-positive-fill: var(--tint-positive-fill);
|
|
784
|
+
--color-tint-positive-edge: var(--tint-positive-edge);
|
|
785
|
+
--color-tint-positive-wash: var(--tint-positive-wash);
|
|
786
|
+
--color-tint-info-fill: var(--tint-info-fill);
|
|
787
|
+
--color-tint-info-edge: var(--tint-info-edge);
|
|
788
|
+
--color-tint-info-wash: var(--tint-info-wash);
|
|
789
|
+
--color-tint-warn-fill: var(--tint-warn-fill);
|
|
790
|
+
--color-tint-warn-edge: var(--tint-warn-edge);
|
|
791
|
+
--color-tint-warn-wash: var(--tint-warn-wash);
|
|
792
|
+
--color-tint-error-fill: var(--tint-error-fill);
|
|
793
|
+
--color-tint-error-edge: var(--tint-error-edge);
|
|
794
|
+
--color-tint-error-wash: var(--tint-error-wash);
|
|
795
|
+
--color-tint-trace-fill: var(--tint-trace-fill);
|
|
796
|
+
--color-tint-trace-edge: var(--tint-trace-edge);
|
|
797
|
+
--color-tint-trace-wash: var(--tint-trace-wash);
|
|
798
|
+
--color-tint-debug-fill: var(--tint-debug-fill);
|
|
799
|
+
--color-tint-debug-edge: var(--tint-debug-edge);
|
|
800
|
+
--color-tint-debug-wash: var(--tint-debug-wash);
|
|
783
801
|
|
|
784
802
|
/* charts — distinguishable hues carrying no significance */
|
|
785
803
|
--color-chart-1: var(--chart-1);
|
|
@@ -819,7 +837,14 @@
|
|
|
819
837
|
* side — ink over white needs ~47% to clear it, dark lands near 4:1. */
|
|
820
838
|
--input: color-mix(in srgb, var(--ink) 48%, transparent);
|
|
821
839
|
--ring: var(--primary-ink);
|
|
822
|
-
--
|
|
840
|
+
--on-secondary: var(--ink);
|
|
841
|
+
/* a solid fill's hover moves away from its label, so the label only gains contrast */
|
|
842
|
+
--primary-hover: color-mix(in srgb, rgb(from var(--on-primary) calc(255 - r) calc(255 - g) calc(255 - b)) var(--tint-hover), var(--primary));
|
|
843
|
+
--accent-trace-hover: color-mix(in srgb, rgb(from var(--on-accent-trace) calc(255 - r) calc(255 - g) calc(255 - b)) var(--tint-hover), var(--accent-trace));
|
|
844
|
+
--accent-debug-hover: color-mix(in srgb, rgb(from var(--on-accent-debug) calc(255 - r) calc(255 - g) calc(255 - b)) var(--tint-hover), var(--accent-debug));
|
|
845
|
+
--accent-info-hover: color-mix(in srgb, rgb(from var(--on-accent-info) calc(255 - r) calc(255 - g) calc(255 - b)) var(--tint-hover), var(--accent-info));
|
|
846
|
+
--accent-warn-hover: color-mix(in srgb, rgb(from var(--on-accent-warn) calc(255 - r) calc(255 - g) calc(255 - b)) var(--tint-hover), var(--accent-warn));
|
|
847
|
+
--accent-error-hover: color-mix(in srgb, rgb(from var(--on-accent-error) calc(255 - r) calc(255 - g) calc(255 - b)) var(--tint-hover), var(--accent-error));
|
|
823
848
|
--primary-border: color-mix(in srgb, var(--primary-ink) 55%, transparent);
|
|
824
849
|
/* the quiet status roles as text on a surface: a fill is a shape, and as text
|
|
825
850
|
* it reads far below AA on a light plane. warn and error have none: they are
|
|
@@ -834,31 +859,40 @@
|
|
|
834
859
|
* same scopes, listed in another order so the contract reader finds one rule
|
|
835
860
|
* per selector. */
|
|
836
861
|
:where([data-theme], [data-brand], .light, .dark, :root) {
|
|
837
|
-
/*
|
|
838
|
-
--button-primary-bg: transparent;
|
|
839
|
-
--button-primary-hover: var(--hover);
|
|
840
|
-
--button-primary-border: color-mix(in srgb, var(--ink) 60%, transparent);
|
|
841
|
-
--button-primary-ink: var(--ink);
|
|
862
|
+
/* danger is an outline in the error role */
|
|
842
863
|
--button-danger-bg: transparent;
|
|
843
|
-
--button-danger-hover: color-mix(in srgb, var(--accent-error)
|
|
864
|
+
--button-danger-hover: color-mix(in srgb, var(--accent-error) var(--tint-hover), transparent);
|
|
844
865
|
--button-danger-border: var(--accent-error);
|
|
845
866
|
--button-danger-ink: var(--accent-error);
|
|
846
867
|
|
|
847
|
-
/*
|
|
848
|
-
* the edge and the label are one hue
|
|
849
|
-
*
|
|
850
|
-
|
|
851
|
-
--
|
|
852
|
-
--
|
|
853
|
-
--
|
|
854
|
-
--
|
|
855
|
-
--
|
|
856
|
-
--
|
|
857
|
-
--
|
|
858
|
-
--
|
|
859
|
-
--
|
|
860
|
-
--
|
|
861
|
-
--
|
|
868
|
+
/* a tone worn as a tint: a chip's fill and edge are the tone's ink at
|
|
869
|
+
* --tint-fill and --tint-edge, so the edge and the label are one hue, and an
|
|
870
|
+
* area's wash is it at --tint-wash. warn and error are their own ink
|
|
871
|
+
* (docs/spec/accents.md). */
|
|
872
|
+
--tint-neutral-fill: var(--hover);
|
|
873
|
+
--tint-neutral-edge: var(--border);
|
|
874
|
+
--tint-neutral-wash: transparent;
|
|
875
|
+
--tint-primary-fill: color-mix(in srgb, var(--primary-ink) var(--tint-fill), transparent);
|
|
876
|
+
--tint-primary-edge: color-mix(in srgb, var(--primary-ink) var(--tint-edge), transparent);
|
|
877
|
+
--tint-primary-wash: color-mix(in srgb, var(--primary-ink) var(--tint-wash), transparent);
|
|
878
|
+
--tint-positive-fill: color-mix(in srgb, var(--positive-ink) var(--tint-fill), transparent);
|
|
879
|
+
--tint-positive-edge: color-mix(in srgb, var(--positive-ink) var(--tint-edge), transparent);
|
|
880
|
+
--tint-positive-wash: color-mix(in srgb, var(--positive-ink) var(--tint-wash), transparent);
|
|
881
|
+
--tint-info-fill: color-mix(in srgb, var(--accent-info-ink) var(--tint-fill), transparent);
|
|
882
|
+
--tint-info-edge: color-mix(in srgb, var(--accent-info-ink) var(--tint-edge), transparent);
|
|
883
|
+
--tint-info-wash: color-mix(in srgb, var(--accent-info-ink) var(--tint-wash), transparent);
|
|
884
|
+
--tint-warn-fill: color-mix(in srgb, var(--accent-warn) var(--tint-fill), transparent);
|
|
885
|
+
--tint-warn-edge: color-mix(in srgb, var(--accent-warn) var(--tint-edge), transparent);
|
|
886
|
+
--tint-warn-wash: color-mix(in srgb, var(--accent-warn) var(--tint-wash), transparent);
|
|
887
|
+
--tint-error-fill: color-mix(in srgb, var(--accent-error) var(--tint-fill), transparent);
|
|
888
|
+
--tint-error-edge: color-mix(in srgb, var(--accent-error) var(--tint-edge), transparent);
|
|
889
|
+
--tint-error-wash: color-mix(in srgb, var(--accent-error) var(--tint-wash), transparent);
|
|
890
|
+
--tint-trace-fill: color-mix(in srgb, var(--accent-trace) var(--tint-fill), transparent);
|
|
891
|
+
--tint-trace-edge: color-mix(in srgb, var(--accent-trace) var(--tint-edge), transparent);
|
|
892
|
+
--tint-trace-wash: color-mix(in srgb, var(--accent-trace) var(--tint-wash), transparent);
|
|
893
|
+
--tint-debug-fill: color-mix(in srgb, var(--accent-debug) var(--tint-fill), transparent);
|
|
894
|
+
--tint-debug-edge: color-mix(in srgb, var(--accent-debug) var(--tint-edge), transparent);
|
|
895
|
+
--tint-debug-wash: color-mix(in srgb, var(--accent-debug) var(--tint-wash), transparent);
|
|
862
896
|
}
|
|
863
897
|
|
|
864
898
|
/* Geometry. A `[data-brand]` scope is a theme root of its own, so it restarts
|
|
@@ -868,22 +902,37 @@
|
|
|
868
902
|
--radius: 0.375rem; /* panels and menus */
|
|
869
903
|
/* control geometry, so a consumer reshapes every button/input at once */
|
|
870
904
|
--control-radius: 0.25rem;
|
|
905
|
+
--control-h: 2.25rem;
|
|
906
|
+
--control-step: 0.25rem;
|
|
907
|
+
--control-inset: 1rem; /* the md rung's side inset; every other rung's moves with its height */
|
|
871
908
|
--chip-radius: 0.25rem;
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
--
|
|
909
|
+
--disabled-opacity: 0.5;
|
|
910
|
+
/* how much of its ink a tint's fill and edge take: an outline by default, a
|
|
911
|
+
* tinted pill where a theme raises the fill; and a tone's pointed-at row or face */
|
|
912
|
+
--tint-fill: 0%;
|
|
913
|
+
--tint-edge: 50%;
|
|
914
|
+
--tint-hover: 10%;
|
|
915
|
+
/* how much of its ink an area in a tone (a banner, an alert) is washed with:
|
|
916
|
+
* an area needs a body to read as content, where a chip reads as an outline.
|
|
917
|
+
* At 10 % Light's positive and warn labels fall under their floor. */
|
|
918
|
+
--tint-wash: 6%;
|
|
876
919
|
/* u2 is flat: depth is surface steps and hairlines. Never `none` — inside
|
|
877
920
|
* Tailwind's comma-separated box-shadow list it invalidates the whole
|
|
878
921
|
* declaration, and the focus ring goes with it. */
|
|
879
922
|
--depth-card: 0 0 #0000;
|
|
880
923
|
--depth-elevated: 0 0 #0000;
|
|
881
924
|
--depth-overlay: 0 0 #0000;
|
|
882
|
-
|
|
883
|
-
/* the Xl (call-to-action) button reads all three */
|
|
925
|
+
/* the Xl (call-to-action) rung's inset and text */
|
|
884
926
|
--control-px: 2rem;
|
|
885
927
|
--control-text: 1rem;
|
|
886
|
-
/*
|
|
928
|
+
/* the type ramps: text steps 1 px, display steps 4 px, a scale over the display tier */
|
|
929
|
+
--body-size: 0.8125rem;
|
|
930
|
+
--body-step: 0.0625rem;
|
|
931
|
+
--body-leading: 1.125rem;
|
|
932
|
+
--display-base: 1rem;
|
|
933
|
+
--display-step: 0.25rem;
|
|
934
|
+
--display-leading: 0.375rem; /* h1, h2 */
|
|
935
|
+
--figure-leading: 0.25rem; /* figure-m, figure-l */
|
|
887
936
|
--display-scale: 1;
|
|
888
937
|
/* the vertical rhythm of a full-bleed <Section>; `tight` is the sub-page one */
|
|
889
938
|
--band-py: 2.25rem;
|
|
@@ -927,6 +976,24 @@
|
|
|
927
976
|
*/
|
|
928
977
|
}
|
|
929
978
|
|
|
979
|
+
/* The control height and inset ramps a `Size` step names, re-derived on every
|
|
980
|
+
* scope that may set `--control-h`. Pin one step to bend the ramp. */
|
|
981
|
+
:where(:root, [data-brand], [data-theme]) {
|
|
982
|
+
--control-h-2xs: calc(var(--control-h) - 3 * var(--control-step));
|
|
983
|
+
--control-h-xs: calc(var(--control-h) - 2 * var(--control-step));
|
|
984
|
+
--control-h-sm: calc(var(--control-h) - var(--control-step));
|
|
985
|
+
--control-h-md: var(--control-h);
|
|
986
|
+
--control-h-lg: calc(var(--control-h) + var(--control-step));
|
|
987
|
+
--control-h-xl: calc(var(--control-h) + 3 * var(--control-step));
|
|
988
|
+
--control-h-touch: max(var(--control-h-lg), 2.75rem); /* the 44 px pointer-target floor (WCAG 2.5.5) */
|
|
989
|
+
--control-inset-xs: calc(var(--control-h-xs) - var(--control-h) + var(--control-inset));
|
|
990
|
+
--control-inset-sm: calc(var(--control-h-sm) - var(--control-h) + var(--control-inset));
|
|
991
|
+
--control-inset-md: var(--control-inset);
|
|
992
|
+
--control-inset-lg: calc(var(--control-h-lg) - var(--control-h) + var(--control-inset));
|
|
993
|
+
--control-inset-xl: var(--control-px);
|
|
994
|
+
--control-inset-touch: calc(var(--control-h-touch) - var(--control-h) + var(--control-inset));
|
|
995
|
+
}
|
|
996
|
+
|
|
930
997
|
:root {
|
|
931
998
|
/* shell offset — viewport space reserved by whatever shell hosts the app.
|
|
932
999
|
Standalone apps get 0; a hosting shell overrides on :root. Size
|