overflow-toolbar 0.1.6 → 0.1.8

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 (26) hide show
  1. package/README.md +25 -4
  2. package/dist/components/MuiOverflow/MuiOverflowMenu.d.ts +3 -2
  3. package/dist/components/MuiOverflow/MuiOverflowMenu.d.ts.map +1 -1
  4. package/dist/components/MuiOverflow/MuiOverflowMenu.js +7 -7
  5. package/dist/components/MuiOverflow/MuiOverflowMenu.js.map +1 -1
  6. package/dist/components/Overflow/Overflow.d.ts.map +1 -1
  7. package/dist/components/Overflow/Overflow.js +35 -27
  8. package/dist/components/Overflow/Overflow.js.map +1 -1
  9. package/dist/components/Overflow/OverflowController.d.ts.map +1 -1
  10. package/dist/components/Overflow/OverflowController.js +11 -7
  11. package/dist/components/Overflow/OverflowController.js.map +1 -1
  12. package/dist/components/Overflow/OverflowMenu.d.ts +6 -2
  13. package/dist/components/Overflow/OverflowMenu.d.ts.map +1 -1
  14. package/dist/components/Overflow/OverflowMenu.js +35 -29
  15. package/dist/components/Overflow/OverflowMenu.js.map +1 -1
  16. package/dist/components/Overflow/index.d.ts +1 -1
  17. package/dist/components/Overflow/index.d.ts.map +1 -1
  18. package/dist/components/Overflow/useResizer.d.ts +1 -1
  19. package/dist/components/Overflow/useResizer.d.ts.map +1 -1
  20. package/dist/components/Overflow/useResizer.js +10 -12
  21. package/dist/components/Overflow/useResizer.js.map +1 -1
  22. package/dist/components/RxOverflow/RxOverflowMenu.d.ts +3 -2
  23. package/dist/components/RxOverflow/RxOverflowMenu.d.ts.map +1 -1
  24. package/dist/components/RxOverflow/RxOverflowMenu.js +17 -16
  25. package/dist/components/RxOverflow/RxOverflowMenu.js.map +1 -1
  26. package/package.json +1 -1
package/README.md CHANGED
@@ -141,10 +141,31 @@ Wraps each toolbar item. Place matching items in both the toolbar and the menu,
141
141
 
142
142
  The dropdown menu container. Must include an `opener` element (the trigger button).
143
143
 
144
- | Prop | Type | Description |
145
- |---|---|---|
146
- | `children` | `ReactNode` | Menu items |
147
- | `opener` | `ReactNode` | The button that opens the menu |
144
+ | Prop | Type | Default | Description |
145
+ |---|---|---|---|
146
+ | `children` | `ReactNode` | — | Menu items |
147
+ | `opener` | `ReactNode` | — | The button that opens the menu |
148
+ | `open` | `boolean` | — | Controlled open state. When provided, you manage open/close. |
149
+ | `onOpenChange` | `(open: boolean) => void` | — | Called when the menu opens or closes. Use alone for notifications, or with `open` for full control. |
150
+
151
+ #### Controlled Menu
152
+
153
+ By default, the menu manages its own open/close state. To control it programmatically, pass `open` and `onOpenChange`:
154
+
155
+ ```tsx
156
+ const [menuOpen, setMenuOpen] = useState(false);
157
+
158
+ <RxOverflowMenu
159
+ opener={<button>More</button>}
160
+ open={menuOpen}
161
+ onOpenChange={setMenuOpen}
162
+ >
163
+ {/* items */}
164
+ </RxOverflowMenu>
165
+
166
+ // Close programmatically from anywhere:
167
+ setMenuOpen(false);
168
+ ```
148
169
 
149
170
  ### `OverflowController`
150
171
 
@@ -1,9 +1,10 @@
1
1
  import type { ReactNode } from 'react';
