@aglyn/besigner-ui 1.0.0-beta.145 → 1.0.0-beta.147
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/package.json +17 -17
- package/src/lib/components/besigner-root-provider.component.js +7 -3
- package/src/lib/components/besigner-root-provider.component.js.map +1 -1
- package/src/lib/components/node-context-menu.js +244 -244
- package/src/lib/components/node-context-menu.js.map +1 -1
- package/src/lib/components/subtree-json-dialog.component.d.ts +11 -0
- package/src/lib/components/subtree-json-dialog.component.js +41 -2
- package/src/lib/components/subtree-json-dialog.component.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aglyn/besigner-ui",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.147",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"homepage": "https://aglyn.com",
|
|
6
6
|
"repository": {
|
|
@@ -25,22 +25,22 @@
|
|
|
25
25
|
"./package.json": "./package.json"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@aglyn/aglyn": "1.0.0-beta.
|
|
29
|
-
"@aglyn/aglyn-markdown-editor": "1.0.0-beta.
|
|
30
|
-
"@aglyn/aglyn-node-renderer": "1.0.0-beta.
|
|
31
|
-
"@aglyn/besigner": "1.0.0-beta.
|
|
32
|
-
"@aglyn/shared-data-enums": "1.0.0-beta.
|
|
33
|
-
"@aglyn/shared-data-mdi": "1.0.0-beta.
|
|
34
|
-
"@aglyn/shared-data-types": "1.0.0-beta.
|
|
35
|
-
"@aglyn/shared-svg-icons": "1.0.0-beta.
|
|
36
|
-
"@aglyn/shared-ui-json-editor": "1.0.0-beta.
|
|
37
|
-
"@aglyn/shared-ui-jsx": "1.0.0-beta.
|
|
38
|
-
"@aglyn/shared-ui-jsx-forms": "1.0.0-beta.
|
|
39
|
-
"@aglyn/shared-ui-snackstack": "1.0.0-beta.
|
|
40
|
-
"@aglyn/shared-ui-theme": "1.0.0-beta.
|
|
41
|
-
"@aglyn/shared-util-dom": "1.0.0-beta.
|
|
42
|
-
"@aglyn/shared-util-tools": "1.0.0-beta.
|
|
43
|
-
"@aglyn/shared-util-vendor": "1.0.0-beta.
|
|
28
|
+
"@aglyn/aglyn": "1.0.0-beta.147",
|
|
29
|
+
"@aglyn/aglyn-markdown-editor": "1.0.0-beta.147",
|
|
30
|
+
"@aglyn/aglyn-node-renderer": "1.0.0-beta.147",
|
|
31
|
+
"@aglyn/besigner": "1.0.0-beta.147",
|
|
32
|
+
"@aglyn/shared-data-enums": "1.0.0-beta.147",
|
|
33
|
+
"@aglyn/shared-data-mdi": "1.0.0-beta.147",
|
|
34
|
+
"@aglyn/shared-data-types": "1.0.0-beta.147",
|
|
35
|
+
"@aglyn/shared-svg-icons": "1.0.0-beta.147",
|
|
36
|
+
"@aglyn/shared-ui-json-editor": "1.0.0-beta.147",
|
|
37
|
+
"@aglyn/shared-ui-jsx": "1.0.0-beta.147",
|
|
38
|
+
"@aglyn/shared-ui-jsx-forms": "1.0.0-beta.147",
|
|
39
|
+
"@aglyn/shared-ui-snackstack": "1.0.0-beta.147",
|
|
40
|
+
"@aglyn/shared-ui-theme": "1.0.0-beta.147",
|
|
41
|
+
"@aglyn/shared-util-dom": "1.0.0-beta.147",
|
|
42
|
+
"@aglyn/shared-util-tools": "1.0.0-beta.147",
|
|
43
|
+
"@aglyn/shared-util-vendor": "1.0.0-beta.147",
|
|
44
44
|
"@dnd-kit/core": "^6.3.1",
|
|
45
45
|
"@dnd-kit/utilities": "^3.2.2",
|
|
46
46
|
"@react-aria/utils": "^3.34.1",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
17
17
|
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
18
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
19
|
import { getDisplayName } from "@aglyn/shared-util-tools";
|
|
20
20
|
import { hoistNonReactStatics } from "@aglyn/shared-util-vendor";
|
|
21
21
|
import { NoSsr } from "@mui/material";
|
|
@@ -25,6 +25,7 @@ import RenderedCanvasElementsProvider from "../contexts/rendered-canvas-elements
|
|
|
25
25
|
import { BesignerAppProvider } from "../contexts/besigner-app-context.js";
|
|
26
26
|
import useClipboardShortcuts from "../hooks/use-clipboard-shortcuts.js";
|
|
27
27
|
import BesignerDndContext from "./besigner-dnd-context.component.js";
|
|
28
|
+
import { SubtreeJsonDialogHost } from "./subtree-json-dialog.component.js";
|
|
28
29
|
export const withBesignerContext = (Component)=>{
|
|
29
30
|
const displayName = getDisplayName(Component);
|
|
30
31
|
const WithBesignerContext = (props)=>{
|
|
@@ -53,8 +54,11 @@ export const BesignerRootProviderComponent = (props)=>{
|
|
|
53
54
|
appName: appName,
|
|
54
55
|
children: /*#__PURE__*/ _jsx(BesignerDndContext, {
|
|
55
56
|
children: /*#__PURE__*/ _jsx(RenderedCanvasElementsProvider, {
|
|
56
|
-
children: /*#__PURE__*/
|
|
57
|
-
children:
|
|
57
|
+
children: /*#__PURE__*/ _jsxs(ComponentsDrawerContextProvider, {
|
|
58
|
+
children: [
|
|
59
|
+
children,
|
|
60
|
+
/*#__PURE__*/ _jsx(SubtreeJsonDialogHost, {})
|
|
61
|
+
]
|
|
58
62
|
})
|
|
59
63
|
})
|
|
60
64
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/besigner-root-provider.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2023 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { AppUUN } from '@aglyn/besigner'\nimport { getDisplayName } from '@aglyn/shared-util-tools'\nimport { hoistNonReactStatics } from '@aglyn/shared-util-vendor'\nimport { NoSsr } from '@mui/material'\nimport { type ComponentType, Fragment } from 'react'\nimport ComponentsDrawerContextProvider from '../contexts/components-drawer-context.provider'\nimport RenderedCanvasElementsProvider from '../contexts/rendered-canvas-elements'\nimport { BesignerAppProvider } from '../contexts/besigner-app-context'\nimport useClipboardShortcuts from '../hooks/use-clipboard-shortcuts'\nimport BesignerDndContext from './besigner-dnd-context.component'\n\nexport interface BesignerComponentProps {\n noSsr?: boolean\n appName?: AppUUN\n children?: JSX.Children\n}\n\nexport const withBesignerContext = <P,>(Component: ComponentType<P>) => {\n const displayName = getDisplayName(Component)\n const WithBesignerContext = (props: BesignerComponentProps & P) => {\n const { noSsr, appName, ...rest } = props\n return (\n <BesignerRootProviderComponent>\n <Component {...(rest as P)} />\n </BesignerRootProviderComponent>\n )\n }\n WithBesignerContext.displayName = `WithBesignerComponent(${displayName})`\n hoistNonReactStatics(WithBesignerContext, Component)\n return WithBesignerContext\n}\n\nexport const BesignerRootProviderComponent = (\n props: BesignerComponentProps,\n) => {\n /*forwardRef<any, BesignerComponentProps>(\n (props, ref) => {*/\n const { noSsr, appName, children } = props\n const Wrapper = noSsr ? NoSsr : Fragment\n\n // Element copy/paste + select-all (AGL-1202). Bound once here so every\n // besigner surface — screens, layouts, components, templates, emails —\n // gets the same shortcuts.\n useClipboardShortcuts()\n\n return (\n <Wrapper>\n <BesignerAppProvider appName={appName}>\n <BesignerDndContext>\n <RenderedCanvasElementsProvider>\n <ComponentsDrawerContextProvider>\n {children}\n </ComponentsDrawerContextProvider>\n </RenderedCanvasElementsProvider>\n </BesignerDndContext>\n </BesignerAppProvider>\n </Wrapper>\n )\n}\n\nBesignerRootProviderComponent.displayName = 'BesignerRootProviderComponent'\nBesignerRootProviderComponent.aglyn = true\n\nexport default BesignerRootProviderComponent\n"],"names":["getDisplayName","hoistNonReactStatics","NoSsr","Fragment","ComponentsDrawerContextProvider","RenderedCanvasElementsProvider","BesignerAppProvider","useClipboardShortcuts","BesignerDndContext","withBesignerContext","Component","displayName","WithBesignerContext","props","noSsr","appName","rest","BesignerRootProviderComponent","children","Wrapper","aglyn"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;;;AAGD,SAASA,cAAc,QAAQ,2BAA0B;AACzD,SAASC,oBAAoB,QAAQ,4BAA2B;AAChE,SAASC,KAAK,QAAQ,gBAAe;AACrC,SAA6BC,QAAQ,QAAQ,QAAO;AACpD,OAAOC,qCAAqC,oDAAgD;AAC5F,OAAOC,oCAAoC,0CAAsC;AACjF,SAASC,mBAAmB,QAAQ,sCAAkC;AACtE,OAAOC,2BAA2B,sCAAkC;AACpE,OAAOC,wBAAwB,sCAAkC;
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/besigner-root-provider.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2023 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { AppUUN } from '@aglyn/besigner'\nimport { getDisplayName } from '@aglyn/shared-util-tools'\nimport { hoistNonReactStatics } from '@aglyn/shared-util-vendor'\nimport { NoSsr } from '@mui/material'\nimport { type ComponentType, Fragment } from 'react'\nimport ComponentsDrawerContextProvider from '../contexts/components-drawer-context.provider'\nimport RenderedCanvasElementsProvider from '../contexts/rendered-canvas-elements'\nimport { BesignerAppProvider } from '../contexts/besigner-app-context'\nimport useClipboardShortcuts from '../hooks/use-clipboard-shortcuts'\nimport BesignerDndContext from './besigner-dnd-context.component'\nimport { SubtreeJsonDialogHost } from './subtree-json-dialog.component'\n\nexport interface BesignerComponentProps {\n noSsr?: boolean\n appName?: AppUUN\n children?: JSX.Children\n}\n\nexport const withBesignerContext = <P,>(Component: ComponentType<P>) => {\n const displayName = getDisplayName(Component)\n const WithBesignerContext = (props: BesignerComponentProps & P) => {\n const { noSsr, appName, ...rest } = props\n return (\n <BesignerRootProviderComponent>\n <Component {...(rest as P)} />\n </BesignerRootProviderComponent>\n )\n }\n WithBesignerContext.displayName = `WithBesignerComponent(${displayName})`\n hoistNonReactStatics(WithBesignerContext, Component)\n return WithBesignerContext\n}\n\nexport const BesignerRootProviderComponent = (\n props: BesignerComponentProps,\n) => {\n /*forwardRef<any, BesignerComponentProps>(\n (props, ref) => {*/\n const { noSsr, appName, children } = props\n const Wrapper = noSsr ? NoSsr : Fragment\n\n // Element copy/paste + select-all (AGL-1202). Bound once here so every\n // besigner surface — screens, layouts, components, templates, emails —\n // gets the same shortcuts.\n useClipboardShortcuts()\n\n return (\n <Wrapper>\n <BesignerAppProvider appName={appName}>\n <BesignerDndContext>\n <RenderedCanvasElementsProvider>\n <ComponentsDrawerContextProvider>\n {children}\n {/*\n Element -> Edit JSON, mounted once per surface (AGL-3208).\n\n It belongs here for the same reason the clipboard shortcuts\n do: every besigner surface offers it, and nothing smaller\n outlives the menu that opens it. Rendered inside\n `NodeContextMenu`, as it was, it was unmounted by the click\n that reached into it.\n */}\n <SubtreeJsonDialogHost />\n </ComponentsDrawerContextProvider>\n </RenderedCanvasElementsProvider>\n </BesignerDndContext>\n </BesignerAppProvider>\n </Wrapper>\n )\n}\n\nBesignerRootProviderComponent.displayName = 'BesignerRootProviderComponent'\nBesignerRootProviderComponent.aglyn = true\n\nexport default BesignerRootProviderComponent\n"],"names":["getDisplayName","hoistNonReactStatics","NoSsr","Fragment","ComponentsDrawerContextProvider","RenderedCanvasElementsProvider","BesignerAppProvider","useClipboardShortcuts","BesignerDndContext","SubtreeJsonDialogHost","withBesignerContext","Component","displayName","WithBesignerContext","props","noSsr","appName","rest","BesignerRootProviderComponent","children","Wrapper","aglyn"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;;;AAGD,SAASA,cAAc,QAAQ,2BAA0B;AACzD,SAASC,oBAAoB,QAAQ,4BAA2B;AAChE,SAASC,KAAK,QAAQ,gBAAe;AACrC,SAA6BC,QAAQ,QAAQ,QAAO;AACpD,OAAOC,qCAAqC,oDAAgD;AAC5F,OAAOC,oCAAoC,0CAAsC;AACjF,SAASC,mBAAmB,QAAQ,sCAAkC;AACtE,OAAOC,2BAA2B,sCAAkC;AACpE,OAAOC,wBAAwB,sCAAkC;AACjE,SAASC,qBAAqB,QAAQ,qCAAiC;AAQvE,OAAO,MAAMC,sBAAsB,CAAKC;IACtC,MAAMC,cAAcZ,eAAeW;IACnC,MAAME,sBAAsB,CAACC;QAC3B,MAAM,EAAEC,KAAK,EAAEC,OAAO,EAAW,GAAGF,OAATG,wCAASH;;;;QACpC,qBACE,KAACI;sBACC,cAAA,KAACP,wBAAeM;;IAGtB;IACAJ,oBAAoBD,WAAW,GAAG,CAAC,sBAAsB,EAAEA,YAAY,CAAC,CAAC;IACzEX,qBAAqBY,qBAAqBF;IAC1C,OAAOE;AACT,EAAC;AAED,OAAO,MAAMK,gCAAgC,CAC3CJ;IAEA;kBACgB,GAChB,MAAM,EAAEC,KAAK,EAAEC,OAAO,EAAEG,QAAQ,EAAE,GAAGL;IACrC,MAAMM,UAAUL,QAAQb,QAAQC;IAEhC,uEAAuE;IACvE,uEAAuE;IACvE,2BAA2B;IAC3BI;IAEA,qBACE,KAACa;kBACC,cAAA,KAACd;YAAoBU,SAASA;sBAC5B,cAAA,KAACR;0BACC,cAAA,KAACH;8BACC,cAAA,MAACD;;4BACEe;0CAUD,KAACV;;;;;;;AAOf,EAAC;AAEDS,8BAA8BN,WAAW,GAAG;AAC5CM,8BAA8BG,KAAK,GAAG;AAEtC,eAAeH,8BAA6B"}
|
|
@@ -32,7 +32,7 @@ import { useCopyElementsCallback, usePasteElementsCallback } from "../hooks/use-
|
|
|
32
32
|
import useDeleteElementCallback, { useDeleteElementsCallback } from "../hooks/use-delete-element-callback.js";
|
|
33
33
|
import { useMoveNodeInCallback, useMoveNodeOutCallback } from "../hooks/use-move-node-callbacks.js";
|
|
34
34
|
import { isNodeHiddenOnSite, nodePropsWithHiddenOnSite } from "../utils/canvas-reveal.js";
|
|
35
|
-
import
|
|
35
|
+
import { openSubtreeJson } from "./subtree-json-dialog.component.js";
|
|
36
36
|
export const NodeContextMenu = observer(/*#__PURE__*/ forwardRef((props, ref)=>{
|
|
37
37
|
var _node_parent_nodes, _node_parent;
|
|
38
38
|
const { node, onAction } = props, rest = _object_without_properties_loose(props, [
|
|
@@ -48,7 +48,6 @@ export const NodeContextMenu = observer(/*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
48
48
|
const elementRef = Besigner.refs.get(node == null ? void 0 : node.$id);
|
|
49
49
|
const [moreOpen, setMoreOpen] = useState(false);
|
|
50
50
|
const [moreButton, moreButtonRef] = useState(null);
|
|
51
|
-
const [jsonOpen, setJsonOpen] = useState(false);
|
|
52
51
|
const closeMore = useCallback(()=>setMoreOpen(false), []);
|
|
53
52
|
const openMore = useCallback(()=>setMoreOpen(true), []);
|
|
54
53
|
const handleDuplicateClick = useCallback((e)=>{
|
|
@@ -166,6 +165,17 @@ export const NodeContextMenu = observer(/*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
166
165
|
onAction,
|
|
167
166
|
pasteElements
|
|
168
167
|
]);
|
|
168
|
+
// Dismiss FIRST, then open (AGL-3208). The dialog is no longer a child of
|
|
169
|
+
// this menu — `SubtreeJsonDialogHost` holds it — so the menu closing can
|
|
170
|
+
// no longer take the editor with it, and leaving the menu standing behind
|
|
171
|
+
// a 95vw dialog only leaves something to click away onto.
|
|
172
|
+
const handleEditJsonClick = useCallback(()=>{
|
|
173
|
+
onAction == null ? void 0 : onAction();
|
|
174
|
+
openSubtreeJson(node);
|
|
175
|
+
}, [
|
|
176
|
+
node,
|
|
177
|
+
onAction
|
|
178
|
+
]);
|
|
169
179
|
// Observed, so the item enables the moment something is copied — even
|
|
170
180
|
// from another document, where the entry arrives via localStorage.
|
|
171
181
|
const canPaste = Besigner.clipboard.hasContent();
|
|
@@ -276,7 +286,7 @@ export const NodeContextMenu = observer(/*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
276
286
|
deleteElementCallback,
|
|
277
287
|
deleteElementsCallback
|
|
278
288
|
]);
|
|
279
|
-
return /*#__PURE__*/
|
|
289
|
+
return /*#__PURE__*/ _jsx(Paper, _extends({
|
|
280
290
|
ref: ref,
|
|
281
291
|
sx: {
|
|
282
292
|
width: 240,
|
|
@@ -295,261 +305,251 @@ export const NodeContextMenu = observer(/*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
295
305
|
overflowX: 'hidden'
|
|
296
306
|
}
|
|
297
307
|
}, rest, {
|
|
298
|
-
children:
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
/*#__PURE__*/ _jsx(
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
path: ICON_VARIANT_MODIFY_MOVE_UP.path
|
|
349
|
-
})
|
|
350
|
-
}),
|
|
351
|
-
/*#__PURE__*/ _jsx(ListItemText, {
|
|
352
|
-
children: "Shift up"
|
|
308
|
+
children: /*#__PURE__*/ _jsxs(MenuList, {
|
|
309
|
+
dense: true,
|
|
310
|
+
children: [
|
|
311
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
312
|
+
variant: "caption",
|
|
313
|
+
color: "text.secondary",
|
|
314
|
+
component: "div",
|
|
315
|
+
sx: {
|
|
316
|
+
px: 1,
|
|
317
|
+
py: 0.15,
|
|
318
|
+
mb: 1,
|
|
319
|
+
textAlign: 'center',
|
|
320
|
+
textOverflow: 'ellipsis',
|
|
321
|
+
overflow: 'hidden',
|
|
322
|
+
whiteSpace: 'nowrap',
|
|
323
|
+
backgroundColor: (theme)=>`rgba(${theme.vars.palette.primary.darkChannel} / 0.12)`
|
|
324
|
+
},
|
|
325
|
+
children: node == null ? void 0 : node.labelShort
|
|
326
|
+
}),
|
|
327
|
+
multi ? null : /*#__PURE__*/ _jsx(MenuItem, {
|
|
328
|
+
onClick: ()=>{
|
|
329
|
+
onAction == null ? void 0 : onAction();
|
|
330
|
+
handleAddElementClick(node);
|
|
331
|
+
},
|
|
332
|
+
children: /*#__PURE__*/ _jsx(ListItemText, {
|
|
333
|
+
inset: true,
|
|
334
|
+
children: "Add element"
|
|
335
|
+
})
|
|
336
|
+
}),
|
|
337
|
+
multi ? null : /*#__PURE__*/ _jsx(Divider, {}),
|
|
338
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
339
|
+
onClick: handleParentOnClick,
|
|
340
|
+
disabled: isRootNode || multi,
|
|
341
|
+
onMouseEnter: handleParentOnMouseEnter,
|
|
342
|
+
onPointerEnter: handleParentOnMouseEnter,
|
|
343
|
+
onMouseLeave: handleParentOnMouseLeave,
|
|
344
|
+
onPointerLeave: handleParentOnMouseLeave,
|
|
345
|
+
children: /*#__PURE__*/ _jsx(ListItemText, {
|
|
346
|
+
inset: true,
|
|
347
|
+
children: "Select parent"
|
|
348
|
+
})
|
|
349
|
+
}),
|
|
350
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
351
|
+
onClick: handleMoveUp,
|
|
352
|
+
disabled: isRootNode || multi || !((node == null ? void 0 : node.index) > 0),
|
|
353
|
+
children: [
|
|
354
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
355
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
356
|
+
fontSize: "inherit",
|
|
357
|
+
path: ICON_VARIANT_MODIFY_MOVE_UP.path
|
|
353
358
|
})
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
359
|
+
}),
|
|
360
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
361
|
+
children: "Shift up"
|
|
362
|
+
})
|
|
363
|
+
]
|
|
364
|
+
}),
|
|
365
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
366
|
+
onClick: handleMoveDown,
|
|
367
|
+
disabled: isRootNode || multi || !((node == null ? void 0 : node.index) < (node == null ? void 0 : (_node_parent = node.parent) == null ? void 0 : (_node_parent_nodes = _node_parent.nodes) == null ? void 0 : _node_parent_nodes.length) - 1),
|
|
368
|
+
children: [
|
|
369
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
370
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
371
|
+
fontSize: "inherit",
|
|
372
|
+
path: ICON_VARIANT_MODIFY_MOVE_DOWN.path
|
|
368
373
|
})
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
374
|
+
}),
|
|
375
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
376
|
+
children: "Shift down"
|
|
377
|
+
})
|
|
378
|
+
]
|
|
379
|
+
}),
|
|
380
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
381
|
+
onClick: handleMoveOut,
|
|
382
|
+
disabled: !canMoveOut,
|
|
383
|
+
children: [
|
|
384
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
385
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
386
|
+
fontSize: "inherit",
|
|
387
|
+
path: ICON_VARIANT_MODIFY_MOVE_OUT.path
|
|
383
388
|
})
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
389
|
+
}),
|
|
390
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
391
|
+
children: "Move out of container"
|
|
392
|
+
})
|
|
393
|
+
]
|
|
394
|
+
}),
|
|
395
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
396
|
+
onClick: handleMoveIn,
|
|
397
|
+
disabled: !canMoveIn,
|
|
398
|
+
children: [
|
|
399
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
400
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
401
|
+
fontSize: "inherit",
|
|
402
|
+
path: ICON_VARIANT_MODIFY_MOVE_IN.path
|
|
398
403
|
})
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
onClick: ()=>setJsonOpen(true),
|
|
403
|
-
children: /*#__PURE__*/ _jsx(ListItemText, {
|
|
404
|
-
inset: true,
|
|
405
|
-
children: "Edit JSON"
|
|
404
|
+
}),
|
|
405
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
406
|
+
children: "Move into element above"
|
|
406
407
|
})
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
408
|
+
]
|
|
409
|
+
}),
|
|
410
|
+
multi ? null : /*#__PURE__*/ _jsx(MenuItem, {
|
|
411
|
+
onClick: handleEditJsonClick,
|
|
412
|
+
children: /*#__PURE__*/ _jsx(ListItemText, {
|
|
413
|
+
inset: true,
|
|
414
|
+
children: "Edit JSON"
|
|
415
|
+
})
|
|
416
|
+
}),
|
|
417
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
418
|
+
disabled: isRootNode,
|
|
419
|
+
onClick: handleToggleHiddenClick,
|
|
420
|
+
children: [
|
|
421
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
422
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
423
|
+
fontSize: "inherit",
|
|
424
|
+
path: hiddenOnSite ? ICON_VARIANT_VISIBILITY_SHOWN.path : ICON_VARIANT_VISIBILITY_HIDDEN.path
|
|
425
|
+
})
|
|
426
|
+
}),
|
|
427
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
428
|
+
secondary: hiddenOnSite ? 'It will be on the page from the first paint' : 'For a menu panel or drawer. To hide it outright, use the eye on its Hierarchy row',
|
|
429
|
+
slotProps: {
|
|
430
|
+
secondary: {
|
|
431
|
+
sx: {
|
|
432
|
+
whiteSpace: 'normal'
|
|
425
433
|
}
|
|
426
|
-
}
|
|
427
|
-
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
children: hiddenOnSite ? 'Do not start hidden' : 'Start hidden until an interaction shows it'
|
|
437
|
+
})
|
|
438
|
+
]
|
|
439
|
+
}),
|
|
440
|
+
/*#__PURE__*/ _jsx(Divider, {}),
|
|
441
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
442
|
+
disabled: isRootNode,
|
|
443
|
+
onClick: handleCopyClick,
|
|
444
|
+
children: [
|
|
445
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
446
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
447
|
+
fontSize: "inherit",
|
|
448
|
+
path: ICON_VARIANT_MODIFY_COPY.path
|
|
428
449
|
})
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
children: multi ? 'Copy selection' : 'Copy'
|
|
450
|
+
}),
|
|
451
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
452
|
+
children: multi ? 'Copy selection' : 'Copy'
|
|
453
|
+
})
|
|
454
|
+
]
|
|
455
|
+
}),
|
|
456
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
457
|
+
disabled: isRootNode,
|
|
458
|
+
onClick: handleCopyStyles,
|
|
459
|
+
children: [
|
|
460
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
461
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
462
|
+
fontSize: "inherit",
|
|
463
|
+
path: ICON_VARIANT_MODIFY_COPY.path
|
|
444
464
|
})
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
465
|
+
}),
|
|
466
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
467
|
+
children: 'Copy styles'
|
|
468
|
+
})
|
|
469
|
+
]
|
|
470
|
+
}),
|
|
471
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
472
|
+
disabled: isRootNode || !canPasteStyles,
|
|
473
|
+
onClick: handlePasteStyles,
|
|
474
|
+
children: [
|
|
475
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
476
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
477
|
+
fontSize: "inherit",
|
|
478
|
+
path: ICON_VARIANT_MODIFY_PASTE.path
|
|
459
479
|
})
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
fontSize: "inherit",
|
|
469
|
-
path: ICON_VARIANT_MODIFY_PASTE.path
|
|
470
|
-
})
|
|
471
|
-
}),
|
|
472
|
-
/*#__PURE__*/ _jsx(ListItemText, {
|
|
473
|
-
slotProps: {
|
|
474
|
-
primary: {
|
|
475
|
-
sx: {
|
|
476
|
-
overflow: 'hidden',
|
|
477
|
-
textOverflow: 'ellipsis',
|
|
478
|
-
whiteSpace: 'nowrap'
|
|
479
|
-
}
|
|
480
|
+
}),
|
|
481
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
482
|
+
slotProps: {
|
|
483
|
+
primary: {
|
|
484
|
+
sx: {
|
|
485
|
+
overflow: 'hidden',
|
|
486
|
+
textOverflow: 'ellipsis',
|
|
487
|
+
whiteSpace: 'nowrap'
|
|
480
488
|
}
|
|
481
|
-
}
|
|
482
|
-
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
children: copiedStyleLabel ? `Paste styles from ${copiedStyleLabel}` : 'Paste styles'
|
|
492
|
+
})
|
|
493
|
+
]
|
|
494
|
+
}),
|
|
495
|
+
/*#__PURE__*/ _jsx(Divider, {}),
|
|
496
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
497
|
+
disabled: !canPaste,
|
|
498
|
+
onClick: handlePasteClick,
|
|
499
|
+
children: [
|
|
500
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
501
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
502
|
+
fontSize: "inherit",
|
|
503
|
+
path: ICON_VARIANT_MODIFY_PASTE.path
|
|
483
504
|
})
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
493
|
-
fontSize: "inherit",
|
|
494
|
-
path: ICON_VARIANT_MODIFY_PASTE.path
|
|
495
|
-
})
|
|
496
|
-
}),
|
|
497
|
-
/*#__PURE__*/ _jsx(ListItemText, {
|
|
498
|
-
slotProps: {
|
|
499
|
-
primary: {
|
|
500
|
-
sx: {
|
|
501
|
-
overflow: 'hidden',
|
|
502
|
-
textOverflow: 'ellipsis',
|
|
503
|
-
whiteSpace: 'nowrap'
|
|
504
|
-
}
|
|
505
|
+
}),
|
|
506
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
507
|
+
slotProps: {
|
|
508
|
+
primary: {
|
|
509
|
+
sx: {
|
|
510
|
+
overflow: 'hidden',
|
|
511
|
+
textOverflow: 'ellipsis',
|
|
512
|
+
whiteSpace: 'nowrap'
|
|
505
513
|
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
}),
|
|
522
|
-
/*#__PURE__*/ _jsx(ListItemText, {
|
|
523
|
-
children: multi ? 'Duplicate selection' : 'Duplicate'
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
children: clipboardLabels.length === 1 ? `Paste ${clipboardLabels[0]}` : clipboardLabels.length > 1 ? `Paste ${clipboardLabels.length} elements` : 'Paste'
|
|
517
|
+
})
|
|
518
|
+
]
|
|
519
|
+
}),
|
|
520
|
+
/*#__PURE__*/ _jsx(Divider, {}),
|
|
521
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
522
|
+
disabled: isRootNode,
|
|
523
|
+
onClick: handleDuplicateClick,
|
|
524
|
+
children: [
|
|
525
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
526
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
527
|
+
fontSize: "inherit",
|
|
528
|
+
path: ICON_VARIANT_MODIFY_DUPLICATE.path
|
|
524
529
|
})
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
530
|
+
}),
|
|
531
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
532
|
+
children: multi ? 'Duplicate selection' : 'Duplicate'
|
|
533
|
+
})
|
|
534
|
+
]
|
|
535
|
+
}),
|
|
536
|
+
/*#__PURE__*/ _jsxs(MenuItem, {
|
|
537
|
+
disabled: isRootNode,
|
|
538
|
+
onClick: handleDeleteClick,
|
|
539
|
+
children: [
|
|
540
|
+
/*#__PURE__*/ _jsx(ListItemIcon, {
|
|
541
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
542
|
+
fontSize: "inherit",
|
|
543
|
+
path: ICON_VARIANT_MODIFY_DELETE.path
|
|
539
544
|
})
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
setJsonOpen(false);
|
|
549
|
-
onAction == null ? void 0 : onAction();
|
|
550
|
-
}
|
|
551
|
-
})
|
|
552
|
-
]
|
|
545
|
+
}),
|
|
546
|
+
/*#__PURE__*/ _jsx(ListItemText, {
|
|
547
|
+
children: multi ? 'Delete selection' : 'Delete'
|
|
548
|
+
})
|
|
549
|
+
]
|
|
550
|
+
})
|
|
551
|
+
]
|
|
552
|
+
})
|
|
553
553
|
}));
|
|
554
554
|
}));
|
|
555
555
|
NodeContextMenu.displayName = 'NodeContextMenu';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/node-context-menu.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type * as Aglyn from '@aglyn/aglyn'\nimport { canvas } from '@aglyn/aglyn'\nimport * as Besigner from '@aglyn/besigner'\nimport {\n BesignerPanelTabFlag,\n setBesignerPanels,\n} from '@aglyn/besigner'\nimport {\n ICON_VARIANT_MODIFY_COPY,\n ICON_VARIANT_MODIFY_DELETE,\n ICON_VARIANT_MODIFY_DUPLICATE,\n ICON_VARIANT_MODIFY_MOVE_DOWN,\n ICON_VARIANT_MODIFY_MOVE_IN,\n ICON_VARIANT_MODIFY_MOVE_OUT,\n ICON_VARIANT_MODIFY_MOVE_UP,\n ICON_VARIANT_MODIFY_PASTE,\n ICON_VARIANT_VISIBILITY_HIDDEN,\n ICON_VARIANT_VISIBILITY_SHOWN,\n} from '@aglyn/shared-data-enums'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport {\n Divider,\n ListItemIcon,\n ListItemText,\n MenuItem,\n MenuList,\n Paper,\n type PaperProps,\n Typography,\n} from '@mui/material'\nimport { action } from 'mobx'\nimport { observer } from 'mobx-react-lite'\nimport { ChangeEvent, forwardRef, useCallback, useState } from 'react'\nimport useAglynBesignerFlag from '../hooks/use-aglyn-besigner-flag'\nimport useAddElementDrawerCallback from '../hooks/use-add-element-drawer-callback'\nimport useBesignerAppContext from '../hooks/use-besigner-app-context'\nimport {\n useCopyElementsCallback,\n usePasteElementsCallback,\n} from '../hooks/use-clipboard-callbacks'\nimport useDeleteElementCallback, {\n useDeleteElementsCallback,\n} from '../hooks/use-delete-element-callback'\nimport {\n useMoveNodeInCallback,\n useMoveNodeOutCallback,\n} from '../hooks/use-move-node-callbacks'\nimport {\n isNodeHiddenOnSite,\n nodePropsWithHiddenOnSite,\n} from '../utils/canvas-reveal'\nimport SubtreeJsonDialog from './subtree-json-dialog.component'\n\nexport interface NodeContextMenuProps extends PaperProps {\n node: Aglyn.NodeSchema<any>\n /** Invoked when a menu action should dismiss the hosting menu/tooltip. */\n onAction?: () => void\n}\n\nexport const NodeContextMenu = observer(\n forwardRef<any, NodeContextMenuProps>((props, ref) => {\n const { node, onAction, ...rest } = props\n\n const isRootNode = canvas.isRootNode(node)\n // Multi-selection (AGL-11): ambiguous single-target actions hide or\n // disable; Duplicate/Delete apply to the whole selection.\n const multi = Besigner.focus.hasMultipleSelected()\n const app = useBesignerAppContext()\n const handleAddElementClick = useAddElementDrawerCallback()\n const elementRef = Besigner.refs.get(node?.$id)\n const [moreOpen, setMoreOpen] = useState(false)\n const [moreButton, moreButtonRef] = useState<HTMLButtonElement | null>(null)\n const [jsonOpen, setJsonOpen] = useState(false)\n\n const closeMore = useCallback(() => setMoreOpen(false), [])\n const openMore = useCallback(() => setMoreOpen(true), [])\n\n const handleDuplicateClick = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n onAction?.()\n const targets = multi ? Besigner.focus.getSelected() : [node]\n for (const target of targets) {\n if (target && !canvas.isRootNode(target)) {\n canvas.duplicateNode(target)\n }\n }\n },\n [node, isRootNode, multi, onAction],\n )\n\n const handleModifyClick = useCallback(\n (e: ChangeEvent<unknown>) => {\n setBesignerPanels(app, {\n panels: (panels) => ({\n ...panels,\n panelRight: {\n ...panels.panelRight,\n toggled: true,\n tab: BesignerPanelTabFlag.ELEMENT_PROPS_FORM,\n },\n }),\n })\n },\n [app],\n )\n const handleMoveUp = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n canvas.reorderNode(node, node?.index - 1)\n },\n [node, isRootNode],\n )\n const handleMoveDown = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n canvas.reorderNode(node, node?.index + 1)\n },\n [node, isRootNode],\n )\n\n /**\n * Reparenting by clicking (AGL-1405). Until these two existed, the only\n * way to move a node into a different container was to drag it — so a\n * node that ended up somewhere it can never render (AGL-1388) could only\n * be rescued by hand-editing the document's JSON.\n *\n * `canMove*` is read through the observer, so the items enable and\n * disable as the selection moves, and both refuse anything the renderer\n * could not draw rather than accepting it and stranding the subtree.\n */\n const moveNodeOut = useMoveNodeOutCallback()\n const moveNodeIn = useMoveNodeInCallback()\n const canMoveOut = !multi && Besigner.canMoveNodeOut(node)\n const canMoveIn = !multi && Besigner.canMoveNodeIn(node)\n\n const handleMoveOut = useCallback(() => {\n onAction?.()\n moveNodeOut(node)\n }, [node, onAction, moveNodeOut])\n\n const handleMoveIn = useCallback(() => {\n onAction?.()\n moveNodeIn(node)\n }, [node, onAction, moveNodeIn])\n\n const handleParentOnClick = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n Besigner.focus.setSelectedNode(node?.parent)\n },\n [node, isRootNode],\n )\n\n const handleParentOnMouseEnter = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n Besigner.focus.setHoveredNode(node)\n },\n [node, isRootNode],\n )\n const handleParentOnMouseLeave = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n Besigner.focus.clearHover()\n },\n [isRootNode],\n )\n\n const copyElements = useCopyElementsCallback()\n const pasteElements = usePasteElementsCallback()\n const handleCopyClick = useCallback(() => {\n if (isRootNode) return\n onAction?.()\n copyElements(multi ? Besigner.focus.getSelected() : [node])\n }, [node, isRootNode, multi, onAction, copyElements])\n\n const handlePasteClick = useCallback(() => {\n onAction?.()\n pasteElements(node)\n }, [node, onAction, pasteElements])\n\n // Observed, so the item enables the moment something is copied — even\n // from another document, where the entry arrives via localStorage.\n const canPaste = Besigner.clipboard.hasContent()\n const clipboardLabels = Besigner.clipboard.getLabels()\n\n /**\n * Start hidden until an interaction shows it (AGL-592).\n *\n * A DIFFERENT switch from the eye on the hierarchy row, and the naming is\n * the whole point. The eye hides an element outright — `display: none`,\n * nothing reveals it. This one enrols the element in a runtime contract:\n * it starts hidden, an interaction's show step reveals it, and the canvas\n * opens it while it is being designed. A mega-menu panel, a drawer, an\n * announcement that appears on scroll.\n *\n * `aglyn-hidden` is the storage — the published stylesheet, the show/hide\n * steps and the canvas reveal all key off it — and until this existed the\n * only way to set it was to know the literal string and type it into the\n * Classes box. An element property with no picker is a missing feature,\n * not a power-user path.\n */\n const [, setRevealedNodeIds] = useAglynBesignerFlag('revealedNodeIds')\n const hiddenOnSite = isNodeHiddenOnSite(node as never)\n const handleToggleHiddenClick = useCallback(() => {\n if (isRootNode) return\n onAction?.()\n const targets = multi ? Besigner.focus.getSelected() : [node]\n const changed: string[] = []\n action(() => {\n for (const target of targets) {\n if (!target || canvas.isRootNode(target)) continue\n const props = nodePropsWithHiddenOnSite(target as never, !hiddenOnSite)\n if (!props) continue\n target.props = props as never\n changed.push(target.$id)\n }\n })()\n // Showing an element again retires its canvas reveal with it. The flag\n // is only meaningful for something the site hides, so leaving an entry\n // behind means the next hide silently starts revealed. Hiding sets\n // nothing: hidden is hidden, and selecting the element — which\n // whichever surface opened this menu has already done — is what shows\n // it while it is being designed.\n if (hiddenOnSite && changed.length) {\n setRevealedNodeIds((current) =>\n (current ?? []).filter((id) => !changed.includes(id)),\n )\n }\n }, [node, isRootNode, multi, hiddenOnSite, onAction, setRevealedNodeIds])\n\n /**\n * Copy and paste a LOOK.\n *\n * `node.sx` — the Styles panel's whole output, including its responsive,\n * `@scheme` and state slices, which are keys inside that object. Classes\n * are deliberately not carried: a class is a name pointing at rules the\n * element does not own, and two of them carry behaviour rather than\n * appearance, so moving them under a label that promises looks would move\n * behaviour with it.\n *\n * Paste REPLACES. Merging makes the result depend on what the target\n * already had, so the same look pasted onto two elements could produce\n * two different ones — and there would be no way to paste \"no styles\".\n */\n const copiedStyleLabel = Besigner.styleClipboard.getStyleLabel()\n const canPasteStyles = Besigner.styleClipboard.hasStyles()\n const handleCopyStyles = useCallback(() => {\n if (isRootNode) return\n onAction?.()\n Besigner.styleClipboard.copyStyles(node)\n }, [node, isRootNode, onAction])\n const handlePasteStyles = useCallback(() => {\n if (isRootNode) return\n onAction?.()\n const targets = multi ? Besigner.focus.getSelected() : [node]\n for (const target of targets) {\n if (target && !canvas.isRootNode(target)) {\n Besigner.styleClipboard.pasteStyles(target)\n }\n }\n }, [node, isRootNode, multi, onAction])\n\n const deleteElementCallback = useDeleteElementCallback()\n const deleteElementsCallback = useDeleteElementsCallback()\n const handleDeleteClick = useCallback(() => {\n closeMore()\n onAction?.()\n if (multi) void deleteElementsCallback(Besigner.focus.getSelected())\n else void deleteElementCallback(node)\n }, [\n node,\n multi,\n closeMore,\n onAction,\n deleteElementCallback,\n deleteElementsCallback,\n ])\n\n return (\n <Paper\n ref={ref}\n sx={{\n width: 240,\n // Caps itself rather than growing past the window (AGL-1405). The\n // Popper can only slide a menu back inside the viewport if it FITS\n // in one; a taller menu was laid out past the bottom of the\n // document and the page grew a scrollbar around it. `dvh` so a\n // mobile browser's retracting toolbar does not leave the last item\n // under it.\n // Shorter than the window, not merely within it. A menu that only\n // just fits is one `preventOverflow` has to slide a long way to\n // place, and a menu that lands 200px from where it was asked for\n // reads as landing at random.\n maxHeight: 'min(420px, calc(100dvh - 24px))',\n overflowY: 'auto',\n overflowX: 'hidden',\n }}\n {...rest}\n >\n <MenuList dense>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n component=\"div\"\n sx={{\n px: 1,\n py: 0.15,\n mb: 1,\n textAlign: 'center',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n backgroundColor: (theme) =>\n `rgba(${(theme as any).vars.palette.primary.darkChannel} / 0.12)`,\n }}\n >\n {node?.labelShort}\n </Typography>\n {multi ? null : (\n <MenuItem\n onClick={() => {\n onAction?.()\n handleAddElementClick(node)\n }}\n >\n <ListItemText inset>Add element</ListItemText>\n </MenuItem>\n )}\n {multi ? null : <Divider />}\n <MenuItem\n onClick={handleParentOnClick}\n disabled={isRootNode || multi}\n onMouseEnter={handleParentOnMouseEnter}\n onPointerEnter={handleParentOnMouseEnter}\n onMouseLeave={handleParentOnMouseLeave}\n onPointerLeave={handleParentOnMouseLeave}\n >\n <ListItemText inset>Select parent</ListItemText>\n </MenuItem>\n <MenuItem\n onClick={handleMoveUp}\n disabled={isRootNode || multi || !(node?.index > 0)}\n >\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_MOVE_UP.path}\n />\n </ListItemIcon>\n <ListItemText>Shift up</ListItemText>\n </MenuItem>\n <MenuItem\n onClick={handleMoveDown}\n disabled={\n isRootNode ||\n multi ||\n !(node?.index < node?.parent?.nodes?.length - 1)\n }\n >\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_MOVE_DOWN.path}\n />\n </ListItemIcon>\n <ListItemText>Shift down</ListItemText>\n </MenuItem>\n <MenuItem onClick={handleMoveOut} disabled={!canMoveOut}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_MOVE_OUT.path}\n />\n </ListItemIcon>\n <ListItemText>Move out of container</ListItemText>\n </MenuItem>\n <MenuItem onClick={handleMoveIn} disabled={!canMoveIn}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_MOVE_IN.path}\n />\n </ListItemIcon>\n <ListItemText>Move into element above</ListItemText>\n </MenuItem>\n {multi ? null : (\n <MenuItem onClick={() => setJsonOpen(true)}>\n <ListItemText inset>Edit JSON</ListItemText>\n </MenuItem>\n )}\n <MenuItem disabled={isRootNode} onClick={handleToggleHiddenClick}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={\n hiddenOnSite\n ? ICON_VARIANT_VISIBILITY_SHOWN.path\n : ICON_VARIANT_VISIBILITY_HIDDEN.path\n }\n />\n </ListItemIcon>\n <ListItemText\n secondary={\n hiddenOnSite\n ? 'It will be on the page from the first paint'\n : 'For a menu panel or drawer. To hide it outright, use the eye on its Hierarchy row'\n }\n slotProps={{ secondary: { sx: { whiteSpace: 'normal' } } }}\n >\n {hiddenOnSite\n ? 'Do not start hidden'\n : 'Start hidden until an interaction shows it'}\n </ListItemText>\n </MenuItem>\n <Divider />\n <MenuItem disabled={isRootNode} onClick={handleCopyClick}>\n <ListItemIcon>\n <MdiIcon fontSize=\"inherit\" path={ICON_VARIANT_MODIFY_COPY.path} />\n </ListItemIcon>\n <ListItemText>{multi ? 'Copy selection' : 'Copy'}</ListItemText>\n </MenuItem>\n <MenuItem disabled={isRootNode} onClick={handleCopyStyles}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_COPY.path}\n />\n </ListItemIcon>\n <ListItemText>{'Copy styles'}</ListItemText>\n </MenuItem>\n <MenuItem\n disabled={isRootNode || !canPasteStyles}\n onClick={handlePasteStyles}\n >\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_PASTE.path}\n />\n </ListItemIcon>\n <ListItemText\n slotProps={{\n primary: {\n sx: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n },\n },\n }}\n >\n {copiedStyleLabel\n ? `Paste styles from ${copiedStyleLabel}`\n : 'Paste styles'}\n </ListItemText>\n </MenuItem>\n <Divider />\n <MenuItem disabled={!canPaste} onClick={handlePasteClick}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_PASTE.path}\n />\n </ListItemIcon>\n <ListItemText\n slotProps={{\n primary: {\n sx: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n },\n },\n }}\n >\n {clipboardLabels.length === 1\n ? `Paste ${clipboardLabels[0]}`\n : clipboardLabels.length > 1\n ? `Paste ${clipboardLabels.length} elements`\n : 'Paste'}\n </ListItemText>\n </MenuItem>\n <Divider />\n <MenuItem disabled={isRootNode} onClick={handleDuplicateClick}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_DUPLICATE.path}\n />\n </ListItemIcon>\n <ListItemText>\n {multi ? 'Duplicate selection' : 'Duplicate'}\n </ListItemText>\n </MenuItem>\n <MenuItem disabled={isRootNode} onClick={handleDeleteClick}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_DELETE.path}\n />\n </ListItemIcon>\n <ListItemText>{multi ? 'Delete selection' : 'Delete'}</ListItemText>\n </MenuItem>\n </MenuList>\n <SubtreeJsonDialog\n node={node}\n open={jsonOpen}\n onClose={() => {\n setJsonOpen(false)\n onAction?.()\n }}\n />\n </Paper>\n )\n }),\n)\nNodeContextMenu.displayName = 'NodeContextMenu'\n\nexport default NodeContextMenu\n"],"names":["canvas","Besigner","BesignerPanelTabFlag","setBesignerPanels","ICON_VARIANT_MODIFY_COPY","ICON_VARIANT_MODIFY_DELETE","ICON_VARIANT_MODIFY_DUPLICATE","ICON_VARIANT_MODIFY_MOVE_DOWN","ICON_VARIANT_MODIFY_MOVE_IN","ICON_VARIANT_MODIFY_MOVE_OUT","ICON_VARIANT_MODIFY_MOVE_UP","ICON_VARIANT_MODIFY_PASTE","ICON_VARIANT_VISIBILITY_HIDDEN","ICON_VARIANT_VISIBILITY_SHOWN","MdiIcon","Divider","ListItemIcon","ListItemText","MenuItem","MenuList","Paper","Typography","action","observer","forwardRef","useCallback","useState","useAglynBesignerFlag","useAddElementDrawerCallback","useBesignerAppContext","useCopyElementsCallback","usePasteElementsCallback","useDeleteElementCallback","useDeleteElementsCallback","useMoveNodeInCallback","useMoveNodeOutCallback","isNodeHiddenOnSite","nodePropsWithHiddenOnSite","SubtreeJsonDialog","NodeContextMenu","props","ref","node","onAction","rest","isRootNode","multi","focus","hasMultipleSelected","app","handleAddElementClick","elementRef","refs","get","$id","moreOpen","setMoreOpen","moreButton","moreButtonRef","jsonOpen","setJsonOpen","closeMore","openMore","handleDuplicateClick","e","targets","getSelected","target","duplicateNode","handleModifyClick","panels","panelRight","toggled","tab","ELEMENT_PROPS_FORM","handleMoveUp","reorderNode","index","handleMoveDown","moveNodeOut","moveNodeIn","canMoveOut","canMoveNodeOut","canMoveIn","canMoveNodeIn","handleMoveOut","handleMoveIn","handleParentOnClick","setSelectedNode","parent","handleParentOnMouseEnter","setHoveredNode","handleParentOnMouseLeave","clearHover","copyElements","pasteElements","handleCopyClick","handlePasteClick","canPaste","clipboard","hasContent","clipboardLabels","getLabels","setRevealedNodeIds","hiddenOnSite","handleToggleHiddenClick","changed","push","length","current","filter","id","includes","copiedStyleLabel","styleClipboard","getStyleLabel","canPasteStyles","hasStyles","handleCopyStyles","copyStyles","handlePasteStyles","pasteStyles","deleteElementCallback","deleteElementsCallback","handleDeleteClick","sx","width","maxHeight","overflowY","overflowX","dense","variant","color","component","px","py","mb","textAlign","textOverflow","overflow","whiteSpace","backgroundColor","theme","vars","palette","primary","darkChannel","labelShort","onClick","inset","disabled","onMouseEnter","onPointerEnter","onMouseLeave","onPointerLeave","fontSize","path","nodes","secondary","slotProps","open","onClose","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/node-context-menu.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type * as Aglyn from '@aglyn/aglyn'\nimport { canvas } from '@aglyn/aglyn'\nimport * as Besigner from '@aglyn/besigner'\nimport {\n BesignerPanelTabFlag,\n setBesignerPanels,\n} from '@aglyn/besigner'\nimport {\n ICON_VARIANT_MODIFY_COPY,\n ICON_VARIANT_MODIFY_DELETE,\n ICON_VARIANT_MODIFY_DUPLICATE,\n ICON_VARIANT_MODIFY_MOVE_DOWN,\n ICON_VARIANT_MODIFY_MOVE_IN,\n ICON_VARIANT_MODIFY_MOVE_OUT,\n ICON_VARIANT_MODIFY_MOVE_UP,\n ICON_VARIANT_MODIFY_PASTE,\n ICON_VARIANT_VISIBILITY_HIDDEN,\n ICON_VARIANT_VISIBILITY_SHOWN,\n} from '@aglyn/shared-data-enums'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport {\n Divider,\n ListItemIcon,\n ListItemText,\n MenuItem,\n MenuList,\n Paper,\n type PaperProps,\n Typography,\n} from '@mui/material'\nimport { action } from 'mobx'\nimport { observer } from 'mobx-react-lite'\nimport { ChangeEvent, forwardRef, useCallback, useState } from 'react'\nimport useAglynBesignerFlag from '../hooks/use-aglyn-besigner-flag'\nimport useAddElementDrawerCallback from '../hooks/use-add-element-drawer-callback'\nimport useBesignerAppContext from '../hooks/use-besigner-app-context'\nimport {\n useCopyElementsCallback,\n usePasteElementsCallback,\n} from '../hooks/use-clipboard-callbacks'\nimport useDeleteElementCallback, {\n useDeleteElementsCallback,\n} from '../hooks/use-delete-element-callback'\nimport {\n useMoveNodeInCallback,\n useMoveNodeOutCallback,\n} from '../hooks/use-move-node-callbacks'\nimport {\n isNodeHiddenOnSite,\n nodePropsWithHiddenOnSite,\n} from '../utils/canvas-reveal'\nimport { openSubtreeJson } from './subtree-json-dialog.component'\n\nexport interface NodeContextMenuProps extends PaperProps {\n node: Aglyn.NodeSchema<any>\n /** Invoked when a menu action should dismiss the hosting menu/tooltip. */\n onAction?: () => void\n}\n\nexport const NodeContextMenu = observer(\n forwardRef<any, NodeContextMenuProps>((props, ref) => {\n const { node, onAction, ...rest } = props\n\n const isRootNode = canvas.isRootNode(node)\n // Multi-selection (AGL-11): ambiguous single-target actions hide or\n // disable; Duplicate/Delete apply to the whole selection.\n const multi = Besigner.focus.hasMultipleSelected()\n const app = useBesignerAppContext()\n const handleAddElementClick = useAddElementDrawerCallback()\n const elementRef = Besigner.refs.get(node?.$id)\n const [moreOpen, setMoreOpen] = useState(false)\n const [moreButton, moreButtonRef] = useState<HTMLButtonElement | null>(null)\n\n const closeMore = useCallback(() => setMoreOpen(false), [])\n const openMore = useCallback(() => setMoreOpen(true), [])\n\n const handleDuplicateClick = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n onAction?.()\n const targets = multi ? Besigner.focus.getSelected() : [node]\n for (const target of targets) {\n if (target && !canvas.isRootNode(target)) {\n canvas.duplicateNode(target)\n }\n }\n },\n [node, isRootNode, multi, onAction],\n )\n\n const handleModifyClick = useCallback(\n (e: ChangeEvent<unknown>) => {\n setBesignerPanels(app, {\n panels: (panels) => ({\n ...panels,\n panelRight: {\n ...panels.panelRight,\n toggled: true,\n tab: BesignerPanelTabFlag.ELEMENT_PROPS_FORM,\n },\n }),\n })\n },\n [app],\n )\n const handleMoveUp = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n canvas.reorderNode(node, node?.index - 1)\n },\n [node, isRootNode],\n )\n const handleMoveDown = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n canvas.reorderNode(node, node?.index + 1)\n },\n [node, isRootNode],\n )\n\n /**\n * Reparenting by clicking (AGL-1405). Until these two existed, the only\n * way to move a node into a different container was to drag it — so a\n * node that ended up somewhere it can never render (AGL-1388) could only\n * be rescued by hand-editing the document's JSON.\n *\n * `canMove*` is read through the observer, so the items enable and\n * disable as the selection moves, and both refuse anything the renderer\n * could not draw rather than accepting it and stranding the subtree.\n */\n const moveNodeOut = useMoveNodeOutCallback()\n const moveNodeIn = useMoveNodeInCallback()\n const canMoveOut = !multi && Besigner.canMoveNodeOut(node)\n const canMoveIn = !multi && Besigner.canMoveNodeIn(node)\n\n const handleMoveOut = useCallback(() => {\n onAction?.()\n moveNodeOut(node)\n }, [node, onAction, moveNodeOut])\n\n const handleMoveIn = useCallback(() => {\n onAction?.()\n moveNodeIn(node)\n }, [node, onAction, moveNodeIn])\n\n const handleParentOnClick = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n Besigner.focus.setSelectedNode(node?.parent)\n },\n [node, isRootNode],\n )\n\n const handleParentOnMouseEnter = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n Besigner.focus.setHoveredNode(node)\n },\n [node, isRootNode],\n )\n const handleParentOnMouseLeave = useCallback(\n (e: ChangeEvent<unknown>) => {\n if (isRootNode) return\n Besigner.focus.clearHover()\n },\n [isRootNode],\n )\n\n const copyElements = useCopyElementsCallback()\n const pasteElements = usePasteElementsCallback()\n const handleCopyClick = useCallback(() => {\n if (isRootNode) return\n onAction?.()\n copyElements(multi ? Besigner.focus.getSelected() : [node])\n }, [node, isRootNode, multi, onAction, copyElements])\n\n const handlePasteClick = useCallback(() => {\n onAction?.()\n pasteElements(node)\n }, [node, onAction, pasteElements])\n\n // Dismiss FIRST, then open (AGL-3208). The dialog is no longer a child of\n // this menu — `SubtreeJsonDialogHost` holds it — so the menu closing can\n // no longer take the editor with it, and leaving the menu standing behind\n // a 95vw dialog only leaves something to click away onto.\n const handleEditJsonClick = useCallback(() => {\n onAction?.()\n openSubtreeJson(node)\n }, [node, onAction])\n\n // Observed, so the item enables the moment something is copied — even\n // from another document, where the entry arrives via localStorage.\n const canPaste = Besigner.clipboard.hasContent()\n const clipboardLabels = Besigner.clipboard.getLabels()\n\n /**\n * Start hidden until an interaction shows it (AGL-592).\n *\n * A DIFFERENT switch from the eye on the hierarchy row, and the naming is\n * the whole point. The eye hides an element outright — `display: none`,\n * nothing reveals it. This one enrols the element in a runtime contract:\n * it starts hidden, an interaction's show step reveals it, and the canvas\n * opens it while it is being designed. A mega-menu panel, a drawer, an\n * announcement that appears on scroll.\n *\n * `aglyn-hidden` is the storage — the published stylesheet, the show/hide\n * steps and the canvas reveal all key off it — and until this existed the\n * only way to set it was to know the literal string and type it into the\n * Classes box. An element property with no picker is a missing feature,\n * not a power-user path.\n */\n const [, setRevealedNodeIds] = useAglynBesignerFlag('revealedNodeIds')\n const hiddenOnSite = isNodeHiddenOnSite(node as never)\n const handleToggleHiddenClick = useCallback(() => {\n if (isRootNode) return\n onAction?.()\n const targets = multi ? Besigner.focus.getSelected() : [node]\n const changed: string[] = []\n action(() => {\n for (const target of targets) {\n if (!target || canvas.isRootNode(target)) continue\n const props = nodePropsWithHiddenOnSite(target as never, !hiddenOnSite)\n if (!props) continue\n target.props = props as never\n changed.push(target.$id)\n }\n })()\n // Showing an element again retires its canvas reveal with it. The flag\n // is only meaningful for something the site hides, so leaving an entry\n // behind means the next hide silently starts revealed. Hiding sets\n // nothing: hidden is hidden, and selecting the element — which\n // whichever surface opened this menu has already done — is what shows\n // it while it is being designed.\n if (hiddenOnSite && changed.length) {\n setRevealedNodeIds((current) =>\n (current ?? []).filter((id) => !changed.includes(id)),\n )\n }\n }, [node, isRootNode, multi, hiddenOnSite, onAction, setRevealedNodeIds])\n\n /**\n * Copy and paste a LOOK.\n *\n * `node.sx` — the Styles panel's whole output, including its responsive,\n * `@scheme` and state slices, which are keys inside that object. Classes\n * are deliberately not carried: a class is a name pointing at rules the\n * element does not own, and two of them carry behaviour rather than\n * appearance, so moving them under a label that promises looks would move\n * behaviour with it.\n *\n * Paste REPLACES. Merging makes the result depend on what the target\n * already had, so the same look pasted onto two elements could produce\n * two different ones — and there would be no way to paste \"no styles\".\n */\n const copiedStyleLabel = Besigner.styleClipboard.getStyleLabel()\n const canPasteStyles = Besigner.styleClipboard.hasStyles()\n const handleCopyStyles = useCallback(() => {\n if (isRootNode) return\n onAction?.()\n Besigner.styleClipboard.copyStyles(node)\n }, [node, isRootNode, onAction])\n const handlePasteStyles = useCallback(() => {\n if (isRootNode) return\n onAction?.()\n const targets = multi ? Besigner.focus.getSelected() : [node]\n for (const target of targets) {\n if (target && !canvas.isRootNode(target)) {\n Besigner.styleClipboard.pasteStyles(target)\n }\n }\n }, [node, isRootNode, multi, onAction])\n\n const deleteElementCallback = useDeleteElementCallback()\n const deleteElementsCallback = useDeleteElementsCallback()\n const handleDeleteClick = useCallback(() => {\n closeMore()\n onAction?.()\n if (multi) void deleteElementsCallback(Besigner.focus.getSelected())\n else void deleteElementCallback(node)\n }, [\n node,\n multi,\n closeMore,\n onAction,\n deleteElementCallback,\n deleteElementsCallback,\n ])\n\n return (\n <Paper\n ref={ref}\n sx={{\n width: 240,\n // Caps itself rather than growing past the window (AGL-1405). The\n // Popper can only slide a menu back inside the viewport if it FITS\n // in one; a taller menu was laid out past the bottom of the\n // document and the page grew a scrollbar around it. `dvh` so a\n // mobile browser's retracting toolbar does not leave the last item\n // under it.\n // Shorter than the window, not merely within it. A menu that only\n // just fits is one `preventOverflow` has to slide a long way to\n // place, and a menu that lands 200px from where it was asked for\n // reads as landing at random.\n maxHeight: 'min(420px, calc(100dvh - 24px))',\n overflowY: 'auto',\n overflowX: 'hidden',\n }}\n {...rest}\n >\n <MenuList dense>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n component=\"div\"\n sx={{\n px: 1,\n py: 0.15,\n mb: 1,\n textAlign: 'center',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n backgroundColor: (theme) =>\n `rgba(${(theme as any).vars.palette.primary.darkChannel} / 0.12)`,\n }}\n >\n {node?.labelShort}\n </Typography>\n {multi ? null : (\n <MenuItem\n onClick={() => {\n onAction?.()\n handleAddElementClick(node)\n }}\n >\n <ListItemText inset>Add element</ListItemText>\n </MenuItem>\n )}\n {multi ? null : <Divider />}\n <MenuItem\n onClick={handleParentOnClick}\n disabled={isRootNode || multi}\n onMouseEnter={handleParentOnMouseEnter}\n onPointerEnter={handleParentOnMouseEnter}\n onMouseLeave={handleParentOnMouseLeave}\n onPointerLeave={handleParentOnMouseLeave}\n >\n <ListItemText inset>Select parent</ListItemText>\n </MenuItem>\n <MenuItem\n onClick={handleMoveUp}\n disabled={isRootNode || multi || !(node?.index > 0)}\n >\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_MOVE_UP.path}\n />\n </ListItemIcon>\n <ListItemText>Shift up</ListItemText>\n </MenuItem>\n <MenuItem\n onClick={handleMoveDown}\n disabled={\n isRootNode ||\n multi ||\n !(node?.index < node?.parent?.nodes?.length - 1)\n }\n >\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_MOVE_DOWN.path}\n />\n </ListItemIcon>\n <ListItemText>Shift down</ListItemText>\n </MenuItem>\n <MenuItem onClick={handleMoveOut} disabled={!canMoveOut}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_MOVE_OUT.path}\n />\n </ListItemIcon>\n <ListItemText>Move out of container</ListItemText>\n </MenuItem>\n <MenuItem onClick={handleMoveIn} disabled={!canMoveIn}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_MOVE_IN.path}\n />\n </ListItemIcon>\n <ListItemText>Move into element above</ListItemText>\n </MenuItem>\n {multi ? null : (\n <MenuItem onClick={handleEditJsonClick}>\n <ListItemText inset>Edit JSON</ListItemText>\n </MenuItem>\n )}\n <MenuItem disabled={isRootNode} onClick={handleToggleHiddenClick}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={\n hiddenOnSite\n ? ICON_VARIANT_VISIBILITY_SHOWN.path\n : ICON_VARIANT_VISIBILITY_HIDDEN.path\n }\n />\n </ListItemIcon>\n <ListItemText\n secondary={\n hiddenOnSite\n ? 'It will be on the page from the first paint'\n : 'For a menu panel or drawer. To hide it outright, use the eye on its Hierarchy row'\n }\n slotProps={{ secondary: { sx: { whiteSpace: 'normal' } } }}\n >\n {hiddenOnSite\n ? 'Do not start hidden'\n : 'Start hidden until an interaction shows it'}\n </ListItemText>\n </MenuItem>\n <Divider />\n <MenuItem disabled={isRootNode} onClick={handleCopyClick}>\n <ListItemIcon>\n <MdiIcon fontSize=\"inherit\" path={ICON_VARIANT_MODIFY_COPY.path} />\n </ListItemIcon>\n <ListItemText>{multi ? 'Copy selection' : 'Copy'}</ListItemText>\n </MenuItem>\n <MenuItem disabled={isRootNode} onClick={handleCopyStyles}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_COPY.path}\n />\n </ListItemIcon>\n <ListItemText>{'Copy styles'}</ListItemText>\n </MenuItem>\n <MenuItem\n disabled={isRootNode || !canPasteStyles}\n onClick={handlePasteStyles}\n >\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_PASTE.path}\n />\n </ListItemIcon>\n <ListItemText\n slotProps={{\n primary: {\n sx: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n },\n },\n }}\n >\n {copiedStyleLabel\n ? `Paste styles from ${copiedStyleLabel}`\n : 'Paste styles'}\n </ListItemText>\n </MenuItem>\n <Divider />\n <MenuItem disabled={!canPaste} onClick={handlePasteClick}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_PASTE.path}\n />\n </ListItemIcon>\n <ListItemText\n slotProps={{\n primary: {\n sx: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n },\n },\n }}\n >\n {clipboardLabels.length === 1\n ? `Paste ${clipboardLabels[0]}`\n : clipboardLabels.length > 1\n ? `Paste ${clipboardLabels.length} elements`\n : 'Paste'}\n </ListItemText>\n </MenuItem>\n <Divider />\n <MenuItem disabled={isRootNode} onClick={handleDuplicateClick}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_DUPLICATE.path}\n />\n </ListItemIcon>\n <ListItemText>\n {multi ? 'Duplicate selection' : 'Duplicate'}\n </ListItemText>\n </MenuItem>\n <MenuItem disabled={isRootNode} onClick={handleDeleteClick}>\n <ListItemIcon>\n <MdiIcon\n fontSize=\"inherit\"\n path={ICON_VARIANT_MODIFY_DELETE.path}\n />\n </ListItemIcon>\n <ListItemText>{multi ? 'Delete selection' : 'Delete'}</ListItemText>\n </MenuItem>\n </MenuList>\n </Paper>\n )\n }),\n)\nNodeContextMenu.displayName = 'NodeContextMenu'\n\nexport default NodeContextMenu\n"],"names":["canvas","Besigner","BesignerPanelTabFlag","setBesignerPanels","ICON_VARIANT_MODIFY_COPY","ICON_VARIANT_MODIFY_DELETE","ICON_VARIANT_MODIFY_DUPLICATE","ICON_VARIANT_MODIFY_MOVE_DOWN","ICON_VARIANT_MODIFY_MOVE_IN","ICON_VARIANT_MODIFY_MOVE_OUT","ICON_VARIANT_MODIFY_MOVE_UP","ICON_VARIANT_MODIFY_PASTE","ICON_VARIANT_VISIBILITY_HIDDEN","ICON_VARIANT_VISIBILITY_SHOWN","MdiIcon","Divider","ListItemIcon","ListItemText","MenuItem","MenuList","Paper","Typography","action","observer","forwardRef","useCallback","useState","useAglynBesignerFlag","useAddElementDrawerCallback","useBesignerAppContext","useCopyElementsCallback","usePasteElementsCallback","useDeleteElementCallback","useDeleteElementsCallback","useMoveNodeInCallback","useMoveNodeOutCallback","isNodeHiddenOnSite","nodePropsWithHiddenOnSite","openSubtreeJson","NodeContextMenu","props","ref","node","onAction","rest","isRootNode","multi","focus","hasMultipleSelected","app","handleAddElementClick","elementRef","refs","get","$id","moreOpen","setMoreOpen","moreButton","moreButtonRef","closeMore","openMore","handleDuplicateClick","e","targets","getSelected","target","duplicateNode","handleModifyClick","panels","panelRight","toggled","tab","ELEMENT_PROPS_FORM","handleMoveUp","reorderNode","index","handleMoveDown","moveNodeOut","moveNodeIn","canMoveOut","canMoveNodeOut","canMoveIn","canMoveNodeIn","handleMoveOut","handleMoveIn","handleParentOnClick","setSelectedNode","parent","handleParentOnMouseEnter","setHoveredNode","handleParentOnMouseLeave","clearHover","copyElements","pasteElements","handleCopyClick","handlePasteClick","handleEditJsonClick","canPaste","clipboard","hasContent","clipboardLabels","getLabels","setRevealedNodeIds","hiddenOnSite","handleToggleHiddenClick","changed","push","length","current","filter","id","includes","copiedStyleLabel","styleClipboard","getStyleLabel","canPasteStyles","hasStyles","handleCopyStyles","copyStyles","handlePasteStyles","pasteStyles","deleteElementCallback","deleteElementsCallback","handleDeleteClick","sx","width","maxHeight","overflowY","overflowX","dense","variant","color","component","px","py","mb","textAlign","textOverflow","overflow","whiteSpace","backgroundColor","theme","vars","palette","primary","darkChannel","labelShort","onClick","inset","disabled","onMouseEnter","onPointerEnter","onMouseLeave","onPointerLeave","fontSize","path","nodes","secondary","slotProps","displayName"],"mappings":"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"}
|
|
@@ -43,4 +43,15 @@ export declare function SubtreeJsonDialog(props: SubtreeJsonDialogProps): import
|
|
|
43
43
|
export declare namespace SubtreeJsonDialog {
|
|
44
44
|
var displayName: string;
|
|
45
45
|
}
|
|
46
|
+
/** Open the subtree editor on `node`. Safe to call as the menu dismisses. */
|
|
47
|
+
export declare const openSubtreeJson: (node: Aglyn.NodeSchema<any>) => void;
|
|
48
|
+
/** Close the subtree editor, whatever opened it. */
|
|
49
|
+
export declare const closeSubtreeJson: () => void;
|
|
50
|
+
/**
|
|
51
|
+
* The single mount for the subtree editor, rendered once per besigner surface
|
|
52
|
+
* by `BesignerRootProviderComponent` (AGL-3208).
|
|
53
|
+
*/
|
|
54
|
+
export declare const SubtreeJsonDialogHost: (() => import("react").JSX.Element) & {
|
|
55
|
+
displayName: string;
|
|
56
|
+
};
|
|
46
57
|
export default SubtreeJsonDialog;
|
|
@@ -17,8 +17,9 @@
|
|
|
17
17
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
18
|
import { canvas, components } from "@aglyn/aglyn";
|
|
19
19
|
import { JsonEditor } from "@aglyn/shared-ui-json-editor";
|
|
20
|
-
import { toJS } from "mobx";
|
|
21
|
-
import {
|
|
20
|
+
import { action, observable, toJS } from "mobx";
|
|
21
|
+
import { observer } from "mobx-react-lite";
|
|
22
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
22
23
|
/**
|
|
23
24
|
* Validates a nested subtree before it replaces canvas content
|
|
24
25
|
* (AGL-338): every node needs a resolvable componentId and ids must be
|
|
@@ -120,6 +121,44 @@ const mintMissingIds = (item)=>{
|
|
|
120
121
|
});
|
|
121
122
|
}
|
|
122
123
|
SubtreeJsonDialog.displayName = 'SubtreeJsonDialog';
|
|
124
|
+
/**
|
|
125
|
+
* The element being edited, held ABOVE the menu that opens it (AGL-3208).
|
|
126
|
+
*
|
|
127
|
+
* This dialog used to be rendered inside `NodeContextMenu`'s own `Paper`,
|
|
128
|
+
* which made it live exactly as long as that menu. Both hosts of the menu end
|
|
129
|
+
* it on the first interaction with anything else: the Hierarchy panel wraps it
|
|
130
|
+
* in a `ClickAwayListener`, and the canvas overlay hands it to a `Tooltip` as
|
|
131
|
+
* its title. A MUI dialog is portalled to `document.body`, so a click inside
|
|
132
|
+
* it IS "away" from the listener, and a pointer entering it HAS left the
|
|
133
|
+
* tooltip's anchor. Opening the editor and then touching it dismissed the
|
|
134
|
+
* menu, unmounted this component with it, and read as the dialog closing
|
|
135
|
+
* itself — the reported "says loading then auto closes", on top of a Monaco
|
|
136
|
+
* that could not load at all.
|
|
137
|
+
*
|
|
138
|
+
* A module-scoped box rather than a context: the two menus are rendered by
|
|
139
|
+
* different trees, and what they need to share is one piece of state that
|
|
140
|
+
* outlives both.
|
|
141
|
+
*/ const editing = observable.box(null, {
|
|
142
|
+
deep: false
|
|
143
|
+
});
|
|
144
|
+
/** Open the subtree editor on `node`. Safe to call as the menu dismisses. */ export const openSubtreeJson = action('openSubtreeJson', (node)=>editing.set(node));
|
|
145
|
+
/** Close the subtree editor, whatever opened it. */ export const closeSubtreeJson = action('closeSubtreeJson', ()=>editing.set(null));
|
|
146
|
+
/**
|
|
147
|
+
* The single mount for the subtree editor, rendered once per besigner surface
|
|
148
|
+
* by `BesignerRootProviderComponent` (AGL-3208).
|
|
149
|
+
*/ export const SubtreeJsonDialogHost = observer(()=>{
|
|
150
|
+
const node = editing.get();
|
|
151
|
+
// The node is kept for the close transition: clearing the box and the
|
|
152
|
+
// content in the same frame empties the dialog while it is still on screen.
|
|
153
|
+
const shown = useRef(null);
|
|
154
|
+
if (node) shown.current = node;
|
|
155
|
+
return /*#__PURE__*/ _jsx(SubtreeJsonDialog, {
|
|
156
|
+
node: node != null ? node : shown.current,
|
|
157
|
+
open: Boolean(node),
|
|
158
|
+
onClose: closeSubtreeJson
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
SubtreeJsonDialogHost.displayName = 'SubtreeJsonDialogHost';
|
|
123
162
|
export default SubtreeJsonDialog;
|
|
124
163
|
|
|
125
164
|
//# sourceMappingURL=subtree-json-dialog.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/subtree-json-dialog.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type * as Aglyn from '@aglyn/aglyn'\nimport { canvas, components } from '@aglyn/aglyn'\nimport { JsonEditor } from '@aglyn/shared-ui-json-editor'\nimport { toJS } from 'mobx'\nimport { useCallback, useMemo } from 'react'\n\nexport interface SubtreeJsonDialogProps {\n node?: Aglyn.NodeSchema<any> | null\n open: boolean\n onClose: () => void\n}\n\ntype NestedNode = {\n $id?: string\n componentId?: string\n nodes?: NestedNode[]\n [key: string]: unknown\n}\n\n/**\n * Validates a nested subtree before it replaces canvas content\n * (AGL-338): every node needs a resolvable componentId and ids must be\n * unique within the subtree (missing ids get minted).\n */\nexport function validateSubtree(root: NestedNode): string | null {\n const seen = new Set<string>()\n const walk = (item: NestedNode, path: string): string | null => {\n if (typeof item !== 'object' || item === null || Array.isArray(item)) {\n return `${path}: each node must be a JSON object`\n }\n if (!item.componentId || typeof item.componentId !== 'string') {\n return `${path}: missing componentId`\n }\n if (!components.getFactory(item.componentId as any)) {\n return `${path}: unknown component \"${item.componentId}\"`\n }\n if (item.$id) {\n if (seen.has(item.$id)) return `${path}: duplicate node id \"${item.$id}\"`\n seen.add(item.$id)\n }\n const children = Array.isArray(item.nodes) ? item.nodes : []\n for (let i = 0; i < children.length; i += 1) {\n const problem = walk(children[i] as NestedNode, `${path}.nodes[${i}]`)\n if (problem) return problem\n }\n return null\n }\n return walk(root, '$')\n}\n\nconst mintMissingIds = (item: NestedNode): void => {\n if (!item.$id) item.$id = canvas.createNodeId()\n for (const child of Array.isArray(item.nodes) ? item.nodes : []) {\n mintMissingIds(child as NestedNode)\n }\n}\n\n/** Node ids of the subtree rooted at `nodeId` in a flat NodesMap. */\nconst collectSubtreeIds = (\n map: Record<string, Aglyn.NodeSchema<any>>,\n nodeId: string,\n out: string[] = [],\n): string[] => {\n out.push(nodeId)\n const children = (map[nodeId]?.nodes ?? []) as string[]\n for (const childId of children) {\n if (typeof childId === 'string' && map[childId]) {\n collectSubtreeIds(map, childId, out)\n }\n }\n return out\n}\n\n/** The parsed draft with the root's identity pinned back on (AGL-338). */\nconst withRootIdentity = (\n value: unknown,\n node: Aglyn.NodeSchema<any>,\n): NestedNode => {\n const parsed = structuredClone(value) as NestedNode\n // The root keeps its identity — the parent's child list references it.\n parsed.$id = node.$id\n parsed['parentId'] = node.parentId\n return parsed\n}\n\n/**\n * Edit the JSON of a single element and its children (AGL-338), instead\n * of the whole screen document — through the SAME editor as the Edit\n * menu's raw JSON dialog (AGL-457). Save validates, keeps the node's\n * identity (so the parent's child list stays intact), and replaces the\n * subtree in one undoable step.\n */\nexport function SubtreeJsonDialog(props: SubtreeJsonDialogProps) {\n const { node, open, onClose } = props\n\n const nested = useMemo(\n () => (open && node ? canvas.makeNested(node as any) : undefined),\n [open, node],\n )\n\n const handleValidate = useCallback(\n (value: unknown) => {\n if (!node) return 'No element selected'\n return validateSubtree(withRootIdentity(value, node))\n },\n [node],\n )\n\n const handleSave = useCallback(\n (_event: unknown, value: unknown) => {\n if (!node) return\n const parsed = withRootIdentity(value, node)\n mintMissingIds(parsed)\n\n // Full-map rebuild: drop the old subtree's descendants, splice in the\n // new flat nodes, and apply as one undoable replacement.\n const map = {\n ...(toJS(canvas.toJSON().nodes) as Record<\n string,\n Aglyn.NodeSchema<any>\n >),\n }\n for (const staleId of collectSubtreeIds(map, node.$id)) {\n delete map[staleId]\n }\n const flat = (canvas.constructor as any).denormalizeNodes(\n [parsed],\n node.parentId!,\n {},\n )\n Object.assign(map, flat)\n canvas.applyNodes(map as any)\n },\n [node],\n )\n\n return (\n <JsonEditor\n open={open}\n title=\"Edit element JSON\"\n description={\n 'This element and its children only — the rest of the screen is ' +\n 'untouched. Save replaces the subtree (undo restores it).'\n }\n defaultValue={nested as any}\n validate={handleValidate}\n onSave={handleSave}\n onClose={onClose}\n />\n )\n}\nSubtreeJsonDialog.displayName = 'SubtreeJsonDialog'\n\nexport default SubtreeJsonDialog\n"],"names":["canvas","components","JsonEditor","toJS","useCallback","useMemo","validateSubtree","root","seen","Set","walk","item","path","Array","isArray","componentId","getFactory","$id","has","add","children","nodes","i","length","problem","mintMissingIds","createNodeId","child","collectSubtreeIds","map","nodeId","out","push","childId","withRootIdentity","value","node","parsed","structuredClone","parentId","SubtreeJsonDialog","props","open","onClose","nested","makeNested","undefined","handleValidate","handleSave","_event","toJSON","staleId","flat","denormalizeNodes","Object","assign","applyNodes","title","description","defaultValue","validate","onSave","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/subtree-json-dialog.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type * as Aglyn from '@aglyn/aglyn'\nimport { canvas, components } from '@aglyn/aglyn'\nimport { JsonEditor } from '@aglyn/shared-ui-json-editor'\nimport { action, observable, toJS } from 'mobx'\nimport { observer } from 'mobx-react-lite'\nimport { useCallback, useMemo, useRef } from 'react'\n\nexport interface SubtreeJsonDialogProps {\n node?: Aglyn.NodeSchema<any> | null\n open: boolean\n onClose: () => void\n}\n\ntype NestedNode = {\n $id?: string\n componentId?: string\n nodes?: NestedNode[]\n [key: string]: unknown\n}\n\n/**\n * Validates a nested subtree before it replaces canvas content\n * (AGL-338): every node needs a resolvable componentId and ids must be\n * unique within the subtree (missing ids get minted).\n */\nexport function validateSubtree(root: NestedNode): string | null {\n const seen = new Set<string>()\n const walk = (item: NestedNode, path: string): string | null => {\n if (typeof item !== 'object' || item === null || Array.isArray(item)) {\n return `${path}: each node must be a JSON object`\n }\n if (!item.componentId || typeof item.componentId !== 'string') {\n return `${path}: missing componentId`\n }\n if (!components.getFactory(item.componentId as any)) {\n return `${path}: unknown component \"${item.componentId}\"`\n }\n if (item.$id) {\n if (seen.has(item.$id)) return `${path}: duplicate node id \"${item.$id}\"`\n seen.add(item.$id)\n }\n const children = Array.isArray(item.nodes) ? item.nodes : []\n for (let i = 0; i < children.length; i += 1) {\n const problem = walk(children[i] as NestedNode, `${path}.nodes[${i}]`)\n if (problem) return problem\n }\n return null\n }\n return walk(root, '$')\n}\n\nconst mintMissingIds = (item: NestedNode): void => {\n if (!item.$id) item.$id = canvas.createNodeId()\n for (const child of Array.isArray(item.nodes) ? item.nodes : []) {\n mintMissingIds(child as NestedNode)\n }\n}\n\n/** Node ids of the subtree rooted at `nodeId` in a flat NodesMap. */\nconst collectSubtreeIds = (\n map: Record<string, Aglyn.NodeSchema<any>>,\n nodeId: string,\n out: string[] = [],\n): string[] => {\n out.push(nodeId)\n const children = (map[nodeId]?.nodes ?? []) as string[]\n for (const childId of children) {\n if (typeof childId === 'string' && map[childId]) {\n collectSubtreeIds(map, childId, out)\n }\n }\n return out\n}\n\n/** The parsed draft with the root's identity pinned back on (AGL-338). */\nconst withRootIdentity = (\n value: unknown,\n node: Aglyn.NodeSchema<any>,\n): NestedNode => {\n const parsed = structuredClone(value) as NestedNode\n // The root keeps its identity — the parent's child list references it.\n parsed.$id = node.$id\n parsed['parentId'] = node.parentId\n return parsed\n}\n\n/**\n * Edit the JSON of a single element and its children (AGL-338), instead\n * of the whole screen document — through the SAME editor as the Edit\n * menu's raw JSON dialog (AGL-457). Save validates, keeps the node's\n * identity (so the parent's child list stays intact), and replaces the\n * subtree in one undoable step.\n */\nexport function SubtreeJsonDialog(props: SubtreeJsonDialogProps) {\n const { node, open, onClose } = props\n\n const nested = useMemo(\n () => (open && node ? canvas.makeNested(node as any) : undefined),\n [open, node],\n )\n\n const handleValidate = useCallback(\n (value: unknown) => {\n if (!node) return 'No element selected'\n return validateSubtree(withRootIdentity(value, node))\n },\n [node],\n )\n\n const handleSave = useCallback(\n (_event: unknown, value: unknown) => {\n if (!node) return\n const parsed = withRootIdentity(value, node)\n mintMissingIds(parsed)\n\n // Full-map rebuild: drop the old subtree's descendants, splice in the\n // new flat nodes, and apply as one undoable replacement.\n const map = {\n ...(toJS(canvas.toJSON().nodes) as Record<\n string,\n Aglyn.NodeSchema<any>\n >),\n }\n for (const staleId of collectSubtreeIds(map, node.$id)) {\n delete map[staleId]\n }\n const flat = (canvas.constructor as any).denormalizeNodes(\n [parsed],\n node.parentId!,\n {},\n )\n Object.assign(map, flat)\n canvas.applyNodes(map as any)\n },\n [node],\n )\n\n return (\n <JsonEditor\n open={open}\n title=\"Edit element JSON\"\n description={\n 'This element and its children only — the rest of the screen is ' +\n 'untouched. Save replaces the subtree (undo restores it).'\n }\n defaultValue={nested as any}\n validate={handleValidate}\n onSave={handleSave}\n onClose={onClose}\n />\n )\n}\nSubtreeJsonDialog.displayName = 'SubtreeJsonDialog'\n\n/**\n * The element being edited, held ABOVE the menu that opens it (AGL-3208).\n *\n * This dialog used to be rendered inside `NodeContextMenu`'s own `Paper`,\n * which made it live exactly as long as that menu. Both hosts of the menu end\n * it on the first interaction with anything else: the Hierarchy panel wraps it\n * in a `ClickAwayListener`, and the canvas overlay hands it to a `Tooltip` as\n * its title. A MUI dialog is portalled to `document.body`, so a click inside\n * it IS \"away\" from the listener, and a pointer entering it HAS left the\n * tooltip's anchor. Opening the editor and then touching it dismissed the\n * menu, unmounted this component with it, and read as the dialog closing\n * itself — the reported \"says loading then auto closes\", on top of a Monaco\n * that could not load at all.\n *\n * A module-scoped box rather than a context: the two menus are rendered by\n * different trees, and what they need to share is one piece of state that\n * outlives both.\n */\nconst editing = observable.box<Aglyn.NodeSchema<any> | null>(null, {\n deep: false,\n})\n\n/** Open the subtree editor on `node`. Safe to call as the menu dismisses. */\nexport const openSubtreeJson = action(\n 'openSubtreeJson',\n (node: Aglyn.NodeSchema<any>) => editing.set(node),\n)\n\n/** Close the subtree editor, whatever opened it. */\nexport const closeSubtreeJson = action('closeSubtreeJson', () =>\n editing.set(null),\n)\n\n/**\n * The single mount for the subtree editor, rendered once per besigner surface\n * by `BesignerRootProviderComponent` (AGL-3208).\n */\nexport const SubtreeJsonDialogHost = observer(() => {\n const node = editing.get()\n // The node is kept for the close transition: clearing the box and the\n // content in the same frame empties the dialog while it is still on screen.\n const shown = useRef<Aglyn.NodeSchema<any> | null>(null)\n if (node) shown.current = node\n return (\n <SubtreeJsonDialog\n node={node ?? shown.current}\n open={Boolean(node)}\n onClose={closeSubtreeJson}\n />\n )\n})\nSubtreeJsonDialogHost.displayName = 'SubtreeJsonDialogHost'\n\nexport default SubtreeJsonDialog\n"],"names":["canvas","components","JsonEditor","action","observable","toJS","observer","useCallback","useMemo","useRef","validateSubtree","root","seen","Set","walk","item","path","Array","isArray","componentId","getFactory","$id","has","add","children","nodes","i","length","problem","mintMissingIds","createNodeId","child","collectSubtreeIds","map","nodeId","out","push","childId","withRootIdentity","value","node","parsed","structuredClone","parentId","SubtreeJsonDialog","props","open","onClose","nested","makeNested","undefined","handleValidate","handleSave","_event","toJSON","staleId","flat","denormalizeNodes","Object","assign","applyNodes","title","description","defaultValue","validate","onSave","displayName","editing","box","deep","openSubtreeJson","set","closeSubtreeJson","SubtreeJsonDialogHost","get","shown","current","Boolean"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;;AAGD,SAASA,MAAM,EAAEC,UAAU,QAAQ,eAAc;AACjD,SAASC,UAAU,QAAQ,+BAA8B;AACzD,SAASC,MAAM,EAAEC,UAAU,EAAEC,IAAI,QAAQ,OAAM;AAC/C,SAASC,QAAQ,QAAQ,kBAAiB;AAC1C,SAASC,WAAW,EAAEC,OAAO,EAAEC,MAAM,QAAQ,QAAO;AAepD;;;;CAIC,GACD,OAAO,SAASC,gBAAgBC,IAAgB;IAC9C,MAAMC,OAAO,IAAIC;IACjB,MAAMC,OAAO,CAACC,MAAkBC;QAC9B,IAAI,OAAOD,SAAS,YAAYA,SAAS,QAAQE,MAAMC,OAAO,CAACH,OAAO;YACpE,OAAO,GAAGC,KAAK,iCAAiC,CAAC;QACnD;QACA,IAAI,CAACD,KAAKI,WAAW,IAAI,OAAOJ,KAAKI,WAAW,KAAK,UAAU;YAC7D,OAAO,GAAGH,KAAK,qBAAqB,CAAC;QACvC;QACA,IAAI,CAACf,WAAWmB,UAAU,CAACL,KAAKI,WAAW,GAAU;YACnD,OAAO,GAAGH,KAAK,qBAAqB,EAAED,KAAKI,WAAW,CAAC,CAAC,CAAC;QAC3D;QACA,IAAIJ,KAAKM,GAAG,EAAE;YACZ,IAAIT,KAAKU,GAAG,CAACP,KAAKM,GAAG,GAAG,OAAO,GAAGL,KAAK,qBAAqB,EAAED,KAAKM,GAAG,CAAC,CAAC,CAAC;YACzET,KAAKW,GAAG,CAACR,KAAKM,GAAG;QACnB;QACA,MAAMG,WAAWP,MAAMC,OAAO,CAACH,KAAKU,KAAK,IAAIV,KAAKU,KAAK,GAAG,EAAE;QAC5D,IAAK,IAAIC,IAAI,GAAGA,IAAIF,SAASG,MAAM,EAAED,KAAK,EAAG;YAC3C,MAAME,UAAUd,KAAKU,QAAQ,CAACE,EAAE,EAAgB,GAAGV,KAAK,OAAO,EAAEU,EAAE,CAAC,CAAC;YACrE,IAAIE,SAAS,OAAOA;QACtB;QACA,OAAO;IACT;IACA,OAAOd,KAAKH,MAAM;AACpB;AAEA,MAAMkB,iBAAiB,CAACd;IACtB,IAAI,CAACA,KAAKM,GAAG,EAAEN,KAAKM,GAAG,GAAGrB,OAAO8B,YAAY;IAC7C,KAAK,MAAMC,SAASd,MAAMC,OAAO,CAACH,KAAKU,KAAK,IAAIV,KAAKU,KAAK,GAAG,EAAE,CAAE;QAC/DI,eAAeE;IACjB;AACF;AAEA,mEAAmE,GACnE,MAAMC,oBAAoB,CACxBC,KACAC,QACAC,MAAgB,EAAE;;QAGAF;IADlBE,IAAIC,IAAI,CAACF;IACT,MAAMV,oBAAYS,cAAAA,GAAG,CAACC,OAAO,qBAAXD,YAAaR,KAAK,mBAAI,EAAE;IAC1C,KAAK,MAAMY,WAAWb,SAAU;QAC9B,IAAI,OAAOa,YAAY,YAAYJ,GAAG,CAACI,QAAQ,EAAE;YAC/CL,kBAAkBC,KAAKI,SAASF;QAClC;IACF;IACA,OAAOA;AACT;AAEA,wEAAwE,GACxE,MAAMG,mBAAmB,CACvBC,OACAC;IAEA,MAAMC,SAASC,gBAAgBH;IAC/B,uEAAuE;IACvEE,OAAOpB,GAAG,GAAGmB,KAAKnB,GAAG;IACrBoB,MAAM,CAAC,WAAW,GAAGD,KAAKG,QAAQ;IAClC,OAAOF;AACT;AAEA;;;;;;CAMC,GACD,OAAO,SAASG,kBAAkBC,KAA6B;IAC7D,MAAM,EAAEL,IAAI,EAAEM,IAAI,EAAEC,OAAO,EAAE,GAAGF;IAEhC,MAAMG,SAASxC,QACb,IAAOsC,QAAQN,OAAOxC,OAAOiD,UAAU,CAACT,QAAeU,WACvD;QAACJ;QAAMN;KAAK;IAGd,MAAMW,iBAAiB5C,YACrB,CAACgC;QACC,IAAI,CAACC,MAAM,OAAO;QAClB,OAAO9B,gBAAgB4B,iBAAiBC,OAAOC;IACjD,GACA;QAACA;KAAK;IAGR,MAAMY,aAAa7C,YACjB,CAAC8C,QAAiBd;QAChB,IAAI,CAACC,MAAM;QACX,MAAMC,SAASH,iBAAiBC,OAAOC;QACvCX,eAAeY;QAEf,sEAAsE;QACtE,yDAAyD;QACzD,MAAMR,MAAM,aACN5B,KAAKL,OAAOsD,MAAM,GAAG7B,KAAK;QAKhC,KAAK,MAAM8B,WAAWvB,kBAAkBC,KAAKO,KAAKnB,GAAG,EAAG;YACtD,OAAOY,GAAG,CAACsB,QAAQ;QACrB;QACA,MAAMC,OAAO,AAACxD,OAAO,WAAW,CAASyD,gBAAgB,CACvD;YAAChB;SAAO,EACRD,KAAKG,QAAQ,EACb,CAAC;QAEHe,OAAOC,MAAM,CAAC1B,KAAKuB;QACnBxD,OAAO4D,UAAU,CAAC3B;IACpB,GACA;QAACO;KAAK;IAGR,qBACE,KAACtC;QACC4C,MAAMA;QACNe,OAAM;QACNC,aACE,oEACA;QAEFC,cAAcf;QACdgB,UAAUb;QACVc,QAAQb;QACRL,SAASA;;AAGf;AACAH,kBAAkBsB,WAAW,GAAG;AAEhC;;;;;;;;;;;;;;;;;CAiBC,GACD,MAAMC,UAAU/D,WAAWgE,GAAG,CAA+B,MAAM;IACjEC,MAAM;AACR;AAEA,2EAA2E,GAC3E,OAAO,MAAMC,kBAAkBnE,OAC7B,mBACA,CAACqC,OAAgC2B,QAAQI,GAAG,CAAC/B,OAC9C;AAED,kDAAkD,GAClD,OAAO,MAAMgC,mBAAmBrE,OAAO,oBAAoB,IACzDgE,QAAQI,GAAG,CAAC,OACb;AAED;;;CAGC,GACD,OAAO,MAAME,wBAAwBnE,SAAS;IAC5C,MAAMkC,OAAO2B,QAAQO,GAAG;IACxB,sEAAsE;IACtE,4EAA4E;IAC5E,MAAMC,QAAQlE,OAAqC;IACnD,IAAI+B,MAAMmC,MAAMC,OAAO,GAAGpC;IAC1B,qBACE,KAACI;QACCJ,IAAI,EAAEA,eAAAA,OAAQmC,MAAMC,OAAO;QAC3B9B,MAAM+B,QAAQrC;QACdO,SAASyB;;AAGf,GAAE;AACFC,sBAAsBP,WAAW,GAAG;AAEpC,eAAetB,kBAAiB"}
|