@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/besigner-ui",
3
- "version": "1.0.0-beta.145",
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.145",
29
- "@aglyn/aglyn-markdown-editor": "1.0.0-beta.145",
30
- "@aglyn/aglyn-node-renderer": "1.0.0-beta.145",
31
- "@aglyn/besigner": "1.0.0-beta.145",
32
- "@aglyn/shared-data-enums": "1.0.0-beta.145",
33
- "@aglyn/shared-data-mdi": "1.0.0-beta.145",
34
- "@aglyn/shared-data-types": "1.0.0-beta.145",
35
- "@aglyn/shared-svg-icons": "1.0.0-beta.145",
36
- "@aglyn/shared-ui-json-editor": "1.0.0-beta.145",
37
- "@aglyn/shared-ui-jsx": "1.0.0-beta.145",
38
- "@aglyn/shared-ui-jsx-forms": "1.0.0-beta.145",
39
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.145",
40
- "@aglyn/shared-ui-theme": "1.0.0-beta.145",
41
- "@aglyn/shared-util-dom": "1.0.0-beta.145",
42
- "@aglyn/shared-util-tools": "1.0.0-beta.145",
43
- "@aglyn/shared-util-vendor": "1.0.0-beta.145",
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__*/ _jsx(ComponentsDrawerContextProvider, {
57
- children: 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;AAQjE,OAAO,MAAMC,sBAAsB,CAAKC;IACtC,MAAMC,cAAcX,eAAeU;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;IACzEV,qBAAqBW,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,QAAQZ,QAAQC;IAEhC,uEAAuE;IACvE,uEAAuE;IACvE,2BAA2B;IAC3BI;IAEA,qBACE,KAACY;kBACC,cAAA,KAACb;YAAoBS,SAASA;sBAC5B,cAAA,KAACP;0BACC,cAAA,KAACH;8BACC,cAAA,KAACD;kCACEc;;;;;;AAOf,EAAC;AAEDD,8BAA8BN,WAAW,GAAG;AAC5CM,8BAA8BG,KAAK,GAAG;AAEtC,eAAeH,8BAA6B"}
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 SubtreeJsonDialog from "./subtree-json-dialog.component.js";
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__*/ _jsxs(Paper, _extends({
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
- /*#__PURE__*/ _jsxs(MenuList, {
300
- dense: true,
301
- children: [
302
- /*#__PURE__*/ _jsx(Typography, {
303
- variant: "caption",
304
- color: "text.secondary",
305
- component: "div",
306
- sx: {
307
- px: 1,
308
- py: 0.15,
309
- mb: 1,
310
- textAlign: 'center',
311
- textOverflow: 'ellipsis',
312
- overflow: 'hidden',
313
- whiteSpace: 'nowrap',
314
- backgroundColor: (theme)=>`rgba(${theme.vars.palette.primary.darkChannel} / 0.12)`
315
- },
316
- children: node == null ? void 0 : node.labelShort
317
- }),
318
- multi ? null : /*#__PURE__*/ _jsx(MenuItem, {
319
- onClick: ()=>{
320
- onAction == null ? void 0 : onAction();
321
- handleAddElementClick(node);
322
- },
323
- children: /*#__PURE__*/ _jsx(ListItemText, {
324
- inset: true,
325
- children: "Add element"
326
- })
327
- }),
328
- multi ? null : /*#__PURE__*/ _jsx(Divider, {}),
329
- /*#__PURE__*/ _jsx(MenuItem, {
330
- onClick: handleParentOnClick,
331
- disabled: isRootNode || multi,
332
- onMouseEnter: handleParentOnMouseEnter,
333
- onPointerEnter: handleParentOnMouseEnter,
334
- onMouseLeave: handleParentOnMouseLeave,
335
- onPointerLeave: handleParentOnMouseLeave,
336
- children: /*#__PURE__*/ _jsx(ListItemText, {
337
- inset: true,
338
- children: "Select parent"
339
- })
340
- }),
341
- /*#__PURE__*/ _jsxs(MenuItem, {
342
- onClick: handleMoveUp,
343
- disabled: isRootNode || multi || !((node == null ? void 0 : node.index) > 0),
344
- children: [
345
- /*#__PURE__*/ _jsx(ListItemIcon, {
346
- children: /*#__PURE__*/ _jsx(MdiIcon, {
347
- fontSize: "inherit",
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
- /*#__PURE__*/ _jsxs(MenuItem, {
357
- onClick: handleMoveDown,
358
- 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),
359
- children: [
360
- /*#__PURE__*/ _jsx(ListItemIcon, {
361
- children: /*#__PURE__*/ _jsx(MdiIcon, {
362
- fontSize: "inherit",
363
- path: ICON_VARIANT_MODIFY_MOVE_DOWN.path
364
- })
365
- }),
366
- /*#__PURE__*/ _jsx(ListItemText, {
367
- children: "Shift down"
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
- /*#__PURE__*/ _jsxs(MenuItem, {
372
- onClick: handleMoveOut,
373
- disabled: !canMoveOut,
374
- children: [
375
- /*#__PURE__*/ _jsx(ListItemIcon, {
376
- children: /*#__PURE__*/ _jsx(MdiIcon, {
377
- fontSize: "inherit",
378
- path: ICON_VARIANT_MODIFY_MOVE_OUT.path
379
- })
380
- }),
381
- /*#__PURE__*/ _jsx(ListItemText, {
382
- children: "Move out of container"
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
- /*#__PURE__*/ _jsxs(MenuItem, {
387
- onClick: handleMoveIn,
388
- disabled: !canMoveIn,
389
- children: [
390
- /*#__PURE__*/ _jsx(ListItemIcon, {
391
- children: /*#__PURE__*/ _jsx(MdiIcon, {
392
- fontSize: "inherit",
393
- path: ICON_VARIANT_MODIFY_MOVE_IN.path
394
- })
395
- }),
396
- /*#__PURE__*/ _jsx(ListItemText, {
397
- children: "Move into element above"
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
- multi ? null : /*#__PURE__*/ _jsx(MenuItem, {
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
- /*#__PURE__*/ _jsxs(MenuItem, {
409
- disabled: isRootNode,
410
- onClick: handleToggleHiddenClick,
411
- children: [
412
- /*#__PURE__*/ _jsx(ListItemIcon, {
413
- children: /*#__PURE__*/ _jsx(MdiIcon, {
414
- fontSize: "inherit",
415
- path: hiddenOnSite ? ICON_VARIANT_VISIBILITY_SHOWN.path : ICON_VARIANT_VISIBILITY_HIDDEN.path
416
- })
417
- }),
418
- /*#__PURE__*/ _jsx(ListItemText, {
419
- 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',
420
- slotProps: {
421
- secondary: {
422
- sx: {
423
- whiteSpace: 'normal'
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
- children: hiddenOnSite ? 'Do not start hidden' : 'Start hidden until an interaction shows it'
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
- /*#__PURE__*/ _jsx(Divider, {}),
432
- /*#__PURE__*/ _jsxs(MenuItem, {
433
- disabled: isRootNode,
434
- onClick: handleCopyClick,
435
- children: [
436
- /*#__PURE__*/ _jsx(ListItemIcon, {
437
- children: /*#__PURE__*/ _jsx(MdiIcon, {
438
- fontSize: "inherit",
439
- path: ICON_VARIANT_MODIFY_COPY.path
440
- })
441
- }),
442
- /*#__PURE__*/ _jsx(ListItemText, {
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
- /*#__PURE__*/ _jsxs(MenuItem, {
448
- disabled: isRootNode,
449
- onClick: handleCopyStyles,
450
- children: [
451
- /*#__PURE__*/ _jsx(ListItemIcon, {
452
- children: /*#__PURE__*/ _jsx(MdiIcon, {
453
- fontSize: "inherit",
454
- path: ICON_VARIANT_MODIFY_COPY.path
455
- })
456
- }),
457
- /*#__PURE__*/ _jsx(ListItemText, {
458
- children: 'Copy styles'
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
- /*#__PURE__*/ _jsxs(MenuItem, {
463
- disabled: isRootNode || !canPasteStyles,
464
- onClick: handlePasteStyles,
465
- children: [
466
- /*#__PURE__*/ _jsx(ListItemIcon, {
467
- children: /*#__PURE__*/ _jsx(MdiIcon, {
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
- children: copiedStyleLabel ? `Paste styles from ${copiedStyleLabel}` : 'Paste styles'
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
- /*#__PURE__*/ _jsx(Divider, {}),
487
- /*#__PURE__*/ _jsxs(MenuItem, {
488
- disabled: !canPaste,
489
- onClick: handlePasteClick,
490
- children: [
491
- /*#__PURE__*/ _jsx(ListItemIcon, {
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
- children: clipboardLabels.length === 1 ? `Paste ${clipboardLabels[0]}` : clipboardLabels.length > 1 ? `Paste ${clipboardLabels.length} elements` : 'Paste'
508
- })
509
- ]
510
- }),
511
- /*#__PURE__*/ _jsx(Divider, {}),
512
- /*#__PURE__*/ _jsxs(MenuItem, {
513
- disabled: isRootNode,
514
- onClick: handleDuplicateClick,
515
- children: [
516
- /*#__PURE__*/ _jsx(ListItemIcon, {
517
- children: /*#__PURE__*/ _jsx(MdiIcon, {
518
- fontSize: "inherit",
519
- path: ICON_VARIANT_MODIFY_DUPLICATE.path
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
- /*#__PURE__*/ _jsxs(MenuItem, {
528
- disabled: isRootNode,
529
- onClick: handleDeleteClick,
530
- children: [
531
- /*#__PURE__*/ _jsx(ListItemIcon, {
532
- children: /*#__PURE__*/ _jsx(MdiIcon, {
533
- fontSize: "inherit",
534
- path: ICON_VARIANT_MODIFY_DELETE.path
535
- })
536
- }),
537
- /*#__PURE__*/ _jsx(ListItemText, {
538
- children: multi ? 'Delete selection' : 'Delete'
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
- /*#__PURE__*/ _jsx(SubtreeJsonDialog, {
545
- node: node,
546
- open: jsonOpen,
547
- onClose: ()=>{
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 { useCallback, useMemo } from "react";
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":"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"}