2
- interface MuiOverflowMenuProps {
2
+ import { type OverflowMenuControlProps } from '../Overflow';
3
+ interface MuiOverflowMenuProps extends OverflowMenuControlProps {
3
4
  opener: ReactNode;
4
5
  children: ReactNode;
5
6
  }
6
- declare function MuiOverflowMenu({ opener, children }: MuiOverflowMenuProps): import("react/jsx-runtime").JSX.Element;
7
+ declare function MuiOverflowMenu({ opener, children, open, onOpenChange }: MuiOverflowMenuProps): import("react/jsx-runtime").JSX.Element;
7
8
  declare const _default: typeof MuiOverflowMenu & {
8
9
  overflowRole: "menu";
9
10
  };
@@ -1 +1 @@
1
- {"version":3,"file":"MuiOverflowMenu.d.ts","sourceRoot":"","sources":["../../../src/components/MuiOverflow/MuiOverflowMenu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,UAAU,oBAAoB;IAC5B,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,iBAAS,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,oBAAoB,2CAYlE;;;;AAED,wBAAiF"}
1
+ {"version":3,"file":"MuiOverflowMenu.d.ts","sourceRoot":"","sources":["../../../src/components/MuiOverflow/MuiOverflowMenu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAgB,KAAK,wBAAwB,EAAwB,MAAM,aAAa,CAAC;AAEhG,UAAU,oBAAqB,SAAQ,wBAAwB;IAC7D,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,iBAAS,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,oBAAoB,2CAYtF;;;;AAED,wBAAiF"}
@@ -1,11 +1,11 @@
1
- import { jsx as e } from "react/jsx-runtime";
2
- import i from "@mui/material/Menu";
3
- import l from "../Overflow/OverflowMenu.js";
4
- function M({ opener: r, children: n }) {
5
- return /* @__PURE__ */ e(l, { opener: r, renderMenu: ({ anchorEl: o, open: u, onClose: t, children: f }) => /* @__PURE__ */ e(i, { anchorEl: o, open: u, onClose: t, children: f }), children: n });
1
+ import { jsx as n } from "react/jsx-runtime";
2
+ import M from "@mui/material/Menu";
3
+ import c from "../Overflow/OverflowMenu.js";
4
+ function m({ opener: r, children: o, open: u, onOpenChange: t }) {
5
+ return /* @__PURE__ */ n(c, { opener: r, renderMenu: ({ anchorEl: f, open: i, onClose: e, children: l }) => /* @__PURE__ */ n(M, { anchorEl: f, open: i, onClose: e, onClick: e, children: l }), open: u, onOpenChange: t, children: o });
6
6
  }
7
- const a = Object.assign(M, { overflowRole: "menu" });
7
+ const v = Object.assign(m, { overflowRole: "menu" });
8
8
  export {
9
- a as default
9
+ v as default
10
10
  };
11
11
  //# sourceMappingURL=MuiOverflowMenu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MuiOverflowMenu.js","sources":["../../../src/components/MuiOverflow/MuiOverflowMenu.tsx"],"sourcesContent":["import Menu from '@mui/material/Menu';\nimport type { ReactNode } from 'react';\nimport { OverflowMenu, type RenderMenuProps } from '../Overflow';\n\ninterface MuiOverflowMenuProps {\n opener: ReactNode;\n children: ReactNode;\n}\n\nfunction MuiOverflowMenu({ opener, children }: MuiOverflowMenuProps) {\n const renderMenu = ({ anchorEl, open, onClose, children: menuChildren }: RenderMenuProps) => (\n <Menu anchorEl={anchorEl} open={open} onClose={onClose}>\n {menuChildren}\n </Menu>\n );\n\n return (\n <OverflowMenu opener={opener} renderMenu={renderMenu}>\n {children}\n </OverflowMenu>\n );\n}\n\nexport default Object.assign(MuiOverflowMenu, { overflowRole: 'menu' as const });\n"],"names":["MuiOverflowMenu","opener","children","jsx","OverflowMenu","anchorEl","open","onClose","menuChildren","Menu","MuiOverflowMenu_default"],"mappings":";;;AASA,SAASA,EAAgB,EAAE,QAAAC,GAAQ,UAAAC,KAAkC;AAOnE,SACE,gBAAAC,EAACC,GAAA,EAAa,QAAAH,GAAgB,YAPb,CAAC,EAAE,UAAAI,GAAU,MAAAC,GAAM,SAAAC,GAAS,UAAUC,EAAA,MACvD,gBAAAL,EAACM,GAAA,EAAK,UAAAJ,GAAoB,MAAAC,GAAY,SAAAC,GACnC,UAAAC,GACH,GAKG,UAAAN,EAAA,CACH;AAEJ;AAEA,MAAAQ,IAAe,OAAO,OAAOV,GAAiB,EAAE,cAAc,QAAiB;"}
1
+ {"version":3,"file":"MuiOverflowMenu.js","sources":["../../../src/components/MuiOverflow/MuiOverflowMenu.tsx"],"sourcesContent":["import Menu from '@mui/material/Menu';\nimport type { ReactNode } from 'react';\nimport { OverflowMenu, type OverflowMenuControlProps, type RenderMenuProps } from '../Overflow';\n\ninterface MuiOverflowMenuProps extends OverflowMenuControlProps {\n opener: ReactNode;\n children: ReactNode;\n}\n\nfunction MuiOverflowMenu({ opener, children, open, onOpenChange }: MuiOverflowMenuProps) {\n const renderMenu = ({ anchorEl, open, onClose, children: menuChildren }: RenderMenuProps) => (\n <Menu anchorEl={anchorEl} open={open} onClose={onClose} onClick={onClose}>\n {menuChildren}\n </Menu>\n );\n\n return (\n <OverflowMenu opener={opener} renderMenu={renderMenu} open={open} onOpenChange={onOpenChange}>\n {children}\n </OverflowMenu>\n );\n}\n\nexport default Object.assign(MuiOverflowMenu, { overflowRole: 'menu' as const });\n"],"names":["MuiOverflowMenu","opener","children","open","onOpenChange","OverflowMenu","anchorEl","onClose","menuChildren","jsx","Menu","MuiOverflowMenu_default"],"mappings":";;;AASA,SAASA,EAAgB,EAAE,QAAAC,GAAQ,UAAAC,GAAU,MAAAC,GAAM,cAAAC,KAAsC;AAOvF,2BACGC,GAAA,EAAa,QAAAJ,GAAgB,YAPb,CAAC,EAAE,UAAAK,GAAU,MAAAH,GAAM,SAAAI,GAAS,UAAUC,QACvD,gBAAAC,EAACC,KAAK,UAAAJ,GAAoB,MAAMH,GAAM,SAAAI,GAAkB,SAASA,GAC9D,UAAAC,GACH,GAIsD,MAAAL,GAAY,cAAAC,GAC/D,UAAAF,GACH;AAEJ;AAEA,MAAAS,IAAe,OAAO,OAAOX,GAAiB,EAAE,cAAc,QAAiB;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Overflow.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/Overflow.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAkD,KAAK,SAAS,EAA0C,MAAM,OAAO,CAAC;AAC/H,OAAO,gBAAgB,CAAC;AAKxB,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,QAAA,MAAM,QAAQ,4GAuEZ,CAAC;AAEH,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Overflow.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/Overflow.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAkD,KAAK,SAAS,EAA8C,MAAM,OAAO,CAAC;AACnI,OAAO,gBAAgB,CAAC;AAKxB,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,QAAA,MAAM,QAAQ,4GAuFZ,CAAC;AAEH,eAAe,QAAQ,CAAC"}
@@ -1,34 +1,42 @@
1
- import { jsx as w } from "react/jsx-runtime";
2
- import { forwardRef as g, useState as j, useRef as z, useMemo as p, Children as i, isValidElement as m, Fragment as A, useCallback as V } from "react";
1
+ import { jsx as S } from "react/jsx-runtime";
2
+ import { forwardRef as z, useState as N, useRef as g, useMemo as p, Children as u, isValidElement as m, Fragment as j, useLayoutEffect as A } from "react";
3
3
  /* empty css */
4
- import W from "./OverflowContext.js";
5
- import { buildOrderedSteps as k, computeNextSteps as B, deriveHiddenMap as C } from "./overflowSteps.js";
4
+ import V from "./OverflowContext.js";
5
+ import { buildOrderedSteps as b, computeNextSteps as R, deriveHiddenMap as B } from "./overflowSteps.js";
6
6
  import { useResizer as F } from "./useResizer.js";
7
- const P = g(function({ children: t, className: S, style: R, compact: x, reverse: d }, M) {
8
- const [f, y] = j([]), I = z(null), a = M ?? I, u = p(() => i.toArray(
9
- i.count(t) === 1 && m(t) && t.type === A ? t.props.children : t
10
- ), [t]), l = p(() => {
11
- const e = [], s = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Set();
12
- i.forEach(u, (o) => {
13
- if (!m(o)) return;
14
- const v = o.type.overflowRole;
15
- v === "menu" ? i.forEach(o.props.children, (r) => {
16
- m(r) && r.props.menuid && (s.add(r.props.menuid), e.includes(r.props.menuid) || e.push(r.props.menuid));
17
- }) : v === "item" && o.props.menuid && (e.includes(o.props.menuid) || e.push(o.props.menuid), o.props.minStateWidth !== void 0 && n.add(o.props.menuid));
7
+ const K = z(function({ children: o, className: W, style: x, compact: y, reverse: d }, M) {
8
+ const [i, c] = N([]), E = g(null), s = M ?? E, f = p(() => u.toArray(
9
+ u.count(o) === 1 && m(o) && o.type === j ? o.props.children : o
10
+ ), [o]), l = p(() => {
11
+ const e = [], r = /* @__PURE__ */ new Set(), v = /* @__PURE__ */ new Set();
12
+ u.forEach(f, (t) => {
13
+ if (!m(t)) return;
14
+ const w = t.type.overflowRole;
15
+ w === "menu" ? u.forEach(t.props.children, (n) => {
16
+ m(n) && n.props.menuid && (r.add(n.props.menuid), e.includes(n.props.menuid) || e.push(n.props.menuid));
17
+ }) : w === "item" && t.props.menuid && (e.includes(t.props.menuid) || e.push(t.props.menuid), t.props.minStateWidth !== void 0 && v.add(t.props.menuid));
18
18
  });
19
- const b = d ? [...e].reverse() : e;
20
- return k(b, s, n);
21
- }, [u, d]), O = V((e, s) => {
22
- y((n) => B(n, e, s, l));
23
- }, [l]);
24
- F(a, O);
25
- const c = p(() => C(f), [f]), E = p(
26
- () => ({ hiddenMap: c }),
27
- [c]
28
- ), N = ["overflow", x && "overflow-compact", d && "overflow-reverse", S].filter(Boolean).join(" ");
29
- return /* @__PURE__ */ w(W, { value: E, children: /* @__PURE__ */ w("ul", { ref: a, className: N, style: { ...R, "--hiddenCount": f.length }, children: u }) });
19
+ const h = d ? [...e].reverse() : e;
20
+ return b(h, r, v);
21
+ }, [f, d]);
22
+ A(() => {
23
+ const e = s.current;
24
+ e && c(
25
+ (r) => R(r, e.scrollWidth, e.clientWidth, l)
26
+ );
27
+ }, [i, l, s]), F(s, () => {
28
+ const e = s.current;
29
+ e && c(
30
+ (r) => R(r, e.scrollWidth, e.clientWidth, l)
31
+ );
32
+ });
33
+ const a = p(() => B(i), [i]), I = p(
34
+ () => ({ hiddenMap: a }),
35
+ [a]
36
+ ), O = ["overflow", y && "overflow-compact", d && "overflow-reverse", W].filter(Boolean).join(" ");
37
+ return /* @__PURE__ */ S(V, { value: I, children: /* @__PURE__ */ S("ul", { ref: s, className: O, style: { ...x, "--hiddenCount": i.length }, children: f }) });
30
38
  });
31
39
  export {
32
- P as default
40
+ K as default
33
41
  };
34
42
  //# sourceMappingURL=Overflow.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Overflow.js","sources":["../../../src/components/Overflow/Overflow.tsx"],"sourcesContent":["import { Children, Fragment, forwardRef, isValidElement, type ReactNode, useCallback, useMemo, useRef, useState } from 'react';\nimport './Overflow.css';\nimport OverflowContext from './OverflowContext';\nimport { type AppliedStep, buildOrderedSteps, computeNextSteps, deriveHiddenMap } from './overflowSteps';\nimport { useResizer } from './useResizer';\n\nexport interface OverflowProps {\n children: ReactNode;\n className?: string;\n style?: React.CSSProperties;\n compact?: boolean;\n reverse?: boolean;\n}\n\nconst Overflow = forwardRef<HTMLUListElement, OverflowProps>(function Overflow({ children, className, style, compact, reverse }, ref) {\n const [appliedSteps, setAppliedSteps] = useState<AppliedStep[]>([]);\n const internalRef = useRef<HTMLUListElement | null>(null);\n const listRef = (ref ?? internalRef) as React.RefObject<HTMLUListElement | null>;\n\n // Unwrap a single top-level Fragment so items work in Storybook args, etc.\n const resolvedChildren = useMemo(() => Children.toArray(\n Children.count(children) === 1 && isValidElement<{ children: ReactNode }>(children) && children.type === Fragment\n ? children.props.children\n : children,\n ), [children]);\n\n // Build ordered steps by scanning resolved children using overflowRole markers\n const orderedSteps = useMemo(() => {\n const menuIds: string[] = [];\n const inMenuIds = new Set<string>();\n const minWidthMenuIds = new Set<string>();\n\n // Scan resolved children: collect menuids, detect which are in an OverflowMenu\n Children.forEach(resolvedChildren, (child) => {\n if (!isValidElement<{ menuid?: string; children?: ReactNode; minStateWidth?: string }>(child)) return;\n\n const role = (child.type as { overflowRole?: string }).overflowRole;\n\n if (role === 'menu') {\n // Scan OverflowMenu children for menuids that have menu representation\n Children.forEach(child.props.children, (menuChild) => {\n if (!isValidElement<{ menuid?: string }>(menuChild)) return;\n if (menuChild.props.menuid) {\n inMenuIds.add(menuChild.props.menuid);\n if (!menuIds.includes(menuChild.props.menuid)) {\n menuIds.push(menuChild.props.menuid);\n }\n }\n });\n } else if (role === 'item' && child.props.menuid) {\n if (!menuIds.includes(child.props.menuid)) {\n menuIds.push(child.props.menuid);\n }\n if (child.props.minStateWidth !== undefined) {\n minWidthMenuIds.add(child.props.menuid);\n }\n }\n });\n\n const orderedIds = reverse ? [...menuIds].reverse() : menuIds;\n return buildOrderedSteps(orderedIds, inMenuIds, minWidthMenuIds);\n }, [resolvedChildren, reverse]);\n\n const onResize = useCallback((scrollWidth: number, clientWidth: number) => {\n setAppliedSteps(prev => computeNextSteps(prev, scrollWidth, clientWidth, orderedSteps));\n }, [orderedSteps]);\n\n useResizer(listRef, onResize);\n\n const hiddenMap = useMemo(() => deriveHiddenMap(appliedSteps), [appliedSteps]);\n\n const ctxValue = useMemo(\n () => ({ hiddenMap }),\n [hiddenMap],\n );\n\n const classNames = ['overflow', compact && 'overflow-compact', reverse && 'overflow-reverse', className].filter(Boolean).join(' ');\n\n return (\n <OverflowContext value={ctxValue}>\n <ul ref={listRef} className={classNames} style={{ ...style, '--hiddenCount': appliedSteps.length } as React.CSSProperties}>\n {resolvedChildren}\n </ul>\n </OverflowContext>\n );\n});\n\nexport default Overflow;\n"],"names":["Overflow","forwardRef","children","className","style","compact","reverse","ref","appliedSteps","setAppliedSteps","useState","internalRef","useRef","listRef","resolvedChildren","useMemo","Children","isValidElement","Fragment","orderedSteps","menuIds","inMenuIds","minWidthMenuIds","child","role","menuChild","orderedIds","buildOrderedSteps","onResize","useCallback","scrollWidth","clientWidth","computeNextSteps","prev","useResizer","hiddenMap","deriveHiddenMap","ctxValue","classNames","OverflowContext","jsx"],"mappings":";;;;;;AAcA,MAAMA,IAAWC,EAA4C,SAAkB,EAAE,UAAAC,GAAU,WAAAC,GAAW,OAAAC,GAAO,SAAAC,GAAS,SAAAC,EAAA,GAAWC,GAAK;AACpI,QAAM,CAACC,GAAcC,CAAe,IAAIC,EAAwB,CAAA,CAAE,GAC5DC,IAAcC,EAAgC,IAAI,GAClDC,IAAWN,KAAOI,GAGlBG,IAAmBC,EAAQ,MAAMC,EAAS;AAAA,IAC9CA,EAAS,MAAMd,CAAQ,MAAM,KAAKe,EAAwCf,CAAQ,KAAKA,EAAS,SAASgB,IACrGhB,EAAS,MAAM,WACfA;AAAA,EAAA,GACH,CAACA,CAAQ,CAAC,GAGPiB,IAAeJ,EAAQ,MAAM;AACjC,UAAMK,IAAoB,CAAA,GACpBC,wBAAgB,IAAA,GAChBC,wBAAsB,IAAA;AAG5B,IAAAN,EAAS,QAAQF,GAAkB,CAACS,MAAU;AAC5C,UAAI,CAACN,EAAkFM,CAAK,EAAG;AAE/F,YAAMC,IAAQD,EAAM,KAAmC;AAEvD,MAAIC,MAAS,SAEXR,EAAS,QAAQO,EAAM,MAAM,UAAU,CAACE,MAAc;AACpD,QAAKR,EAAoCQ,CAAS,KAC9CA,EAAU,MAAM,WAClBJ,EAAU,IAAII,EAAU,MAAM,MAAM,GAC/BL,EAAQ,SAASK,EAAU,MAAM,MAAM,KAC1CL,EAAQ,KAAKK,EAAU,MAAM,MAAM;AAAA,MAGzC,CAAC,IACQD,MAAS,UAAUD,EAAM,MAAM,WACnCH,EAAQ,SAASG,EAAM,MAAM,MAAM,KACtCH,EAAQ,KAAKG,EAAM,MAAM,MAAM,GAE7BA,EAAM,MAAM,kBAAkB,UAChCD,EAAgB,IAAIC,EAAM,MAAM,MAAM;AAAA,IAG5C,CAAC;AAED,UAAMG,IAAapB,IAAU,CAAC,GAAGc,CAAO,EAAE,YAAYA;AACtD,WAAOO,EAAkBD,GAAYL,GAAWC,CAAe;AAAA,EACjE,GAAG,CAACR,GAAkBR,CAAO,CAAC,GAExBsB,IAAWC,EAAY,CAACC,GAAqBC,MAAwB;AACzE,IAAAtB,EAAgB,OAAQuB,EAAiBC,GAAMH,GAAaC,GAAaZ,CAAY,CAAC;AAAA,EACxF,GAAG,CAACA,CAAY,CAAC;AAEjB,EAAAe,EAAWrB,GAASe,CAAQ;AAE5B,QAAMO,IAAYpB,EAAQ,MAAMqB,EAAgB5B,CAAY,GAAG,CAACA,CAAY,CAAC,GAEvE6B,IAAWtB;AAAA,IACf,OAAO,EAAE,WAAAoB,EAAA;AAAA,IACT,CAACA,CAAS;AAAA,EAAA,GAGNG,IAAa,CAAC,YAAYjC,KAAW,oBAAoBC,KAAW,oBAAoBH,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAEjI,2BACGoC,GAAA,EAAgB,OAAOF,GACtB,UAAA,gBAAAG,EAAC,MAAA,EAAG,KAAK3B,GAAS,WAAWyB,GAAY,OAAO,EAAE,GAAGlC,GAAO,iBAAiBI,EAAa,OAAA,GACvF,aACH,GACF;AAEJ,CAAC;"}
1
+ {"version":3,"file":"Overflow.js","sources":["../../../src/components/Overflow/Overflow.tsx"],"sourcesContent":["import { Children, Fragment, forwardRef, isValidElement, type ReactNode, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport './Overflow.css';\nimport OverflowContext from './OverflowContext';\nimport { type AppliedStep, buildOrderedSteps, computeNextSteps, deriveHiddenMap } from './overflowSteps';\nimport { useResizer } from './useResizer';\n\nexport interface OverflowProps {\n children: ReactNode;\n className?: string;\n style?: React.CSSProperties;\n compact?: boolean;\n reverse?: boolean;\n}\n\nconst Overflow = forwardRef<HTMLUListElement, OverflowProps>(function Overflow({ children, className, style, compact, reverse }, ref) {\n const [appliedSteps, setAppliedSteps] = useState<AppliedStep[]>([]);\n const internalRef = useRef<HTMLUListElement | null>(null);\n const listRef = (ref ?? internalRef) as React.RefObject<HTMLUListElement | null>;\n\n // Unwrap a single top-level Fragment so items work in Storybook args, etc.\n const resolvedChildren = useMemo(() => Children.toArray(\n Children.count(children) === 1 && isValidElement<{ children: ReactNode }>(children) && children.type === Fragment\n ? children.props.children\n : children,\n ), [children]);\n\n // Build ordered steps by scanning resolved children using overflowRole markers\n const orderedSteps = useMemo(() => {\n const menuIds: string[] = [];\n const inMenuIds = new Set<string>();\n const minWidthMenuIds = new Set<string>();\n\n // Scan resolved children: collect menuids, detect which are in an OverflowMenu\n Children.forEach(resolvedChildren, (child) => {\n if (!isValidElement<{ menuid?: string; children?: ReactNode; minStateWidth?: string }>(child)) return;\n\n const role = (child.type as { overflowRole?: string }).overflowRole;\n\n if (role === 'menu') {\n // Scan OverflowMenu children for menuids that have menu representation\n Children.forEach(child.props.children, (menuChild) => {\n if (!isValidElement<{ menuid?: string }>(menuChild)) return;\n if (menuChild.props.menuid) {\n inMenuIds.add(menuChild.props.menuid);\n if (!menuIds.includes(menuChild.props.menuid)) {\n menuIds.push(menuChild.props.menuid);\n }\n }\n });\n } else if (role === 'item' && child.props.menuid) {\n if (!menuIds.includes(child.props.menuid)) {\n menuIds.push(child.props.menuid);\n }\n if (child.props.minStateWidth !== undefined) {\n minWidthMenuIds.add(child.props.menuid);\n }\n }\n });\n\n const orderedIds = reverse ? [...menuIds].reverse() : menuIds;\n return buildOrderedSteps(orderedIds, inMenuIds, minWidthMenuIds);\n }, [resolvedChildren, reverse]);\n\n // Measure and collapse/expand after each render until stable.\n // useLayoutEffect runs synchronously after DOM mutations but before paint,\n // so all collapsing settles in one frame — no intermediate flicker.\n useLayoutEffect(() => {\n const element = listRef.current;\n if (!element) return;\n setAppliedSteps(prev =>\n computeNextSteps(prev, element.scrollWidth, element.clientWidth, orderedSteps)\n );\n }, [appliedSteps, orderedSteps, listRef]);\n\n // Re-measure when the container is externally resized (window resize, parent layout change)\n const onResize = () => {\n const element = listRef.current;\n if (!element) return;\n setAppliedSteps(prev =>\n computeNextSteps(prev, element.scrollWidth, element.clientWidth, orderedSteps)\n );\n };\n\n useResizer(listRef, onResize);\n\n const hiddenMap = useMemo(() => deriveHiddenMap(appliedSteps), [appliedSteps]);\n\n const ctxValue = useMemo(\n () => ({ hiddenMap }),\n [hiddenMap],\n );\n\n const classNames = ['overflow', compact && 'overflow-compact', reverse && 'overflow-reverse', className].filter(Boolean).join(' ');\n\n return (\n <OverflowContext value={ctxValue}>\n <ul ref={listRef} className={classNames} style={{ ...style, '--hiddenCount': appliedSteps.length } as React.CSSProperties}>\n {resolvedChildren}\n </ul>\n </OverflowContext>\n );\n});\n\nexport default Overflow;\n"],"names":["Overflow","forwardRef","children","className","style","compact","reverse","ref","appliedSteps","setAppliedSteps","useState","internalRef","useRef","listRef","resolvedChildren","useMemo","Children","isValidElement","Fragment","orderedSteps","menuIds","inMenuIds","minWidthMenuIds","child","role","menuChild","orderedIds","buildOrderedSteps","useLayoutEffect","element","computeNextSteps","prev","useResizer","hiddenMap","deriveHiddenMap","ctxValue","classNames","OverflowContext","jsx"],"mappings":";;;;;;AAcA,MAAMA,IAAWC,EAA4C,SAAkB,EAAE,UAAAC,GAAU,WAAAC,GAAW,OAAAC,GAAO,SAAAC,GAAS,SAAAC,EAAA,GAAWC,GAAK;AACpI,QAAM,CAACC,GAAcC,CAAe,IAAIC,EAAwB,CAAA,CAAE,GAC5DC,IAAcC,EAAgC,IAAI,GAClDC,IAAWN,KAAOI,GAGlBG,IAAmBC,EAAQ,MAAMC,EAAS;AAAA,IAC9CA,EAAS,MAAMd,CAAQ,MAAM,KAAKe,EAAwCf,CAAQ,KAAKA,EAAS,SAASgB,IACrGhB,EAAS,MAAM,WACfA;AAAA,EAAA,GACH,CAACA,CAAQ,CAAC,GAGPiB,IAAeJ,EAAQ,MAAM;AACjC,UAAMK,IAAoB,CAAA,GACpBC,wBAAgB,IAAA,GAChBC,wBAAsB,IAAA;AAG5B,IAAAN,EAAS,QAAQF,GAAkB,CAACS,MAAU;AAC5C,UAAI,CAACN,EAAkFM,CAAK,EAAG;AAE/F,YAAMC,IAAQD,EAAM,KAAmC;AAEvD,MAAIC,MAAS,SAEXR,EAAS,QAAQO,EAAM,MAAM,UAAU,CAACE,MAAc;AACpD,QAAKR,EAAoCQ,CAAS,KAC9CA,EAAU,MAAM,WAClBJ,EAAU,IAAII,EAAU,MAAM,MAAM,GAC/BL,EAAQ,SAASK,EAAU,MAAM,MAAM,KAC1CL,EAAQ,KAAKK,EAAU,MAAM,MAAM;AAAA,MAGzC,CAAC,IACQD,MAAS,UAAUD,EAAM,MAAM,WACnCH,EAAQ,SAASG,EAAM,MAAM,MAAM,KACtCH,EAAQ,KAAKG,EAAM,MAAM,MAAM,GAE7BA,EAAM,MAAM,kBAAkB,UAChCD,EAAgB,IAAIC,EAAM,MAAM,MAAM;AAAA,IAG5C,CAAC;AAED,UAAMG,IAAapB,IAAU,CAAC,GAAGc,CAAO,EAAE,YAAYA;AACtD,WAAOO,EAAkBD,GAAYL,GAAWC,CAAe;AAAA,EACjE,GAAG,CAACR,GAAkBR,CAAO,CAAC;AAK9B,EAAAsB,EAAgB,MAAM;AACpB,UAAMC,IAAUhB,EAAQ;AACxB,IAAKgB,KACLpB;AAAA,MAAgB,OACdqB,EAAiBC,GAAMF,EAAQ,aAAaA,EAAQ,aAAaV,CAAY;AAAA,IAAA;AAAA,EAEjF,GAAG,CAACX,GAAcW,GAAcN,CAAO,CAAC,GAWxCmB,EAAWnB,GARM,MAAM;AACrB,UAAMgB,IAAUhB,EAAQ;AACxB,IAAKgB,KACLpB;AAAA,MAAgB,OACdqB,EAAiBC,GAAMF,EAAQ,aAAaA,EAAQ,aAAaV,CAAY;AAAA,IAAA;AAAA,EAEjF,CAE4B;AAE5B,QAAMc,IAAYlB,EAAQ,MAAMmB,EAAgB1B,CAAY,GAAG,CAACA,CAAY,CAAC,GAEvE2B,IAAWpB;AAAA,IACf,OAAO,EAAE,WAAAkB,EAAA;AAAA,IACT,CAACA,CAAS;AAAA,EAAA,GAGNG,IAAa,CAAC,YAAY/B,KAAW,oBAAoBC,KAAW,oBAAoBH,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAEjI,2BACGkC,GAAA,EAAgB,OAAOF,GACtB,UAAA,gBAAAG,EAAC,MAAA,EAAG,KAAKzB,GAAS,WAAWuB,GAAY,OAAO,EAAE,GAAGhC,GAAO,iBAAiBI,EAAa,OAAA,GACvF,aACH,GACF;AAEJ,CAAC;"}
@@ -1 +1 @@
1
- {"version":3,"file":"OverflowController.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/OverflowController.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,WAAW,CAAC;IAChB,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,WAAW,CAAC;IAChB,SAAS,EAAE,WAAW,CAAC;IACvB,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,2DAA2D;IAC3D,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,IAAI,WAAW,CAAC;IAC9B,YAAY,IAAI,UAAU,CAAC;IAC3B,SAAS,IAAI,OAAO,CAAC;IACrB,SAAS,IAAI,OAAO,CAAC;CACtB;AAyBD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,EAAE,CAA+B;IACzC,OAAO,CAAC,QAAQ,CAA2D;gBAE/D,IAAI,EAAE,YAAY;IAI9B,iDAAiD;IACjD,OAAO,IAAI,IAAI;IAKf,kDAAkD;IAClD,UAAU,IAAI,IAAI;IAMlB,oEAAoE;IACpE,MAAM,IAAI,IAAI;IAQd,OAAO,CAAC,IAAI;IAmBZ,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,UAAU;IAmDlB,OAAO,CAAC,cAAc;IAkCtB,OAAO,CAAC,mBAAmB;IAmD3B,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,UAAU;CA8BnB"}
1
+ {"version":3,"file":"OverflowController.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/OverflowController.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,WAAW,CAAC;IAChB,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,WAAW,CAAC;IAChB,SAAS,EAAE,WAAW,CAAC;IACvB,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,2DAA2D;IAC3D,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,IAAI,WAAW,CAAC;IAC9B,YAAY,IAAI,UAAU,CAAC;IAC3B,SAAS,IAAI,OAAO,CAAC;IACrB,SAAS,IAAI,OAAO,CAAC;CACtB;AAyBD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,EAAE,CAA+B;IACzC,OAAO,CAAC,QAAQ,CAA2D;gBAE/D,IAAI,EAAE,YAAY;IAI9B,iDAAiD;IACjD,OAAO,IAAI,IAAI;IAKf,kDAAkD;IAClD,UAAU,IAAI,IAAI;IAMlB,oEAAoE;IACpE,MAAM,IAAI,IAAI;IAQd,OAAO,CAAC,IAAI;IAmBZ,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,QAAQ;IAoBhB,OAAO,CAAC,UAAU;IAmDlB,OAAO,CAAC,cAAc;IAkCtB,OAAO,CAAC,mBAAmB;IAmD3B,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,UAAU;CA8BnB"}
@@ -49,13 +49,17 @@ class g {
49
49
  this.ro = new ResizeObserver(() => this.onResize()), this.ro.observe(t), this.onResize(), this.applyState();
50
50
  }
51
51
  onResize() {
52
- const t = this.host.getContainerEl(), { scrollWidth: e, clientWidth: s } = t, n = f(
53
- this.appliedSteps,
54
- e,
55
- s,
56
- this.orderedSteps
57
- );
58
- n !== this.appliedSteps && (this.appliedSteps = n, this.applyState());
52
+ const t = this.host.getContainerEl();
53
+ for (; ; ) {
54
+ const { scrollWidth: e, clientWidth: s } = t, n = f(
55
+ this.appliedSteps,
56
+ e,
57
+ s,
58
+ this.orderedSteps
59
+ );
60
+ if (n === this.appliedSteps) break;
61
+ this.appliedSteps = n, this.applyState();
62
+ }
59
63
  }
60
64
  applyState() {
61
65
  const t = S(this.appliedSteps);
@@ -1 +1 @@
1
- {"version":3,"file":"OverflowController.js","sources":["../../../src/components/Overflow/OverflowController.ts"],"sourcesContent":["import {\n type AppliedStep,\n type Step,\n buildOrderedSteps,\n computeNextSteps,\n deriveHiddenMap,\n} from './overflowSteps';\n\n/* ── Public types ───────────────────────────────────────── */\n\nexport interface ScannedItem {\n el: HTMLElement;\n buttonEl: HTMLElement | null;\n menuid: string | undefined;\n minStateWidth: string | undefined;\n}\n\nexport interface ScannedMenu {\n el: HTMLElement;\n triggerEl: HTMLElement;\n menuItemEls: HTMLElement[];\n inMenuIds: Set<string>;\n hasMenuOnlyItems: boolean;\n}\n\nexport interface ScanResult {\n items: ScannedItem[];\n menu: ScannedMenu | null;\n /** true when the menu appears before items in DOM order */\n menuFirst: boolean;\n}\n\nexport interface OverflowHost {\n getContainerEl(): HTMLElement;\n scanChildren(): ScanResult;\n isCompact(): boolean;\n isReverse(): boolean;\n}\n\n/* ── Shared style constants (kebab-case for setProperty) ── */\n\nconst MIN_STATE_STYLES: Record<string, string> = {\n 'font-size': '0',\n 'min-width': '100%',\n 'width': '100%',\n 'max-width': '100%',\n 'align-items': 'center',\n 'justify-content': 'center',\n 'gap': '0',\n};\n\nconst MIN_STATE_KEYS = Object.keys(MIN_STATE_STYLES);\n\nconst CORNER_PROPS = [\n 'border-top-left-radius',\n 'border-bottom-left-radius',\n 'border-top-right-radius',\n 'border-bottom-right-radius',\n] as const;\n\n/* ── Controller ─────────────────────────────────────────── */\n\nexport class OverflowController {\n private host: OverflowHost;\n private orderedSteps: Step[] = [];\n private appliedSteps: AppliedStep[] = [];\n private ro: ResizeObserver | null = null;\n private lastScan: ScanResult = { items: [], menu: null, menuFirst: false };\n\n constructor(host: OverflowHost) {\n this.host = host;\n }\n\n /** Start observing (call after DOM is ready). */\n connect(): void {\n this.scan();\n this.startObserver();\n }\n\n /** Stop observing and clear all applied state. */\n disconnect(): void {\n this.ro?.disconnect();\n this.ro = null;\n this.clearState();\n }\n\n /** Re-scan children + restart (call after external DOM changes). */\n update(): void {\n this.appliedSteps = [];\n this.scan();\n this.startObserver();\n }\n\n /* ── Private ──────────────────────────────────────────── */\n\n private scan(): void {\n this.lastScan = this.host.scanChildren();\n\n const menuIds: string[] = [];\n const minWidthMenuIds = new Set<string>();\n\n for (const item of this.lastScan.items) {\n if (item.menuid) {\n menuIds.push(item.menuid);\n if (item.minStateWidth) minWidthMenuIds.add(item.menuid);\n }\n }\n\n const inMenuIds = this.lastScan.menu?.inMenuIds ?? new Set<string>();\n const isReverse = this.host.isReverse();\n const ids = isReverse ? [...menuIds].reverse() : menuIds;\n this.orderedSteps = buildOrderedSteps(ids, inMenuIds, minWidthMenuIds);\n }\n\n private startObserver(): void {\n this.ro?.disconnect();\n const container = this.host.getContainerEl();\n this.ro = new ResizeObserver(() => this.onResize());\n this.ro.observe(container);\n this.onResize();\n this.applyState();\n }\n\n private onResize(): void {\n const container = this.host.getContainerEl();\n const { scrollWidth, clientWidth } = container;\n const next = computeNextSteps(\n this.appliedSteps,\n scrollWidth,\n clientWidth,\n this.orderedSteps,\n );\n if (next !== this.appliedSteps) {\n this.appliedSteps = next;\n this.applyState();\n }\n }\n\n private applyState(): void {\n const hiddenMap = deriveHiddenMap(this.appliedSteps);\n const container = this.host.getContainerEl();\n container.style.setProperty('--hiddenCount', String(this.appliedSteps.length));\n\n const isCompact = this.host.isCompact();\n const isReverse = this.host.isReverse();\n\n let anyFullyHidden = false;\n const visibleItems: ScannedItem[] = [];\n\n // Apply item states\n for (const item of this.lastScan.items) {\n const state = item.menuid\n ? (hiddenMap.get(item.menuid) ?? 'visible')\n : 'visible';\n\n item.el.setAttribute('data-state', state);\n\n if (state === 'visible') {\n item.el.style.removeProperty('display');\n item.el.style.removeProperty('max-width');\n item.el.style.removeProperty('overflow');\n this.clearMinStyles(item.buttonEl);\n visibleItems.push(item);\n } else if (state === 'min') {\n item.el.style.removeProperty('display');\n item.el.style.setProperty('max-width', item.minStateWidth ?? '2.25rem');\n item.el.style.setProperty('overflow', 'hidden');\n this.applyMinStyles(item.buttonEl);\n visibleItems.push(item);\n } else {\n // hidden\n item.el.style.setProperty('display', 'none');\n item.el.style.removeProperty('max-width');\n item.el.style.removeProperty('overflow');\n this.clearMinStyles(item.buttonEl);\n anyFullyHidden = true;\n }\n }\n\n // Menu\n const { menu, menuFirst } = this.lastScan;\n const menuVisible = this.applyMenuState(menu, hiddenMap, anyFullyHidden);\n\n // Compact corners\n this.applyCompactCorners(\n visibleItems, menu, menuFirst, menuVisible, isCompact, isReverse,\n );\n }\n\n private applyMenuState(\n menu: ScannedMenu | null,\n hiddenMap: Map<string, 'min' | 'hidden'>,\n anyFullyHidden: boolean,\n ): boolean {\n if (!menu) return false;\n\n const showOpener = anyFullyHidden || menu.hasMenuOnlyItems;\n menu.el.style.setProperty('display', showOpener ? '' : 'none');\n menu.el.setAttribute('data-state', showOpener ? 'visible' : 'hidden');\n\n // Opener trigger styles (icon-only display)\n if (showOpener) {\n this.applyMinStyles(menu.triggerEl);\n } else {\n this.clearMinStyles(menu.triggerEl);\n }\n\n // Show/hide individual menu items\n for (const mi of menu.menuItemEls) {\n const mid = mi.getAttribute('menuid') ?? mi.dataset.menuid;\n if (!mid) {\n // Menu-only item — always visible\n mi.style.removeProperty('display');\n } else if (hiddenMap.get(mid) === 'hidden') {\n mi.style.removeProperty('display');\n } else {\n mi.style.setProperty('display', 'none');\n }\n }\n\n return showOpener;\n }\n\n private applyCompactCorners(\n visibleItems: ScannedItem[],\n menu: ScannedMenu | null,\n menuFirst: boolean,\n menuVisible: boolean,\n isCompact: boolean,\n isReverse: boolean,\n ): void {\n for (let i = 0; i < visibleItems.length; i++) {\n const btn = visibleItems[i].buttonEl;\n if (!btn) continue;\n\n const isFirst = i === 0;\n const isLast = i === visibleItems.length - 1;\n\n // Determine adjacency based on menu position\n const hasPrev = menuFirst\n ? (!isFirst || menuVisible)\n : !isFirst;\n const hasNext = menuFirst\n ? !isLast\n : (!isLast || menuVisible);\n\n // Normal (row): prev = left, next = right\n // Reverse (row-reverse): prev = right, next = left\n this.setCorners(btn,\n isCompact && (isReverse ? hasNext : hasPrev),\n isCompact && (isReverse ? hasPrev : hasNext),\n );\n }\n\n // Menu trigger corners\n if (menu?.triggerEl) {\n const hasAdjacentItem = menuVisible && visibleItems.length > 0;\n\n if (menuFirst) {\n // Menu first in DOM → left in normal, right in reverse\n this.setCorners(menu.triggerEl,\n isCompact && hasAdjacentItem && isReverse,\n isCompact && hasAdjacentItem && !isReverse,\n );\n } else {\n // Menu last in DOM → right in normal, left in reverse\n this.setCorners(menu.triggerEl,\n isCompact && hasAdjacentItem && !isReverse,\n isCompact && hasAdjacentItem && isReverse,\n );\n }\n }\n }\n\n private setCorners(\n el: HTMLElement,\n squareLeft: boolean,\n squareRight: boolean,\n ): void {\n el.style.borderTopLeftRadius = squareLeft ? '0' : '';\n el.style.borderBottomLeftRadius = squareLeft ? '0' : '';\n el.style.borderTopRightRadius = squareRight ? '0' : '';\n el.style.borderBottomRightRadius = squareRight ? '0' : '';\n }\n\n private applyMinStyles(el: HTMLElement | null): void {\n if (!el) return;\n for (const key of MIN_STATE_KEYS) {\n el.style.setProperty(key, MIN_STATE_STYLES[key]);\n }\n }\n\n private clearMinStyles(el: HTMLElement | null): void {\n if (!el) return;\n for (const key of MIN_STATE_KEYS) {\n el.style.removeProperty(key);\n }\n }\n\n private clearState(): void {\n const container = this.host.getContainerEl();\n container.style.removeProperty('--hiddenCount');\n\n for (const item of this.lastScan.items) {\n item.el.removeAttribute('data-state');\n item.el.style.removeProperty('display');\n item.el.style.removeProperty('max-width');\n item.el.style.removeProperty('overflow');\n this.clearMinStyles(item.buttonEl);\n if (item.buttonEl) {\n for (const prop of CORNER_PROPS) {\n item.buttonEl.style.removeProperty(prop);\n }\n }\n }\n\n const menu = this.lastScan.menu;\n if (menu) {\n menu.el.removeAttribute('data-state');\n menu.el.style.removeProperty('display');\n this.clearMinStyles(menu.triggerEl);\n for (const prop of CORNER_PROPS) {\n menu.triggerEl.style.removeProperty(prop);\n }\n for (const mi of menu.menuItemEls) {\n mi.style.removeProperty('display');\n }\n }\n }\n}\n"],"names":["MIN_STATE_STYLES","MIN_STATE_KEYS","CORNER_PROPS","OverflowController","host","menuIds","minWidthMenuIds","item","inMenuIds","ids","buildOrderedSteps","container","scrollWidth","clientWidth","next","computeNextSteps","hiddenMap","deriveHiddenMap","isCompact","isReverse","anyFullyHidden","visibleItems","state","menu","menuFirst","menuVisible","showOpener","mi","mid","i","btn","isFirst","isLast","hasPrev","hasNext","hasAdjacentItem","el","squareLeft","squareRight","key","prop"],"mappings":"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"}
1
+ {"version":3,"file":"OverflowController.js","sources":["../../../src/components/Overflow/OverflowController.ts"],"sourcesContent":["import {\n type AppliedStep,\n type Step,\n buildOrderedSteps,\n computeNextSteps,\n deriveHiddenMap,\n} from './overflowSteps';\n\n/* ── Public types ───────────────────────────────────────── */\n\nexport interface ScannedItem {\n el: HTMLElement;\n buttonEl: HTMLElement | null;\n menuid: string | undefined;\n minStateWidth: string | undefined;\n}\n\nexport interface ScannedMenu {\n el: HTMLElement;\n triggerEl: HTMLElement;\n menuItemEls: HTMLElement[];\n inMenuIds: Set<string>;\n hasMenuOnlyItems: boolean;\n}\n\nexport interface ScanResult {\n items: ScannedItem[];\n menu: ScannedMenu | null;\n /** true when the menu appears before items in DOM order */\n menuFirst: boolean;\n}\n\nexport interface OverflowHost {\n getContainerEl(): HTMLElement;\n scanChildren(): ScanResult;\n isCompact(): boolean;\n isReverse(): boolean;\n}\n\n/* ── Shared style constants (kebab-case for setProperty) ── */\n\nconst MIN_STATE_STYLES: Record<string, string> = {\n 'font-size': '0',\n 'min-width': '100%',\n 'width': '100%',\n 'max-width': '100%',\n 'align-items': 'center',\n 'justify-content': 'center',\n 'gap': '0',\n};\n\nconst MIN_STATE_KEYS = Object.keys(MIN_STATE_STYLES);\n\nconst CORNER_PROPS = [\n 'border-top-left-radius',\n 'border-bottom-left-radius',\n 'border-top-right-radius',\n 'border-bottom-right-radius',\n] as const;\n\n/* ── Controller ─────────────────────────────────────────── */\n\nexport class OverflowController {\n private host: OverflowHost;\n private orderedSteps: Step[] = [];\n private appliedSteps: AppliedStep[] = [];\n private ro: ResizeObserver | null = null;\n private lastScan: ScanResult = { items: [], menu: null, menuFirst: false };\n\n constructor(host: OverflowHost) {\n this.host = host;\n }\n\n /** Start observing (call after DOM is ready). */\n connect(): void {\n this.scan();\n this.startObserver();\n }\n\n /** Stop observing and clear all applied state. */\n disconnect(): void {\n this.ro?.disconnect();\n this.ro = null;\n this.clearState();\n }\n\n /** Re-scan children + restart (call after external DOM changes). */\n update(): void {\n this.appliedSteps = [];\n this.scan();\n this.startObserver();\n }\n\n /* ── Private ──────────────────────────────────────────── */\n\n private scan(): void {\n this.lastScan = this.host.scanChildren();\n\n const menuIds: string[] = [];\n const minWidthMenuIds = new Set<string>();\n\n for (const item of this.lastScan.items) {\n if (item.menuid) {\n menuIds.push(item.menuid);\n if (item.minStateWidth) minWidthMenuIds.add(item.menuid);\n }\n }\n\n const inMenuIds = this.lastScan.menu?.inMenuIds ?? new Set<string>();\n const isReverse = this.host.isReverse();\n const ids = isReverse ? [...menuIds].reverse() : menuIds;\n this.orderedSteps = buildOrderedSteps(ids, inMenuIds, minWidthMenuIds);\n }\n\n private startObserver(): void {\n this.ro?.disconnect();\n const container = this.host.getContainerEl();\n this.ro = new ResizeObserver(() => this.onResize());\n this.ro.observe(container);\n this.onResize();\n this.applyState();\n }\n\n private onResize(): void {\n const container = this.host.getContainerEl();\n\n // Loop until stable — each applyState() mutates the DOM synchronously,\n // so the next iteration gets updated dimensions.\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { scrollWidth, clientWidth } = container;\n const next = computeNextSteps(\n this.appliedSteps,\n scrollWidth,\n clientWidth,\n this.orderedSteps,\n );\n if (next === this.appliedSteps) break;\n this.appliedSteps = next;\n this.applyState();\n }\n }\n\n private applyState(): void {\n const hiddenMap = deriveHiddenMap(this.appliedSteps);\n const container = this.host.getContainerEl();\n container.style.setProperty('--hiddenCount', String(this.appliedSteps.length));\n\n const isCompact = this.host.isCompact();\n const isReverse = this.host.isReverse();\n\n let anyFullyHidden = false;\n const visibleItems: ScannedItem[] = [];\n\n // Apply item states\n for (const item of this.lastScan.items) {\n const state = item.menuid\n ? (hiddenMap.get(item.menuid) ?? 'visible')\n : 'visible';\n\n item.el.setAttribute('data-state', state);\n\n if (state === 'visible') {\n item.el.style.removeProperty('display');\n item.el.style.removeProperty('max-width');\n item.el.style.removeProperty('overflow');\n this.clearMinStyles(item.buttonEl);\n visibleItems.push(item);\n } else if (state === 'min') {\n item.el.style.removeProperty('display');\n item.el.style.setProperty('max-width', item.minStateWidth ?? '2.25rem');\n item.el.style.setProperty('overflow', 'hidden');\n this.applyMinStyles(item.buttonEl);\n visibleItems.push(item);\n } else {\n // hidden\n item.el.style.setProperty('display', 'none');\n item.el.style.removeProperty('max-width');\n item.el.style.removeProperty('overflow');\n this.clearMinStyles(item.buttonEl);\n anyFullyHidden = true;\n }\n }\n\n // Menu\n const { menu, menuFirst } = this.lastScan;\n const menuVisible = this.applyMenuState(menu, hiddenMap, anyFullyHidden);\n\n // Compact corners\n this.applyCompactCorners(\n visibleItems, menu, menuFirst, menuVisible, isCompact, isReverse,\n );\n }\n\n private applyMenuState(\n menu: ScannedMenu | null,\n hiddenMap: Map<string, 'min' | 'hidden'>,\n anyFullyHidden: boolean,\n ): boolean {\n if (!menu) return false;\n\n const showOpener = anyFullyHidden || menu.hasMenuOnlyItems;\n menu.el.style.setProperty('display', showOpener ? '' : 'none');\n menu.el.setAttribute('data-state', showOpener ? 'visible' : 'hidden');\n\n // Opener trigger styles (icon-only display)\n if (showOpener) {\n this.applyMinStyles(menu.triggerEl);\n } else {\n this.clearMinStyles(menu.triggerEl);\n }\n\n // Show/hide individual menu items\n for (const mi of menu.menuItemEls) {\n const mid = mi.getAttribute('menuid') ?? mi.dataset.menuid;\n if (!mid) {\n // Menu-only item — always visible\n mi.style.removeProperty('display');\n } else if (hiddenMap.get(mid) === 'hidden') {\n mi.style.removeProperty('display');\n } else {\n mi.style.setProperty('display', 'none');\n }\n }\n\n return showOpener;\n }\n\n private applyCompactCorners(\n visibleItems: ScannedItem[],\n menu: ScannedMenu | null,\n menuFirst: boolean,\n menuVisible: boolean,\n isCompact: boolean,\n isReverse: boolean,\n ): void {\n for (let i = 0; i < visibleItems.length; i++) {\n const btn = visibleItems[i].buttonEl;\n if (!btn) continue;\n\n const isFirst = i === 0;\n const isLast = i === visibleItems.length - 1;\n\n // Determine adjacency based on menu position\n const hasPrev = menuFirst\n ? (!isFirst || menuVisible)\n : !isFirst;\n const hasNext = menuFirst\n ? !isLast\n : (!isLast || menuVisible);\n\n // Normal (row): prev = left, next = right\n // Reverse (row-reverse): prev = right, next = left\n this.setCorners(btn,\n isCompact && (isReverse ? hasNext : hasPrev),\n isCompact && (isReverse ? hasPrev : hasNext),\n );\n }\n\n // Menu trigger corners\n if (menu?.triggerEl) {\n const hasAdjacentItem = menuVisible && visibleItems.length > 0;\n\n if (menuFirst) {\n // Menu first in DOM → left in normal, right in reverse\n this.setCorners(menu.triggerEl,\n isCompact && hasAdjacentItem && isReverse,\n isCompact && hasAdjacentItem && !isReverse,\n );\n } else {\n // Menu last in DOM → right in normal, left in reverse\n this.setCorners(menu.triggerEl,\n isCompact && hasAdjacentItem && !isReverse,\n isCompact && hasAdjacentItem && isReverse,\n );\n }\n }\n }\n\n private setCorners(\n el: HTMLElement,\n squareLeft: boolean,\n squareRight: boolean,\n ): void {\n el.style.borderTopLeftRadius = squareLeft ? '0' : '';\n el.style.borderBottomLeftRadius = squareLeft ? '0' : '';\n el.style.borderTopRightRadius = squareRight ? '0' : '';\n el.style.borderBottomRightRadius = squareRight ? '0' : '';\n }\n\n private applyMinStyles(el: HTMLElement | null): void {\n if (!el) return;\n for (const key of MIN_STATE_KEYS) {\n el.style.setProperty(key, MIN_STATE_STYLES[key]);\n }\n }\n\n private clearMinStyles(el: HTMLElement | null): void {\n if (!el) return;\n for (const key of MIN_STATE_KEYS) {\n el.style.removeProperty(key);\n }\n }\n\n private clearState(): void {\n const container = this.host.getContainerEl();\n container.style.removeProperty('--hiddenCount');\n\n for (const item of this.lastScan.items) {\n item.el.removeAttribute('data-state');\n item.el.style.removeProperty('display');\n item.el.style.removeProperty('max-width');\n item.el.style.removeProperty('overflow');\n this.clearMinStyles(item.buttonEl);\n if (item.buttonEl) {\n for (const prop of CORNER_PROPS) {\n item.buttonEl.style.removeProperty(prop);\n }\n }\n }\n\n const menu = this.lastScan.menu;\n if (menu) {\n menu.el.removeAttribute('data-state');\n menu.el.style.removeProperty('display');\n this.clearMinStyles(menu.triggerEl);\n for (const prop of CORNER_PROPS) {\n menu.triggerEl.style.removeProperty(prop);\n }\n for (const mi of menu.menuItemEls) {\n mi.style.removeProperty('display');\n }\n }\n }\n}\n"],"names":["MIN_STATE_STYLES","MIN_STATE_KEYS","CORNER_PROPS","OverflowController","host","menuIds","minWidthMenuIds","item","inMenuIds","ids","buildOrderedSteps","container","scrollWidth","clientWidth","next","computeNextSteps","hiddenMap","deriveHiddenMap","isCompact","isReverse","anyFullyHidden","visibleItems","state","menu","menuFirst","menuVisible","showOpener","mi","mid","i","btn","isFirst","isLast","hasPrev","hasNext","hasAdjacentItem","el","squareLeft","squareRight","key","prop"],"mappings":"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"}
@@ -5,12 +5,16 @@ export interface RenderMenuProps {
5
5
  onClose: () => void;
6
6
  children: ReactNode;
7
7
  }
8
- interface OverflowMenuProps {
8
+ export interface OverflowMenuControlProps {
9
+ open?: boolean;
10
+ onOpenChange?: (open: boolean) => void;
11
+ }
12
+ interface OverflowMenuProps extends OverflowMenuControlProps {
9
13
  opener: ReactNode;
10
14
  children: ReactNode;
11
15
  renderMenu: (props: RenderMenuProps) => ReactNode;
12
16
  }
13
- declare function OverflowMenu({ opener, children, renderMenu }: OverflowMenuProps): import("react/jsx-runtime").JSX.Element;
17
+ declare function OverflowMenu({ opener, children, renderMenu, open: controlledOpen, onOpenChange }: OverflowMenuProps): import("react/jsx-runtime").JSX.Element;
14
18
  declare const _default: typeof OverflowMenu & {
15
19
  overflowRole: "menu";
16
20
  };
@@ -1 +1 @@
1
- {"version":3,"file":"OverflowMenu.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/OverflowMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6D,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;AAI/H,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,UAAU,iBAAiB;IACzB,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,SAAS,CAAC;CACnD;AAED,iBAAS,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,iBAAiB,2CAqExE;;;;AAED,wBAA8E"}
1
+ {"version":3,"file":"OverflowMenu.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/OverflowMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;AAI9F,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED,UAAU,iBAAkB,SAAQ,wBAAwB;IAC1D,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,SAAS,CAAC;CACnD;AAED,iBAAS,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,iBAAiB,2CA4E5G;;;;AAED,wBAA8E"}
@@ -1,36 +1,42 @@
1
- import { jsxs as M, Fragment as j, jsx as x } from "react/jsx-runtime";
2
- import { useState as H, useRef as b, useEffect as R, Children as $, isValidElement as l, cloneElement as m } from "react";
3
- import { useOverflow as A } from "./OverflowContext.js";
4
- function B({ opener: s, children: f, renderMenu: h }) {
5
- const { hiddenMap: i } = A(), [c, t] = H(null), p = !!c, n = [...i.values()].some((e) => e === "hidden"), d = b(n);
6
- R(() => {
7
- d.current && !n && t(null), d.current = n;
8
- }, [n]);
9
- const v = (e) => {
10
- t(e.currentTarget);
11
- }, u = () => {
12
- t(null);
13
- }, r = [];
14
- $.forEach(f, (e) => {
15
- l(e) && r.push({ menuid: e.props.menuid, content: e.props.children });
1
+ import { jsxs as j, Fragment as x, jsx as H } from "react/jsx-runtime";
2
+ import { useState as R, useRef as m, useEffect as h, Children as v, isValidElement as A } from "react";
3
+ import { useOverflow as k } from "./OverflowContext.js";
4
+ function B({ opener: p, children: E, renderMenu: w, open: t, onOpenChange: s }) {
5
+ const { hiddenMap: d } = k(), [c, o] = R(null), l = m(null), r = t !== void 0, i = r ? t : !!c, n = [...d.values()].some((e) => e === "hidden"), f = m(n);
6
+ h(() => {
7
+ f.current && !n && i && (o(null), s?.(!1)), f.current = n;
8
+ }, [n, i, s]), h(() => {
9
+ r && !t && o(null);
10
+ }, [r, t]);
11
+ const y = () => {
12
+ const e = l.current?.firstElementChild;
13
+ o(e ?? l.current), i || s?.(!0);
14
+ }, C = () => {
15
+ r || o(null), s?.(!1);
16
+ }, u = [];
17
+ v.forEach(E, (e) => {
18
+ A(e) && u.push({ menuid: e.props.menuid, content: e.props.children });
16
19
  });
17
- const C = r.filter(({ menuid: e }) => e === void 0 ? !0 : i.get(e) === "hidden"), E = r.some(({ menuid: e }) => e === void 0), a = !n && !E, O = l(s) ? m(s, { onClick: v }) : s, g = C.map(({ menuid: e, content: o }, w) => {
18
- const k = e ?? `menu-item-${w}`;
19
- return l(o) ? m(o, {
20
- key: k,
21
- onClick: (...y) => {
22
- const I = o.props.onClick;
23
- I?.(...y), u();
20
+ const I = u.filter(({ menuid: e }) => e === void 0 ? !0 : d.get(e) === "hidden"), M = u.some(({ menuid: e }) => e === void 0), a = !n && !M, b = v.toArray(
21
+ I.map(({ content: e }) => e)
22
+ );
23
+ return /* @__PURE__ */ j(x, { children: [
24
+ /* @__PURE__ */ H(
25
+ "li",
26
+ {
27
+ ref: l,
28
+ className: "overflow-opener",
29
+ "data-state": a ? "hidden" : void 0,
30
+ style: a ? { display: "none" } : void 0,
31
+ onClick: y,
32
+ children: p
24
33
  }
25
- }) : o;
26
- });
27
- return /* @__PURE__ */ M(j, { children: [
28
- /* @__PURE__ */ x("li", { className: "overflow-opener", "data-state": a ? "hidden" : void 0, style: a ? { display: "none" } : void 0, children: O }),
29
- h({ anchorEl: c, open: p, onClose: u, children: g })
34
+ ),
35
+ w({ anchorEl: c, open: i, onClose: C, children: b })
30
36
  ] });
31
37
  }
32
- const T = Object.assign(B, { overflowRole: "menu" });
38
+ const V = Object.assign(B, { overflowRole: "menu" });
33
39
  export {
34
- T as default
40
+ V as default
35
41
  };
36
42
  //# sourceMappingURL=OverflowMenu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OverflowMenu.js","sources":["../../../src/components/Overflow/OverflowMenu.tsx"],"sourcesContent":["import { Children, cloneElement, isValidElement, type ReactElement, type ReactNode, useEffect, useRef, useState } from 'react';\nimport { useOverflow } from './OverflowContext';\nimport type { OverflowItemProps } from './OverflowItem';\n\nexport interface RenderMenuProps {\n anchorEl: HTMLElement | null;\n open: boolean;\n onClose: () => void;\n children: ReactNode;\n}\n\ninterface OverflowMenuProps {\n opener: ReactNode;\n children: ReactNode;\n renderMenu: (props: RenderMenuProps) => ReactNode;\n}\n\nfunction OverflowMenu({ opener, children, renderMenu }: OverflowMenuProps) {\n const { hiddenMap } = useOverflow();\n const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);\n const open = Boolean(anchorEl);\n\n const hasHiddenItems = [...hiddenMap.values()].some(s => s === 'hidden');\n const prevHasHidden = useRef(hasHiddenItems);\n\n // Auto-close when no items are fully hidden\n useEffect(() => {\n if (prevHasHidden.current && !hasHiddenItems) {\n setAnchorEl(null);\n }\n prevHasHidden.current = hasHiddenItems;\n }, [hasHiddenItems]);\n\n const handleOpen = (event: React.MouseEvent<HTMLElement>) => {\n setAnchorEl(event.currentTarget);\n };\n\n const handleClose = () => {\n setAnchorEl(null);\n };\n\n // Collect menuid set from children to determine which are \"menu-only\"\n const menuItems: { menuid: string | undefined; content: ReactNode }[] = [];\n Children.forEach(children, (child) => {\n if (!isValidElement<OverflowItemProps>(child)) return;\n menuItems.push({ menuid: child.props.menuid, content: child.props.children });\n });\n\n // Determine visible menu items: show when fully hidden or menu-only\n const visibleItems = menuItems.filter(({ menuid }) => {\n if (menuid === undefined) return true; // no menuid = always shown in menu\n return hiddenMap.get(menuid) === 'hidden'; // shown when fully hidden in toolbar\n });\n\n const hasMenuOnlyItems = menuItems.some(({ menuid }) => menuid === undefined);\n const hidden = !hasHiddenItems && !hasMenuOnlyItems;\n\n // Clone opener to attach click handler\n const openerElement = isValidElement<Record<string, unknown>>(opener)\n ? cloneElement(opener as ReactElement<{ onClick?: (e: React.MouseEvent<HTMLElement>) => void }>, { onClick: handleOpen })\n : opener;\n\n const menuChildren = visibleItems.map(({ menuid, content }, i) => {\n // Wrap each menu item's content and attach close-on-click\n const key = menuid ?? `menu-item-${i}`;\n if (isValidElement<{ onClick?: () => void }>(content)) {\n return cloneElement(content as ReactElement<{ onClick?: () => void }>, {\n key,\n onClick: (...args: unknown[]) => {\n const original = (content as ReactElement<{ onClick?: (...a: unknown[]) => void }>).props.onClick;\n original?.(...args);\n handleClose();\n },\n });\n }\n return content;\n });\n\n return (\n <>\n <li className=\"overflow-opener\" data-state={hidden ? 'hidden' : undefined} style={hidden ? { display: 'none' } : undefined}>\n {openerElement}\n </li>\n {renderMenu({ anchorEl, open, onClose: handleClose, children: menuChildren })}\n </>\n );\n}\n\nexport default Object.assign(OverflowMenu, { overflowRole: 'menu' as const });\n"],"names":["OverflowMenu","opener","children","renderMenu","hiddenMap","useOverflow","anchorEl","setAnchorEl","useState","open","hasHiddenItems","s","prevHasHidden","useRef","useEffect","handleOpen","event","handleClose","menuItems","Children","child","isValidElement","visibleItems","menuid","hasMenuOnlyItems","hidden","openerElement","cloneElement","menuChildren","content","i","key","args","original","jsxs","Fragment","jsx","OverflowMenu$1"],"mappings":";;;AAiBA,SAASA,EAAa,EAAE,QAAAC,GAAQ,UAAAC,GAAU,YAAAC,KAAiC;AACzE,QAAM,EAAE,WAAAC,EAAA,IAAcC,EAAA,GAChB,CAACC,GAAUC,CAAW,IAAIC,EAA6B,IAAI,GAC3DC,IAAO,EAAQH,GAEfI,IAAiB,CAAC,GAAGN,EAAU,OAAA,CAAQ,EAAE,KAAK,CAAAO,MAAKA,MAAM,QAAQ,GACjEC,IAAgBC,EAAOH,CAAc;AAG3C,EAAAI,EAAU,MAAM;AACd,IAAIF,EAAc,WAAW,CAACF,KAC5BH,EAAY,IAAI,GAElBK,EAAc,UAAUF;AAAA,EAC1B,GAAG,CAACA,CAAc,CAAC;AAEnB,QAAMK,IAAa,CAACC,MAAyC;AAC3D,IAAAT,EAAYS,EAAM,aAAa;AAAA,EACjC,GAEMC,IAAc,MAAM;AACxB,IAAAV,EAAY,IAAI;AAAA,EAClB,GAGMW,IAAkE,CAAA;AACxE,EAAAC,EAAS,QAAQjB,GAAU,CAACkB,MAAU;AACpC,IAAKC,EAAkCD,CAAK,KAC5CF,EAAU,KAAK,EAAE,QAAQE,EAAM,MAAM,QAAQ,SAASA,EAAM,MAAM,SAAA,CAAU;AAAA,EAC9E,CAAC;AAGD,QAAME,IAAeJ,EAAU,OAAO,CAAC,EAAE,QAAAK,QACnCA,MAAW,SAAkB,KAC1BnB,EAAU,IAAImB,CAAM,MAAM,QAClC,GAEKC,IAAmBN,EAAU,KAAK,CAAC,EAAE,QAAAK,EAAA,MAAaA,MAAW,MAAS,GACtEE,IAAS,CAACf,KAAkB,CAACc,GAG7BE,IAAgBL,EAAwCpB,CAAM,IAChE0B,EAAa1B,GAAkF,EAAE,SAASc,EAAA,CAAY,IACtHd,GAEE2B,IAAeN,EAAa,IAAI,CAAC,EAAE,QAAAC,GAAQ,SAAAM,EAAA,GAAWC,MAAM;AAEhE,UAAMC,IAAMR,KAAU,aAAaO,CAAC;AACpC,WAAIT,EAAyCQ,CAAO,IAC3CF,EAAaE,GAAmD;AAAA,MACrE,KAAAE;AAAA,MACA,SAAS,IAAIC,MAAoB;AAC/B,cAAMC,IAAYJ,EAAkE,MAAM;AAC1F,QAAAI,IAAW,GAAGD,CAAI,GAClBf,EAAA;AAAA,MACF;AAAA,IAAA,CACD,IAEIY;AAAA,EACT,CAAC;AAED,SACE,gBAAAK,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAC,EAAC,MAAA,EAAG,WAAU,mBAAkB,cAAYX,IAAS,WAAW,QAAW,OAAOA,IAAS,EAAE,SAAS,OAAA,IAAW,QAC9G,UAAAC,GACH;AAAA,IACCvB,EAAW,EAAE,UAAAG,GAAU,MAAAG,GAAM,SAASQ,GAAa,UAAUW,GAAc;AAAA,EAAA,GAC9E;AAEJ;AAEA,MAAAS,IAAe,OAAO,OAAOrC,GAAc,EAAE,cAAc,QAAiB;"}
1
+ {"version":3,"file":"OverflowMenu.js","sources":["../../../src/components/Overflow/OverflowMenu.tsx"],"sourcesContent":["import { Children, isValidElement, type ReactNode, useEffect, useRef, useState } from 'react';\nimport { useOverflow } from './OverflowContext';\nimport type { OverflowItemProps } from './OverflowItem';\n\nexport interface RenderMenuProps {\n anchorEl: HTMLElement | null;\n open: boolean;\n onClose: () => void;\n children: ReactNode;\n}\n\nexport interface OverflowMenuControlProps {\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ninterface OverflowMenuProps extends OverflowMenuControlProps {\n opener: ReactNode;\n children: ReactNode;\n renderMenu: (props: RenderMenuProps) => ReactNode;\n}\n\nfunction OverflowMenu({ opener, children, renderMenu, open: controlledOpen, onOpenChange }: OverflowMenuProps) {\n const { hiddenMap } = useOverflow();\n const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);\n const openerRef = useRef<HTMLLIElement>(null);\n\n const isControlled = controlledOpen !== undefined;\n const open = isControlled ? controlledOpen : Boolean(anchorEl);\n\n const hasHiddenItems = [...hiddenMap.values()].some(s => s === 'hidden');\n const prevHasHidden = useRef(hasHiddenItems);\n\n // Auto-close when no items are fully hidden\n useEffect(() => {\n if (prevHasHidden.current && !hasHiddenItems && open) {\n setAnchorEl(null);\n onOpenChange?.(false);\n }\n prevHasHidden.current = hasHiddenItems;\n }, [hasHiddenItems, open, onOpenChange]);\n\n // Sync anchorEl when controlled open changes to false\n useEffect(() => {\n if (isControlled && !controlledOpen) {\n setAnchorEl(null);\n }\n }, [isControlled, controlledOpen]);\n\n const handleOpen = () => {\n const button = openerRef.current?.firstElementChild as HTMLElement | null;\n setAnchorEl(button ?? openerRef.current);\n if (!open) {\n onOpenChange?.(true);\n }\n };\n\n const handleClose = () => {\n if (!isControlled) {\n setAnchorEl(null);\n }\n onOpenChange?.(false);\n };\n\n // Collect menuid set from children to determine which are \"menu-only\"\n const menuItems: { menuid: string | undefined; content: ReactNode }[] = [];\n Children.forEach(children, (child) => {\n if (!isValidElement<OverflowItemProps>(child)) return;\n menuItems.push({ menuid: child.props.menuid, content: child.props.children });\n });\n\n // Determine visible menu items: show when fully hidden or menu-only\n const visibleItems = menuItems.filter(({ menuid }) => {\n if (menuid === undefined) return true; // no menuid = always shown in menu\n return hiddenMap.get(menuid) === 'hidden'; // shown when fully hidden in toolbar\n });\n\n const hasMenuOnlyItems = menuItems.some(({ menuid }) => menuid === undefined);\n const hidden = !hasHiddenItems && !hasMenuOnlyItems;\n\n const menuChildren = Children.toArray(\n visibleItems.map(({ content }) => content)\n );\n\n return (\n <>\n <li\n ref={openerRef}\n className=\"overflow-opener\"\n data-state={hidden ? 'hidden' : undefined}\n style={hidden ? { display: 'none' } : undefined}\n onClick={handleOpen}\n >\n {opener}\n </li>\n {renderMenu({ anchorEl, open, onClose: handleClose, children: menuChildren })}\n </>\n );\n}\n\nexport default Object.assign(OverflowMenu, { overflowRole: 'menu' as const });\n"],"names":["OverflowMenu","opener","children","renderMenu","controlledOpen","onOpenChange","hiddenMap","useOverflow","anchorEl","setAnchorEl","useState","openerRef","useRef","isControlled","open","hasHiddenItems","s","prevHasHidden","useEffect","handleOpen","button","handleClose","menuItems","Children","child","isValidElement","visibleItems","menuid","hasMenuOnlyItems","hidden","menuChildren","content","jsxs","Fragment","jsx","OverflowMenu$1"],"mappings":";;;AAsBA,SAASA,EAAa,EAAE,QAAAC,GAAQ,UAAAC,GAAU,YAAAC,GAAY,MAAMC,GAAgB,cAAAC,KAAmC;AAC7G,QAAM,EAAE,WAAAC,EAAA,IAAcC,EAAA,GAChB,CAACC,GAAUC,CAAW,IAAIC,EAA6B,IAAI,GAC3DC,IAAYC,EAAsB,IAAI,GAEtCC,IAAeT,MAAmB,QAClCU,IAAOD,IAAeT,IAAiB,EAAQI,GAE/CO,IAAiB,CAAC,GAAGT,EAAU,OAAA,CAAQ,EAAE,KAAK,CAAAU,MAAKA,MAAM,QAAQ,GACjEC,IAAgBL,EAAOG,CAAc;AAG3C,EAAAG,EAAU,MAAM;AACd,IAAID,EAAc,WAAW,CAACF,KAAkBD,MAC9CL,EAAY,IAAI,GAChBJ,IAAe,EAAK,IAEtBY,EAAc,UAAUF;AAAA,EAC1B,GAAG,CAACA,GAAgBD,GAAMT,CAAY,CAAC,GAGvCa,EAAU,MAAM;AACd,IAAIL,KAAgB,CAACT,KACnBK,EAAY,IAAI;AAAA,EAEpB,GAAG,CAACI,GAAcT,CAAc,CAAC;AAEjC,QAAMe,IAAa,MAAM;AACvB,UAAMC,IAAST,EAAU,SAAS;AAClC,IAAAF,EAAYW,KAAUT,EAAU,OAAO,GAClCG,KACHT,IAAe,EAAI;AAAA,EAEvB,GAEMgB,IAAc,MAAM;AACxB,IAAKR,KACHJ,EAAY,IAAI,GAElBJ,IAAe,EAAK;AAAA,EACtB,GAGMiB,IAAkE,CAAA;AACxE,EAAAC,EAAS,QAAQrB,GAAU,CAACsB,MAAU;AACpC,IAAKC,EAAkCD,CAAK,KAC5CF,EAAU,KAAK,EAAE,QAAQE,EAAM,MAAM,QAAQ,SAASA,EAAM,MAAM,SAAA,CAAU;AAAA,EAC9E,CAAC;AAGD,QAAME,IAAeJ,EAAU,OAAO,CAAC,EAAE,QAAAK,QACnCA,MAAW,SAAkB,KAC1BrB,EAAU,IAAIqB,CAAM,MAAM,QAClC,GAEKC,IAAmBN,EAAU,KAAK,CAAC,EAAE,QAAAK,EAAA,MAAaA,MAAW,MAAS,GACtEE,IAAS,CAACd,KAAkB,CAACa,GAE7BE,IAAeP,EAAS;AAAA,IAC5BG,EAAa,IAAI,CAAC,EAAE,SAAAK,EAAA,MAAcA,CAAO;AAAA,EAAA;AAG3C,SACE,gBAAAC,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAKvB;AAAA,QACL,WAAU;AAAA,QACV,cAAYkB,IAAS,WAAW;AAAA,QAChC,OAAOA,IAAS,EAAE,SAAS,WAAW;AAAA,QACtC,SAASV;AAAA,QAER,UAAAlB;AAAA,MAAA;AAAA,IAAA;AAAA,IAEFE,EAAW,EAAE,UAAAK,GAAU,MAAAM,GAAM,SAASO,GAAa,UAAUS,GAAc;AAAA,EAAA,GAC9E;AAEJ;AAEA,MAAAK,IAAe,OAAO,OAAOnC,GAAc,EAAE,cAAc,QAAiB;"}
@@ -3,7 +3,7 @@ export type { OverflowProps } from './Overflow';
3
3
  export { default as OverflowItem } from './OverflowItem';
4
4
  export type { OverflowItemProps } from './OverflowItem';
5
5
  export { default as OverflowMenu } from './OverflowMenu';
6
- export type { RenderMenuProps } from './OverflowMenu';
6
+ export type { RenderMenuProps, OverflowMenuControlProps } from './OverflowMenu';
7
7
  export { default as OverflowContext, useOverflow } from './OverflowContext';
8
8
  export { OverflowController } from './OverflowController';
9
9
  export type { OverflowHost, ScanResult, ScannedItem, ScannedMenu, } from './OverflowController';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,WAAW,GACZ,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,WAAW,GACZ,MAAM,sBAAsB,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import { type RefObject } from "react";
2
- export declare function useResizer(ref: RefObject<HTMLElement | null>, onResize: (maxWidth: number, currentWidth: number) => void): void;
2
+ export declare function useResizer(ref: RefObject<HTMLElement | null>, onResize: () => void): void;
3
3
  //# sourceMappingURL=useResizer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useResizer.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/useResizer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,wBAAgB,UAAU,CACxB,GAAG,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAClC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,QAqB3D"}
1
+ {"version":3,"file":"useResizer.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/useResizer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,wBAAgB,UAAU,CACxB,GAAG,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAClC,QAAQ,EAAE,MAAM,IAAI,QAgBrB"}
@@ -1,16 +1,14 @@
1
- import { useRef as o, useEffect as u } from "react";
2
- function f(r, t) {
3
- const c = o(t);
4
- c.current = t, u(() => {
5
- const e = r.current;
6
- if (!e) return;
7
- const n = () => {
8
- c.current(e.scrollWidth, e.clientWidth);
9
- }, s = new ResizeObserver(n);
10
- return s.observe(e), n(), () => {
11
- s.disconnect();
1
+ import { useRef as s, useEffect as o } from "react";
2
+ function f(e, r) {
3
+ const t = s(r);
4
+ t.current = r, o(() => {
5
+ const n = e.current;
6
+ if (!n) return;
7
+ const c = new ResizeObserver(() => t.current());
8
+ return c.observe(n), () => {
9
+ c.disconnect();
12
10
  };
13
- }, [r]);
11
+ }, [e]);
14
12
  }
15
13
  export {
16
14
  f as useResizer
@@ -1 +1 @@
1
- {"version":3,"file":"useResizer.js","sources":["../../../src/components/Overflow/useResizer.tsx"],"sourcesContent":["import { useEffect, useRef, type RefObject } from \"react\";\n\nexport function useResizer(\n ref: RefObject<HTMLElement | null>,\n onResize: (maxWidth: number, currentWidth: number) => void\n) {\n const callbackRef = useRef(onResize);\n callbackRef.current = onResize;\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const observe = () => {\n callbackRef.current(element.scrollWidth, element.clientWidth);\n };\n const observer = new ResizeObserver(observe);\n\n observer.observe(element);\n observe(); // Trigger initial measurement\n\n return () => {\n observer.disconnect();\n };\n }, [ref]);\n}"],"names":["useResizer","ref","onResize","callbackRef","useRef","useEffect","element","observe","observer"],"mappings":";AAEO,SAASA,EACdC,GACAC,GACA;AACA,QAAMC,IAAcC,EAAOF,CAAQ;AACnC,EAAAC,EAAY,UAAUD,GAEtBG,EAAU,MAAM;AACd,UAAMC,IAAUL,EAAI;AACpB,QAAI,CAACK,EAAS;AAEd,UAAMC,IAAU,MAAM;AACpB,MAAAJ,EAAY,QAAQG,EAAQ,aAAaA,EAAQ,WAAW;AAAA,IAC9D,GACME,IAAW,IAAI,eAAeD,CAAO;AAE3C,WAAAC,EAAS,QAAQF,CAAO,GACxBC,EAAA,GAEO,MAAM;AACX,MAAAC,EAAS,WAAA;AAAA,IACX;AAAA,EACF,GAAG,CAACP,CAAG,CAAC;AACV;"}
1
+ {"version":3,"file":"useResizer.js","sources":["../../../src/components/Overflow/useResizer.tsx"],"sourcesContent":["import { useEffect, useRef, type RefObject } from \"react\";\n\nexport function useResizer(\n ref: RefObject<HTMLElement | null>,\n onResize: () => void\n) {\n const callbackRef = useRef(onResize);\n callbackRef.current = onResize;\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const observer = new ResizeObserver(() => callbackRef.current());\n observer.observe(element);\n\n return () => {\n observer.disconnect();\n };\n }, [ref]);\n}\n"],"names":["useResizer","ref","onResize","callbackRef","useRef","useEffect","element","observer"],"mappings":";AAEO,SAASA,EACdC,GACAC,GACA;AACA,QAAMC,IAAcC,EAAOF,CAAQ;AACnC,EAAAC,EAAY,UAAUD,GAEtBG,EAAU,MAAM;AACd,UAAMC,IAAUL,EAAI;AACpB,QAAI,CAACK,EAAS;AAEd,UAAMC,IAAW,IAAI,eAAe,MAAMJ,EAAY,SAAS;AAC/D,WAAAI,EAAS,QAAQD,CAAO,GAEjB,MAAM;AACX,MAAAC,EAAS,WAAA;AAAA,IACX;AAAA,EACF,GAAG,CAACN,CAAG,CAAC;AACV;"}
@@ -1,9 +1,10 @@
1
1
  import { type ReactNode } from 'react';
2
- interface RxOverflowMenuProps {
2
+ import { type OverflowMenuControlProps } from '../Overflow';
3
+ interface RxOverflowMenuProps extends OverflowMenuControlProps {
3
4
  opener: ReactNode;
4
5
  children: ReactNode;
5
6
  }
6
- declare function RxOverflowMenu({ opener, children }: RxOverflowMenuProps): import("react/jsx-runtime").JSX.Element;
7
+ declare function RxOverflowMenu({ opener, children, open, onOpenChange }: RxOverflowMenuProps): import("react/jsx-runtime").JSX.Element;
7
8
  declare const _default: typeof RxOverflowMenu & {
8
9
  overflowRole: "menu";
9
10
  };
@@ -1 +1 @@
1
- {"version":3,"file":"RxOverflowMenu.d.ts","sourceRoot":"","sources":["../../../src/components/RxOverflow/RxOverflowMenu.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAU,MAAM,OAAO,CAAC;AAG/C,UAAU,mBAAmB;IAC3B,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,iBAAS,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,mBAAmB,2CAYhE;;;;AAED,wBAAgF"}
1
+ {"version":3,"file":"RxOverflowMenu.d.ts","sourceRoot":"","sources":["../../../src/components/RxOverflow/RxOverflowMenu.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAU,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAgB,KAAK,wBAAwB,EAAwB,MAAM,aAAa,CAAC;AAEhG,UAAU,mBAAoB,SAAQ,wBAAwB;IAC5D,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,iBAAS,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,mBAAmB,2CAYpF;;;;AAED,wBAAgF"}
@@ -1,33 +1,34 @@
1
- import { jsx as e, jsxs as c } from "react/jsx-runtime";
2
- import * as r from "@radix-ui/react-popover";
3
- import { useRef as s } from "react";
4
- import a from "../Overflow/OverflowMenu.js";
5
- function d({ opener: n, children: o }) {
6
- return /* @__PURE__ */ e(a, { opener: n, renderMenu: ({ anchorEl: i, open: t, onClose: u, children: l }) => /* @__PURE__ */ e(m, { anchorEl: i, open: t, onClose: u, children: l }), children: o });
1
+ import { jsx as e, jsxs as a } from "react/jsx-runtime";
2
+ import * as o from "@radix-ui/react-popover";
3
+ import { useRef as d } from "react";
4
+ import m from "../Overflow/OverflowMenu.js";
5
+ function p({ opener: n, children: r, open: t, onOpenChange: i }) {
6
+ return /* @__PURE__ */ e(m, { opener: n, renderMenu: ({ anchorEl: f, open: l, onClose: c, children: s }) => /* @__PURE__ */ e(R, { anchorEl: f, open: l, onClose: c, children: s }), open: t, onOpenChange: i, children: r });
7
7
  }
8
- const v = Object.assign(d, { overflowRole: "menu" });
9
- function m({ anchorEl: n, open: o, onClose: f, children: i }) {
10
- const t = s({
8
+ const M = Object.assign(p, { overflowRole: "menu" });
9
+ function R({ anchorEl: n, open: r, onClose: t, children: i }) {
10
+ const u = d({
11
11
  getBoundingClientRect: () => new DOMRect()
12
12
  });
13
- return n && (t.current = {
13
+ return n && (u.current = {
14
14
  getBoundingClientRect: () => n.getBoundingClientRect()
15
- }), /* @__PURE__ */ c(r.Root, { open: o, onOpenChange: (u) => {
16
- u || f();
15
+ }), /* @__PURE__ */ a(o.Root, { open: r, onOpenChange: (f) => {
16
+ f || t();
17
17
  }, children: [
18
- /* @__PURE__ */ e(r.Anchor, { virtualRef: t }),
19
- /* @__PURE__ */ e(r.Portal, { children: /* @__PURE__ */ e(
20
- r.Content,
18
+ /* @__PURE__ */ e(o.Anchor, { virtualRef: u }),
19
+ /* @__PURE__ */ e(o.Portal, { children: /* @__PURE__ */ e(
20
+ o.Content,
21
21
  {
22
22
  className: "rx-menu-panel",
23
23
  sideOffset: 4,
24
24
  align: "start",
25
+ onClick: t,
25
26
  children: i
26
27
  }
27
28
  ) })
28
29
  ] });
29
30
  }
30
31
  export {
31
- v as default
32
+ M as default
32
33
  };
33
34
  //# sourceMappingURL=RxOverflowMenu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RxOverflowMenu.js","sources":["../../../src/components/RxOverflow/RxOverflowMenu.tsx"],"sourcesContent":["import * as Popover from '@radix-ui/react-popover';\nimport { type ReactNode, useRef } from 'react';\nimport { OverflowMenu, type RenderMenuProps } from '../Overflow';\n\ninterface RxOverflowMenuProps {\n opener: ReactNode;\n children: ReactNode;\n}\n\nfunction RxOverflowMenu({ opener, children }: RxOverflowMenuProps) {\n const renderMenu = ({ anchorEl, open, onClose, children: menuChildren }: RenderMenuProps) => (\n <RxPopoverMenu anchorEl={anchorEl} open={open} onClose={onClose}>\n {menuChildren}\n </RxPopoverMenu>\n );\n\n return (\n <OverflowMenu opener={opener} renderMenu={renderMenu}>\n {children}\n </OverflowMenu>\n );\n}\n\nexport default Object.assign(RxOverflowMenu, { overflowRole: 'menu' as const });\n\nfunction RxPopoverMenu({ anchorEl, open, onClose, children }: RenderMenuProps) {\n const virtualRef = useRef<{ getBoundingClientRect: () => DOMRect }>({\n getBoundingClientRect: () => new DOMRect(),\n });\n\n // Update synchronously during render so the popover positions correctly\n // on the same frame it opens (useEffect would be one frame too late).\n if (anchorEl) {\n virtualRef.current = {\n getBoundingClientRect: () => anchorEl.getBoundingClientRect(),\n };\n }\n\n return (\n <Popover.Root open={open} onOpenChange={(o) => { if (!o) onClose(); }}>\n <Popover.Anchor virtualRef={virtualRef} />\n <Popover.Portal>\n <Popover.Content\n className=\"rx-menu-panel\"\n sideOffset={4}\n align=\"start\"\n >\n {children}\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n"],"names":["RxOverflowMenu","opener","children","jsx","OverflowMenu","anchorEl","open","onClose","menuChildren","RxPopoverMenu","RxOverflowMenu_default","virtualRef","useRef","Popover","o"],"mappings":";;;;AASA,SAASA,EAAe,EAAE,QAAAC,GAAQ,UAAAC,KAAiC;AAOjE,SACE,gBAAAC,EAACC,GAAA,EAAa,QAAAH,GAAgB,YAPb,CAAC,EAAE,UAAAI,GAAU,MAAAC,GAAM,SAAAC,GAAS,UAAUC,EAAA,MACvD,gBAAAL,EAACM,GAAA,EAAc,UAAAJ,GAAoB,MAAAC,GAAY,SAAAC,GAC5C,UAAAC,GACH,GAKG,UAAAN,EAAA,CACH;AAEJ;AAEA,MAAAQ,IAAe,OAAO,OAAOV,GAAgB,EAAE,cAAc,QAAiB;AAE9E,SAASS,EAAc,EAAE,UAAAJ,GAAU,MAAAC,GAAM,SAAAC,GAAS,UAAAL,KAA6B;AAC7E,QAAMS,IAAaC,EAAiD;AAAA,IAClE,uBAAuB,MAAM,IAAI,QAAA;AAAA,EAAQ,CAC1C;AAID,SAAIP,MACFM,EAAW,UAAU;AAAA,IACnB,uBAAuB,MAAMN,EAAS,sBAAA;AAAA,EAAsB,sBAK7DQ,EAAQ,MAAR,EAAa,MAAAP,GAAY,cAAc,CAACQ,MAAM;AAAE,IAAKA,KAAGP,EAAA;AAAA,EAAW,GAClE,UAAA;AAAA,IAAA,gBAAAJ,EAACU,EAAQ,QAAR,EAAe,YAAAF,EAAA,CAAwB;AAAA,IACxC,gBAAAR,EAACU,EAAQ,QAAR,EACC,UAAA,gBAAAV;AAAA,MAACU,EAAQ;AAAA,MAAR;AAAA,QACC,WAAU;AAAA,QACV,YAAY;AAAA,QACZ,OAAM;AAAA,QAEL,UAAAX;AAAA,MAAA;AAAA,IAAA,EACH,CACF;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"RxOverflowMenu.js","sources":["../../../src/components/RxOverflow/RxOverflowMenu.tsx"],"sourcesContent":["import * as Popover from '@radix-ui/react-popover';\nimport { type ReactNode, useRef } from 'react';\nimport { OverflowMenu, type OverflowMenuControlProps, type RenderMenuProps } from '../Overflow';\n\ninterface RxOverflowMenuProps extends OverflowMenuControlProps {\n opener: ReactNode;\n children: ReactNode;\n}\n\nfunction RxOverflowMenu({ opener, children, open, onOpenChange }: RxOverflowMenuProps) {\n const renderMenu = ({ anchorEl, open, onClose, children: menuChildren }: RenderMenuProps) => (\n <RxPopoverMenu anchorEl={anchorEl} open={open} onClose={onClose}>\n {menuChildren}\n </RxPopoverMenu>\n );\n\n return (\n <OverflowMenu opener={opener} renderMenu={renderMenu} open={open} onOpenChange={onOpenChange}>\n {children}\n </OverflowMenu>\n );\n}\n\nexport default Object.assign(RxOverflowMenu, { overflowRole: 'menu' as const });\n\nfunction RxPopoverMenu({ anchorEl, open, onClose, children }: RenderMenuProps) {\n const virtualRef = useRef<{ getBoundingClientRect: () => DOMRect }>({\n getBoundingClientRect: () => new DOMRect(),\n });\n\n // Update synchronously during render so the popover positions correctly\n // on the same frame it opens (useEffect would be one frame too late).\n if (anchorEl) {\n virtualRef.current = {\n getBoundingClientRect: () => anchorEl.getBoundingClientRect(),\n };\n }\n\n return (\n <Popover.Root open={open} onOpenChange={(o) => { if (!o) onClose(); }}>\n <Popover.Anchor virtualRef={virtualRef} />\n <Popover.Portal>\n <Popover.Content\n className=\"rx-menu-panel\"\n sideOffset={4}\n align=\"start\"\n onClick={onClose}\n >\n {children}\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n"],"names":["RxOverflowMenu","opener","children","open","onOpenChange","OverflowMenu","anchorEl","onClose","menuChildren","RxPopoverMenu","RxOverflowMenu_default","virtualRef","useRef","Popover","o","jsx"],"mappings":";;;;AASA,SAASA,EAAe,EAAE,QAAAC,GAAQ,UAAAC,GAAU,MAAAC,GAAM,cAAAC,KAAqC;AAOrF,2BACGC,GAAA,EAAa,QAAAJ,GAAgB,YAPb,CAAC,EAAE,UAAAK,GAAU,MAAAH,GAAM,SAAAI,GAAS,UAAUC,EAAA,wBACtDC,GAAA,EAAc,UAAAH,GAAoB,MAAMH,GAAM,SAAAI,GAC5C,UAAAC,GACH,GAIsD,MAAAL,GAAY,cAAAC,GAC/D,UAAAF,GACH;AAEJ;AAEA,MAAAQ,IAAe,OAAO,OAAOV,GAAgB,EAAE,cAAc,QAAiB;AAE9E,SAASS,EAAc,EAAE,UAAAH,GAAU,MAAAH,GAAM,SAAAI,GAAS,UAAAL,KAA6B;AAC7E,QAAMS,IAAaC,EAAiD;AAAA,IAClE,uBAAuB,MAAM,IAAI,QAAA;AAAA,EAAQ,CAC1C;AAID,SAAIN,MACFK,EAAW,UAAU;AAAA,IACnB,uBAAuB,MAAML,EAAS,sBAAA;AAAA,EAAsB,sBAK7DO,EAAQ,MAAR,EAAa,MAAAV,GAAY,cAAc,CAACW,MAAM;AAAE,IAAKA,KAAGP,EAAA;AAAA,EAAW,GAClE,UAAA;AAAA,IAAA,gBAAAQ,EAACF,EAAQ,QAAR,EAAe,YAAAF,EAAA,CAAwB;AAAA,IACxC,gBAAAI,EAACF,EAAQ,QAAR,EACC,UAAA,gBAAAE;AAAA,MAACF,EAAQ;AAAA,MAAR;AAAA,QACC,WAAU;AAAA,QACV,YAAY;AAAA,QACZ,OAAM;AAAA,QACN,SAASN;AAAA,QAER,UAAAL;AAAA,MAAA;AAAA,IAAA,EACH,CACF;AAAA,EAAA,GACF;AAEJ;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overflow-toolbar",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "description": "Responsive toolbar overflow component — items automatically collapse into a dropdown menu as the container shrinks. Supports visible, icon-only (min), and hidden states. Ships with React (Radix UI), MUI, and vanilla JS implementations.",
6
6
  "license": "MIT",