overflow-toolbar 0.2.1 → 0.2.2

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.
@@ -1 +1 @@
1
- .overflow{--u: 8px;--u1: calc(var(--u) * 1);--u2: calc(var(--u) * 2);--u3: calc(var(--u) * 3);--u4: calc(var(--u) * 4);--u5: calc(var(--u) * 5);--hiddenCount: 0;display:flex;gap:0;justify-content:flex-start;white-space:nowrap;max-width:100%;overflow:hidden;list-style:none;margin:0 0 0 auto;padding:0;flex:min(var(--hiddenCount, 0)) 1 auto}.overflow>*{flex:0 0 fit-content;list-style:none;padding:0;margin:0}.overflow>:not([data-state=hidden]):first-child,.overflow>[data-state=hidden]:first-child+:not([data-state=hidden]){margin-left:auto;margin-right:0}.overflow>li.overflow-opener{margin-left:auto;max-width:var(--u5)}.overflow-compact{gap:1px!important}.overflow-compact:not(.overflow-reverse)>:not([data-state=hidden])~:not([data-state=hidden])>button{border-top-left-radius:0;border-bottom-left-radius:0}.overflow-compact:not(.overflow-reverse)>:not([data-state=hidden]):has(~:not([data-state=hidden]))>button{border-top-right-radius:0;border-bottom-right-radius:0}.overflow-reverse{margin-left:0;margin-right:auto;flex-direction:row-reverse}.overflow-reverse>:not([data-state=hidden]):first-child,.overflow-reverse>[data-state=hidden]:first-child+:not([data-state=hidden]){margin-left:0;margin-right:auto}.overflow-reverse>li.overflow-opener{margin-left:0;margin-right:auto}.overflow-compact.overflow-reverse>:not([data-state=hidden])~:not([data-state=hidden])>button{border-top-right-radius:0;border-bottom-right-radius:0}.overflow-compact.overflow-reverse>:not([data-state=hidden]):has(~:not([data-state=hidden]))>button{border-top-left-radius:0;border-bottom-left-radius:0}:is(.overflow-item-min,.overflow-opener,.overflow-snap:has(>[data-state=min])>[data-can-min]:not([data-state=min]):not([data-state=hidden]))>button{font-size:0;min-width:100%;width:100%;max-width:100%;align-items:center;justify-content:center;gap:0}.overflow-snap:has(>[data-state=min])>[data-can-min]:not([data-state=min]):not([data-state=hidden]){max-width:var(--min-state-width, 2.25rem);overflow:hidden}
1
+ .overflow{--u: 8px;--u1: calc(var(--u) * 1);--u2: calc(var(--u) * 2);--u3: calc(var(--u) * 3);--u4: calc(var(--u) * 4);--u5: calc(var(--u) * 5);--hiddenCount: 0;display:flex;gap:0;justify-content:flex-start;white-space:nowrap;max-width:100%;overflow:hidden;list-style:none;margin:0 0 0 auto;padding:0;flex:min(var(--hiddenCount, 0)) 1 auto}.overflow>*{flex:0 0 fit-content;list-style:none;padding:0;margin:0}.overflow>:not([data-state=hidden]):first-child,.overflow>[data-state=hidden]:first-child+:not([data-state=hidden]){margin-left:auto;margin-right:0}.overflow>li.overflow-opener{margin-left:auto;max-width:var(--u5)}.overflow-compact{gap:1px!important}.overflow-compact:not(.overflow-reverse)>:not([data-state=hidden])~:not([data-state=hidden])>button{border-top-left-radius:0;border-bottom-left-radius:0}.overflow-compact:not(.overflow-reverse)>:not([data-state=hidden]):has(~:not([data-state=hidden]))>button{border-top-right-radius:0;border-bottom-right-radius:0}.overflow-reverse{margin-left:0;margin-right:auto;flex-direction:row-reverse}.overflow-reverse>:not([data-state=hidden]):first-child,.overflow-reverse>[data-state=hidden]:first-child+:not([data-state=hidden]){margin-left:0;margin-right:auto}.overflow-reverse>li.overflow-opener{margin-left:0;margin-right:auto}.overflow-compact.overflow-reverse>:not([data-state=hidden])~:not([data-state=hidden])>button{border-top-right-radius:0;border-bottom-right-radius:0}.overflow-compact.overflow-reverse>:not([data-state=hidden]):has(~:not([data-state=hidden]))>button{border-top-left-radius:0;border-bottom-left-radius:0}:is(.overflow-item-min,.overflow-opener)>button{font-size:0;min-width:100%;width:100%;max-width:100%;align-items:center;justify-content:center;gap:0}
@@ -1 +1 @@
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;AAUnI,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,+FAA+F;IAC/F,QAAQ,EAAE,SAAS,CAAC;IACpB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8HAA8H;IAC9H,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,QAAA,MAAM,QAAQ,4GA0FZ,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;AAUnI,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,+FAA+F;IAC/F,QAAQ,EAAE,SAAS,CAAC;IACpB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8HAA8H;IAC9H,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,QAAA,MAAM,QAAQ,4GA2FZ,CAAC;AAEH,eAAe,QAAQ,CAAC"}
@@ -1,42 +1,43 @@
1
- import { jsx as S } from "react/jsx-runtime";
2
- import { forwardRef as N, useState as g, useRef as j, useMemo as d, Children as i, isValidElement as c, Fragment as A, useLayoutEffect as V } from "react";
3
- import b from "./OverflowContext.js";
4
- import { buildOrderedSteps as B, computeNextSteps as R, deriveHiddenMap as F } from "./overflowSteps.js";
5
- import { useResizer as H } from "./useResizer.js";
6
- const P = N(function({ children: r, className: M, style: W, compact: x, reverse: y, snap: u }, E) {
7
- const [p, m] = g([]), O = j(null), s = E ?? O, f = d(() => i.toArray(
8
- i.count(r) === 1 && c(r) && r.type === A ? r.props.children : r
9
- ), [r]), { orderedSteps: l, inMenuIds: a } = d(() => {
10
- const e = [], t = /* @__PURE__ */ new Set(), v = /* @__PURE__ */ new Set();
1
+ import { jsx as M } from "react/jsx-runtime";
2
+ import { forwardRef as g, useState as j, useRef as A, useMemo as p, Children as i, isValidElement as c, Fragment as V, useLayoutEffect as b } from "react";
3
+ import B from "./OverflowContext.js";
4
+ import { buildOrderedSteps as F, computeNextSteps as R, deriveHiddenMap as H } from "./overflowSteps.js";
5
+ import { useResizer as L } from "./useResizer.js";
6
+ const Q = g(function({ children: r, className: W, style: h, compact: x, reverse: y, snap: u }, E) {
7
+ const [d, a] = j([]), O = A(null), n = E ?? O, f = p(() => i.toArray(
8
+ i.count(r) === 1 && c(r) && r.type === V ? r.props.children : r
9
+ ), [r]), { orderedSteps: l, inMenuIds: I, minWidthMenuIds: v } = p(() => {
10
+ const e = [], t = /* @__PURE__ */ new Set(), m = /* @__PURE__ */ new Set();
11
11
  return i.forEach(f, (o) => {
12
12
  if (!c(o)) return;
13
- const w = o.type.overflowRole;
14
- w === "menu" ? i.forEach(o.props.children, (n) => {
15
- c(n) && n.props.menuId && (t.add(n.props.menuId), e.includes(n.props.menuId) || e.push(n.props.menuId));
16
- }) : w === "item" && o.props.menuId && (e.includes(o.props.menuId) || e.push(o.props.menuId), o.props.minStateWidth !== void 0 && v.add(o.props.menuId));
13
+ const S = o.type.overflowRole;
14
+ S === "menu" ? i.forEach(o.props.children, (s) => {
15
+ c(s) && s.props.menuId && (t.add(s.props.menuId), e.includes(s.props.menuId) || e.push(s.props.menuId));
16
+ }) : S === "item" && o.props.menuId && (e.includes(o.props.menuId) || e.push(o.props.menuId), o.props.minStateWidth !== void 0 && m.add(o.props.menuId));
17
17
  }), {
18
- orderedSteps: B(e, t, v),
19
- inMenuIds: t
18
+ orderedSteps: F(e, t, m),
19
+ inMenuIds: t,
20
+ minWidthMenuIds: m
20
21
  };
21
22
  }, [f]);
22
- V(() => {
23
- const e = s.current;
24
- e && m(
23
+ b(() => {
24
+ const e = n.current;
25
+ e && a(
25
26
  (t) => R(t, e.scrollWidth, e.clientWidth, l)
26
27
  );
27
- }, [p, l, s]), H(s, () => {
28
- const e = s.current;
29
- e && m(
28
+ }, [d, l, n]), L(n, () => {
29
+ const e = n.current;
30
+ e && a(
30
31
  (t) => R(t, e.scrollWidth, e.clientWidth, l)
31
32
  );
32
33
  });
33
- const I = d(() => F(p, u, a), [p, u, a]), h = d(
34
- () => ({ hiddenMap: I }),
35
- [I]
36
- ), z = ["overflow", x && "overflow-compact", y && "overflow-reverse", u && "overflow-snap", M].filter(Boolean).join(" ");
37
- return /* @__PURE__ */ S(b, { value: h, children: /* @__PURE__ */ S("ul", { ref: s, className: z, style: { ...W, "--hiddenCount": p.length }, children: f }) });
34
+ const w = p(() => H(d, u, I, v), [d, u, I, v]), z = p(
35
+ () => ({ hiddenMap: w }),
36
+ [w]
37
+ ), N = ["overflow", x && "overflow-compact", y && "overflow-reverse", u && "overflow-snap", W].filter(Boolean).join(" ");
38
+ return /* @__PURE__ */ M(B, { value: z, children: /* @__PURE__ */ M("ul", { ref: n, className: N, style: { ...h, "--hiddenCount": d.length }, children: f }) });
38
39
  });
39
40
  export {
40
- P as default
41
+ Q as default
41
42
  };
42
43
  //# 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, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport OverflowContext from './OverflowContext';\nimport { type AppliedStep, buildOrderedSteps, computeNextSteps, deriveHiddenMap } from './overflowSteps';\nimport { useResizer } from './useResizer';\n\n/** Shared type for components that declare an overflowRole ('item' | 'menu'). */\ninterface OverflowRoleComponent {\n overflowRole?: 'item' | 'menu';\n}\n\n/** Props for the Overflow container component. */\nexport interface OverflowProps {\n /** OverflowItem and OverflowMenu components. Must be direct children (no wrapper elements). */\n children: ReactNode;\n /** CSS class name for the container `<ul>`. */\n className?: string;\n /** Inline styles for the container `<ul>`. */\n style?: React.CSSProperties;\n /** When true, items collapse one at a time with tight spacing and grouped corners. */\n compact?: boolean;\n /** When true, items collapse from the right instead of the left. */\n reverse?: boolean;\n /** When true, all items with a `minStateWidth` snap to min state together, and all hideable items snap to hidden together. */\n snap?: boolean;\n}\n\nconst Overflow = forwardRef<HTMLUListElement, OverflowProps>(function Overflow({ children, className, style, compact, reverse, snap }, 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, inMenuIds } = 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 OverflowRoleComponent).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 = menuIds;\n return {\n orderedSteps: buildOrderedSteps(orderedIds, inMenuIds, minWidthMenuIds),\n inMenuIds,\n };\n }, [resolvedChildren]);\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, snap, inMenuIds), [appliedSteps, snap, inMenuIds]);\n\n const ctxValue = useMemo(\n () => ({ hiddenMap }),\n [hiddenMap],\n );\n\n const classNames = ['overflow', compact && 'overflow-compact', reverse && 'overflow-reverse', snap && 'overflow-snap', 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","snap","ref","appliedSteps","setAppliedSteps","useState","internalRef","useRef","listRef","resolvedChildren","useMemo","Children","isValidElement","Fragment","orderedSteps","inMenuIds","menuIds","minWidthMenuIds","child","role","menuChild","buildOrderedSteps","useLayoutEffect","element","computeNextSteps","prev","useResizer","hiddenMap","deriveHiddenMap","ctxValue","classNames","OverflowContext","jsx"],"mappings":";;;;;AA0BA,MAAMA,IAAWC,EAA4C,SAAkB,EAAE,UAAAC,GAAU,WAAAC,GAAW,OAAAC,GAAO,SAAAC,GAAS,SAAAC,GAAS,MAAAC,EAAA,GAAQC,GAAK;AAC1I,QAAM,CAACC,GAAcC,CAAe,IAAIC,EAAwB,CAAA,CAAE,GAC5DC,IAAcC,EAAgC,IAAI,GAClDC,IAAWN,KAAOI,GAGlBG,IAAmBC,EAAQ,MAAMC,EAAS;AAAA,IAC9CA,EAAS,MAAMf,CAAQ,MAAM,KAAKgB,EAAwChB,CAAQ,KAAKA,EAAS,SAASiB,IACrGjB,EAAS,MAAM,WACfA;AAAA,EAAA,GACH,CAACA,CAAQ,CAAC,GAGP,EAAE,cAAAkB,GAAc,WAAAC,EAAA,IAAcL,EAAQ,MAAM;AAChD,UAAMM,IAAoB,CAAA,GACpBD,wBAAgB,IAAA,GAChBE,wBAAsB,IAAA;AAG5B,WAAAN,EAAS,QAAQF,GAAkB,CAACS,MAAU;AAC5C,UAAI,CAACN,EAAkFM,CAAK,EAAG;AAE/F,YAAMC,IAAQD,EAAM,KAA+B;AAEnD,MAAIC,MAAS,SAEXR,EAAS,QAAQO,EAAM,MAAM,UAAU,CAACE,MAAc;AACpD,QAAKR,EAAoCQ,CAAS,KAC9CA,EAAU,MAAM,WAClBL,EAAU,IAAIK,EAAU,MAAM,MAAM,GAC/BJ,EAAQ,SAASI,EAAU,MAAM,MAAM,KAC1CJ,EAAQ,KAAKI,EAAU,MAAM,MAAM;AAAA,MAGzC,CAAC,IACQD,MAAS,UAAUD,EAAM,MAAM,WACnCF,EAAQ,SAASE,EAAM,MAAM,MAAM,KACtCF,EAAQ,KAAKE,EAAM,MAAM,MAAM,GAE7BA,EAAM,MAAM,kBAAkB,UAChCD,EAAgB,IAAIC,EAAM,MAAM,MAAM;AAAA,IAG5C,CAAC,GAGM;AAAA,MACL,cAAcG,EAFGL,GAE2BD,GAAWE,CAAe;AAAA,MACtE,WAAAF;AAAAA,IAAA;AAAA,EAEJ,GAAG,CAACN,CAAgB,CAAC;AAKrB,EAAAa,EAAgB,MAAM;AACpB,UAAMC,IAAUf,EAAQ;AACxB,IAAKe,KACLnB;AAAA,MAAgB,OACdoB,EAAiBC,GAAMF,EAAQ,aAAaA,EAAQ,aAAaT,CAAY;AAAA,IAAA;AAAA,EAEjF,GAAG,CAACX,GAAcW,GAAcN,CAAO,CAAC,GAWxCkB,EAAWlB,GARM,MAAM;AACrB,UAAMe,IAAUf,EAAQ;AACxB,IAAKe,KACLnB;AAAA,MAAgB,OACdoB,EAAiBC,GAAMF,EAAQ,aAAaA,EAAQ,aAAaT,CAAY;AAAA,IAAA;AAAA,EAEjF,CAE4B;AAE5B,QAAMa,IAAYjB,EAAQ,MAAMkB,EAAgBzB,GAAcF,GAAMc,CAAS,GAAG,CAACZ,GAAcF,GAAMc,CAAS,CAAC,GAEzGc,IAAWnB;AAAA,IACf,OAAO,EAAE,WAAAiB,EAAA;AAAA,IACT,CAACA,CAAS;AAAA,EAAA,GAGNG,IAAa,CAAC,YAAY/B,KAAW,oBAAoBC,KAAW,oBAAoBC,KAAQ,iBAAiBJ,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAE1J,2BACGkC,GAAA,EAAgB,OAAOF,GACtB,UAAA,gBAAAG,EAAC,MAAA,EAAG,KAAKxB,GAAS,WAAWsB,GAAY,OAAO,EAAE,GAAGhC,GAAO,iBAAiBK,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 OverflowContext from './OverflowContext';\nimport { type AppliedStep, buildOrderedSteps, computeNextSteps, deriveHiddenMap } from './overflowSteps';\nimport { useResizer } from './useResizer';\n\n/** Shared type for components that declare an overflowRole ('item' | 'menu'). */\ninterface OverflowRoleComponent {\n overflowRole?: 'item' | 'menu';\n}\n\n/** Props for the Overflow container component. */\nexport interface OverflowProps {\n /** OverflowItem and OverflowMenu components. Must be direct children (no wrapper elements). */\n children: ReactNode;\n /** CSS class name for the container `<ul>`. */\n className?: string;\n /** Inline styles for the container `<ul>`. */\n style?: React.CSSProperties;\n /** When true, items collapse one at a time with tight spacing and grouped corners. */\n compact?: boolean;\n /** When true, items collapse from the right instead of the left. */\n reverse?: boolean;\n /** When true, all items with a `minStateWidth` snap to min state together, and all hideable items snap to hidden together. */\n snap?: boolean;\n}\n\nconst Overflow = forwardRef<HTMLUListElement, OverflowProps>(function Overflow({ children, className, style, compact, reverse, snap }, 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, inMenuIds, minWidthMenuIds } = 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 OverflowRoleComponent).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 = menuIds;\n return {\n orderedSteps: buildOrderedSteps(orderedIds, inMenuIds, minWidthMenuIds),\n inMenuIds,\n minWidthMenuIds,\n };\n }, [resolvedChildren]);\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, snap, inMenuIds, minWidthMenuIds), [appliedSteps, snap, inMenuIds, minWidthMenuIds]);\n\n const ctxValue = useMemo(\n () => ({ hiddenMap }),\n [hiddenMap],\n );\n\n const classNames = ['overflow', compact && 'overflow-compact', reverse && 'overflow-reverse', snap && 'overflow-snap', 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","snap","ref","appliedSteps","setAppliedSteps","useState","internalRef","useRef","listRef","resolvedChildren","useMemo","Children","isValidElement","Fragment","orderedSteps","inMenuIds","minWidthMenuIds","menuIds","child","role","menuChild","buildOrderedSteps","useLayoutEffect","element","computeNextSteps","prev","useResizer","hiddenMap","deriveHiddenMap","ctxValue","classNames","OverflowContext","jsx"],"mappings":";;;;;AA0BA,MAAMA,IAAWC,EAA4C,SAAkB,EAAE,UAAAC,GAAU,WAAAC,GAAW,OAAAC,GAAO,SAAAC,GAAS,SAAAC,GAAS,MAAAC,EAAA,GAAQC,GAAK;AAC1I,QAAM,CAACC,GAAcC,CAAe,IAAIC,EAAwB,CAAA,CAAE,GAC5DC,IAAcC,EAAgC,IAAI,GAClDC,IAAWN,KAAOI,GAGlBG,IAAmBC,EAAQ,MAAMC,EAAS;AAAA,IAC9CA,EAAS,MAAMf,CAAQ,MAAM,KAAKgB,EAAwChB,CAAQ,KAAKA,EAAS,SAASiB,IACrGjB,EAAS,MAAM,WACfA;AAAA,EAAA,GACH,CAACA,CAAQ,CAAC,GAGP,EAAE,cAAAkB,GAAc,WAAAC,GAAW,iBAAAC,EAAA,IAAoBN,EAAQ,MAAM;AACjE,UAAMO,IAAoB,CAAA,GACpBF,wBAAgB,IAAA,GAChBC,wBAAsB,IAAA;AAG5B,WAAAL,EAAS,QAAQF,GAAkB,CAACS,MAAU;AAC5C,UAAI,CAACN,EAAkFM,CAAK,EAAG;AAE/F,YAAMC,IAAQD,EAAM,KAA+B;AAEnD,MAAIC,MAAS,SAEXR,EAAS,QAAQO,EAAM,MAAM,UAAU,CAACE,MAAc;AACpD,QAAKR,EAAoCQ,CAAS,KAC9CA,EAAU,MAAM,WAClBL,EAAU,IAAIK,EAAU,MAAM,MAAM,GAC/BH,EAAQ,SAASG,EAAU,MAAM,MAAM,KAC1CH,EAAQ,KAAKG,EAAU,MAAM,MAAM;AAAA,MAGzC,CAAC,IACQD,MAAS,UAAUD,EAAM,MAAM,WACnCD,EAAQ,SAASC,EAAM,MAAM,MAAM,KACtCD,EAAQ,KAAKC,EAAM,MAAM,MAAM,GAE7BA,EAAM,MAAM,kBAAkB,UAChCF,EAAgB,IAAIE,EAAM,MAAM,MAAM;AAAA,IAG5C,CAAC,GAGM;AAAA,MACL,cAAcG,EAFGJ,GAE2BF,GAAWC,CAAe;AAAA,MACtE,WAAAD;AAAAA,MACA,iBAAAC;AAAAA,IAAA;AAAA,EAEJ,GAAG,CAACP,CAAgB,CAAC;AAKrB,EAAAa,EAAgB,MAAM;AACpB,UAAMC,IAAUf,EAAQ;AACxB,IAAKe,KACLnB;AAAA,MAAgB,OACdoB,EAAiBC,GAAMF,EAAQ,aAAaA,EAAQ,aAAaT,CAAY;AAAA,IAAA;AAAA,EAEjF,GAAG,CAACX,GAAcW,GAAcN,CAAO,CAAC,GAWxCkB,EAAWlB,GARM,MAAM;AACrB,UAAMe,IAAUf,EAAQ;AACxB,IAAKe,KACLnB;AAAA,MAAgB,OACdoB,EAAiBC,GAAMF,EAAQ,aAAaA,EAAQ,aAAaT,CAAY;AAAA,IAAA;AAAA,EAEjF,CAE4B;AAE5B,QAAMa,IAAYjB,EAAQ,MAAMkB,EAAgBzB,GAAcF,GAAMc,GAAWC,CAAe,GAAG,CAACb,GAAcF,GAAMc,GAAWC,CAAe,CAAC,GAE3Ia,IAAWnB;AAAA,IACf,OAAO,EAAE,WAAAiB,EAAA;AAAA,IACT,CAACA,CAAS;AAAA,EAAA,GAGNG,IAAa,CAAC,YAAY/B,KAAW,oBAAoBC,KAAW,oBAAoBC,KAAQ,iBAAiBJ,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAE1J,2BACGkC,GAAA,EAAgB,OAAOF,GACtB,UAAA,gBAAAG,EAAC,MAAA,EAAG,KAAKxB,GAAS,WAAWsB,GAAY,OAAO,EAAE,GAAGhC,GAAO,iBAAiBK,EAAa,OAAA,GACvF,aACH,GACF;AAEJ,CAAC;"}
@@ -28,6 +28,7 @@ export declare class OverflowController {
28
28
  private host;
29
29
  private orderedSteps;
30
30
  private appliedSteps;
31
+ private minWidthMenuIds;
31
32
  private ro;
32
33
  private lastScan;
33
34
  constructor(host: OverflowHost);
@@ -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;IACrB,MAAM,IAAI,OAAO,CAAC;CACnB;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;IAsBZ,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,UAAU;IAwDlB,OAAO,CAAC,cAAc;IAsCtB,OAAO,CAAC,mBAAmB;IAmD3B,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,UAAU;CAkCnB"}
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;IACrB,MAAM,IAAI,OAAO,CAAC;CACnB;AAyBD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,eAAe,CAAqB;IAC5C,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;IAuBZ,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,UAAU;IAyDlB,OAAO,CAAC,cAAc;IAsCtB,OAAO,CAAC,mBAAmB;IAmD3B,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,UAAU;CAkCnB"}
@@ -17,6 +17,7 @@ class v {
17
17
  host;
18
18
  orderedSteps = [];
19
19
  appliedSteps = [];
20
+ minWidthMenuIds = /* @__PURE__ */ new Set();
20
21
  ro = null;
21
22
  lastScan = { items: [], menu: null, menuFirst: !1 };
22
23
  constructor(t) {
@@ -41,7 +42,7 @@ class v {
41
42
  for (const r of this.lastScan.items)
42
43
  r.menuId && (t.push(r.menuId), r.minStateWidth && e.add(r.menuId)), r.minStateWidth && (r.el.style.setProperty("--min-state-width", r.minStateWidth), r.el.setAttribute("data-can-min", ""));
43
44
  const s = this.lastScan.menu?.inMenuIds ?? /* @__PURE__ */ new Set();
44
- this.orderedSteps = u(t, s, e);
45
+ this.minWidthMenuIds = e, this.orderedSteps = u(t, s, e);
45
46
  }
46
47
  startObserver() {
47
48
  this.ro?.disconnect();
@@ -65,7 +66,8 @@ class v {
65
66
  const t = this.host.isSnap(), e = f(
66
67
  this.appliedSteps,
67
68
  t,
68
- this.lastScan.menu?.inMenuIds
69
+ this.lastScan.menu?.inMenuIds,
70
+ this.minWidthMenuIds
69
71
  );
70
72
  this.host.getContainerEl().style.setProperty("--hiddenCount", String(this.appliedSteps.length));
71
73
  const r = this.host.isCompact(), n = this.host.isReverse();
@@ -75,11 +77,11 @@ class v {
75
77
  const a = i.menuId ? e.get(i.menuId) ?? "visible" : "visible";
76
78
  i.el.setAttribute("data-state", a), a === "visible" ? (i.el.style.removeProperty("display"), i.el.style.removeProperty("max-width"), i.el.style.removeProperty("overflow"), this.clearMinStyles(i.buttonEl), o.push(i)) : a === "min" ? (i.el.style.removeProperty("display"), i.el.style.setProperty("max-width", i.minStateWidth ?? "2.25rem"), i.el.style.setProperty("overflow", "hidden"), this.applyMinStyles(i.buttonEl), o.push(i)) : (i.el.style.setProperty("display", "none"), i.el.style.removeProperty("max-width"), i.el.style.removeProperty("overflow"), this.clearMinStyles(i.buttonEl), l = !0);
77
79
  }
78
- const { menu: p, menuFirst: d } = this.lastScan, h = this.applyMenuState(p, e, l);
80
+ const { menu: d, menuFirst: p } = this.lastScan, h = this.applyMenuState(d, e, l);
79
81
  this.applyCompactCorners(
80
82
  o,
81
- p,
82
83
  d,
84
+ p,
83
85
  h,
84
86
  r,
85
87
  n
@@ -97,11 +99,11 @@ class v {
97
99
  }
98
100
  applyCompactCorners(t, e, s, r, n, l) {
99
101
  for (let o = 0; o < t.length; o++) {
100
- const p = t[o].buttonEl;
101
- if (!p) continue;
102
- const d = o === 0, h = o === t.length - 1, i = s ? !d || r : !d, a = s ? !h : !h || r;
102
+ const d = t[o].buttonEl;
103
+ if (!d) continue;
104
+ const p = o === 0, h = o === t.length - 1, i = s ? !p || r : !p, a = s ? !h : !h || r;
103
105
  this.setCorners(
104
- p,
106
+ d,
105
107
  n && (l ? a : i),
106
108
  n && (l ? i : a)
107
109
  );
@@ -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 isSnap(): 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 // Set CSS custom properties for snap targeting\n if (item.minStateWidth) {\n item.el.style.setProperty('--min-state-width', item.minStateWidth);\n item.el.setAttribute('data-can-min', '');\n }\n }\n\n const inMenuIds = this.lastScan.menu?.inMenuIds ?? new Set<string>();\n this.orderedSteps = buildOrderedSteps(menuIds, 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 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 isSnap = this.host.isSnap();\n const hiddenMap = deriveHiddenMap(\n this.appliedSteps,\n isSnap,\n this.lastScan.menu?.inMenuIds,\n );\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 // ARIA attributes on the trigger\n menu.triggerEl.setAttribute('aria-haspopup', 'menu');\n menu.triggerEl.setAttribute('aria-expanded', String(showOpener));\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.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.removeAttribute('data-can-min');\n item.el.style.removeProperty('display');\n item.el.style.removeProperty('max-width');\n item.el.style.removeProperty('overflow');\n item.el.style.removeProperty('--min-state-width');\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 menu.triggerEl.removeAttribute('aria-haspopup');\n menu.triggerEl.removeAttribute('aria-expanded');\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","buildOrderedSteps","container","scrollWidth","clientWidth","next","computeNextSteps","isSnap","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 isSnap(): 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 minWidthMenuIds = new Set<string>();\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 // Set CSS custom properties for snap targeting\n if (item.minStateWidth) {\n item.el.style.setProperty('--min-state-width', item.minStateWidth);\n item.el.setAttribute('data-can-min', '');\n }\n }\n\n const inMenuIds = this.lastScan.menu?.inMenuIds ?? new Set<string>();\n this.minWidthMenuIds = minWidthMenuIds;\n this.orderedSteps = buildOrderedSteps(menuIds, 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 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 isSnap = this.host.isSnap();\n const hiddenMap = deriveHiddenMap(\n this.appliedSteps,\n isSnap,\n this.lastScan.menu?.inMenuIds,\n this.minWidthMenuIds,\n );\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 // ARIA attributes on the trigger\n menu.triggerEl.setAttribute('aria-haspopup', 'menu');\n menu.triggerEl.setAttribute('aria-expanded', String(showOpener));\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.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.removeAttribute('data-can-min');\n item.el.style.removeProperty('display');\n item.el.style.removeProperty('max-width');\n item.el.style.removeProperty('overflow');\n item.el.style.removeProperty('--min-state-width');\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 menu.triggerEl.removeAttribute('aria-haspopup');\n menu.triggerEl.removeAttribute('aria-expanded');\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","buildOrderedSteps","container","scrollWidth","clientWidth","next","computeNextSteps","isSnap","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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"}
@@ -22,9 +22,9 @@ export declare function computeNextSteps(prev: AppliedStep[], scrollWidth: numbe
22
22
  * Derive the hiddenMap from appliedSteps.
23
23
  * Later steps for the same menuId overwrite earlier ones (e.g., min → hidden).
24
24
  *
25
- * When `snap` is true, hidden state is expanded: if any item is 'hidden',
26
- * all menuIds in `inMenuIds` are also set to 'hidden'. Min state snap is
27
- * handled purely via CSS (`.overflow-snap:has(> [data-state="min"])`).
25
+ * When `snap` is true, states are expanded:
26
+ * - If any item is 'min', all items in `minWidthMenuIds` are set to 'min'.
27
+ * - If any item is 'hidden', all items in `inMenuIds` are set to 'hidden'.
28
28
  */
29
- export declare function deriveHiddenMap(appliedSteps: AppliedStep[], snap?: boolean, inMenuIds?: Set<string>): Map<string, 'min' | 'hidden'>;
29
+ export declare function deriveHiddenMap(appliedSteps: AppliedStep[], snap?: boolean, inMenuIds?: Set<string>, minWidthMenuIds?: Set<string>): Map<string, 'min' | 'hidden'>;
30
30
  //# sourceMappingURL=overflowSteps.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"overflowSteps.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/overflowSteps.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,GAAG,QAAQ,CAAC;CACxB;AAED,MAAM,WAAW,WAAY,SAAQ,IAAI;IACvC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EACtB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,GAC3B,IAAI,EAAE,CAaR;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,WAAW,EAAE,EACnB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,IAAI,EAAE,GACnB,WAAW,EAAE,CAef;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,WAAW,EAAE,EAC3B,IAAI,CAAC,EAAE,OAAO,EACd,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GACtB,GAAG,CAAC,MAAM,EAAE,KAAK,GAAG,QAAQ,CAAC,CAiB/B"}
1
+ {"version":3,"file":"overflowSteps.d.ts","sourceRoot":"","sources":["../../../src/components/Overflow/overflowSteps.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,GAAG,QAAQ,CAAC;CACxB;AAED,MAAM,WAAW,WAAY,SAAQ,IAAI;IACvC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EACtB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,GAC3B,IAAI,EAAE,CAaR;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,WAAW,EAAE,EACnB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,IAAI,EAAE,GACnB,WAAW,EAAE,CAef;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,WAAW,EAAE,EAC3B,IAAI,CAAC,EAAE,OAAO,EACd,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAC5B,GAAG,CAAC,MAAM,EAAE,KAAK,GAAG,QAAQ,CAAC,CAwB/B"}
@@ -1,43 +1,43 @@
1
- function i(e, o, s) {
2
- const n = [];
1
+ function u(e, o, n) {
2
+ const f = [];
3
3
  for (const t of e)
4
- s.has(t) && n.push({ menuId: t, step: "min" });
4
+ n.has(t) && f.push({ menuId: t, step: "min" });
5
5
  for (const t of e)
6
- o.has(t) && n.push({ menuId: t, step: "hidden" });
7
- return n;
6
+ o.has(t) && f.push({ menuId: t, step: "hidden" });
7
+ return f;
8
8
  }
9
- function d(e, o, s, n) {
10
- if (o > s) {
11
- const t = n[e.length];
12
- return t ? [...e, { ...t, width: s }] : e;
9
+ function d(e, o, n, f) {
10
+ if (o > n) {
11
+ const t = f[e.length];
12
+ return t ? [...e, { ...t, width: n }] : e;
13
13
  }
14
14
  if (e.length > 0) {
15
15
  const t = e[e.length - 1];
16
- if (s > t.width)
16
+ if (n > t.width)
17
17
  return e.slice(0, -1);
18
18
  }
19
19
  return e;
20
20
  }
21
- function r(e, o, s) {
22
- const n = /* @__PURE__ */ new Map();
23
- for (const { menuId: t, step: f } of e)
24
- n.set(t, f);
25
- if (o && s) {
26
- let t = !1;
27
- for (const f of n.values())
28
- if (f === "hidden") {
29
- t = !0;
30
- break;
31
- }
32
- if (t)
33
- for (const f of s)
34
- n.set(f, "hidden");
21
+ function c(e, o, n, f) {
22
+ const t = /* @__PURE__ */ new Map();
23
+ for (const { menuId: i, step: r } of e)
24
+ t.set(i, r);
25
+ if (o) {
26
+ let i = !1, r = !1;
27
+ for (const s of t.values())
28
+ s === "min" && (i = !0), s === "hidden" && (r = !0);
29
+ if (i && f)
30
+ for (const s of f)
31
+ t.has(s) || t.set(s, "min");
32
+ if (r && n)
33
+ for (const s of n)
34
+ t.set(s, "hidden");
35
35
  }
36
- return n;
36
+ return t;
37
37
  }
38
38
  export {
39
- i as buildOrderedSteps,
39
+ u as buildOrderedSteps,
40
40
  d as computeNextSteps,
41
- r as deriveHiddenMap
41
+ c as deriveHiddenMap
42
42
  };
43
43
  //# sourceMappingURL=overflowSteps.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"overflowSteps.js","sources":["../../../src/components/Overflow/overflowSteps.ts"],"sourcesContent":["export interface Step {\n menuId: string;\n step: 'min' | 'hidden';\n}\n\nexport interface AppliedStep extends Step {\n width: number;\n}\n\n/**\n * Build the ordered collapse sequence.\n * All min steps come first (in menuId order), then all hidden steps (in menuId order).\n * A menuId only gets a min step if it has a minStateWidth.\n * A menuId only gets a hidden step if it's represented in the menu.\n */\nexport function buildOrderedSteps(\n menuIds: string[],\n inMenuIds: Set<string>,\n minWidthMenuIds: Set<string>,\n): Step[] {\n const steps: Step[] = [];\n for (const menuId of menuIds) {\n if (minWidthMenuIds.has(menuId)) {\n steps.push({ menuId, step: 'min' });\n }\n }\n for (const menuId of menuIds) {\n if (inMenuIds.has(menuId)) {\n steps.push({ menuId, step: 'hidden' });\n }\n }\n return steps;\n}\n\n/**\n * Compute the next appliedSteps state given a resize event.\n * On overflow: push the next step from orderedSteps.\n * On space available: pop the last step if the container is wider than when it was applied.\n */\nexport function computeNextSteps(\n prev: AppliedStep[],\n scrollWidth: number,\n clientWidth: number,\n orderedSteps: Step[],\n): AppliedStep[] {\n if (scrollWidth > clientWidth) {\n const nextStep = orderedSteps[prev.length];\n if (!nextStep) return prev;\n return [...prev, { ...nextStep, width: clientWidth }];\n }\n\n if (prev.length > 0) {\n const lastStep = prev[prev.length - 1];\n if (clientWidth > lastStep.width) {\n return prev.slice(0, -1);\n }\n }\n\n return prev;\n}\n\n/**\n * Derive the hiddenMap from appliedSteps.\n * Later steps for the same menuId overwrite earlier ones (e.g., min → hidden).\n *\n * When `snap` is true, hidden state is expanded: if any item is 'hidden',\n * all menuIds in `inMenuIds` are also set to 'hidden'. Min state snap is\n * handled purely via CSS (`.overflow-snap:has(> [data-state=\"min\"])`).\n */\nexport function deriveHiddenMap(\n appliedSteps: AppliedStep[],\n snap?: boolean,\n inMenuIds?: Set<string>,\n): Map<string, 'min' | 'hidden'> {\n const map = new Map<string, 'min' | 'hidden'>();\n for (const { menuId, step } of appliedSteps) {\n map.set(menuId, step);\n }\n if (snap && inMenuIds) {\n let hasHidden = false;\n for (const v of map.values()) {\n if (v === 'hidden') { hasHidden = true; break; }\n }\n if (hasHidden) {\n for (const id of inMenuIds) {\n map.set(id, 'hidden');\n }\n }\n }\n return map;\n}\n"],"names":["buildOrderedSteps","menuIds","inMenuIds","minWidthMenuIds","steps","menuId","computeNextSteps","prev","scrollWidth","clientWidth","orderedSteps","nextStep","lastStep","deriveHiddenMap","appliedSteps","snap","map","step","hasHidden","v","id"],"mappings":"AAeO,SAASA,EACdC,GACAC,GACAC,GACQ;AACR,QAAMC,IAAgB,CAAA;AACtB,aAAWC,KAAUJ;AACnB,IAAIE,EAAgB,IAAIE,CAAM,KAC5BD,EAAM,KAAK,EAAE,QAAAC,GAAQ,MAAM,OAAO;AAGtC,aAAWA,KAAUJ;AACnB,IAAIC,EAAU,IAAIG,CAAM,KACtBD,EAAM,KAAK,EAAE,QAAAC,GAAQ,MAAM,UAAU;AAGzC,SAAOD;AACT;AAOO,SAASE,EACdC,GACAC,GACAC,GACAC,GACe;AACf,MAAIF,IAAcC,GAAa;AAC7B,UAAME,IAAWD,EAAaH,EAAK,MAAM;AACzC,WAAKI,IACE,CAAC,GAAGJ,GAAM,EAAE,GAAGI,GAAU,OAAOF,GAAa,IAD9BF;AAAA,EAExB;AAEA,MAAIA,EAAK,SAAS,GAAG;AACnB,UAAMK,IAAWL,EAAKA,EAAK,SAAS,CAAC;AACrC,QAAIE,IAAcG,EAAS;AACzB,aAAOL,EAAK,MAAM,GAAG,EAAE;AAAA,EAE3B;AAEA,SAAOA;AACT;AAUO,SAASM,EACdC,GACAC,GACAb,GAC+B;AAC/B,QAAMc,wBAAU,IAAA;AAChB,aAAW,EAAE,QAAAX,GAAQ,MAAAY,EAAA,KAAUH;AAC7B,IAAAE,EAAI,IAAIX,GAAQY,CAAI;AAEtB,MAAIF,KAAQb,GAAW;AACrB,QAAIgB,IAAY;AAChB,eAAWC,KAAKH,EAAI;AAClB,UAAIG,MAAM,UAAU;AAAE,QAAAD,IAAY;AAAM;AAAA,MAAO;AAEjD,QAAIA;AACF,iBAAWE,KAAMlB;AACf,QAAAc,EAAI,IAAII,GAAI,QAAQ;AAAA,EAG1B;AACA,SAAOJ;AACT;"}
1
+ {"version":3,"file":"overflowSteps.js","sources":["../../../src/components/Overflow/overflowSteps.ts"],"sourcesContent":["export interface Step {\n menuId: string;\n step: 'min' | 'hidden';\n}\n\nexport interface AppliedStep extends Step {\n width: number;\n}\n\n/**\n * Build the ordered collapse sequence.\n * All min steps come first (in menuId order), then all hidden steps (in menuId order).\n * A menuId only gets a min step if it has a minStateWidth.\n * A menuId only gets a hidden step if it's represented in the menu.\n */\nexport function buildOrderedSteps(\n menuIds: string[],\n inMenuIds: Set<string>,\n minWidthMenuIds: Set<string>,\n): Step[] {\n const steps: Step[] = [];\n for (const menuId of menuIds) {\n if (minWidthMenuIds.has(menuId)) {\n steps.push({ menuId, step: 'min' });\n }\n }\n for (const menuId of menuIds) {\n if (inMenuIds.has(menuId)) {\n steps.push({ menuId, step: 'hidden' });\n }\n }\n return steps;\n}\n\n/**\n * Compute the next appliedSteps state given a resize event.\n * On overflow: push the next step from orderedSteps.\n * On space available: pop the last step if the container is wider than when it was applied.\n */\nexport function computeNextSteps(\n prev: AppliedStep[],\n scrollWidth: number,\n clientWidth: number,\n orderedSteps: Step[],\n): AppliedStep[] {\n if (scrollWidth > clientWidth) {\n const nextStep = orderedSteps[prev.length];\n if (!nextStep) return prev;\n return [...prev, { ...nextStep, width: clientWidth }];\n }\n\n if (prev.length > 0) {\n const lastStep = prev[prev.length - 1];\n if (clientWidth > lastStep.width) {\n return prev.slice(0, -1);\n }\n }\n\n return prev;\n}\n\n/**\n * Derive the hiddenMap from appliedSteps.\n * Later steps for the same menuId overwrite earlier ones (e.g., min → hidden).\n *\n * When `snap` is true, states are expanded:\n * - If any item is 'min', all items in `minWidthMenuIds` are set to 'min'.\n * - If any item is 'hidden', all items in `inMenuIds` are set to 'hidden'.\n */\nexport function deriveHiddenMap(\n appliedSteps: AppliedStep[],\n snap?: boolean,\n inMenuIds?: Set<string>,\n minWidthMenuIds?: Set<string>,\n): Map<string, 'min' | 'hidden'> {\n const map = new Map<string, 'min' | 'hidden'>();\n for (const { menuId, step } of appliedSteps) {\n map.set(menuId, step);\n }\n if (snap) {\n let hasMin = false;\n let hasHidden = false;\n for (const v of map.values()) {\n if (v === 'min') hasMin = true;\n if (v === 'hidden') hasHidden = true;\n }\n if (hasMin && minWidthMenuIds) {\n for (const id of minWidthMenuIds) {\n if (!map.has(id)) map.set(id, 'min');\n }\n }\n if (hasHidden && inMenuIds) {\n for (const id of inMenuIds) {\n map.set(id, 'hidden');\n }\n }\n }\n return map;\n}\n"],"names":["buildOrderedSteps","menuIds","inMenuIds","minWidthMenuIds","steps","menuId","computeNextSteps","prev","scrollWidth","clientWidth","orderedSteps","nextStep","lastStep","deriveHiddenMap","appliedSteps","snap","map","step","hasMin","hasHidden","v","id"],"mappings":"AAeO,SAASA,EACdC,GACAC,GACAC,GACQ;AACR,QAAMC,IAAgB,CAAA;AACtB,aAAWC,KAAUJ;AACnB,IAAIE,EAAgB,IAAIE,CAAM,KAC5BD,EAAM,KAAK,EAAE,QAAAC,GAAQ,MAAM,OAAO;AAGtC,aAAWA,KAAUJ;AACnB,IAAIC,EAAU,IAAIG,CAAM,KACtBD,EAAM,KAAK,EAAE,QAAAC,GAAQ,MAAM,UAAU;AAGzC,SAAOD;AACT;AAOO,SAASE,EACdC,GACAC,GACAC,GACAC,GACe;AACf,MAAIF,IAAcC,GAAa;AAC7B,UAAME,IAAWD,EAAaH,EAAK,MAAM;AACzC,WAAKI,IACE,CAAC,GAAGJ,GAAM,EAAE,GAAGI,GAAU,OAAOF,GAAa,IAD9BF;AAAA,EAExB;AAEA,MAAIA,EAAK,SAAS,GAAG;AACnB,UAAMK,IAAWL,EAAKA,EAAK,SAAS,CAAC;AACrC,QAAIE,IAAcG,EAAS;AACzB,aAAOL,EAAK,MAAM,GAAG,EAAE;AAAA,EAE3B;AAEA,SAAOA;AACT;AAUO,SAASM,EACdC,GACAC,GACAb,GACAC,GAC+B;AAC/B,QAAMa,wBAAU,IAAA;AAChB,aAAW,EAAE,QAAAX,GAAQ,MAAAY,EAAA,KAAUH;AAC7B,IAAAE,EAAI,IAAIX,GAAQY,CAAI;AAEtB,MAAIF,GAAM;AACR,QAAIG,IAAS,IACTC,IAAY;AAChB,eAAWC,KAAKJ,EAAI;AAClB,MAAII,MAAM,UAAOF,IAAS,KACtBE,MAAM,aAAUD,IAAY;AAElC,QAAID,KAAUf;AACZ,iBAAWkB,KAAMlB;AACf,QAAKa,EAAI,IAAIK,CAAE,KAAGL,EAAI,IAAIK,GAAI,KAAK;AAGvC,QAAIF,KAAajB;AACf,iBAAWmB,KAAMnB;AACf,QAAAc,EAAI,IAAIK,GAAI,QAAQ;AAAA,EAG1B;AACA,SAAOL;AACT;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overflow-toolbar",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
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",