@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.
- package/LICENSE +201 -0
- package/README.md +22 -0
- package/package.json +47 -0
- package/src/index.d.ts +21 -0
- package/src/index.js +22 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/accordion.d.ts +96 -0
- package/src/lib/components/accordion.js +392 -0
- package/src/lib/components/accordion.js.map +1 -0
- package/src/lib/components/app-bar.d.ts +32 -0
- package/src/lib/components/app-bar.js +86 -0
- package/src/lib/components/app-bar.js.map +1 -0
- package/src/lib/components/blocks.d.ts +46 -0
- package/src/lib/components/blocks.js +1007 -0
- package/src/lib/components/blocks.js.map +1 -0
- package/src/lib/components/box.d.ts +47 -0
- package/src/lib/components/box.js +125 -0
- package/src/lib/components/box.js.map +1 -0
- package/src/lib/components/breadcrumbs.d.ts +44 -0
- package/src/lib/components/breadcrumbs.js +172 -0
- package/src/lib/components/breadcrumbs.js.map +1 -0
- package/src/lib/components/button.d.ts +89 -0
- package/src/lib/components/button.js +272 -0
- package/src/lib/components/button.js.map +1 -0
- package/src/lib/components/card.d.ts +61 -0
- package/src/lib/components/card.js +336 -0
- package/src/lib/components/card.js.map +1 -0
- package/src/lib/components/collection.d.ts +514 -0
- package/src/lib/components/collection.js +2999 -0
- package/src/lib/components/collection.js.map +1 -0
- package/src/lib/components/container.d.ts +42 -0
- package/src/lib/components/container.js +169 -0
- package/src/lib/components/container.js.map +1 -0
- package/src/lib/components/custom-html.d.ts +78 -0
- package/src/lib/components/custom-html.js +219 -0
- package/src/lib/components/custom-html.js.map +1 -0
- package/src/lib/components/data-table.d.ts +57 -0
- package/src/lib/components/data-table.js +216 -0
- package/src/lib/components/data-table.js.map +1 -0
- package/src/lib/components/document-root.d.ts +77 -0
- package/src/lib/components/document-root.js +118 -0
- package/src/lib/components/document-root.js.map +1 -0
- package/src/lib/components/drawer.d.ts +93 -0
- package/src/lib/components/drawer.js +566 -0
- package/src/lib/components/drawer.js.map +1 -0
- package/src/lib/components/function-controls.d.ts +66 -0
- package/src/lib/components/function-controls.js +207 -0
- package/src/lib/components/function-controls.js.map +1 -0
- package/src/lib/components/function-scope.d.ts +110 -0
- package/src/lib/components/function-scope.js +478 -0
- package/src/lib/components/function-scope.js.map +1 -0
- package/src/lib/components/function-widget.d.ts +75 -0
- package/src/lib/components/function-widget.js +307 -0
- package/src/lib/components/function-widget.js.map +1 -0
- package/src/lib/components/grid.d.ts +91 -0
- package/src/lib/components/grid.js +322 -0
- package/src/lib/components/grid.js.map +1 -0
- package/src/lib/components/icon.d.ts +54 -0
- package/src/lib/components/icon.js +163 -0
- package/src/lib/components/icon.js.map +1 -0
- package/src/lib/components/image-list.d.ts +58 -0
- package/src/lib/components/image-list.js +336 -0
- package/src/lib/components/image-list.js.map +1 -0
- package/src/lib/components/image.d.ts +154 -0
- package/src/lib/components/image.js +451 -0
- package/src/lib/components/image.js.map +1 -0
- package/src/lib/components/inline-text.d.ts +74 -0
- package/src/lib/components/inline-text.js +407 -0
- package/src/lib/components/inline-text.js.map +1 -0
- package/src/lib/components/language-switcher.d.ts +35 -0
- package/src/lib/components/language-switcher.js +179 -0
- package/src/lib/components/language-switcher.js.map +1 -0
- package/src/lib/components/layout-slot.d.ts +68 -0
- package/src/lib/components/layout-slot.js +192 -0
- package/src/lib/components/layout-slot.js.map +1 -0
- package/src/lib/components/link-box-accessible-name.d.ts +79 -0
- package/src/lib/components/link-box-accessible-name.js +158 -0
- package/src/lib/components/link-box-accessible-name.js.map +1 -0
- package/src/lib/components/link-box.d.ts +66 -0
- package/src/lib/components/link-box.js +212 -0
- package/src/lib/components/link-box.js.map +1 -0
- package/src/lib/components/list-item-text.d.ts +22 -0
- package/src/lib/components/list-item-text.js +86 -0
- package/src/lib/components/list-item-text.js.map +1 -0
- package/src/lib/components/list-item.d.ts +32 -0
- package/src/lib/components/list-item.js +127 -0
- package/src/lib/components/list-item.js.map +1 -0
- package/src/lib/components/list.d.ts +34 -0
- package/src/lib/components/list.js +108 -0
- package/src/lib/components/list.js.map +1 -0
- package/src/lib/components/markdown.d.ts +129 -0
- package/src/lib/components/markdown.js +853 -0
- package/src/lib/components/markdown.js.map +1 -0
- package/src/lib/components/nav-menu.d.ts +68 -0
- package/src/lib/components/nav-menu.js +683 -0
- package/src/lib/components/nav-menu.js.map +1 -0
- package/src/lib/components/pagination.d.ts +59 -0
- package/src/lib/components/pagination.js +243 -0
- package/src/lib/components/pagination.js.map +1 -0
- package/src/lib/components/paper.d.ts +47 -0
- package/src/lib/components/paper.js +202 -0
- package/src/lib/components/paper.js.map +1 -0
- package/src/lib/components/plugin-frame.d.ts +64 -0
- package/src/lib/components/plugin-frame.js +335 -0
- package/src/lib/components/plugin-frame.js.map +1 -0
- package/src/lib/components/plugin.d.ts +95 -0
- package/src/lib/components/plugin.js +304 -0
- package/src/lib/components/plugin.js.map +1 -0
- package/src/lib/components/product.d.ts +40 -0
- package/src/lib/components/product.js +287 -0
- package/src/lib/components/product.js.map +1 -0
- package/src/lib/components/reusable-instance.d.ts +57 -0
- package/src/lib/components/reusable-instance.js +126 -0
- package/src/lib/components/reusable-instance.js.map +1 -0
- package/src/lib/components/screen-link.d.ts +85 -0
- package/src/lib/components/screen-link.js +324 -0
- package/src/lib/components/screen-link.js.map +1 -0
- package/src/lib/components/search-box.d.ts +41 -0
- package/src/lib/components/search-box.js +125 -0
- package/src/lib/components/search-box.js.map +1 -0
- package/src/lib/components/section.d.ts +56 -0
- package/src/lib/components/section.js +132 -0
- package/src/lib/components/section.js.map +1 -0
- package/src/lib/components/stack.d.ts +55 -0
- package/src/lib/components/stack.js +309 -0
- package/src/lib/components/stack.js.map +1 -0
- package/src/lib/components/tabs.d.ts +288 -0
- package/src/lib/components/tabs.js +788 -0
- package/src/lib/components/tabs.js.map +1 -0
- package/src/lib/components/theme-mode-switcher.d.ts +38 -0
- package/src/lib/components/theme-mode-switcher.js +168 -0
- package/src/lib/components/theme-mode-switcher.js.map +1 -0
- package/src/lib/components/toolbar.d.ts +37 -0
- package/src/lib/components/toolbar.js +117 -0
- package/src/lib/components/toolbar.js.map +1 -0
- package/src/lib/components/typography.d.ts +33 -0
- package/src/lib/components/typography.js +433 -0
- package/src/lib/components/typography.js.map +1 -0
- package/src/lib/components/video-lightbox-controls.d.ts +131 -0
- package/src/lib/components/video-lightbox-controls.js +536 -0
- package/src/lib/components/video-lightbox-controls.js.map +1 -0
- package/src/lib/components/video-lightbox.d.ts +60 -0
- package/src/lib/components/video-lightbox.js +247 -0
- package/src/lib/components/video-lightbox.js.map +1 -0
- package/src/lib/components/video-playback-beacon.d.ts +80 -0
- package/src/lib/components/video-playback-beacon.js +128 -0
- package/src/lib/components/video-playback-beacon.js.map +1 -0
- package/src/lib/components/video-player-frame.d.ts +58 -0
- package/src/lib/components/video-player-frame.js +51 -0
- package/src/lib/components/video-player-frame.js.map +1 -0
- package/src/lib/components/video.d.ts +220 -0
- package/src/lib/components/video.js +874 -0
- package/src/lib/components/video.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +17 -0
- package/src/lib/constants/bundle-common.js +18 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/constants/field-presets.d.ts +93 -0
- package/src/lib/constants/field-presets.js +248 -0
- package/src/lib/constants/field-presets.js.map +1 -0
- package/src/lib/plugin.d.ts +80 -0
- package/src/lib/plugin.js +599 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/utils/author-html-label.d.ts +73 -0
- package/src/lib/utils/author-html-label.js +89 -0
- package/src/lib/utils/author-html-label.js.map +1 -0
- package/src/lib/utils/drop-cleared-props.d.ts +18 -0
- package/src/lib/utils/drop-cleared-props.js +74 -0
- package/src/lib/utils/drop-cleared-props.js.map +1 -0
- package/src/lib/utils/element-picker.d.ts +99 -0
- package/src/lib/utils/element-picker.js +140 -0
- package/src/lib/utils/element-picker.js.map +1 -0
- package/src/lib/utils/generate-preset-id.d.ts +19 -0
- package/src/lib/utils/generate-preset-id.js +25 -0
- package/src/lib/utils/generate-preset-id.js.map +1 -0
- package/src/lib/utils/link-target-props.d.ts +53 -0
- package/src/lib/utils/link-target-props.js +53 -0
- 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
|