@godxjp/ui 28.6.0 → 28.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/dist/components/data-display/data-table.d.ts +10 -2
  2. package/dist/components/data-display/data-table.js +12 -5
  3. package/dist/components/data-display/index.d.ts +2 -0
  4. package/dist/components/data-display/index.js +2 -0
  5. package/dist/components/data-display/marquee.d.ts +16 -0
  6. package/dist/components/data-display/marquee.js +155 -0
  7. package/dist/components/data-display/scroll-area.js +16 -2
  8. package/dist/components/data-display/service-launcher-card.d.ts +25 -0
  9. package/dist/components/data-display/table.d.ts +38 -1
  10. package/dist/components/data-display/table.js +57 -39
  11. package/dist/components/data-entry/form-field.js +29 -12
  12. package/dist/components/general/reveal.d.ts +23 -2
  13. package/dist/components/general/reveal.js +37 -7
  14. package/dist/components/general/typography.d.ts +4 -1
  15. package/dist/components/general/typography.js +14 -1
  16. package/dist/components/layout/affix.d.ts +86 -0
  17. package/dist/components/layout/affix.js +187 -0
  18. package/dist/components/layout/index.d.ts +4 -0
  19. package/dist/components/layout/index.js +4 -0
  20. package/dist/components/layout/legal-document-shell.js +4 -3
  21. package/dist/components/layout/masonry.d.ts +74 -0
  22. package/dist/components/layout/masonry.js +214 -0
  23. package/dist/components/layout/page-container.js +5 -20
  24. package/dist/components/navigation/anchor.d.ts +64 -0
  25. package/dist/components/navigation/anchor.js +284 -0
  26. package/dist/components/navigation/app-setting-picker.js +20 -3
  27. package/dist/components/navigation/index.d.ts +4 -0
  28. package/dist/components/navigation/index.js +4 -0
  29. package/dist/components/navigation/mega-menu.d.ts +21 -0
  30. package/dist/components/navigation/mega-menu.js +526 -0
  31. package/dist/components/ui/table.js +1 -0
  32. package/dist/contracts/measurement.json +1 -1
  33. package/dist/i18n/messages/en.json +522 -1
  34. package/dist/i18n/messages/ja.json +518 -1
  35. package/dist/i18n/messages/vi.json +518 -1
  36. package/dist/lib/hooks.d.ts +91 -0
  37. package/dist/lib/hooks.js +79 -0
  38. package/dist/lib/platform.d.ts +14 -0
  39. package/dist/lib/platform.js +10 -1
  40. package/dist/lib/utils.d.ts +1 -1
  41. package/dist/lib/utils.js +3 -2
  42. package/dist/props/components/data-display.prop.d.ts +109 -1
  43. package/dist/props/components/general.prop.d.ts +47 -3
  44. package/dist/props/components/layout.prop.d.ts +194 -0
  45. package/dist/props/components/navigation.prop.d.ts +263 -0
  46. package/dist/props/registry.d.ts +360 -5
  47. package/dist/props/registry.js +474 -4
  48. package/dist/props/vocabulary/index.d.ts +1 -1
  49. package/dist/props/vocabulary/interaction.prop.d.ts +39 -2
  50. package/dist/styles/control.css +5 -6
  51. package/dist/styles/data-display-layout.css +2 -1
  52. package/dist/styles/density.css +4 -0
  53. package/dist/styles/form-layout.css +22 -0
  54. package/dist/styles/layout.css +79 -1
  55. package/dist/styles/motion.css +121 -1
  56. package/dist/styles/navigation-layout.css +415 -20
  57. package/dist/styles/shell-layout.css +3 -0
  58. package/dist/styles/text-layout.css +52 -4
  59. package/dist/tokens/base.css +5 -0
  60. package/dist/tokens/components/affix.css +7 -0
  61. package/dist/tokens/components/anchor.css +17 -0
  62. package/dist/tokens/components/control.css +3 -3
  63. package/dist/tokens/components/form.css +3 -1
  64. package/dist/tokens/components/marquee.css +7 -0
  65. package/dist/tokens/components/masonry.css +6 -0
  66. package/dist/tokens/components/mega-menu.css +62 -0
  67. package/dist/tokens/components/navigation.css +2 -0
  68. package/dist/tokens/components/shell.css +3 -0
  69. package/dist/tokens/foundation.css +11 -0
  70. package/dist/tokens/semantic/layout.css +7 -0
  71. package/docs/COMPOSITION-VS-COMPONENT.md +21 -0
  72. package/docs/DESIGN-AUTHORITY.md +124 -23
  73. package/docs/FRAME-COVERAGE-REPORT.md +7 -2
  74. package/docs/data-display/marquee.tsx +254 -0
  75. package/docs/data-display/scroll-area.tsx +31 -0
  76. package/docs/data-display/service-launcher-card.tsx +275 -115
  77. package/docs/foundation/_theme-editor-scope.ts +222 -0
  78. package/docs/foundation/density.tsx +12 -2
  79. package/docs/foundation/spacing.tsx +5 -0
  80. package/docs/foundation/theme-editor.tsx +645 -0
  81. package/docs/general/activity.tsx +65 -0
  82. package/docs/general/reveal.tsx +290 -22
  83. package/docs/general/typography.tsx +91 -1
  84. package/docs/layout/affix.tsx +209 -0
  85. package/docs/layout/masonry.tsx +291 -0
  86. package/docs/navigation/anchor.tsx +285 -0
  87. package/docs/navigation/mega-menu-panel.tsx +86 -0
  88. package/docs/navigation/mega-menu.tsx +254 -0
  89. package/docs/roadmap/website-components.md +779 -0
  90. package/docs/showcase/acme-website.tsx +75 -39
  91. package/docs/showcase/futurelastic-web.tsx +91 -49
  92. package/docs/showcase/marketing-page.tsx +885 -0
  93. package/docs/showcase/table-footer-totals.tsx +12 -2
  94. package/docs/showcase/theme-customization.tsx +1259 -0
  95. package/package.json +8 -5
  96. package/scripts/brand-accent.generated.mjs +27 -0
  97. package/scripts/ui-audit.mjs +66 -0
  98. package/scripts/visual-audit-rules.mjs +46 -2
  99. package/scripts/visual-audit.mjs +29 -1
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+ import type { MegaMenuItemProp, MegaMenuLinkComponentProp } from "../../props/components/navigation.prop.js";
3
+ export type { MegaMenuGroupProp, MegaMenuGroupProp as MegaMenuGroupProps, MegaMenuItemProp, MegaMenuItemProp as MegaMenuItemProps, MegaMenuLinkComponentProp, MegaMenuLinkComponentProp as MegaMenuLinkComponentProps, MegaMenuLinkProp, MegaMenuLinkProp as MegaMenuLinkProps, MegaMenuPanelProp, MegaMenuPanelProp as MegaMenuPanelProps, MegaMenuProp, MegaMenuProp as MegaMenuProps, MegaMenuTriggerActionProp, MegaMenuTriggerActionProp as MegaMenuTriggerActionProps, } from "../../props/components/navigation.prop.js";
4
+ export declare const MegaMenu: React.ForwardRefExoticComponent<{
5
+ items: readonly MegaMenuItemProp[];
6
+ open?: string | null;
7
+ defaultOpen?: string | null;
8
+ onOpenChange?: (key: string | null) => void;
9
+ value?: string;
10
+ defaultValue?: string;
11
+ onValueChange?: (key: string) => void;
12
+ size?: "xs" | "sm" | "md" | "lg";
13
+ triggerAction?: import("./mega-menu.js").MegaMenuTriggerActionProp;
14
+ openDelay?: number;
15
+ closeDelay?: number;
16
+ label?: string;
17
+ expandIcon?: React.ReactNode | false;
18
+ linkComponent?: MegaMenuLinkComponentProp;
19
+ id?: import("../../props/index.js").IdProp;
20
+ className?: import("../../props/index.js").ClassNameProp;
21
+ } & Omit<React.HTMLAttributes<HTMLElement>, "children" | "defaultValue" | "onChange"> & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1,526 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { ChevronDown } from "lucide-react";
5
+ import { cn } from "../../lib/utils.js";
6
+ import { useTranslation } from "../../i18n/use-translation.js";
7
+ const OPEN_DELAY_MS = 0;
8
+ const CLOSE_DELAY_MS = 100;
9
+ function nextEnabled(items, from, step) {
10
+ const count = items.length;
11
+ for (let hop = 1; hop <= count; hop++) {
12
+ const index = (from + step * hop + count * count) % count;
13
+ if (!items[index]?.disabled) return index;
14
+ }
15
+ return from;
16
+ }
17
+ function firstEnabled(items, from) {
18
+ const order = from === "start" ? items.map((_, i) => i) : items.map((_, i) => i).reverse();
19
+ return order.find((index) => !items[index]?.disabled) ?? 0;
20
+ }
21
+ function panelLinks(panel) {
22
+ if (!panel) return [];
23
+ return Array.from(panel.querySelectorAll("a[href]"));
24
+ }
25
+ function MegaMenuPanelLink({
26
+ link,
27
+ itemKey,
28
+ current,
29
+ linkComponent: LinkComponent,
30
+ onActivate
31
+ }) {
32
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
33
+ link.icon ? (
34
+ // Decorative: the label is the accessible name, so the glyph must not be announced twice.
35
+ /* @__PURE__ */ jsx("span", { "data-slot": "mega-menu-link-icon", className: "ui-mega-menu-link-icon", "aria-hidden": "true", children: link.icon })
36
+ ) : null,
37
+ /* @__PURE__ */ jsxs("span", { "data-slot": "mega-menu-link-text", className: "ui-mega-menu-link-text", children: [
38
+ /* @__PURE__ */ jsx("span", { className: "ui-mega-menu-link-label", children: link.label }),
39
+ link.description ? /* @__PURE__ */ jsx("span", { "data-slot": "mega-menu-link-description", className: "ui-mega-menu-link-description", children: link.description }) : null
40
+ ] })
41
+ ] });
42
+ const anchorProps = {
43
+ className: "ui-mega-menu-link ui-focus-ring",
44
+ "data-slot": "mega-menu-link",
45
+ href: link.disabled ? void 0 : link.href,
46
+ "aria-current": current ? "page" : void 0,
47
+ "aria-disabled": link.disabled || void 0,
48
+ "data-disabled": link.disabled ? "true" : void 0,
49
+ onClick: (event) => {
50
+ if (link.disabled) {
51
+ event.preventDefault();
52
+ return;
53
+ }
54
+ onActivate(link.key);
55
+ }
56
+ };
57
+ return /* @__PURE__ */ jsx("li", { className: "ui-mega-menu-link-row", "data-item": itemKey, children: LinkComponent && link.href && !link.disabled ? /* @__PURE__ */ jsx(LinkComponent, { ...anchorProps, children: content }) : (
58
+ // An href-less anchor is the DISABLED row: no destination, so no tab stop and no arrow
59
+ // landing, while `aria-disabled` keeps it announced with its name and its reason.
60
+ /* @__PURE__ */ jsx("a", { ...anchorProps, children: content })
61
+ ) });
62
+ }
63
+ function MegaMenuGroupColumn({
64
+ group,
65
+ itemKey,
66
+ value,
67
+ linkComponent,
68
+ onActivate,
69
+ headingId
70
+ }) {
71
+ return /* @__PURE__ */ jsxs("li", { className: "ui-mega-menu-group", "data-slot": "mega-menu-group", children: [
72
+ group.label ? /* @__PURE__ */ jsxs("p", { className: "ui-mega-menu-group-label", id: headingId, "data-slot": "mega-menu-group-label", children: [
73
+ group.icon ? /* @__PURE__ */ jsx("span", { className: "ui-mega-menu-group-icon", "aria-hidden": "true", children: group.icon }) : null,
74
+ group.label
75
+ ] }) : null,
76
+ group.description ? /* @__PURE__ */ jsx("p", { className: "ui-mega-menu-group-description", "data-slot": "mega-menu-group-description", children: group.description }) : null,
77
+ /* @__PURE__ */ jsx(
78
+ "ul",
79
+ {
80
+ className: "ui-mega-menu-group-links",
81
+ "aria-labelledby": group.label ? headingId : void 0,
82
+ children: group.links.map((link) => /* @__PURE__ */ jsx(
83
+ MegaMenuPanelLink,
84
+ {
85
+ link,
86
+ itemKey,
87
+ current: value === link.key,
88
+ linkComponent,
89
+ onActivate
90
+ },
91
+ link.key
92
+ ))
93
+ }
94
+ )
95
+ ] });
96
+ }
97
+ const MegaMenu = React.forwardRef(function MegaMenu2({
98
+ items,
99
+ open,
100
+ defaultOpen = null,
101
+ onOpenChange,
102
+ value,
103
+ defaultValue,
104
+ onValueChange,
105
+ size = "md",
106
+ triggerAction = "click",
107
+ openDelay = OPEN_DELAY_MS,
108
+ closeDelay = CLOSE_DELAY_MS,
109
+ label,
110
+ expandIcon,
111
+ linkComponent,
112
+ className,
113
+ id,
114
+ style,
115
+ ...props
116
+ }, ref) {
117
+ const { t } = useTranslation();
118
+ const reactId = React.useId();
119
+ const baseId = id ?? `mega-menu-${reactId}`;
120
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
121
+ const openKey = open !== void 0 ? open : uncontrolledOpen;
122
+ const [uncontrolledValue, setUncontrolledValue] = React.useState(
123
+ defaultValue
124
+ );
125
+ const currentValue = value !== void 0 ? value : uncontrolledValue;
126
+ const [focusIndex, setFocusIndex] = React.useState(() => firstEnabled(items, "start"));
127
+ const rootRef = React.useRef(null);
128
+ const triggerRefs = React.useRef(/* @__PURE__ */ new Map());
129
+ const panelRefs = React.useRef(/* @__PURE__ */ new Map());
130
+ const openTimer = React.useRef(null);
131
+ const closeTimer = React.useRef(null);
132
+ const setRootRef = React.useCallback(
133
+ (node) => {
134
+ rootRef.current = node;
135
+ if (typeof ref === "function") ref(node);
136
+ else if (ref) ref.current = node;
137
+ },
138
+ [ref]
139
+ );
140
+ const clearTimers = React.useCallback(() => {
141
+ if (openTimer.current) {
142
+ clearTimeout(openTimer.current);
143
+ openTimer.current = null;
144
+ }
145
+ if (closeTimer.current) {
146
+ clearTimeout(closeTimer.current);
147
+ closeTimer.current = null;
148
+ }
149
+ }, []);
150
+ React.useEffect(() => clearTimers, [clearTimers]);
151
+ const [panelOffset, setPanelOffset] = React.useState(
152
+ null
153
+ );
154
+ React.useLayoutEffect(() => {
155
+ if (openKey === null) {
156
+ setPanelOffset(null);
157
+ return;
158
+ }
159
+ const measure = () => {
160
+ const node = rootRef.current;
161
+ if (!node || typeof window === "undefined") return;
162
+ const rect = node.getBoundingClientRect();
163
+ const rtl = window.getComputedStyle(node).direction === "rtl";
164
+ setPanelOffset({
165
+ // Under RTL the panel's own `inset-inline-start: 0` resolves to the viewport's RIGHT
166
+ // edge, so the offset is measured from there and is normally negative.
167
+ x: rtl ? rect.right - window.innerWidth : rect.left,
168
+ y: rect.bottom,
169
+ w: rect.width
170
+ });
171
+ };
172
+ measure();
173
+ window.addEventListener("resize", measure);
174
+ window.addEventListener("scroll", measure, { capture: true, passive: true });
175
+ return () => {
176
+ window.removeEventListener("resize", measure);
177
+ window.removeEventListener("scroll", measure, { capture: true });
178
+ };
179
+ }, [openKey]);
180
+ const commitOpen = React.useCallback(
181
+ (key) => {
182
+ if (open === void 0) setUncontrolledOpen(key);
183
+ onOpenChange?.(key);
184
+ },
185
+ [open, onOpenChange]
186
+ );
187
+ const close = React.useCallback(() => {
188
+ clearTimers();
189
+ if (openKey !== null) commitOpen(null);
190
+ }, [clearTimers, commitOpen, openKey]);
191
+ const closeAndRestore = React.useCallback(
192
+ (key) => {
193
+ clearTimers();
194
+ commitOpen(null);
195
+ triggerRefs.current.get(key)?.focus();
196
+ },
197
+ [clearTimers, commitOpen]
198
+ );
199
+ const activate = React.useCallback(
200
+ (key) => {
201
+ if (value === void 0) setUncontrolledValue(key);
202
+ onValueChange?.(key);
203
+ close();
204
+ },
205
+ [value, onValueChange, close]
206
+ );
207
+ const firstRoute = React.useRef(true);
208
+ React.useEffect(() => {
209
+ if (firstRoute.current) {
210
+ firstRoute.current = false;
211
+ return;
212
+ }
213
+ close();
214
+ }, [currentValue]);
215
+ React.useEffect(() => {
216
+ if (openKey === null) return;
217
+ const onPointerDown = (event) => {
218
+ const node = rootRef.current;
219
+ if (node && event.target instanceof Node && !node.contains(event.target)) close();
220
+ };
221
+ document.addEventListener("pointerdown", onPointerDown);
222
+ return () => document.removeEventListener("pointerdown", onPointerDown);
223
+ }, [openKey, close]);
224
+ const isRtl = () => {
225
+ const node = rootRef.current;
226
+ if (!node || typeof window === "undefined") return false;
227
+ return window.getComputedStyle(node).direction === "rtl";
228
+ };
229
+ const focusTrigger = (index) => {
230
+ const item = items[index];
231
+ if (!item) return;
232
+ setFocusIndex(index);
233
+ triggerRefs.current.get(item.key)?.focus();
234
+ };
235
+ const [pendingFocus, setPendingFocus] = React.useState(null);
236
+ React.useLayoutEffect(() => {
237
+ if (!pendingFocus) return;
238
+ if (openKey === pendingFocus.key) {
239
+ const links = panelLinks(panelRefs.current.get(pendingFocus.key) ?? null);
240
+ const target = pendingFocus.edge === "first" ? links[0] : links[links.length - 1];
241
+ target?.focus();
242
+ }
243
+ setPendingFocus(null);
244
+ }, [pendingFocus, openKey]);
245
+ const openPanel = React.useCallback(
246
+ (key, focus) => {
247
+ clearTimers();
248
+ commitOpen(key);
249
+ if (focus) setPendingFocus({ key, edge: focus });
250
+ },
251
+ [clearTimers, commitOpen]
252
+ );
253
+ const onBarKeyDown = (event, index, item) => {
254
+ const forward = isRtl() ? "ArrowLeft" : "ArrowRight";
255
+ const backward = isRtl() ? "ArrowRight" : "ArrowLeft";
256
+ const move = (to) => {
257
+ event.preventDefault();
258
+ focusTrigger(to);
259
+ if (openKey !== null) {
260
+ const target = items[to];
261
+ if (target?.panel) commitOpen(target.key);
262
+ else commitOpen(null);
263
+ }
264
+ };
265
+ switch (event.key) {
266
+ case forward:
267
+ move(nextEnabled(items, index, 1));
268
+ return;
269
+ case backward:
270
+ move(nextEnabled(items, index, -1));
271
+ return;
272
+ case "Home":
273
+ move(firstEnabled(items, "start"));
274
+ return;
275
+ case "End":
276
+ move(firstEnabled(items, "end"));
277
+ return;
278
+ case "Escape":
279
+ if (openKey !== null) {
280
+ event.preventDefault();
281
+ closeAndRestore(openKey);
282
+ }
283
+ return;
284
+ case "ArrowDown":
285
+ if (item.panel) {
286
+ event.preventDefault();
287
+ openPanel(item.key, "first");
288
+ }
289
+ return;
290
+ case "ArrowUp":
291
+ if (item.panel) {
292
+ event.preventDefault();
293
+ openPanel(item.key, "last");
294
+ }
295
+ return;
296
+ case "Enter":
297
+ case " ":
298
+ if (item.panel) {
299
+ event.preventDefault();
300
+ if (openKey === item.key) closeAndRestore(item.key);
301
+ else openPanel(item.key);
302
+ }
303
+ return;
304
+ default:
305
+ }
306
+ };
307
+ const onPanelKeyDown = (event, itemKey) => {
308
+ const links = panelLinks(panelRefs.current.get(itemKey) ?? null);
309
+ const at = links.indexOf(document.activeElement);
310
+ const focusLink = (to) => {
311
+ event.preventDefault();
312
+ links[Math.max(0, Math.min(links.length - 1, to))]?.focus();
313
+ };
314
+ switch (event.key) {
315
+ case "Escape":
316
+ event.preventDefault();
317
+ closeAndRestore(itemKey);
318
+ return;
319
+ case "ArrowDown":
320
+ focusLink(at + 1);
321
+ return;
322
+ case "ArrowUp":
323
+ if (at <= 0) {
324
+ event.preventDefault();
325
+ closeAndRestore(itemKey);
326
+ return;
327
+ }
328
+ focusLink(at - 1);
329
+ return;
330
+ case "Home":
331
+ focusLink(0);
332
+ return;
333
+ case "End":
334
+ focusLink(links.length - 1);
335
+ return;
336
+ default:
337
+ }
338
+ };
339
+ const onBlurCapture = (event) => {
340
+ const node = rootRef.current;
341
+ const next = event.relatedTarget;
342
+ if (!node) return;
343
+ if (next instanceof Node && node.contains(next)) return;
344
+ close();
345
+ };
346
+ const hoverable = triggerAction === "hover";
347
+ const onTriggerPointerEnter = (event, item) => {
348
+ if (!hoverable || item.disabled || !item.panel) return;
349
+ if (event.pointerType === "touch") return;
350
+ if (closeTimer.current) {
351
+ clearTimeout(closeTimer.current);
352
+ closeTimer.current = null;
353
+ }
354
+ if (openKey !== null) {
355
+ clearTimers();
356
+ commitOpen(item.key);
357
+ return;
358
+ }
359
+ if (openTimer.current) clearTimeout(openTimer.current);
360
+ openTimer.current = setTimeout(() => {
361
+ openTimer.current = null;
362
+ commitOpen(item.key);
363
+ }, openDelay);
364
+ };
365
+ const onTriggerPointerLeave = () => {
366
+ if (openTimer.current) {
367
+ clearTimeout(openTimer.current);
368
+ openTimer.current = null;
369
+ }
370
+ };
371
+ const onRootPointerEnter = () => {
372
+ if (closeTimer.current) {
373
+ clearTimeout(closeTimer.current);
374
+ closeTimer.current = null;
375
+ }
376
+ };
377
+ const onRootPointerLeave = (event) => {
378
+ if (!hoverable || event.pointerType === "touch") return;
379
+ if (openKey === null) return;
380
+ if (closeTimer.current) clearTimeout(closeTimer.current);
381
+ closeTimer.current = setTimeout(() => {
382
+ closeTimer.current = null;
383
+ const node = rootRef.current;
384
+ if (node && node.contains(document.activeElement)) return;
385
+ commitOpen(null);
386
+ }, closeDelay);
387
+ };
388
+ const chevron = expandIcon === false ? null : /* @__PURE__ */ jsx(
389
+ "span",
390
+ {
391
+ "data-slot": "mega-menu-expand-icon",
392
+ className: "ui-mega-menu-expand-icon",
393
+ "aria-hidden": "true",
394
+ children: expandIcon ?? /* @__PURE__ */ jsx(ChevronDown, {})
395
+ }
396
+ );
397
+ return /* @__PURE__ */ jsx(
398
+ "nav",
399
+ {
400
+ ref: setRootRef,
401
+ id: baseId,
402
+ "data-slot": "mega-menu",
403
+ "data-size": size,
404
+ "data-trigger-action": triggerAction,
405
+ "data-open": openKey === null ? void 0 : "true",
406
+ "aria-label": label ?? t("navigation.megaMenu.label"),
407
+ className: cn("ui-mega-menu", className),
408
+ style: panelOffset ? {
409
+ ...style,
410
+ "--mega-menu-panel-translate-x": `${panelOffset.x}px`,
411
+ "--mega-menu-panel-translate-y": `${panelOffset.y}px`,
412
+ "--mega-menu-panel-measured-width": `${panelOffset.w}px`
413
+ } : style,
414
+ onPointerEnter: onRootPointerEnter,
415
+ onPointerLeave: onRootPointerLeave,
416
+ onBlurCapture,
417
+ ...props,
418
+ children: /* @__PURE__ */ jsx("ul", { "data-slot": "mega-menu-bar", className: "ui-mega-menu-bar", children: items.map((item, index) => {
419
+ const panelId = `${baseId}-panel-${item.key}`;
420
+ const expanded = openKey === item.key;
421
+ const current = currentValue === item.key;
422
+ const roving = index === focusIndex ? 0 : -1;
423
+ const sharedTrigger = {
424
+ "data-slot": "mega-menu-trigger",
425
+ "data-open": expanded ? "true" : void 0,
426
+ className: "ui-mega-menu-trigger ui-focus-ring",
427
+ tabIndex: item.disabled ? -1 : roving,
428
+ onKeyDown: (event) => onBarKeyDown(event, index, item),
429
+ onFocus: () => setFocusIndex(index),
430
+ onPointerEnter: (event) => onTriggerPointerEnter(event, item),
431
+ onPointerLeave: onTriggerPointerLeave
432
+ };
433
+ const labelNode = /* @__PURE__ */ jsxs(Fragment, { children: [
434
+ item.icon ? /* @__PURE__ */ jsx("span", { className: "ui-mega-menu-trigger-icon", "aria-hidden": "true", children: item.icon }) : null,
435
+ /* @__PURE__ */ jsx("span", { className: "ui-mega-menu-trigger-label", children: item.label })
436
+ ] });
437
+ return /* @__PURE__ */ jsxs("li", { className: "ui-mega-menu-item", "data-slot": "mega-menu-item", children: [
438
+ item.panel ? (
439
+ // ui-audit-disable-next-line no-raw-button — a DISCLOSURE TRIGGER, not a Button.
440
+ // The APG pattern names `<button aria-expanded aria-controls>` as the element, and
441
+ // this one is a bar cell under a roving tabindex: wrapping it in `Button` would
442
+ // layer Button's variant padding, its own focus treatment and its tabIndex on top
443
+ // of the bar's. Sidebar's own nav row carries the identical exemption.
444
+ /* @__PURE__ */ jsxs(
445
+ "button",
446
+ {
447
+ type: "button",
448
+ ref: (node) => {
449
+ if (node) triggerRefs.current.set(item.key, node);
450
+ else triggerRefs.current.delete(item.key);
451
+ },
452
+ "aria-expanded": expanded,
453
+ "aria-controls": panelId,
454
+ "aria-current": current ? "page" : void 0,
455
+ disabled: item.disabled,
456
+ onClick: () => {
457
+ if (expanded) closeAndRestore(item.key);
458
+ else openPanel(item.key);
459
+ },
460
+ ...sharedTrigger,
461
+ children: [
462
+ labelNode,
463
+ chevron
464
+ ]
465
+ }
466
+ )
467
+ ) : /* @__PURE__ */ jsx(
468
+ "a",
469
+ {
470
+ ref: (node) => {
471
+ if (node) triggerRefs.current.set(item.key, node);
472
+ else triggerRefs.current.delete(item.key);
473
+ },
474
+ href: item.disabled ? void 0 : item.href,
475
+ "aria-current": current ? "page" : void 0,
476
+ "aria-disabled": item.disabled || void 0,
477
+ "data-disabled": item.disabled ? "true" : void 0,
478
+ onClick: (event) => {
479
+ if (item.disabled) {
480
+ event.preventDefault();
481
+ return;
482
+ }
483
+ activate(item.key);
484
+ },
485
+ ...sharedTrigger,
486
+ children: labelNode
487
+ }
488
+ ),
489
+ item.panel ? /* @__PURE__ */ jsx(
490
+ "div",
491
+ {
492
+ ref: (node) => {
493
+ if (node) panelRefs.current.set(item.key, node);
494
+ else panelRefs.current.delete(item.key);
495
+ },
496
+ id: panelId,
497
+ "data-slot": "mega-menu-panel",
498
+ className: "ui-mega-menu-panel",
499
+ hidden: !expanded,
500
+ onKeyDown: (event) => onPanelKeyDown(event, item.key),
501
+ children: /* @__PURE__ */ jsxs("div", { className: "ui-mega-menu-panel-inner", children: [
502
+ /* @__PURE__ */ jsx("ul", { className: "ui-mega-menu-groups", children: item.panel.groups.map((group) => /* @__PURE__ */ jsx(
503
+ MegaMenuGroupColumn,
504
+ {
505
+ group,
506
+ itemKey: item.key,
507
+ value: currentValue,
508
+ linkComponent,
509
+ onActivate: activate,
510
+ headingId: `${panelId}-${group.key}`
511
+ },
512
+ group.key
513
+ )) }),
514
+ item.panel.footer ? /* @__PURE__ */ jsx("div", { "data-slot": "mega-menu-panel-footer", className: "ui-mega-menu-panel-footer", children: item.panel.footer }) : null
515
+ ] })
516
+ }
517
+ ) : null
518
+ ] }, item.key);
519
+ }) })
520
+ }
521
+ );
522
+ });
523
+ MegaMenu.displayName = "MegaMenu";
524
+ export {
525
+ MegaMenu
526
+ };
@@ -1 +1,2 @@
1
+ "use client";
1
2
  export * from "../data-display/table.js";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
3
- "version": "28.6.0",
3
+ "version": "28.8.0",
4
4
  "targetSize": {
5
5
  "standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
6
6
  "min": 24,