@aglyn/besigner-ui 1.0.0-beta.218 → 1.0.0-beta.220

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +17 -2
  2. package/package.json +18 -18
  3. package/src/lib/components/app-bar-breadcrumbs.component.js +2 -2
  4. package/src/lib/components/app-bar-breadcrumbs.component.js.map +1 -1
  5. package/src/lib/components/aside-panel.component.js +2 -2
  6. package/src/lib/components/aside-panel.component.js.map +1 -1
  7. package/src/lib/components/element-classes-field.component.js +63 -40
  8. package/src/lib/components/element-classes-field.component.js.map +1 -1
  9. package/src/lib/components/element-detail.component.d.ts +12 -0
  10. package/src/lib/components/element-detail.component.js +12 -19
  11. package/src/lib/components/element-detail.component.js.map +1 -1
  12. package/src/lib/components/element-props-form.component.js +4 -4
  13. package/src/lib/components/element-props-form.component.js.map +1 -1
  14. package/src/lib/components/empty-document-slot.js +1 -1
  15. package/src/lib/components/empty-document-slot.js.map +1 -1
  16. package/src/lib/components/node-leaf.js +1 -1
  17. package/src/lib/components/node-leaf.js.map +1 -1
  18. package/src/lib/components/properties-dialog.component.js +1 -1
  19. package/src/lib/components/properties-dialog.component.js.map +1 -1
  20. package/src/lib/components/property-values-form.component.d.ts +13 -0
  21. package/src/lib/components/property-values-form.component.js +32 -10
  22. package/src/lib/components/property-values-form.component.js.map +1 -1
  23. package/src/lib/components/screen-link-field.component.js +1 -1
  24. package/src/lib/components/screen-link-field.component.js.map +1 -1
  25. package/src/lib/components/subtree-json-dialog.component.js +1 -1
  26. package/src/lib/components/subtree-json-dialog.component.js.map +1 -1
  27. package/src/lib/components/token-pill.component.js +1 -1
  28. package/src/lib/components/token-pill.component.js.map +1 -1
  29. package/src/lib/contexts/element-drawer-context.d.ts +3 -3
  30. package/src/lib/drafts/besigner-draft-store.d.ts +6 -1
  31. package/src/lib/drafts/besigner-draft-store.js.map +1 -1
  32. package/src/lib/hooks/use-aglyn-besigner-flag.js +9 -2
  33. package/src/lib/hooks/use-aglyn-besigner-flag.js.map +1 -1
  34. package/src/lib/hooks/use-insert-token-options.d.ts +10 -6
  35. package/src/lib/hooks/use-insert-token-options.js +64 -53
  36. package/src/lib/hooks/use-insert-token-options.js.map +1 -1
  37. package/src/lib/utils/docs-help.d.ts +1 -1
  38. package/src/lib/utils/docs-help.generated.d.ts +2 -2
  39. package/src/lib/utils/docs-help.generated.js +7 -1
  40. package/src/lib/utils/docs-help.generated.js.map +1 -1
  41. package/src/lib/utils/docs-help.js +1 -1
  42. package/src/lib/utils/docs-help.js.map +1 -1
  43. package/src/lib/utils/token-segments.d.ts +6 -4
  44. package/src/lib/utils/token-segments.js +3 -3
  45. package/src/lib/utils/token-segments.js.map +1 -1
package/README.md CHANGED
@@ -83,8 +83,23 @@ import {
83
83
  } from '@aglyn/besigner-ui'
84
84
  ```
85
85
 
86
- The reference composition is the console's screen editor page in the
87
- monorepo, under
86
+ Two things have to be in place before the editor mounts, or it throws on
87
+ its first render:
88
+
89
+ - an editor app: call `initializeBesignerApp()` from `@aglyn/besigner` once;
90
+ - the console theme served as CSS variables: render the editor inside
91
+ `ThemeCssVarProvider` from `@aglyn/shared-ui-theme`, given
92
+ `{ light: consoleThemeLight, dark: consoleThemeDark }`. A plain MUI
93
+ `ThemeProvider` is not enough, because the editor's styles read the theme's
94
+ CSS variables.
95
+
96
+ The smallest working composition is the example app in the monorepo,
97
+ [`examples/consumers/besigner-ui`](https://github.com/aglyn/aglyn/tree/main/examples/consumers/besigner-ui):
98
+ a Vite app that installs these packages from npm, registers four element
99
+ types of its own, and mounts the workspace, viewport and canvas. Aglyn's CI
100
+ builds it and opens it in a browser on every release.
101
+
102
+ The full composition is the console's screen editor page, under
88
103
  `apps/console/app/(editor)/[orgSlug]/hosts/[host]/screens/[screenId]/versions/[versionId]/besigner/page.tsx`.
89
104
  It wraps the page with `withBesignerContext`, loads the document with
90
105
  `useBesignerDocument`, and lays out the workspace, viewport and panels. The
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/besigner-ui",
3
- "version": "1.0.0-beta.218",
3
+ "version": "1.0.0-beta.220",
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.218",
29
- "@aglyn/aglyn-markdown-editor": "1.0.0-beta.218",
30
- "@aglyn/aglyn-node-renderer": "1.0.0-beta.218",
31
- "@aglyn/besigner": "1.0.0-beta.218",
32
- "@aglyn/shared-data-enums": "1.0.0-beta.218",
33
- "@aglyn/shared-data-mdi": "1.0.0-beta.218",
34
- "@aglyn/shared-data-types": "1.0.0-beta.218",
35
- "@aglyn/shared-svg-icons": "1.0.0-beta.218",
36
- "@aglyn/shared-ui-json-editor": "1.0.0-beta.218",
37
- "@aglyn/shared-ui-jsx": "1.0.0-beta.218",
38
- "@aglyn/shared-ui-jsx-forms": "1.0.0-beta.218",
39
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.218",
40
- "@aglyn/shared-ui-theme": "1.0.0-beta.218",
41
- "@aglyn/shared-util-dom": "1.0.0-beta.218",
42
- "@aglyn/shared-util-tools": "1.0.0-beta.218",
43
- "@aglyn/shared-util-vendor": "1.0.0-beta.218",
28
+ "@aglyn/aglyn": "1.0.0-beta.220",
29
+ "@aglyn/aglyn-markdown-editor": "1.0.0-beta.220",
30
+ "@aglyn/aglyn-node-renderer": "1.0.0-beta.220",
31
+ "@aglyn/besigner": "1.0.0-beta.220",
32
+ "@aglyn/shared-data-enums": "1.0.0-beta.220",
33
+ "@aglyn/shared-data-mdi": "1.0.0-beta.220",
34
+ "@aglyn/shared-data-types": "1.0.0-beta.220",
35
+ "@aglyn/shared-svg-icons": "1.0.0-beta.220",
36
+ "@aglyn/shared-ui-json-editor": "1.0.0-beta.220",
37
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.220",
38
+ "@aglyn/shared-ui-jsx-forms": "1.0.0-beta.220",
39
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.220",
40
+ "@aglyn/shared-ui-theme": "1.0.0-beta.220",
41
+ "@aglyn/shared-util-dom": "1.0.0-beta.220",
42
+ "@aglyn/shared-util-tools": "1.0.0-beta.220",
43
+ "@aglyn/shared-util-vendor": "1.0.0-beta.220",
44
44
  "@dnd-kit/core": "^6.3.1",
45
45
  "@dnd-kit/utilities": "^3.2.2",
46
46
  "@react-aria/utils": "^3.34.1",
@@ -63,7 +63,7 @@
63
63
  "@mui/material": "^9.3.1",
64
64
  "@mui/system": "^9.2.0",
65
65
  "firebase": "^12.18.0",
66
- "next": "16.3.3",
66
+ "next": "^16.3.3",
67
67
  "react": "^19.2.8"
68
68
  },
69
69
  "sideEffects": false,
@@ -196,7 +196,7 @@ export const AppBarBreadcrumbsComponent = /*#__PURE__*/ forwardRef((props, ref)=
196
196
  ]);
197
197
  // This strip is the canvas column's bottom chrome, so it is what a
198
198
  // viewport-fixed affordance in that corner would clip (AGL-2486). It
199
- // publishes its own height as the stand-off the Assist launcher reads;
199
+ // publishes its own height as the stand-off a dock launcher reads;
200
200
  // measured rather than assumed, because "24px dense toolbar plus a
201
201
  // border" is exactly the kind of constant that stops being true the
202
202
  // first time a chip wraps.
@@ -212,7 +212,7 @@ export const AppBarBreadcrumbsComponent = /*#__PURE__*/ forwardRef((props, ref)=
212
212
  const node = stripRef.current;
213
213
  if (!node) return undefined;
214
214
  const root = document.documentElement;
215
- const property = '--aglyn-assist-inset-bottom';
215
+ const property = '--aglyn-dock-inset-bottom';
216
216
  const publish = ()=>{
217
217
  const { height } = node.getBoundingClientRect();
218
218
  root.style.setProperty(property, `${Math.round(height) + 20}px`);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/app-bar-breadcrumbs.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 * as Aglyn from '@aglyn/aglyn'\nimport { canvas } from '@aglyn/aglyn'\nimport * as Besigner from '@aglyn/besigner'\nimport {\n generateComponentClassKeys,\n mergeSxProps,\n styled,\n} from '@aglyn/shared-ui-theme'\nimport {\n alpha,\n AppBar as MuiAppBar,\n type AppBarProps as MuiAppBarProps,\n Breadcrumbs as MuiBreadcrumbs,\n breadcrumbsClasses,\n type BreadcrumbsProps as MuiBreadcrumbsProps,\n ButtonBase as MuiButtonBase,\n type ButtonBaseProps as ButtonBaseProps,\n Chip,\n Stack,\n Toolbar as MuiToolbar,\n} from '@mui/material'\nimport clsx from 'clsx'\nimport { observer } from 'mobx-react-lite'\nimport { forwardRef, useCallback, useEffect, useRef } from 'react'\nimport useLeafDrop from '../hooks/use-leaf-drop'\n\nconst breadcrumbItemClassKey = generateComponentClassKeys('BreadcrumbItem', [\n 'root',\n 'lastItem',\n 'hovered',\n])\n\nconst StyledBreadcrumbs = styled(MuiBreadcrumbs)(({ theme }) => {\n const tv = (theme as any).vars || theme\n return {\n lineHeight: 1,\n fontSize: 11,\n overflowX: 'auto',\n\n [`.${breadcrumbsClasses.ol}`]: {\n flexWrap: 'nowrap',\n whiteSpace: 'nowrap',\n },\n [`.${breadcrumbsClasses.separator}`]: {\n margin: 0,\n padding: 0,\n },\n [`.${breadcrumbsClasses.li}`]: {\n marginLeft: theme.spacing(-0.5),\n [`.${breadcrumbItemClassKey.root}`]: {\n fontSize: 'inherit',\n padding: theme.spacing(0.75),\n paddingLeft: theme.spacing(1.75),\n paddingRight: theme.spacing(1.75),\n marginLeft: theme.spacing(-0.5),\n clipPath: `polygon(calc(100% - ${theme.spacing(\n 1,\n )}) 0px, 100% 50%, calc(100% - ${theme.spacing(\n 1,\n )}) 100%, 0% 100%, ${theme.spacing(1)} 50%, 0% 0%)`,\n\n color: tv.palette.text.primary,\n background: `rgba(${tv.palette.primary.lightChannel} / ${theme.palette.action.hoverOpacity})`,\n [`:hover, .${breadcrumbItemClassKey.hovered}`]: {\n background: `rgba(${tv.palette.primary.lightChannel} / ${theme.palette.action.activatedOpacity})`,\n },\n [`:focus`]: {\n background: `rgba(${tv.palette.primary.lightChannel} / ${theme.palette.action.focusOpacity})`,\n },\n [`:active`]: {\n background: `rgba(${tv.palette.primary.lightChannel} / ${theme.palette.action.activatedOpacity})`,\n },\n },\n\n [':before']: {\n content: '\"\"',\n position: 'absolute',\n top: 0,\n height: '100%',\n width: `calc(${theme.spacing(1)} + 1px)`,\n backgroundColor: tv.palette.divider,\n marginLeft: theme.spacing(-0.5),\n clipPath: `polygon(calc(100% - ${theme.spacing(\n 1,\n )}) 0px, 100% 50%, calc(100% - ${theme.spacing(\n 1,\n )}) 100%, 0% 100%, ${theme.spacing(1)} 50%, 0% 0%)`,\n },\n\n [`:first-of-type .${breadcrumbItemClassKey.root}`]: {\n clipPath: `polygon(calc(100% - ${theme.spacing(\n 1,\n )}) 0px, 100% 50%, calc(100% - ${theme.spacing(\n 1,\n )}) 100%, 0% 100%, 0% 0%, 0% 0%)`,\n },\n\n [[\n `:last-of-type .${breadcrumbItemClassKey.root}`,\n `.${breadcrumbItemClassKey.root} .${breadcrumbItemClassKey.lastItem}`,\n ].join()]: {\n color: tv.palette.text.primary,\n background: `rgba(${tv.palette.secondary.lightChannel} / ${theme.palette.action.selectedOpacity})`,\n [`:hover, ${breadcrumbItemClassKey.hovered}`]: {\n background: `rgba(${tv.palette.secondary.lightChannel} / ${theme.palette.action.activatedOpacity})`,\n },\n [`:focus, .Mui-focusVisible`]: {\n background: `rgba(${tv.palette.secondary.lightChannel} / ${theme.palette.action.focusOpacity})`,\n },\n [`:active`]: {\n background: `rgba(${tv.palette.secondary.lightChannel} / ${theme.palette.action.hoverOpacity})`,\n },\n },\n },\n }\n})\n\nexport interface BreadcrumbItemProps\n extends Partial<\n Omit<\n ButtonBaseProps<'button'>,\n 'onClick' | 'onMouseEnter' | 'onFocusVisible'\n >\n > {\n $id: Aglyn.NodeId\n lastItem?: boolean\n onClick?: (e, node: Aglyn.NodeSchema<any>) => void\n onMouseEnter?: (e, node: Aglyn.NodeSchema<any>) => void\n onFocusVisible?: (e, node: Aglyn.NodeSchema<any>) => void\n}\n\nconst BreadcrumbItem = observer((props: BreadcrumbItemProps) => {\n const {\n children,\n $id,\n lastItem,\n onClick,\n onMouseEnter,\n onFocusVisible,\n ...rest\n } = props\n const node = canvas.getNode($id)\n const isHovered = Besigner.focus.isNodeHovered(node)\n const { setNodeRef: setDroppableNodeRef } = useLeafDrop(\n node,\n undefined,\n 'breadcrumbs',\n )\n\n const handleClick = useCallback(\n (e) => {\n onClick && onClick(e, node)\n },\n [onClick, node],\n )\n\n const handleMouseEnter = useCallback(\n (e) => {\n onMouseEnter && onMouseEnter(e, node)\n },\n [onMouseEnter, node],\n )\n\n const handleFocusVisible = useCallback(\n (e) => {\n onFocusVisible && onFocusVisible(e, node)\n },\n [onFocusVisible, node],\n )\n\n return (\n <MuiButtonBase\n ref={setDroppableNodeRef}\n onClick={handleClick}\n onMouseEnter={handleMouseEnter}\n onFocusVisible={handleFocusVisible}\n className={clsx(breadcrumbItemClassKey.root, {\n [breadcrumbItemClassKey.lastItem]: lastItem,\n [breadcrumbItemClassKey.hovered]: isHovered,\n })}\n {...rest}\n >\n <>\n {node?.labelShort}\n {children}\n </>\n </MuiButtonBase>\n )\n})\n\ninterface BreadcrumbsProps extends Partial<MuiBreadcrumbsProps> {}\n\nconst Breadcrumbs = observer((props: BreadcrumbsProps) => {\n const { children, sx, ...rest } = props\n const lastSelected = Besigner.focus.getLastSelected()\n const selectionCount = Besigner.focus.selectionCount()\n\n const handleClick = useCallback((e, node: Aglyn.NodeSchema<any>) => {\n Besigner.focus.setSelectedNode(node)\n }, [])\n\n const handleMouseEnter = useCallback((e, node: Aglyn.NodeSchema<any>) => {\n Besigner.focus.setHoveredNode(node)\n }, [])\n\n const handleFocusVisible = useCallback((e, node: Aglyn.NodeSchema<any>) => {\n Besigner.focus.setHoveredNode(node)\n }, [])\n\n return (\n <StyledBreadcrumbs\n separator={null}\n aria-label=\"breadcrumb\"\n sx={sx}\n {...rest}\n >\n {lastSelected?.breadcrumbPath.map(($id) => {\n return (\n <BreadcrumbItem\n key={$id}\n $id={$id}\n onClick={handleClick}\n onMouseEnter={handleMouseEnter}\n onFocusVisible={handleFocusVisible}\n lastItem={lastSelected?.$id === $id}\n />\n )\n })}\n {selectionCount > 1 ? (\n <Chip\n label={`+${selectionCount - 1} selected`}\n size=\"small\"\n variant=\"outlined\"\n color=\"primary\"\n sx={{ ml: 0.5, height: 18, fontSize: '0.65rem' }}\n />\n ) : null}\n </StyledBreadcrumbs>\n )\n})\n\nexport interface AppBarBreadcrumbsComponentProps\n extends Partial<MuiAppBarProps> {}\n\nexport const AppBarBreadcrumbsComponent = forwardRef<\n any,\n AppBarBreadcrumbsComponentProps\n>((props, ref) => {\n const { children, sx, ...rest } = props\n\n // This strip is the canvas column's bottom chrome, so it is what a\n // viewport-fixed affordance in that corner would clip (AGL-2486). It\n // publishes its own height as the stand-off the Assist launcher reads;\n // measured rather than assumed, because \"24px dense toolbar plus a\n // border\" is exactly the kind of constant that stops being true the\n // first time a chip wraps.\n const stripRef = useRef<HTMLElement | null>(null)\n const setRefs = useCallback(\n (node: HTMLElement | null) => {\n stripRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as { current: unknown }).current = node\n },\n [ref],\n )\n useEffect(() => {\n const node = stripRef.current\n if (!node) return undefined\n const root = document.documentElement\n const property = '--aglyn-assist-inset-bottom'\n const publish = () => {\n const { height } = node.getBoundingClientRect()\n root.style.setProperty(property, `${Math.round(height) + 20}px`)\n }\n publish()\n // Guarded: jsdom has no ResizeObserver, and the initial publish above\n // is the part that matters — the observer only keeps it honest.\n const observer =\n typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(publish)\n observer?.observe(node)\n return () => {\n observer?.disconnect()\n root.style.removeProperty(property)\n }\n }, [])\n\n return (\n <MuiAppBar\n ref={setRefs}\n id=\"aglyn:besigner-appbar-secondary\"\n aria-label=\"secondary app toolbar\"\n position=\"static\"\n color=\"surface\"\n component=\"header\"\n elevation={0}\n sx={mergeSxProps(\n {\n top: 0,\n // Stack above the canvas selection overlays (portaled, low z).\n position: 'relative',\n zIndex: 'appBar',\n borderBottomWidth: '1px',\n borderBottomStyle: 'solid',\n borderBottomColor: 'divider',\n [`& .MuiToolbar-root`]: { minHeight: 24 },\n },\n sx,\n )}\n {...rest}\n >\n <MuiToolbar variant=\"dense\" sx={{ px: { xs: 0, sm: 0 } }}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{\n alignItems: \"center\",\n justifyContent: \"space-between\",\n width: 1\n }}>\n <Breadcrumbs />\n {children}\n </Stack>\n </MuiToolbar>\n </MuiAppBar>\n );\n})\n\nAppBarBreadcrumbsComponent.displayName = 'AppBarBreadcrumbsComponent'\nAppBarBreadcrumbsComponent.aglyn = true\n\nexport default AppBarBreadcrumbsComponent\n"],"names":["canvas","Besigner","generateComponentClassKeys","mergeSxProps","styled","AppBar","MuiAppBar","Breadcrumbs","MuiBreadcrumbs","breadcrumbsClasses","ButtonBase","MuiButtonBase","Chip","Stack","Toolbar","MuiToolbar","clsx","observer","forwardRef","useCallback","useEffect","useRef","useLeafDrop","breadcrumbItemClassKey","StyledBreadcrumbs","theme","tv","vars","lineHeight","fontSize","overflowX","ol","flexWrap","whiteSpace","separator","margin","padding","li","marginLeft","spacing","root","paddingLeft","paddingRight","clipPath","color","palette","text","primary","background","lightChannel","action","hoverOpacity","hovered","activatedOpacity","focusOpacity","content","position","top","height","width","backgroundColor","divider","lastItem","join","secondary","selectedOpacity","BreadcrumbItem","props","children","$id","onClick","onMouseEnter","onFocusVisible","rest","node","getNode","isHovered","focus","isNodeHovered","setNodeRef","setDroppableNodeRef","undefined","handleClick","e","handleMouseEnter","handleFocusVisible","ref","className","labelShort","sx","lastSelected","getLastSelected","selectionCount","setSelectedNode","setHoveredNode","aria-label","breadcrumbPath","map","label","size","variant","ml","AppBarBreadcrumbsComponent","stripRef","setRefs","current","document","documentElement","property","publish","getBoundingClientRect","style","setProperty","Math","round","ResizeObserver","observe","disconnect","removeProperty","id","component","elevation","zIndex","borderBottomWidth","borderBottomStyle","borderBottomColor","minHeight","px","xs","sm","direction","alignItems","justifyContent","displayName","aglyn"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/app-bar-breadcrumbs.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 * as Aglyn from '@aglyn/aglyn'\nimport { canvas } from '@aglyn/aglyn'\nimport * as Besigner from '@aglyn/besigner'\nimport {\n generateComponentClassKeys,\n mergeSxProps,\n styled,\n} from '@aglyn/shared-ui-theme'\nimport {\n alpha,\n AppBar as MuiAppBar,\n type AppBarProps as MuiAppBarProps,\n Breadcrumbs as MuiBreadcrumbs,\n breadcrumbsClasses,\n type BreadcrumbsProps as MuiBreadcrumbsProps,\n ButtonBase as MuiButtonBase,\n type ButtonBaseProps as ButtonBaseProps,\n Chip,\n Stack,\n Toolbar as MuiToolbar,\n} from '@mui/material'\nimport clsx from 'clsx'\nimport { observer } from 'mobx-react-lite'\nimport { forwardRef, useCallback, useEffect, useRef } from 'react'\nimport useLeafDrop from '../hooks/use-leaf-drop'\n\nconst breadcrumbItemClassKey = generateComponentClassKeys('BreadcrumbItem', [\n 'root',\n 'lastItem',\n 'hovered',\n])\n\nconst StyledBreadcrumbs = styled(MuiBreadcrumbs)(({ theme }) => {\n const tv = (theme as any).vars || theme\n return {\n lineHeight: 1,\n fontSize: 11,\n overflowX: 'auto',\n\n [`.${breadcrumbsClasses.ol}`]: {\n flexWrap: 'nowrap',\n whiteSpace: 'nowrap',\n },\n [`.${breadcrumbsClasses.separator}`]: {\n margin: 0,\n padding: 0,\n },\n [`.${breadcrumbsClasses.li}`]: {\n marginLeft: theme.spacing(-0.5),\n [`.${breadcrumbItemClassKey.root}`]: {\n fontSize: 'inherit',\n padding: theme.spacing(0.75),\n paddingLeft: theme.spacing(1.75),\n paddingRight: theme.spacing(1.75),\n marginLeft: theme.spacing(-0.5),\n clipPath: `polygon(calc(100% - ${theme.spacing(\n 1,\n )}) 0px, 100% 50%, calc(100% - ${theme.spacing(\n 1,\n )}) 100%, 0% 100%, ${theme.spacing(1)} 50%, 0% 0%)`,\n\n color: tv.palette.text.primary,\n background: `rgba(${tv.palette.primary.lightChannel} / ${theme.palette.action.hoverOpacity})`,\n [`:hover, .${breadcrumbItemClassKey.hovered}`]: {\n background: `rgba(${tv.palette.primary.lightChannel} / ${theme.palette.action.activatedOpacity})`,\n },\n [`:focus`]: {\n background: `rgba(${tv.palette.primary.lightChannel} / ${theme.palette.action.focusOpacity})`,\n },\n [`:active`]: {\n background: `rgba(${tv.palette.primary.lightChannel} / ${theme.palette.action.activatedOpacity})`,\n },\n },\n\n [':before']: {\n content: '\"\"',\n position: 'absolute',\n top: 0,\n height: '100%',\n width: `calc(${theme.spacing(1)} + 1px)`,\n backgroundColor: tv.palette.divider,\n marginLeft: theme.spacing(-0.5),\n clipPath: `polygon(calc(100% - ${theme.spacing(\n 1,\n )}) 0px, 100% 50%, calc(100% - ${theme.spacing(\n 1,\n )}) 100%, 0% 100%, ${theme.spacing(1)} 50%, 0% 0%)`,\n },\n\n [`:first-of-type .${breadcrumbItemClassKey.root}`]: {\n clipPath: `polygon(calc(100% - ${theme.spacing(\n 1,\n )}) 0px, 100% 50%, calc(100% - ${theme.spacing(\n 1,\n )}) 100%, 0% 100%, 0% 0%, 0% 0%)`,\n },\n\n [[\n `:last-of-type .${breadcrumbItemClassKey.root}`,\n `.${breadcrumbItemClassKey.root} .${breadcrumbItemClassKey.lastItem}`,\n ].join()]: {\n color: tv.palette.text.primary,\n background: `rgba(${tv.palette.secondary.lightChannel} / ${theme.palette.action.selectedOpacity})`,\n [`:hover, ${breadcrumbItemClassKey.hovered}`]: {\n background: `rgba(${tv.palette.secondary.lightChannel} / ${theme.palette.action.activatedOpacity})`,\n },\n [`:focus, .Mui-focusVisible`]: {\n background: `rgba(${tv.palette.secondary.lightChannel} / ${theme.palette.action.focusOpacity})`,\n },\n [`:active`]: {\n background: `rgba(${tv.palette.secondary.lightChannel} / ${theme.palette.action.hoverOpacity})`,\n },\n },\n },\n }\n})\n\nexport interface BreadcrumbItemProps\n extends Partial<\n Omit<\n ButtonBaseProps<'button'>,\n 'onClick' | 'onMouseEnter' | 'onFocusVisible'\n >\n > {\n $id: Aglyn.NodeId\n lastItem?: boolean\n onClick?: (e, node: Aglyn.NodeSchema<any>) => void\n onMouseEnter?: (e, node: Aglyn.NodeSchema<any>) => void\n onFocusVisible?: (e, node: Aglyn.NodeSchema<any>) => void\n}\n\nconst BreadcrumbItem = observer((props: BreadcrumbItemProps) => {\n const {\n children,\n $id,\n lastItem,\n onClick,\n onMouseEnter,\n onFocusVisible,\n ...rest\n } = props\n const node = canvas.getNode($id)\n const isHovered = Besigner.focus.isNodeHovered(node)\n const { setNodeRef: setDroppableNodeRef } = useLeafDrop(\n node,\n undefined,\n 'breadcrumbs',\n )\n\n const handleClick = useCallback(\n (e) => {\n onClick && onClick(e, node)\n },\n [onClick, node],\n )\n\n const handleMouseEnter = useCallback(\n (e) => {\n onMouseEnter && onMouseEnter(e, node)\n },\n [onMouseEnter, node],\n )\n\n const handleFocusVisible = useCallback(\n (e) => {\n onFocusVisible && onFocusVisible(e, node)\n },\n [onFocusVisible, node],\n )\n\n return (\n <MuiButtonBase\n ref={setDroppableNodeRef}\n onClick={handleClick}\n onMouseEnter={handleMouseEnter}\n onFocusVisible={handleFocusVisible}\n className={clsx(breadcrumbItemClassKey.root, {\n [breadcrumbItemClassKey.lastItem]: lastItem,\n [breadcrumbItemClassKey.hovered]: isHovered,\n })}\n {...rest}\n >\n <>\n {node?.labelShort}\n {children}\n </>\n </MuiButtonBase>\n )\n})\n\ninterface BreadcrumbsProps extends Partial<MuiBreadcrumbsProps> {}\n\nconst Breadcrumbs = observer((props: BreadcrumbsProps) => {\n const { children, sx, ...rest } = props\n const lastSelected = Besigner.focus.getLastSelected()\n const selectionCount = Besigner.focus.selectionCount()\n\n const handleClick = useCallback((e, node: Aglyn.NodeSchema<any>) => {\n Besigner.focus.setSelectedNode(node)\n }, [])\n\n const handleMouseEnter = useCallback((e, node: Aglyn.NodeSchema<any>) => {\n Besigner.focus.setHoveredNode(node)\n }, [])\n\n const handleFocusVisible = useCallback((e, node: Aglyn.NodeSchema<any>) => {\n Besigner.focus.setHoveredNode(node)\n }, [])\n\n return (\n <StyledBreadcrumbs\n separator={null}\n aria-label=\"breadcrumb\"\n sx={sx}\n {...rest}\n >\n {lastSelected?.breadcrumbPath.map(($id) => {\n return (\n <BreadcrumbItem\n key={$id}\n $id={$id}\n onClick={handleClick}\n onMouseEnter={handleMouseEnter}\n onFocusVisible={handleFocusVisible}\n lastItem={lastSelected?.$id === $id}\n />\n )\n })}\n {selectionCount > 1 ? (\n <Chip\n label={`+${selectionCount - 1} selected`}\n size=\"small\"\n variant=\"outlined\"\n color=\"primary\"\n sx={{ ml: 0.5, height: 18, fontSize: '0.65rem' }}\n />\n ) : null}\n </StyledBreadcrumbs>\n )\n})\n\nexport interface AppBarBreadcrumbsComponentProps\n extends Partial<MuiAppBarProps> {}\n\nexport const AppBarBreadcrumbsComponent = forwardRef<\n any,\n AppBarBreadcrumbsComponentProps\n>((props, ref) => {\n const { children, sx, ...rest } = props\n\n // This strip is the canvas column's bottom chrome, so it is what a\n // viewport-fixed affordance in that corner would clip (AGL-2486). It\n // publishes its own height as the stand-off a dock launcher reads;\n // measured rather than assumed, because \"24px dense toolbar plus a\n // border\" is exactly the kind of constant that stops being true the\n // first time a chip wraps.\n const stripRef = useRef<HTMLElement | null>(null)\n const setRefs = useCallback(\n (node: HTMLElement | null) => {\n stripRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as { current: unknown }).current = node\n },\n [ref],\n )\n useEffect(() => {\n const node = stripRef.current\n if (!node) return undefined\n const root = document.documentElement\n const property = '--aglyn-dock-inset-bottom'\n const publish = () => {\n const { height } = node.getBoundingClientRect()\n root.style.setProperty(property, `${Math.round(height) + 20}px`)\n }\n publish()\n // Guarded: jsdom has no ResizeObserver, and the initial publish above\n // is the part that matters — the observer only keeps it honest.\n const observer =\n typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(publish)\n observer?.observe(node)\n return () => {\n observer?.disconnect()\n root.style.removeProperty(property)\n }\n }, [])\n\n return (\n <MuiAppBar\n ref={setRefs}\n id=\"aglyn:besigner-appbar-secondary\"\n aria-label=\"secondary app toolbar\"\n position=\"static\"\n color=\"surface\"\n component=\"header\"\n elevation={0}\n sx={mergeSxProps(\n {\n top: 0,\n // Stack above the canvas selection overlays (portaled, low z).\n position: 'relative',\n zIndex: 'appBar',\n borderBottomWidth: '1px',\n borderBottomStyle: 'solid',\n borderBottomColor: 'divider',\n [`& .MuiToolbar-root`]: { minHeight: 24 },\n },\n sx,\n )}\n {...rest}\n >\n <MuiToolbar variant=\"dense\" sx={{ px: { xs: 0, sm: 0 } }}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{\n alignItems: \"center\",\n justifyContent: \"space-between\",\n width: 1\n }}>\n <Breadcrumbs />\n {children}\n </Stack>\n </MuiToolbar>\n </MuiAppBar>\n );\n})\n\nAppBarBreadcrumbsComponent.displayName = 'AppBarBreadcrumbsComponent'\nAppBarBreadcrumbsComponent.aglyn = true\n\nexport default AppBarBreadcrumbsComponent\n"],"names":["canvas","Besigner","generateComponentClassKeys","mergeSxProps","styled","AppBar","MuiAppBar","Breadcrumbs","MuiBreadcrumbs","breadcrumbsClasses","ButtonBase","MuiButtonBase","Chip","Stack","Toolbar","MuiToolbar","clsx","observer","forwardRef","useCallback","useEffect","useRef","useLeafDrop","breadcrumbItemClassKey","StyledBreadcrumbs","theme","tv","vars","lineHeight","fontSize","overflowX","ol","flexWrap","whiteSpace","separator","margin","padding","li","marginLeft","spacing","root","paddingLeft","paddingRight","clipPath","color","palette","text","primary","background","lightChannel","action","hoverOpacity","hovered","activatedOpacity","focusOpacity","content","position","top","height","width","backgroundColor","divider","lastItem","join","secondary","selectedOpacity","BreadcrumbItem","props","children","$id","onClick","onMouseEnter","onFocusVisible","rest","node","getNode","isHovered","focus","isNodeHovered","setNodeRef","setDroppableNodeRef","undefined","handleClick","e","handleMouseEnter","handleFocusVisible","ref","className","labelShort","sx","lastSelected","getLastSelected","selectionCount","setSelectedNode","setHoveredNode","aria-label","breadcrumbPath","map","label","size","variant","ml","AppBarBreadcrumbsComponent","stripRef","setRefs","current","document","documentElement","property","publish","getBoundingClientRect","style","setProperty","Math","round","ResizeObserver","observe","disconnect","removeProperty","id","component","elevation","zIndex","borderBottomWidth","borderBottomStyle","borderBottomColor","minHeight","px","xs","sm","direction","alignItems","justifyContent","displayName","aglyn"],"mappings":"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"}
@@ -463,7 +463,7 @@ export const AsidePanelComponent = /*#__PURE__*/ forwardRef((props, ref)=>{
463
463
  const value = tab || defaultTab;
464
464
  // The bottom-right corner belongs to this panel while it is open
465
465
  // (AGL-2486), so publish how far a viewport-fixed affordance has to
466
- // stand off to clear it. The Assist launcher reads this; the console's
466
+ // stand off to clear it. A console-dock launcher reads this; the console's
467
467
  // own chrome leaves the corner free and never sets it, which is why the
468
468
  // variable carries the offset rather than the panel width — an unset
469
469
  // variable then means "the corner is yours" everywhere else.
@@ -480,7 +480,7 @@ export const AsidePanelComponent = /*#__PURE__*/ forwardRef((props, ref)=>{
480
480
  useEffect(()=>{
481
481
  if (panelKey !== 'panelRight') return undefined;
482
482
  const root = document.documentElement;
483
- const property = '--aglyn-assist-inset-right';
483
+ const property = '--aglyn-dock-inset-right';
484
484
  if (rightInset === null) {
485
485
  root.style.removeProperty(property);
486
486
  } else {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/aside-panel.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 { canvas, NODE_ROOT_ID } from '@aglyn/aglyn'\nimport * as Besigner from '@aglyn/besigner'\nimport {\n type BesignerPanelKey,\n BesignerPanelTabFlag,\n} from '@aglyn/besigner'\nimport {\n ICON_VARIANT_ELEMENT,\n ICON_VARIANT_ELEMENT_BROWSE,\n ICON_VARIANT_ELEMENT_INTERACTIONS,\n ICON_VARIANT_ELEMENT_PROPERTIES,\n ICON_VARIANT_ELEMENT_STYLES,\n ICON_VARIANT_ELEMENT_TREE_VIEW,\n ICON_VARIANT_MODIFY_ADD,\n} from '@aglyn/shared-data-enums'\nimport { HelpTip, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { mergeSxProps, styled } from '@aglyn/shared-ui-theme'\nimport {\n getDisplayName,\n numberFromHexadecimal,\n numberToHexadecimal,\n} from '@aglyn/shared-util-tools'\nimport { hoistNonReactStatics } from '@aglyn/shared-util-vendor'\nimport {\n TabContext as MuiTabContext,\n TabList as MuiTabList,\n TabPanel as MuiTabPanel,\n type TabPanelProps as MuiTabPanelProps,\n} from '@mui/lab'\nimport {\n AppBar as MuiAppBar,\n Box,\n Button,\n Chip,\n Stack,\n Tab as MuiTab,\n Typography,\n} from '@mui/material'\nimport { observer } from 'mobx-react-lite'\nimport {\n type ComponentType,\n forwardRef,\n type SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react'\nimport useAddElementDrawerCallback from '../hooks/use-add-element-drawer-callback'\nimport useAglynBesignerPanel from '../hooks/use-aglyn-besigner-panel'\nimport AccordionListComponent from './accordion-list.component'\nimport ElementInteractionsForm from './element-interactions-form.component'\nimport ComponentAccordionList from './component-accordion-list'\nimport ElementPropsForm from './element-props-form.component'\nimport ElementStylesForm from './element-styles-form.component'\nimport NodeTreeView, { type NodeTreeViewProps } from './node-tree-view'\nimport SiteThemeColorTokensProvider from './site-theme-color-tokens-provider.component'\nimport { usePublishActiveHostTheme } from '../utils/active-host-theme'\nimport { besignerInspected } from '../contexts/inspected-selection'\nimport {\n type LayoutElementSelection,\n layoutStyleSelection,\n} from '../contexts/layout-style-selection'\nimport {\n inspectorExtrasFor,\n useBesignerInspectorExtras,\n} from '../contexts/inspector-extras-context'\nimport { besignerDocsUrl } from '../utils/docs-help'\nimport WorkspacePanelComponent, {\n type WorkspacePanelComponentProps,\n} from './workspace-panel.component'\n\nconst TabPanel = styled(MuiTabPanel, {\n name: 'AglynTabPanel',\n})<MuiTabPanelProps>({\n padding: 0,\n overflow: 'auto',\n height: '100%',\n})\nconst TabPanelInner = styled('div', {\n name: 'AglynTabPanelInner',\n})(({ theme }) => ({\n width: '100%',\n}))\n\nconst emptyView = (\n <Stack\n direction=\"column\"\n component={TabPanelInner}\n sx={{\n justifyContent: 'center',\n height: 1,\n p: 2,\n }}\n >\n <Typography\n color=\"textSecondary\"\n variant=\"overline\"\n component=\"div\"\n align=\"center\"\n >\n <MdiIcon\n sx={{ opacity: 0.3, fontSize: 80 }}\n path={ICON_VARIANT_ELEMENT.path}\n />\n <div>{'Select an element'}</div>\n </Typography>\n </Stack>\n)\n\n\n/**\n * `Hero · Section` with a `SELECTED` tag — the inspector header the\n * `/product` hero mockup shows (AGL-2175).\n *\n * The right panel had no header at all: three tabs of controls with\n * nothing naming what they act on. On a canvas where clicking a child\n * moves the selection under you, that is the difference between editing\n * the section and editing the heading inside it — and the panel looked\n * identical either way.\n *\n * The second half is the COMPONENT, not a category: `labelShort` is the\n * preset's name (`Hero`) and the schema's is what it actually is\n * (`Section`). They are the same word often enough that it is dropped\n * when it would only repeat itself.\n */\nconst SelectedNodeHeader = observer(\n ({ node }: { node: Besigner.LastSelectedNode }) => {\n const name = node?.labelShort ?? ''\n const component = (node as { componentSchema?: { displayName?: string } })\n ?.componentSchema?.displayName\n const subtitle =\n component && component.toLowerCase() !== name.toLowerCase()\n ? `${name} · ${component}`\n : name\n return (\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{\n alignItems: 'center',\n px: 2,\n py: 1,\n borderBottom: 1,\n borderColor: 'divider',\n }}\n >\n <Typography variant=\"subtitle2\" noWrap sx={{ flex: 1, minWidth: 0 }}>\n {subtitle || 'Element'}\n </Typography>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color=\"secondary\"\n label=\"SELECTED\"\n sx={{ height: 18, '& .MuiChip-label': { px: 0.75, fontSize: 10 } }}\n />\n </Stack>\n )\n },\n)\nSelectedNodeHeader.displayName = 'SelectedNodeHeader'\n\n/**\n * The panel while a shared-layout element is the target (AGL-3286): named in\n * the header like any selection, and marked as the layout's, styles only.\n */\nconst LayoutElementHeader = ({\n selection,\n}: {\n selection: LayoutElementSelection\n}) => (\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{\n alignItems: 'center',\n px: 2,\n py: 1,\n borderBottom: 1,\n borderColor: 'divider',\n }}\n >\n <Typography variant=\"subtitle2\" noWrap sx={{ flex: 1, minWidth: 0 }}>\n {`${selection.label} · Layout`}\n </Typography>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color=\"info\"\n label=\"STYLES ONLY\"\n sx={{ height: 18, '& .MuiChip-label': { px: 0.75, fontSize: 10 } }}\n />\n </Stack>\n)\n\n/** What the Attributes and Interactions tabs say about a layout element. */\nconst LayoutElementNote = ({\n selection,\n}: {\n selection: LayoutElementSelection\n}) => (\n <Stack spacing={1.5} sx={{ p: 2 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`This element belongs to the shared layout${\n selection.layoutName ? ` \"${selection.layoutName}\"` : ''\n }. Its content is edited in the layout itself — use Edit layout above ` +\n 'the canvas. On this page you can change how it looks on the Styles tab.'}\n </Typography>\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => layoutStyleSelection.clear()}\n >\n {'Back to page elements'}\n </Button>\n </Stack>\n)\n\nfunction withLastSelectedNode<P>(\n WrappedComponent: JSX.ComponentType<P & { node: Besigner.LastSelectedNode }>,\n /**\n * What this tab shows while a layout element is the target (AGL-3286):\n * `styles` hands the wrapped Styles form the screen root and the target;\n * `note` says where the element's content is edited.\n */\n layoutMode: 'styles' | 'note' = 'note',\n) {\n const displayName = getDisplayName(WrappedComponent)\n\n const WithLastSelectedNode = observer((props: P) => {\n const { ...rest } = props\n const layoutTarget = layoutStyleSelection.current\n const selected = Besigner.focus.getLastSelected()\n /**\n * The LIVE node for that selection, re-resolved by id every render\n * (AGL-2486).\n *\n * The focus store holds node OBJECTS, not ids. Anything that replaces the\n * canvas map wholesale — `undo`, `redo`, a co-editing `applyNodes`, a\n * local-draft restore — builds fresh node instances and leaves the store\n * pointing at the pre-restore ones. The panels then read their fields from\n * an orphan and, worse, write back through it: `updateNodeProps` assigns\n * `node.props` on an object the canvas no longer owns, so the edit lands\n * nowhere. Nothing throws and nothing marks the document dirty, so an\n * author sees their new text in the box, an unchanged canvas, and `UP TO\n * DATE` — the reported \"the Text attribute silently discards edits\".\n *\n * Resolving here rather than in the three panels because they share this\n * one seam, and it is `observer`-tracked: `getNode` reads the observable\n * map, so a restore re-renders the panel with the live node instead of\n * leaving stale values in the fields.\n *\n * A node the map no longer has (deleted, or a test node that was never in\n * it) falls back to the stored object, which is exactly today's behaviour\n * for that case — there is no live node to prefer.\n */\n const lastSelected = selected\n ? canvas.getNode(selected.$id) ?? selected\n : selected\n\n if (layoutTarget) {\n // The page's layout overrides are kept on the screen root, so that is\n // the node the Styles form is handed; the target says which slice.\n const root = canvas.getNode(NODE_ROOT_ID)\n return (\n <>\n <LayoutElementHeader selection={layoutTarget} />\n {layoutMode === 'styles' && root ? (\n <WrappedComponent\n node={root}\n {...({ layoutTarget } as any)}\n {...rest}\n />\n ) : (\n <LayoutElementNote selection={layoutTarget} />\n )}\n </>\n )\n }\n\n return (\n <>\n {!lastSelected ? (\n emptyView\n ) : (\n <>\n {/* One header for all three right-panel tabs, so Attributes,\n Styles and Info cannot disagree about what is selected. */}\n <SelectedNodeHeader node={lastSelected} />\n <WrappedComponent node={lastSelected} {...rest} />\n </>\n )}\n </>\n )\n })\n WithLastSelectedNode.displayName = `WithLastSelectedNode(${displayName})`\n hoistNonReactStatics(WithLastSelectedNode, WrappedComponent)\n\n return WithLastSelectedNode\n}\n\nconst withTabPanelInner = (Component: ComponentType<any>) => (props: any) => {\n return (\n <TabPanelInner sx={{ p: 2 }}>\n <Component {...props} />\n </TabPanelInner>\n )\n}\n\n/**\n * The Attributes form with the host app's section beneath it (AGL-2940):\n * whatever `BesignerInspectorExtrasContext` carries, drawn under the\n * selected element's own fields — for that element, when the host supplied\n * a function — and nothing when the host supplied nothing.\n *\n * The selection travels with `editable` (AGL-2908), the same rule the form's\n * own Save as reusable component and Detach actions are drawn under: the\n * canvas root and locked layout chrome answer false. It is read here because\n * a host section has the node and not the editor, and the rule is the drag\n * manager's.\n */\nconst ElementPropsFormWithExtras = (props: any) => {\n const supplied = useBesignerInspectorExtras()\n const inspected = besignerInspected(props.node)\n const extras = inspected ? inspectorExtrasFor(supplied, inspected) : null\n return (\n <>\n <ElementPropsForm {...props} />\n {extras ? <Box sx={{ pt: 2 }}>{extras}</Box> : null}\n </>\n )\n}\n\nconst ElementsTree = forwardRef<any, NodeTreeViewProps>((props, ref) => {\n const handleAddElementClick = useAddElementDrawerCallback()\n return (\n <TabPanelInner sx={{ pl: 0.5 }}>\n <Box\n sx={{\n px: 0.05,\n pb: 1,\n pt: 1,\n display: 'flex',\n alignItems: 'center',\n }}\n >\n <Button\n color=\"primary\"\n startIcon={\n <MdiIcon fontSize=\"inherit\" path={ICON_VARIANT_MODIFY_ADD.path} />\n }\n onClick={() =>\n handleAddElementClick(Besigner.focus.getLastSelected())\n }\n >\n {'Add Element'}\n </Button>\n {/* The hierarchy is the one panel whose rules are not visible in it\n (AGL-2167): which elements accept children, and what dropping on\n an edge does versus dropping in the center. */}\n <HelpTip\n title=\"Drag, drop & hierarchy\"\n excerpt=\"Reparent by dragging here or on the canvas. Containers accept children; dropping on a leaf element makes a sibling instead.\"\n href={besignerDocsUrl('dragDropHierarchy', '#drop-zones-edges-vs-center')}\n sx={{ ml: 'auto', mr: 0.5, fontSize: '0.9em' }}\n />\n </Box>\n <NodeTreeView ref={ref} {...props} />\n </TabPanelInner>\n )\n})\n\nconst panelTabs: Partial<Record<BesignerPanelKey, any>> = {\n panelLeft: {\n defaultTab: BesignerPanelTabFlag.ELEMENTS_TREE,\n panel: {\n id: 'left',\n anchor: 'left',\n 'aria-label': 'left toolbox panel',\n },\n tabs: [\n {\n value: BesignerPanelTabFlag.ELEMENTS_TREE,\n tab: {\n icon: { path: ICON_VARIANT_ELEMENT_TREE_VIEW.path },\n label: 'Hierarchy',\n },\n panel: {\n Component: ElementsTree,\n },\n },\n {\n value: BesignerPanelTabFlag.ELEMENT_BROWSE,\n tab: {\n icon: { path: ICON_VARIANT_ELEMENT_BROWSE.path },\n label: 'Elements',\n },\n panel: {\n Component: ComponentAccordionList,\n },\n },\n ],\n },\n panelRight: {\n // Attributes first and open by default — it is what you reach for on\n // selecting an element. Tab order here is display order only; the flag\n // values are persisted in panel state, so they stay put.\n defaultTab: BesignerPanelTabFlag.ELEMENT_PROPS_FORM,\n panel: {\n id: 'right',\n anchor: 'right',\n 'aria-label': 'right toolbox panel',\n },\n tabs: [\n {\n value: BesignerPanelTabFlag.ELEMENT_PROPS_FORM,\n tab: {\n icon: { path: ICON_VARIANT_ELEMENT_PROPERTIES.path },\n label: 'Attributes',\n },\n panel: {\n Component: withLastSelectedNode(withTabPanelInner(ElementPropsFormWithExtras)),\n },\n },\n {\n value: BesignerPanelTabFlag.ELEMENT_STYLES,\n tab: {\n icon: { path: ICON_VARIANT_ELEMENT_STYLES.path },\n label: 'Styles',\n },\n panel: {\n Component: withLastSelectedNode(ElementStylesForm as any, 'styles'),\n },\n },\n /*\n * Interactions, between Styles and where Info used to be.\n *\n * They lived at the bottom of Attributes, under every field the\n * component declares — below the fold on anything with more than a\n * handful, so an author had no reason to believe the element had any.\n * An interaction is not an attribute: it is a behaviour, authored in a\n * dialog rather than a field, and it belongs beside the styles as a\n * peer.\n *\n * INFO IS GONE. Its two accordions are reference detail about the\n * component and the node's ids — worth having, not worth a tab — and\n * they now sit at the bottom of Attributes, beside the fields they\n * describe. Its flag value stays reserved; panel state is persisted,\n * and a reader whose last session ended on Info would otherwise return\n * to a tab id that means something else.\n */\n {\n value: BesignerPanelTabFlag.ELEMENT_INTERACTIONS,\n tab: {\n icon: { path: ICON_VARIANT_ELEMENT_INTERACTIONS.path },\n label: 'Interactions',\n },\n panel: {\n Component: withLastSelectedNode(\n withTabPanelInner(ElementInteractionsForm as any),\n ),\n },\n },\n ],\n },\n}\n\nexport interface AsidePanelComponentProps extends WorkspacePanelComponentProps {\n panel: BesignerPanelKey\n}\n\nexport const AsidePanelComponent = forwardRef<any, AsidePanelComponentProps>(\n (props, ref) => {\n const { children, panel: panelKey, ...rest } = props\n\n // Republish the page's site theme for surfaces that render OUTSIDE the\n // page tree (AGL-2486). This panel is inside `HostThemeDocumentContext`;\n // the Choose-element dialog — rendered by `withBesignerContext`, which\n // wraps the page — is not, and its element preview was painting the\n // console's brand onto someone else's site.\n usePublishActiveHostTheme()\n\n const [panel, setPanel] = useAglynBesignerPanel(panelKey)\n const {\n panel: { id, ...panelProps },\n defaultTab,\n tabs,\n } = panelTabs[panelKey]\n const { toggled, tab, size } = panel || {}\n const value = tab || defaultTab\n\n // The bottom-right corner belongs to this panel while it is open\n // (AGL-2486), so publish how far a viewport-fixed affordance has to\n // stand off to clear it. The Assist launcher reads this; the console's\n // own chrome leaves the corner free and never sets it, which is why the\n // variable carries the offset rather than the panel width — an unset\n // variable then means \"the corner is yours\" everywhere else.\n //\n // Kept in an effect on the LIVE panel state so it tracks the author\n // dragging the panel wider or collapsing it, and removed on unmount:\n // navigating from the besigner back into the console must not leave a\n // 395px inset behind on a page with no panel at all.\n // `size` is `string | number` on the panel state, so a numeric width is\n // parsed rather than added to: `'375' + 20` is `'37520'`, which is a\n // perfectly valid CSS length and would park the launcher off-screen.\n const panelWidth = Number.parseFloat(String(size ?? ''))\n const rightInset =\n panelKey === 'panelRight' && toggled && Number.isFinite(panelWidth)\n ? panelWidth + 20\n : null\n useEffect(() => {\n if (panelKey !== 'panelRight') return undefined\n const root = document.documentElement\n const property = '--aglyn-assist-inset-right'\n if (rightInset === null) {\n root.style.removeProperty(property)\n } else {\n root.style.setProperty(property, `${rightInset}px`)\n }\n return () => {\n root.style.removeProperty(property)\n }\n }, [panelKey, rightInset])\n\n const handleTabChange = useCallback(\n (e: SyntheticEvent, val: string) => {\n setPanel((panel) => ({ ...panel, tab: numberFromHexadecimal(val) }))\n },\n [setPanel],\n )\n\n return (\n <WorkspacePanelComponent\n ref={ref}\n id={`aglyn:panel-${id}`}\n aria-label=\"left toolbox panel\"\n size={size}\n open={toggled}\n component=\"aside\"\n {...panelProps}\n {...rest}\n >\n <MuiTabContext value={numberToHexadecimal(value)}>\n <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>\n <MuiAppBar\n color=\"surface\"\n position=\"relative\"\n elevation={0}\n enableColorOnDark\n >\n <MuiTabList\n onChange={handleTabChange}\n variant=\"fullWidth\"\n sx={{\n '& .MuiTab-root': {\n '&.Mui-selected': {\n // Use sx string shorthands instead of palette callbacks so the\n // sx system resolves them via theme.vars (CSS custom-property refs)\n // rather than the static light-mode palette values.\n color: 'text.primary',\n backgroundColor: 'background.paper',\n },\n },\n '& .MuiTabs-indicator': {\n top: 0,\n backgroundColor: 'secondary.main',\n },\n }}\n >\n {tabs.map(({ value, tab: { icon, ...tab } }) => (\n <MuiTab\n key={value}\n // color={'tertiary'}\n value={numberToHexadecimal(value)}\n iconPosition=\"top\"\n icon={<MdiIcon {...icon} fontSize=\"small\" />}\n sx={{\n minHeight: 'unset',\n fontSize: (theme) => theme.typography.pxToRem(12),\n lineHeight: 0.8,\n pt: 1,\n }}\n {...tab}\n />\n ))}\n </MuiTabList>\n </MuiAppBar>\n </Box>\n\n {/* Site-theme color tokens (AGL-588): every COLOR_PICKER field\n in these panels — styles panel, attribute forms, email\n blocks — offers the site palette's token references. */}\n <SiteThemeColorTokensProvider>\n {tabs.map(({ value, panel: { Component, ...panel } }) => (\n <TabPanel\n key={value}\n value={numberToHexadecimal(value)}\n {...panel}\n >\n <Component />\n </TabPanel>\n ))}\n </SiteThemeColorTokensProvider>\n </MuiTabContext>\n\n {children}\n </WorkspacePanelComponent>\n )\n },\n)\n\nAsidePanelComponent.displayName = 'AsidePanelComponent'\nAsidePanelComponent.aglyn = true\n\nexport default AsidePanelComponent\n"],"names":["canvas","NODE_ROOT_ID","Besigner","BesignerPanelTabFlag","ICON_VARIANT_ELEMENT","ICON_VARIANT_ELEMENT_BROWSE","ICON_VARIANT_ELEMENT_INTERACTIONS","ICON_VARIANT_ELEMENT_PROPERTIES","ICON_VARIANT_ELEMENT_STYLES","ICON_VARIANT_ELEMENT_TREE_VIEW","ICON_VARIANT_MODIFY_ADD","HelpTip","MdiIcon","styled","getDisplayName","numberFromHexadecimal","numberToHexadecimal","hoistNonReactStatics","TabContext","MuiTabContext","TabList","MuiTabList","TabPanel","MuiTabPanel","AppBar","MuiAppBar","Box","Button","Chip","Stack","Tab","MuiTab","Typography","observer","forwardRef","useCallback","useEffect","useAddElementDrawerCallback","useAglynBesignerPanel","ElementInteractionsForm","ComponentAccordionList","ElementPropsForm","ElementStylesForm","NodeTreeView","SiteThemeColorTokensProvider","usePublishActiveHostTheme","besignerInspected","layoutStyleSelection","inspectorExtrasFor","useBesignerInspectorExtras","besignerDocsUrl","WorkspacePanelComponent","name","padding","overflow","height","TabPanelInner","theme","width","emptyView","direction","component","sx","justifyContent","p","color","variant","align","opacity","fontSize","path","div","SelectedNodeHeader","node","labelShort","componentSchema","displayName","subtitle","toLowerCase","spacing","alignItems","px","py","borderBottom","borderColor","noWrap","flex","minWidth","size","label","LayoutElementHeader","selection","LayoutElementNote","layoutName","onClick","clear","withLastSelectedNode","WrappedComponent","layoutMode","WithLastSelectedNode","props","rest","layoutTarget","current","selected","focus","getLastSelected","lastSelected","getNode","$id","root","withTabPanelInner","Component","ElementPropsFormWithExtras","supplied","inspected","extras","pt","ElementsTree","ref","handleAddElementClick","pl","pb","display","startIcon","title","excerpt","href","ml","mr","panelTabs","panelLeft","defaultTab","ELEMENTS_TREE","panel","id","anchor","tabs","value","tab","icon","ELEMENT_BROWSE","panelRight","ELEMENT_PROPS_FORM","ELEMENT_STYLES","ELEMENT_INTERACTIONS","AsidePanelComponent","children","panelKey","setPanel","panelProps","toggled","panelWidth","Number","parseFloat","String","rightInset","isFinite","undefined","document","documentElement","property","style","removeProperty","setProperty","handleTabChange","e","val","aria-label","open","position","elevation","enableColorOnDark","onChange","backgroundColor","top","map","iconPosition","minHeight","typography","pxToRem","lineHeight","aglyn"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/aside-panel.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 { canvas, NODE_ROOT_ID } from '@aglyn/aglyn'\nimport * as Besigner from '@aglyn/besigner'\nimport {\n type BesignerPanelKey,\n BesignerPanelTabFlag,\n} from '@aglyn/besigner'\nimport {\n ICON_VARIANT_ELEMENT,\n ICON_VARIANT_ELEMENT_BROWSE,\n ICON_VARIANT_ELEMENT_INTERACTIONS,\n ICON_VARIANT_ELEMENT_PROPERTIES,\n ICON_VARIANT_ELEMENT_STYLES,\n ICON_VARIANT_ELEMENT_TREE_VIEW,\n ICON_VARIANT_MODIFY_ADD,\n} from '@aglyn/shared-data-enums'\nimport { HelpTip, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { mergeSxProps, styled } from '@aglyn/shared-ui-theme'\nimport {\n getDisplayName,\n numberFromHexadecimal,\n numberToHexadecimal,\n} from '@aglyn/shared-util-tools'\nimport { hoistNonReactStatics } from '@aglyn/shared-util-vendor'\nimport {\n TabContext as MuiTabContext,\n TabList as MuiTabList,\n TabPanel as MuiTabPanel,\n type TabPanelProps as MuiTabPanelProps,\n} from '@mui/lab'\nimport {\n AppBar as MuiAppBar,\n Box,\n Button,\n Chip,\n Stack,\n Tab as MuiTab,\n Typography,\n} from '@mui/material'\nimport { observer } from 'mobx-react-lite'\nimport {\n type ComponentType,\n forwardRef,\n type SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react'\nimport useAddElementDrawerCallback from '../hooks/use-add-element-drawer-callback'\nimport useAglynBesignerPanel from '../hooks/use-aglyn-besigner-panel'\nimport AccordionListComponent from './accordion-list.component'\nimport ElementInteractionsForm from './element-interactions-form.component'\nimport ComponentAccordionList from './component-accordion-list'\nimport ElementPropsForm from './element-props-form.component'\nimport ElementStylesForm from './element-styles-form.component'\nimport NodeTreeView, { type NodeTreeViewProps } from './node-tree-view'\nimport SiteThemeColorTokensProvider from './site-theme-color-tokens-provider.component'\nimport { usePublishActiveHostTheme } from '../utils/active-host-theme'\nimport { besignerInspected } from '../contexts/inspected-selection'\nimport {\n type LayoutElementSelection,\n layoutStyleSelection,\n} from '../contexts/layout-style-selection'\nimport {\n inspectorExtrasFor,\n useBesignerInspectorExtras,\n} from '../contexts/inspector-extras-context'\nimport { besignerDocsUrl } from '../utils/docs-help'\nimport WorkspacePanelComponent, {\n type WorkspacePanelComponentProps,\n} from './workspace-panel.component'\n\nconst TabPanel = styled(MuiTabPanel, {\n name: 'AglynTabPanel',\n})<MuiTabPanelProps>({\n padding: 0,\n overflow: 'auto',\n height: '100%',\n})\nconst TabPanelInner = styled('div', {\n name: 'AglynTabPanelInner',\n})(({ theme }) => ({\n width: '100%',\n}))\n\nconst emptyView = (\n <Stack\n direction=\"column\"\n component={TabPanelInner}\n sx={{\n justifyContent: 'center',\n height: 1,\n p: 2,\n }}\n >\n <Typography\n color=\"textSecondary\"\n variant=\"overline\"\n component=\"div\"\n align=\"center\"\n >\n <MdiIcon\n sx={{ opacity: 0.3, fontSize: 80 }}\n path={ICON_VARIANT_ELEMENT.path}\n />\n <div>{'Select an element'}</div>\n </Typography>\n </Stack>\n)\n\n\n/**\n * `Hero · Section` with a `SELECTED` tag — the inspector header the\n * `/product` hero mockup shows (AGL-2175).\n *\n * The right panel had no header at all: three tabs of controls with\n * nothing naming what they act on. On a canvas where clicking a child\n * moves the selection under you, that is the difference between editing\n * the section and editing the heading inside it — and the panel looked\n * identical either way.\n *\n * The second half is the COMPONENT, not a category: `labelShort` is the\n * preset's name (`Hero`) and the schema's is what it actually is\n * (`Section`). They are the same word often enough that it is dropped\n * when it would only repeat itself.\n */\nconst SelectedNodeHeader = observer(\n ({ node }: { node: Besigner.LastSelectedNode }) => {\n const name = node?.labelShort ?? ''\n const component = (node as { componentSchema?: { displayName?: string } })\n ?.componentSchema?.displayName\n const subtitle =\n component && component.toLowerCase() !== name.toLowerCase()\n ? `${name} · ${component}`\n : name\n return (\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{\n alignItems: 'center',\n px: 2,\n py: 1,\n borderBottom: 1,\n borderColor: 'divider',\n }}\n >\n <Typography variant=\"subtitle2\" noWrap sx={{ flex: 1, minWidth: 0 }}>\n {subtitle || 'Element'}\n </Typography>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color=\"secondary\"\n label=\"SELECTED\"\n sx={{ height: 18, '& .MuiChip-label': { px: 0.75, fontSize: 10 } }}\n />\n </Stack>\n )\n },\n)\nSelectedNodeHeader.displayName = 'SelectedNodeHeader'\n\n/**\n * The panel while a shared-layout element is the target (AGL-3286): named in\n * the header like any selection, and marked as the layout's, styles only.\n */\nconst LayoutElementHeader = ({\n selection,\n}: {\n selection: LayoutElementSelection\n}) => (\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{\n alignItems: 'center',\n px: 2,\n py: 1,\n borderBottom: 1,\n borderColor: 'divider',\n }}\n >\n <Typography variant=\"subtitle2\" noWrap sx={{ flex: 1, minWidth: 0 }}>\n {`${selection.label} · Layout`}\n </Typography>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color=\"info\"\n label=\"STYLES ONLY\"\n sx={{ height: 18, '& .MuiChip-label': { px: 0.75, fontSize: 10 } }}\n />\n </Stack>\n)\n\n/** What the Attributes and Interactions tabs say about a layout element. */\nconst LayoutElementNote = ({\n selection,\n}: {\n selection: LayoutElementSelection\n}) => (\n <Stack spacing={1.5} sx={{ p: 2 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`This element belongs to the shared layout${\n selection.layoutName ? ` \"${selection.layoutName}\"` : ''\n }. Its content is edited in the layout itself — use Edit layout above ` +\n 'the canvas. On this page you can change how it looks on the Styles tab.'}\n </Typography>\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => layoutStyleSelection.clear()}\n >\n {'Back to page elements'}\n </Button>\n </Stack>\n)\n\nfunction withLastSelectedNode<P>(\n WrappedComponent: JSX.ComponentType<P & { node: Besigner.LastSelectedNode }>,\n /**\n * What this tab shows while a layout element is the target (AGL-3286):\n * `styles` hands the wrapped Styles form the screen root and the target;\n * `note` says where the element's content is edited.\n */\n layoutMode: 'styles' | 'note' = 'note',\n) {\n const displayName = getDisplayName(WrappedComponent)\n\n const WithLastSelectedNode = observer((props: P) => {\n const { ...rest } = props\n const layoutTarget = layoutStyleSelection.current\n const selected = Besigner.focus.getLastSelected()\n /**\n * The LIVE node for that selection, re-resolved by id every render\n * (AGL-2486).\n *\n * The focus store holds node OBJECTS, not ids. Anything that replaces the\n * canvas map wholesale — `undo`, `redo`, a co-editing `applyNodes`, a\n * local-draft restore — builds fresh node instances and leaves the store\n * pointing at the pre-restore ones. The panels then read their fields from\n * an orphan and, worse, write back through it: `updateNodeProps` assigns\n * `node.props` on an object the canvas no longer owns, so the edit lands\n * nowhere. Nothing throws and nothing marks the document dirty, so an\n * author sees their new text in the box, an unchanged canvas, and `UP TO\n * DATE` — the reported \"the Text attribute silently discards edits\".\n *\n * Resolving here rather than in the three panels because they share this\n * one seam, and it is `observer`-tracked: `getNode` reads the observable\n * map, so a restore re-renders the panel with the live node instead of\n * leaving stale values in the fields.\n *\n * A node the map no longer has (deleted, or a test node that was never in\n * it) falls back to the stored object, which is exactly today's behaviour\n * for that case — there is no live node to prefer.\n */\n const lastSelected = selected\n ? canvas.getNode(selected.$id) ?? selected\n : selected\n\n if (layoutTarget) {\n // The page's layout overrides are kept on the screen root, so that is\n // the node the Styles form is handed; the target says which slice.\n const root = canvas.getNode(NODE_ROOT_ID)\n return (\n <>\n <LayoutElementHeader selection={layoutTarget} />\n {layoutMode === 'styles' && root ? (\n <WrappedComponent\n node={root}\n {...({ layoutTarget } as any)}\n {...rest}\n />\n ) : (\n <LayoutElementNote selection={layoutTarget} />\n )}\n </>\n )\n }\n\n return (\n <>\n {!lastSelected ? (\n emptyView\n ) : (\n <>\n {/* One header for all three right-panel tabs, so Attributes,\n Styles and Info cannot disagree about what is selected. */}\n <SelectedNodeHeader node={lastSelected} />\n <WrappedComponent node={lastSelected} {...rest} />\n </>\n )}\n </>\n )\n })\n WithLastSelectedNode.displayName = `WithLastSelectedNode(${displayName})`\n hoistNonReactStatics(WithLastSelectedNode, WrappedComponent)\n\n return WithLastSelectedNode\n}\n\nconst withTabPanelInner = (Component: ComponentType<any>) => (props: any) => {\n return (\n <TabPanelInner sx={{ p: 2 }}>\n <Component {...props} />\n </TabPanelInner>\n )\n}\n\n/**\n * The Attributes form with the host app's section beneath it (AGL-2940):\n * whatever `BesignerInspectorExtrasContext` carries, drawn under the\n * selected element's own fields — for that element, when the host supplied\n * a function — and nothing when the host supplied nothing.\n *\n * The selection travels with `editable` (AGL-2908), the same rule the form's\n * own Save as reusable component and Detach actions are drawn under: the\n * canvas root and locked layout chrome answer false. It is read here because\n * a host section has the node and not the editor, and the rule is the drag\n * manager's.\n */\nconst ElementPropsFormWithExtras = (props: any) => {\n const supplied = useBesignerInspectorExtras()\n const inspected = besignerInspected(props.node)\n const extras = inspected ? inspectorExtrasFor(supplied, inspected) : null\n return (\n <>\n <ElementPropsForm {...props} />\n {extras ? <Box sx={{ pt: 2 }}>{extras}</Box> : null}\n </>\n )\n}\n\nconst ElementsTree = forwardRef<any, NodeTreeViewProps>((props, ref) => {\n const handleAddElementClick = useAddElementDrawerCallback()\n return (\n <TabPanelInner sx={{ pl: 0.5 }}>\n <Box\n sx={{\n px: 0.05,\n pb: 1,\n pt: 1,\n display: 'flex',\n alignItems: 'center',\n }}\n >\n <Button\n color=\"primary\"\n startIcon={\n <MdiIcon fontSize=\"inherit\" path={ICON_VARIANT_MODIFY_ADD.path} />\n }\n onClick={() =>\n handleAddElementClick(Besigner.focus.getLastSelected())\n }\n >\n {'Add Element'}\n </Button>\n {/* The hierarchy is the one panel whose rules are not visible in it\n (AGL-2167): which elements accept children, and what dropping on\n an edge does versus dropping in the center. */}\n <HelpTip\n title=\"Drag, drop & hierarchy\"\n excerpt=\"Reparent by dragging here or on the canvas. Containers accept children; dropping on a leaf element makes a sibling instead.\"\n href={besignerDocsUrl('dragDropHierarchy', '#drop-zones-edges-vs-center')}\n sx={{ ml: 'auto', mr: 0.5, fontSize: '0.9em' }}\n />\n </Box>\n <NodeTreeView ref={ref} {...props} />\n </TabPanelInner>\n )\n})\n\nconst panelTabs: Partial<Record<BesignerPanelKey, any>> = {\n panelLeft: {\n defaultTab: BesignerPanelTabFlag.ELEMENTS_TREE,\n panel: {\n id: 'left',\n anchor: 'left',\n 'aria-label': 'left toolbox panel',\n },\n tabs: [\n {\n value: BesignerPanelTabFlag.ELEMENTS_TREE,\n tab: {\n icon: { path: ICON_VARIANT_ELEMENT_TREE_VIEW.path },\n label: 'Hierarchy',\n },\n panel: {\n Component: ElementsTree,\n },\n },\n {\n value: BesignerPanelTabFlag.ELEMENT_BROWSE,\n tab: {\n icon: { path: ICON_VARIANT_ELEMENT_BROWSE.path },\n label: 'Elements',\n },\n panel: {\n Component: ComponentAccordionList,\n },\n },\n ],\n },\n panelRight: {\n // Attributes first and open by default — it is what you reach for on\n // selecting an element. Tab order here is display order only; the flag\n // values are persisted in panel state, so they stay put.\n defaultTab: BesignerPanelTabFlag.ELEMENT_PROPS_FORM,\n panel: {\n id: 'right',\n anchor: 'right',\n 'aria-label': 'right toolbox panel',\n },\n tabs: [\n {\n value: BesignerPanelTabFlag.ELEMENT_PROPS_FORM,\n tab: {\n icon: { path: ICON_VARIANT_ELEMENT_PROPERTIES.path },\n label: 'Attributes',\n },\n panel: {\n Component: withLastSelectedNode(withTabPanelInner(ElementPropsFormWithExtras)),\n },\n },\n {\n value: BesignerPanelTabFlag.ELEMENT_STYLES,\n tab: {\n icon: { path: ICON_VARIANT_ELEMENT_STYLES.path },\n label: 'Styles',\n },\n panel: {\n Component: withLastSelectedNode(ElementStylesForm as any, 'styles'),\n },\n },\n /*\n * Interactions, between Styles and where Info used to be.\n *\n * They lived at the bottom of Attributes, under every field the\n * component declares — below the fold on anything with more than a\n * handful, so an author had no reason to believe the element had any.\n * An interaction is not an attribute: it is a behaviour, authored in a\n * dialog rather than a field, and it belongs beside the styles as a\n * peer.\n *\n * INFO IS GONE. Its two accordions are reference detail about the\n * component and the node's ids — worth having, not worth a tab — and\n * they now sit at the bottom of Attributes, beside the fields they\n * describe. Its flag value stays reserved; panel state is persisted,\n * and a reader whose last session ended on Info would otherwise return\n * to a tab id that means something else.\n */\n {\n value: BesignerPanelTabFlag.ELEMENT_INTERACTIONS,\n tab: {\n icon: { path: ICON_VARIANT_ELEMENT_INTERACTIONS.path },\n label: 'Interactions',\n },\n panel: {\n Component: withLastSelectedNode(\n withTabPanelInner(ElementInteractionsForm as any),\n ),\n },\n },\n ],\n },\n}\n\nexport interface AsidePanelComponentProps extends WorkspacePanelComponentProps {\n panel: BesignerPanelKey\n}\n\nexport const AsidePanelComponent = forwardRef<any, AsidePanelComponentProps>(\n (props, ref) => {\n const { children, panel: panelKey, ...rest } = props\n\n // Republish the page's site theme for surfaces that render OUTSIDE the\n // page tree (AGL-2486). This panel is inside `HostThemeDocumentContext`;\n // the Choose-element dialog — rendered by `withBesignerContext`, which\n // wraps the page — is not, and its element preview was painting the\n // console's brand onto someone else's site.\n usePublishActiveHostTheme()\n\n const [panel, setPanel] = useAglynBesignerPanel(panelKey)\n const {\n panel: { id, ...panelProps },\n defaultTab,\n tabs,\n } = panelTabs[panelKey]\n const { toggled, tab, size } = panel || {}\n const value = tab || defaultTab\n\n // The bottom-right corner belongs to this panel while it is open\n // (AGL-2486), so publish how far a viewport-fixed affordance has to\n // stand off to clear it. A console-dock launcher reads this; the console's\n // own chrome leaves the corner free and never sets it, which is why the\n // variable carries the offset rather than the panel width — an unset\n // variable then means \"the corner is yours\" everywhere else.\n //\n // Kept in an effect on the LIVE panel state so it tracks the author\n // dragging the panel wider or collapsing it, and removed on unmount:\n // navigating from the besigner back into the console must not leave a\n // 395px inset behind on a page with no panel at all.\n // `size` is `string | number` on the panel state, so a numeric width is\n // parsed rather than added to: `'375' + 20` is `'37520'`, which is a\n // perfectly valid CSS length and would park the launcher off-screen.\n const panelWidth = Number.parseFloat(String(size ?? ''))\n const rightInset =\n panelKey === 'panelRight' && toggled && Number.isFinite(panelWidth)\n ? panelWidth + 20\n : null\n useEffect(() => {\n if (panelKey !== 'panelRight') return undefined\n const root = document.documentElement\n const property = '--aglyn-dock-inset-right'\n if (rightInset === null) {\n root.style.removeProperty(property)\n } else {\n root.style.setProperty(property, `${rightInset}px`)\n }\n return () => {\n root.style.removeProperty(property)\n }\n }, [panelKey, rightInset])\n\n const handleTabChange = useCallback(\n (e: SyntheticEvent, val: string) => {\n setPanel((panel) => ({ ...panel, tab: numberFromHexadecimal(val) }))\n },\n [setPanel],\n )\n\n return (\n <WorkspacePanelComponent\n ref={ref}\n id={`aglyn:panel-${id}`}\n aria-label=\"left toolbox panel\"\n size={size}\n open={toggled}\n component=\"aside\"\n {...panelProps}\n {...rest}\n >\n <MuiTabContext value={numberToHexadecimal(value)}>\n <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>\n <MuiAppBar\n color=\"surface\"\n position=\"relative\"\n elevation={0}\n enableColorOnDark\n >\n <MuiTabList\n onChange={handleTabChange}\n variant=\"fullWidth\"\n sx={{\n '& .MuiTab-root': {\n '&.Mui-selected': {\n // Use sx string shorthands instead of palette callbacks so the\n // sx system resolves them via theme.vars (CSS custom-property refs)\n // rather than the static light-mode palette values.\n color: 'text.primary',\n backgroundColor: 'background.paper',\n },\n },\n '& .MuiTabs-indicator': {\n top: 0,\n backgroundColor: 'secondary.main',\n },\n }}\n >\n {tabs.map(({ value, tab: { icon, ...tab } }) => (\n <MuiTab\n key={value}\n // color={'tertiary'}\n value={numberToHexadecimal(value)}\n iconPosition=\"top\"\n icon={<MdiIcon {...icon} fontSize=\"small\" />}\n sx={{\n minHeight: 'unset',\n fontSize: (theme) => theme.typography.pxToRem(12),\n lineHeight: 0.8,\n pt: 1,\n }}\n {...tab}\n />\n ))}\n </MuiTabList>\n </MuiAppBar>\n </Box>\n\n {/* Site-theme color tokens (AGL-588): every COLOR_PICKER field\n in these panels — styles panel, attribute forms, email\n blocks — offers the site palette's token references. */}\n <SiteThemeColorTokensProvider>\n {tabs.map(({ value, panel: { Component, ...panel } }) => (\n <TabPanel\n key={value}\n value={numberToHexadecimal(value)}\n {...panel}\n >\n <Component />\n </TabPanel>\n ))}\n </SiteThemeColorTokensProvider>\n </MuiTabContext>\n\n {children}\n </WorkspacePanelComponent>\n )\n },\n)\n\nAsidePanelComponent.displayName = 'AsidePanelComponent'\nAsidePanelComponent.aglyn = true\n\nexport default AsidePanelComponent\n"],"names":["canvas","NODE_ROOT_ID","Besigner","BesignerPanelTabFlag","ICON_VARIANT_ELEMENT","ICON_VARIANT_ELEMENT_BROWSE","ICON_VARIANT_ELEMENT_INTERACTIONS","ICON_VARIANT_ELEMENT_PROPERTIES","ICON_VARIANT_ELEMENT_STYLES","ICON_VARIANT_ELEMENT_TREE_VIEW","ICON_VARIANT_MODIFY_ADD","HelpTip","MdiIcon","styled","getDisplayName","numberFromHexadecimal","numberToHexadecimal","hoistNonReactStatics","TabContext","MuiTabContext","TabList","MuiTabList","TabPanel","MuiTabPanel","AppBar","MuiAppBar","Box","Button","Chip","Stack","Tab","MuiTab","Typography","observer","forwardRef","useCallback","useEffect","useAddElementDrawerCallback","useAglynBesignerPanel","ElementInteractionsForm","ComponentAccordionList","ElementPropsForm","ElementStylesForm","NodeTreeView","SiteThemeColorTokensProvider","usePublishActiveHostTheme","besignerInspected","layoutStyleSelection","inspectorExtrasFor","useBesignerInspectorExtras","besignerDocsUrl","WorkspacePanelComponent","name","padding","overflow","height","TabPanelInner","theme","width","emptyView","direction","component","sx","justifyContent","p","color","variant","align","opacity","fontSize","path","div","SelectedNodeHeader","node","labelShort","componentSchema","displayName","subtitle","toLowerCase","spacing","alignItems","px","py","borderBottom","borderColor","noWrap","flex","minWidth","size","label","LayoutElementHeader","selection","LayoutElementNote","layoutName","onClick","clear","withLastSelectedNode","WrappedComponent","layoutMode","WithLastSelectedNode","props","rest","layoutTarget","current","selected","focus","getLastSelected","lastSelected","getNode","$id","root","withTabPanelInner","Component","ElementPropsFormWithExtras","supplied","inspected","extras","pt","ElementsTree","ref","handleAddElementClick","pl","pb","display","startIcon","title","excerpt","href","ml","mr","panelTabs","panelLeft","defaultTab","ELEMENTS_TREE","panel","id","anchor","tabs","value","tab","icon","ELEMENT_BROWSE","panelRight","ELEMENT_PROPS_FORM","ELEMENT_STYLES","ELEMENT_INTERACTIONS","AsidePanelComponent","children","panelKey","setPanel","panelProps","toggled","panelWidth","Number","parseFloat","String","rightInset","isFinite","undefined","document","documentElement","property","style","removeProperty","setProperty","handleTabChange","e","val","aria-label","open","position","elevation","enableColorOnDark","onChange","backgroundColor","top","map","iconPosition","minHeight","typography","pxToRem","lineHeight","aglyn"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,MAAM,EAAEC,YAAY,QAAQ,eAAc;AACnD,YAAYC,cAAc,kBAAiB;AAC3C,SAEEC,oBAAoB,QACf,kBAAiB;AACxB,SACEC,oBAAoB,EACpBC,2BAA2B,EAC3BC,iCAAiC,EACjCC,+BAA+B,EAC/BC,2BAA2B,EAC3BC,8BAA8B,EAC9BC,uBAAuB,QAClB,2BAA0B;AACjC,SAASC,OAAO,EAAEC,OAAO,QAAQ,uBAAsB;AACvD,SAAuBC,MAAM,QAAQ,yBAAwB;AAC7D,SACEC,cAAc,EACdC,qBAAqB,EACrBC,mBAAmB,QACd,2BAA0B;AACjC,SAASC,oBAAoB,QAAQ,4BAA2B;AAChE,SACEC,cAAcC,aAAa,EAC3BC,WAAWC,UAAU,EACrBC,YAAYC,WAAW,QAElB,WAAU;AACjB,SACEC,UAAUC,SAAS,EACnBC,GAAG,EACHC,MAAM,EACNC,IAAI,EACJC,KAAK,EACLC,OAAOC,MAAM,EACbC,UAAU,QACL,gBAAe;AACtB,SAASC,QAAQ,QAAQ,kBAAiB;AAC1C,SAEEC,UAAU,EAEVC,WAAW,EACXC,SAAS,QAGJ,QAAO;AACd,OAAOC,iCAAiC,8CAA0C;AAClF,OAAOC,2BAA2B,uCAAmC;AAErE,OAAOC,6BAA6B,2CAAuC;AAC3E,OAAOC,4BAA4B,gCAA4B;AAC/D,OAAOC,sBAAsB,oCAAgC;AAC7D,OAAOC,uBAAuB,qCAAiC;AAC/D,OAAOC,kBAA8C,sBAAkB;AACvE,OAAOC,kCAAkC,kDAA8C;AACvF,SAASC,yBAAyB,QAAQ,gCAA4B;AACtE,SAASC,iBAAiB,QAAQ,qCAAiC;AACnE,SAEEC,oBAAoB,QACf,wCAAoC;AAC3C,SACEC,kBAAkB,EAClBC,0BAA0B,QACrB,0CAAsC;AAC7C,SAASC,eAAe,QAAQ,wBAAoB;AACpD,OAAOC,6BAEA,iCAA6B;AAEpC,MAAM7B,WAAWT,OAAOU,aAAa;IACnC6B,MAAM;AACR,GAAqB;IACnBC,SAAS;IACTC,UAAU;IACVC,QAAQ;AACV;AACA,MAAMC,gBAAgB3C,OAAO,OAAO;IAClCuC,MAAM;AACR,GAAG,CAAC,EAAEK,KAAK,EAAE,GAAM,CAAA;QACjBC,OAAO;IACT,CAAA;AAEA,MAAMC,0BACJ,KAAC9B;IACC+B,WAAU;IACVC,WAAWL;IACXM,IAAI;QACFC,gBAAgB;QAChBR,QAAQ;QACRS,GAAG;IACL;cAEA,cAAA,MAAChC;QACCiC,OAAM;QACNC,SAAQ;QACRL,WAAU;QACVM,OAAM;;0BAEN,KAACvD;gBACCkD,IAAI;oBAAEM,SAAS;oBAAKC,UAAU;gBAAG;gBACjCC,MAAMlE,qBAAqBkE,IAAI;;0BAEjC,KAACC;0BAAK;;;;;AAMZ;;;;;;;;;;;;;;CAcC,GACD,MAAMC,qBAAqBvC,SACzB,CAAC,EAAEwC,IAAI,EAAuC;;QAE1B;IADlB,MAAMrB,eAAOqB,wBAAAA,KAAMC,UAAU,mBAAI;IACjC,MAAMb,YAAaY,yBAAD,wBAAA,AAACA,KACfE,eAAe,qBADD,sBACGC,WAAW;IAChC,MAAMC,WACJhB,aAAaA,UAAUiB,WAAW,OAAO1B,KAAK0B,WAAW,KACrD,GAAG1B,KAAK,GAAG,EAAES,WAAW,GACxBT;IACN,qBACE,MAACvB;QACC+B,WAAU;QACVmB,SAAS;QACTjB,IAAI;YACFkB,YAAY;YACZC,IAAI;YACJC,IAAI;YACJC,cAAc;YACdC,aAAa;QACf;;0BAEA,KAACpD;gBAAWkC,SAAQ;gBAAYmB,MAAM;gBAACvB,IAAI;oBAAEwB,MAAM;oBAAGC,UAAU;gBAAE;0BAC/DV,YAAY;;0BAEf,KAACjD;gBACC4D,MAAK;gBACLtB,SAAQ;gBACRD,OAAM;gBACNwB,OAAM;gBACN3B,IAAI;oBAAEP,QAAQ;oBAAI,oBAAoB;wBAAE0B,IAAI;wBAAMZ,UAAU;oBAAG;gBAAE;;;;AAIzE;AAEFG,mBAAmBI,WAAW,GAAG;AAEjC;;;CAGC,GACD,MAAMc,sBAAsB,CAAC,EAC3BC,SAAS,EAGV,iBACC,MAAC9D;QACC+B,WAAU;QACVmB,SAAS;QACTjB,IAAI;YACFkB,YAAY;YACZC,IAAI;YACJC,IAAI;YACJC,cAAc;YACdC,aAAa;QACf;;0BAEA,KAACpD;gBAAWkC,SAAQ;gBAAYmB,MAAM;gBAACvB,IAAI;oBAAEwB,MAAM;oBAAGC,UAAU;gBAAE;0BAC/D,GAAGI,UAAUF,KAAK,CAAC,SAAS,CAAC;;0BAEhC,KAAC7D;gBACC4D,MAAK;gBACLtB,SAAQ;gBACRD,OAAM;gBACNwB,OAAM;gBACN3B,IAAI;oBAAEP,QAAQ;oBAAI,oBAAoB;wBAAE0B,IAAI;wBAAMZ,UAAU;oBAAG;gBAAE;;;;AAKvE,0EAA0E,GAC1E,MAAMuB,oBAAoB,CAAC,EACzBD,SAAS,EAGV,iBACC,MAAC9D;QAAMkD,SAAS;QAAKjB,IAAI;YAAEE,GAAG;QAAE;;0BAC9B,KAAChC;gBAAWkC,SAAQ;gBAAQD,OAAM;0BAC/B,CAAC,yCAAyC,EACzC0B,UAAUE,UAAU,GAAG,CAAC,EAAE,EAAEF,UAAUE,UAAU,CAAC,CAAC,CAAC,GAAG,GACvD,qEAAqE,CAAC,GACrE;;0BAEJ,KAAClE;gBACC6D,MAAK;gBACLtB,SAAQ;gBACR4B,SAAS,IAAM/C,qBAAqBgD,KAAK;0BAExC;;;;AAKP,SAASC,qBACPC,gBAA4E,EAC5E;;;;GAIC,GACDC,aAAgC,MAAM;IAEtC,MAAMtB,cAAc9D,eAAemF;IAEnC,MAAME,uBAAuBlE,SAAS,CAACmE;YA4BjCpG;QA3BJ,MAAM,EAAW,GAAGoG,OAATC,oBAASD;QACpB,MAAME,eAAevD,qBAAqBwD,OAAO;QACjD,MAAMC,WAAWtG,SAASuG,KAAK,CAACC,eAAe;QAC/C;;;;;;;;;;;;;;;;;;;;;;KAsBC,GACD,MAAMC,eAAeH,YACjBxG,kBAAAA,OAAO4G,OAAO,CAACJ,SAASK,GAAG,aAA3B7G,kBAAgCwG,WAChCA;QAEJ,IAAIF,cAAc;YAChB,sEAAsE;YACtE,mEAAmE;YACnE,MAAMQ,OAAO9G,OAAO4G,OAAO,CAAC3G;YAC5B,qBACE;;kCACE,KAACyF;wBAAoBC,WAAWW;;oBAC/BJ,eAAe,YAAYY,qBAC1B,KAACb;wBACCxB,MAAMqC;uBACD;wBAAER;oBAAa,GAChBD,uBAGN,KAACT;wBAAkBD,WAAWW;;;;QAItC;QAEA,qBACE;sBACG,CAACK,eACAhD,0BAEA;;kCAGE,KAACa;wBAAmBC,MAAMkC;;kCAC1B,KAACV;wBAAiBxB,MAAMkC;uBAAkBN;;;;IAKpD;IACAF,qBAAqBvB,WAAW,GAAG,CAAC,qBAAqB,EAAEA,YAAY,CAAC,CAAC;IACzE3D,qBAAqBkF,sBAAsBF;IAE3C,OAAOE;AACT;AAEA,MAAMY,oBAAoB,CAACC,YAAkC,CAACZ;QAC5D,qBACE,KAAC5C;YAAcM,IAAI;gBAAEE,GAAG;YAAE;sBACxB,cAAA,KAACgD,wBAAcZ;;IAGrB;AAEA;;;;;;;;;;;CAWC,GACD,MAAMa,6BAA6B,CAACb;IAClC,MAAMc,WAAWjE;IACjB,MAAMkE,YAAYrE,kBAAkBsD,MAAM3B,IAAI;IAC9C,MAAM2C,SAASD,YAAYnE,mBAAmBkE,UAAUC,aAAa;IACrE,qBACE;;0BACE,KAAC1E,+BAAqB2D;YACrBgB,uBAAS,KAAC1F;gBAAIoC,IAAI;oBAAEuD,IAAI;gBAAE;0BAAID;iBAAgB;;;AAGrD;AAEA,MAAME,6BAAepF,WAAmC,CAACkE,OAAOmB;IAC9D,MAAMC,wBAAwBnF;IAC9B,qBACE,MAACmB;QAAcM,IAAI;YAAE2D,IAAI;QAAI;;0BAC3B,MAAC/F;gBACCoC,IAAI;oBACFmB,IAAI;oBACJyC,IAAI;oBACJL,IAAI;oBACJM,SAAS;oBACT3C,YAAY;gBACd;;kCAEA,KAACrD;wBACCsC,OAAM;wBACN2D,yBACE,KAAChH;4BAAQyD,UAAS;4BAAUC,MAAM5D,wBAAwB4D,IAAI;;wBAEhEwB,SAAS,IACP0B,sBAAsBtH,SAASuG,KAAK,CAACC,eAAe;kCAGrD;;kCAKH,KAAC/F;wBACCkH,OAAM;wBACNC,SAAQ;wBACRC,MAAM7E,gBAAgB,qBAAqB;wBAC3CY,IAAI;4BAAEkE,IAAI;4BAAQC,IAAI;4BAAK5D,UAAU;wBAAQ;;;;0BAGjD,KAAC1B;gBAAa4E,KAAKA;eAASnB;;;AAGlC;AAEA,MAAM8B,YAAoD;IACxDC,WAAW;QACTC,YAAYjI,qBAAqBkI,aAAa;QAC9CC,OAAO;YACLC,IAAI;YACJC,QAAQ;YACR,cAAc;QAChB;QACAC,MAAM;YACJ;gBACEC,OAAOvI,qBAAqBkI,aAAa;gBACzCM,KAAK;oBACHC,MAAM;wBAAEtE,MAAM7D,+BAA+B6D,IAAI;oBAAC;oBAClDmB,OAAO;gBACT;gBACA6C,OAAO;oBACLtB,WAAWM;gBACb;YACF;YACA;gBACEoB,OAAOvI,qBAAqB0I,cAAc;gBAC1CF,KAAK;oBACHC,MAAM;wBAAEtE,MAAMjE,4BAA4BiE,IAAI;oBAAC;oBAC/CmB,OAAO;gBACT;gBACA6C,OAAO;oBACLtB,WAAWxE;gBACb;YACF;SACD;IACH;IACAsG,YAAY;QACV,qEAAqE;QACrE,uEAAuE;QACvE,yDAAyD;QACzDV,YAAYjI,qBAAqB4I,kBAAkB;QACnDT,OAAO;YACLC,IAAI;YACJC,QAAQ;YACR,cAAc;QAChB;QACAC,MAAM;YACJ;gBACEC,OAAOvI,qBAAqB4I,kBAAkB;gBAC9CJ,KAAK;oBACHC,MAAM;wBAAEtE,MAAM/D,gCAAgC+D,IAAI;oBAAC;oBACnDmB,OAAO;gBACT;gBACA6C,OAAO;oBACLtB,WAAWhB,qBAAqBe,kBAAkBE;gBACpD;YACF;YACA;gBACEyB,OAAOvI,qBAAqB6I,cAAc;gBAC1CL,KAAK;oBACHC,MAAM;wBAAEtE,MAAM9D,4BAA4B8D,IAAI;oBAAC;oBAC/CmB,OAAO;gBACT;gBACA6C,OAAO;oBACLtB,WAAWhB,qBAAqBtD,mBAA0B;gBAC5D;YACF;YACA;;;;;;;;;;;;;;;;OAgBC,GACD;gBACEgG,OAAOvI,qBAAqB8I,oBAAoB;gBAChDN,KAAK;oBACHC,MAAM;wBAAEtE,MAAMhE,kCAAkCgE,IAAI;oBAAC;oBACrDmB,OAAO;gBACT;gBACA6C,OAAO;oBACLtB,WAAWhB,qBACTe,kBAAkBxE;gBAEtB;YACF;SACD;IACH;AACF;AAMA,OAAO,MAAM2G,oCAAsBhH,WACjC,CAACkE,OAAOmB;IACN,MAAM,EAAE4B,QAAQ,EAAEb,OAAOc,QAAQ,EAAW,GAAGhD,OAATC,wCAASD;;;;IAE/C,uEAAuE;IACvE,yEAAyE;IACzE,uEAAuE;IACvE,oEAAoE;IACpE,4CAA4C;IAC5CvD;IAEA,MAAM,CAACyF,OAAOe,SAAS,GAAG/G,sBAAsB8G;IAChD,MAIIlB,sBAAAA,SAAS,CAACkB,SAAS,EAJjB,EACJd,WAAAA,EAGD,GAAGJ,qBAHK,EAAEK,EAAE,EAAiB,SAAZe;;QADZ,EAEJlB,UAAU,EACVK,IAAI,EACL,GAAGP;IACJ,MAAM,EAAEqB,OAAO,EAAEZ,GAAG,EAAEnD,IAAI,EAAE,GAAG8C,SAAS,CAAC;IACzC,MAAMI,QAAQC,OAAOP;IAErB,iEAAiE;IACjE,oEAAoE;IACpE,2EAA2E;IAC3E,wEAAwE;IACxE,qEAAqE;IACrE,6DAA6D;IAC7D,EAAE;IACF,oEAAoE;IACpE,qEAAqE;IACrE,sEAAsE;IACtE,qDAAqD;IACrD,wEAAwE;IACxE,qEAAqE;IACrE,qEAAqE;IACrE,MAAMoB,aAAaC,OAAOC,UAAU,CAACC,OAAOnE,eAAAA,OAAQ;IACpD,MAAMoE,aACJR,aAAa,gBAAgBG,WAAWE,OAAOI,QAAQ,CAACL,cACpDA,aAAa,KACb;IACNpH,UAAU;QACR,IAAIgH,aAAa,cAAc,OAAOU;QACtC,MAAMhD,OAAOiD,SAASC,eAAe;QACrC,MAAMC,WAAW;QACjB,IAAIL,eAAe,MAAM;YACvB9C,KAAKoD,KAAK,CAACC,cAAc,CAACF;QAC5B,OAAO;YACLnD,KAAKoD,KAAK,CAACE,WAAW,CAACH,UAAU,GAAGL,WAAW,EAAE,CAAC;QACpD;QACA,OAAO;YACL9C,KAAKoD,KAAK,CAACC,cAAc,CAACF;QAC5B;IACF,GAAG;QAACb;QAAUQ;KAAW;IAEzB,MAAMS,kBAAkBlI,YACtB,CAACmI,GAAmBC;QAClBlB,SAAS,CAACf,QAAW,aAAKA;gBAAOK,KAAK5H,sBAAsBwJ;;IAC9D,GACA;QAAClB;KAAS;IAGZ,qBACE,MAAClG;QACCoE,KAAKA;QACLgB,IAAI,CAAC,YAAY,EAAEA,IAAI;QACvBiC,cAAW;QACXhF,MAAMA;QACNiF,MAAMlB;QACN1F,WAAU;OACNyF,YACAjD;;0BAEJ,MAAClF;gBAAcuH,OAAO1H,oBAAoB0H;;kCACxC,KAAChH;wBAAIoC,IAAI;4BAAEqB,cAAc;4BAAGC,aAAa;wBAAU;kCACjD,cAAA,KAAC3D;4BACCwC,OAAM;4BACNyG,UAAS;4BACTC,WAAW;4BACXC,iBAAiB;sCAEjB,cAAA,KAACvJ;gCACCwJ,UAAUR;gCACVnG,SAAQ;gCACRJ,IAAI;oCACF,kBAAkB;wCAChB,kBAAkB;4CAChB,+DAA+D;4CAC/D,oEAAoE;4CACpE,oDAAoD;4CACpDG,OAAO;4CACP6G,iBAAiB;wCACnB;oCACF;oCACA,wBAAwB;wCACtBC,KAAK;wCACLD,iBAAiB;oCACnB;gCACF;0CAECrC,KAAKuC,GAAG,CAAC;wCAAC,EAAEtC,KAAK,EAAEC,SAAAA,EAAuB,OAAlB,EAAEC,IAAI,EAAU,SAALD;;;yDAClC,KAAC5G;wCAEC,qBAAqB;wCACrB2G,OAAO1H,oBAAoB0H;wCAC3BuC,cAAa;wCACbrC,oBAAM,KAAChI,sBAAYgI;4CAAMvE,UAAS;;wCAClCP,IAAI;4CACFoH,WAAW;4CACX7G,UAAU,CAACZ,QAAUA,MAAM0H,UAAU,CAACC,OAAO,CAAC;4CAC9CC,YAAY;4CACZhE,IAAI;wCACN;uCACIsB,MAXCD;;;;;kCAqBf,KAAC9F;kCACE6F,KAAKuC,GAAG,CAAC;gCAAC,EAAEtC,KAAK,EAAEJ,WAAAA,EAAgC,OAAzB,EAAEtB,SAAS,EAAY,SAAPsB;;;iDACzC,KAAChH;gCAECoH,OAAO1H,oBAAoB0H;+BACvBJ;0CAEJ,cAAA,KAACtB;gCAJI0B;;;;;YAUZS;;;AAGP,GACD;AAEDD,oBAAoBtE,WAAW,GAAG;AAClCsE,oBAAoBoC,KAAK,GAAG;AAE5B,eAAepC,oBAAmB"}
@@ -20,12 +20,69 @@ import { FieldMuteButton } from "@aglyn/shared-ui-jsx-forms";
20
20
  import { Autocomplete, Chip, TextField } from "@mui/material";
21
21
  import { action } from "mobx";
22
22
  import { observer } from "mobx-react-lite";
23
- import { useCallback, useMemo } from "react";
23
+ import { memo, useCallback, useMemo } from "react";
24
24
  import useAglynBesignerFlag from "../hooks/use-aglyn-besigner-flag.js";
25
25
  import { toggleRevealedNodeId } from "../utils/canvas-reveal.js";
26
26
  import { isClassMuted, isClassSwitchable, toggleMutedClass } from "../utils/muted-classes.js";
27
27
  /** Valid CSS class identifier (letters, digits, hyphen, underscore). */ const CLASS_NAME_PATTERN = /^-?[_a-zA-Z][_a-zA-Z0-9-]*$/;
28
28
  export const isValidClassName = (name)=>CLASS_NAME_PATTERN.test(name);
29
+ /** Free-text only: there is no list of classes to choose from. */ const NO_OPTIONS = [];
30
+ /**
31
+ * The class chips themselves, MEMOIZED on props that hold still while the
32
+ * classes and their switches do (AGL-3423).
33
+ *
34
+ * A multiple Autocomplete hands its input a new chip array as
35
+ * `startAdornment` on every render, and MUI's `InputBase` copies that into
36
+ * its `FormControl` from a passive effect: a state update left pending after
37
+ * every commit the field takes part in. React 19 counts each such commit as
38
+ * a nested update, and keystrokes delivered back to back elsewhere in the
39
+ * panel commit one after another with nothing to clear the count, so the
40
+ * fifty-first throws "Maximum update depth exceeded" (#185). The field above
41
+ * is an `observer` of `node.props`, which every attribute commit replaces;
42
+ * kept out of those renders, the chips commit only when they change.
43
+ */ const ElementClassesChips = /*#__PURE__*/ memo(function ElementClassesChips(props) {
44
+ const { classes, isSwitchedOff, onToggle, onChange } = props;
45
+ return /*#__PURE__*/ _jsx(Autocomplete, {
46
+ multiple: true,
47
+ freeSolo: true,
48
+ size: "small",
49
+ options: NO_OPTIONS,
50
+ value: classes,
51
+ onChange: onChange,
52
+ renderValue: (value, getItemProps)=>value.map((option, index)=>{
53
+ const off = isSwitchedOff(option);
54
+ const switchable = isClassSwitchable(option);
55
+ return /*#__PURE__*/ _createElement(Chip, _extends({
56
+ label: option,
57
+ size: "small"
58
+ }, getItemProps({
59
+ index
60
+ }), {
61
+ key: option,
62
+ variant: off ? 'outlined' : 'filled',
63
+ sx: off ? {
64
+ textDecoration: 'line-through',
65
+ opacity: 0.6
66
+ } : undefined,
67
+ icon: /*#__PURE__*/ _jsx(FieldMuteButton, {
68
+ mute: {
69
+ muted: off,
70
+ label: switchable ? off ? `Apply ${option} again` : `Stop applying ${option} while designing` : off ? `Stop showing this element on the canvas` : `Show this element on the canvas`,
71
+ onToggle: ()=>onToggle(option)
72
+ },
73
+ sx: {
74
+ ml: 0.5
75
+ }
76
+ })
77
+ }));
78
+ }),
79
+ renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
80
+ label: "Classes",
81
+ placeholder: "Add class…",
82
+ helperText: "Custom CSS classes — targetable from theme styles and interactions"
83
+ }))
84
+ });
85
+ });
29
86
  /**
30
87
  * Custom CSS classes on the selected element (AGL-335): chips persisted
31
88
  * into `node.props.className` (space-separated), merged into the
@@ -93,45 +150,11 @@ export const isValidClassName = (name)=>CLASS_NAME_PATTERN.test(name);
93
150
  }, [
94
151
  node
95
152
  ]);
96
- return /*#__PURE__*/ _jsx(Autocomplete, {
97
- multiple: true,
98
- freeSolo: true,
99
- size: "small",
100
- options: [],
101
- value: classes,
102
- onChange: handleChange,
103
- renderValue: (value, getItemProps)=>value.map((option, index)=>{
104
- const off = isSwitchedOff(option);
105
- const switchable = isClassSwitchable(option);
106
- return /*#__PURE__*/ _createElement(Chip, _extends({
107
- label: option,
108
- size: "small"
109
- }, getItemProps({
110
- index
111
- }), {
112
- key: option,
113
- variant: off ? 'outlined' : 'filled',
114
- sx: off ? {
115
- textDecoration: 'line-through',
116
- opacity: 0.6
117
- } : undefined,
118
- icon: /*#__PURE__*/ _jsx(FieldMuteButton, {
119
- mute: {
120
- muted: off,
121
- label: switchable ? off ? `Apply ${option} again` : `Stop applying ${option} while designing` : off ? `Stop showing this element on the canvas` : `Show this element on the canvas`,
122
- onToggle: ()=>toggleClass(option)
123
- },
124
- sx: {
125
- ml: 0.5
126
- }
127
- })
128
- }));
129
- }),
130
- renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
131
- label: "Classes",
132
- placeholder: "Add class…",
133
- helperText: "Custom CSS classes — targetable from theme styles and interactions"
134
- }))
153
+ return /*#__PURE__*/ _jsx(ElementClassesChips, {
154
+ classes: classes,
155
+ isSwitchedOff: isSwitchedOff,
156
+ onToggle: toggleClass,
157
+ onChange: handleChange
135
158
  });
136
159
  });
137
160
  ElementClassesField.displayName = 'ElementClassesField';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/element-classes-field.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 { FieldMuteButton } from '@aglyn/shared-ui-jsx-forms'\nimport { Autocomplete, Chip, TextField } from '@mui/material'\nimport { action } from 'mobx'\nimport { observer } from 'mobx-react-lite'\nimport { useCallback, useMemo } from 'react'\n\nimport useAglynBesignerFlag from '../hooks/use-aglyn-besigner-flag'\nimport { toggleRevealedNodeId } from '../utils/canvas-reveal'\nimport {\n isClassMuted,\n isClassSwitchable,\n toggleMutedClass,\n} from '../utils/muted-classes'\n\n/** Valid CSS class identifier (letters, digits, hyphen, underscore). */\nconst CLASS_NAME_PATTERN = /^-?[_a-zA-Z][_a-zA-Z0-9-]*$/\n\nexport const isValidClassName = (name: string): boolean =>\n CLASS_NAME_PATTERN.test(name)\n\nexport interface ElementClassesFieldProps {\n node?: Aglyn.NodeSchema\n}\n\n/**\n * Custom CSS classes on the selected element (AGL-335): chips persisted\n * into `node.props.className` (space-separated), merged into the\n * rendered className by the node renderer. Pairs with theme stylesheet\n * classes and the interaction builder's class actions.\n *\n * Each chip carries an eye as well as its ✕ (AGL-2486). The eye stops the\n * class applying ON THE CANVAS and keeps it on the element; the ✕ is still\n * the one control that takes a class off. Nothing about the eye is written\n * down, so the chips are always the class list that ships.\n *\n * The hidden class is the exception, and deliberately so: switching it off\n * on the canvas is the same act as the hierarchy's visibility eye (AGL-592),\n * so its chip drives THAT state rather than a second one that could\n * disagree with it.\n */\nexport const ElementClassesField = observer(\n (props: ElementClassesFieldProps) => {\n const { node } = props\n const classes = useMemo(\n () =>\n String((node?.props as any)?.className ?? '')\n .split(/\\s+/)\n .filter(Boolean),\n [(node?.props as any)?.className],\n )\n\n const [mutedClasses, setMutedClasses] = useAglynBesignerFlag('mutedClasses')\n const [revealedNodeIds, setRevealedNodeIds] =\n useAglynBesignerFlag('revealedNodeIds')\n\n const nodeId = node?.$id\n\n /** Whether the canvas is currently rendering without this class. */\n const isSwitchedOff = useCallback(\n (className: string) => {\n if (!nodeId) return false\n return isClassSwitchable(className)\n ? isClassMuted(mutedClasses, { nodeId, className })\n : Boolean(revealedNodeIds?.some((id) => id === nodeId))\n },\n [nodeId, mutedClasses, revealedNodeIds],\n )\n\n const toggleClass = useCallback(\n (className: string) => {\n if (!nodeId) return\n if (isClassSwitchable(className)) {\n setMutedClasses((current) =>\n toggleMutedClass(current, { nodeId, className }),\n )\n return\n }\n // One switch, two places to reach it.\n setRevealedNodeIds((current) => toggleRevealedNodeId(current, nodeId))\n },\n [nodeId, setMutedClasses, setRevealedNodeIds],\n )\n\n const handleChange = useCallback(\n (event: unknown, value: string[]) => {\n if (!node) return\n const cleaned = value\n .map((name) => name.trim())\n .filter((name) => isValidClassName(name))\n action(() => {\n const nextProps: Record<string, unknown> = { ...(node.props as any) }\n if (cleaned.length) nextProps['className'] = cleaned.join(' ')\n else delete nextProps['className']\n node.props = nextProps as any\n })()\n },\n [node],\n )\n\n return (\n <Autocomplete\n multiple\n freeSolo\n size=\"small\"\n options={[] as string[]}\n value={classes}\n onChange={handleChange}\n renderValue={(value, getItemProps) =>\n value.map((option, index) => {\n const off = isSwitchedOff(option)\n const switchable = isClassSwitchable(option)\n return (\n <Chip\n label={option}\n size=\"small\"\n {...getItemProps({ index })}\n key={option}\n variant={off ? 'outlined' : 'filled'}\n sx={\n off\n ? { textDecoration: 'line-through', opacity: 0.6 }\n : undefined\n }\n icon={\n <FieldMuteButton\n mute={{\n muted: off,\n label: switchable\n ? off\n ? `Apply ${option} again`\n : `Stop applying ${option} while designing`\n : off\n ? `Stop showing this element on the canvas`\n : `Show this element on the canvas`,\n onToggle: () => toggleClass(option),\n }}\n sx={{ ml: 0.5 }}\n />\n }\n />\n )\n })\n }\n renderInput={(params) => (\n <TextField\n {...params}\n label=\"Classes\"\n placeholder=\"Add class…\"\n helperText=\"Custom CSS classes — targetable from theme styles and interactions\"\n />\n )}\n />\n )\n },\n)\nElementClassesField.displayName = 'ElementClassesField'\n\nexport default ElementClassesField\n"],"names":["FieldMuteButton","Autocomplete","Chip","TextField","action","observer","useCallback","useMemo","useAglynBesignerFlag","toggleRevealedNodeId","isClassMuted","isClassSwitchable","toggleMutedClass","CLASS_NAME_PATTERN","isValidClassName","name","test","ElementClassesField","props","node","classes","String","className","split","filter","Boolean","mutedClasses","setMutedClasses","revealedNodeIds","setRevealedNodeIds","nodeId","$id","isSwitchedOff","some","id","toggleClass","current","handleChange","event","value","cleaned","map","trim","nextProps","length","join","multiple","freeSolo","size","options","onChange","renderValue","getItemProps","option","index","off","switchable","label","key","variant","sx","textDecoration","opacity","undefined","icon","mute","muted","onToggle","ml","renderInput","params","placeholder","helperText","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/components/element-classes-field.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 { FieldMuteButton } from '@aglyn/shared-ui-jsx-forms'\nimport { Autocomplete, Chip, TextField } from '@mui/material'\nimport { action } from 'mobx'\nimport { observer } from 'mobx-react-lite'\nimport { memo, useCallback, useMemo } from 'react'\n\nimport useAglynBesignerFlag from '../hooks/use-aglyn-besigner-flag'\nimport { toggleRevealedNodeId } from '../utils/canvas-reveal'\nimport {\n isClassMuted,\n isClassSwitchable,\n toggleMutedClass,\n} from '../utils/muted-classes'\n\n/** Valid CSS class identifier (letters, digits, hyphen, underscore). */\nconst CLASS_NAME_PATTERN = /^-?[_a-zA-Z][_a-zA-Z0-9-]*$/\n\nexport const isValidClassName = (name: string): boolean =>\n CLASS_NAME_PATTERN.test(name)\n\n/** Free-text only: there is no list of classes to choose from. */\nconst NO_OPTIONS: string[] = []\n\ninterface ElementClassesChipsProps {\n classes: readonly string[]\n isSwitchedOff(className: string): boolean\n onToggle(className: string): void\n onChange(event: unknown, value: string[]): void\n}\n\n/**\n * The class chips themselves, MEMOIZED on props that hold still while the\n * classes and their switches do (AGL-3423).\n *\n * A multiple Autocomplete hands its input a new chip array as\n * `startAdornment` on every render, and MUI's `InputBase` copies that into\n * its `FormControl` from a passive effect: a state update left pending after\n * every commit the field takes part in. React 19 counts each such commit as\n * a nested update, and keystrokes delivered back to back elsewhere in the\n * panel commit one after another with nothing to clear the count, so the\n * fifty-first throws \"Maximum update depth exceeded\" (#185). The field above\n * is an `observer` of `node.props`, which every attribute commit replaces;\n * kept out of those renders, the chips commit only when they change.\n */\nconst ElementClassesChips = memo(function ElementClassesChips(\n props: ElementClassesChipsProps,\n) {\n const { classes, isSwitchedOff, onToggle, onChange } = props\n return (\n <Autocomplete\n multiple\n freeSolo\n size=\"small\"\n options={NO_OPTIONS}\n value={classes as string[]}\n onChange={onChange}\n renderValue={(value, getItemProps) =>\n value.map((option, index) => {\n const off = isSwitchedOff(option)\n const switchable = isClassSwitchable(option)\n return (\n <Chip\n label={option}\n size=\"small\"\n {...getItemProps({ index })}\n key={option}\n variant={off ? 'outlined' : 'filled'}\n sx={\n off\n ? { textDecoration: 'line-through', opacity: 0.6 }\n : undefined\n }\n icon={\n <FieldMuteButton\n mute={{\n muted: off,\n label: switchable\n ? off\n ? `Apply ${option} again`\n : `Stop applying ${option} while designing`\n : off\n ? `Stop showing this element on the canvas`\n : `Show this element on the canvas`,\n onToggle: () => onToggle(option),\n }}\n sx={{ ml: 0.5 }}\n />\n }\n />\n )\n })\n }\n renderInput={(params) => (\n <TextField\n {...params}\n label=\"Classes\"\n placeholder=\"Add class…\"\n helperText=\"Custom CSS classes — targetable from theme styles and interactions\"\n />\n )}\n />\n )\n})\n\n\nexport interface ElementClassesFieldProps {\n node?: Aglyn.NodeSchema\n}\n\n/**\n * Custom CSS classes on the selected element (AGL-335): chips persisted\n * into `node.props.className` (space-separated), merged into the\n * rendered className by the node renderer. Pairs with theme stylesheet\n * classes and the interaction builder's class actions.\n *\n * Each chip carries an eye as well as its ✕ (AGL-2486). The eye stops the\n * class applying ON THE CANVAS and keeps it on the element; the ✕ is still\n * the one control that takes a class off. Nothing about the eye is written\n * down, so the chips are always the class list that ships.\n *\n * The hidden class is the exception, and deliberately so: switching it off\n * on the canvas is the same act as the hierarchy's visibility eye (AGL-592),\n * so its chip drives THAT state rather than a second one that could\n * disagree with it.\n */\nexport const ElementClassesField = observer(\n (props: ElementClassesFieldProps) => {\n const { node } = props\n const classes = useMemo(\n () =>\n String((node?.props as any)?.className ?? '')\n .split(/\\s+/)\n .filter(Boolean),\n [(node?.props as any)?.className],\n )\n\n const [mutedClasses, setMutedClasses] = useAglynBesignerFlag('mutedClasses')\n const [revealedNodeIds, setRevealedNodeIds] =\n useAglynBesignerFlag('revealedNodeIds')\n\n const nodeId = node?.$id\n\n /** Whether the canvas is currently rendering without this class. */\n const isSwitchedOff = useCallback(\n (className: string) => {\n if (!nodeId) return false\n return isClassSwitchable(className)\n ? isClassMuted(mutedClasses, { nodeId, className })\n : Boolean(revealedNodeIds?.some((id) => id === nodeId))\n },\n [nodeId, mutedClasses, revealedNodeIds],\n )\n\n const toggleClass = useCallback(\n (className: string) => {\n if (!nodeId) return\n if (isClassSwitchable(className)) {\n setMutedClasses((current) =>\n toggleMutedClass(current, { nodeId, className }),\n )\n return\n }\n // One switch, two places to reach it.\n setRevealedNodeIds((current) => toggleRevealedNodeId(current, nodeId))\n },\n [nodeId, setMutedClasses, setRevealedNodeIds],\n )\n\n const handleChange = useCallback(\n (event: unknown, value: string[]) => {\n if (!node) return\n const cleaned = value\n .map((name) => name.trim())\n .filter((name) => isValidClassName(name))\n action(() => {\n const nextProps: Record<string, unknown> = { ...(node.props as any) }\n if (cleaned.length) nextProps['className'] = cleaned.join(' ')\n else delete nextProps['className']\n node.props = nextProps as any\n })()\n },\n [node],\n )\n\n return (\n <ElementClassesChips\n classes={classes}\n isSwitchedOff={isSwitchedOff}\n onToggle={toggleClass}\n onChange={handleChange}\n />\n )\n },\n)\nElementClassesField.displayName = 'ElementClassesField'\n\nexport default ElementClassesField\n"],"names":["FieldMuteButton","Autocomplete","Chip","TextField","action","observer","memo","useCallback","useMemo","useAglynBesignerFlag","toggleRevealedNodeId","isClassMuted","isClassSwitchable","toggleMutedClass","CLASS_NAME_PATTERN","isValidClassName","name","test","NO_OPTIONS","ElementClassesChips","props","classes","isSwitchedOff","onToggle","onChange","multiple","freeSolo","size","options","value","renderValue","getItemProps","map","option","index","off","switchable","label","key","variant","sx","textDecoration","opacity","undefined","icon","mute","muted","ml","renderInput","params","placeholder","helperText","ElementClassesField","node","String","className","split","filter","Boolean","mutedClasses","setMutedClasses","revealedNodeIds","setRevealedNodeIds","nodeId","$id","some","id","toggleClass","current","handleChange","event","cleaned","trim","nextProps","length","join","displayName"],"mappings":"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"}
@@ -15,6 +15,18 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  import type { ElementDetail } from '../utils/describe-element';
18
+ import { type BesignerDocsAnchor } from '../utils/docs-help';
19
+ /**
20
+ * Element category → its section of the element catalog page.
21
+ *
22
+ * The catalog's H2s ARE the drawer's categories, so the deep link is derived
23
+ * from the page's own headings rather than mapped by hand per category — a
24
+ * category is its heading's slug (`Data Display` → `#data-display`). A
25
+ * category the page has no section for — a plugin-registered label, "Your
26
+ * components" — lands on the page itself, which is correct rather than
27
+ * broken.
28
+ */
29
+ export declare function elementCatalogAnchor(category: string | undefined): BesignerDocsAnchor<'elementCatalog'> | undefined;
18
30
  export interface ElementDetailViewProps {
19
31
  detail: ElementDetail | null;
20
32
  /**