@aglyn/plugins-mui 1.0.0-beta.223 → 1.0.0-beta.225
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -7
- package/src/lib/components/box.js +6 -0
- package/src/lib/components/box.js.map +1 -1
- package/src/lib/components/button.js +2 -0
- package/src/lib/components/button.js.map +1 -1
- package/src/lib/components/container.js +6 -0
- package/src/lib/components/container.js.map +1 -1
- package/src/lib/components/grid.js +6 -0
- package/src/lib/components/grid.js.map +1 -1
- package/src/lib/components/icon.js +2 -0
- package/src/lib/components/icon.js.map +1 -1
- package/src/lib/components/image.js +2 -0
- package/src/lib/components/image.js.map +1 -1
- package/src/lib/components/inline-text.js +2 -0
- package/src/lib/components/inline-text.js.map +1 -1
- package/src/lib/components/layout-slot.js +4 -0
- package/src/lib/components/layout-slot.js.map +1 -1
- package/src/lib/components/link-box.js +6 -0
- package/src/lib/components/link-box.js.map +1 -1
- package/src/lib/components/list-item-text.js +2 -0
- package/src/lib/components/list-item-text.js.map +1 -1
- package/src/lib/components/list-item.js +4 -0
- package/src/lib/components/list-item.js.map +1 -1
- package/src/lib/components/list.js +4 -0
- package/src/lib/components/list.js.map +1 -1
- package/src/lib/components/paper.js +6 -0
- package/src/lib/components/paper.js.map +1 -1
- package/src/lib/components/screen-link.js +2 -0
- package/src/lib/components/screen-link.js.map +1 -1
- package/src/lib/components/section.js +6 -0
- package/src/lib/components/section.js.map +1 -1
- package/src/lib/components/stack.js +4 -0
- package/src/lib/components/stack.js.map +1 -1
- package/src/lib/components/typography.js +2 -0
- package/src/lib/components/typography.js.map +1 -1
- package/src/lib/utils/image-sizes.js +10 -1
- package/src/lib/utils/image-sizes.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aglyn/plugins-mui",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.225",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"homepage": "https://aglyn.com",
|
|
6
6
|
"repository": {
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
"./package.json": "./package.json"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@aglyn/aglyn": "1.0.0-beta.
|
|
29
|
-
"@aglyn/shared-data-enums": "1.0.0-beta.
|
|
30
|
-
"@aglyn/shared-data-mdi": "1.0.0-beta.
|
|
31
|
-
"@aglyn/shared-ui-jsx": "1.0.0-beta.
|
|
32
|
-
"@aglyn/shared-ui-theme": "1.0.0-beta.
|
|
33
|
-
"@aglyn/shared-util-vendor": "1.0.0-beta.
|
|
28
|
+
"@aglyn/aglyn": "1.0.0-beta.225",
|
|
29
|
+
"@aglyn/shared-data-enums": "1.0.0-beta.225",
|
|
30
|
+
"@aglyn/shared-data-mdi": "1.0.0-beta.225",
|
|
31
|
+
"@aglyn/shared-ui-jsx": "1.0.0-beta.225",
|
|
32
|
+
"@aglyn/shared-ui-theme": "1.0.0-beta.225",
|
|
33
|
+
"@aglyn/shared-util-vendor": "1.0.0-beta.225",
|
|
34
34
|
"@swc/helpers": "0.5.23",
|
|
35
35
|
"mobx": "^7.0.5",
|
|
36
36
|
"mobx-react-lite": "^5.1.0"
|
|
@@ -67,6 +67,12 @@ export const schema = {
|
|
|
67
67
|
$id: ID,
|
|
68
68
|
pluginId: BUNDLE_ID,
|
|
69
69
|
displayName: 'Box',
|
|
70
|
+
// Static, and its children sit directly in its root: a subtree it heads
|
|
71
|
+
// keeps its server HTML until the visitor nears it (AGL-3581).
|
|
72
|
+
flags: {
|
|
73
|
+
lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,
|
|
74
|
+
childrenInRoot: Aglyn.FEATURE_FLAG.ENABLED
|
|
75
|
+
},
|
|
70
76
|
description: 'Generic container with no styling of its own — style it from the ' + 'styles panel.',
|
|
71
77
|
category: Aglyn.ComponentCategory.LAYOUT,
|
|
72
78
|
icon: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/box.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 * as Aglyn from '@aglyn/aglyn'\nimport { mdiSquareOutline } from '@aglyn/shared-data-mdi'\nimport MuiBox from '@mui/material/Box'\nimport { forwardRef, type ReactNode } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { colorSchemeAttribute } from '../utils/color-scheme-attribute'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiBox'\n\n/**\n * Elements Box may render as. Deliberately *not* the landmark set —\n * section/article/nav/header/footer/main belong to the Section element,\n * which also exposes the accessible-name field a landmark needs. Box owns\n * the generic wrappers that carry no document outline.\n *\n * An allow-list rather than a free-text field: `component` is persisted\n * and rendered verbatim, so a typed value would let an author put\n * `script`/`iframe` into every visitor's page.\n */\nexport const BOX_ELEMENTS = [\n 'div',\n 'span',\n 'p',\n 'figure',\n 'figcaption',\n 'blockquote',\n 'pre',\n] as const\nexport type BoxElement = (typeof BOX_ELEMENTS)[number]\n\nexport interface BoxElementProps {\n /** The DOM element rendered; defaults to `div`. */\n component?: BoxElement\n children?: ReactNode\n}\n\n/**\n * The plain styling primitive (https://mui.com/material-ui/react-box/):\n * a wrapper with no opinions of its own, sized/spaced/coloured entirely\n * from the styles panel's `sx`. Use it when the grouping is purely\n * visual; use Section when the grouping means something in the document\n * outline.\n */\nconst BoxElement = forwardRef<HTMLElement, BoxElementProps>((props, ref) => {\n const { component, children, ...rest } = props\n const element = BOX_ELEMENTS.includes(component as BoxElement)\n ? (component as BoxElement)\n : 'div'\n return (\n <MuiBox ref={ref} component={element} {...rest}>\n {children}\n </MuiBox>\n )\n})\nBoxElement.displayName = 'AglynBox'\n\nexport const schema: Aglyn.ComponentSchema<BoxElementProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Box',\n description:\n 'Generic container with no styling of its own — style it from the ' +\n 'styles panel.',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiSquareOutline.path, sx: { color: '#2196f3' } },\n attributes: [\n {\n name: 'component',\n label: 'Component',\n description:\n 'The DOM element this box renders as. For landmarks ' +\n '(section, article, nav, header, footer, main) use the Section ' +\n 'element instead — it also names the landmark for screen readers.',\n component: Aglyn.FieldComponentType.SELECT,\n options: BOX_ELEMENTS.map((value) => ({ value, label: value })),\n },\n colorSchemeAttribute(),\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Box',\n pluginId: BUNDLE_ID,\n description: 'Generic container you style yourself',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n // Ships with padding and a visible outline: an empty, zero-height\n // div is dropped onto the canvas and appears to have done nothing.\n props: { component: 'div' },\n // On the node's own sx, not in props (AGL-1346): the Styles panel\n // edits `node.sx`, so an outline authored in `props.sx` was one no\n // click could remove.\n sx: {\n paddingTop: 2,\n paddingRight: 2,\n paddingBottom: 2,\n paddingLeft: 2,\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n },\n },\n },\n]\n\nexport default BoxElement\n"],"names":["Aglyn","mdiSquareOutline","MuiBox","forwardRef","BUNDLE_ID","colorSchemeAttribute","generatePresetId","ID","BOX_ELEMENTS","BoxElement","props","ref","component","children","rest","element","includes","displayName","schema","$id","pluginId","description","category","ComponentCategory","LAYOUT","icon","path","sx","color","attributes","name","label","FieldComponentType","SELECT","options","map","value","presets","type","NodeType","PRESET","data","componentId","paddingTop","paddingRight","paddingBottom","paddingLeft","border","borderColor","borderRadius"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,gBAAgB,QAAQ,yBAAwB;AACzD,OAAOC,YAAY,oBAAmB;AACtC,SAASC,UAAU,QAAwB,QAAO;AAClD,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,oBAAoB,QAAQ,qCAAiC;AACtE,SAASC,gBAAgB,QAAQ,iCAA6B;AAE9D,iEAAiE;AACjE,OAAO,MAAMC,KAAwB,SAAQ;AAE7C;;;;;;;;;CASC,GACD,OAAO,MAAMC,eAAe;IAC1B;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAS;AASV;;;;;;CAMC,GACD,MAAMC,2BAAaN,WAAyC,CAACO,OAAOC;IAClE,MAAM,EAAEC,SAAS,EAAEC,QAAQ,EAAW,GAAGH,OAATI,wCAASJ;;;;IACzC,MAAMK,UAAUP,aAAaQ,QAAQ,CAACJ,aACjCA,YACD;IACJ,qBACE,KAACV;QAAOS,KAAKA;QAAKC,WAAWG;OAAaD;kBACvCD;;AAGP;AACAJ,WAAWQ,WAAW,GAAG;AAEzB,OAAO,MAAMC,SAAiD;IAC5DC,KAAKZ;IACLa,UAAUhB;IACVa,aAAa;
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/box.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 * as Aglyn from '@aglyn/aglyn'\nimport { mdiSquareOutline } from '@aglyn/shared-data-mdi'\nimport MuiBox from '@mui/material/Box'\nimport { forwardRef, type ReactNode } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { colorSchemeAttribute } from '../utils/color-scheme-attribute'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiBox'\n\n/**\n * Elements Box may render as. Deliberately *not* the landmark set —\n * section/article/nav/header/footer/main belong to the Section element,\n * which also exposes the accessible-name field a landmark needs. Box owns\n * the generic wrappers that carry no document outline.\n *\n * An allow-list rather than a free-text field: `component` is persisted\n * and rendered verbatim, so a typed value would let an author put\n * `script`/`iframe` into every visitor's page.\n */\nexport const BOX_ELEMENTS = [\n 'div',\n 'span',\n 'p',\n 'figure',\n 'figcaption',\n 'blockquote',\n 'pre',\n] as const\nexport type BoxElement = (typeof BOX_ELEMENTS)[number]\n\nexport interface BoxElementProps {\n /** The DOM element rendered; defaults to `div`. */\n component?: BoxElement\n children?: ReactNode\n}\n\n/**\n * The plain styling primitive (https://mui.com/material-ui/react-box/):\n * a wrapper with no opinions of its own, sized/spaced/coloured entirely\n * from the styles panel's `sx`. Use it when the grouping is purely\n * visual; use Section when the grouping means something in the document\n * outline.\n */\nconst BoxElement = forwardRef<HTMLElement, BoxElementProps>((props, ref) => {\n const { component, children, ...rest } = props\n const element = BOX_ELEMENTS.includes(component as BoxElement)\n ? (component as BoxElement)\n : 'div'\n return (\n <MuiBox ref={ref} component={element} {...rest}>\n {children}\n </MuiBox>\n )\n})\nBoxElement.displayName = 'AglynBox'\n\nexport const schema: Aglyn.ComponentSchema<BoxElementProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Box',\n // Static, and its children sit directly in its root: a subtree it heads\n // keeps its server HTML until the visitor nears it (AGL-3581).\n flags: {\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n childrenInRoot: Aglyn.FEATURE_FLAG.ENABLED,\n },\n description:\n 'Generic container with no styling of its own — style it from the ' +\n 'styles panel.',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiSquareOutline.path, sx: { color: '#2196f3' } },\n attributes: [\n {\n name: 'component',\n label: 'Component',\n description:\n 'The DOM element this box renders as. For landmarks ' +\n '(section, article, nav, header, footer, main) use the Section ' +\n 'element instead — it also names the landmark for screen readers.',\n component: Aglyn.FieldComponentType.SELECT,\n options: BOX_ELEMENTS.map((value) => ({ value, label: value })),\n },\n colorSchemeAttribute(),\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Box',\n pluginId: BUNDLE_ID,\n description: 'Generic container you style yourself',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n // Ships with padding and a visible outline: an empty, zero-height\n // div is dropped onto the canvas and appears to have done nothing.\n props: { component: 'div' },\n // On the node's own sx, not in props (AGL-1346): the Styles panel\n // edits `node.sx`, so an outline authored in `props.sx` was one no\n // click could remove.\n sx: {\n paddingTop: 2,\n paddingRight: 2,\n paddingBottom: 2,\n paddingLeft: 2,\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n },\n },\n },\n]\n\nexport default BoxElement\n"],"names":["Aglyn","mdiSquareOutline","MuiBox","forwardRef","BUNDLE_ID","colorSchemeAttribute","generatePresetId","ID","BOX_ELEMENTS","BoxElement","props","ref","component","children","rest","element","includes","displayName","schema","$id","pluginId","flags","lazyHydration","FEATURE_FLAG","ENABLED","childrenInRoot","description","category","ComponentCategory","LAYOUT","icon","path","sx","color","attributes","name","label","FieldComponentType","SELECT","options","map","value","presets","type","NodeType","PRESET","data","componentId","paddingTop","paddingRight","paddingBottom","paddingLeft","border","borderColor","borderRadius"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,gBAAgB,QAAQ,yBAAwB;AACzD,OAAOC,YAAY,oBAAmB;AACtC,SAASC,UAAU,QAAwB,QAAO;AAClD,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,oBAAoB,QAAQ,qCAAiC;AACtE,SAASC,gBAAgB,QAAQ,iCAA6B;AAE9D,iEAAiE;AACjE,OAAO,MAAMC,KAAwB,SAAQ;AAE7C;;;;;;;;;CASC,GACD,OAAO,MAAMC,eAAe;IAC1B;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAS;AASV;;;;;;CAMC,GACD,MAAMC,2BAAaN,WAAyC,CAACO,OAAOC;IAClE,MAAM,EAAEC,SAAS,EAAEC,QAAQ,EAAW,GAAGH,OAATI,wCAASJ;;;;IACzC,MAAMK,UAAUP,aAAaQ,QAAQ,CAACJ,aACjCA,YACD;IACJ,qBACE,KAACV;QAAOS,KAAKA;QAAKC,WAAWG;OAAaD;kBACvCD;;AAGP;AACAJ,WAAWQ,WAAW,GAAG;AAEzB,OAAO,MAAMC,SAAiD;IAC5DC,KAAKZ;IACLa,UAAUhB;IACVa,aAAa;IACb,wEAAwE;IACxE,+DAA+D;IAC/DI,OAAO;QACLC,eAAetB,MAAMuB,YAAY,CAACC,OAAO;QACzCC,gBAAgBzB,MAAMuB,YAAY,CAACC,OAAO;IAC5C;IACAE,aACE,sEACA;IACFC,UAAU3B,MAAM4B,iBAAiB,CAACC,MAAM;IACxCC,MAAM;QAAEC,MAAM9B,iBAAiB8B,IAAI;QAAEC,IAAI;YAAEC,OAAO;QAAU;IAAE;IAC9DC,YAAY;QACV;YACEC,MAAM;YACNC,OAAO;YACPV,aACE,wDACA,mEACA;YACFd,WAAWZ,MAAMqC,kBAAkB,CAACC,MAAM;YAC1CC,SAAS/B,aAAagC,GAAG,CAAC,CAACC,QAAW,CAAA;oBAAEA;oBAAOL,OAAOK;gBAAM,CAAA;QAC9D;QACApC;KACD;AACH,EAAC;AAED,OAAO,MAAMqC,UAAgC;IAC3C;QACEvB,KAAKb,iBAAiBC;QACtBoC,MAAM3C,MAAM4C,QAAQ,CAACC,MAAM;QAC3B5B,aAAa;QACbG,UAAUhB;QACVsB,aAAa;QACbC,UAAU3B,MAAM4B,iBAAiB,CAACC,MAAM;QACxCC,MAAMZ,OAAOY,IAAI;QACjBgB,MAAM;YACJ3B,KAAK;YACL4B,aAAaxC;YACba,UAAUhB;YACV,kEAAkE;YAClE,mEAAmE;YACnEM,OAAO;gBAAEE,WAAW;YAAM;YAC1B,kEAAkE;YAClE,mEAAmE;YACnE,sBAAsB;YACtBoB,IAAI;gBACFgB,YAAY;gBACZC,cAAc;gBACdC,eAAe;gBACfC,aAAa;gBACbC,QAAQ;gBACRC,aAAa;gBACbC,cAAc;YAChB;QACF;IACF;CACD,CAAA;AAED,eAAe7C,WAAU"}
|
|
@@ -148,6 +148,8 @@ export const schema = {
|
|
|
148
148
|
}
|
|
149
149
|
},
|
|
150
150
|
flags: {
|
|
151
|
+
// Static: may sit in a subtree that keeps its server HTML (AGL-3581).
|
|
152
|
+
lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,
|
|
151
153
|
textEditable: Aglyn.FEATURE_FLAG.ENABLED,
|
|
152
154
|
richTextEditable: Aglyn.FEATURE_FLAG.ENABLED
|
|
153
155
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/button.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 * as Aglyn from '@aglyn/aglyn'\nimport { mdiGestureTapButton } from '@aglyn/shared-data-mdi'\nimport { getMdiIconPath } from '@aglyn/shared-data-mdi'\nimport { AppLink, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport Button, { type ButtonProps } from '@mui/material/Button'\nimport { forwardRef } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { withAuthorHtmlLabel } from '../utils/author-html-label'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport {\n FIELD_COLOR,\n FIELD_DISABLED,\n FIELD_FULL_WIDTH,\n FIELD_LINK_TARGET,\n FIELD_LINK_TARGET_NAME,\n FIELD_SIZE,\n FIELD_TEXT_CONTENT,\n} from '../constants/field-presets'\nimport { generatePresetId } from '../utils/generate-preset-id'\nimport {\n type LinkTargetChoice,\n linkTargetProps,\n} from '../utils/link-target-props'\n\n// Component ids are persisted in screen documents; keep the legacy ids.\nexport const ID: Aglyn.ComponentId = 'muiButton'\n\nexport interface LinkableButtonProps extends ButtonProps {\n /** Target screen id; resolved from the routing map (AGL-139). */\n screenId?: string\n /** External URL, used only when no `screenId` is set. */\n href?: string\n /** mdi icon id rendered before the label (AGL-146). */\n startIconId?: string\n /** mdi icon id rendered after the label (AGL-146). */\n endIconId?: string\n /** Resolved SVG path for `startIconId`, stored at author time (AGL-1212). */\n startIconPath?: string\n /** Resolved SVG path for `endIconId`, stored at author time (AGL-1212). */\n endIconPath?: string\n /**\n * What the LINK MODE announces as (AGL-1426). Persisted in screen\n * documents; never rename, and `undefined` must keep meaning `'button'` —\n * every button authored before this existed is one.\n *\n * - `'button'` (or unset) — `<a role=\"button\">` with the button's look.\n * - `'linkButton'` — a plain `<a>` with NO role, keeping the button's\n * `variant`/`size`/`fullWidth`. Appearance without semantics.\n *\n * There is no `'link'` value here: a plain text link is `muiScreenLink`'s\n * job, and this component's whole purpose is the button styling.\n */\n renderAs?: 'button' | 'linkButton'\n /**\n * Where LINK MODE opens. Persisted in screen documents; never rename a\n * value, and `undefined` must keep meaning `'_self'`. Inert on a button\n * with nothing to point at — that is a real `<button>`, which has no\n * browsing context to choose.\n */\n target?: LinkTargetChoice\n /** Window name used only when `target` is `'custom'`. */\n targetName?: string\n /**\n * Sanitized emphasis markup for the label, written by the inline editor's\n * rich mode (AGL-2557). `children` keeps the plain-text reading of it, and\n * is what every surface that cannot render markup falls back to.\n */\n html?: string\n}\n\n/**\n * What a button-styled LINK renders as while navigation is suppressed\n * (besigner canvas, preview). `role: undefined` is the load-bearing half:\n * MUI's `ButtonBase` stamps `role=\"button\"` onto any non-`<button>` root,\n * and merges the caller's props AFTER its own, so an explicit `undefined`\n * is what removes it. Mirrors `screen-link.tsx` (AGL-1347).\n */\nconst STYLED_LINK_PLACEHOLDER = { component: 'span', role: undefined } as const\n\n/**\n * mdi id → icon element; unknown/empty ids render nothing.\n *\n * Prefers the persisted path (AGL-1212) so render surfaces never need the\n * ~2.9 MB catalog, and falls back to the catalog for buttons authored before\n * paths were stored. `getMdiIconPath` rather than `getMdiIconFromId`: the\n * latter substitutes `DEFAULT_ICON`, which has a real path, so a miss used to\n * render a \"help\" glyph instead of nothing.\n */\nfunction iconFromId(iconId?: string, iconPath?: string) {\n const path = iconPath || getMdiIconPath(iconId)\n return path ? <MdiIcon path={path} fontSize=\"small\" /> : undefined\n}\n\n/**\n * Button with optional link mode (AGL-139): a screen id or external URL\n * renders through AppLink exactly like the Screen Link component —\n * degrading to a plain button in the besigner/preview and when the id\n * doesn't resolve.\n *\n * Resolution (id-vs-URL precedence, protocol hardening) is `useLinkTarget`\n * so a `Link`-typed component prop bound into EITHER field resolves the\n * same way here as in Screen Link, Link Box and Image (AGL-1335).\n *\n * `renderAs=\"linkButton\"` splits appearance from semantics in that link mode\n * (AGL-1426), the same split `screen-link.tsx` got in AGL-1347. The 12 chips\n * in \"Dig in, or just say hello\" on `aglyn.com/` are Buttons, not Screen\n * Links: docs URLs, `mailto:` and social profiles, every one of them purely\n * navigating, and every one announcing as a button — which tells a\n * screen-reader user to expect an action and costs them the link list and\n * the open-in-new-tab affordance. This mode keeps the `variant`/`size`/\n * `fullWidth` pixels and drops the role, exactly as MUI's own\n * `Button component={Link}` does.\n *\n * It only touches the link branch. A Button with no link target is a genuine\n * `<button>` whose role is correct, so the value is inert there.\n */\nconst LinkableButton = forwardRef<any, LinkableButtonProps>((props, ref) => {\n const {\n screenId,\n href: externalHref,\n startIconId,\n endIconId,\n startIconPath,\n endIconPath,\n renderAs,\n target,\n targetName,\n html,\n ...spread\n } = props\n // A CLEARED attribute persists as null, and null is not \"use the default\"\n // in React — `color={null}` reaches MUI, which capitalizes it and throws\n // error #7 during SSR, 500ing the page (AGL-1226).\n //\n // The formatted label (AGL-2557) is substituted for `children` here rather\n // than at each return below, so the two branches keep one shape and an\n // unformatted button renders the identical tree it always did.\n const rest = withAuthorHtmlLabel(dropClearedProps(spread), html)\n const iconProps = {\n startIcon: iconFromId(startIconId, startIconPath),\n endIcon: iconFromId(endIconId, endIconPath),\n }\n const { href, suppressNavigation, leavesSite } = Aglyn.useLinkTarget(\n screenId,\n externalHref,\n )\n // Resolved rather than spread: `'custom'` is an authoring sentinel, and an\n // anchor carrying `target=\"custom\"` would open a window literally named\n // that. The pair is destructured OUT of `spread` above, so the plain-button\n // and suppressed branches below never stamp it on a `<button>`.\n const targetAttrs = linkTargetProps(target, targetName, leavesSite)\n // Semantics and appearance are independent choices now (AGL-1426): a\n // styled link takes the button's styling props and none of its role.\n const asStyledLink = renderAs === 'linkButton'\n\n if (!href || suppressNavigation) {\n // The canvas must not lie about which element the page will ship, so a\n // suppressed styled link mirrors the live shape. Gated on `href` unlike\n // `screen-link.tsx`: there, no target still means a link, but here it\n // means a genuine button, which must keep being a real `<button>`.\n return (\n <Button\n ref={ref}\n {...(asStyledLink && href ? STYLED_LINK_PLACEHOLDER : {})}\n {...iconProps}\n {...rest}\n />\n )\n }\n return (\n <AppLink\n ref={ref}\n componentVariant=\"button\"\n href={href}\n {...targetAttrs}\n // The whole defect in one attribute. `ButtonBase` adds `role=\"button\"`\n // to every non-`<button>` root, so the button LOOK used to drag the\n // button ROLE onto a navigating anchor. It spreads the caller's props\n // after its own, so passing `undefined` here is what clears it — and\n // only for the mode that asked to be a link. `'button'` is what\n // `ButtonBase` stamps anyway, so nothing already authored moves.\n role={asStyledLink ? undefined : 'button'}\n {...iconProps}\n {...rest}\n />\n )\n})\nLinkableButton.displayName = 'LinkableButton'\n\nexport const schema: Aglyn.ComponentSchema<LinkableButtonProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Button',\n description:\n 'A button — or a link styled as one, if you point it at a page or URL.',\n category: Aglyn.ComponentCategory.INPUT,\n icon: {\n path: mdiGestureTapButton.path,\n sx: { color: '#2196f3' },\n },\n flags: {\n textEditable: Aglyn.FEATURE_FLAG.ENABLED,\n richTextEditable: Aglyn.FEATURE_FLAG.ENABLED,\n },\n // Emphasis only (AGL-2557). With no link target this is a real `<button>`,\n // whose content model admits no list and no nested control; with one it is\n // an `<a>`, where a second anchor is the same invalid nesting. Both shapes\n // land on the same answer, so the schema does not have to know which one\n // an author picked.\n richTextCommands: [Aglyn.RICH_TEXT_COMMANDS.EMPHASIS],\n attributes: [\n FIELD_TEXT_CONTENT,\n FIELD_COLOR,\n FIELD_DISABLED,\n FIELD_FULL_WIDTH,\n FIELD_SIZE,\n {\n name: 'variant',\n description:\n 'How much weight the button carries: Contained is a filled primary ' +\n 'action, Outlined a secondary one, Text the lightest. One contained ' +\n 'button per view is a good rule.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Variant',\n // \"Default\" deleted (AGL-1453): it could not persist, and `text` — the\n // value it resolved to, MUI's own default — is already on the list.\n options: [\n { value: 'text', label: 'Text' },\n { value: 'outlined', label: 'Outlined' },\n { value: 'contained', label: 'Contained' },\n ],\n },\n {\n name: 'screenId',\n description:\n 'Optional: navigate to this page when clicked — the address ' +\n 'follows the published path like a Page Link (AGL-139).',\n component: Aglyn.FieldComponentType.SCREEN_SELECT,\n label: 'Link to page',\n },\n {\n name: 'href',\n description:\n 'Where the button goes when it points off this site. Ignored while ' +\n 'Link to page names one — that field wins, so clear it to use a ' +\n 'URL. Absolute (https://…) for another site, or a path for one of ' +\n 'your own routes.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'External URL',\n // A bare `#fragment` saves and goes nowhere (AGL-2867).\n resolveProps: Aglyn.bareFragmentLinkFieldProps,\n },\n FIELD_LINK_TARGET,\n FIELD_LINK_TARGET_NAME,\n {\n name: 'renderAs',\n description:\n 'What this announces as once it links somewhere. Button is for ' +\n 'calls to action; pick \"Link (button styling)\" for a chip that only ' +\n 'navigates, so it keeps this look but announces as the link it is. ' +\n 'Ignored when there is no page or URL to point at.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Render as',\n // `'button'` is a REAL SENTINEL, not a deletion (AGL-1453). Unlike the\n // \"Default\" options on this component, `''` here spelled an author's\n // actual choice, and one they could not make: the attributes form\n // strips `''` before save (AGL-1191), so a button switched to Link\n // (button styling) had no route in this dropdown back to Button — the\n // pick reverted and the stored `linkButton` stayed.\n //\n // Safe because `renderAs` never reaches MUI: it is destructured out\n // above and read only as `renderAs === 'linkButton'`. So `'button'` and\n // an absent value take the identical branch, which is also what keeps\n // every button authored before this existed rendering unchanged.\n options: [\n { value: 'button', label: 'Button' },\n { value: 'linkButton', label: 'Link (button styling)' },\n ],\n },\n {\n name: 'startIconId',\n description: 'Icon shown before the label.',\n component: Aglyn.FieldComponentType.ICON_PICKER,\n label: 'Start icon',\n },\n {\n name: 'endIconId',\n description: 'Icon shown after the label.',\n component: Aglyn.FieldComponentType.ICON_PICKER,\n label: 'End icon',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Outlined Button',\n icon: {\n path: mdiGestureTapButton.path,\n sx: { color: '#2196f3' },\n },\n category: Aglyn.ComponentCategory.INPUT,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n variant: 'outlined',\n children: 'Click Me',\n },\n },\n },\n]\n\nexport default LinkableButton\n"],"names":["Aglyn","mdiGestureTapButton","getMdiIconPath","AppLink","MdiIcon","Button","forwardRef","BUNDLE_ID","withAuthorHtmlLabel","dropClearedProps","FIELD_COLOR","FIELD_DISABLED","FIELD_FULL_WIDTH","FIELD_LINK_TARGET","FIELD_LINK_TARGET_NAME","FIELD_SIZE","FIELD_TEXT_CONTENT","generatePresetId","linkTargetProps","ID","STYLED_LINK_PLACEHOLDER","component","role","undefined","iconFromId","iconId","iconPath","path","fontSize","LinkableButton","props","ref","screenId","href","externalHref","startIconId","endIconId","startIconPath","endIconPath","renderAs","target","targetName","html","spread","rest","iconProps","startIcon","endIcon","suppressNavigation","leavesSite","useLinkTarget","targetAttrs","asStyledLink","componentVariant","displayName","schema","$id","pluginId","description","category","ComponentCategory","INPUT","icon","sx","color","flags","textEditable","FEATURE_FLAG","ENABLED","richTextEditable","richTextCommands","RICH_TEXT_COMMANDS","EMPHASIS","attributes","name","FieldComponentType","SELECT","label","options","value","SCREEN_SELECT","TEXT_FIELD","resolveProps","bareFragmentLinkFieldProps","ICON_PICKER","presets","type","NodeType","PRESET","data","componentId","variant","children"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,mBAAmB,QAAQ,yBAAwB;AAC5D,SAASC,cAAc,QAAQ,yBAAwB;AACvD,SAASC,OAAO,EAAEC,OAAO,QAAQ,uBAAsB;AACvD,OAAOC,YAAkC,uBAAsB;AAC/D,SAASC,UAAU,QAAQ,QAAO;AAClC,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,mBAAmB,QAAQ,gCAA4B;AAChE,SAASC,gBAAgB,QAAQ,iCAA6B;AAC9D,SACEC,WAAW,EACXC,cAAc,EACdC,gBAAgB,EAChBC,iBAAiB,EACjBC,sBAAsB,EACtBC,UAAU,EACVC,kBAAkB,QACb,gCAA4B;AACnC,SAASC,gBAAgB,QAAQ,iCAA6B;AAC9D,SAEEC,eAAe,QACV,gCAA4B;AAEnC,wEAAwE;AACxE,OAAO,MAAMC,KAAwB,YAAW;AA6ChD;;;;;;CAMC,GACD,MAAMC,0BAA0B;IAAEC,WAAW;IAAQC,MAAMC;AAAU;AAErE;;;;;;;;CAQC,GACD,SAASC,WAAWC,MAAe,EAAEC,QAAiB;IACpD,MAAMC,OAAOD,YAAYxB,eAAeuB;IACxC,OAAOE,qBAAO,KAACvB;QAAQuB,MAAMA;QAAMC,UAAS;SAAaL;AAC3D;AAEA;;;;;;;;;;;;;;;;;;;;;;CAsBC,GACD,MAAMM,+BAAiBvB,WAAqC,CAACwB,OAAOC;IAClE,MAAM,EACJC,QAAQ,EACRC,MAAMC,YAAY,EAClBC,WAAW,EACXC,SAAS,EACTC,aAAa,EACbC,WAAW,EACXC,QAAQ,EACRC,MAAM,EACNC,UAAU,EACVC,IAAI,EAEL,GAAGZ,OADCa,0CACDb;;;;;;;;;;;;IACJ,0EAA0E;IAC1E,yEAAyE;IACzE,mDAAmD;IACnD,EAAE;IACF,2EAA2E;IAC3E,uEAAuE;IACvE,+DAA+D;IAC/D,MAAMc,OAAOpC,oBAAoBC,iBAAiBkC,SAASD;IAC3D,MAAMG,YAAY;QAChBC,WAAWtB,WAAWW,aAAaE;QACnCU,SAASvB,WAAWY,WAAWE;IACjC;IACA,MAAM,EAAEL,IAAI,EAAEe,kBAAkB,EAAEC,UAAU,EAAE,GAAGjD,MAAMkD,aAAa,CAClElB,UACAE;IAEF,2EAA2E;IAC3E,wEAAwE;IACxE,4EAA4E;IAC5E,gEAAgE;IAChE,MAAMiB,cAAcjC,gBAAgBsB,QAAQC,YAAYQ;IACxD,qEAAqE;IACrE,qEAAqE;IACrE,MAAMG,eAAeb,aAAa;IAElC,IAAI,CAACN,QAAQe,oBAAoB;QAC/B,uEAAuE;QACvE,wEAAwE;QACxE,sEAAsE;QACtE,mEAAmE;QACnE,qBACE,KAAC3C;YACC0B,KAAKA;WACAqB,gBAAgBnB,OAAOb,0BAA0B,CAAC,GACnDyB,WACAD;IAGV;IACA,qBACE,KAACzC;QACC4B,KAAKA;QACLsB,kBAAiB;QACjBpB,MAAMA;OACFkB;QACJ,uEAAuE;QACvE,oEAAoE;QACpE,sEAAsE;QACtE,qEAAqE;QACrE,gEAAgE;QAChE,iEAAiE;QACjE7B,MAAM8B,eAAe7B,YAAY;OAC7BsB,WACAD;AAGV;AACAf,eAAeyB,WAAW,GAAG;AAE7B,OAAO,MAAMC,SAAqD;IAChEC,KAAKrC;IACLsC,UAAUlD;IACV+C,aAAa;IACbI,aACE;IACFC,UAAU3D,MAAM4D,iBAAiB,CAACC,KAAK;IACvCC,MAAM;QACJnC,MAAM1B,oBAAoB0B,IAAI;QAC9BoC,IAAI;YAAEC,OAAO;QAAU;IACzB;IACAC,OAAO;QACLC,cAAclE,MAAMmE,YAAY,CAACC,OAAO;QACxCC,kBAAkBrE,MAAMmE,YAAY,CAACC,OAAO;IAC9C;IACA,2EAA2E;IAC3E,2EAA2E;IAC3E,2EAA2E;IAC3E,yEAAyE;IACzE,oBAAoB;IACpBE,kBAAkB;QAACtE,MAAMuE,kBAAkB,CAACC,QAAQ;KAAC;IACrDC,YAAY;QACVzD;QACAN;QACAC;QACAC;QACAG;QACA;YACE2D,MAAM;YACNhB,aACE,uEACA,wEACA;YACFrC,WAAWrB,MAAM2E,kBAAkB,CAACC,MAAM;YAC1CC,OAAO;YACP,uEAAuE;YACvE,oEAAoE;YACpEC,SAAS;gBACP;oBAAEC,OAAO;oBAAQF,OAAO;gBAAO;gBAC/B;oBAAEE,OAAO;oBAAYF,OAAO;gBAAW;gBACvC;oBAAEE,OAAO;oBAAaF,OAAO;gBAAY;aAC1C;QACH;QACA;YACEH,MAAM;YACNhB,aACE,gEACA;YACFrC,WAAWrB,MAAM2E,kBAAkB,CAACK,aAAa;YACjDH,OAAO;QACT;QACA;YACEH,MAAM;YACNhB,aACE,uEACA,oEACA,sEACA;YACFrC,WAAWrB,MAAM2E,kBAAkB,CAACM,UAAU;YAC9CJ,OAAO;YACP,wDAAwD;YACxDK,cAAclF,MAAMmF,0BAA0B;QAChD;QACAtE;QACAC;QACA;YACE4D,MAAM;YACNhB,aACE,mEACA,wEACA,uEACA;YACFrC,WAAWrB,MAAM2E,kBAAkB,CAACC,MAAM;YAC1CC,OAAO;YACP,uEAAuE;YACvE,qEAAqE;YACrE,kEAAkE;YAClE,mEAAmE;YACnE,sEAAsE;YACtE,oDAAoD;YACpD,EAAE;YACF,oEAAoE;YACpE,wEAAwE;YACxE,sEAAsE;YACtE,iEAAiE;YACjEC,SAAS;gBACP;oBAAEC,OAAO;oBAAUF,OAAO;gBAAS;gBACnC;oBAAEE,OAAO;oBAAcF,OAAO;gBAAwB;aACvD;QACH;QACA;YACEH,MAAM;YACNhB,aAAa;YACbrC,WAAWrB,MAAM2E,kBAAkB,CAACS,WAAW;YAC/CP,OAAO;QACT;QACA;YACEH,MAAM;YACNhB,aAAa;YACbrC,WAAWrB,MAAM2E,kBAAkB,CAACS,WAAW;YAC/CP,OAAO;QACT;KACD;AACH,EAAC;AAED,OAAO,MAAMQ,UAAgC;IAC3C;QACE7B,KAAKvC,iBAAiBE;QACtBmE,MAAMtF,MAAMuF,QAAQ,CAACC,MAAM;QAC3BlC,aAAa;QACbQ,MAAM;YACJnC,MAAM1B,oBAAoB0B,IAAI;YAC9BoC,IAAI;gBAAEC,OAAO;YAAU;QACzB;QACAL,UAAU3D,MAAM4D,iBAAiB,CAACC,KAAK;QACvC4B,MAAM;YACJjC,KAAK;YACLkC,aAAavE;YACbsC,UAAUlD;YACVuB,OAAO;gBACL6D,SAAS;gBACTC,UAAU;YACZ;QACF;IACF;CACD,CAAA;AAED,eAAe/D,eAAc"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/button.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 * as Aglyn from '@aglyn/aglyn'\nimport { mdiGestureTapButton } from '@aglyn/shared-data-mdi'\nimport { getMdiIconPath } from '@aglyn/shared-data-mdi'\nimport { AppLink, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport Button, { type ButtonProps } from '@mui/material/Button'\nimport { forwardRef } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { withAuthorHtmlLabel } from '../utils/author-html-label'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport {\n FIELD_COLOR,\n FIELD_DISABLED,\n FIELD_FULL_WIDTH,\n FIELD_LINK_TARGET,\n FIELD_LINK_TARGET_NAME,\n FIELD_SIZE,\n FIELD_TEXT_CONTENT,\n} from '../constants/field-presets'\nimport { generatePresetId } from '../utils/generate-preset-id'\nimport {\n type LinkTargetChoice,\n linkTargetProps,\n} from '../utils/link-target-props'\n\n// Component ids are persisted in screen documents; keep the legacy ids.\nexport const ID: Aglyn.ComponentId = 'muiButton'\n\nexport interface LinkableButtonProps extends ButtonProps {\n /** Target screen id; resolved from the routing map (AGL-139). */\n screenId?: string\n /** External URL, used only when no `screenId` is set. */\n href?: string\n /** mdi icon id rendered before the label (AGL-146). */\n startIconId?: string\n /** mdi icon id rendered after the label (AGL-146). */\n endIconId?: string\n /** Resolved SVG path for `startIconId`, stored at author time (AGL-1212). */\n startIconPath?: string\n /** Resolved SVG path for `endIconId`, stored at author time (AGL-1212). */\n endIconPath?: string\n /**\n * What the LINK MODE announces as (AGL-1426). Persisted in screen\n * documents; never rename, and `undefined` must keep meaning `'button'` —\n * every button authored before this existed is one.\n *\n * - `'button'` (or unset) — `<a role=\"button\">` with the button's look.\n * - `'linkButton'` — a plain `<a>` with NO role, keeping the button's\n * `variant`/`size`/`fullWidth`. Appearance without semantics.\n *\n * There is no `'link'` value here: a plain text link is `muiScreenLink`'s\n * job, and this component's whole purpose is the button styling.\n */\n renderAs?: 'button' | 'linkButton'\n /**\n * Where LINK MODE opens. Persisted in screen documents; never rename a\n * value, and `undefined` must keep meaning `'_self'`. Inert on a button\n * with nothing to point at — that is a real `<button>`, which has no\n * browsing context to choose.\n */\n target?: LinkTargetChoice\n /** Window name used only when `target` is `'custom'`. */\n targetName?: string\n /**\n * Sanitized emphasis markup for the label, written by the inline editor's\n * rich mode (AGL-2557). `children` keeps the plain-text reading of it, and\n * is what every surface that cannot render markup falls back to.\n */\n html?: string\n}\n\n/**\n * What a button-styled LINK renders as while navigation is suppressed\n * (besigner canvas, preview). `role: undefined` is the load-bearing half:\n * MUI's `ButtonBase` stamps `role=\"button\"` onto any non-`<button>` root,\n * and merges the caller's props AFTER its own, so an explicit `undefined`\n * is what removes it. Mirrors `screen-link.tsx` (AGL-1347).\n */\nconst STYLED_LINK_PLACEHOLDER = { component: 'span', role: undefined } as const\n\n/**\n * mdi id → icon element; unknown/empty ids render nothing.\n *\n * Prefers the persisted path (AGL-1212) so render surfaces never need the\n * ~2.9 MB catalog, and falls back to the catalog for buttons authored before\n * paths were stored. `getMdiIconPath` rather than `getMdiIconFromId`: the\n * latter substitutes `DEFAULT_ICON`, which has a real path, so a miss used to\n * render a \"help\" glyph instead of nothing.\n */\nfunction iconFromId(iconId?: string, iconPath?: string) {\n const path = iconPath || getMdiIconPath(iconId)\n return path ? <MdiIcon path={path} fontSize=\"small\" /> : undefined\n}\n\n/**\n * Button with optional link mode (AGL-139): a screen id or external URL\n * renders through AppLink exactly like the Screen Link component —\n * degrading to a plain button in the besigner/preview and when the id\n * doesn't resolve.\n *\n * Resolution (id-vs-URL precedence, protocol hardening) is `useLinkTarget`\n * so a `Link`-typed component prop bound into EITHER field resolves the\n * same way here as in Screen Link, Link Box and Image (AGL-1335).\n *\n * `renderAs=\"linkButton\"` splits appearance from semantics in that link mode\n * (AGL-1426), the same split `screen-link.tsx` got in AGL-1347. The 12 chips\n * in \"Dig in, or just say hello\" on `aglyn.com/` are Buttons, not Screen\n * Links: docs URLs, `mailto:` and social profiles, every one of them purely\n * navigating, and every one announcing as a button — which tells a\n * screen-reader user to expect an action and costs them the link list and\n * the open-in-new-tab affordance. This mode keeps the `variant`/`size`/\n * `fullWidth` pixels and drops the role, exactly as MUI's own\n * `Button component={Link}` does.\n *\n * It only touches the link branch. A Button with no link target is a genuine\n * `<button>` whose role is correct, so the value is inert there.\n */\nconst LinkableButton = forwardRef<any, LinkableButtonProps>((props, ref) => {\n const {\n screenId,\n href: externalHref,\n startIconId,\n endIconId,\n startIconPath,\n endIconPath,\n renderAs,\n target,\n targetName,\n html,\n ...spread\n } = props\n // A CLEARED attribute persists as null, and null is not \"use the default\"\n // in React — `color={null}` reaches MUI, which capitalizes it and throws\n // error #7 during SSR, 500ing the page (AGL-1226).\n //\n // The formatted label (AGL-2557) is substituted for `children` here rather\n // than at each return below, so the two branches keep one shape and an\n // unformatted button renders the identical tree it always did.\n const rest = withAuthorHtmlLabel(dropClearedProps(spread), html)\n const iconProps = {\n startIcon: iconFromId(startIconId, startIconPath),\n endIcon: iconFromId(endIconId, endIconPath),\n }\n const { href, suppressNavigation, leavesSite } = Aglyn.useLinkTarget(\n screenId,\n externalHref,\n )\n // Resolved rather than spread: `'custom'` is an authoring sentinel, and an\n // anchor carrying `target=\"custom\"` would open a window literally named\n // that. The pair is destructured OUT of `spread` above, so the plain-button\n // and suppressed branches below never stamp it on a `<button>`.\n const targetAttrs = linkTargetProps(target, targetName, leavesSite)\n // Semantics and appearance are independent choices now (AGL-1426): a\n // styled link takes the button's styling props and none of its role.\n const asStyledLink = renderAs === 'linkButton'\n\n if (!href || suppressNavigation) {\n // The canvas must not lie about which element the page will ship, so a\n // suppressed styled link mirrors the live shape. Gated on `href` unlike\n // `screen-link.tsx`: there, no target still means a link, but here it\n // means a genuine button, which must keep being a real `<button>`.\n return (\n <Button\n ref={ref}\n {...(asStyledLink && href ? STYLED_LINK_PLACEHOLDER : {})}\n {...iconProps}\n {...rest}\n />\n )\n }\n return (\n <AppLink\n ref={ref}\n componentVariant=\"button\"\n href={href}\n {...targetAttrs}\n // The whole defect in one attribute. `ButtonBase` adds `role=\"button\"`\n // to every non-`<button>` root, so the button LOOK used to drag the\n // button ROLE onto a navigating anchor. It spreads the caller's props\n // after its own, so passing `undefined` here is what clears it — and\n // only for the mode that asked to be a link. `'button'` is what\n // `ButtonBase` stamps anyway, so nothing already authored moves.\n role={asStyledLink ? undefined : 'button'}\n {...iconProps}\n {...rest}\n />\n )\n})\nLinkableButton.displayName = 'LinkableButton'\n\nexport const schema: Aglyn.ComponentSchema<LinkableButtonProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Button',\n description:\n 'A button — or a link styled as one, if you point it at a page or URL.',\n category: Aglyn.ComponentCategory.INPUT,\n icon: {\n path: mdiGestureTapButton.path,\n sx: { color: '#2196f3' },\n },\n flags: {\n // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n textEditable: Aglyn.FEATURE_FLAG.ENABLED,\n richTextEditable: Aglyn.FEATURE_FLAG.ENABLED,\n },\n // Emphasis only (AGL-2557). With no link target this is a real `<button>`,\n // whose content model admits no list and no nested control; with one it is\n // an `<a>`, where a second anchor is the same invalid nesting. Both shapes\n // land on the same answer, so the schema does not have to know which one\n // an author picked.\n richTextCommands: [Aglyn.RICH_TEXT_COMMANDS.EMPHASIS],\n attributes: [\n FIELD_TEXT_CONTENT,\n FIELD_COLOR,\n FIELD_DISABLED,\n FIELD_FULL_WIDTH,\n FIELD_SIZE,\n {\n name: 'variant',\n description:\n 'How much weight the button carries: Contained is a filled primary ' +\n 'action, Outlined a secondary one, Text the lightest. One contained ' +\n 'button per view is a good rule.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Variant',\n // \"Default\" deleted (AGL-1453): it could not persist, and `text` — the\n // value it resolved to, MUI's own default — is already on the list.\n options: [\n { value: 'text', label: 'Text' },\n { value: 'outlined', label: 'Outlined' },\n { value: 'contained', label: 'Contained' },\n ],\n },\n {\n name: 'screenId',\n description:\n 'Optional: navigate to this page when clicked — the address ' +\n 'follows the published path like a Page Link (AGL-139).',\n component: Aglyn.FieldComponentType.SCREEN_SELECT,\n label: 'Link to page',\n },\n {\n name: 'href',\n description:\n 'Where the button goes when it points off this site. Ignored while ' +\n 'Link to page names one — that field wins, so clear it to use a ' +\n 'URL. Absolute (https://…) for another site, or a path for one of ' +\n 'your own routes.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'External URL',\n // A bare `#fragment` saves and goes nowhere (AGL-2867).\n resolveProps: Aglyn.bareFragmentLinkFieldProps,\n },\n FIELD_LINK_TARGET,\n FIELD_LINK_TARGET_NAME,\n {\n name: 'renderAs',\n description:\n 'What this announces as once it links somewhere. Button is for ' +\n 'calls to action; pick \"Link (button styling)\" for a chip that only ' +\n 'navigates, so it keeps this look but announces as the link it is. ' +\n 'Ignored when there is no page or URL to point at.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Render as',\n // `'button'` is a REAL SENTINEL, not a deletion (AGL-1453). Unlike the\n // \"Default\" options on this component, `''` here spelled an author's\n // actual choice, and one they could not make: the attributes form\n // strips `''` before save (AGL-1191), so a button switched to Link\n // (button styling) had no route in this dropdown back to Button — the\n // pick reverted and the stored `linkButton` stayed.\n //\n // Safe because `renderAs` never reaches MUI: it is destructured out\n // above and read only as `renderAs === 'linkButton'`. So `'button'` and\n // an absent value take the identical branch, which is also what keeps\n // every button authored before this existed rendering unchanged.\n options: [\n { value: 'button', label: 'Button' },\n { value: 'linkButton', label: 'Link (button styling)' },\n ],\n },\n {\n name: 'startIconId',\n description: 'Icon shown before the label.',\n component: Aglyn.FieldComponentType.ICON_PICKER,\n label: 'Start icon',\n },\n {\n name: 'endIconId',\n description: 'Icon shown after the label.',\n component: Aglyn.FieldComponentType.ICON_PICKER,\n label: 'End icon',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Outlined Button',\n icon: {\n path: mdiGestureTapButton.path,\n sx: { color: '#2196f3' },\n },\n category: Aglyn.ComponentCategory.INPUT,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n variant: 'outlined',\n children: 'Click Me',\n },\n },\n },\n]\n\nexport default LinkableButton\n"],"names":["Aglyn","mdiGestureTapButton","getMdiIconPath","AppLink","MdiIcon","Button","forwardRef","BUNDLE_ID","withAuthorHtmlLabel","dropClearedProps","FIELD_COLOR","FIELD_DISABLED","FIELD_FULL_WIDTH","FIELD_LINK_TARGET","FIELD_LINK_TARGET_NAME","FIELD_SIZE","FIELD_TEXT_CONTENT","generatePresetId","linkTargetProps","ID","STYLED_LINK_PLACEHOLDER","component","role","undefined","iconFromId","iconId","iconPath","path","fontSize","LinkableButton","props","ref","screenId","href","externalHref","startIconId","endIconId","startIconPath","endIconPath","renderAs","target","targetName","html","spread","rest","iconProps","startIcon","endIcon","suppressNavigation","leavesSite","useLinkTarget","targetAttrs","asStyledLink","componentVariant","displayName","schema","$id","pluginId","description","category","ComponentCategory","INPUT","icon","sx","color","flags","lazyHydration","FEATURE_FLAG","ENABLED","textEditable","richTextEditable","richTextCommands","RICH_TEXT_COMMANDS","EMPHASIS","attributes","name","FieldComponentType","SELECT","label","options","value","SCREEN_SELECT","TEXT_FIELD","resolveProps","bareFragmentLinkFieldProps","ICON_PICKER","presets","type","NodeType","PRESET","data","componentId","variant","children"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,mBAAmB,QAAQ,yBAAwB;AAC5D,SAASC,cAAc,QAAQ,yBAAwB;AACvD,SAASC,OAAO,EAAEC,OAAO,QAAQ,uBAAsB;AACvD,OAAOC,YAAkC,uBAAsB;AAC/D,SAASC,UAAU,QAAQ,QAAO;AAClC,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,mBAAmB,QAAQ,gCAA4B;AAChE,SAASC,gBAAgB,QAAQ,iCAA6B;AAC9D,SACEC,WAAW,EACXC,cAAc,EACdC,gBAAgB,EAChBC,iBAAiB,EACjBC,sBAAsB,EACtBC,UAAU,EACVC,kBAAkB,QACb,gCAA4B;AACnC,SAASC,gBAAgB,QAAQ,iCAA6B;AAC9D,SAEEC,eAAe,QACV,gCAA4B;AAEnC,wEAAwE;AACxE,OAAO,MAAMC,KAAwB,YAAW;AA6ChD;;;;;;CAMC,GACD,MAAMC,0BAA0B;IAAEC,WAAW;IAAQC,MAAMC;AAAU;AAErE;;;;;;;;CAQC,GACD,SAASC,WAAWC,MAAe,EAAEC,QAAiB;IACpD,MAAMC,OAAOD,YAAYxB,eAAeuB;IACxC,OAAOE,qBAAO,KAACvB;QAAQuB,MAAMA;QAAMC,UAAS;SAAaL;AAC3D;AAEA;;;;;;;;;;;;;;;;;;;;;;CAsBC,GACD,MAAMM,+BAAiBvB,WAAqC,CAACwB,OAAOC;IAClE,MAAM,EACJC,QAAQ,EACRC,MAAMC,YAAY,EAClBC,WAAW,EACXC,SAAS,EACTC,aAAa,EACbC,WAAW,EACXC,QAAQ,EACRC,MAAM,EACNC,UAAU,EACVC,IAAI,EAEL,GAAGZ,OADCa,0CACDb;;;;;;;;;;;;IACJ,0EAA0E;IAC1E,yEAAyE;IACzE,mDAAmD;IACnD,EAAE;IACF,2EAA2E;IAC3E,uEAAuE;IACvE,+DAA+D;IAC/D,MAAMc,OAAOpC,oBAAoBC,iBAAiBkC,SAASD;IAC3D,MAAMG,YAAY;QAChBC,WAAWtB,WAAWW,aAAaE;QACnCU,SAASvB,WAAWY,WAAWE;IACjC;IACA,MAAM,EAAEL,IAAI,EAAEe,kBAAkB,EAAEC,UAAU,EAAE,GAAGjD,MAAMkD,aAAa,CAClElB,UACAE;IAEF,2EAA2E;IAC3E,wEAAwE;IACxE,4EAA4E;IAC5E,gEAAgE;IAChE,MAAMiB,cAAcjC,gBAAgBsB,QAAQC,YAAYQ;IACxD,qEAAqE;IACrE,qEAAqE;IACrE,MAAMG,eAAeb,aAAa;IAElC,IAAI,CAACN,QAAQe,oBAAoB;QAC/B,uEAAuE;QACvE,wEAAwE;QACxE,sEAAsE;QACtE,mEAAmE;QACnE,qBACE,KAAC3C;YACC0B,KAAKA;WACAqB,gBAAgBnB,OAAOb,0BAA0B,CAAC,GACnDyB,WACAD;IAGV;IACA,qBACE,KAACzC;QACC4B,KAAKA;QACLsB,kBAAiB;QACjBpB,MAAMA;OACFkB;QACJ,uEAAuE;QACvE,oEAAoE;QACpE,sEAAsE;QACtE,qEAAqE;QACrE,gEAAgE;QAChE,iEAAiE;QACjE7B,MAAM8B,eAAe7B,YAAY;OAC7BsB,WACAD;AAGV;AACAf,eAAeyB,WAAW,GAAG;AAE7B,OAAO,MAAMC,SAAqD;IAChEC,KAAKrC;IACLsC,UAAUlD;IACV+C,aAAa;IACbI,aACE;IACFC,UAAU3D,MAAM4D,iBAAiB,CAACC,KAAK;IACvCC,MAAM;QACJnC,MAAM1B,oBAAoB0B,IAAI;QAC9BoC,IAAI;YAAEC,OAAO;QAAU;IACzB;IACAC,OAAO;QACL,sEAAsE;QACtEC,eAAelE,MAAMmE,YAAY,CAACC,OAAO;QACzCC,cAAcrE,MAAMmE,YAAY,CAACC,OAAO;QACxCE,kBAAkBtE,MAAMmE,YAAY,CAACC,OAAO;IAC9C;IACA,2EAA2E;IAC3E,2EAA2E;IAC3E,2EAA2E;IAC3E,yEAAyE;IACzE,oBAAoB;IACpBG,kBAAkB;QAACvE,MAAMwE,kBAAkB,CAACC,QAAQ;KAAC;IACrDC,YAAY;QACV1D;QACAN;QACAC;QACAC;QACAG;QACA;YACE4D,MAAM;YACNjB,aACE,uEACA,wEACA;YACFrC,WAAWrB,MAAM4E,kBAAkB,CAACC,MAAM;YAC1CC,OAAO;YACP,uEAAuE;YACvE,oEAAoE;YACpEC,SAAS;gBACP;oBAAEC,OAAO;oBAAQF,OAAO;gBAAO;gBAC/B;oBAAEE,OAAO;oBAAYF,OAAO;gBAAW;gBACvC;oBAAEE,OAAO;oBAAaF,OAAO;gBAAY;aAC1C;QACH;QACA;YACEH,MAAM;YACNjB,aACE,gEACA;YACFrC,WAAWrB,MAAM4E,kBAAkB,CAACK,aAAa;YACjDH,OAAO;QACT;QACA;YACEH,MAAM;YACNjB,aACE,uEACA,oEACA,sEACA;YACFrC,WAAWrB,MAAM4E,kBAAkB,CAACM,UAAU;YAC9CJ,OAAO;YACP,wDAAwD;YACxDK,cAAcnF,MAAMoF,0BAA0B;QAChD;QACAvE;QACAC;QACA;YACE6D,MAAM;YACNjB,aACE,mEACA,wEACA,uEACA;YACFrC,WAAWrB,MAAM4E,kBAAkB,CAACC,MAAM;YAC1CC,OAAO;YACP,uEAAuE;YACvE,qEAAqE;YACrE,kEAAkE;YAClE,mEAAmE;YACnE,sEAAsE;YACtE,oDAAoD;YACpD,EAAE;YACF,oEAAoE;YACpE,wEAAwE;YACxE,sEAAsE;YACtE,iEAAiE;YACjEC,SAAS;gBACP;oBAAEC,OAAO;oBAAUF,OAAO;gBAAS;gBACnC;oBAAEE,OAAO;oBAAcF,OAAO;gBAAwB;aACvD;QACH;QACA;YACEH,MAAM;YACNjB,aAAa;YACbrC,WAAWrB,MAAM4E,kBAAkB,CAACS,WAAW;YAC/CP,OAAO;QACT;QACA;YACEH,MAAM;YACNjB,aAAa;YACbrC,WAAWrB,MAAM4E,kBAAkB,CAACS,WAAW;YAC/CP,OAAO;QACT;KACD;AACH,EAAC;AAED,OAAO,MAAMQ,UAAgC;IAC3C;QACE9B,KAAKvC,iBAAiBE;QACtBoE,MAAMvF,MAAMwF,QAAQ,CAACC,MAAM;QAC3BnC,aAAa;QACbQ,MAAM;YACJnC,MAAM1B,oBAAoB0B,IAAI;YAC9BoC,IAAI;gBAAEC,OAAO;YAAU;QACzB;QACAL,UAAU3D,MAAM4D,iBAAiB,CAACC,KAAK;QACvC6B,MAAM;YACJlC,KAAK;YACLmC,aAAaxE;YACbsC,UAAUlD;YACVuB,OAAO;gBACL8D,SAAS;gBACTC,UAAU;YACZ;QACF;IACF;CACD,CAAA;AAED,eAAehE,eAAc"}
|
|
@@ -51,6 +51,12 @@ export const schema = {
|
|
|
51
51
|
$id: ID,
|
|
52
52
|
pluginId: BUNDLE_ID,
|
|
53
53
|
displayName: 'Container',
|
|
54
|
+
// Static, and its children sit directly in its root: a subtree it heads
|
|
55
|
+
// keeps its server HTML until the visitor nears it (AGL-3581).
|
|
56
|
+
flags: {
|
|
57
|
+
lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,
|
|
58
|
+
childrenInRoot: Aglyn.FEATURE_FLAG.ENABLED
|
|
59
|
+
},
|
|
54
60
|
description: 'Centers your page content and caps how wide it gets.',
|
|
55
61
|
category: Aglyn.ComponentCategory.LAYOUT,
|
|
56
62
|
icon: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/container.ts"],"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 * as Aglyn from '@aglyn/aglyn'\nimport {\n mdiTextBoxOutline,\n mdiViewArrayOutline,\n} from '@aglyn/shared-data-mdi'\nimport MuiContainer, { type ContainerProps } from '@mui/material/Container'\nimport { createElement, forwardRef } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { colorSchemeAttribute } from '../utils/color-scheme-attribute'\nimport {\n applySemanticElement,\n semanticElementAttribute,\n semanticElementLabelAttribute,\n} from '../utils/element-picker'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n/**\n * MUI's Container behind the cleared-prop guard (AGL-1435).\n *\n * `maxWidth` is the one authorable attribute in this plugin where a cleared\n * value changes PAGE LAYOUT instead of showing an obviously wrong value, and\n * it satisfied neither branch of MUI's own logic:\n *\n * - `''` / `null` is not `undefined`, so the `maxWidth = 'lg'` destructuring\n * default in `@mui/system/Container/createContainer.js` never fires;\n * - `''` / `null` is falsy, so the `ownerState.maxWidth &&` guard skips both\n * the branch that emits the `max-width` rule and the one that emits the\n * matching utility class.\n *\n * The result is a section with NO width constraint at all — full-bleed, with\n * nothing thrown and nothing visibly wrong in the editor. Clearing the field\n * persists `null` (the AGL-1226 shape; 106 cleared prop values live in the\n * corpus today across other components), so this was reachable, not\n * theoretical. Dropping the key instead lets MUI's own `lg` apply.\n */\nconst Container = forwardRef<HTMLDivElement, ContainerProps>((props, ref) =>\n createElement(MuiContainer, {\n ...applySemanticElement(dropClearedProps(props) as Record<string, unknown>),\n ref,\n }),\n)\nContainer.displayName = 'AglynContainer'\n\n// Component ids are persisted in screen documents; keep the legacy ids.\nexport const ID: Aglyn.ComponentId = 'muiContainer'\n\nexport const schema: Aglyn.ComponentSchema<ContainerProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Container',\n description: 'Centers your page content and caps how wide it gets.',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: {\n path: mdiViewArrayOutline.path,\n sx: { color: '#2196f3' },\n },\n attributes: [\n semanticElementAttribute('this container'),\n semanticElementLabelAttribute(),\n {\n name: 'fixed',\n description:\n \"If true, set the max-width to match the min-width of the current breakpoint. This is useful if you'd prefer to design for a fixed set of sizes instead of trying to accommodate a fully fluid viewport. It's fluid by default.\",\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Fixed Breakpoints',\n },\n {\n name: 'disableGutters',\n description:\n 'Removes the container’s side padding, so its content runs to the ' +\n 'full width it is centered in. Use it for a full-bleed band; leave ' +\n 'it off for text, which needs the margin on a phone.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Disable Gutters?',\n },\n {\n name: 'maxWidth',\n description:\n 'The width this section stops growing at. New containers start at ' +\n 'XL (1536px), the standard for full-width page sections. Long-form ' +\n 'prose — legal pages, docs, blog and changelog bodies — uses MD ' +\n '(900px), which lands near the 65–75 characters a line that reads ' +\n 'comfortably; the \"Prose Container\" preset starts there. LG (1200px) ' +\n 'is the deliberate middle case for a wide but text-led section, not ' +\n 'a default to spread. Clearing the field falls back to the MUI ' +\n 'default of LG. There is no \"Default\" option: \"Fluid Responsive\" is ' +\n 'the only way to render edge-to-edge, and it has to be chosen on ' +\n 'purpose.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Max Width',\n // Every value here is a real, persistable one. The list used to open\n // with `{ value: '', label: 'Default' }`, which was unpersistable by\n // construction — the attributes form strips `''` on change (AGL-1191)\n // — and, on any path that DID land it, rendered full-bleed rather than\n // any default at all (AGL-1435).\n options: [\n { value: 'xs', label: 'XS - Mobile (444px)' },\n { value: 'sm', label: 'SM - Tablet (600px)' },\n { value: 'md', label: 'MD - Laptop (900px)' },\n { value: 'lg', label: 'LG - Desktop (1200px)' },\n { value: 'xl', label: 'XL - Widescreen (1536px, section standard)' },\n { value: false, label: 'Fluid Responsive (no max width)' },\n ],\n },\n colorSchemeAttribute(),\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Container',\n icon: {\n path: mdiViewArrayOutline.path,\n sx: { color: '#2196f3' },\n },\n category: Aglyn.ComponentCategory.LAYOUT,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n // Explicit, not implicit: a dropped Container is a page section, and\n // sections are XL here (245 of the 248 authored on the marketing host).\n // Relying on MUI's implicit `lg` is what made \"what does no value mean\"\n // an open question in the first place (AGL-1435).\n props: { maxWidth: 'xl' },\n },\n },\n {\n // Case is MD on READING grounds, not as \"one step down\" — at XL a\n // paragraph runs 110–120 characters a line, and even LG (1200px) is far\n // past the 65–75 the eye tracks without losing its place. MD is the\n // stock breakpoint that lands in that band, so the standard grows a\n // third case without growing a bespoke number: the 1328px ban holds\n // because 1328 is a content width, not a breakpoint.\n $id: generatePresetId(ID, 'prose'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Prose Container',\n icon: {\n path: mdiTextBoxOutline.path,\n sx: { color: '#2196f3' },\n },\n category: Aglyn.ComponentCategory.LAYOUT,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { maxWidth: 'md' },\n },\n },\n]\n\nexport default Container\n"],"names":["Aglyn","mdiTextBoxOutline","mdiViewArrayOutline","MuiContainer","createElement","forwardRef","BUNDLE_ID","colorSchemeAttribute","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","dropClearedProps","generatePresetId","Container","props","ref","displayName","ID","schema","$id","pluginId","description","category","ComponentCategory","LAYOUT","icon","path","sx","color","attributes","name","component","FieldComponentType","SWITCH","label","SELECT","options","value","presets","type","NodeType","PRESET","data","componentId","maxWidth"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/container.ts"],"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 * as Aglyn from '@aglyn/aglyn'\nimport {\n mdiTextBoxOutline,\n mdiViewArrayOutline,\n} from '@aglyn/shared-data-mdi'\nimport MuiContainer, { type ContainerProps } from '@mui/material/Container'\nimport { createElement, forwardRef } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { colorSchemeAttribute } from '../utils/color-scheme-attribute'\nimport {\n applySemanticElement,\n semanticElementAttribute,\n semanticElementLabelAttribute,\n} from '../utils/element-picker'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n/**\n * MUI's Container behind the cleared-prop guard (AGL-1435).\n *\n * `maxWidth` is the one authorable attribute in this plugin where a cleared\n * value changes PAGE LAYOUT instead of showing an obviously wrong value, and\n * it satisfied neither branch of MUI's own logic:\n *\n * - `''` / `null` is not `undefined`, so the `maxWidth = 'lg'` destructuring\n * default in `@mui/system/Container/createContainer.js` never fires;\n * - `''` / `null` is falsy, so the `ownerState.maxWidth &&` guard skips both\n * the branch that emits the `max-width` rule and the one that emits the\n * matching utility class.\n *\n * The result is a section with NO width constraint at all — full-bleed, with\n * nothing thrown and nothing visibly wrong in the editor. Clearing the field\n * persists `null` (the AGL-1226 shape; 106 cleared prop values live in the\n * corpus today across other components), so this was reachable, not\n * theoretical. Dropping the key instead lets MUI's own `lg` apply.\n */\nconst Container = forwardRef<HTMLDivElement, ContainerProps>((props, ref) =>\n createElement(MuiContainer, {\n ...applySemanticElement(dropClearedProps(props) as Record<string, unknown>),\n ref,\n }),\n)\nContainer.displayName = 'AglynContainer'\n\n// Component ids are persisted in screen documents; keep the legacy ids.\nexport const ID: Aglyn.ComponentId = 'muiContainer'\n\nexport const schema: Aglyn.ComponentSchema<ContainerProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Container',\n // Static, and its children sit directly in its root: a subtree it heads\n // keeps its server HTML until the visitor nears it (AGL-3581).\n flags: {\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n childrenInRoot: Aglyn.FEATURE_FLAG.ENABLED,\n },\n description: 'Centers your page content and caps how wide it gets.',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: {\n path: mdiViewArrayOutline.path,\n sx: { color: '#2196f3' },\n },\n attributes: [\n semanticElementAttribute('this container'),\n semanticElementLabelAttribute(),\n {\n name: 'fixed',\n description:\n \"If true, set the max-width to match the min-width of the current breakpoint. This is useful if you'd prefer to design for a fixed set of sizes instead of trying to accommodate a fully fluid viewport. It's fluid by default.\",\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Fixed Breakpoints',\n },\n {\n name: 'disableGutters',\n description:\n 'Removes the container’s side padding, so its content runs to the ' +\n 'full width it is centered in. Use it for a full-bleed band; leave ' +\n 'it off for text, which needs the margin on a phone.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Disable Gutters?',\n },\n {\n name: 'maxWidth',\n description:\n 'The width this section stops growing at. New containers start at ' +\n 'XL (1536px), the standard for full-width page sections. Long-form ' +\n 'prose — legal pages, docs, blog and changelog bodies — uses MD ' +\n '(900px), which lands near the 65–75 characters a line that reads ' +\n 'comfortably; the \"Prose Container\" preset starts there. LG (1200px) ' +\n 'is the deliberate middle case for a wide but text-led section, not ' +\n 'a default to spread. Clearing the field falls back to the MUI ' +\n 'default of LG. There is no \"Default\" option: \"Fluid Responsive\" is ' +\n 'the only way to render edge-to-edge, and it has to be chosen on ' +\n 'purpose.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Max Width',\n // Every value here is a real, persistable one. The list used to open\n // with `{ value: '', label: 'Default' }`, which was unpersistable by\n // construction — the attributes form strips `''` on change (AGL-1191)\n // — and, on any path that DID land it, rendered full-bleed rather than\n // any default at all (AGL-1435).\n options: [\n { value: 'xs', label: 'XS - Mobile (444px)' },\n { value: 'sm', label: 'SM - Tablet (600px)' },\n { value: 'md', label: 'MD - Laptop (900px)' },\n { value: 'lg', label: 'LG - Desktop (1200px)' },\n { value: 'xl', label: 'XL - Widescreen (1536px, section standard)' },\n { value: false, label: 'Fluid Responsive (no max width)' },\n ],\n },\n colorSchemeAttribute(),\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Container',\n icon: {\n path: mdiViewArrayOutline.path,\n sx: { color: '#2196f3' },\n },\n category: Aglyn.ComponentCategory.LAYOUT,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n // Explicit, not implicit: a dropped Container is a page section, and\n // sections are XL here (245 of the 248 authored on the marketing host).\n // Relying on MUI's implicit `lg` is what made \"what does no value mean\"\n // an open question in the first place (AGL-1435).\n props: { maxWidth: 'xl' },\n },\n },\n {\n // Case is MD on READING grounds, not as \"one step down\" — at XL a\n // paragraph runs 110–120 characters a line, and even LG (1200px) is far\n // past the 65–75 the eye tracks without losing its place. MD is the\n // stock breakpoint that lands in that band, so the standard grows a\n // third case without growing a bespoke number: the 1328px ban holds\n // because 1328 is a content width, not a breakpoint.\n $id: generatePresetId(ID, 'prose'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Prose Container',\n icon: {\n path: mdiTextBoxOutline.path,\n sx: { color: '#2196f3' },\n },\n category: Aglyn.ComponentCategory.LAYOUT,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { maxWidth: 'md' },\n },\n },\n]\n\nexport default Container\n"],"names":["Aglyn","mdiTextBoxOutline","mdiViewArrayOutline","MuiContainer","createElement","forwardRef","BUNDLE_ID","colorSchemeAttribute","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","dropClearedProps","generatePresetId","Container","props","ref","displayName","ID","schema","$id","pluginId","flags","lazyHydration","FEATURE_FLAG","ENABLED","childrenInRoot","description","category","ComponentCategory","LAYOUT","icon","path","sx","color","attributes","name","component","FieldComponentType","SWITCH","label","SELECT","options","value","presets","type","NodeType","PRESET","data","componentId","maxWidth"],"mappings":"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"}
|
|
@@ -140,6 +140,12 @@ export const schema = {
|
|
|
140
140
|
$id: ID,
|
|
141
141
|
pluginId: BUNDLE_ID,
|
|
142
142
|
displayName: 'Grid',
|
|
143
|
+
// Static, and its children sit directly in its root: a subtree it heads
|
|
144
|
+
// keeps its server HTML until the visitor nears it (AGL-3581).
|
|
145
|
+
flags: {
|
|
146
|
+
lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,
|
|
147
|
+
childrenInRoot: Aglyn.FEATURE_FLAG.ENABLED
|
|
148
|
+
},
|
|
143
149
|
description: 'Responsive 12-column layout. Turn on Container for the row; give ' + 'each cell a Span.',
|
|
144
150
|
category: Aglyn.ComponentCategory.LAYOUT,
|
|
145
151
|
icon: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/grid.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 * as Aglyn from '@aglyn/aglyn'\nimport { mdiViewGrid, mdiViewGridOutline } from '@aglyn/shared-data-mdi'\n// Deep import, NOT the barrel (AGL-1151): `@aglyn/shared-data-enums` re-exports\n// `firebase-auth`, whose `AuthErrorCodes` is a VALUE import of `firebase/auth`.\n// This bundle is `alwaysOn`, so the barrel put the whole Firebase auth client\n// into the chunk every published tenant page loads — a database/identity SDK\n// shipped and evaluated to render static HTML that authenticates nobody. Three\n// breakpoint symbols are the entire reason this module reaches for that\n// library; they live here, one file away from the barrel.\nimport {\n parseBreakpointSpan,\n SPAN_BREAKPOINTS,\n type SpanBreakpoint,\n} from '@aglyn/shared-data-enums/breakpoint-span'\nimport MuiGrid from '@mui/material/Grid'\nimport { forwardRef, type ReactNode } from 'react'\nimport {\n applySemanticElement,\n semanticElementAttribute,\n semanticElementLabelAttribute,\n} from '../utils/element-picker'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { colorSchemeAttribute } from '../utils/color-scheme-attribute'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiGrid'\n\n/**\n * Breakpoint keys MUI's responsive `size`/`offset` objects accept.\n *\n * Re-exported from `@aglyn/shared-data-enums` rather than declared twice\n * (AGL-2486): the attributes panel's breakpoint row and this parser have to\n * agree on the list, and two copies is how they stop agreeing.\n */\nexport const BREAKPOINTS = SPAN_BREAKPOINTS\nexport type Breakpoint = SpanBreakpoint\n\nexport interface GridElementProps {\n /** Flex container behavior; items are its direct Grid children. */\n container?: boolean\n /**\n * Column span. Persisted as one string: a bare span (`6`), the keywords\n * `auto`/`grow`, or per-breakpoint pairs (`xs:12 md:6`). Authored through\n * the breakpoint row in the attributes panel (AGL-2486); the stored\n * format is unchanged from when it was a text box.\n */\n size?: string | number\n /** Empty columns before the item; same syntax as `size`, minus `grow`. */\n offset?: string | number\n spacing?: number | string\n rowSpacing?: number | string\n columnSpacing?: number | string\n /** Total columns in the container; MUI's default is 12. */\n columns?: number | string\n /**\n * Container flow. MUI supports `row`/`row-reverse` ONLY — Grid subdivides\n * a layout into columns, and `column`/`column-reverse` are documented as\n * unsupported (use a Stack for a vertical layout).\n */\n direction?: 'row' | 'row-reverse'\n /** `flex-wrap` for the container; MUI's default is `wrap`. */\n wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'\n children?: ReactNode\n}\n\n/**\n * Parses the authored span syntax into what MUI v6+ Grid expects.\n *\n * MUI dropped the `item` prop and the per-breakpoint `xs=`/`md=` props in\n * v6; v9 (installed here) takes a single `size` that is either a value or\n * a `{ xs, md, … }` object. One STORED string covers both, and this parser\n * owns the translation:\n *\n * `6` → 6\n * `auto` → 'auto'\n * `grow` → 'grow'\n * `xs:12 md:6` → { xs: 12, md: 6 }\n *\n * Anything unparseable returns `undefined` rather than a partial object:\n * a half-applied breakpoint map is a layout that silently differs from\n * what the author typed.\n */\nexport function parseSpan(\n value: unknown,\n): number | 'auto' | 'grow' | Record<string, number | 'auto' | 'grow'> | undefined {\n // The reading itself is `parseBreakpointSpan` in `@aglyn/shared-data-enums`\n // (AGL-2486), shared with the attributes panel's breakpoint row so the\n // editor and the renderer cannot disagree about a stored string. This\n // function keeps its own signature and its \"unparseable means unset\"\n // contract: `raw` is what the editor hands back untouched, and what MUI\n // must never receive.\n const span = parseBreakpointSpan(value as string | number)\n if (span.raw !== undefined) return undefined\n if (span.base !== undefined) return span.base\n return span.values && Object.keys(span.values).length\n ? (span.values as Record<string, number | 'auto' | 'grow'>)\n : undefined\n}\n\n/**\n * Same syntax as `parseSpan`, minus `grow`.\n *\n * MUI's `GridOffset` is `'auto' | number` only — a `grow` offset is not\n * a wider gap, it is a value the layout cannot use, so it is dropped\n * here rather than passed through to be ignored.\n */\nexport function parseOffset(value: unknown) {\n const parsed = parseSpan(value)\n if (parsed === 'grow') return undefined\n if (parsed && typeof parsed === 'object') {\n const kept = Object.fromEntries(\n Object.entries(parsed).filter(([, span]) => span !== 'grow'),\n )\n return Object.keys(kept).length\n ? (kept as Record<string, number | 'auto'>)\n : undefined\n }\n return parsed as number | 'auto' | undefined\n}\n\n/** Spacing/columns arrive as strings from number fields; MUI wants numbers. */\nfunction toNumber(value: unknown): number | undefined {\n if (value == null || value === '') return undefined\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\n/**\n * Responsive 12-column grid (https://mui.com/material-ui/react-grid/).\n * One element covers both roles, matching MUI v6+: switch **Container**\n * on for the row, leave it off and set a **Span** for each cell.\n */\nconst GridElement = forwardRef<HTMLDivElement, GridElementProps>(\n (props, ref) => {\n const {\n container,\n size,\n offset,\n spacing,\n rowSpacing,\n columnSpacing,\n columns,\n direction,\n wrap,\n children,\n ...rest\n } = props\n return (\n <MuiGrid\n ref={ref}\n container={!!container}\n size={parseSpan(size)}\n offset={parseOffset(offset)}\n // Spacing props only apply to containers; MUI ignores them on\n // items, so no need to strip them here.\n spacing={toNumber(spacing)}\n rowSpacing={toNumber(rowSpacing)}\n columnSpacing={toNumber(columnSpacing)}\n columns={toNumber(columns)}\n // A CLEARED select persists as `null`, and MUI resolves both of these\n // as responsive values — `null.xs` throws during SSR and 500s the\n // published page (the AGL-1226 shape). `undefined` is what \"cleared\"\n // has to mean by the time it reaches MUI.\n {...dropClearedProps({ direction, wrap })}\n {...applySemanticElement(dropClearedProps(rest) as Record<string, unknown>)}\n >\n {children}\n </MuiGrid>\n )\n },\n)\nGridElement.displayName = 'AglynGrid'\n\n/** Container-only props: MUI ignores these on an item. */\nconst CONTAINER_ONLY = { when: 'container', is: true }\n/** Item-only props: a container spans its parent, not a column count. */\nconst ITEM_ONLY = { when: 'container', is: true, notMatch: true }\n\nconst SPAN_HELP =\n 'How many columns this cell takes. Set **All** for every screen size, or ' +\n 'give individual breakpoints a value — `xs` applies from the smallest ' +\n 'screens up and each larger breakpoint overrides it. `auto` fits the ' +\n 'content, `grow` takes the remaining space.'\n\nexport const schema: Aglyn.ComponentSchema<GridElementProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Grid',\n description:\n 'Responsive 12-column layout. Turn on Container for the row; give ' +\n 'each cell a Span.',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiViewGrid.path, sx: { color: '#2196f3' } },\n attributes: [\n semanticElementAttribute('this grid'),\n semanticElementLabelAttribute(),\n {\n name: 'container',\n label: 'Container?',\n description:\n 'If true, this grid lays its direct Grid children out in columns. ' +\n 'Leave it off for a cell inside another grid.',\n component: Aglyn.FieldComponentType.SWITCH,\n },\n {\n name: 'size',\n label: 'Span',\n description: SPAN_HELP,\n // A row of breakpoint controls rather than a text box (AGL-2486). The\n // STORED value is the same string it always was; only the way it is\n // authored changed. `xs:12 md:2` was a developer syntax documented\n // nowhere but this tooltip, so the responsive capability was there and\n // effectively unreachable.\n component: Aglyn.FieldComponentType.BREAKPOINT_SPAN,\n condition: ITEM_ONLY,\n },\n {\n name: 'offset',\n label: 'Offset',\n description:\n 'Empty columns before this cell. `auto` pushes the cell to the ' +\n 'right; `grow` is a span keyword and not an offset, so it is not ' +\n 'offered here.',\n component: Aglyn.FieldComponentType.BREAKPOINT_SPAN,\n // MUI's GridOffset is `'auto' | number`: a zero offset is a real\n // choice, and `grow` is not one at all.\n allowGrow: false,\n minSpan: 0,\n condition: ITEM_ONLY,\n },\n {\n name: 'spacing',\n label: 'Spacing',\n description:\n 'Gap between cells, in theme spacing units (1 = 8px by default).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: CONTAINER_ONLY,\n },\n {\n name: 'rowSpacing',\n label: 'Row spacing',\n description: 'Vertical gap only; overrides Spacing.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: CONTAINER_ONLY,\n },\n {\n name: 'columnSpacing',\n label: 'Column spacing',\n description: 'Horizontal gap only; overrides Spacing.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: CONTAINER_ONLY,\n },\n {\n name: 'columns',\n label: 'Columns',\n description: 'Total columns the row is divided into. Default 12.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: CONTAINER_ONLY,\n },\n {\n name: 'direction',\n label: 'Direction',\n // The option that is NOT offered is the point of this field. MUI's own\n // API doc: \"Only `row` and `row-reverse` are supported. `column` and\n // `column-reverse` are not supported, because the Grid component is\n // designed to subdivide layouts into columns, not rows.\" Offering them\n // would be a control that silently does nothing.\n description:\n 'Sets the `flex-direction` for the row. Only Row and Row Reversed ' +\n 'are supported — Grid divides a layout into columns, so a column ' +\n 'direction does nothing. Use a Stack for a vertical layout.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'row', label: 'Row' },\n { value: 'row-reverse', label: 'Row Reversed' },\n ],\n condition: CONTAINER_ONLY,\n },\n {\n name: 'wrap',\n label: 'Wrap',\n description:\n 'Whether cells that do not fit move onto a new line. Default Wrap; ' +\n 'No Wrap keeps every cell on one line and lets them shrink instead.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'wrap', label: 'Wrap' },\n { value: 'nowrap', label: 'No Wrap' },\n { value: 'wrap-reverse', label: 'Wrap Reversed' },\n ],\n condition: CONTAINER_ONLY,\n },\n colorSchemeAttribute(),\n ],\n}\n\nconst cell = (size: string, text: string) => ({\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { size },\n nodes: [\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: { variant: 'body2', children: text },\n },\n ],\n})\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n // Ships as a working responsive row, not a bare container: an empty\n // grid renders as nothing at all on the canvas.\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Grid',\n pluginId: BUNDLE_ID,\n description: 'Responsive row — three columns that stack on mobile',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { container: true, spacing: 2 },\n nodes: [\n cell('xs:12 md:4', 'Column one'),\n cell('xs:12 md:4', 'Column two'),\n cell('xs:12 md:4', 'Column three'),\n ],\n },\n },\n {\n $id: generatePresetId(ID, 'cell'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Grid Cell',\n pluginId: BUNDLE_ID,\n description: 'A single cell to add to an existing grid row',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiViewGridOutline.path, sx: { color: '#2196f3' } },\n data: cell('xs:12 md:6', 'Cell'),\n },\n]\n\nexport default GridElement\n"],"names":["Aglyn","mdiViewGrid","mdiViewGridOutline","parseBreakpointSpan","SPAN_BREAKPOINTS","MuiGrid","forwardRef","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","BUNDLE_ID","colorSchemeAttribute","dropClearedProps","generatePresetId","ID","BREAKPOINTS","parseSpan","value","span","raw","undefined","base","values","Object","keys","length","parseOffset","parsed","kept","fromEntries","entries","filter","toNumber","Number","isFinite","GridElement","props","ref","container","size","offset","spacing","rowSpacing","columnSpacing","columns","direction","wrap","children","rest","displayName","CONTAINER_ONLY","when","is","ITEM_ONLY","notMatch","SPAN_HELP","schema","$id","pluginId","description","category","ComponentCategory","LAYOUT","icon","path","sx","color","attributes","name","label","component","FieldComponentType","SWITCH","BREAKPOINT_SPAN","condition","allowGrow","minSpan","TEXT_FIELD","type","SELECT","options","cell","text","componentId","nodes","variant","presets","NodeType","PRESET","data"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/grid.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 * as Aglyn from '@aglyn/aglyn'\nimport { mdiViewGrid, mdiViewGridOutline } from '@aglyn/shared-data-mdi'\n// Deep import, NOT the barrel (AGL-1151): `@aglyn/shared-data-enums` re-exports\n// `firebase-auth`, whose `AuthErrorCodes` is a VALUE import of `firebase/auth`.\n// This bundle is `alwaysOn`, so the barrel put the whole Firebase auth client\n// into the chunk every published tenant page loads — a database/identity SDK\n// shipped and evaluated to render static HTML that authenticates nobody. Three\n// breakpoint symbols are the entire reason this module reaches for that\n// library; they live here, one file away from the barrel.\nimport {\n parseBreakpointSpan,\n SPAN_BREAKPOINTS,\n type SpanBreakpoint,\n} from '@aglyn/shared-data-enums/breakpoint-span'\nimport MuiGrid from '@mui/material/Grid'\nimport { forwardRef, type ReactNode } from 'react'\nimport {\n applySemanticElement,\n semanticElementAttribute,\n semanticElementLabelAttribute,\n} from '../utils/element-picker'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { colorSchemeAttribute } from '../utils/color-scheme-attribute'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiGrid'\n\n/**\n * Breakpoint keys MUI's responsive `size`/`offset` objects accept.\n *\n * Re-exported from `@aglyn/shared-data-enums` rather than declared twice\n * (AGL-2486): the attributes panel's breakpoint row and this parser have to\n * agree on the list, and two copies is how they stop agreeing.\n */\nexport const BREAKPOINTS = SPAN_BREAKPOINTS\nexport type Breakpoint = SpanBreakpoint\n\nexport interface GridElementProps {\n /** Flex container behavior; items are its direct Grid children. */\n container?: boolean\n /**\n * Column span. Persisted as one string: a bare span (`6`), the keywords\n * `auto`/`grow`, or per-breakpoint pairs (`xs:12 md:6`). Authored through\n * the breakpoint row in the attributes panel (AGL-2486); the stored\n * format is unchanged from when it was a text box.\n */\n size?: string | number\n /** Empty columns before the item; same syntax as `size`, minus `grow`. */\n offset?: string | number\n spacing?: number | string\n rowSpacing?: number | string\n columnSpacing?: number | string\n /** Total columns in the container; MUI's default is 12. */\n columns?: number | string\n /**\n * Container flow. MUI supports `row`/`row-reverse` ONLY — Grid subdivides\n * a layout into columns, and `column`/`column-reverse` are documented as\n * unsupported (use a Stack for a vertical layout).\n */\n direction?: 'row' | 'row-reverse'\n /** `flex-wrap` for the container; MUI's default is `wrap`. */\n wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'\n children?: ReactNode\n}\n\n/**\n * Parses the authored span syntax into what MUI v6+ Grid expects.\n *\n * MUI dropped the `item` prop and the per-breakpoint `xs=`/`md=` props in\n * v6; v9 (installed here) takes a single `size` that is either a value or\n * a `{ xs, md, … }` object. One STORED string covers both, and this parser\n * owns the translation:\n *\n * `6` → 6\n * `auto` → 'auto'\n * `grow` → 'grow'\n * `xs:12 md:6` → { xs: 12, md: 6 }\n *\n * Anything unparseable returns `undefined` rather than a partial object:\n * a half-applied breakpoint map is a layout that silently differs from\n * what the author typed.\n */\nexport function parseSpan(\n value: unknown,\n): number | 'auto' | 'grow' | Record<string, number | 'auto' | 'grow'> | undefined {\n // The reading itself is `parseBreakpointSpan` in `@aglyn/shared-data-enums`\n // (AGL-2486), shared with the attributes panel's breakpoint row so the\n // editor and the renderer cannot disagree about a stored string. This\n // function keeps its own signature and its \"unparseable means unset\"\n // contract: `raw` is what the editor hands back untouched, and what MUI\n // must never receive.\n const span = parseBreakpointSpan(value as string | number)\n if (span.raw !== undefined) return undefined\n if (span.base !== undefined) return span.base\n return span.values && Object.keys(span.values).length\n ? (span.values as Record<string, number | 'auto' | 'grow'>)\n : undefined\n}\n\n/**\n * Same syntax as `parseSpan`, minus `grow`.\n *\n * MUI's `GridOffset` is `'auto' | number` only — a `grow` offset is not\n * a wider gap, it is a value the layout cannot use, so it is dropped\n * here rather than passed through to be ignored.\n */\nexport function parseOffset(value: unknown) {\n const parsed = parseSpan(value)\n if (parsed === 'grow') return undefined\n if (parsed && typeof parsed === 'object') {\n const kept = Object.fromEntries(\n Object.entries(parsed).filter(([, span]) => span !== 'grow'),\n )\n return Object.keys(kept).length\n ? (kept as Record<string, number | 'auto'>)\n : undefined\n }\n return parsed as number | 'auto' | undefined\n}\n\n/** Spacing/columns arrive as strings from number fields; MUI wants numbers. */\nfunction toNumber(value: unknown): number | undefined {\n if (value == null || value === '') return undefined\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\n/**\n * Responsive 12-column grid (https://mui.com/material-ui/react-grid/).\n * One element covers both roles, matching MUI v6+: switch **Container**\n * on for the row, leave it off and set a **Span** for each cell.\n */\nconst GridElement = forwardRef<HTMLDivElement, GridElementProps>(\n (props, ref) => {\n const {\n container,\n size,\n offset,\n spacing,\n rowSpacing,\n columnSpacing,\n columns,\n direction,\n wrap,\n children,\n ...rest\n } = props\n return (\n <MuiGrid\n ref={ref}\n container={!!container}\n size={parseSpan(size)}\n offset={parseOffset(offset)}\n // Spacing props only apply to containers; MUI ignores them on\n // items, so no need to strip them here.\n spacing={toNumber(spacing)}\n rowSpacing={toNumber(rowSpacing)}\n columnSpacing={toNumber(columnSpacing)}\n columns={toNumber(columns)}\n // A CLEARED select persists as `null`, and MUI resolves both of these\n // as responsive values — `null.xs` throws during SSR and 500s the\n // published page (the AGL-1226 shape). `undefined` is what \"cleared\"\n // has to mean by the time it reaches MUI.\n {...dropClearedProps({ direction, wrap })}\n {...applySemanticElement(dropClearedProps(rest) as Record<string, unknown>)}\n >\n {children}\n </MuiGrid>\n )\n },\n)\nGridElement.displayName = 'AglynGrid'\n\n/** Container-only props: MUI ignores these on an item. */\nconst CONTAINER_ONLY = { when: 'container', is: true }\n/** Item-only props: a container spans its parent, not a column count. */\nconst ITEM_ONLY = { when: 'container', is: true, notMatch: true }\n\nconst SPAN_HELP =\n 'How many columns this cell takes. Set **All** for every screen size, or ' +\n 'give individual breakpoints a value — `xs` applies from the smallest ' +\n 'screens up and each larger breakpoint overrides it. `auto` fits the ' +\n 'content, `grow` takes the remaining space.'\n\nexport const schema: Aglyn.ComponentSchema<GridElementProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Grid',\n // Static, and its children sit directly in its root: a subtree it heads\n // keeps its server HTML until the visitor nears it (AGL-3581).\n flags: {\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n childrenInRoot: Aglyn.FEATURE_FLAG.ENABLED,\n },\n description:\n 'Responsive 12-column layout. Turn on Container for the row; give ' +\n 'each cell a Span.',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiViewGrid.path, sx: { color: '#2196f3' } },\n attributes: [\n semanticElementAttribute('this grid'),\n semanticElementLabelAttribute(),\n {\n name: 'container',\n label: 'Container?',\n description:\n 'If true, this grid lays its direct Grid children out in columns. ' +\n 'Leave it off for a cell inside another grid.',\n component: Aglyn.FieldComponentType.SWITCH,\n },\n {\n name: 'size',\n label: 'Span',\n description: SPAN_HELP,\n // A row of breakpoint controls rather than a text box (AGL-2486). The\n // STORED value is the same string it always was; only the way it is\n // authored changed. `xs:12 md:2` was a developer syntax documented\n // nowhere but this tooltip, so the responsive capability was there and\n // effectively unreachable.\n component: Aglyn.FieldComponentType.BREAKPOINT_SPAN,\n condition: ITEM_ONLY,\n },\n {\n name: 'offset',\n label: 'Offset',\n description:\n 'Empty columns before this cell. `auto` pushes the cell to the ' +\n 'right; `grow` is a span keyword and not an offset, so it is not ' +\n 'offered here.',\n component: Aglyn.FieldComponentType.BREAKPOINT_SPAN,\n // MUI's GridOffset is `'auto' | number`: a zero offset is a real\n // choice, and `grow` is not one at all.\n allowGrow: false,\n minSpan: 0,\n condition: ITEM_ONLY,\n },\n {\n name: 'spacing',\n label: 'Spacing',\n description:\n 'Gap between cells, in theme spacing units (1 = 8px by default).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: CONTAINER_ONLY,\n },\n {\n name: 'rowSpacing',\n label: 'Row spacing',\n description: 'Vertical gap only; overrides Spacing.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: CONTAINER_ONLY,\n },\n {\n name: 'columnSpacing',\n label: 'Column spacing',\n description: 'Horizontal gap only; overrides Spacing.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: CONTAINER_ONLY,\n },\n {\n name: 'columns',\n label: 'Columns',\n description: 'Total columns the row is divided into. Default 12.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: CONTAINER_ONLY,\n },\n {\n name: 'direction',\n label: 'Direction',\n // The option that is NOT offered is the point of this field. MUI's own\n // API doc: \"Only `row` and `row-reverse` are supported. `column` and\n // `column-reverse` are not supported, because the Grid component is\n // designed to subdivide layouts into columns, not rows.\" Offering them\n // would be a control that silently does nothing.\n description:\n 'Sets the `flex-direction` for the row. Only Row and Row Reversed ' +\n 'are supported — Grid divides a layout into columns, so a column ' +\n 'direction does nothing. Use a Stack for a vertical layout.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'row', label: 'Row' },\n { value: 'row-reverse', label: 'Row Reversed' },\n ],\n condition: CONTAINER_ONLY,\n },\n {\n name: 'wrap',\n label: 'Wrap',\n description:\n 'Whether cells that do not fit move onto a new line. Default Wrap; ' +\n 'No Wrap keeps every cell on one line and lets them shrink instead.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'wrap', label: 'Wrap' },\n { value: 'nowrap', label: 'No Wrap' },\n { value: 'wrap-reverse', label: 'Wrap Reversed' },\n ],\n condition: CONTAINER_ONLY,\n },\n colorSchemeAttribute(),\n ],\n}\n\nconst cell = (size: string, text: string) => ({\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { size },\n nodes: [\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: { variant: 'body2', children: text },\n },\n ],\n})\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n // Ships as a working responsive row, not a bare container: an empty\n // grid renders as nothing at all on the canvas.\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Grid',\n pluginId: BUNDLE_ID,\n description: 'Responsive row — three columns that stack on mobile',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { container: true, spacing: 2 },\n nodes: [\n cell('xs:12 md:4', 'Column one'),\n cell('xs:12 md:4', 'Column two'),\n cell('xs:12 md:4', 'Column three'),\n ],\n },\n },\n {\n $id: generatePresetId(ID, 'cell'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Grid Cell',\n pluginId: BUNDLE_ID,\n description: 'A single cell to add to an existing grid row',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiViewGridOutline.path, sx: { color: '#2196f3' } },\n data: cell('xs:12 md:6', 'Cell'),\n },\n]\n\nexport default GridElement\n"],"names":["Aglyn","mdiViewGrid","mdiViewGridOutline","parseBreakpointSpan","SPAN_BREAKPOINTS","MuiGrid","forwardRef","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","BUNDLE_ID","colorSchemeAttribute","dropClearedProps","generatePresetId","ID","BREAKPOINTS","parseSpan","value","span","raw","undefined","base","values","Object","keys","length","parseOffset","parsed","kept","fromEntries","entries","filter","toNumber","Number","isFinite","GridElement","props","ref","container","size","offset","spacing","rowSpacing","columnSpacing","columns","direction","wrap","children","rest","displayName","CONTAINER_ONLY","when","is","ITEM_ONLY","notMatch","SPAN_HELP","schema","$id","pluginId","flags","lazyHydration","FEATURE_FLAG","ENABLED","childrenInRoot","description","category","ComponentCategory","LAYOUT","icon","path","sx","color","attributes","name","label","component","FieldComponentType","SWITCH","BREAKPOINT_SPAN","condition","allowGrow","minSpan","TEXT_FIELD","type","SELECT","options","cell","text","componentId","nodes","variant","presets","NodeType","PRESET","data"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/icon.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 * as Aglyn from '@aglyn/aglyn'\nimport { getMdiIconPath, mdiShapePlus } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport Box from '@mui/material/Box'\nimport type { SxProps } from '@mui/material/styles'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'icon'\n\nexport interface IconProps {\n /** mdi icon id from the picker (AGL-146). */\n iconId?: string\n /**\n * Resolved SVG path for `iconId`, denormalized at author time (AGL-1212).\n * Render surfaces read this and never load the icon catalog.\n */\n iconPath?: string\n /** Icon size in px; defaults to 24. */\n size?: number\n /** CSS color; defaults to the inherited text color. */\n color?: string\n /**\n * Authored node styles, handed over by the renderer rather than typed\n * into an attribute — recomposed below so the Styles panel's values are\n * merged rather than replaced (AGL-1284).\n */\n sx?: SxProps\n}\n\n/**\n * Icon element (AGL-146): renders a picked mdi icon with size/color\n * controls; an empty pick shows a labeled placeholder so the element stays\n * selectable in the editor.\n *\n * Path resolution order (AGL-1212): the persisted `iconPath` first, then the\n * in-memory catalog for documents authored before paths were stored. The\n * catalog is ~2.9 MB and is only loaded by picker surfaces, so on the tenant\n * site and in preview the second lookup misses — which is why it must NOT go\n * through `getMdiIconFromId`, whose `DEFAULT_ICON` fallback carries a real\n * path and rendered a \"help\" glyph on every published page.\n */\nconst Icon = forwardRef<HTMLElement, IconProps>((props, ref) => {\n const { iconId, iconPath, size, color, ...rest } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n const path = iconPath || getMdiIconPath(iconId)\n const icon = path ? { path } : undefined\n if (!icon?.path) {\n // The labeled box is for the author, so only editing surfaces draw it; a\n // published page renders the bare element, as the span a picked icon is.\n if (!suppressNavigation) return <Box ref={ref} component=\"span\" {...rest} />\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n width: 48,\n height: 48,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n border: '1px dashed',\n borderColor: 'divider',\n borderRadius: 1,\n color: 'text.secondary',\n fontSize: 10,\n fontFamily: 'system-ui, sans-serif',\n },\n ...nodeSx,\n ]}\n >\n {'Icon'}\n </Box>\n )\n }\n return (\n <Box ref={ref} component=\"span\" sx={{ display: 'inline-flex' }} {...rest}>\n <MdiIcon\n path={icon.path}\n sx={{\n fontSize: size && size > 0 ? size : 24,\n ...(color ? { color } : {}),\n }}\n />\n </Box>\n )\n})\nIcon.displayName = 'Icon'\n\nexport const schema: Aglyn.ComponentSchema<IconProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Icon',\n description:\n 'A single icon from the library, at the size and color you pick.',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: {\n path: mdiShapePlus.path,\n sx: { color: '#7b1fa2' },\n },\n flags: {\n selfClosing: Aglyn.FEATURE_FLAG.ENABLED,\n },\n attributes: [\n {\n name: 'iconId',\n description: 'Pick any icon from the library.',\n component: Aglyn.FieldComponentType.ICON_PICKER,\n label: 'Icon',\n },\n {\n name: 'size',\n description: 'Icon size in pixels (default 24).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Size (px)',\n type: 'number',\n },\n {\n name: 'color',\n description: 'CSS color, e.g. #7b1fa2; empty inherits the text color.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Color',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Icon',\n pluginId: BUNDLE_ID,\n description: 'A single icon from the mdi library',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: {\n path: mdiShapePlus.path,\n sx: { color: '#7b1fa2' },\n },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default Icon\n"],"names":["Aglyn","getMdiIconPath","mdiShapePlus","MdiIcon","Box","forwardRef","useContext","BUNDLE_ID","generatePresetId","ID","Icon","props","ref","iconId","iconPath","size","color","rest","nodeSx","Array","isArray","suppressNavigation","ScreenLinkContext","path","icon","undefined","component","sx","width","height","display","alignItems","justifyContent","border","borderColor","borderRadius","fontSize","fontFamily","displayName","schema","$id","pluginId","description","category","ComponentCategory","MEDIA","flags","
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/icon.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 * as Aglyn from '@aglyn/aglyn'\nimport { getMdiIconPath, mdiShapePlus } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport Box from '@mui/material/Box'\nimport type { SxProps } from '@mui/material/styles'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'icon'\n\nexport interface IconProps {\n /** mdi icon id from the picker (AGL-146). */\n iconId?: string\n /**\n * Resolved SVG path for `iconId`, denormalized at author time (AGL-1212).\n * Render surfaces read this and never load the icon catalog.\n */\n iconPath?: string\n /** Icon size in px; defaults to 24. */\n size?: number\n /** CSS color; defaults to the inherited text color. */\n color?: string\n /**\n * Authored node styles, handed over by the renderer rather than typed\n * into an attribute — recomposed below so the Styles panel's values are\n * merged rather than replaced (AGL-1284).\n */\n sx?: SxProps\n}\n\n/**\n * Icon element (AGL-146): renders a picked mdi icon with size/color\n * controls; an empty pick shows a labeled placeholder so the element stays\n * selectable in the editor.\n *\n * Path resolution order (AGL-1212): the persisted `iconPath` first, then the\n * in-memory catalog for documents authored before paths were stored. The\n * catalog is ~2.9 MB and is only loaded by picker surfaces, so on the tenant\n * site and in preview the second lookup misses — which is why it must NOT go\n * through `getMdiIconFromId`, whose `DEFAULT_ICON` fallback carries a real\n * path and rendered a \"help\" glyph on every published page.\n */\nconst Icon = forwardRef<HTMLElement, IconProps>((props, ref) => {\n const { iconId, iconPath, size, color, ...rest } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n const path = iconPath || getMdiIconPath(iconId)\n const icon = path ? { path } : undefined\n if (!icon?.path) {\n // The labeled box is for the author, so only editing surfaces draw it; a\n // published page renders the bare element, as the span a picked icon is.\n if (!suppressNavigation) return <Box ref={ref} component=\"span\" {...rest} />\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n width: 48,\n height: 48,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n border: '1px dashed',\n borderColor: 'divider',\n borderRadius: 1,\n color: 'text.secondary',\n fontSize: 10,\n fontFamily: 'system-ui, sans-serif',\n },\n ...nodeSx,\n ]}\n >\n {'Icon'}\n </Box>\n )\n }\n return (\n <Box ref={ref} component=\"span\" sx={{ display: 'inline-flex' }} {...rest}>\n <MdiIcon\n path={icon.path}\n sx={{\n fontSize: size && size > 0 ? size : 24,\n ...(color ? { color } : {}),\n }}\n />\n </Box>\n )\n})\nIcon.displayName = 'Icon'\n\nexport const schema: Aglyn.ComponentSchema<IconProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Icon',\n description:\n 'A single icon from the library, at the size and color you pick.',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: {\n path: mdiShapePlus.path,\n sx: { color: '#7b1fa2' },\n },\n flags: {\n // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n selfClosing: Aglyn.FEATURE_FLAG.ENABLED,\n },\n attributes: [\n {\n name: 'iconId',\n description: 'Pick any icon from the library.',\n component: Aglyn.FieldComponentType.ICON_PICKER,\n label: 'Icon',\n },\n {\n name: 'size',\n description: 'Icon size in pixels (default 24).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Size (px)',\n type: 'number',\n },\n {\n name: 'color',\n description: 'CSS color, e.g. #7b1fa2; empty inherits the text color.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Color',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Icon',\n pluginId: BUNDLE_ID,\n description: 'A single icon from the mdi library',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: {\n path: mdiShapePlus.path,\n sx: { color: '#7b1fa2' },\n },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default Icon\n"],"names":["Aglyn","getMdiIconPath","mdiShapePlus","MdiIcon","Box","forwardRef","useContext","BUNDLE_ID","generatePresetId","ID","Icon","props","ref","iconId","iconPath","size","color","rest","nodeSx","Array","isArray","suppressNavigation","ScreenLinkContext","path","icon","undefined","component","sx","width","height","display","alignItems","justifyContent","border","borderColor","borderRadius","fontSize","fontFamily","displayName","schema","$id","pluginId","description","category","ComponentCategory","MEDIA","flags","lazyHydration","FEATURE_FLAG","ENABLED","selfClosing","attributes","name","FieldComponentType","ICON_PICKER","label","TEXT_FIELD","type","presets","NodeType","PRESET","data","componentId"],"mappings":"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"}
|