@exsto/ds 0.0.1-rc.18 → 0.0.1-rc.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +22 -1
  2. package/dist/index.js +3 -2
  3. package/dist/source-hash.txt +1 -1
  4. package/dist/styles.css +54 -55
  5. package/dist/theme.css +6 -1
  6. package/dist/ui/src/components/edyn/file-input/file-input.js +2 -2
  7. package/dist/ui/src/components/edyn/file-input/file-input.js.map +1 -1
  8. package/dist/ui/src/components/edyn/multi-select/multi-select.js +6 -6
  9. package/dist/ui/src/components/edyn/multi-select/multi-select.js.map +1 -1
  10. package/dist/ui/src/components/edyn/rich-text-editor/mention-list.js +1 -1
  11. package/dist/ui/src/components/edyn/rich-text-editor/rich-text-editor.js +1 -1
  12. package/dist/ui/src/components/edyn/rich-text-editor/rich-text-editor.js.map +1 -1
  13. package/dist/ui/src/components/edyn/rich-text-editor/toolbar.js +1 -1
  14. package/dist/ui/src/components/edyn/rich-text-editor/toolbar.js.map +1 -1
  15. package/dist/ui/src/components/edyn/time-field/time-field.js +8 -1
  16. package/dist/ui/src/components/edyn/time-field/time-field.js.map +1 -1
  17. package/dist/ui/src/components/ui/breadcrumb/breadcrumb.js +1 -1
  18. package/dist/ui/src/components/ui/breadcrumb/breadcrumb.js.map +1 -1
  19. package/dist/ui/src/components/ui/button/button.js +2 -2
  20. package/dist/ui/src/components/ui/button/button.js.map +1 -1
  21. package/dist/ui/src/components/ui/card/card.js +1 -1
  22. package/dist/ui/src/components/ui/card/card.js.map +1 -1
  23. package/dist/ui/src/components/ui/checkbox/checkbox.js +1 -1
  24. package/dist/ui/src/components/ui/checkbox/checkbox.js.map +1 -1
  25. package/dist/ui/src/components/ui/combobox/combobox.d.ts +5 -1
  26. package/dist/ui/src/components/ui/combobox/combobox.js +12 -18
  27. package/dist/ui/src/components/ui/combobox/combobox.js.map +1 -1
  28. package/dist/ui/src/components/ui/command/command.js +2 -2
  29. package/dist/ui/src/components/ui/command/command.js.map +1 -1
  30. package/dist/ui/src/components/ui/context-menu/context-menu.js +5 -9
  31. package/dist/ui/src/components/ui/context-menu/context-menu.js.map +1 -1
  32. package/dist/ui/src/components/ui/dropdown-menu/dropdown-menu.js +5 -9
  33. package/dist/ui/src/components/ui/dropdown-menu/dropdown-menu.js.map +1 -1
  34. package/dist/ui/src/components/ui/empty/empty.js +1 -1
  35. package/dist/ui/src/components/ui/empty/empty.js.map +1 -1
  36. package/dist/ui/src/components/ui/field/field.js +2 -2
  37. package/dist/ui/src/components/ui/field/field.js.map +1 -1
  38. package/dist/ui/src/components/ui/hover-card/hover-card.js +2 -1
  39. package/dist/ui/src/components/ui/hover-card/hover-card.js.map +1 -1
  40. package/dist/ui/src/components/ui/input/input.js +1 -1
  41. package/dist/ui/src/components/ui/input/input.js.map +1 -1
  42. package/dist/ui/src/components/ui/input-group/input-group.js +1 -1
  43. package/dist/ui/src/components/ui/input-group/input-group.js.map +1 -1
  44. package/dist/ui/src/components/ui/input-otp/input-otp.js +1 -1
  45. package/dist/ui/src/components/ui/input-otp/input-otp.js.map +1 -1
  46. package/dist/ui/src/components/ui/label/label.js +1 -1
  47. package/dist/ui/src/components/ui/label/label.js.map +1 -1
  48. package/dist/ui/src/components/ui/menubar/menubar.js +7 -4
  49. package/dist/ui/src/components/ui/menubar/menubar.js.map +1 -1
  50. package/dist/ui/src/components/ui/native-select/native-select.js +1 -1
  51. package/dist/ui/src/components/ui/native-select/native-select.js.map +1 -1
  52. package/dist/ui/src/components/ui/navigation-menu/navigation-menu.js +2 -1
  53. package/dist/ui/src/components/ui/navigation-menu/navigation-menu.js.map +1 -1
  54. package/dist/ui/src/components/ui/popover/popover.js +2 -1
  55. package/dist/ui/src/components/ui/popover/popover.js.map +1 -1
  56. package/dist/ui/src/components/ui/questionnaire/questionnaire.js +4 -4
  57. package/dist/ui/src/components/ui/questionnaire/questionnaire.js.map +1 -1
  58. package/dist/ui/src/components/ui/radio-group/radio-group.js +1 -1
  59. package/dist/ui/src/components/ui/radio-group/radio-group.js.map +1 -1
  60. package/dist/ui/src/components/ui/scroll-area/index.d.ts +1 -0
  61. package/dist/ui/src/components/ui/scroll-area/popup-list-scroll.d.ts +13 -0
  62. package/dist/ui/src/components/ui/scroll-area/popup-list-scroll.js +69 -0
  63. package/dist/ui/src/components/ui/scroll-area/popup-list-scroll.js.map +1 -0
  64. package/dist/ui/src/components/ui/scroll-area/scroll-area.d.ts +2 -4
  65. package/dist/ui/src/components/ui/scroll-area/scroll-area.js +27 -4
  66. package/dist/ui/src/components/ui/scroll-area/scroll-area.js.map +1 -1
  67. package/dist/ui/src/components/ui/select/select.js +9 -14
  68. package/dist/ui/src/components/ui/select/select.js.map +1 -1
  69. package/dist/ui/src/components/ui/tabs/tabs.js +1 -1
  70. package/dist/ui/src/components/ui/tabs/tabs.js.map +1 -1
  71. package/dist/ui/src/components/ui/textarea/textarea.js +1 -1
  72. package/dist/ui/src/components/ui/textarea/textarea.js.map +1 -1
  73. package/dist/ui/src/components/ui/toggle/toggle.js +2 -2
  74. package/dist/ui/src/components/ui/toggle/toggle.js.map +1 -1
  75. package/dist/ui/src/components/ui/tooltip/tooltip.js +2 -1
  76. package/dist/ui/src/components/ui/tooltip/tooltip.js.map +1 -1
  77. package/dist/ui/src/index.d.ts +1 -1
  78. package/dist/ui/src/lib/popup-list.d.ts +7 -10
  79. package/dist/ui/src/lib/popup-list.js +8 -11
  80. package/dist/ui/src/lib/popup-list.js.map +1 -1
  81. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popup-list-scroll.js","names":[],"sources":["../../../../../../../ui/src/components/ui/scroll-area/popup-list-scroll.tsx"],"sourcesContent":["import { POPUP_LIST_HEIGHT_CLASS } from '@edyn/ui/lib/popup-list';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { type ReactNode, useLayoutEffect, useRef } from 'react';\nimport { ScrollArea } from './scroll-area';\n\nconst ROW = '[role=\"option\"], [role^=\"menuitem\"]';\nconst FULL_ROWS = 8;\n/** POPUP_LIST_HEIGHT_CLASS's margin, above and below. */\nconst AIR = 8;\n\nexport interface IPopupListScrollProps {\n children: ReactNode;\n className?: string;\n /** See ScrollArea. A menu turns it off: its items are the tab stops. */\n focusable?: boolean;\n}\n\n/**\n * The scrolling part of a popup list: eight rows at most, or the whole rows the room allows. Only rows are counted; a label\n * or separator among them adds its own height. POPUP_LIST_HEIGHT_CLASS holds the CSS cap until this has measured\n * (`--popup-list-cap`). See docs/architecture.md.\n */\nexport const PopupListScroll = ({ children, className, focusable }: IPopupListScrollProps) => {\n const refRoot = useRef<HTMLDivElement | null>(null);\n const refViewport = useRef<HTMLDivElement | null>(null);\n\n useLayoutEffect(() => {\n const root = refRoot.current;\n const content = refViewport.current?.firstElementChild;\n if (!root || !(content instanceof HTMLElement)) {\n return;\n }\n const measure = () => {\n // In layout units, not the scale of the opening animation.\n const box = content.getBoundingClientRect();\n const scale = content.offsetHeight > 0 ? box.height / content.offsetHeight : 1;\n const bottoms = [...content.querySelectorAll<HTMLElement>(ROW)].map((row) => (row.getBoundingClientRect().bottom - box.top) / scale);\n const available = Number.parseFloat(getComputedStyle(root).getPropertyValue('--available-height'));\n const room = Number.isFinite(available) ? available - AIR : Number.POSITIVE_INFINITY;\n let rows = Math.min(bottoms.length, FULL_ROWS);\n while (rows > 0 && (bottoms[rows - 1] ?? 0) > room + 0.5) {\n rows -= 1;\n }\n const everything = bottoms.length <= FULL_ROWS && content.offsetHeight <= room + 0.5;\n const cap = everything ? content.offsetHeight : rows > 0 ? (bottoms[rows - 1] ?? 0) : undefined;\n if (cap === undefined) {\n root.style.removeProperty('--popup-list-cap');\n } else {\n root.style.setProperty('--popup-list-cap', `${Math.ceil(cap)}px`);\n }\n };\n measure();\n const resized = new ResizeObserver(measure);\n resized.observe(content);\n const changed = new MutationObserver(measure);\n changed.observe(content, { childList: true, subtree: true });\n // The room changes as the popup is placed and as the window moves.\n let positioner: HTMLElement | null = root.parentElement;\n while (positioner && positioner.style.getPropertyValue('--available-height') === '') {\n positioner = positioner.parentElement;\n }\n const moved = new MutationObserver(measure);\n if (positioner) {\n moved.observe(positioner, { attributes: true, attributeFilter: ['style'] });\n }\n return () => {\n resized.disconnect();\n changed.disconnect();\n moved.disconnect();\n };\n }, []);\n\n return (\n <ScrollArea ref={refRoot} viewportRef={refViewport} type=\"always\" fade focusable={focusable} className={cn(POPUP_LIST_HEIGHT_CLASS, className)}>\n {children}\n </ScrollArea>\n );\n};\n"],"mappings":";;;;;;AAKA,IAAM,MAAM;AACZ,IAAM,YAAY;;AAElB,IAAM,MAAM;;;;;;AAcZ,IAAa,mBAAmB,EAAE,UAAU,WAAW,gBAAuC;CAC5F,MAAM,UAAU,OAA8B,IAAI;CAClD,MAAM,cAAc,OAA8B,IAAI;CAEtD,sBAAsB;EACpB,MAAM,OAAO,QAAQ;EACrB,MAAM,UAAU,YAAY,SAAS;EACrC,IAAI,CAAC,QAAQ,EAAE,mBAAmB,cAChC;EAEF,MAAM,gBAAgB;GAEpB,MAAM,MAAM,QAAQ,sBAAsB;GAC1C,MAAM,QAAQ,QAAQ,eAAe,IAAI,IAAI,SAAS,QAAQ,eAAe;GAC7E,MAAM,UAAU,CAAC,GAAG,QAAQ,iBAA8B,GAAG,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,sBAAsB,CAAC,CAAC,SAAS,IAAI,OAAO,KAAK;GACnI,MAAM,YAAY,OAAO,WAAW,iBAAiB,IAAI,CAAC,CAAC,iBAAiB,oBAAoB,CAAC;GACjG,MAAM,OAAO,OAAO,SAAS,SAAS,IAAI,YAAY,MAAM,OAAO;GACnE,IAAI,OAAO,KAAK,IAAI,QAAQ,QAAQ,SAAS;GAC7C,OAAO,OAAO,MAAM,QAAQ,OAAO,MAAM,KAAK,OAAO,IACnD,QAAQ;GAGV,MAAM,MADa,QAAQ,UAAU,aAAa,QAAQ,gBAAgB,OAAO,KACxD,QAAQ,eAAe,OAAO,IAAK,QAAQ,OAAO,MAAM,IAAK,KAAA;GACtF,IAAI,QAAQ,KAAA,GACV,KAAK,MAAM,eAAe,kBAAkB;QAE5C,KAAK,MAAM,YAAY,oBAAoB,GAAG,KAAK,KAAK,GAAG,EAAE,GAAG;EAEpE;EACA,QAAQ;EACR,MAAM,UAAU,IAAI,eAAe,OAAO;EAC1C,QAAQ,QAAQ,OAAO;EACvB,MAAM,UAAU,IAAI,iBAAiB,OAAO;EAC5C,QAAQ,QAAQ,SAAS;GAAE,WAAW;GAAM,SAAS;EAAK,CAAC;EAE3D,IAAI,aAAiC,KAAK;EAC1C,OAAO,cAAc,WAAW,MAAM,iBAAiB,oBAAoB,MAAM,IAC/E,aAAa,WAAW;EAE1B,MAAM,QAAQ,IAAI,iBAAiB,OAAO;EAC1C,IAAI,YACF,MAAM,QAAQ,YAAY;GAAE,YAAY;GAAM,iBAAiB,CAAC,OAAO;EAAE,CAAC;EAE5E,aAAa;GACX,QAAQ,WAAW;GACnB,QAAQ,WAAW;GACnB,MAAM,WAAW;EACnB;CACF,GAAG,CAAC,CAAC;CAEL,OACE,oBAAC,YAAD;EAAY,KAAK;EAAS,aAAa;EAAa,MAAK;EAAS,MAAA;EAAgB;EAAW,WAAW,GAAG,yBAAyB,SAAS;EAC1I;CACS,CAAA;AAEhB"}
@@ -39,10 +39,8 @@ export interface IScrollAreaProps extends ComponentProps<typeof BaseScrollArea.R
39
39
  /** Published on the viewport as data-scroll-restoration-id, for a router that restores scroll position. */
40
40
  scrollRestorationId?: string;
41
41
  /**
42
- * Whether the viewport is a tab stop of its own (default). Turn it off inside a
43
- * widget that already owns focus, a menu above all: its items are the tab
44
- * stops, and a focusable wrapper between the role and its items is both
45
- * redundant and an aria-required-children violation.
42
+ * Whether the viewport may be a tab stop (default). It is one only while it overflows and nothing inside can take Tab
43
+ * (axe's scrollable-region-focusable), with a 1px keyboard-only line. Off inside a menu, whose items are the tab stops.
46
44
  */
47
45
  focusable?: boolean;
48
46
  /** @deprecated Use `viewportId`. */
@@ -1,6 +1,6 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { useMergedRefs } from "../../../hooks/use-merged-refs.js";
3
- import { useEffect, useRef } from "react";
3
+ import { useEffect, useRef, useState } from "react";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import { ScrollArea } from "@base-ui/react/scroll-area";
6
6
  //#region ../ui/src/components/ui/scroll-area/scroll-area.tsx
@@ -29,6 +29,8 @@ var ScrollBar = ({ className, orientation = "vertical", visibility = "hover", ..
29
29
  * the a11y lint rule, which cannot tell it from an invalid role.
30
30
  */
31
31
  var NO_ROLE = { role: void 0 };
32
+ /** What takes Tab inside a region: if any is there, the region is not a stop of its own. */
33
+ var FOCUSABLE_INSIDE = "a[href], button:not(:disabled), input:not([type=\"hidden\"]):not(:disabled), select:not(:disabled), textarea:not(:disabled), summary, [contenteditable], [tabindex]:not([tabindex=\"-1\"])";
32
34
  /** Base UI makes the viewport a tab stop (0, or -1 with nothing to scroll); undefined takes that away. */
33
35
  var NO_TAB_STOP = { tabIndex: void 0 };
34
36
  var FADE_AXIS = {
@@ -65,6 +67,27 @@ var FADE_AXIS = {
65
67
  var ScrollArea$1 = ({ className, children, orientation = "vertical", type = "hover", fade = false, fadeFrom = "card", scrollbarClassName, viewportId, viewportRef, viewportClassName, scrollRestorationId, focusable = true, viewPortId, viewPortRef, viewPortClassName, scrollVerticalClassName, scrollHorizontalClassName, ...props }) => {
66
68
  const refInner = useRef(null);
67
69
  const refsViewport = useMergedRefs(refInner, viewportRef ?? viewPortRef);
70
+ const [holdsFocusable, setHoldsFocusable] = useState(false);
71
+ useEffect(() => {
72
+ const el = refInner.current;
73
+ if (!el || !focusable) return;
74
+ const read = () => setHoldsFocusable(el.querySelector(FOCUSABLE_INSIDE) !== null);
75
+ read();
76
+ const observer = new MutationObserver(read);
77
+ observer.observe(el, {
78
+ childList: true,
79
+ subtree: true,
80
+ attributes: true,
81
+ attributeFilter: [
82
+ "tabindex",
83
+ "disabled",
84
+ "href"
85
+ ]
86
+ });
87
+ return () => {
88
+ observer.disconnect();
89
+ };
90
+ }, [focusable]);
68
91
  useEffect(() => {
69
92
  const el = refInner.current;
70
93
  if (!el) return;
@@ -80,7 +103,7 @@ var ScrollArea$1 = ({ className, children, orientation = "vertical", type = "hov
80
103
  return /* @__PURE__ */ jsxs(ScrollArea.Root, {
81
104
  "data-slot": "scroll-area",
82
105
  "data-focus": "inset",
83
- className: cn("group/scroll-area relative grid min-w-0 grid-rows-1 overflow-hidden", className),
106
+ className: cn("group/scroll-area relative grid min-w-0 grid-rows-1 overflow-hidden", orientation !== "vertical" && "data-has-overflow-x:pb-(--scroll-bar-reserve)", className),
84
107
  "data-fade": fade ? FADE_AXIS[orientation] : void 0,
85
108
  ...NO_ROLE,
86
109
  ...props,
@@ -102,8 +125,8 @@ var ScrollArea$1 = ({ className, children, orientation = "vertical", type = "hov
102
125
  ref: refsViewport,
103
126
  "data-scroll-restoration-id": scrollRestorationId,
104
127
  ...NO_ROLE,
105
- ...focusable ? null : NO_TAB_STOP,
106
- className: cn("max-h-inherit w-full rounded-[inherit]", orientation === "vertical" && "overflow-x-hidden!", orientation === "horizontal" && "overflow-y-hidden!", orientation !== "vertical" && "data-has-overflow-x:pb-(--scroll-bar-reserve)", viewportClassName ?? viewPortClassName),
128
+ ...focusable && !holdsFocusable ? null : NO_TAB_STOP,
129
+ className: cn("max-h-inherit w-full rounded-[inherit]", orientation === "vertical" && "overflow-x-hidden!", orientation === "horizontal" && "overflow-y-hidden!", viewportClassName ?? viewPortClassName),
107
130
  children: /* @__PURE__ */ jsx(ScrollArea.Content, {
108
131
  ...NO_ROLE,
109
132
  style: orientation === "vertical" ? { minWidth: 0 } : void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"scroll-area.js","names":[],"sources":["../../../../../../../ui/src/components/ui/scroll-area/scroll-area.tsx"],"sourcesContent":["import { ScrollArea as BaseScrollArea } from '@base-ui/react/scroll-area';\nimport { useMergedRefs } from '@edyn/ui/hooks/use-merged-refs';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { type ComponentProps, type RefObject, useEffect, useRef } from 'react';\n\n/**\n * When the bar shows: 'hover' on area hover or while scrolling (default),\n * 'scroll' only while scrolling, 'always' permanent. In every mode the bar is\n * mounted only while that axis actually overflows, so 'always' means \"always\n * when there is something to scroll\", never a bar on a list that fits.\n */\nexport type TScrollbarVisibility = 'hover' | 'scroll' | 'always';\n\n/**\n * Surface the edge fades blended into, back when they were painted.\n *\n * @deprecated The fades are cut into the content by a mask, so they match any\n * surface without being told which one. Still accepted, and ignored.\n */\nexport type TScrollAreaFadeFrom = 'card' | 'background' | 'sidebar' | 'popover';\n\nexport interface IScrollBarProps extends ComponentProps<typeof BaseScrollArea.Scrollbar> {\n visibility?: TScrollbarVisibility;\n}\n\nexport const ScrollBar = ({ className, orientation = 'vertical', visibility = 'hover', ...props }: IScrollBarProps) => {\n return (\n <BaseScrollArea.Scrollbar\n data-slot=\"scroll-area-scrollbar\"\n orientation={orientation}\n className={cn(\n 'peer/scrollbar z-100 flex touch-none select-none motion-safe:transition-opacity motion-safe:duration-150',\n // Size, gap and start read --scroll-bar-size, --scroll-bar-gap and --scroll-bar-start (see scroll-bar.css), whose\n // defaults are the 8px bar flush with the box that it has always been.\n orientation === 'vertical' &&\n 'h-(--scroll-bar-length) w-(--scroll-bar-size) me-(--scroll-bar-gap) mt-(--scroll-bar-offset-top) border-l border-l-transparent p-px',\n orientation === 'horizontal' &&\n 'h-(--scroll-bar-size) ms-(--scroll-bar-gap) me-(--scroll-bar-gap) mb-(--scroll-bar-gap) flex-col border-t border-t-transparent p-px',\n visibility !== 'always' && 'opacity-0 data-scrolling:opacity-100',\n visibility === 'hover' && 'data-hovering:opacity-100 group-hover/scroll-area:opacity-100',\n className,\n )}\n {...props}\n >\n <BaseScrollArea.Thumb className=\"relative flex-1 rounded-full bg-muted-foreground/50 transition-colors hover:bg-muted-foreground/70 data-scrolling:bg-muted-foreground/70\" />\n </BaseScrollArea.Scrollbar>\n );\n};\n\nexport interface IScrollAreaProps extends ComponentProps<typeof BaseScrollArea.Root> {\n /** Which axes get a styled scrollbar; content decides what actually overflows. */\n orientation?: 'horizontal' | 'vertical' | 'both';\n /** Scrollbar reveal behavior (mirrors the Radix ScrollArea `type` prop). */\n type?: TScrollbarVisibility;\n /** Edge fades hinting at clipped content; each one shows only while its own edge hides something. */\n fade?: boolean;\n /**\n * @deprecated No longer read. The fades mask the content, so they sit correctly\n * on any surface; passing this does nothing and is safe to delete.\n */\n fadeFrom?: TScrollAreaFadeFrom;\n /** Places both bars, for a host that gives them a gutter of their own (a sidebar menu). */\n scrollbarClassName?: string;\n viewportId?: string;\n /** Access to the scrollable viewport (e.g. to reset scroll position on route changes). */\n viewportRef?: RefObject<HTMLDivElement | null>;\n viewportClassName?: string;\n /** Published on the viewport as data-scroll-restoration-id, for a router that restores scroll position. */\n scrollRestorationId?: string;\n /**\n * Whether the viewport is a tab stop of its own (default). Turn it off inside a\n * widget that already owns focus, a menu above all: its items are the tab\n * stops, and a focusable wrapper between the role and its items is both\n * redundant and an aria-required-children violation.\n */\n focusable?: boolean;\n /** @deprecated Use `viewportId`. */\n viewPortId?: string;\n /** @deprecated Use `viewportRef`. */\n viewPortRef?: RefObject<HTMLDivElement | null>;\n /** @deprecated Use `viewportClassName`. */\n viewPortClassName?: string;\n /** Places the vertical bar only; `scrollbarClassName` covers both. */\n scrollVerticalClassName?: string;\n /** Places the horizontal bar only; `scrollbarClassName` covers both. */\n scrollHorizontalClassName?: string;\n}\n\n/**\n * Which axes fade, published for scroll-fade.css to key its mask off. The\n * stylesheet reaches this element's own viewport through a child combinator, so a\n * ScrollArea nested in another one cannot pick up its ancestor's edges.\n */\n/**\n * Base UI gives the root, the viewport and the content `role=\"presentation\"`. On\n * a div that changes nothing for a screen reader, but it is an EXPLICIT role, and\n * axe treats explicit presentation children as foreign to a parent that owns\n * required children. A ScrollArea inside `role=\"menu\"` or `role=\"listbox\"` then\n * fails as a critical aria-required-children violation, while the same div with\n * no role passes straight through. Clearing it is what makes a ScrollArea legal\n * in a popup list. A spread because the literal `role={undefined}` is flagged by\n * the a11y lint rule, which cannot tell it from an invalid role.\n */\nconst NO_ROLE = { role: undefined } as const;\n\n/** Base UI makes the viewport a tab stop (0, or -1 with nothing to scroll); undefined takes that away. */\nconst NO_TAB_STOP = { tabIndex: undefined } as const;\n\nconst FADE_AXIS = {\n vertical: 'block',\n horizontal: 'inline',\n both: 'both',\n} as const;\n\n/**\n * Themed scroll container (Base UI): overflowing content scrolls INSIDE the component\n * with a slim overlay scrollbar instead of exposing a native browser scrollbar. House\n * rule: wide/tall content (tables, lists, code) always goes through this, never a bare\n * overflow-* utility.\n *\n * Cap the height with a plain class on the component itself, e.g.\n * `<ScrollArea className=\"max-h-88\">`. The viewport picks the cap up through\n * `max-h-inherit`, which matters because the viewport is the element that actually\n * scrolls: a cap that lands only on the root leaves tall content spilling out\n * underneath with no scrollbar, and that reads as a working height right up until the\n * content outgrows it.\n *\n * `fade` fades out each edge that is currently hiding content, rather than always\n * fading one: a permanent fade is a lie half the time, dimming the last row that fits\n * and promising more below when the reader is already at the end. It is cut into the\n * content by a mask (@edyn/theme/scroll-fade.css), so it needs no surface colour and\n * reads correctly over a tint, a gradient or a glow. A host that keeps something\n * unscrolled at the top, such as a sticky table header, exempts that band by setting\n * --scroll-fade-offset on the ScrollArea. The static faded-* utilities in\n * @edyn/theme/utilities.css are the other tool, for DECORATIVE edges that do not\n * track scroll position.\n *\n * The viewport publishes its size as --scroll-area-width/--scroll-area-height CSS vars\n * so children can size against the visible area.\n */\nexport const ScrollArea = ({\n className,\n children,\n orientation = 'vertical',\n type = 'hover',\n fade = false,\n fadeFrom = 'card',\n scrollbarClassName,\n viewportId,\n viewportRef,\n viewportClassName,\n scrollRestorationId,\n focusable = true,\n viewPortId,\n viewPortRef,\n viewPortClassName,\n scrollVerticalClassName,\n scrollHorizontalClassName,\n ...props\n}: IScrollAreaProps) => {\n const refInner = useRef<HTMLDivElement | null>(null);\n // The viewPort* spellings are the pre-rc.4 names, kept so existing callers\n // keep working; the viewport* ones match the rest of the ecosystem.\n const refsViewport = useMergedRefs(refInner, viewportRef ?? viewPortRef);\n\n useEffect(() => {\n const el = refInner.current;\n if (!el) {\n return;\n }\n const observer = new ResizeObserver(() => {\n el.style.setProperty('--scroll-area-width', `${el.clientWidth}px`);\n el.style.setProperty('--scroll-area-height', `${el.clientHeight}px`);\n });\n observer.observe(el);\n return () => {\n observer.disconnect();\n };\n }, []);\n\n return (\n <BaseScrollArea.Root\n data-slot=\"scroll-area\"\n // Everything inside clips at this box, so a focus ring drawn outside an\n // element at the edge would be cut off; see @edyn/theme/focus.css.\n data-focus=\"inset\"\n // The single-row grid is load-bearing rather than tidying. `h-full` on the viewport\n // cannot be trusted to size it: a percentage height only resolves against a definite\n // containing block, and a host that sizes this by flex inside a max-height column\n // (`min-h-0 flex-1`) is not definite, so the viewport fell back to auto and grew to\n // its content instead of scrolling. A grid item stretches to its track, and the track\n // is sized from the root's used height, which flex has already settled. `grid-rows-1`\n // is `repeat(1, minmax(0, 1fr))`: one track that may shrink below its content.\n className={cn('group/scroll-area relative grid min-w-0 grid-rows-1 overflow-hidden', className)}\n data-fade={fade ? FADE_AXIS[orientation] : undefined}\n {...NO_ROLE}\n {...props}\n >\n {(orientation === 'vertical' || orientation === 'both') && (\n <ScrollBar orientation=\"vertical\" visibility={type} className={cn(scrollbarClassName, scrollVerticalClassName)} />\n )}\n {(orientation === 'horizontal' || orientation === 'both') && (\n <ScrollBar orientation=\"horizontal\" visibility={type} className={cn(scrollbarClassName, scrollHorizontalClassName)} />\n )}\n <BaseScrollArea.Corner />\n <BaseScrollArea.Viewport\n data-slot=\"scroll-area-viewport\"\n id={viewportId ?? viewPortId}\n ref={refsViewport}\n data-scroll-restoration-id={scrollRestorationId}\n {...NO_ROLE}\n {...(focusable ? null : NO_TAB_STOP)}\n // One axis means one axis. Base UI leaves both axes scrollable, so a\n // vertical list could still be dragged sideways, and anything that put a\n // row in view (focus moving, scrollIntoView with inline: nearest) slid\n // the whole list across. The clamp is marked important because Base UI\n // sets the viewport's overflow itself.\n className={cn(\n 'max-h-inherit w-full rounded-[inherit]',\n orientation === 'vertical' && 'overflow-x-hidden!',\n orientation === 'horizontal' && 'overflow-y-hidden!',\n // The horizontal bar overlays the foot of the viewport, over whatever the last row is. While the content overflows\n // sideways the viewport keeps the bar's height clear below it, so the last row can always be scrolled up out from\n // under the bar (and a short one stands above it).\n orientation !== 'vertical' && 'data-has-overflow-x:pb-(--scroll-bar-reserve)',\n viewportClassName ?? viewPortClassName,\n )}\n >\n {/* Content is NOT optional: it carries the ResizeObserver that recomputes the\n thumb when the CONTENT resizes without the viewport resizing (e.g. a route\n swap to a shorter page). Without it the thumb keeps the previous page's\n geometry and a fully-visible page still shows a scrollbar.\n\n A vertical scroller also pins its content to the viewport's width, so a\n long label truncates instead of widening the list and inventing a\n horizontal scroll. Base UI sets min-width: fit-content inline, which is\n what makes that happen and why this is an inline style too. */}\n <BaseScrollArea.Content {...NO_ROLE} style={orientation === 'vertical' ? { minWidth: 0 } : undefined}>\n {children}\n </BaseScrollArea.Content>\n </BaseScrollArea.Viewport>\n </BaseScrollArea.Root>\n );\n};\n"],"mappings":";;;;;;AAyBA,IAAa,aAAa,EAAE,WAAW,cAAc,YAAY,aAAa,SAAS,GAAG,YAA6B;CACrH,OACE,oBAAC,WAAe,WAAhB;EACE,aAAU;EACG;EACb,WAAW,GACT,4GAGA,gBAAgB,cACd,uIACF,gBAAgB,gBACd,uIACF,eAAe,YAAY,wCAC3B,eAAe,WAAW,iEAC1B,SACF;EACA,GAAI;EAEJ,UAAA,oBAAC,WAAe,OAAhB,EAAsB,WAAU,2IAA4I,CAAA;CACpJ,CAAA;AAE9B;;;;;;;;;;;;;;;;AAwDA,IAAM,UAAU,EAAE,MAAM,KAAA,EAAU;;AAGlC,IAAM,cAAc,EAAE,UAAU,KAAA,EAAU;AAE1C,IAAM,YAAY;CAChB,UAAU;CACV,YAAY;CACZ,MAAM;AACR;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,IAAa,gBAAc,EACzB,WACA,UACA,cAAc,YACd,OAAO,SACP,OAAO,OACP,WAAW,QACX,oBACA,YACA,aACA,mBACA,qBACA,YAAY,MACZ,YACA,aACA,mBACA,yBACA,2BACA,GAAG,YACmB;CACtB,MAAM,WAAW,OAA8B,IAAI;CAGnD,MAAM,eAAe,cAAc,UAAU,eAAe,WAAW;CAEvE,gBAAgB;EACd,MAAM,KAAK,SAAS;EACpB,IAAI,CAAC,IACH;EAEF,MAAM,WAAW,IAAI,qBAAqB;GACxC,GAAG,MAAM,YAAY,uBAAuB,GAAG,GAAG,YAAY,GAAG;GACjE,GAAG,MAAM,YAAY,wBAAwB,GAAG,GAAG,aAAa,GAAG;EACrE,CAAC;EACD,SAAS,QAAQ,EAAE;EACnB,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG,CAAC,CAAC;CAEL,OACE,qBAAC,WAAe,MAAhB;EACE,aAAU;EAGV,cAAW;EAQX,WAAW,GAAG,uEAAuE,SAAS;EAC9F,aAAW,OAAO,UAAU,eAAe,KAAA;EAC3C,GAAI;EACJ,GAAI;EAfN,UAAA;IAiBI,gBAAgB,cAAc,gBAAgB,WAC9C,oBAAC,WAAD;IAAW,aAAY;IAAW,YAAY;IAAM,WAAW,GAAG,oBAAoB,uBAAuB;GAAI,CAAA;IAEjH,gBAAgB,gBAAgB,gBAAgB,WAChD,oBAAC,WAAD;IAAW,aAAY;IAAa,YAAY;IAAM,WAAW,GAAG,oBAAoB,yBAAyB;GAAI,CAAA;GAEvH,oBAAC,WAAe,QAAhB,CAAwB,CAAA;GACxB,oBAAC,WAAe,UAAhB;IACE,aAAU;IACV,IAAI,cAAc;IAClB,KAAK;IACL,8BAA4B;IAC5B,GAAI;IACJ,GAAK,YAAY,OAAO;IAMxB,WAAW,GACT,0CACA,gBAAgB,cAAc,sBAC9B,gBAAgB,gBAAgB,sBAIhC,gBAAgB,cAAc,iDAC9B,qBAAqB,iBACvB;IAWA,UAAA,oBAAC,WAAe,SAAhB;KAAwB,GAAI;KAAS,OAAO,gBAAgB,aAAa,EAAE,UAAU,EAAE,IAAI,KAAA;KACxF;IACqB,CAAA;GACD,CAAA;EACN;;AAEzB"}
1
+ {"version":3,"file":"scroll-area.js","names":[],"sources":["../../../../../../../ui/src/components/ui/scroll-area/scroll-area.tsx"],"sourcesContent":["import { ScrollArea as BaseScrollArea } from '@base-ui/react/scroll-area';\nimport { useMergedRefs } from '@edyn/ui/hooks/use-merged-refs';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { type ComponentProps, type RefObject, useEffect, useRef, useState } from 'react';\n\n/**\n * When the bar shows: 'hover' on area hover or while scrolling (default),\n * 'scroll' only while scrolling, 'always' permanent. In every mode the bar is\n * mounted only while that axis actually overflows, so 'always' means \"always\n * when there is something to scroll\", never a bar on a list that fits.\n */\nexport type TScrollbarVisibility = 'hover' | 'scroll' | 'always';\n\n/**\n * Surface the edge fades blended into, back when they were painted.\n *\n * @deprecated The fades are cut into the content by a mask, so they match any\n * surface without being told which one. Still accepted, and ignored.\n */\nexport type TScrollAreaFadeFrom = 'card' | 'background' | 'sidebar' | 'popover';\n\nexport interface IScrollBarProps extends ComponentProps<typeof BaseScrollArea.Scrollbar> {\n visibility?: TScrollbarVisibility;\n}\n\nexport const ScrollBar = ({ className, orientation = 'vertical', visibility = 'hover', ...props }: IScrollBarProps) => {\n return (\n <BaseScrollArea.Scrollbar\n data-slot=\"scroll-area-scrollbar\"\n orientation={orientation}\n className={cn(\n 'peer/scrollbar z-100 flex touch-none select-none motion-safe:transition-opacity motion-safe:duration-150',\n // Size, gap and start read --scroll-bar-size, --scroll-bar-gap and --scroll-bar-start (see scroll-bar.css), whose\n // defaults are the 8px bar flush with the box that it has always been.\n orientation === 'vertical' &&\n 'h-(--scroll-bar-length) w-(--scroll-bar-size) me-(--scroll-bar-gap) mt-(--scroll-bar-offset-top) border-l border-l-transparent p-px',\n orientation === 'horizontal' &&\n 'h-(--scroll-bar-size) ms-(--scroll-bar-gap) me-(--scroll-bar-gap) mb-(--scroll-bar-gap) flex-col border-t border-t-transparent p-px',\n visibility !== 'always' && 'opacity-0 data-scrolling:opacity-100',\n visibility === 'hover' && 'data-hovering:opacity-100 group-hover/scroll-area:opacity-100',\n className,\n )}\n {...props}\n >\n <BaseScrollArea.Thumb className=\"relative flex-1 rounded-full bg-muted-foreground/50 transition-colors hover:bg-muted-foreground/70 data-scrolling:bg-muted-foreground/70\" />\n </BaseScrollArea.Scrollbar>\n );\n};\n\nexport interface IScrollAreaProps extends ComponentProps<typeof BaseScrollArea.Root> {\n /** Which axes get a styled scrollbar; content decides what actually overflows. */\n orientation?: 'horizontal' | 'vertical' | 'both';\n /** Scrollbar reveal behavior (mirrors the Radix ScrollArea `type` prop). */\n type?: TScrollbarVisibility;\n /** Edge fades hinting at clipped content; each one shows only while its own edge hides something. */\n fade?: boolean;\n /**\n * @deprecated No longer read. The fades mask the content, so they sit correctly\n * on any surface; passing this does nothing and is safe to delete.\n */\n fadeFrom?: TScrollAreaFadeFrom;\n /** Places both bars, for a host that gives them a gutter of their own (a sidebar menu). */\n scrollbarClassName?: string;\n viewportId?: string;\n /** Access to the scrollable viewport (e.g. to reset scroll position on route changes). */\n viewportRef?: RefObject<HTMLDivElement | null>;\n viewportClassName?: string;\n /** Published on the viewport as data-scroll-restoration-id, for a router that restores scroll position. */\n scrollRestorationId?: string;\n /**\n * Whether the viewport may be a tab stop (default). It is one only while it overflows and nothing inside can take Tab\n * (axe's scrollable-region-focusable), with a 1px keyboard-only line. Off inside a menu, whose items are the tab stops.\n */\n focusable?: boolean;\n /** @deprecated Use `viewportId`. */\n viewPortId?: string;\n /** @deprecated Use `viewportRef`. */\n viewPortRef?: RefObject<HTMLDivElement | null>;\n /** @deprecated Use `viewportClassName`. */\n viewPortClassName?: string;\n /** Places the vertical bar only; `scrollbarClassName` covers both. */\n scrollVerticalClassName?: string;\n /** Places the horizontal bar only; `scrollbarClassName` covers both. */\n scrollHorizontalClassName?: string;\n}\n\n/**\n * Which axes fade, published for scroll-fade.css to key its mask off. The\n * stylesheet reaches this element's own viewport through a child combinator, so a\n * ScrollArea nested in another one cannot pick up its ancestor's edges.\n */\n/**\n * Base UI gives the root, the viewport and the content `role=\"presentation\"`. On\n * a div that changes nothing for a screen reader, but it is an EXPLICIT role, and\n * axe treats explicit presentation children as foreign to a parent that owns\n * required children. A ScrollArea inside `role=\"menu\"` or `role=\"listbox\"` then\n * fails as a critical aria-required-children violation, while the same div with\n * no role passes straight through. Clearing it is what makes a ScrollArea legal\n * in a popup list. A spread because the literal `role={undefined}` is flagged by\n * the a11y lint rule, which cannot tell it from an invalid role.\n */\nconst NO_ROLE = { role: undefined } as const;\n\n/** What takes Tab inside a region: if any is there, the region is not a stop of its own. */\nconst FOCUSABLE_INSIDE =\n 'a[href], button:not(:disabled), input:not([type=\"hidden\"]):not(:disabled), select:not(:disabled), textarea:not(:disabled), summary, [contenteditable], [tabindex]:not([tabindex=\"-1\"])';\n\n/** Base UI makes the viewport a tab stop (0, or -1 with nothing to scroll); undefined takes that away. */\nconst NO_TAB_STOP = { tabIndex: undefined } as const;\n\nconst FADE_AXIS = {\n vertical: 'block',\n horizontal: 'inline',\n both: 'both',\n} as const;\n\n/**\n * Themed scroll container (Base UI): overflowing content scrolls INSIDE the component\n * with a slim overlay scrollbar instead of exposing a native browser scrollbar. House\n * rule: wide/tall content (tables, lists, code) always goes through this, never a bare\n * overflow-* utility.\n *\n * Cap the height with a plain class on the component itself, e.g.\n * `<ScrollArea className=\"max-h-88\">`. The viewport picks the cap up through\n * `max-h-inherit`, which matters because the viewport is the element that actually\n * scrolls: a cap that lands only on the root leaves tall content spilling out\n * underneath with no scrollbar, and that reads as a working height right up until the\n * content outgrows it.\n *\n * `fade` fades out each edge that is currently hiding content, rather than always\n * fading one: a permanent fade is a lie half the time, dimming the last row that fits\n * and promising more below when the reader is already at the end. It is cut into the\n * content by a mask (@edyn/theme/scroll-fade.css), so it needs no surface colour and\n * reads correctly over a tint, a gradient or a glow. A host that keeps something\n * unscrolled at the top, such as a sticky table header, exempts that band by setting\n * --scroll-fade-offset on the ScrollArea. The static faded-* utilities in\n * @edyn/theme/utilities.css are the other tool, for DECORATIVE edges that do not\n * track scroll position.\n *\n * The viewport publishes its size as --scroll-area-width/--scroll-area-height CSS vars\n * so children can size against the visible area.\n */\nexport const ScrollArea = ({\n className,\n children,\n orientation = 'vertical',\n type = 'hover',\n fade = false,\n fadeFrom = 'card',\n scrollbarClassName,\n viewportId,\n viewportRef,\n viewportClassName,\n scrollRestorationId,\n focusable = true,\n viewPortId,\n viewPortRef,\n viewPortClassName,\n scrollVerticalClassName,\n scrollHorizontalClassName,\n ...props\n}: IScrollAreaProps) => {\n const refInner = useRef<HTMLDivElement | null>(null);\n // The viewPort* spellings are the pre-rc.4 names, kept so existing callers\n // keep working; the viewport* ones match the rest of the ecosystem.\n const refsViewport = useMergedRefs(refInner, viewportRef ?? viewPortRef);\n\n const [holdsFocusable, setHoldsFocusable] = useState(false);\n\n useEffect(() => {\n const el = refInner.current;\n if (!el || !focusable) {\n return;\n }\n const read = () => setHoldsFocusable(el.querySelector(FOCUSABLE_INSIDE) !== null);\n read();\n const observer = new MutationObserver(read);\n observer.observe(el, { childList: true, subtree: true, attributes: true, attributeFilter: ['tabindex', 'disabled', 'href'] });\n return () => {\n observer.disconnect();\n };\n }, [focusable]);\n\n useEffect(() => {\n const el = refInner.current;\n if (!el) {\n return;\n }\n const observer = new ResizeObserver(() => {\n el.style.setProperty('--scroll-area-width', `${el.clientWidth}px`);\n el.style.setProperty('--scroll-area-height', `${el.clientHeight}px`);\n });\n observer.observe(el);\n return () => {\n observer.disconnect();\n };\n }, []);\n\n return (\n <BaseScrollArea.Root\n data-slot=\"scroll-area\"\n // Everything inside clips at this box, so a focus ring drawn outside an\n // element at the edge would be cut off; see @edyn/theme/focus.css.\n data-focus=\"inset\"\n // The single-row grid is load-bearing rather than tidying. `h-full` on the viewport\n // cannot be trusted to size it: a percentage height only resolves against a definite\n // containing block, and a host that sizes this by flex inside a max-height column\n // (`min-h-0 flex-1`) is not definite, so the viewport fell back to auto and grew to\n // its content instead of scrolling. A grid item stretches to its track, and the track\n // is sized from the root's used height, which flex has already settled. `grid-rows-1`\n // is `repeat(1, minmax(0, 1fr))`: one track that may shrink below its content.\n // While the content overflows sideways the root keeps the horizontal bar's height clear under the viewport, so the bar\n // stands below the last row. It is the root's padding, not the viewport's: padding inside the scroller made it scroll.\n className={cn(\n 'group/scroll-area relative grid min-w-0 grid-rows-1 overflow-hidden',\n orientation !== 'vertical' && 'data-has-overflow-x:pb-(--scroll-bar-reserve)',\n className,\n )}\n data-fade={fade ? FADE_AXIS[orientation] : undefined}\n {...NO_ROLE}\n {...props}\n >\n {(orientation === 'vertical' || orientation === 'both') && (\n <ScrollBar orientation=\"vertical\" visibility={type} className={cn(scrollbarClassName, scrollVerticalClassName)} />\n )}\n {(orientation === 'horizontal' || orientation === 'both') && (\n <ScrollBar orientation=\"horizontal\" visibility={type} className={cn(scrollbarClassName, scrollHorizontalClassName)} />\n )}\n <BaseScrollArea.Corner />\n <BaseScrollArea.Viewport\n data-slot=\"scroll-area-viewport\"\n id={viewportId ?? viewPortId}\n ref={refsViewport}\n data-scroll-restoration-id={scrollRestorationId}\n {...NO_ROLE}\n {...(focusable && !holdsFocusable ? null : NO_TAB_STOP)}\n // One axis means one axis. Base UI leaves both axes scrollable, so a\n // vertical list could still be dragged sideways, and anything that put a\n // row in view (focus moving, scrollIntoView with inline: nearest) slid\n // the whole list across. The clamp is marked important because Base UI\n // sets the viewport's overflow itself.\n className={cn(\n 'max-h-inherit w-full rounded-[inherit]',\n orientation === 'vertical' && 'overflow-x-hidden!',\n orientation === 'horizontal' && 'overflow-y-hidden!',\n viewportClassName ?? viewPortClassName,\n )}\n >\n {/* Content is NOT optional: it carries the ResizeObserver that recomputes the\n thumb when the CONTENT resizes without the viewport resizing (e.g. a route\n swap to a shorter page). Without it the thumb keeps the previous page's\n geometry and a fully-visible page still shows a scrollbar.\n\n A vertical scroller also pins its content to the viewport's width, so a\n long label truncates instead of widening the list and inventing a\n horizontal scroll. Base UI sets min-width: fit-content inline, which is\n what makes that happen and why this is an inline style too. */}\n <BaseScrollArea.Content {...NO_ROLE} style={orientation === 'vertical' ? { minWidth: 0 } : undefined}>\n {children}\n </BaseScrollArea.Content>\n </BaseScrollArea.Viewport>\n </BaseScrollArea.Root>\n );\n};\n"],"mappings":";;;;;;AAyBA,IAAa,aAAa,EAAE,WAAW,cAAc,YAAY,aAAa,SAAS,GAAG,YAA6B;CACrH,OACE,oBAAC,WAAe,WAAhB;EACE,aAAU;EACG;EACb,WAAW,GACT,4GAGA,gBAAgB,cACd,uIACF,gBAAgB,gBACd,uIACF,eAAe,YAAY,wCAC3B,eAAe,WAAW,iEAC1B,SACF;EACA,GAAI;EAEJ,UAAA,oBAAC,WAAe,OAAhB,EAAsB,WAAU,2IAA4I,CAAA;CACpJ,CAAA;AAE9B;;;;;;;;;;;;;;;;AAsDA,IAAM,UAAU,EAAE,MAAM,KAAA,EAAU;;AAGlC,IAAM,mBACJ;;AAGF,IAAM,cAAc,EAAE,UAAU,KAAA,EAAU;AAE1C,IAAM,YAAY;CAChB,UAAU;CACV,YAAY;CACZ,MAAM;AACR;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,IAAa,gBAAc,EACzB,WACA,UACA,cAAc,YACd,OAAO,SACP,OAAO,OACP,WAAW,QACX,oBACA,YACA,aACA,mBACA,qBACA,YAAY,MACZ,YACA,aACA,mBACA,yBACA,2BACA,GAAG,YACmB;CACtB,MAAM,WAAW,OAA8B,IAAI;CAGnD,MAAM,eAAe,cAAc,UAAU,eAAe,WAAW;CAEvE,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,KAAK;CAE1D,gBAAgB;EACd,MAAM,KAAK,SAAS;EACpB,IAAI,CAAC,MAAM,CAAC,WACV;EAEF,MAAM,aAAa,kBAAkB,GAAG,cAAc,gBAAgB,MAAM,IAAI;EAChF,KAAK;EACL,MAAM,WAAW,IAAI,iBAAiB,IAAI;EAC1C,SAAS,QAAQ,IAAI;GAAE,WAAW;GAAM,SAAS;GAAM,YAAY;GAAM,iBAAiB;IAAC;IAAY;IAAY;GAAM;EAAE,CAAC;EAC5H,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG,CAAC,SAAS,CAAC;CAEd,gBAAgB;EACd,MAAM,KAAK,SAAS;EACpB,IAAI,CAAC,IACH;EAEF,MAAM,WAAW,IAAI,qBAAqB;GACxC,GAAG,MAAM,YAAY,uBAAuB,GAAG,GAAG,YAAY,GAAG;GACjE,GAAG,MAAM,YAAY,wBAAwB,GAAG,GAAG,aAAa,GAAG;EACrE,CAAC;EACD,SAAS,QAAQ,EAAE;EACnB,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG,CAAC,CAAC;CAEL,OACE,qBAAC,WAAe,MAAhB;EACE,aAAU;EAGV,cAAW;EAUX,WAAW,GACT,uEACA,gBAAgB,cAAc,iDAC9B,SACF;EACA,aAAW,OAAO,UAAU,eAAe,KAAA;EAC3C,GAAI;EACJ,GAAI;EArBN,UAAA;IAuBI,gBAAgB,cAAc,gBAAgB,WAC9C,oBAAC,WAAD;IAAW,aAAY;IAAW,YAAY;IAAM,WAAW,GAAG,oBAAoB,uBAAuB;GAAI,CAAA;IAEjH,gBAAgB,gBAAgB,gBAAgB,WAChD,oBAAC,WAAD;IAAW,aAAY;IAAa,YAAY;IAAM,WAAW,GAAG,oBAAoB,yBAAyB;GAAI,CAAA;GAEvH,oBAAC,WAAe,QAAhB,CAAwB,CAAA;GACxB,oBAAC,WAAe,UAAhB;IACE,aAAU;IACV,IAAI,cAAc;IAClB,KAAK;IACL,8BAA4B;IAC5B,GAAI;IACJ,GAAK,aAAa,CAAC,iBAAiB,OAAO;IAM3C,WAAW,GACT,0CACA,gBAAgB,cAAc,sBAC9B,gBAAgB,gBAAgB,sBAChC,qBAAqB,iBACvB;IAWA,UAAA,oBAAC,WAAe,SAAhB;KAAwB,GAAI;KAAS,OAAO,gBAAgB,aAAa,EAAE,UAAU,EAAE,IAAI,KAAA;KACxF;IACqB,CAAA;GACD,CAAA;EACN;;AAEzB"}
@@ -1,7 +1,7 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { useExposedFocusGuards } from "../../../lib/focus-guards.js";
3
- import { ScrollArea } from "../scroll-area/scroll-area.js";
4
- import { POPUP_FRAME_CLASS, POPUP_GROUP_LABEL_CLASS, POPUP_ITEM_INDICATOR_CLASS, POPUP_LIST_HEIGHT_CLASS, POPUP_LIST_WIDTH_CLASS, popupItemClass } from "../../../lib/popup-list.js";
3
+ import { POPUP_FRAME_CLASS, POPUP_GROUP_LABEL_CLASS, POPUP_ITEM_INDICATOR_CLASS, POPUP_LAYER_CLASS, POPUP_LIST_WIDTH_CLASS, popupItemClass } from "../../../lib/popup-list.js";
4
+ import { PopupListScroll } from "../scroll-area/popup-list-scroll.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { IconCheck, IconChevronDown } from "@tabler/icons-react";
7
7
  import { Select } from "@base-ui/react/select";
@@ -15,7 +15,7 @@ var Select$1 = ({ ...props }) => {
15
15
  var SelectTrigger = ({ className, size = "default", children, ...props }) => {
16
16
  return /* @__PURE__ */ jsxs(Select.Trigger, {
17
17
  "data-slot": "select-trigger",
18
- className: cn("flex w-full cursor-pointer items-center justify-between gap-2 rounded-lg border border-input bg-transparent text-sm text-foreground transition-colors outline-none", "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50", "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50", "aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20", "data-popup-open:border-ring data-popup-open:ring-3 data-popup-open:ring-ring/50", "dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", size === "sm" ? "h-7 px-2.5 text-[0.8rem]" : "h-8 px-2.5", className),
18
+ className: cn("flex w-full cursor-pointer items-center justify-between gap-2 rounded-lg border border-control bg-transparent text-sm text-foreground transition-colors outline-none", "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50", "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50", "aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20", "data-popup-open:border-ring data-popup-open:ring-3 data-popup-open:ring-ring/50", "dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", size === "sm" ? "h-7 px-2.5 text-xs" : "h-8 px-2.5", className),
19
19
  ...props,
20
20
  children: [children, /* @__PURE__ */ jsx(Select.Icon, {
21
21
  "data-slot": "select-icon",
@@ -40,21 +40,16 @@ var SelectContent = ({ className, children, portalContainer, ...props }) => {
40
40
  sideOffset: 4,
41
41
  align: "start",
42
42
  alignItemWithTrigger: false,
43
+ className: POPUP_LAYER_CLASS,
43
44
  children: /* @__PURE__ */ jsx(Select.Popup, {
44
45
  "data-slot": "select-content",
45
46
  className: cn("z-50 flex max-h-(--available-height) flex-col overflow-hidden", POPUP_FRAME_CLASS, POPUP_LIST_WIDTH_CLASS, "origin-[var(--transform-origin)]", "transition-[transform,scale,opacity] motion-reduce:animate-none motion-reduce:transition-none data-open:scale-100 data-open:opacity-100 data-closed:scale-95 data-closed:opacity-0 data-open:animate-in data-closed:animate-out data-open:fade-in-0 data-closed:fade-out-0", className),
46
47
  ...props,
47
- children: /* @__PURE__ */ jsx(ScrollArea, {
48
- type: "always",
49
- fade: true,
50
- className: POPUP_LIST_HEIGHT_CLASS,
51
- viewportClassName: "scroll-py-1",
52
- children: /* @__PURE__ */ jsx(Select.List, {
53
- "data-slot": "select-list",
54
- className: "p-1",
55
- children
56
- })
57
- })
48
+ children: /* @__PURE__ */ jsx(PopupListScroll, { children: /* @__PURE__ */ jsx(Select.List, {
49
+ "data-slot": "select-list",
50
+ className: "px-1",
51
+ children
52
+ }) })
58
53
  })
59
54
  })
60
55
  });
@@ -1 +1 @@
1
- {"version":3,"file":"select.js","names":[],"sources":["../../../../../../../ui/src/components/ui/select/select.tsx"],"sourcesContent":["import { Select as SelectPrimitive } from '@base-ui/react/select';\nimport { useExposedFocusGuards } from '@edyn/ui/lib/focus-guards';\nimport {\n POPUP_FRAME_CLASS,\n POPUP_GROUP_LABEL_CLASS,\n POPUP_ITEM_INDICATOR_CLASS,\n POPUP_LIST_HEIGHT_CLASS,\n POPUP_LIST_WIDTH_CLASS,\n popupItemClass,\n} from '@edyn/ui/lib/popup-list';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconCheck, IconChevronDown } from '@tabler/icons-react';\nimport type * as React from 'react';\nimport { ScrollArea } from '../scroll-area';\n\nexport const Select = <TValue,>({ ...props }: SelectPrimitive.Root.Props<TValue>) => {\n return <SelectPrimitive.Root data-slot=\"select\" {...props} />;\n};\n\nexport type TSelectTriggerSize = 'sm' | 'default';\n\nexport interface ISelectTriggerProps extends SelectPrimitive.Trigger.Props {\n size?: TSelectTriggerSize;\n}\n\nexport const SelectTrigger = ({ className, size = 'default', children, ...props }: ISelectTriggerProps) => {\n return (\n <SelectPrimitive.Trigger\n data-slot=\"select-trigger\"\n className={cn(\n 'flex w-full cursor-pointer items-center justify-between gap-2 rounded-lg border border-input bg-transparent text-sm text-foreground transition-colors outline-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50',\n 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',\n 'aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20',\n 'data-popup-open:border-ring data-popup-open:ring-3 data-popup-open:ring-ring/50',\n 'dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',\n size === 'sm' ? 'h-7 px-2.5 text-[0.8rem]' : 'h-8 px-2.5',\n className,\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon data-slot=\"select-icon\" className=\"shrink-0 text-muted-foreground\">\n <IconChevronDown className=\"size-4\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n );\n};\n\nexport const SelectValue = ({ className, ...props }: SelectPrimitive.Value.Props) => {\n return <SelectPrimitive.Value data-slot=\"select-value\" className={cn('truncate data-placeholder:text-muted-foreground', className)} {...props} />;\n};\n\nexport interface ISelectContentProps extends SelectPrimitive.Popup.Props {\n portalContainer?: SelectPrimitive.Portal.Props['container'];\n}\n\nexport const SelectContent = ({ className, children, portalContainer, ...props }: ISelectContentProps) => {\n useExposedFocusGuards();\n return (\n <SelectPrimitive.Portal container={portalContainer}>\n {/* alignItemWithTrigger=false: drop below the trigger (shadcn style), not Base UI's macOS-style overlay */}\n <SelectPrimitive.Positioner data-slot=\"select-positioner\" sideOffset={4} align=\"start\" alignItemWithTrigger={false}>\n <SelectPrimitive.Popup\n data-slot=\"select-content\"\n className={cn(\n 'z-50 flex max-h-(--available-height) flex-col overflow-hidden',\n POPUP_FRAME_CLASS,\n POPUP_LIST_WIDTH_CLASS,\n 'origin-[var(--transform-origin)]',\n 'transition-[transform,scale,opacity] motion-reduce:animate-none motion-reduce:transition-none data-open:scale-100 data-open:opacity-100 data-closed:scale-95 data-closed:opacity-0 data-open:animate-in data-closed:animate-out data-open:fade-in-0 data-closed:fade-out-0',\n className,\n )}\n {...props}\n >\n {/* A long option list has to scroll inside the popup: the popup clips\n (overflow-hidden) and carries no height of its own, so the options\n past the fold were simply unreachable. POPUP_LIST_HEIGHT_CLASS caps\n it at eight rows, or at the whole rows the room the positioner\n measured allows, so the foot of the list is never a half row. */}\n {/* Select.List is what makes the wrappers legal: with a list present Base\n UI moves `role=\"listbox\"` off the popup and onto it, so the options\n stay direct children of the role and the ScrollArea sits outside it.\n The list holds the padding, so it scrolls with the rows. */}\n <ScrollArea type=\"always\" fade className={POPUP_LIST_HEIGHT_CLASS} viewportClassName=\"scroll-py-1\">\n <SelectPrimitive.List data-slot=\"select-list\" className=\"p-1\">\n {children}\n </SelectPrimitive.List>\n </ScrollArea>\n </SelectPrimitive.Popup>\n </SelectPrimitive.Positioner>\n </SelectPrimitive.Portal>\n );\n};\n\nexport const SelectGroup = ({ className, ...props }: SelectPrimitive.Group.Props) => {\n // No gap between the rows of a group: a gap would put them 34px apart in a group and 32px apart outside one, and the list's\n // whole-row height is counted in 32s.\n return <SelectPrimitive.Group data-slot=\"select-group\" className={className} {...props} />;\n};\n\nexport const SelectLabel = ({ className, ...props }: SelectPrimitive.GroupLabel.Props) => {\n return <SelectPrimitive.GroupLabel data-slot=\"select-label\" className={cn(POPUP_GROUP_LABEL_CLASS, className)} {...props} />;\n};\n\nexport const SelectItem = ({ className, children, ...props }: SelectPrimitive.Item.Props) => {\n return (\n <SelectPrimitive.Item data-slot=\"select-item\" className={cn(popupItemClass('base-ui', true), className)} {...props}>\n <SelectPrimitive.ItemText data-slot=\"select-item-text\">{children}</SelectPrimitive.ItemText>\n {/* After the text, not before it: the check marks the end of the item in\n every list in the system, so the labels all start on one line. */}\n <SelectPrimitive.ItemIndicator data-slot=\"select-item-indicator\" className={POPUP_ITEM_INDICATOR_CLASS}>\n <IconCheck className=\"size-3.5\" />\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n );\n};\n\nexport const SelectSeparator = ({ className, ...props }: React.ComponentProps<'div'>) => {\n return <div data-slot=\"select-separator\" className={cn('-mx-1 my-1 h-px bg-border', className)} aria-hidden=\"true\" {...props} />;\n};\n"],"mappings":";;;;;;;;AAeA,IAAa,YAAmB,EAAE,GAAG,YAAgD;CACnF,OAAO,oBAAC,OAAgB,MAAjB;EAAsB,aAAU;EAAS,GAAI;CAAQ,CAAA;AAC9D;AAQA,IAAa,iBAAiB,EAAE,WAAW,OAAO,WAAW,UAAU,GAAG,YAAiC;CACzG,OACE,qBAAC,OAAgB,SAAjB;EACE,aAAU;EACV,WAAW,GACT,sKACA,6EACA,gFACA,wFACA,mFACA,4HACA,SAAS,OAAO,6BAA6B,cAC7C,SACF;EACA,GAAI;EAZN,UAAA,CAcG,UACD,oBAAC,OAAgB,MAAjB;GAAsB,aAAU;GAAc,WAAU;GACtD,UAAA,oBAAC,iBAAD,EAAiB,WAAU,SAAU,CAAA;EACjB,CAAA,CACC;;AAE7B;AAEA,IAAa,eAAe,EAAE,WAAW,GAAG,YAAyC;CACnF,OAAO,oBAAC,OAAgB,OAAjB;EAAuB,aAAU;EAAe,WAAW,GAAG,mDAAmD,SAAS;EAAG,GAAI;CAAQ,CAAA;AAClJ;AAMA,IAAa,iBAAiB,EAAE,WAAW,UAAU,iBAAiB,GAAG,YAAiC;CACxG,sBAAsB;CACtB,OACE,oBAAC,OAAgB,QAAjB;EAAwB,WAAW;EAEjC,UAAA,oBAAC,OAAgB,YAAjB;GAA4B,aAAU;GAAoB,YAAY;GAAG,OAAM;GAAQ,sBAAsB;GAC3G,UAAA,oBAAC,OAAgB,OAAjB;IACE,aAAU;IACV,WAAW,GACT,iEACA,mBACA,wBACA,oCACA,8QACA,SACF;IACA,GAAI;IAWJ,UAAA,oBAAC,YAAD;KAAY,MAAK;KAAS,MAAA;KAAK,WAAW;KAAyB,mBAAkB;KACnF,UAAA,oBAAC,OAAgB,MAAjB;MAAsB,aAAU;MAAc,WAAU;MACrD;KACmB,CAAA;IACZ,CAAA;GACS,CAAA;EACG,CAAA;CACN,CAAA;AAE5B;AAEA,IAAa,eAAe,EAAE,WAAW,GAAG,YAAyC;CAGnF,OAAO,oBAAC,OAAgB,OAAjB;EAAuB,aAAU;EAA0B;EAAW,GAAI;CAAQ,CAAA;AAC3F;AAEA,IAAa,eAAe,EAAE,WAAW,GAAG,YAA8C;CACxF,OAAO,oBAAC,OAAgB,YAAjB;EAA4B,aAAU;EAAe,WAAW,GAAG,yBAAyB,SAAS;EAAG,GAAI;CAAQ,CAAA;AAC7H;AAEA,IAAa,cAAc,EAAE,WAAW,UAAU,GAAG,YAAwC;CAC3F,OACE,qBAAC,OAAgB,MAAjB;EAAsB,aAAU;EAAc,WAAW,GAAG,eAAe,WAAW,IAAI,GAAG,SAAS;EAAG,GAAI;EAA7G,UAAA,CACE,oBAAC,OAAgB,UAAjB;GAA0B,aAAU;GAAoB;EAAmC,CAAA,GAG3F,oBAAC,OAAgB,eAAjB;GAA+B,aAAU;GAAwB,WAAW;GAC1E,UAAA,oBAAC,WAAD,EAAW,WAAU,WAAY,CAAA;EACJ,CAAA,CACX;;AAE1B;AAEA,IAAa,mBAAmB,EAAE,WAAW,GAAG,YAAyC;CACvF,OAAO,oBAAC,OAAD;EAAK,aAAU;EAAmB,WAAW,GAAG,6BAA6B,SAAS;EAAG,eAAY;EAAO,GAAI;CAAQ,CAAA;AACjI"}
1
+ {"version":3,"file":"select.js","names":[],"sources":["../../../../../../../ui/src/components/ui/select/select.tsx"],"sourcesContent":["import { Select as SelectPrimitive } from '@base-ui/react/select';\nimport { useExposedFocusGuards } from '@edyn/ui/lib/focus-guards';\nimport {\n POPUP_FRAME_CLASS,\n POPUP_GROUP_LABEL_CLASS,\n POPUP_ITEM_INDICATOR_CLASS,\n POPUP_LAYER_CLASS,\n POPUP_LIST_WIDTH_CLASS,\n popupItemClass,\n} from '@edyn/ui/lib/popup-list';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconCheck, IconChevronDown } from '@tabler/icons-react';\nimport type * as React from 'react';\nimport { PopupListScroll } from '../scroll-area';\n\nexport const Select = <TValue,>({ ...props }: SelectPrimitive.Root.Props<TValue>) => {\n return <SelectPrimitive.Root data-slot=\"select\" {...props} />;\n};\n\nexport type TSelectTriggerSize = 'sm' | 'default';\n\nexport interface ISelectTriggerProps extends SelectPrimitive.Trigger.Props {\n size?: TSelectTriggerSize;\n}\n\nexport const SelectTrigger = ({ className, size = 'default', children, ...props }: ISelectTriggerProps) => {\n return (\n <SelectPrimitive.Trigger\n data-slot=\"select-trigger\"\n className={cn(\n 'flex w-full cursor-pointer items-center justify-between gap-2 rounded-lg border border-control bg-transparent text-sm text-foreground transition-colors outline-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50',\n 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',\n 'aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20',\n 'data-popup-open:border-ring data-popup-open:ring-3 data-popup-open:ring-ring/50',\n 'dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',\n size === 'sm' ? 'h-7 px-2.5 text-xs' : 'h-8 px-2.5',\n className,\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon data-slot=\"select-icon\" className=\"shrink-0 text-muted-foreground\">\n <IconChevronDown className=\"size-4\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n );\n};\n\nexport const SelectValue = ({ className, ...props }: SelectPrimitive.Value.Props) => {\n return <SelectPrimitive.Value data-slot=\"select-value\" className={cn('truncate data-placeholder:text-muted-foreground', className)} {...props} />;\n};\n\nexport interface ISelectContentProps extends SelectPrimitive.Popup.Props {\n portalContainer?: SelectPrimitive.Portal.Props['container'];\n}\n\nexport const SelectContent = ({ className, children, portalContainer, ...props }: ISelectContentProps) => {\n useExposedFocusGuards();\n return (\n <SelectPrimitive.Portal container={portalContainer}>\n {/* alignItemWithTrigger=false: drop below the trigger (shadcn style), not Base UI's macOS-style overlay */}\n <SelectPrimitive.Positioner\n data-slot=\"select-positioner\"\n sideOffset={4}\n align=\"start\"\n alignItemWithTrigger={false}\n className={POPUP_LAYER_CLASS}\n >\n <SelectPrimitive.Popup\n data-slot=\"select-content\"\n className={cn(\n 'z-50 flex max-h-(--available-height) flex-col overflow-hidden',\n POPUP_FRAME_CLASS,\n POPUP_LIST_WIDTH_CLASS,\n 'origin-[var(--transform-origin)]',\n 'transition-[transform,scale,opacity] motion-reduce:animate-none motion-reduce:transition-none data-open:scale-100 data-open:opacity-100 data-closed:scale-95 data-closed:opacity-0 data-open:animate-in data-closed:animate-out data-open:fade-in-0 data-closed:fade-out-0',\n className,\n )}\n {...props}\n >\n {/* A long option list has to scroll inside the popup: the popup clips\n (overflow-hidden) and carries no height of its own, so the options\n past the fold were simply unreachable. POPUP_LIST_HEIGHT_CLASS caps\n it at eight rows, or at the whole rows the room the positioner\n measured allows, so the foot of the list is never a half row. */}\n {/* Select.List is what makes the wrappers legal: with a list present Base\n UI moves `role=\"listbox\"` off the popup and onto it, so the options\n stay direct children of the role and the ScrollArea sits outside it.\n The list keeps only the sideways padding: the air above and\n below the rows is POPUP_LIST_HEIGHT_CLASS's margin, outside what scrolls. */}\n <PopupListScroll>\n <SelectPrimitive.List data-slot=\"select-list\" className=\"px-1\">\n {children}\n </SelectPrimitive.List>\n </PopupListScroll>\n </SelectPrimitive.Popup>\n </SelectPrimitive.Positioner>\n </SelectPrimitive.Portal>\n );\n};\n\nexport const SelectGroup = ({ className, ...props }: SelectPrimitive.Group.Props) => {\n // No gap between the rows of a group: a gap would put them 34px apart in a group and 32px apart outside one, and the list's\n // whole-row height is counted in 32s.\n return <SelectPrimitive.Group data-slot=\"select-group\" className={className} {...props} />;\n};\n\nexport const SelectLabel = ({ className, ...props }: SelectPrimitive.GroupLabel.Props) => {\n return <SelectPrimitive.GroupLabel data-slot=\"select-label\" className={cn(POPUP_GROUP_LABEL_CLASS, className)} {...props} />;\n};\n\nexport const SelectItem = ({ className, children, ...props }: SelectPrimitive.Item.Props) => {\n return (\n <SelectPrimitive.Item data-slot=\"select-item\" className={cn(popupItemClass('base-ui', true), className)} {...props}>\n <SelectPrimitive.ItemText data-slot=\"select-item-text\">{children}</SelectPrimitive.ItemText>\n {/* After the text, not before it: the check marks the end of the item in\n every list in the system, so the labels all start on one line. */}\n <SelectPrimitive.ItemIndicator data-slot=\"select-item-indicator\" className={POPUP_ITEM_INDICATOR_CLASS}>\n <IconCheck className=\"size-3.5\" />\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n );\n};\n\nexport const SelectSeparator = ({ className, ...props }: React.ComponentProps<'div'>) => {\n return <div data-slot=\"select-separator\" className={cn('-mx-1 my-1 h-px bg-border', className)} aria-hidden=\"true\" {...props} />;\n};\n"],"mappings":";;;;;;;;AAeA,IAAa,YAAmB,EAAE,GAAG,YAAgD;CACnF,OAAO,oBAAC,OAAgB,MAAjB;EAAsB,aAAU;EAAS,GAAI;CAAQ,CAAA;AAC9D;AAQA,IAAa,iBAAiB,EAAE,WAAW,OAAO,WAAW,UAAU,GAAG,YAAiC;CACzG,OACE,qBAAC,OAAgB,SAAjB;EACE,aAAU;EACV,WAAW,GACT,wKACA,6EACA,gFACA,wFACA,mFACA,4HACA,SAAS,OAAO,uBAAuB,cACvC,SACF;EACA,GAAI;EAZN,UAAA,CAcG,UACD,oBAAC,OAAgB,MAAjB;GAAsB,aAAU;GAAc,WAAU;GACtD,UAAA,oBAAC,iBAAD,EAAiB,WAAU,SAAU,CAAA;EACjB,CAAA,CACC;;AAE7B;AAEA,IAAa,eAAe,EAAE,WAAW,GAAG,YAAyC;CACnF,OAAO,oBAAC,OAAgB,OAAjB;EAAuB,aAAU;EAAe,WAAW,GAAG,mDAAmD,SAAS;EAAG,GAAI;CAAQ,CAAA;AAClJ;AAMA,IAAa,iBAAiB,EAAE,WAAW,UAAU,iBAAiB,GAAG,YAAiC;CACxG,sBAAsB;CACtB,OACE,oBAAC,OAAgB,QAAjB;EAAwB,WAAW;EAEjC,UAAA,oBAAC,OAAgB,YAAjB;GACE,aAAU;GACV,YAAY;GACZ,OAAM;GACN,sBAAsB;GACtB,WAAW;GAEX,UAAA,oBAAC,OAAgB,OAAjB;IACE,aAAU;IACV,WAAW,GACT,iEACA,mBACA,wBACA,oCACA,8QACA,SACF;IACA,GAAI;IAYJ,UAAA,oBAAC,iBAAD,EAAA,UACE,oBAAC,OAAgB,MAAjB;KAAsB,aAAU;KAAc,WAAU;KACrD;IACmB,CAAA,EACP,CAAA;GACI,CAAA;EACG,CAAA;CACN,CAAA;AAE5B;AAEA,IAAa,eAAe,EAAE,WAAW,GAAG,YAAyC;CAGnF,OAAO,oBAAC,OAAgB,OAAjB;EAAuB,aAAU;EAA0B;EAAW,GAAI;CAAQ,CAAA;AAC3F;AAEA,IAAa,eAAe,EAAE,WAAW,GAAG,YAA8C;CACxF,OAAO,oBAAC,OAAgB,YAAjB;EAA4B,aAAU;EAAe,WAAW,GAAG,yBAAyB,SAAS;EAAG,GAAI;CAAQ,CAAA;AAC7H;AAEA,IAAa,cAAc,EAAE,WAAW,UAAU,GAAG,YAAwC;CAC3F,OACE,qBAAC,OAAgB,MAAjB;EAAsB,aAAU;EAAc,WAAW,GAAG,eAAe,WAAW,IAAI,GAAG,SAAS;EAAG,GAAI;EAA7G,UAAA,CACE,oBAAC,OAAgB,UAAjB;GAA0B,aAAU;GAAoB;EAAmC,CAAA,GAG3F,oBAAC,OAAgB,eAAjB;GAA+B,aAAU;GAAwB,WAAW;GAC1E,UAAA,oBAAC,WAAD,EAAW,WAAU,WAAY,CAAA;EACJ,CAAA,CACX;;AAE1B;AAEA,IAAa,mBAAmB,EAAE,WAAW,GAAG,YAAyC;CACvF,OAAO,oBAAC,OAAD;EAAK,aAAU;EAAmB,WAAW,GAAG,6BAA6B,SAAS;EAAG,eAAY;EAAO,GAAI;CAAQ,CAAA;AACjI"}
@@ -34,7 +34,7 @@ var TabsTrigger = ({ value, disabled, className, children, ...props }) => /* @__
34
34
  ...props,
35
35
  value,
36
36
  disabled,
37
- className: cn("relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\"size-\"])]:size-4", "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent", "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground", "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100", className),
37
+ className: cn("relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\"size-\"])]:size-4", "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent", "data-active:bg-background data-active:text-foreground dark:data-active:border-control dark:data-active:bg-input/30 dark:data-active:text-foreground", "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100", className),
38
38
  children
39
39
  });
40
40
  var TabsContent = ({ value, keepMounted = false, className, children, ...props }) => /* @__PURE__ */ jsx(Tabs.Panel, {
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.js","names":[],"sources":["../../../../../../../ui/src/components/ui/tabs/tabs.tsx"],"sourcesContent":["import { Tabs as BaseTabs } from '@base-ui/react/tabs';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport type * as React from 'react';\n\nexport interface ITabsProps extends Omit<BaseTabs.Root.Props, 'value' | 'defaultValue' | 'onValueChange' | 'className' | 'orientation' | 'children'> {\n /** Controlled selected tab. Provide with `onValueChange`. */\n value?: string;\n /** Uncontrolled initial tab. Use this when the component should own its state. */\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n className?: string;\n orientation?: 'horizontal' | 'vertical';\n children: React.ReactNode;\n}\n\nexport const Tabs = ({ value, defaultValue, onValueChange, className, orientation = 'horizontal', children, ...props }: ITabsProps) => (\n <BaseTabs.Root\n data-slot=\"tabs\"\n {...props}\n data-orientation={orientation}\n value={value}\n defaultValue={defaultValue}\n orientation={orientation}\n onValueChange={(next) => {\n onValueChange?.(String(next));\n }}\n className={cn('group/tabs flex w-full gap-2 data-[orientation=horizontal]:flex-col', className)}\n >\n {children}\n </BaseTabs.Root>\n);\n\nexport const tabsListVariants = cva(\n 'group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-[orientation=horizontal]/tabs:h-8 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col data-[variant=line]:rounded-none',\n {\n variants: {\n variant: {\n default: 'bg-muted',\n line: 'gap-1 bg-transparent',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n);\n\nexport interface ITabsListProps extends VariantProps<typeof tabsListVariants>, Omit<BaseTabs.List.Props, 'className' | 'children'> {\n className?: string;\n children: React.ReactNode;\n}\n\nexport const TabsList = ({ className, variant = 'default', children, ...props }: ITabsListProps) => (\n <BaseTabs.List data-slot=\"tabs-list\" {...props} data-variant={variant} className={cn(tabsListVariants({ variant }), className)}>\n {children}\n </BaseTabs.List>\n);\n\nexport interface ITabsTriggerProps extends Omit<BaseTabs.Tab.Props, 'value' | 'disabled' | 'className' | 'children'> {\n value: string;\n disabled?: boolean;\n className?: string;\n children: React.ReactNode;\n}\n\nexport const TabsTrigger = ({ value, disabled, className, children, ...props }: ITabsTriggerProps) => (\n <BaseTabs.Tab\n {...props}\n value={value}\n disabled={disabled}\n className={cn(\n 'relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\"size-\"])]:size-4',\n 'group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent',\n 'data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground',\n 'after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100',\n className,\n )}\n >\n {children}\n </BaseTabs.Tab>\n);\n\nexport interface ITabsContentProps extends Omit<BaseTabs.Panel.Props, 'value' | 'keepMounted' | 'className' | 'children'> {\n value: string;\n keepMounted?: boolean;\n className?: string;\n children: React.ReactNode;\n}\n\nexport const TabsContent = ({ value, keepMounted = false, className, children, ...props }: ITabsContentProps) => (\n <BaseTabs.Panel {...props} value={value} keepMounted={keepMounted} className={cn('flex-1 text-sm outline-none', className)}>\n {children}\n </BaseTabs.Panel>\n);\n"],"mappings":";;;;;AAgBA,IAAa,UAAQ,EAAE,OAAO,cAAc,eAAe,WAAW,cAAc,cAAc,UAAU,GAAG,YAC7G,oBAAC,KAAS,MAAV;CACE,aAAU;CACV,GAAI;CACJ,oBAAkB;CACX;CACO;CACD;CACb,gBAAgB,SAAS;EACvB,gBAAgB,OAAO,IAAI,CAAC;CAC9B;CACA,WAAW,GAAG,uEAAuE,SAAS;CAE7F;AACY,CAAA;AAGjB,IAAa,mBAAmB,IAC9B,qRACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,MAAM;CACR,EACF;CACA,iBAAiB,EACf,SAAS,UACX;AACF,CACF;AAOA,IAAa,YAAY,EAAE,WAAW,UAAU,WAAW,UAAU,GAAG,YACtE,oBAAC,KAAS,MAAV;CAAe,aAAU;CAAY,GAAI;CAAO,gBAAc;CAAS,WAAW,GAAG,iBAAiB,EAAE,QAAQ,CAAC,GAAG,SAAS;CAC1H;AACY,CAAA;AAUjB,IAAa,eAAe,EAAE,OAAO,UAAU,WAAW,UAAU,GAAG,YACrE,oBAAC,KAAS,KAAV;CACE,GAAI;CACG;CACG;CACV,WAAW,GACT,2vBACA,iQACA,qJACA,4dACA,SACF;CAEC;AACW,CAAA;AAUhB,IAAa,eAAe,EAAE,OAAO,cAAc,OAAO,WAAW,UAAU,GAAG,YAChF,oBAAC,KAAS,OAAV;CAAgB,GAAI;CAAc;CAAoB;CAAa,WAAW,GAAG,+BAA+B,SAAS;CACtH;AACa,CAAA"}
1
+ {"version":3,"file":"tabs.js","names":[],"sources":["../../../../../../../ui/src/components/ui/tabs/tabs.tsx"],"sourcesContent":["import { Tabs as BaseTabs } from '@base-ui/react/tabs';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport type * as React from 'react';\n\nexport interface ITabsProps extends Omit<BaseTabs.Root.Props, 'value' | 'defaultValue' | 'onValueChange' | 'className' | 'orientation' | 'children'> {\n /** Controlled selected tab. Provide with `onValueChange`. */\n value?: string;\n /** Uncontrolled initial tab. Use this when the component should own its state. */\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n className?: string;\n orientation?: 'horizontal' | 'vertical';\n children: React.ReactNode;\n}\n\nexport const Tabs = ({ value, defaultValue, onValueChange, className, orientation = 'horizontal', children, ...props }: ITabsProps) => (\n <BaseTabs.Root\n data-slot=\"tabs\"\n {...props}\n data-orientation={orientation}\n value={value}\n defaultValue={defaultValue}\n orientation={orientation}\n onValueChange={(next) => {\n onValueChange?.(String(next));\n }}\n className={cn('group/tabs flex w-full gap-2 data-[orientation=horizontal]:flex-col', className)}\n >\n {children}\n </BaseTabs.Root>\n);\n\nexport const tabsListVariants = cva(\n 'group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-[orientation=horizontal]/tabs:h-8 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col data-[variant=line]:rounded-none',\n {\n variants: {\n variant: {\n default: 'bg-muted',\n line: 'gap-1 bg-transparent',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n);\n\nexport interface ITabsListProps extends VariantProps<typeof tabsListVariants>, Omit<BaseTabs.List.Props, 'className' | 'children'> {\n className?: string;\n children: React.ReactNode;\n}\n\nexport const TabsList = ({ className, variant = 'default', children, ...props }: ITabsListProps) => (\n <BaseTabs.List data-slot=\"tabs-list\" {...props} data-variant={variant} className={cn(tabsListVariants({ variant }), className)}>\n {children}\n </BaseTabs.List>\n);\n\nexport interface ITabsTriggerProps extends Omit<BaseTabs.Tab.Props, 'value' | 'disabled' | 'className' | 'children'> {\n value: string;\n disabled?: boolean;\n className?: string;\n children: React.ReactNode;\n}\n\nexport const TabsTrigger = ({ value, disabled, className, children, ...props }: ITabsTriggerProps) => (\n <BaseTabs.Tab\n {...props}\n value={value}\n disabled={disabled}\n className={cn(\n 'relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\"size-\"])]:size-4',\n 'group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent',\n 'data-active:bg-background data-active:text-foreground dark:data-active:border-control dark:data-active:bg-input/30 dark:data-active:text-foreground',\n 'after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100',\n className,\n )}\n >\n {children}\n </BaseTabs.Tab>\n);\n\nexport interface ITabsContentProps extends Omit<BaseTabs.Panel.Props, 'value' | 'keepMounted' | 'className' | 'children'> {\n value: string;\n keepMounted?: boolean;\n className?: string;\n children: React.ReactNode;\n}\n\nexport const TabsContent = ({ value, keepMounted = false, className, children, ...props }: ITabsContentProps) => (\n <BaseTabs.Panel {...props} value={value} keepMounted={keepMounted} className={cn('flex-1 text-sm outline-none', className)}>\n {children}\n </BaseTabs.Panel>\n);\n"],"mappings":";;;;;AAgBA,IAAa,UAAQ,EAAE,OAAO,cAAc,eAAe,WAAW,cAAc,cAAc,UAAU,GAAG,YAC7G,oBAAC,KAAS,MAAV;CACE,aAAU;CACV,GAAI;CACJ,oBAAkB;CACX;CACO;CACD;CACb,gBAAgB,SAAS;EACvB,gBAAgB,OAAO,IAAI,CAAC;CAC9B;CACA,WAAW,GAAG,uEAAuE,SAAS;CAE7F;AACY,CAAA;AAGjB,IAAa,mBAAmB,IAC9B,qRACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,MAAM;CACR,EACF;CACA,iBAAiB,EACf,SAAS,UACX;AACF,CACF;AAOA,IAAa,YAAY,EAAE,WAAW,UAAU,WAAW,UAAU,GAAG,YACtE,oBAAC,KAAS,MAAV;CAAe,aAAU;CAAY,GAAI;CAAO,gBAAc;CAAS,WAAW,GAAG,iBAAiB,EAAE,QAAQ,CAAC,GAAG,SAAS;CAC1H;AACY,CAAA;AAUjB,IAAa,eAAe,EAAE,OAAO,UAAU,WAAW,UAAU,GAAG,YACrE,oBAAC,KAAS,KAAV;CACE,GAAI;CACG;CACG;CACV,WAAW,GACT,2vBACA,iQACA,uJACA,4dACA,SACF;CAEC;AACW,CAAA;AAUhB,IAAa,eAAe,EAAE,OAAO,cAAc,OAAO,WAAW,UAAU,GAAG,YAChF,oBAAC,KAAS,OAAV;CAAgB,GAAI;CAAc;CAAoB;CAAa,WAAW,GAAG,+BAA+B,SAAS;CACtH;AACa,CAAA"}
@@ -4,7 +4,7 @@ import { jsx } from "react/jsx-runtime";
4
4
  var Textarea = ({ className, ...props }) => {
5
5
  return /* @__PURE__ */ jsx("textarea", {
6
6
  "data-slot": "textarea",
7
- className: cn("block min-h-16 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1.5 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 field-sizing-content resize-y md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", className),
7
+ className: cn("block min-h-16 w-full min-w-0 rounded-lg border border-control bg-transparent px-2.5 py-1.5 text-base transition-colors outline-none placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 field-sizing-content resize-none md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", className),
8
8
  ...props
9
9
  });
10
10
  };
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.js","names":[],"sources":["../../../../../../../ui/src/components/ui/textarea/textarea.tsx"],"sourcesContent":["import { cn } from '@edyn/ui/lib/utils';\nimport type * as React from 'react';\n\nexport const Textarea = ({ className, ...props }: React.ComponentProps<'textarea'>) => {\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n 'block min-h-16 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1.5 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 field-sizing-content resize-y md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',\n className,\n )}\n {...props}\n />\n );\n};\n"],"mappings":";;;AAGA,IAAa,YAAY,EAAE,WAAW,GAAG,YAA8C;CACrF,OACE,oBAAC,YAAD;EACE,aAAU;EACV,WAAW,GACT,2kBACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"textarea.js","names":[],"sources":["../../../../../../../ui/src/components/ui/textarea/textarea.tsx"],"sourcesContent":["import { cn } from '@edyn/ui/lib/utils';\nimport type * as React from 'react';\n\nexport const Textarea = ({ className, ...props }: React.ComponentProps<'textarea'>) => {\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n 'block min-h-16 w-full min-w-0 rounded-lg border border-control bg-transparent px-2.5 py-1.5 text-base transition-colors outline-none placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 field-sizing-content resize-none md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',\n className,\n )}\n {...props}\n />\n );\n};\n"],"mappings":";;;AAGA,IAAa,YAAY,EAAE,WAAW,GAAG,YAA8C;CACrF,OACE,oBAAC,YAAD;EACE,aAAU;EACV,WAAW,GACT,sgBACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -7,10 +7,10 @@ var toggleVariants = cva("inline-flex shrink-0 cursor-pointer items-center justi
7
7
  variants: {
8
8
  variant: {
9
9
  default: "bg-transparent hover:bg-muted hover:text-foreground data-pressed:bg-muted",
10
- outline: "border-border bg-background hover:bg-muted hover:text-foreground data-pressed:bg-muted dark:border-input dark:bg-input/30 dark:hover:bg-input/50"
10
+ outline: "border-control bg-background hover:bg-muted hover:text-foreground data-pressed:bg-muted dark:bg-input/30 dark:hover:bg-input/50"
11
11
  },
12
12
  size: {
13
- sm: "h-7 px-2.5 text-[0.8rem]",
13
+ sm: "h-7 px-2.5 text-xs",
14
14
  default: "h-8 px-2.5",
15
15
  lg: "h-9 px-3"
16
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"toggle.js","names":[],"sources":["../../../../../../../ui/src/components/ui/toggle/toggle.tsx"],"sourcesContent":["import { Toggle as TogglePrimitive } from '@base-ui/react/toggle';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nexport const toggleVariants = cva(\n 'inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 rounded-lg border border-transparent text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-pressed:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\"size-\"])]:size-4',\n {\n variants: {\n variant: {\n default: 'bg-transparent hover:bg-muted hover:text-foreground data-pressed:bg-muted',\n outline:\n 'border-border bg-background hover:bg-muted hover:text-foreground data-pressed:bg-muted dark:border-input dark:bg-input/30 dark:hover:bg-input/50',\n },\n size: {\n sm: 'h-7 px-2.5 text-[0.8rem]',\n default: 'h-8 px-2.5',\n lg: 'h-9 px-3',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n);\n\nexport type TToggleVariants = VariantProps<typeof toggleVariants>;\n\nexport const Toggle = <Value extends string>({\n className,\n variant = 'default',\n size = 'default',\n ...props\n}: TogglePrimitive.Props<Value> & TToggleVariants) => {\n return <TogglePrimitive data-slot=\"toggle\" className={cn(toggleVariants({ variant, size, className }))} {...props} />;\n};\n"],"mappings":";;;;;AAIA,IAAa,iBAAiB,IAC5B,0aACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,SACE;EACJ;EACA,MAAM;GACJ,IAAI;GACJ,SAAS;GACT,IAAI;EACN;CACF;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;AACF,CACF;AAIA,IAAa,YAAgC,EAC3C,WACA,UAAU,WACV,OAAO,WACP,GAAG,YACiD;CACpD,OAAO,oBAAC,QAAD;EAAiB,aAAU;EAAS,WAAW,GAAG,eAAe;GAAE;GAAS;GAAM;EAAU,CAAC,CAAC;EAAG,GAAI;CAAQ,CAAA;AACtH"}
1
+ {"version":3,"file":"toggle.js","names":[],"sources":["../../../../../../../ui/src/components/ui/toggle/toggle.tsx"],"sourcesContent":["import { Toggle as TogglePrimitive } from '@base-ui/react/toggle';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nexport const toggleVariants = cva(\n 'inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 rounded-lg border border-transparent text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-pressed:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\"size-\"])]:size-4',\n {\n variants: {\n variant: {\n default: 'bg-transparent hover:bg-muted hover:text-foreground data-pressed:bg-muted',\n outline: 'border-control bg-background hover:bg-muted hover:text-foreground data-pressed:bg-muted dark:bg-input/30 dark:hover:bg-input/50',\n },\n size: {\n sm: 'h-7 px-2.5 text-xs',\n default: 'h-8 px-2.5',\n lg: 'h-9 px-3',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n);\n\nexport type TToggleVariants = VariantProps<typeof toggleVariants>;\n\nexport const Toggle = <Value extends string>({\n className,\n variant = 'default',\n size = 'default',\n ...props\n}: TogglePrimitive.Props<Value> & TToggleVariants) => {\n return <TogglePrimitive data-slot=\"toggle\" className={cn(toggleVariants({ variant, size, className }))} {...props} />;\n};\n"],"mappings":";;;;;AAIA,IAAa,iBAAiB,IAC5B,0aACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,SAAS;EACX;EACA,MAAM;GACJ,IAAI;GACJ,SAAS;GACT,IAAI;EACN;CACF;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;AACF,CACF;AAIA,IAAa,YAAgC,EAC3C,WACA,UAAU,WACV,OAAO,WACP,GAAG,YACiD;CACpD,OAAO,oBAAC,QAAD;EAAiB,aAAU;EAAS,WAAW,GAAG,eAAe;GAAE;GAAS;GAAM;EAAU,CAAC,CAAC;EAAG,GAAI;CAAQ,CAAA;AACtH"}
@@ -1,4 +1,5 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
+ import { POPUP_LAYER_CLASS } from "../../../lib/popup-list.js";
2
3
  import { jsx, jsxs } from "react/jsx-runtime";
3
4
  import { Tooltip } from "@base-ui/react/tooltip";
4
5
  //#region ../ui/src/components/ui/tooltip/tooltip.tsx
@@ -27,7 +28,7 @@ var TooltipContent = ({ className, side = "top", sideOffset = 4, align = "center
27
28
  alignOffset,
28
29
  side,
29
30
  sideOffset,
30
- className: "isolate z-50",
31
+ className: cn(POPUP_LAYER_CLASS, "isolate"),
31
32
  children: /* @__PURE__ */ jsxs(Tooltip.Popup, {
32
33
  "data-slot": "tooltip-content",
33
34
  className: cn("z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", "motion-reduce:animate-none", className),
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.js","names":[],"sources":["../../../../../../../ui/src/components/ui/tooltip/tooltip.tsx"],"sourcesContent":["import { Tooltip as TooltipPrimitive } from '@base-ui/react/tooltip';\n\nimport { cn } from '@edyn/ui/lib/utils';\n\nexport const TooltipProvider = ({ delay = 0, ...props }: TooltipPrimitive.Provider.Props) => {\n return <TooltipPrimitive.Provider data-slot=\"tooltip-provider\" delay={delay} {...props} />;\n};\n\nexport const Tooltip = ({ ...props }: TooltipPrimitive.Root.Props) => {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />;\n};\n\nexport const TooltipTrigger = ({ ...props }: TooltipPrimitive.Trigger.Props) => {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />;\n};\n\nexport const TooltipContent = ({\n className,\n side = 'top',\n sideOffset = 4,\n align = 'center',\n alignOffset = 0,\n children,\n ...props\n}: TooltipPrimitive.Popup.Props & Pick<TooltipPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) => {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Positioner align={align} alignOffset={alignOffset} side={side} sideOffset={sideOffset} className=\"isolate z-50\">\n <TooltipPrimitive.Popup\n data-slot=\"tooltip-content\"\n className={cn(\n 'z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',\n 'motion-reduce:animate-none',\n className,\n )}\n {...props}\n >\n {children}\n <TooltipPrimitive.Arrow className=\"z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5\" />\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n );\n};\n"],"mappings":";;;;AAIA,IAAa,mBAAmB,EAAE,QAAQ,GAAG,GAAG,YAA6C;CAC3F,OAAO,oBAAC,QAAiB,UAAlB;EAA2B,aAAU;EAA0B;EAAO,GAAI;CAAQ,CAAA;AAC3F;AAEA,IAAa,aAAW,EAAE,GAAG,YAAyC;CACpE,OAAO,oBAAC,QAAiB,MAAlB;EAAuB,aAAU;EAAU,GAAI;CAAQ,CAAA;AAChE;AAEA,IAAa,kBAAkB,EAAE,GAAG,YAA4C;CAC9E,OAAO,oBAAC,QAAiB,SAAlB;EAA0B,aAAU;EAAkB,GAAI;CAAQ,CAAA;AAC3E;AAEA,IAAa,kBAAkB,EAC7B,WACA,OAAO,OACP,aAAa,GACb,QAAQ,UACR,cAAc,GACd,UACA,GAAG,YAC0H;CAC7H,OACE,oBAAC,QAAiB,QAAlB,EAAA,UACE,oBAAC,QAAiB,YAAlB;EAAoC;EAAoB;EAAmB;EAAkB;EAAY,WAAU;EACjH,UAAA,qBAAC,QAAiB,OAAlB;GACE,aAAU;GACV,WAAW,GACT,mwBACA,8BACA,SACF;GACA,GAAI;GAPN,UAAA,CASG,UACD,oBAAC,QAAiB,OAAlB,EAAwB,WAAU,2hBAA4hB,CAAA,CACxiB;;CACG,CAAA,EACN,CAAA;AAE7B"}
1
+ {"version":3,"file":"tooltip.js","names":[],"sources":["../../../../../../../ui/src/components/ui/tooltip/tooltip.tsx"],"sourcesContent":["import { Tooltip as TooltipPrimitive } from '@base-ui/react/tooltip';\n\nimport { POPUP_LAYER_CLASS } from '@edyn/ui/lib/popup-list';\nimport { cn } from '@edyn/ui/lib/utils';\n\nexport const TooltipProvider = ({ delay = 0, ...props }: TooltipPrimitive.Provider.Props) => {\n return <TooltipPrimitive.Provider data-slot=\"tooltip-provider\" delay={delay} {...props} />;\n};\n\nexport const Tooltip = ({ ...props }: TooltipPrimitive.Root.Props) => {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />;\n};\n\nexport const TooltipTrigger = ({ ...props }: TooltipPrimitive.Trigger.Props) => {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />;\n};\n\nexport const TooltipContent = ({\n className,\n side = 'top',\n sideOffset = 4,\n align = 'center',\n alignOffset = 0,\n children,\n ...props\n}: TooltipPrimitive.Popup.Props & Pick<TooltipPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) => {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className={cn(POPUP_LAYER_CLASS, 'isolate')}\n >\n <TooltipPrimitive.Popup\n data-slot=\"tooltip-content\"\n className={cn(\n 'z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',\n 'motion-reduce:animate-none',\n className,\n )}\n {...props}\n >\n {children}\n <TooltipPrimitive.Arrow className=\"z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5\" />\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n );\n};\n"],"mappings":";;;;;AAKA,IAAa,mBAAmB,EAAE,QAAQ,GAAG,GAAG,YAA6C;CAC3F,OAAO,oBAAC,QAAiB,UAAlB;EAA2B,aAAU;EAA0B;EAAO,GAAI;CAAQ,CAAA;AAC3F;AAEA,IAAa,aAAW,EAAE,GAAG,YAAyC;CACpE,OAAO,oBAAC,QAAiB,MAAlB;EAAuB,aAAU;EAAU,GAAI;CAAQ,CAAA;AAChE;AAEA,IAAa,kBAAkB,EAAE,GAAG,YAA4C;CAC9E,OAAO,oBAAC,QAAiB,SAAlB;EAA0B,aAAU;EAAkB,GAAI;CAAQ,CAAA;AAC3E;AAEA,IAAa,kBAAkB,EAC7B,WACA,OAAO,OACP,aAAa,GACb,QAAQ,UACR,cAAc,GACd,UACA,GAAG,YAC0H;CAC7H,OACE,oBAAC,QAAiB,QAAlB,EAAA,UACE,oBAAC,QAAiB,YAAlB;EACS;EACM;EACP;EACM;EACZ,WAAW,GAAG,mBAAmB,SAAS;EAE1C,UAAA,qBAAC,QAAiB,OAAlB;GACE,aAAU;GACV,WAAW,GACT,mwBACA,8BACA,SACF;GACA,GAAI;GAPN,UAAA,CASG,UACD,oBAAC,QAAiB,OAAlB,EAAwB,WAAU,2hBAA4hB,CAAA,CACxiB;;CACG,CAAA,EACN,CAAA;AAE7B"}
@@ -72,5 +72,5 @@ export * from './components/ui/tooltip';
72
72
  export * from './hooks/use-media-player';
73
73
  export * from './hooks/use-merged-refs';
74
74
  export * from './hooks/use-mobile';
75
- export { POPUP_FRAME_CLASS, POPUP_GROUP_LABEL_CLASS, POPUP_ITEM_INDICATOR_CLASS, POPUP_LIST_HEIGHT_CLASS, POPUP_LIST_WIDTH_CLASS, popupItemClass, type TPopupItemFlavor, } from './lib/popup-list';
75
+ export { POPUP_FRAME_CLASS, POPUP_GROUP_LABEL_CLASS, POPUP_ITEM_INDICATOR_CLASS, POPUP_LAYER_CLASS, POPUP_LIST_HEIGHT_CLASS, POPUP_LIST_WIDTH_CLASS, popupItemClass, type TPopupItemFlavor, } from './lib/popup-list';
76
76
  export { cn } from './lib/utils';
@@ -42,7 +42,7 @@ export declare const popupItemClass: (flavor?: TPopupItemFlavor, checkable?: boo
42
42
  * The check's slot, at the end of the item and the same size whether or not the
43
43
  * check is in it, so a list does not shift as the choice moves.
44
44
  */
45
- export declare const POPUP_ITEM_INDICATOR_CLASS = "pointer-events-none absolute right-2 flex size-4 items-center justify-center text-foreground";
45
+ export declare const POPUP_ITEM_INDICATOR_CLASS = "pointer-events-none absolute right-2 flex size-4 items-center justify-center text-foreground [&_svg]:size-3.5";
46
46
  /** A group's heading in any of these lists. */
47
47
  export declare const POPUP_GROUP_LABEL_CLASS = "px-2 py-1.5 text-xs font-medium text-muted-foreground";
48
48
  /**
@@ -66,13 +66,10 @@ export declare const POPUP_FRAME_CLASS = "rounded-lg bg-popover text-popover-for
66
66
  */
67
67
  export declare const POPUP_LIST_WIDTH_CLASS = "w-max min-w-[max(8rem,var(--anchor-width))] max-w-[max(var(--anchor-width),min(28rem,var(--available-width)))]";
68
68
  /**
69
- * How tall the scrolling part of a popup grows, so that it ends on a whole row. The list scrolls inside its popup and shows
70
- * at most eight rows (the 2rem each of popupItemClass, and the 0.5rem of padding the list holds above and below them), or
71
- * as many whole rows as the room the positioner measured allows, whichever is less. `round(down, ...)` is what makes the
72
- * second case end on a row too: a bare `max-h-(--available-height)` ends wherever the window ends, which cut a row in half
73
- * at the foot of a short window, and a fixed `max-h-60` cut the eighth row of a long list.
74
- *
75
- * It goes on the ScrollArea, which must hold the list's own 0.25rem of padding inside it (the viewport scrolls it with the
76
- * rows) and sit in a popup that is a flex column.
69
+ * How tall the scrolling part of a popup grows: eight rows, or the whole rows the positioner's room allows, ending on a row.
70
+ * The 0.25rem of air above and below is its own margin (`my-1`), so the list inside takes `px-1` and no vertical padding.
71
+ * PopupListScroll is the ScrollArea ready made, and counts rows only (`--popup-list-cap`). See docs/architecture.md.
77
72
  */
78
- export declare const POPUP_LIST_HEIGHT_CLASS = "min-h-0 max-h-[min(16.5rem,round(down,var(--available-height,100dvh)_-_0.5rem,2rem)_+_0.5rem)]";
73
+ export declare const POPUP_LIST_HEIGHT_CLASS = "my-1 min-h-0 max-h-[var(--popup-list-cap,min(16rem,round(down,var(--available-height,100dvh)_-_0.5rem,2rem)))]";
74
+ /** Where a popup is drawn: `z-60` on its Positioner, above the `z-50` of the Sheet, Dialog or Drawer it opens from. */
75
+ export declare const POPUP_LAYER_CLASS = "z-60";
@@ -11,7 +11,7 @@ var popupItemClass = (flavor = "base-ui", checkable = false) => cn(ITEM_BASE, IT
11
11
  * The check's slot, at the end of the item and the same size whether or not the
12
12
  * check is in it, so a list does not shift as the choice moves.
13
13
  */
14
- var POPUP_ITEM_INDICATOR_CLASS = "pointer-events-none absolute right-2 flex size-4 items-center justify-center text-foreground";
14
+ var POPUP_ITEM_INDICATOR_CLASS = "pointer-events-none absolute right-2 flex size-4 items-center justify-center text-foreground [&_svg]:size-3.5";
15
15
  /** A group's heading in any of these lists. */
16
16
  var POPUP_GROUP_LABEL_CLASS = "px-2 py-1.5 text-xs font-medium text-muted-foreground";
17
17
  /**
@@ -35,17 +35,14 @@ var POPUP_FRAME_CLASS = "rounded-lg bg-popover text-popover-foreground shadow-md
35
35
  */
36
36
  var POPUP_LIST_WIDTH_CLASS = "w-max min-w-[max(8rem,var(--anchor-width))] max-w-[max(var(--anchor-width),min(28rem,var(--available-width)))]";
37
37
  /**
38
- * How tall the scrolling part of a popup grows, so that it ends on a whole row. The list scrolls inside its popup and shows
39
- * at most eight rows (the 2rem each of popupItemClass, and the 0.5rem of padding the list holds above and below them), or
40
- * as many whole rows as the room the positioner measured allows, whichever is less. `round(down, ...)` is what makes the
41
- * second case end on a row too: a bare `max-h-(--available-height)` ends wherever the window ends, which cut a row in half
42
- * at the foot of a short window, and a fixed `max-h-60` cut the eighth row of a long list.
43
- *
44
- * It goes on the ScrollArea, which must hold the list's own 0.25rem of padding inside it (the viewport scrolls it with the
45
- * rows) and sit in a popup that is a flex column.
38
+ * How tall the scrolling part of a popup grows: eight rows, or the whole rows the positioner's room allows, ending on a row.
39
+ * The 0.25rem of air above and below is its own margin (`my-1`), so the list inside takes `px-1` and no vertical padding.
40
+ * PopupListScroll is the ScrollArea ready made, and counts rows only (`--popup-list-cap`). See docs/architecture.md.
46
41
  */
47
- var POPUP_LIST_HEIGHT_CLASS = "min-h-0 max-h-[min(16.5rem,round(down,var(--available-height,100dvh)_-_0.5rem,2rem)_+_0.5rem)]";
42
+ var POPUP_LIST_HEIGHT_CLASS = "my-1 min-h-0 max-h-[var(--popup-list-cap,min(16rem,round(down,var(--available-height,100dvh)_-_0.5rem,2rem)))]";
43
+ /** Where a popup is drawn: `z-60` on its Positioner, above the `z-50` of the Sheet, Dialog or Drawer it opens from. */
44
+ var POPUP_LAYER_CLASS = "z-60";
48
45
  //#endregion
49
- export { POPUP_FRAME_CLASS, POPUP_GROUP_LABEL_CLASS, POPUP_ITEM_INDICATOR_CLASS, POPUP_LIST_HEIGHT_CLASS, POPUP_LIST_WIDTH_CLASS, popupItemClass };
46
+ export { POPUP_FRAME_CLASS, POPUP_GROUP_LABEL_CLASS, POPUP_ITEM_INDICATOR_CLASS, POPUP_LAYER_CLASS, POPUP_LIST_HEIGHT_CLASS, POPUP_LIST_WIDTH_CLASS, popupItemClass };
50
47
 
51
48
  //# sourceMappingURL=popup-list.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"popup-list.js","names":[],"sources":["../../../../../ui/src/lib/popup-list.ts"],"sourcesContent":["import { cn } from '@edyn/ui/lib/utils';\n\n/**\n * The one look for a list in a popup or a menu: the command palette, Select,\n * Combobox, MultiSelect and the dropdown menus.\n *\n * These lists used to disagree with each other in every detail that shows:\n * three different radii, two different paddings, a grey fill for the highlight\n * in one and the accent in another, and the chosen item marked by a check on\n * the left in Select and on the right in the menus. Picking something from one\n * list then felt like a different product from picking something in the next.\n *\n * It lives here as classes rather than as a stylesheet so a caller's own\n * className still wins: an unlayered rule would beat every utility, including\n * the one someone passes for a single list.\n *\n * ONE ITEM: transparent at rest, 32px tall, 6px radius (--radius-sm), 6px by\n * 8px of padding, text-sm, its own icons 16px and muted. Under the pointer or\n * the keyboard it takes one translucent fill of the text colour, and its icons\n * the text colour. Chosen is medium weight with a check at the END, never a\n * fill, so \"where I am\" and \"what I picked\" can be told apart at a glance.\n */\n\n/**\n * Which primitive renders the item, because the two disagree about the same\n * attribute names in a way that silently breaks the styling:\n *\n * - cmdk writes `data-selected=\"false\"` and `data-disabled=\"false\"` on items\n * that are neither, so a bare `data-selected:` variant matches EVERY item and\n * highlights the whole list. Its states have to be matched by value.\n * - Base UI omits the attribute instead, so presence is the test there. That\n * needs the BRACKET form for `selected`: shadcn redefines the bare\n * `data-selected:` variant to match only data-selected=\"true\" (for the\n * calendar), and Base UI writes it as an empty string, so the bare form\n * compiles and silently never applies. `highlighted` and `disabled` have no\n * such override, so those stay bare.\n * - And the same name means different things: cmdk's `data-selected` is the\n * keyboard cursor, Base UI's is the chosen value. In cmdk the chosen state is\n * `data-checked`, which the DS's own CommandItem sets.\n */\nexport type TPopupItemFlavor = 'base-ui' | 'cmdk';\n\nconst ITEM_BASE =\n \"relative flex min-h-8 cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm text-foreground outline-none select-none [&>svg]:pointer-events-none [&>svg]:shrink-0 [&>svg]:text-muted-foreground [&>svg:not([class*='size-'])]:size-4\";\n\nconst ITEM_STATES: Record<TPopupItemFlavor, string> = {\n 'base-ui':\n 'data-highlighted:bg-foreground/6 data-highlighted:[&>svg]:text-foreground data-[selected]:font-medium data-disabled:pointer-events-none data-disabled:opacity-50',\n cmdk: 'data-[selected=true]:bg-foreground/6 data-[selected=true]:[&>svg]:text-foreground data-[checked=true]:font-medium data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',\n};\n\n/** The shared item look. `checkable` leaves room at the end for the check. */\nexport const popupItemClass = (flavor: TPopupItemFlavor = 'base-ui', checkable = false): string =>\n cn(ITEM_BASE, ITEM_STATES[flavor], checkable && 'pr-8');\n\n/**\n * The check's slot, at the end of the item and the same size whether or not the\n * check is in it, so a list does not shift as the choice moves.\n */\nexport const POPUP_ITEM_INDICATOR_CLASS = 'pointer-events-none absolute right-2 flex size-4 items-center justify-center text-foreground';\n\n/** A group's heading in any of these lists. */\nexport const POPUP_GROUP_LABEL_CLASS = 'px-2 py-1.5 text-xs font-medium text-muted-foreground';\n\n/**\n * The frame of every popup that holds a list: Select, Combobox, MultiSelect and the menus. One radius, and one outline, the\n * 1px ring of the text colour at 10% that the menus, Popover and the dialogs already wear. It is a ring and not a border so\n * the frame takes no room: the popup is exactly as tall as its rows, which is what lets a list end on a whole row (see\n * POPUP_LIST_HEIGHT_CLASS). Select used to draw a 14px border, Combobox a 10px one, and the menus a ring.\n *\n * `outline-none` is the popup's own focus outline, switched off: a popup is a container, and the highlighted row is where\n * focus is shown.\n */\nexport const POPUP_FRAME_CLASS = 'rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-none';\n\n/**\n * How wide a popup is, for every popup alike: never narrower than the control it opens from (and never under 8rem, for a\n * control that is only an icon), as wide as its longest row up to 28rem or what the window leaves from the control's start\n * (the popup is aligned to that start), whichever is less. A control wider than that cap keeps its own width. Longer rows\n * are cut by their item, they do not widen the popup.\n *\n * The popups used to disagree: the menus were the control's width, MultiSelect at least 16rem and at most 24rem, Combobox\n * followed the control, and an app's command palette in a popover was 18rem whatever it held.\n */\nexport const POPUP_LIST_WIDTH_CLASS =\n 'w-max min-w-[max(8rem,var(--anchor-width))] max-w-[max(var(--anchor-width),min(28rem,var(--available-width)))]';\n\n/**\n * How tall the scrolling part of a popup grows, so that it ends on a whole row. The list scrolls inside its popup and shows\n * at most eight rows (the 2rem each of popupItemClass, and the 0.5rem of padding the list holds above and below them), or\n * as many whole rows as the room the positioner measured allows, whichever is less. `round(down, ...)` is what makes the\n * second case end on a row too: a bare `max-h-(--available-height)` ends wherever the window ends, which cut a row in half\n * at the foot of a short window, and a fixed `max-h-60` cut the eighth row of a long list.\n *\n * It goes on the ScrollArea, which must hold the list's own 0.25rem of padding inside it (the viewport scrolls it with the\n * rows) and sit in a popup that is a flex column.\n */\nexport const POPUP_LIST_HEIGHT_CLASS = 'min-h-0 max-h-[min(16.5rem,round(down,var(--available-height,100dvh)_-_0.5rem,2rem)_+_0.5rem)]';\n"],"mappings":";;AA0CA,IAAM,YACJ;AAEF,IAAM,cAAgD;CACpD,WACE;CACF,MAAM;AACR;;AAGA,IAAa,kBAAkB,SAA2B,WAAW,YAAY,UAC/E,GAAG,WAAW,YAAY,SAAS,aAAa,MAAM;;;;;AAMxD,IAAa,6BAA6B;;AAG1C,IAAa,0BAA0B;;;;;;;;;;AAWvC,IAAa,oBAAoB;;;;;;;;;;AAWjC,IAAa,yBACX;;;;;;;;;;;AAYF,IAAa,0BAA0B"}
1
+ {"version":3,"file":"popup-list.js","names":[],"sources":["../../../../../ui/src/lib/popup-list.ts"],"sourcesContent":["import { cn } from '@edyn/ui/lib/utils';\n\n/**\n * The one look for a list in a popup or a menu: the command palette, Select,\n * Combobox, MultiSelect and the dropdown menus.\n *\n * These lists used to disagree with each other in every detail that shows:\n * three different radii, two different paddings, a grey fill for the highlight\n * in one and the accent in another, and the chosen item marked by a check on\n * the left in Select and on the right in the menus. Picking something from one\n * list then felt like a different product from picking something in the next.\n *\n * It lives here as classes rather than as a stylesheet so a caller's own\n * className still wins: an unlayered rule would beat every utility, including\n * the one someone passes for a single list.\n *\n * ONE ITEM: transparent at rest, 32px tall, 6px radius (--radius-sm), 6px by\n * 8px of padding, text-sm, its own icons 16px and muted. Under the pointer or\n * the keyboard it takes one translucent fill of the text colour, and its icons\n * the text colour. Chosen is medium weight with a check at the END, never a\n * fill, so \"where I am\" and \"what I picked\" can be told apart at a glance.\n */\n\n/**\n * Which primitive renders the item, because the two disagree about the same\n * attribute names in a way that silently breaks the styling:\n *\n * - cmdk writes `data-selected=\"false\"` and `data-disabled=\"false\"` on items\n * that are neither, so a bare `data-selected:` variant matches EVERY item and\n * highlights the whole list. Its states have to be matched by value.\n * - Base UI omits the attribute instead, so presence is the test there. That\n * needs the BRACKET form for `selected`: shadcn redefines the bare\n * `data-selected:` variant to match only data-selected=\"true\" (for the\n * calendar), and Base UI writes it as an empty string, so the bare form\n * compiles and silently never applies. `highlighted` and `disabled` have no\n * such override, so those stay bare.\n * - And the same name means different things: cmdk's `data-selected` is the\n * keyboard cursor, Base UI's is the chosen value. In cmdk the chosen state is\n * `data-checked`, which the DS's own CommandItem sets.\n */\nexport type TPopupItemFlavor = 'base-ui' | 'cmdk';\n\nconst ITEM_BASE =\n \"relative flex min-h-8 cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm text-foreground outline-none select-none [&>svg]:pointer-events-none [&>svg]:shrink-0 [&>svg]:text-muted-foreground [&>svg:not([class*='size-'])]:size-4\";\n\nconst ITEM_STATES: Record<TPopupItemFlavor, string> = {\n 'base-ui':\n 'data-highlighted:bg-foreground/6 data-highlighted:[&>svg]:text-foreground data-[selected]:font-medium data-disabled:pointer-events-none data-disabled:opacity-50',\n cmdk: 'data-[selected=true]:bg-foreground/6 data-[selected=true]:[&>svg]:text-foreground data-[checked=true]:font-medium data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',\n};\n\n/** The shared item look. `checkable` leaves room at the end for the check. */\nexport const popupItemClass = (flavor: TPopupItemFlavor = 'base-ui', checkable = false): string =>\n cn(ITEM_BASE, ITEM_STATES[flavor], checkable && 'pr-8');\n\n/**\n * The check's slot, at the end of the item and the same size whether or not the\n * check is in it, so a list does not shift as the choice moves.\n */\nexport const POPUP_ITEM_INDICATOR_CLASS =\n 'pointer-events-none absolute right-2 flex size-4 items-center justify-center text-foreground [&_svg]:size-3.5';\n\n/** A group's heading in any of these lists. */\nexport const POPUP_GROUP_LABEL_CLASS = 'px-2 py-1.5 text-xs font-medium text-muted-foreground';\n\n/**\n * The frame of every popup that holds a list: Select, Combobox, MultiSelect and the menus. One radius, and one outline, the\n * 1px ring of the text colour at 10% that the menus, Popover and the dialogs already wear. It is a ring and not a border so\n * the frame takes no room: the popup is exactly as tall as its rows, which is what lets a list end on a whole row (see\n * POPUP_LIST_HEIGHT_CLASS). Select used to draw a 14px border, Combobox a 10px one, and the menus a ring.\n *\n * `outline-none` is the popup's own focus outline, switched off: a popup is a container, and the highlighted row is where\n * focus is shown.\n */\nexport const POPUP_FRAME_CLASS = 'rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-none';\n\n/**\n * How wide a popup is, for every popup alike: never narrower than the control it opens from (and never under 8rem, for a\n * control that is only an icon), as wide as its longest row up to 28rem or what the window leaves from the control's start\n * (the popup is aligned to that start), whichever is less. A control wider than that cap keeps its own width. Longer rows\n * are cut by their item, they do not widen the popup.\n *\n * The popups used to disagree: the menus were the control's width, MultiSelect at least 16rem and at most 24rem, Combobox\n * followed the control, and an app's command palette in a popover was 18rem whatever it held.\n */\nexport const POPUP_LIST_WIDTH_CLASS =\n 'w-max min-w-[max(8rem,var(--anchor-width))] max-w-[max(var(--anchor-width),min(28rem,var(--available-width)))]';\n\n/**\n * How tall the scrolling part of a popup grows: eight rows, or the whole rows the positioner's room allows, ending on a row.\n * The 0.25rem of air above and below is its own margin (`my-1`), so the list inside takes `px-1` and no vertical padding.\n * PopupListScroll is the ScrollArea ready made, and counts rows only (`--popup-list-cap`). See docs/architecture.md.\n */\nexport const POPUP_LIST_HEIGHT_CLASS =\n 'my-1 min-h-0 max-h-[var(--popup-list-cap,min(16rem,round(down,var(--available-height,100dvh)_-_0.5rem,2rem)))]';\n\n/** Where a popup is drawn: `z-60` on its Positioner, above the `z-50` of the Sheet, Dialog or Drawer it opens from. */\nexport const POPUP_LAYER_CLASS = 'z-60';\n"],"mappings":";;AA0CA,IAAM,YACJ;AAEF,IAAM,cAAgD;CACpD,WACE;CACF,MAAM;AACR;;AAGA,IAAa,kBAAkB,SAA2B,WAAW,YAAY,UAC/E,GAAG,WAAW,YAAY,SAAS,aAAa,MAAM;;;;;AAMxD,IAAa,6BACX;;AAGF,IAAa,0BAA0B;;;;;;;;;;AAWvC,IAAa,oBAAoB;;;;;;;;;;AAWjC,IAAa,yBACX;;;;;;AAOF,IAAa,0BACX;;AAGF,IAAa,oBAAoB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exsto/ds",
3
- "version": "0.0.1-rc.18",
3
+ "version": "0.0.1-rc.19",
4
4
  "description": "The eDynamix design system: React components and design tokens.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [