@aglyn/plugins-mui 1.0.0-beta.143

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 (177) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +22 -0
  3. package/package.json +47 -0
  4. package/src/index.d.ts +21 -0
  5. package/src/index.js +22 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/accordion.d.ts +96 -0
  8. package/src/lib/components/accordion.js +392 -0
  9. package/src/lib/components/accordion.js.map +1 -0
  10. package/src/lib/components/app-bar.d.ts +32 -0
  11. package/src/lib/components/app-bar.js +86 -0
  12. package/src/lib/components/app-bar.js.map +1 -0
  13. package/src/lib/components/blocks.d.ts +46 -0
  14. package/src/lib/components/blocks.js +1007 -0
  15. package/src/lib/components/blocks.js.map +1 -0
  16. package/src/lib/components/box.d.ts +47 -0
  17. package/src/lib/components/box.js +125 -0
  18. package/src/lib/components/box.js.map +1 -0
  19. package/src/lib/components/breadcrumbs.d.ts +44 -0
  20. package/src/lib/components/breadcrumbs.js +172 -0
  21. package/src/lib/components/breadcrumbs.js.map +1 -0
  22. package/src/lib/components/button.d.ts +89 -0
  23. package/src/lib/components/button.js +272 -0
  24. package/src/lib/components/button.js.map +1 -0
  25. package/src/lib/components/card.d.ts +61 -0
  26. package/src/lib/components/card.js +336 -0
  27. package/src/lib/components/card.js.map +1 -0
  28. package/src/lib/components/collection.d.ts +514 -0
  29. package/src/lib/components/collection.js +2999 -0
  30. package/src/lib/components/collection.js.map +1 -0
  31. package/src/lib/components/container.d.ts +42 -0
  32. package/src/lib/components/container.js +169 -0
  33. package/src/lib/components/container.js.map +1 -0
  34. package/src/lib/components/custom-html.d.ts +78 -0
  35. package/src/lib/components/custom-html.js +219 -0
  36. package/src/lib/components/custom-html.js.map +1 -0
  37. package/src/lib/components/data-table.d.ts +57 -0
  38. package/src/lib/components/data-table.js +216 -0
  39. package/src/lib/components/data-table.js.map +1 -0
  40. package/src/lib/components/document-root.d.ts +77 -0
  41. package/src/lib/components/document-root.js +118 -0
  42. package/src/lib/components/document-root.js.map +1 -0
  43. package/src/lib/components/drawer.d.ts +93 -0
  44. package/src/lib/components/drawer.js +566 -0
  45. package/src/lib/components/drawer.js.map +1 -0
  46. package/src/lib/components/function-controls.d.ts +66 -0
  47. package/src/lib/components/function-controls.js +207 -0
  48. package/src/lib/components/function-controls.js.map +1 -0
  49. package/src/lib/components/function-scope.d.ts +110 -0
  50. package/src/lib/components/function-scope.js +478 -0
  51. package/src/lib/components/function-scope.js.map +1 -0
  52. package/src/lib/components/function-widget.d.ts +75 -0
  53. package/src/lib/components/function-widget.js +307 -0
  54. package/src/lib/components/function-widget.js.map +1 -0
  55. package/src/lib/components/grid.d.ts +91 -0
  56. package/src/lib/components/grid.js +322 -0
  57. package/src/lib/components/grid.js.map +1 -0
  58. package/src/lib/components/icon.d.ts +54 -0
  59. package/src/lib/components/icon.js +163 -0
  60. package/src/lib/components/icon.js.map +1 -0
  61. package/src/lib/components/image-list.d.ts +58 -0
  62. package/src/lib/components/image-list.js +336 -0
  63. package/src/lib/components/image-list.js.map +1 -0
  64. package/src/lib/components/image.d.ts +154 -0
  65. package/src/lib/components/image.js +451 -0
  66. package/src/lib/components/image.js.map +1 -0
  67. package/src/lib/components/inline-text.d.ts +74 -0
  68. package/src/lib/components/inline-text.js +407 -0
  69. package/src/lib/components/inline-text.js.map +1 -0
  70. package/src/lib/components/language-switcher.d.ts +35 -0
  71. package/src/lib/components/language-switcher.js +179 -0
  72. package/src/lib/components/language-switcher.js.map +1 -0
  73. package/src/lib/components/layout-slot.d.ts +68 -0
  74. package/src/lib/components/layout-slot.js +192 -0
  75. package/src/lib/components/layout-slot.js.map +1 -0
  76. package/src/lib/components/link-box-accessible-name.d.ts +79 -0
  77. package/src/lib/components/link-box-accessible-name.js +158 -0
  78. package/src/lib/components/link-box-accessible-name.js.map +1 -0
  79. package/src/lib/components/link-box.d.ts +66 -0
  80. package/src/lib/components/link-box.js +212 -0
  81. package/src/lib/components/link-box.js.map +1 -0
  82. package/src/lib/components/list-item-text.d.ts +22 -0
  83. package/src/lib/components/list-item-text.js +86 -0
  84. package/src/lib/components/list-item-text.js.map +1 -0
  85. package/src/lib/components/list-item.d.ts +32 -0
  86. package/src/lib/components/list-item.js +127 -0
  87. package/src/lib/components/list-item.js.map +1 -0
  88. package/src/lib/components/list.d.ts +34 -0
  89. package/src/lib/components/list.js +108 -0
  90. package/src/lib/components/list.js.map +1 -0
  91. package/src/lib/components/markdown.d.ts +129 -0
  92. package/src/lib/components/markdown.js +853 -0
  93. package/src/lib/components/markdown.js.map +1 -0
  94. package/src/lib/components/nav-menu.d.ts +68 -0
  95. package/src/lib/components/nav-menu.js +683 -0
  96. package/src/lib/components/nav-menu.js.map +1 -0
  97. package/src/lib/components/pagination.d.ts +59 -0
  98. package/src/lib/components/pagination.js +243 -0
  99. package/src/lib/components/pagination.js.map +1 -0
  100. package/src/lib/components/paper.d.ts +47 -0
  101. package/src/lib/components/paper.js +202 -0
  102. package/src/lib/components/paper.js.map +1 -0
  103. package/src/lib/components/plugin-frame.d.ts +64 -0
  104. package/src/lib/components/plugin-frame.js +335 -0
  105. package/src/lib/components/plugin-frame.js.map +1 -0
  106. package/src/lib/components/plugin.d.ts +95 -0
  107. package/src/lib/components/plugin.js +304 -0
  108. package/src/lib/components/plugin.js.map +1 -0
  109. package/src/lib/components/product.d.ts +40 -0
  110. package/src/lib/components/product.js +287 -0
  111. package/src/lib/components/product.js.map +1 -0
  112. package/src/lib/components/reusable-instance.d.ts +57 -0
  113. package/src/lib/components/reusable-instance.js +126 -0
  114. package/src/lib/components/reusable-instance.js.map +1 -0
  115. package/src/lib/components/screen-link.d.ts +85 -0
  116. package/src/lib/components/screen-link.js +324 -0
  117. package/src/lib/components/screen-link.js.map +1 -0
  118. package/src/lib/components/search-box.d.ts +41 -0
  119. package/src/lib/components/search-box.js +125 -0
  120. package/src/lib/components/search-box.js.map +1 -0
  121. package/src/lib/components/section.d.ts +56 -0
  122. package/src/lib/components/section.js +132 -0
  123. package/src/lib/components/section.js.map +1 -0
  124. package/src/lib/components/stack.d.ts +55 -0
  125. package/src/lib/components/stack.js +309 -0
  126. package/src/lib/components/stack.js.map +1 -0
  127. package/src/lib/components/tabs.d.ts +288 -0
  128. package/src/lib/components/tabs.js +788 -0
  129. package/src/lib/components/tabs.js.map +1 -0
  130. package/src/lib/components/theme-mode-switcher.d.ts +38 -0
  131. package/src/lib/components/theme-mode-switcher.js +168 -0
  132. package/src/lib/components/theme-mode-switcher.js.map +1 -0
  133. package/src/lib/components/toolbar.d.ts +37 -0
  134. package/src/lib/components/toolbar.js +117 -0
  135. package/src/lib/components/toolbar.js.map +1 -0
  136. package/src/lib/components/typography.d.ts +33 -0
  137. package/src/lib/components/typography.js +433 -0
  138. package/src/lib/components/typography.js.map +1 -0
  139. package/src/lib/components/video-lightbox-controls.d.ts +131 -0
  140. package/src/lib/components/video-lightbox-controls.js +536 -0
  141. package/src/lib/components/video-lightbox-controls.js.map +1 -0
  142. package/src/lib/components/video-lightbox.d.ts +60 -0
  143. package/src/lib/components/video-lightbox.js +247 -0
  144. package/src/lib/components/video-lightbox.js.map +1 -0
  145. package/src/lib/components/video-playback-beacon.d.ts +80 -0
  146. package/src/lib/components/video-playback-beacon.js +128 -0
  147. package/src/lib/components/video-playback-beacon.js.map +1 -0
  148. package/src/lib/components/video-player-frame.d.ts +58 -0
  149. package/src/lib/components/video-player-frame.js +51 -0
  150. package/src/lib/components/video-player-frame.js.map +1 -0
  151. package/src/lib/components/video.d.ts +220 -0
  152. package/src/lib/components/video.js +874 -0
  153. package/src/lib/components/video.js.map +1 -0
  154. package/src/lib/constants/bundle-common.d.ts +17 -0
  155. package/src/lib/constants/bundle-common.js +18 -0
  156. package/src/lib/constants/bundle-common.js.map +1 -0
  157. package/src/lib/constants/field-presets.d.ts +93 -0
  158. package/src/lib/constants/field-presets.js +248 -0
  159. package/src/lib/constants/field-presets.js.map +1 -0
  160. package/src/lib/plugin.d.ts +80 -0
  161. package/src/lib/plugin.js +599 -0
  162. package/src/lib/plugin.js.map +1 -0
  163. package/src/lib/utils/author-html-label.d.ts +73 -0
  164. package/src/lib/utils/author-html-label.js +89 -0
  165. package/src/lib/utils/author-html-label.js.map +1 -0
  166. package/src/lib/utils/drop-cleared-props.d.ts +18 -0
  167. package/src/lib/utils/drop-cleared-props.js +74 -0
  168. package/src/lib/utils/drop-cleared-props.js.map +1 -0
  169. package/src/lib/utils/element-picker.d.ts +99 -0
  170. package/src/lib/utils/element-picker.js +140 -0
  171. package/src/lib/utils/element-picker.js.map +1 -0
  172. package/src/lib/utils/generate-preset-id.d.ts +19 -0
  173. package/src/lib/utils/generate-preset-id.js +25 -0
  174. package/src/lib/utils/generate-preset-id.js.map +1 -0
  175. package/src/lib/utils/link-target-props.d.ts +53 -0
  176. package/src/lib/utils/link-target-props.js +53 -0
  177. package/src/lib/utils/link-target-props.js.map +1 -0
@@ -0,0 +1,683 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
+ /**
5
+ * @license
6
+ * Copyright 2026 Aglyn LLC
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */ import * as Aglyn from "@aglyn/aglyn";
20
+ import { mdiChevronDown, mdiFormDropdown, mdiViewGridOutline } from "@aglyn/shared-data-mdi";
21
+ import { MdiIcon } from "@aglyn/shared-ui-jsx";
22
+ import Box from "@mui/material/Box";
23
+ import Button from "@mui/material/Button";
24
+ import ClickAwayListener from "@mui/material/ClickAwayListener";
25
+ import Paper from "@mui/material/Paper";
26
+ import Stack from "@mui/material/Stack";
27
+ import Typography from "@mui/material/Typography";
28
+ import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
29
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
30
+ import { generatePresetId } from "../utils/generate-preset-id.js";
31
+ import { isLeafSelectedWithin, parseLeafNodeId } from "./drawer.js";
32
+ // Component ids are persisted in screen documents; never rename.
33
+ export const NAV_MENU_ID = 'muiNavMenu';
34
+ export const MEGA_MENU_ID = 'muiMegaMenu';
35
+ /** Hover close grace period so the pointer can cross into the panel. */ const HOVER_CLOSE_DELAY_MS = 150;
36
+ /**
37
+ * Mounted menus in mount order (AGL-568). Broadcast commands (no target
38
+ * node id) are answered by the FIRST registered menu only, mirroring the
39
+ * drawer bus, so a page with one menu needs no wiring at all.
40
+ */ const mountedMenus = [];
41
+ /**
42
+ * The panel sx per mega-menu width preset. Wide/full center under the
43
+ * trigger with the 50%/translate trick, so no measuring is needed and
44
+ * SSR markup is stable.
45
+ */ export function megaMenuPanelSx(panelWidth) {
46
+ switch(panelWidth){
47
+ case 'full':
48
+ return {
49
+ width: '100vw',
50
+ maxWidth: '100vw',
51
+ left: '50%',
52
+ transform: 'translateX(-50%)',
53
+ borderRadius: 0
54
+ };
55
+ case 'wide':
56
+ return {
57
+ width: 'min(90vw, 720px)',
58
+ left: '50%',
59
+ transform: 'translateX(-50%)'
60
+ };
61
+ default:
62
+ return {
63
+ minWidth: 280,
64
+ left: 0
65
+ };
66
+ }
67
+ }
68
+ /**
69
+ * Trigger typography (AGL-1198). A menu label sits in a nav beside plain
70
+ * links, so it reads as navigation, not as a call to action — MUI's
71
+ * uppercase Button transform shouts "PRODUCT" next to "Pricing". The
72
+ * default lives on the WRAPPER and the Button inherits it, so an author
73
+ * who does want uppercase can set it in STYLES → Typography on the
74
+ * element and have it win; before this there was no way to change it at
75
+ * all, because the Button is internal to the element.
76
+ */ const TRIGGER_SHELL_SX = {
77
+ position: 'relative',
78
+ display: 'inline-flex',
79
+ textTransform: 'none'
80
+ };
81
+ /**
82
+ * The rest of the same argument, generalized (AGL-2542).
83
+ *
84
+ * `textTransform` was one symptom of a whole button's worth of them. The
85
+ * trigger still arrived as a `Button`: 0.875rem where the links beside it
86
+ * were 15px, `min-width: 64px` padding "Docs" out to a width its own text
87
+ * never asked for, and `6px 8px` of padding widening the visual gap on two
88
+ * items out of five. In a nav laid out on a flat gap, that is a rhythm one
89
+ * element breaks and no author can fix — the Button is internal, so a font
90
+ * size set in STYLES lands on the wrapper and MUI's own class outranks it.
91
+ *
92
+ * So every typographic property is handed back to the wrapper the same way
93
+ * `textTransform` was, and the button chrome that has no meaning on a nav
94
+ * item is dropped. The element now renders as what it is — a label in a nav
95
+ * — and STYLES → Typography on it reaches the label, which is the control an
96
+ * author was reaching for when they found there wasn't one.
97
+ *
98
+ * `endIcon`'s negative right margin goes with the padding it was tucking
99
+ * into; left at -4px against zero padding, the chevron would hang outside
100
+ * the element and break the gap it just stopped breaking.
101
+ *
102
+ * ⚠️ Padding is where the hover target came from, and a hover-opened menu is
103
+ * only as reachable as its trigger. It belongs on the WRAPPER now — which is
104
+ * both what an author can actually edit and what `onMouseLeave` measures, so
105
+ * padding added there enlarges the target instead of merely looking like it.
106
+ */ const TRIGGER_SX = {
107
+ fontFamily: 'inherit',
108
+ fontSize: 'inherit',
109
+ fontWeight: 'inherit',
110
+ lineHeight: 'inherit',
111
+ letterSpacing: 'inherit',
112
+ textTransform: 'inherit',
113
+ color: 'inherit',
114
+ minWidth: 0,
115
+ padding: 0,
116
+ '& .MuiButton-endIcon': {
117
+ marginRight: 0
118
+ }
119
+ };
120
+ const MenuShell = /*#__PURE__*/ forwardRef((props, ref)=>{
121
+ const { label, editorHint, panelSx, sx, children } = props, rest = _object_without_properties_loose(props, [
122
+ "label",
123
+ "editorHint",
124
+ "panelSx",
125
+ "sx",
126
+ "children"
127
+ ]);
128
+ // Node styles ride the sx prop the renderer merges; keep them by
129
+ // composing with the shell's own layout sx (stack.ts pattern).
130
+ const nodeSx = Array.isArray(sx) ? sx : sx ? [
131
+ sx
132
+ ] : [];
133
+ const { editorInert } = Aglyn.useScreenLink(undefined);
134
+ const [open, setOpen] = useState(false);
135
+ // True while the menu is open BECAUSE a hover interaction opened it —
136
+ // only then does pointer leave close the menu.
137
+ const hoverOpenRef = useRef(false);
138
+ const closeTimer = useRef(null);
139
+ // The renderer stamps the node id on every leaf; commands target it.
140
+ const nodeId = useMemo(()=>parseLeafNodeId(rest['data-aglyn']), // eslint-disable-next-line react-hooks/exhaustive-deps
141
+ [
142
+ rest['data-aglyn']
143
+ ]);
144
+ const cancelClose = useCallback(()=>{
145
+ if (closeTimer.current) {
146
+ clearTimeout(closeTimer.current);
147
+ closeTimer.current = null;
148
+ }
149
+ }, []);
150
+ const closeNow = useCallback(()=>{
151
+ cancelClose();
152
+ hoverOpenRef.current = false;
153
+ setOpen(false);
154
+ }, [
155
+ cancelClose
156
+ ]);
157
+ const scheduleClose = useCallback(()=>{
158
+ cancelClose();
159
+ closeTimer.current = setTimeout(closeNow, HOVER_CLOSE_DELAY_MS);
160
+ }, [
161
+ cancelClose,
162
+ closeNow
163
+ ]);
164
+ // Menu command bus enrollment (AGL-568): mirrors the drawer exactly —
165
+ // live surfaces only, keyed by node id, broadcasts answered by the
166
+ // first mounted menu.
167
+ useEffect(()=>{
168
+ if (editorInert || !nodeId) return undefined;
169
+ mountedMenus.push(nodeId);
170
+ const unsubscribe = Aglyn.subscribeMenuCommands((detail)=>{
171
+ // Match on the un-namespaced suffix (AGL-573): a command authored on
172
+ // a layout-scoped menu carries the raw canvas id while this menu's
173
+ // live id is `layout__`-namespaced (or vice versa) — leafIdsMatch
174
+ // compares them equal without re-authoring the persisted action.
175
+ const targeted = detail.nodeId ? Aglyn.leafIdsMatch(detail.nodeId, nodeId) : mountedMenus[0] === nodeId;
176
+ if (!targeted) return;
177
+ cancelClose();
178
+ if (detail.command === 'close') {
179
+ hoverOpenRef.current = false;
180
+ setOpen(false);
181
+ return;
182
+ }
183
+ // open/toggle: remember hover provenance so pointer leave closes
184
+ // hover-opened menus (and never click/command-opened ones).
185
+ hoverOpenRef.current = Boolean(detail.hover);
186
+ if (detail.command === 'open') setOpen(true);
187
+ else setOpen((value)=>!value);
188
+ });
189
+ return ()=>{
190
+ unsubscribe();
191
+ cancelClose();
192
+ const index = mountedMenus.indexOf(nodeId);
193
+ if (index >= 0) mountedMenus.splice(index, 1);
194
+ };
195
+ }, [
196
+ editorInert,
197
+ nodeId,
198
+ cancelClose
199
+ ]);
200
+ if (editorInert) {
201
+ // Editor affordance (AGL-571): collapsed trigger by default — exactly
202
+ // what the live site shows — expanding to the editable panel only while
203
+ // the menu subtree holds the selection.
204
+ const authoring = isLeafSelectedWithin(rest);
205
+ return /*#__PURE__*/ _jsxs(Box, _extends({
206
+ ref: ref
207
+ }, rest, {
208
+ // Relative so the authoring panel drops UNDER the trigger as an
209
+ // overlay (AGL-830). The old inline-block expanded the panel in the
210
+ // toolbar's flow, shoving and overlapping the other nav items in a
211
+ // horizontal app bar; positioning it like the live popup keeps the
212
+ // bar intact while the panel stays selectable and editable in place.
213
+ sx: [
214
+ TRIGGER_SHELL_SX,
215
+ ...nodeSx
216
+ ],
217
+ children: [
218
+ /*#__PURE__*/ _jsx(Button, {
219
+ color: "inherit",
220
+ "aria-expanded": authoring || undefined,
221
+ endIcon: /*#__PURE__*/ _jsx(MdiIcon, {
222
+ path: mdiChevronDown.path
223
+ }),
224
+ sx: TRIGGER_SX,
225
+ children: label
226
+ }),
227
+ authoring ? /*#__PURE__*/ _jsxs(Paper, {
228
+ elevation: 4,
229
+ "aria-label": label,
230
+ sx: [
231
+ {
232
+ position: 'absolute',
233
+ top: '100%',
234
+ mt: 0.5,
235
+ zIndex: (theme)=>theme.zIndex.modal,
236
+ p: 1,
237
+ border: '1px dashed',
238
+ borderColor: 'divider'
239
+ },
240
+ panelSx
241
+ ],
242
+ children: [
243
+ /*#__PURE__*/ _jsx(Typography, {
244
+ variant: "caption",
245
+ color: "text.secondary",
246
+ sx: {
247
+ display: 'block',
248
+ mb: 0.5,
249
+ px: 1
250
+ },
251
+ children: editorHint
252
+ }),
253
+ children
254
+ ]
255
+ }) : null
256
+ ]
257
+ }));
258
+ }
259
+ return /*#__PURE__*/ _jsx(ClickAwayListener, {
260
+ onClickAway: ()=>open && closeNow(),
261
+ children: /*#__PURE__*/ _jsxs(Box, _extends({
262
+ ref: ref
263
+ }, rest, {
264
+ // Hover-close choreography (AGL-568): the panel renders inside
265
+ // this wrapper (no portal), so trigger + panel share one
266
+ // enter/leave pair. Only hover-opened menus follow the pointer
267
+ // out; enter always cancels a pending close so the pointer can
268
+ // travel between trigger and panel.
269
+ onMouseEnter: cancelClose,
270
+ onMouseLeave: ()=>{
271
+ if (hoverOpenRef.current) scheduleClose();
272
+ },
273
+ onKeyDown: (event)=>{
274
+ if (event.key === 'Escape') closeNow();
275
+ },
276
+ sx: [
277
+ TRIGGER_SHELL_SX,
278
+ ...nodeSx
279
+ ],
280
+ children: [
281
+ /*#__PURE__*/ _jsx(Button, {
282
+ color: "inherit",
283
+ "aria-haspopup": "true",
284
+ "aria-expanded": open || undefined,
285
+ endIcon: /*#__PURE__*/ _jsx(MdiIcon, {
286
+ path: mdiChevronDown.path
287
+ }),
288
+ sx: TRIGGER_SX,
289
+ onClick: ()=>{
290
+ // Zero-config default: the trigger click-toggles its menu;
291
+ // a click also "pins" a hover-opened menu.
292
+ cancelClose();
293
+ hoverOpenRef.current = false;
294
+ setOpen((value)=>!value);
295
+ },
296
+ children: label
297
+ }),
298
+ open ? /*#__PURE__*/ _jsx(Paper, {
299
+ elevation: 4,
300
+ "aria-label": label,
301
+ sx: [
302
+ {
303
+ position: 'absolute',
304
+ top: '100%',
305
+ zIndex: (theme)=>theme.zIndex.modal,
306
+ p: 1
307
+ },
308
+ panelSx
309
+ ],
310
+ children: children
311
+ }) : null
312
+ ]
313
+ }))
314
+ });
315
+ });
316
+ MenuShell.displayName = 'AglynMenuShell';
317
+ /**
318
+ * Strips the pre-AGL-568 "Open on" attribute persisted docs may still
319
+ * carry. Behavior configuration rides the interactions system now; the
320
+ * stored value is ignored silently — no migrations, no warnings — and
321
+ * must never leak onto the DOM.
322
+ */ function stripLegacyTrigger(rest) {
323
+ delete rest['trigger'];
324
+ }
325
+ /**
326
+ * Dropdown nav item (AGL-562): a labeled nav button whose children —
327
+ * screen links, buttons, anything — open in a dropdown panel. Clicking
328
+ * the trigger toggles it; interactions drive it over the menu command
329
+ * bus (AGL-568). SSR ships the menu closed; no window access happens at
330
+ * render.
331
+ */ const NavMenu = /*#__PURE__*/ forwardRef((props, ref)=>{
332
+ const { label, children } = props, rest = _object_without_properties_loose(props, [
333
+ "label",
334
+ "children"
335
+ ]);
336
+ stripLegacyTrigger(rest);
337
+ return /*#__PURE__*/ _jsx(MenuShell, _extends({
338
+ ref: ref,
339
+ label: label || 'Menu',
340
+ editorHint: "Dropdown items — shown in a menu on the live site",
341
+ panelSx: {
342
+ minWidth: 220,
343
+ left: 0
344
+ }
345
+ }, rest, {
346
+ children: /*#__PURE__*/ _jsx(Stack, {
347
+ spacing: 0.5,
348
+ sx: {
349
+ alignItems: 'stretch'
350
+ },
351
+ children: children
352
+ })
353
+ }));
354
+ });
355
+ NavMenu.displayName = 'AglynNavMenu';
356
+ /**
357
+ * Mega menu (AGL-562): a SaaS-style wide panel anchored under a nav
358
+ * item with a free-form canvas slot — columns of links, promos,
359
+ * whatever the author drops in. Click-toggles like the dropdown; the
360
+ * SaaS hover-open convention is one interaction away ("On hover → Open
361
+ * menu", AGL-568) and then closes itself on pointer leave.
362
+ */ export const MegaMenu = /*#__PURE__*/ forwardRef((props, ref)=>{
363
+ const { label, panelWidth, children } = props, rest = _object_without_properties_loose(props, [
364
+ "label",
365
+ "panelWidth",
366
+ "children"
367
+ ]);
368
+ stripLegacyTrigger(rest);
369
+ return /*#__PURE__*/ _jsx(MenuShell, _extends({
370
+ ref: ref,
371
+ label: label || 'Menu',
372
+ editorHint: "Mega menu panel — opens under the nav item on the live site",
373
+ panelSx: _extends({
374
+ p: 3
375
+ }, megaMenuPanelSx(panelWidth || 'auto'))
376
+ }, rest, {
377
+ children: children
378
+ }));
379
+ });
380
+ MegaMenu.displayName = 'AglynMegaMenu';
381
+ export const navMenuSchema = {
382
+ $id: NAV_MENU_ID,
383
+ pluginId: BUNDLE_ID,
384
+ displayName: 'Dropdown Menu',
385
+ description: 'A nav item that opens a dropdown of links beneath it.',
386
+ category: Aglyn.ComponentCategory.NAVIGATION,
387
+ icon: {
388
+ path: mdiFormDropdown.path,
389
+ sx: {
390
+ color: '#2196f3'
391
+ }
392
+ },
393
+ // Open/close behavior deliberately has NO attribute (AGL-568): click
394
+ // toggles by default and everything else is authored as an
395
+ // interaction (e.g. "On hover → Open menu").
396
+ attributes: [
397
+ {
398
+ name: 'label',
399
+ description: 'Text on the nav item that opens the dropdown.',
400
+ component: Aglyn.FieldComponentType.TEXT_FIELD,
401
+ label: 'Label'
402
+ }
403
+ ]
404
+ };
405
+ export const megaMenuSchema = {
406
+ $id: MEGA_MENU_ID,
407
+ pluginId: BUNDLE_ID,
408
+ displayName: 'Mega Menu',
409
+ description: 'A nav item that opens a wide panel — columns of links, promos, whatever you build.',
410
+ category: Aglyn.ComponentCategory.NAVIGATION,
411
+ icon: {
412
+ path: mdiViewGridOutline.path,
413
+ sx: {
414
+ color: '#2196f3'
415
+ }
416
+ },
417
+ // Open/close behavior deliberately has NO attribute (AGL-568) — see
418
+ // navMenuSchema.
419
+ attributes: [
420
+ {
421
+ name: 'label',
422
+ description: 'Text on the nav item that opens the panel.',
423
+ component: Aglyn.FieldComponentType.TEXT_FIELD,
424
+ label: 'Label'
425
+ },
426
+ {
427
+ name: 'panelWidth',
428
+ description: 'How wide the opened panel is.',
429
+ component: Aglyn.FieldComponentType.SELECT,
430
+ label: 'Panel width',
431
+ // `auto` is the `MegaMenuPanelWidth` member `megaMenuPanelSx` already
432
+ // switches on, so the sentinel names the case that existed in code
433
+ // but not in the option list (AGL-1451); `''` could not persist
434
+ // (AGL-1191), so a wide panel could not be narrowed again.
435
+ options: [
436
+ {
437
+ value: 'auto',
438
+ label: 'Fit content'
439
+ },
440
+ {
441
+ value: 'wide',
442
+ label: 'Wide (720px)'
443
+ },
444
+ {
445
+ value: 'full',
446
+ label: 'Full width'
447
+ }
448
+ ]
449
+ }
450
+ ]
451
+ };
452
+ const navLink = (label)=>({
453
+ $id: null,
454
+ componentId: 'muiScreenLink',
455
+ pluginId: BUNDLE_ID,
456
+ props: {
457
+ children: label,
458
+ color: 'inherit'
459
+ }
460
+ });
461
+ const megaColumn = (title, links)=>({
462
+ $id: null,
463
+ componentId: 'muiStack',
464
+ pluginId: BUNDLE_ID,
465
+ props: {
466
+ spacing: 0.5
467
+ },
468
+ // Styling goes on the node's own sx, never in props (AGL-1346) — that is
469
+ // the record the Styles panel edits.
470
+ sx: {
471
+ minWidth: 180,
472
+ alignItems: 'flex-start'
473
+ },
474
+ nodes: [
475
+ {
476
+ $id: null,
477
+ componentId: 'muiTypography',
478
+ pluginId: BUNDLE_ID,
479
+ props: {
480
+ variant: 'overline',
481
+ color: 'text.secondary',
482
+ children: title
483
+ }
484
+ },
485
+ ...links.map(navLink)
486
+ ]
487
+ });
488
+ export const navMenuPresets = [
489
+ {
490
+ $id: generatePresetId(NAV_MENU_ID),
491
+ type: Aglyn.NodeType.PRESET,
492
+ displayName: 'Dropdown Menu',
493
+ pluginId: BUNDLE_ID,
494
+ description: 'Nav item that opens a dropdown of links',
495
+ category: Aglyn.ComponentCategory.NAVIGATION,
496
+ icon: navMenuSchema.icon,
497
+ data: {
498
+ $id: null,
499
+ componentId: NAV_MENU_ID,
500
+ pluginId: BUNDLE_ID,
501
+ props: {
502
+ label: 'More'
503
+ },
504
+ nodes: [
505
+ navLink('About'),
506
+ navLink('Blog'),
507
+ navLink('Contact')
508
+ ]
509
+ }
510
+ },
511
+ // Primitive dropdown scaffold (AGL-589): the same result as the menu
512
+ // elements but built from a Stack + Button + hidden panel, with the
513
+ // hover choreography (grace delay, Esc/outside-click dismissal)
514
+ // pre-wired as real interactions the user can edit or remove. The
515
+ // panel carries `aglyn-hidden` so it starts closed on the live site;
516
+ // the canvas shows it for editing (the hidden style only injects at
517
+ // runtime).
518
+ {
519
+ $id: generatePresetId('muiStack', 'dropdown-panel'),
520
+ type: Aglyn.NodeType.PRESET,
521
+ displayName: 'Dropdown Panel',
522
+ pluginId: BUNDLE_ID,
523
+ description: 'Trigger + hover panel built from primitives — opens on hover, ' + 'closes on leave with a grace delay, dismisses on Esc or outside ' + 'click; the wiring arrives as editable interactions',
524
+ category: Aglyn.ComponentCategory.NAVIGATION,
525
+ icon: {
526
+ path: mdiFormDropdown.path,
527
+ sx: {
528
+ color: '#2196f3'
529
+ }
530
+ },
531
+ data: {
532
+ $id: null,
533
+ presetRef: 'wrapper',
534
+ componentId: 'muiStack',
535
+ pluginId: BUNDLE_ID,
536
+ props: {},
537
+ sx: {
538
+ position: 'relative',
539
+ display: 'inline-flex'
540
+ },
541
+ nodes: [
542
+ {
543
+ $id: null,
544
+ presetRef: 'trigger',
545
+ componentId: 'muiButton',
546
+ pluginId: BUNDLE_ID,
547
+ props: {
548
+ children: 'Explore',
549
+ color: 'inherit'
550
+ }
551
+ },
552
+ {
553
+ $id: null,
554
+ presetRef: 'panel',
555
+ componentId: 'muiStack',
556
+ pluginId: BUNDLE_ID,
557
+ props: {
558
+ className: 'aglyn-hidden',
559
+ direction: 'row',
560
+ spacing: 4
561
+ },
562
+ // The panel's whole positioning. It lived in `props.sx` on the
563
+ // documents this preset seeded, where the Styles panel could
564
+ // neither show nor clear it (AGL-1339/AGL-1346); a fresh insert
565
+ // now puts it where a click can reach it. Same keys, same order,
566
+ // and `node.sx` composes last — the panel renders identically.
567
+ sx: {
568
+ position: 'absolute',
569
+ top: '100%',
570
+ left: 0,
571
+ zIndex: 1300,
572
+ paddingTop: 3,
573
+ paddingRight: 3,
574
+ paddingBottom: 3,
575
+ paddingLeft: 3,
576
+ minWidth: 560,
577
+ flexWrap: 'wrap',
578
+ backgroundColor: 'background.paper',
579
+ color: 'text.primary',
580
+ boxShadow: 8,
581
+ borderRadius: 1
582
+ },
583
+ nodes: [
584
+ megaColumn('Shop', [
585
+ 'New arrivals',
586
+ 'Best sellers',
587
+ 'Sale'
588
+ ]),
589
+ megaColumn('Company', [
590
+ 'About',
591
+ 'Careers',
592
+ 'Press'
593
+ ]),
594
+ megaColumn('Support', [
595
+ 'Help center',
596
+ 'Contact'
597
+ ])
598
+ ]
599
+ }
600
+ ]
601
+ },
602
+ interactionTemplates: [
603
+ {
604
+ name: 'Dropdown panel — open on hover',
605
+ event: 'elementHoverEnter',
606
+ triggerRef: 'wrapper',
607
+ steps: [
608
+ {
609
+ type: 'showElement',
610
+ targetRef: 'panel',
611
+ dismissOn: [
612
+ 'escape',
613
+ 'outsideClick'
614
+ ]
615
+ }
616
+ ]
617
+ },
618
+ {
619
+ name: 'Dropdown panel — close on hover leave',
620
+ event: 'elementHoverLeave',
621
+ triggerRef: 'wrapper',
622
+ steps: [
623
+ {
624
+ type: 'hideElement',
625
+ targetRef: 'panel',
626
+ delayMs: 250
627
+ }
628
+ ]
629
+ }
630
+ ]
631
+ },
632
+ {
633
+ $id: generatePresetId(MEGA_MENU_ID),
634
+ type: Aglyn.NodeType.PRESET,
635
+ displayName: 'Mega Menu',
636
+ pluginId: BUNDLE_ID,
637
+ description: 'Wide panel with columns of links; add a hover interaction to ' + 'open it on hover',
638
+ category: Aglyn.ComponentCategory.NAVIGATION,
639
+ icon: megaMenuSchema.icon,
640
+ data: {
641
+ $id: null,
642
+ componentId: MEGA_MENU_ID,
643
+ pluginId: BUNDLE_ID,
644
+ props: {
645
+ label: 'Products',
646
+ panelWidth: 'wide'
647
+ },
648
+ nodes: [
649
+ {
650
+ $id: null,
651
+ componentId: 'muiStack',
652
+ pluginId: BUNDLE_ID,
653
+ props: {
654
+ direction: 'row',
655
+ spacing: 4
656
+ },
657
+ sx: {
658
+ flexWrap: 'wrap'
659
+ },
660
+ nodes: [
661
+ megaColumn('Shop', [
662
+ 'New arrivals',
663
+ 'Best sellers',
664
+ 'Sale'
665
+ ]),
666
+ megaColumn('Company', [
667
+ 'About',
668
+ 'Careers',
669
+ 'Press'
670
+ ]),
671
+ megaColumn('Support', [
672
+ 'Help center',
673
+ 'Contact'
674
+ ])
675
+ ]
676
+ }
677
+ ]
678
+ }
679
+ }
680
+ ];
681
+ export default NavMenu;
682
+
683
+ //# sourceMappingURL=nav-menu.js.map