@aglyn/plugins-mui 1.0.0-beta.172 → 1.0.0-beta.173
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 +3 -1
- package/src/lib/components/box.js.map +1 -1
- package/src/lib/components/container.js +3 -1
- package/src/lib/components/container.js.map +1 -1
- package/src/lib/components/grid.js +3 -1
- package/src/lib/components/grid.js.map +1 -1
- package/src/lib/components/reusable-instance.js +3 -2
- package/src/lib/components/reusable-instance.js.map +1 -1
- package/src/lib/components/section.js +3 -1
- package/src/lib/components/section.js.map +1 -1
- package/src/lib/components/stack.js +5 -1
- package/src/lib/components/stack.js.map +1 -1
- package/src/lib/utils/color-scheme-attribute.d.ts +32 -0
- package/src/lib/utils/color-scheme-attribute.js +53 -0
- package/src/lib/utils/color-scheme-attribute.js.map +1 -0
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.173",
|
|
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.173",
|
|
29
|
+
"@aglyn/shared-data-enums": "1.0.0-beta.173",
|
|
30
|
+
"@aglyn/shared-data-mdi": "1.0.0-beta.173",
|
|
31
|
+
"@aglyn/shared-ui-jsx": "1.0.0-beta.173",
|
|
32
|
+
"@aglyn/shared-ui-theme": "1.0.0-beta.173",
|
|
33
|
+
"@aglyn/shared-util-vendor": "1.0.0-beta.173",
|
|
34
34
|
"@swc/helpers": "0.5.23",
|
|
35
35
|
"mobx": "^6.16.1",
|
|
36
36
|
"mobx-react-lite": "^4.1.1"
|
|
@@ -21,6 +21,7 @@ import { mdiSquareOutline } from "@aglyn/shared-data-mdi";
|
|
|
21
21
|
import MuiBox from "@mui/material/Box";
|
|
22
22
|
import { forwardRef } from "react";
|
|
23
23
|
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
24
|
+
import { colorSchemeAttribute } from "../utils/color-scheme-attribute.js";
|
|
24
25
|
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
25
26
|
// Component ids are persisted in screen documents; never rename.
|
|
26
27
|
export const ID = 'muiBox';
|
|
@@ -84,7 +85,8 @@ export const schema = {
|
|
|
84
85
|
value,
|
|
85
86
|
label: value
|
|
86
87
|
}))
|
|
87
|
-
}
|
|
88
|
+
},
|
|
89
|
+
colorSchemeAttribute()
|
|
88
90
|
]
|
|
89
91
|
};
|
|
90
92
|
export const presets = [
|
|
@@ -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 { 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 ],\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","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,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,
|
|
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;IACbI,aACE,sEACA;IACFC,UAAUtB,MAAMuB,iBAAiB,CAACC,MAAM;IACxCC,MAAM;QAAEC,MAAMzB,iBAAiByB,IAAI;QAAEC,IAAI;YAAEC,OAAO;QAAU;IAAE;IAC9DC,YAAY;QACV;YACEC,MAAM;YACNC,OAAO;YACPV,aACE,wDACA,mEACA;YACFT,WAAWZ,MAAMgC,kBAAkB,CAACC,MAAM;YAC1CC,SAAS1B,aAAa2B,GAAG,CAAC,CAACC,QAAW,CAAA;oBAAEA;oBAAOL,OAAOK;gBAAM,CAAA;QAC9D;QACA/B;KACD;AACH,EAAC;AAED,OAAO,MAAMgC,UAAgC;IAC3C;QACElB,KAAKb,iBAAiBC;QACtB+B,MAAMtC,MAAMuC,QAAQ,CAACC,MAAM;QAC3BvB,aAAa;QACbG,UAAUhB;QACViB,aAAa;QACbC,UAAUtB,MAAMuB,iBAAiB,CAACC,MAAM;QACxCC,MAAMP,OAAOO,IAAI;QACjBgB,MAAM;YACJtB,KAAK;YACLuB,aAAanC;YACba,UAAUhB;YACV,kEAAkE;YAClE,mEAAmE;YACnEM,OAAO;gBAAEE,WAAW;YAAM;YAC1B,kEAAkE;YAClE,mEAAmE;YACnE,sBAAsB;YACtBe,IAAI;gBACFgB,YAAY;gBACZC,cAAc;gBACdC,eAAe;gBACfC,aAAa;gBACbC,QAAQ;gBACRC,aAAa;gBACbC,cAAc;YAChB;QACF;IACF;CACD,CAAA;AAED,eAAexC,WAAU"}
|
|
@@ -19,6 +19,7 @@ import { mdiTextBoxOutline, mdiViewArrayOutline } from "@aglyn/shared-data-mdi";
|
|
|
19
19
|
import MuiContainer from "@mui/material/Container";
|
|
20
20
|
import { createElement, forwardRef } from "react";
|
|
21
21
|
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
22
|
+
import { colorSchemeAttribute } from "../utils/color-scheme-attribute.js";
|
|
22
23
|
import { applySemanticElement, semanticElementAttribute, semanticElementLabelAttribute } from "../utils/element-picker.js";
|
|
23
24
|
import { dropClearedProps } from "../utils/drop-cleared-props.js";
|
|
24
25
|
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
@@ -109,7 +110,8 @@ export const schema = {
|
|
|
109
110
|
label: 'Fluid Responsive (no max width)'
|
|
110
111
|
}
|
|
111
112
|
]
|
|
112
|
-
}
|
|
113
|
+
},
|
|
114
|
+
colorSchemeAttribute()
|
|
113
115
|
]
|
|
114
116
|
};
|
|
115
117
|
export const presets = [
|
|
@@ -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 {\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 ],\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","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":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SACEC,iBAAiB,EACjBC,mBAAmB,QACd,yBAAwB;AAC/B,OAAOC,kBAA2C,0BAAyB;AAC3E,SAASC,aAAa,EAAEC,UAAU,QAAQ,QAAO;AACjD,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SACEC,oBAAoB,EACpBC,wBAAwB,EACxBC,6BAA6B,QACxB,6BAAyB;AAChC,SAASC,gBAAgB,QAAQ,iCAA6B;AAC9D,SAASC,gBAAgB,QAAQ,iCAA6B;AAE9D;;;;;;;;;;;;;;;;;;CAkBC,GACD,MAAMC,
|
|
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":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SACEC,iBAAiB,EACjBC,mBAAmB,QACd,yBAAwB;AAC/B,OAAOC,kBAA2C,0BAAyB;AAC3E,SAASC,aAAa,EAAEC,UAAU,QAAQ,QAAO;AACjD,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,oBAAoB,QAAQ,qCAAiC;AACtE,SACEC,oBAAoB,EACpBC,wBAAwB,EACxBC,6BAA6B,QACxB,6BAAyB;AAChC,SAASC,gBAAgB,QAAQ,iCAA6B;AAC9D,SAASC,gBAAgB,QAAQ,iCAA6B;AAE9D;;;;;;;;;;;;;;;;;;CAkBC,GACD,MAAMC,YAAYR,WAA2C,CAACS,OAAOC,MACnEX,cAAcD,cAAc,aACvBK,qBAAqBG,iBAAiBG;QACzCC;;AAGJF,UAAUG,WAAW,GAAG;AAExB,wEAAwE;AACxE,OAAO,MAAMC,KAAwB,eAAc;AAEnD,OAAO,MAAMC,SAAgD;IAC3DC,KAAKF;IACLG,UAAUd;IACVU,aAAa;IACbK,aAAa;IACbC,UAAUtB,MAAMuB,iBAAiB,CAACC,MAAM;IACxCC,MAAM;QACJC,MAAMxB,oBAAoBwB,IAAI;QAC9BC,IAAI;YAAEC,OAAO;QAAU;IACzB;IACAC,YAAY;QACVpB,yBAAyB;QACzBC;QACA;YACEoB,MAAM;YACNT,aACE;YACFU,WAAW/B,MAAMgC,kBAAkB,CAACC,MAAM;YAC1CC,OAAO;QACT;QACA;YACEJ,MAAM;YACNT,aACE,sEACA,uEACA;YACFU,WAAW/B,MAAMgC,kBAAkB,CAACC,MAAM;YAC1CC,OAAO;QACT;QACA;YACEJ,MAAM;YACNT,aACE,sEACA,uEACA,oEACA,sEACA,yEACA,wEACA,mEACA,wEACA,qEACA;YACFU,WAAW/B,MAAMgC,kBAAkB,CAACG,MAAM;YAC1CD,OAAO;YACP,qEAAqE;YACrE,qEAAqE;YACrE,sEAAsE;YACtE,uEAAuE;YACvE,iCAAiC;YACjCE,SAAS;gBACP;oBAAEC,OAAO;oBAAMH,OAAO;gBAAsB;gBAC5C;oBAAEG,OAAO;oBAAMH,OAAO;gBAAsB;gBAC5C;oBAAEG,OAAO;oBAAMH,OAAO;gBAAsB;gBAC5C;oBAAEG,OAAO;oBAAMH,OAAO;gBAAwB;gBAC9C;oBAAEG,OAAO;oBAAMH,OAAO;gBAA6C;gBACnE;oBAAEG,OAAO;oBAAOH,OAAO;gBAAkC;aAC1D;QACH;QACA3B;KACD;AACH,EAAC;AAED,OAAO,MAAM+B,UAAgC;IAC3C;QACEnB,KAAKP,iBAAiBK;QACtBsB,MAAMvC,MAAMwC,QAAQ,CAACC,MAAM;QAC3BzB,aAAa;QACbS,MAAM;YACJC,MAAMxB,oBAAoBwB,IAAI;YAC9BC,IAAI;gBAAEC,OAAO;YAAU;QACzB;QACAN,UAAUtB,MAAMuB,iBAAiB,CAACC,MAAM;QACxCkB,MAAM;YACJvB,KAAK;YACLwB,aAAa1B;YACbG,UAAUd;YACV,qEAAqE;YACrE,wEAAwE;YACxE,wEAAwE;YACxE,kDAAkD;YAClDQ,OAAO;gBAAE8B,UAAU;YAAK;QAC1B;IACF;IACA;QACE,kEAAkE;QAClE,wEAAwE;QACxE,oEAAoE;QACpE,oEAAoE;QACpE,oEAAoE;QACpE,qDAAqD;QACrDzB,KAAKP,iBAAiBK,IAAI;QAC1BsB,MAAMvC,MAAMwC,QAAQ,CAACC,MAAM;QAC3BzB,aAAa;QACbS,MAAM;YACJC,MAAMzB,kBAAkByB,IAAI;YAC5BC,IAAI;gBAAEC,OAAO;YAAU;QACzB;QACAN,UAAUtB,MAAMuB,iBAAiB,CAACC,MAAM;QACxCkB,MAAM;YACJvB,KAAK;YACLwB,aAAa1B;YACbG,UAAUd;YACVQ,OAAO;gBAAE8B,UAAU;YAAK;QAC1B;IACF;CACD,CAAA;AAED,eAAe/B,UAAS"}
|
|
@@ -30,6 +30,7 @@ import MuiGrid from "@mui/material/Grid";
|
|
|
30
30
|
import { forwardRef } from "react";
|
|
31
31
|
import { applySemanticElement, semanticElementAttribute, semanticElementLabelAttribute } from "../utils/element-picker.js";
|
|
32
32
|
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
33
|
+
import { colorSchemeAttribute } from "../utils/color-scheme-attribute.js";
|
|
33
34
|
import { dropClearedProps } from "../utils/drop-cleared-props.js";
|
|
34
35
|
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
35
36
|
// Component ids are persisted in screen documents; never rename.
|
|
@@ -253,7 +254,8 @@ export const schema = {
|
|
|
253
254
|
}
|
|
254
255
|
],
|
|
255
256
|
condition: CONTAINER_ONLY
|
|
256
|
-
}
|
|
257
|
+
},
|
|
258
|
+
colorSchemeAttribute()
|
|
257
259
|
]
|
|
258
260
|
};
|
|
259
261
|
const cell = (size, text)=>({
|
|
@@ -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 { 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 ],\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","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 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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"}
|
|
@@ -113,8 +113,9 @@ export const schema = {
|
|
|
113
113
|
* the definition's root in its place, so the only node that reaches a
|
|
114
114
|
* published page is the component's own (AGL-2521). An element picker here
|
|
115
115
|
* briefly existed (AGL-2514) and configured a wrapper that no longer
|
|
116
|
-
* exists — what it was reaching for is **
|
|
117
|
-
*
|
|
116
|
+
* exists — what it was reaching for is **Change it on this page only →
|
|
117
|
+
* Whole component**, which sets the definition root's element for this
|
|
118
|
+
* placement (AGL-3288).
|
|
118
119
|
*/ attributes: []
|
|
119
120
|
};
|
|
120
121
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/reusable-instance.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 { mdiPackageVariant } from '@aglyn/shared-data-mdi'\nimport Box, { type BoxProps } from '@mui/material/Box'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\n// Persisted in screen documents; never rename (see AGL-34 ADR).\nexport const ID: Aglyn.ComponentId = Aglyn.REUSABLE_INSTANCE_COMPONENT_ID\n\nexport interface ReusableInstanceProps extends BoxProps {\n /** Definition id in `hosts/{hostId}/components`; grafted at render time. */\n refId?: string\n /**\n * The definition's display name, carried on the instance purely so the\n * editor placeholder can say which component this stands for (AGL-1193).\n * Never rendered on production surfaces, where the graft fills the box.\n */\n name?: string\n /**\n * This instance's declared-prop overrides (AGL-1247). Addressed to the\n * GRAFT, which reads it off the stored node to substitute `{{prop.*}}`\n * inside its private copy of the definition — the wrapper element itself\n * has no use for it, and it is stripped below rather than spread.\n */\n propValues?: Record<string, unknown>\n}\n\n/**\n * Wrapper element for a reusable-component instance. On production surfaces\n * the compose step (`composeReusableComponentNodes`) grafts the definition\n * subtree inside, so this renders as a plain container. In the editor the\n * instance has no children (definitions aren't grafted into the editable\n * canvas), so the CSS `:empty` placeholder marks it visibly instead — named,\n * since a layout whose chrome has been promoted is otherwise nothing but\n * indistinguishable dashed boxes.\n *\n * The placeholder is drawn on editing surfaces only. A published instance\n * whose definition does not resolve is left empty by the compose step, and a\n * visitor must not see the marker there.\n */\nconst ReusableInstance = forwardRef<any, ReusableInstanceProps>(\n (props, ref) => {\n const {\n refId: _refId,\n name,\n // Instance-scoped directives, not element attributes. `refId` and\n // `name` were always stripped; `propValues` was not, so the author's\n // overrides spread onto the Box and reached the DOM — React logs\n // \"does not recognize the `propValues` prop\" on the canvas, and a\n // published page serialised the same copy a second time as\n // `propvalues=\"[object Object]\"` on the wrapper (AGL-2486).\n //\n // Stripped HERE rather than in the graft because the canvas renders\n // an instance the graft has not touched (definitions are not grafted\n // into the editable canvas), so a strip upstream would fix the\n // published page and leave the editor warning on every render.\n [Aglyn.REUSABLE_INSTANCE_PROP_VALUES_KEY]: _propValues,\n children,\n sx,\n ...rest\n } = props\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n return (\n <Box\n ref={ref}\n // `content: attr()` rather than a child, so the box stays `:empty`\n // and the placeholder cannot be mistaken for grafted content.\n data-aglyn-component={name || 'Reusable component'}\n sx={[\n Boolean(suppressNavigation) && {\n '&:empty': {\n minHeight: 56,\n m: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderWidth: 1,\n borderStyle: 'dashed',\n borderColor: 'divider',\n borderRadius: 1,\n },\n '&:empty::after': {\n content: 'attr(data-aglyn-component)',\n color: 'text.secondary',\n fontSize: 12,\n letterSpacing: 1,\n textTransform: 'uppercase',\n },\n },\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ]}\n {...rest}\n >\n {children}\n </Box>\n )\n },\n)\nReusableInstance.displayName = 'ReusableInstance'\n\nexport const schema: Aglyn.ComponentSchema<ReusableInstanceProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Reusable Component',\n description:\n 'Where a reusable component is placed. Edit the component once and every instance follows.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: {\n path: mdiPackageVariant.path,\n sx: { color: '#9c27b0' },\n },\n flags: {\n // Instances are opaque: their content lives in the definition, so\n // nothing may be dropped inside from the canvas.\n dropping: Aglyn.FEATURE_FLAG.DISABLED,\n },\n /*\n * No attributes. An instance is a REFERENCE, not an element: the graft puts\n * the definition's root in its place, so the only node that reaches a\n * published page is the component's own (AGL-2521). An element picker here\n * briefly existed (AGL-2514) and configured a wrapper that no longer\n * exists — what it was reaching for is **
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/reusable-instance.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 { mdiPackageVariant } from '@aglyn/shared-data-mdi'\nimport Box, { type BoxProps } from '@mui/material/Box'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\n// Persisted in screen documents; never rename (see AGL-34 ADR).\nexport const ID: Aglyn.ComponentId = Aglyn.REUSABLE_INSTANCE_COMPONENT_ID\n\nexport interface ReusableInstanceProps extends BoxProps {\n /** Definition id in `hosts/{hostId}/components`; grafted at render time. */\n refId?: string\n /**\n * The definition's display name, carried on the instance purely so the\n * editor placeholder can say which component this stands for (AGL-1193).\n * Never rendered on production surfaces, where the graft fills the box.\n */\n name?: string\n /**\n * This instance's declared-prop overrides (AGL-1247). Addressed to the\n * GRAFT, which reads it off the stored node to substitute `{{prop.*}}`\n * inside its private copy of the definition — the wrapper element itself\n * has no use for it, and it is stripped below rather than spread.\n */\n propValues?: Record<string, unknown>\n}\n\n/**\n * Wrapper element for a reusable-component instance. On production surfaces\n * the compose step (`composeReusableComponentNodes`) grafts the definition\n * subtree inside, so this renders as a plain container. In the editor the\n * instance has no children (definitions aren't grafted into the editable\n * canvas), so the CSS `:empty` placeholder marks it visibly instead — named,\n * since a layout whose chrome has been promoted is otherwise nothing but\n * indistinguishable dashed boxes.\n *\n * The placeholder is drawn on editing surfaces only. A published instance\n * whose definition does not resolve is left empty by the compose step, and a\n * visitor must not see the marker there.\n */\nconst ReusableInstance = forwardRef<any, ReusableInstanceProps>(\n (props, ref) => {\n const {\n refId: _refId,\n name,\n // Instance-scoped directives, not element attributes. `refId` and\n // `name` were always stripped; `propValues` was not, so the author's\n // overrides spread onto the Box and reached the DOM — React logs\n // \"does not recognize the `propValues` prop\" on the canvas, and a\n // published page serialised the same copy a second time as\n // `propvalues=\"[object Object]\"` on the wrapper (AGL-2486).\n //\n // Stripped HERE rather than in the graft because the canvas renders\n // an instance the graft has not touched (definitions are not grafted\n // into the editable canvas), so a strip upstream would fix the\n // published page and leave the editor warning on every render.\n [Aglyn.REUSABLE_INSTANCE_PROP_VALUES_KEY]: _propValues,\n children,\n sx,\n ...rest\n } = props\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n return (\n <Box\n ref={ref}\n // `content: attr()` rather than a child, so the box stays `:empty`\n // and the placeholder cannot be mistaken for grafted content.\n data-aglyn-component={name || 'Reusable component'}\n sx={[\n Boolean(suppressNavigation) && {\n '&:empty': {\n minHeight: 56,\n m: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderWidth: 1,\n borderStyle: 'dashed',\n borderColor: 'divider',\n borderRadius: 1,\n },\n '&:empty::after': {\n content: 'attr(data-aglyn-component)',\n color: 'text.secondary',\n fontSize: 12,\n letterSpacing: 1,\n textTransform: 'uppercase',\n },\n },\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ]}\n {...rest}\n >\n {children}\n </Box>\n )\n },\n)\nReusableInstance.displayName = 'ReusableInstance'\n\nexport const schema: Aglyn.ComponentSchema<ReusableInstanceProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Reusable Component',\n description:\n 'Where a reusable component is placed. Edit the component once and every instance follows.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: {\n path: mdiPackageVariant.path,\n sx: { color: '#9c27b0' },\n },\n flags: {\n // Instances are opaque: their content lives in the definition, so\n // nothing may be dropped inside from the canvas.\n dropping: Aglyn.FEATURE_FLAG.DISABLED,\n },\n /*\n * No attributes. An instance is a REFERENCE, not an element: the graft puts\n * the definition's root in its place, so the only node that reaches a\n * published page is the component's own (AGL-2521). An element picker here\n * briefly existed (AGL-2514) and configured a wrapper that no longer\n * exists — what it was reaching for is **Change it on this page only →\n * Whole component**, which sets the definition root's element for this\n * placement (AGL-3288).\n */\n attributes: [],\n}\n\n/**\n * No static presets: instances are inserted from per-host definitions, which\n * the console registers dynamically (category \"Your components\").\n */\nexport const presets: Aglyn.PresetSchema[] = []\n\nexport default ReusableInstance\n"],"names":["Aglyn","mdiPackageVariant","Box","forwardRef","useContext","BUNDLE_ID","ID","REUSABLE_INSTANCE_COMPONENT_ID","ReusableInstance","props","ref","REUSABLE_INSTANCE_PROP_VALUES_KEY","refId","_refId","name","_propValues","children","sx","rest","suppressNavigation","ScreenLinkContext","data-aglyn-component","Boolean","minHeight","m","display","alignItems","justifyContent","borderWidth","borderStyle","borderColor","borderRadius","content","color","fontSize","letterSpacing","textTransform","Array","isArray","displayName","schema","$id","pluginId","description","category","ComponentCategory","SURFACE","icon","path","flags","dropping","FEATURE_FLAG","DISABLED","attributes","presets"],"mappings":";;;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,iBAAiB,QAAQ,yBAAwB;AAC1D,OAAOC,SAA4B,oBAAmB;AACtD,SAASC,UAAU,EAAEC,UAAU,QAAQ,QAAO;AAC9C,SAASC,SAAS,QAAQ,gCAA4B;AAEtD,gEAAgE;AAChE,OAAO,MAAMC,KAAwBN,MAAMO,8BAA8B,CAAA;AAoBzE;;;;;;;;;;;;CAYC,GACD,MAAMC,iCAAmBL,WACvB,CAACM,OAAOC;IACN,aAcGV,MAAMW,iCAAiC,EAdpC,EACJC,OAAOC,MAAM,EACbC,IAAI,EACJ,kEAAkE;IAClE,qEAAqE;IACrE,iEAAiE;IACjE,kEAAkE;IAClE,2DAA2D;IAC3D,4DAA4D;IAC5D,EAAE;IACF,oEAAoE;IACpE,qEAAqE;IACrE,+DAA+D;IAC/D,+DAA+D;IAC/D,MAAyC,EAAEC,WAAW,EACtDC,QAAQ,EACRC,EAAE,EAEH,GAAGR,OADCS,wCACDT;;;;;;;IACJ,MAAM,EAAEU,kBAAkB,EAAE,GAAGf,WAAWJ,MAAMoB,iBAAiB;IACjE,qBACE,KAAClB;QACCQ,KAAKA;QACL,mEAAmE;QACnE,8DAA8D;QAC9DW,wBAAsBP,QAAQ;QAC9BG,IAAI;YACFK,QAAQH,uBAAuB;gBAC7B,WAAW;oBACTI,WAAW;oBACXC,GAAG;oBACHC,SAAS;oBACTC,YAAY;oBACZC,gBAAgB;oBAChBC,aAAa;oBACbC,aAAa;oBACbC,aAAa;oBACbC,cAAc;gBAChB;gBACA,kBAAkB;oBAChBC,SAAS;oBACTC,OAAO;oBACPC,UAAU;oBACVC,eAAe;oBACfC,eAAe;gBACjB;YACF;eACIC,MAAMC,OAAO,CAACrB,MAAMA,KAAKA,KAAK;gBAACA;aAAG,GAAG,EAAE;SAC5C;OACGC;kBAEHF;;AAGP;AAEFR,iBAAiB+B,WAAW,GAAG;AAE/B,OAAO,MAAMC,SAAuD;IAClEC,KAAKnC;IACLoC,UAAUrC;IACVkC,aAAa;IACbI,aACE;IACFC,UAAU5C,MAAM6C,iBAAiB,CAACC,OAAO;IACzCC,MAAM;QACJC,MAAM/C,kBAAkB+C,IAAI;QAC5B/B,IAAI;YAAEgB,OAAO;QAAU;IACzB;IACAgB,OAAO;QACL,kEAAkE;QAClE,iDAAiD;QACjDC,UAAUlD,MAAMmD,YAAY,CAACC,QAAQ;IACvC;IACA;;;;;;;;GAQC,GACDC,YAAY,EAAE;AAChB,EAAC;AAED;;;CAGC,GACD,OAAO,MAAMC,UAAgC,EAAE,CAAA;AAE/C,eAAe9C,iBAAgB"}
|
|
@@ -21,6 +21,7 @@ import { mdiPageLayoutBody } from "@aglyn/shared-data-mdi";
|
|
|
21
21
|
import Box from "@mui/material/Box";
|
|
22
22
|
import { forwardRef } from "react";
|
|
23
23
|
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
24
|
+
import { colorSchemeAttribute } from "../utils/color-scheme-attribute.js";
|
|
24
25
|
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
25
26
|
// Component ids are persisted in screen documents; never rename.
|
|
26
27
|
export const ID = 'section';
|
|
@@ -100,7 +101,8 @@ export const schema = {
|
|
|
100
101
|
label: 'Accessible label',
|
|
101
102
|
description: 'Names the landmark for screen readers (recommended when a page ' + 'has several of the same element).',
|
|
102
103
|
component: Aglyn.FieldComponentType.TEXT_FIELD
|
|
103
|
-
}
|
|
104
|
+
},
|
|
105
|
+
colorSchemeAttribute()
|
|
104
106
|
]
|
|
105
107
|
};
|
|
106
108
|
export const presets = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/section.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 { mdiPageLayoutBody } from '@aglyn/shared-data-mdi'\nimport Box from '@mui/material/Box'\nimport { forwardRef } 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 = 'section'\n\n/**\n * W3C sectioning/grouping elements the component may render as (AGL-336).\n *\n * ⛔ `main` IS NOT ONE OF THEM (AGL-2486). A published page carries exactly\n * one `main` landmark, placed by composition on the page's content region —\n * the layout's slot, or the screen root when there is no layout, each of which\n * offers its own element picker. An author-selectable `main` on a grouping\n * container that may appear any number of times per page could only ever\n * produce a SECOND one — and two `main` elements is a worse\n * accessibility outcome than none, because the landmark stops naming anything\n * in particular. It was offered in this select, with field help recommending\n * it, which made the duplicate the documented choice rather than a mistake.\n *\n * Removing it degrades rather than breaks: the resolver below falls back to\n * `section` for any value not in this list, so a stored `element: 'main'` on a\n * published screen renders as `<section>` — still a grouping element, still\n * where the author put it, and no longer competing with the layout's landmark.\n */\nexport const SECTION_ELEMENTS = [\n 'section',\n 'div',\n 'article',\n 'aside',\n 'nav',\n 'header',\n 'footer',\n] as const\nexport type SectionElement = (typeof SECTION_ELEMENTS)[number]\n\nexport interface SectionProps {\n /** The DOM element rendered; defaults to `section`. */\n element?: SectionElement\n /** Accessible name announced for landmark elements. */\n ariaLabel?: string\n children?: JSX.Children\n}\n\n/**\n * Semantic grouping container (AGL-336): renders children inside the\n * chosen W3C element so pages keep meaningful document structure\n * (landmarks for assistive tech, better SEO outlines) instead of\n * div-soup. Behaves like any container: droppable, stylable via sx,\n * classes, and interactions.\n */\nconst Section = forwardRef<HTMLElement, SectionProps>((props, ref) => {\n const { element, ariaLabel, children, ...rest } = props\n const component = SECTION_ELEMENTS.includes(element as SectionElement)\n ? (element as SectionElement)\n : 'section'\n return (\n <Box\n ref={ref}\n component={component}\n aria-label={ariaLabel || undefined}\n {...rest}\n >\n {children}\n </Box>\n )\n})\nSection.displayName = 'AglynSection'\n\nexport const schema: Aglyn.ComponentSchema<SectionProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Section',\n description:\n 'Groups components inside a semantic HTML element (section, article, nav, …).',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiPageLayoutBody.path, sx: { color: '#2196f3' } },\n attributes: [\n {\n name: 'element',\n label: 'Component',\n description:\n 'The DOM element this section renders as, per W3C semantics. ' +\n 'Use section/article/aside/nav/header/footer for meaningful ' +\n 'structure; div for purely visual grouping.',\n component: Aglyn.FieldComponentType.SELECT,\n options: SECTION_ELEMENTS.map((value) => ({ value, label: value })),\n },\n {\n name: 'ariaLabel',\n label: 'Accessible label',\n description:\n 'Names the landmark for screen readers (recommended when a page ' +\n 'has several of the same element).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Section',\n pluginId: BUNDLE_ID,\n description: 'Semantic grouping container (section/div/article/…)',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiPageLayoutBody.path, sx: { color: '#2196f3' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { element: 'section' },\n },\n },\n]\n\nexport default Section\n"],"names":["Aglyn","mdiPageLayoutBody","Box","forwardRef","BUNDLE_ID","generatePresetId","ID","SECTION_ELEMENTS","Section","props","ref","element","ariaLabel","children","rest","component","includes","aria-label","undefined","displayName","schema","$id","pluginId","description","category","ComponentCategory","LAYOUT","icon","path","sx","color","attributes","name","label","FieldComponentType","SELECT","options","map","value","TEXT_FIELD","presets","type","NodeType","PRESET","data","componentId"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,iBAAiB,QAAQ,yBAAwB;AAC1D,OAAOC,SAAS,oBAAmB;AACnC,SAASC,UAAU,QAAQ,QAAO;AAClC,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,gBAAgB,QAAQ,iCAA6B;AAE9D,iEAAiE;AACjE,OAAO,MAAMC,KAAwB,UAAS;AAE9C;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,MAAMC,mBAAmB;IAC9B;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAS;AAWV;;;;;;CAMC,GACD,MAAMC,
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/section.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 { mdiPageLayoutBody } from '@aglyn/shared-data-mdi'\nimport Box from '@mui/material/Box'\nimport { forwardRef } 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 = 'section'\n\n/**\n * W3C sectioning/grouping elements the component may render as (AGL-336).\n *\n * ⛔ `main` IS NOT ONE OF THEM (AGL-2486). A published page carries exactly\n * one `main` landmark, placed by composition on the page's content region —\n * the layout's slot, or the screen root when there is no layout, each of which\n * offers its own element picker. An author-selectable `main` on a grouping\n * container that may appear any number of times per page could only ever\n * produce a SECOND one — and two `main` elements is a worse\n * accessibility outcome than none, because the landmark stops naming anything\n * in particular. It was offered in this select, with field help recommending\n * it, which made the duplicate the documented choice rather than a mistake.\n *\n * Removing it degrades rather than breaks: the resolver below falls back to\n * `section` for any value not in this list, so a stored `element: 'main'` on a\n * published screen renders as `<section>` — still a grouping element, still\n * where the author put it, and no longer competing with the layout's landmark.\n */\nexport const SECTION_ELEMENTS = [\n 'section',\n 'div',\n 'article',\n 'aside',\n 'nav',\n 'header',\n 'footer',\n] as const\nexport type SectionElement = (typeof SECTION_ELEMENTS)[number]\n\nexport interface SectionProps {\n /** The DOM element rendered; defaults to `section`. */\n element?: SectionElement\n /** Accessible name announced for landmark elements. */\n ariaLabel?: string\n children?: JSX.Children\n}\n\n/**\n * Semantic grouping container (AGL-336): renders children inside the\n * chosen W3C element so pages keep meaningful document structure\n * (landmarks for assistive tech, better SEO outlines) instead of\n * div-soup. Behaves like any container: droppable, stylable via sx,\n * classes, and interactions.\n */\nconst Section = forwardRef<HTMLElement, SectionProps>((props, ref) => {\n const { element, ariaLabel, children, ...rest } = props\n const component = SECTION_ELEMENTS.includes(element as SectionElement)\n ? (element as SectionElement)\n : 'section'\n return (\n <Box\n ref={ref}\n component={component}\n aria-label={ariaLabel || undefined}\n {...rest}\n >\n {children}\n </Box>\n )\n})\nSection.displayName = 'AglynSection'\n\nexport const schema: Aglyn.ComponentSchema<SectionProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Section',\n description:\n 'Groups components inside a semantic HTML element (section, article, nav, …).',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiPageLayoutBody.path, sx: { color: '#2196f3' } },\n attributes: [\n {\n name: 'element',\n label: 'Component',\n description:\n 'The DOM element this section renders as, per W3C semantics. ' +\n 'Use section/article/aside/nav/header/footer for meaningful ' +\n 'structure; div for purely visual grouping.',\n component: Aglyn.FieldComponentType.SELECT,\n options: SECTION_ELEMENTS.map((value) => ({ value, label: value })),\n },\n {\n name: 'ariaLabel',\n label: 'Accessible label',\n description:\n 'Names the landmark for screen readers (recommended when a page ' +\n 'has several of the same element).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n colorSchemeAttribute(),\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Section',\n pluginId: BUNDLE_ID,\n description: 'Semantic grouping container (section/div/article/…)',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiPageLayoutBody.path, sx: { color: '#2196f3' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { element: 'section' },\n },\n },\n]\n\nexport default Section\n"],"names":["Aglyn","mdiPageLayoutBody","Box","forwardRef","BUNDLE_ID","colorSchemeAttribute","generatePresetId","ID","SECTION_ELEMENTS","Section","props","ref","element","ariaLabel","children","rest","component","includes","aria-label","undefined","displayName","schema","$id","pluginId","description","category","ComponentCategory","LAYOUT","icon","path","sx","color","attributes","name","label","FieldComponentType","SELECT","options","map","value","TEXT_FIELD","presets","type","NodeType","PRESET","data","componentId"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,iBAAiB,QAAQ,yBAAwB;AAC1D,OAAOC,SAAS,oBAAmB;AACnC,SAASC,UAAU,QAAQ,QAAO;AAClC,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,oBAAoB,QAAQ,qCAAiC;AACtE,SAASC,gBAAgB,QAAQ,iCAA6B;AAE9D,iEAAiE;AACjE,OAAO,MAAMC,KAAwB,UAAS;AAE9C;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,MAAMC,mBAAmB;IAC9B;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAS;AAWV;;;;;;CAMC,GACD,MAAMC,wBAAUN,WAAsC,CAACO,OAAOC;IAC5D,MAAM,EAAEC,OAAO,EAAEC,SAAS,EAAEC,QAAQ,EAAW,GAAGJ,OAATK,wCAASL;;;;;IAClD,MAAMM,YAAYR,iBAAiBS,QAAQ,CAACL,WACvCA,UACD;IACJ,qBACE,KAACV;QACCS,KAAKA;QACLK,WAAWA;QACXE,cAAYL,aAAaM;OACrBJ;kBAEHD;;AAGP;AACAL,QAAQW,WAAW,GAAG;AAEtB,OAAO,MAAMC,SAA8C;IACzDC,KAAKf;IACLgB,UAAUnB;IACVgB,aAAa;IACbI,aACE;IACFC,UAAUzB,MAAM0B,iBAAiB,CAACC,MAAM;IACxCC,MAAM;QAAEC,MAAM5B,kBAAkB4B,IAAI;QAAEC,IAAI;YAAEC,OAAO;QAAU;IAAE;IAC/DC,YAAY;QACV;YACEC,MAAM;YACNC,OAAO;YACPV,aACE,iEACA,gEACA;YACFR,WAAWhB,MAAMmC,kBAAkB,CAACC,MAAM;YAC1CC,SAAS7B,iBAAiB8B,GAAG,CAAC,CAACC,QAAW,CAAA;oBAAEA;oBAAOL,OAAOK;gBAAM,CAAA;QAClE;QACA;YACEN,MAAM;YACNC,OAAO;YACPV,aACE,oEACA;YACFR,WAAWhB,MAAMmC,kBAAkB,CAACK,UAAU;QAChD;QACAnC;KACD;AACH,EAAC;AAED,OAAO,MAAMoC,UAAgC;IAC3C;QACEnB,KAAKhB,iBAAiBC;QACtBmC,MAAM1C,MAAM2C,QAAQ,CAACC,MAAM;QAC3BxB,aAAa;QACbG,UAAUnB;QACVoB,aAAa;QACbC,UAAUzB,MAAM0B,iBAAiB,CAACC,MAAM;QACxCC,MAAM;YAAEC,MAAM5B,kBAAkB4B,IAAI;YAAEC,IAAI;gBAAEC,OAAO;YAAU;QAAE;QAC/Dc,MAAM;YACJvB,KAAK;YACLwB,aAAavC;YACbgB,UAAUnB;YACVM,OAAO;gBAAEE,SAAS;YAAU;QAC9B;IACF;CACD,CAAA;AAED,eAAeH,QAAO"}
|
|
@@ -21,6 +21,7 @@ import MuiDivider from "@mui/material/Divider";
|
|
|
21
21
|
import MuiStack from "@mui/material/Stack";
|
|
22
22
|
import { createElement, forwardRef } from "react";
|
|
23
23
|
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
24
|
+
import { colorSchemeAttribute } from "../utils/color-scheme-attribute.js";
|
|
24
25
|
import { applySemanticElement, semanticElementAttribute, semanticElementLabelAttribute } from "../utils/element-picker.js";
|
|
25
26
|
import { dropClearedProps } from "../utils/drop-cleared-props.js";
|
|
26
27
|
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
@@ -294,7 +295,10 @@ export const schema = {
|
|
|
294
295
|
label: 'Dashed'
|
|
295
296
|
}
|
|
296
297
|
]
|
|
297
|
-
}
|
|
298
|
+
},
|
|
299
|
+
// No Repeat fields: every element's Attributes panel draws the same Repeat
|
|
300
|
+
// section (AGL-3111), writing the props a Stack has always stored.
|
|
301
|
+
colorSchemeAttribute()
|
|
298
302
|
]
|
|
299
303
|
};
|
|
300
304
|
export const presets = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/stack.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 mdiViewColumn,\n mdiViewSequential,\n} from '@aglyn/shared-data-mdi'\nimport MuiDivider from '@mui/material/Divider'\nimport MuiStack, { type StackProps } from '@mui/material/Stack'\nimport type { CSSProperties, ReactElement } from 'react'\nimport { createElement, forwardRef } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\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 * The dividers the `divider` attribute can name (AGL-2486).\n *\n * MUI's own `divider` prop takes a NODE, which an attributes panel cannot\n * author — so the persisted value is a style name and this file builds the\n * element. Anything else (an author's stray string, a paste) renders no\n * divider rather than the literal text between every pair of children.\n */\nconst DIVIDER_STYLES = {\n line: {},\n dashed: { borderStyle: 'dashed' },\n} as const\n\nexport type StackDivider = keyof typeof DIVIDER_STYLES\n\n// justifyContent/alignItems/flexWrap are not direct StackProps in MUI v6+;\n// pass them through sx.\ntype StackWithFlexProps = Omit<StackProps, 'divider'> & {\n justifyContent?: CSSProperties['justifyContent']\n alignItems?: CSSProperties['alignItems']\n flexWrap?: CSSProperties['flexWrap']\n /** Divider STYLE name, not a node — see {@link DIVIDER_STYLES}. */\n divider?: StackDivider | string\n /**\n * A repeat's directives (AGL-103, AGL-181). The published page's\n * composition consumes them before anything renders; a surface that renders\n * the stored node as written, like a component editor, still hands them over.\n */\n repeatDataset?: string\n repeatLimit?: number | string\n repeatFilter?: string\n repeatSort?: string\n}\n\n/**\n * A Stack's divider runs ACROSS the flow, so its orientation is the\n * opposite of the stack's own axis. A responsive `direction` (an array or\n * object) is not authorable here, so only the string form is inspected;\n * anything else falls back to MUI's default horizontal rule.\n */\nfunction buildDivider(\n divider: unknown,\n direction: unknown,\n): ReactElement | undefined {\n if (typeof divider !== 'string') return undefined\n // `hasOwnProperty`, not a truthiness test on the lookup: `\"constructor\"`\n // and friends resolve through Object.prototype and would sail past one.\n if (!Object.prototype.hasOwnProperty.call(DIVIDER_STYLES, divider)) {\n return undefined\n }\n const style = DIVIDER_STYLES[divider as StackDivider]\n const horizontal =\n typeof direction === 'string' && direction.startsWith('row')\n return createElement(MuiDivider, {\n orientation: horizontal ? 'vertical' : 'horizontal',\n // Without it a vertical divider collapses to zero height in a flex row.\n flexItem: horizontal,\n sx: style,\n })\n}\n\n/**\n * Displays that make a Stack the flex container MUI's `spacing` assumes.\n */\nconst FLEX_DISPLAYS = new Set(['flex', 'inline-flex'])\n\n/**\n * Whether an author's `sx` takes the Stack out of flex at any breakpoint\n * (AGL-3214).\n *\n * A function `sx` cannot be read without a theme, so it counts as flex and\n * the stack keeps MUI's own behaviour.\n */\nfunction hasNonFlexDisplay(sx: unknown): boolean {\n if (Array.isArray(sx)) return sx.some(hasNonFlexDisplay)\n if (!sx || typeof sx !== 'object') return false\n const display = (sx as Record<string, unknown>).display\n const notFlex = (value: unknown) =>\n typeof value === 'string' && !FLEX_DISPLAYS.has(value)\n if (typeof display === 'string') return notFlex(display)\n // Responsive, in either of the forms the styles panel writes: an array of\n // breakpoint values, or a `{ xs, md }` map.\n if (Array.isArray(display)) return display.some(notFlex)\n if (display && typeof display === 'object')\n return Object.values(display).some(notFlex)\n return false\n}\n\nconst Stack = forwardRef<HTMLDivElement, StackWithFlexProps>(\n // repeatDataset/repeatLimit are compose-time attributes (AGL-103): the\n // tenant expands them before render; strip so they never hit the DOM.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n ({ justifyContent, alignItems, flexWrap, divider, useFlexGap, repeatDataset, repeatLimit, repeatFilter, repeatSort, sx, ...props }, ref) =>\n createElement(MuiStack, {\n ref,\n sx: [\n { justifyContent, alignItems, flexWrap },\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ],\n // The stored value is a style NAME; MUI wants a node (AGL-2486).\n divider: buildDivider(divider, props.direction),\n // A cleared `direction` persists as null, and MUI resolves it as a\n // responsive value — `null.xs` throws during SSR and 500s the page.\n // Same class as the AGL-1226 button colour, different sharp edge.\n // Last, so an author's element wins over anything `props` carried\n // (AGL-2525). A stack IS the nav row on most sites; before this it\n // could only be wrapped in one.\n ...applySemanticElement(dropClearedProps(props) as Record<string, unknown>),\n // After the spread, so the element picker cannot carry a `useFlexGap`\n // past it. `spacing` reaches children as `margin-left` unless this is\n // on, and those margins assume flex: on a grid they land INSIDE the\n // track, so every item but the first sits a spacing-step right of its\n // column and the left gutter goes ragged (AGL-3214). `gap` is correct\n // for grid, multi-column and flex alike, and an author's own `sx` gap\n // still wins over it. A cleared switch persists as null, which is why\n // this reads `??` and not `||` — an author's explicit OFF stands.\n useFlexGap: useFlexGap ?? (hasNonFlexDisplay(sx) || undefined),\n }),\n)\n\n// Component ids are persisted in screen documents; keep the legacy ids.\nexport const ID: Aglyn.ComponentId = 'muiStack'\n\nexport const schema: Aglyn.ComponentSchema = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Stack',\n description:\n 'Lays children out in a row or column with even spacing — the workhorse for most layouts.',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: {\n path: mdiViewColumn.path,\n sx: { color: '#2196f3' },\n },\n attributes: [\n semanticElementAttribute('this stack'),\n semanticElementLabelAttribute(),\n {\n name: 'direction',\n label: 'Direction',\n description:\n 'Defines the directional flow using the `flex-direction` style property. It is applied for all screen sizes.',\n component: Aglyn.FieldComponentType.SELECT,\n // \"Default\" deleted (AGL-1453): unpersistable, and a second name for\n // `column`, MUI Stack's own default, already on the list.\n options: [\n { value: 'column', label: 'Column' },\n { value: 'column-reverse', label: 'Column Reversed' },\n { value: 'row', label: 'Row' },\n { value: 'row-reverse', label: 'Row Reversed' },\n ],\n },\n {\n name: 'justifyContent',\n label: 'Justify Content',\n description:\n 'Defines how the browser distributes space between and around content items along the main-axis of the container.',\n component: Aglyn.FieldComponentType.SELECT,\n // \"Default\" deleted (AGL-1453). Unpersistable, and a second name for\n // `flex-start`: CSS's initial `justify-content` is `normal`, which on a\n // flex container — which a Stack always is — behaves as `flex-start`.\n //\n // Deleted rather than sentinelled for a second reason specific to this\n // prop: `justifyContent` is destructured out ABOVE and pushed into\n // `sx`, so it never passes through `dropClearedProps`. It is the one\n // attribute on this component the guard does not cover, so the right\n // move is to stop minting values it would have to catch.\n options: [\n { value: 'flex-start', label: 'Flex Start' },\n { value: 'center', label: 'Center' },\n { value: 'flex-end', label: 'Flex End' },\n { value: 'space-between', label: 'Space Between' },\n { value: 'space-around', label: 'Space Around' },\n { value: 'space-evenly', label: 'Space Evenly' },\n ],\n },\n {\n name: 'alignItems',\n label: 'Align Items',\n description:\n 'Defines how the browser distributes space between and around ' +\n 'content items along the cross-axis of the container — the axis ' +\n 'across the Direction.',\n component: Aglyn.FieldComponentType.SELECT,\n // No \"Default\" sentinel (AGL-1453): `stretch` is CSS's own initial\n // `align-items` and is already on the list, and like `justifyContent`\n // this prop is pushed into `sx` rather than through\n // `dropClearedProps`, so an unpersistable `''` would not be caught.\n options: [\n { value: 'stretch', label: 'Stretch' },\n { value: 'flex-start', label: 'Flex Start' },\n { value: 'center', label: 'Center' },\n { value: 'flex-end', label: 'Flex End' },\n { value: 'baseline', label: 'Baseline' },\n ],\n },\n {\n name: 'spacing',\n label: 'Spacing',\n description: 'Defines the space/gap between its immediate children.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n },\n {\n name: 'useFlexGap',\n label: 'Use flex gap',\n description:\n 'Space children with the CSS `gap` property instead of margins. ' +\n 'Required for Spacing to survive wrapping, and it leaves child ' +\n 'margins alone — but `gap` is unsupported in some older browsers.',\n component: Aglyn.FieldComponentType.SWITCH,\n },\n {\n name: 'flexWrap',\n label: 'Wrap',\n description:\n 'Whether children that do not fit move onto a new line. Turn on ' +\n 'Use flex gap as well, or Spacing is applied as margins and the ' +\n 'wrapped rows get an uneven gap.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'nowrap', label: 'No Wrap' },\n { value: 'wrap', label: 'Wrap' },\n { value: 'wrap-reverse', label: 'Wrap Reversed' },\n ],\n },\n {\n name: 'divider',\n label: 'Divider',\n description:\n 'Draws a rule between each pair of children, across the ' +\n 'Direction. Clear the field for no divider.',\n component: Aglyn.FieldComponentType.SELECT,\n // MUI's own prop takes a node; the persisted value is a style name and\n // the component builds the element. No `''` option (AGL-1453) — \"no\n // divider\" is the field's ✕, which persists as cleared.\n options: [\n { value: 'line', label: 'Line' },\n { value: 'dashed', label: 'Dashed' },\n ],\n },\n // No Repeat fields: every element's Attributes panel draws the same Repeat\n // section (AGL-3111), writing the props a Stack has always stored.\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Stack Horizontal',\n icon: {\n path: mdiViewColumn.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: { direction: 'row' },\n },\n },\n {\n $id: generatePresetId(ID, 'vertical'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Stack Vertical',\n icon: {\n path: mdiViewSequential.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: { direction: 'column' },\n },\n },\n]\n\nexport default Stack\n"],"names":["Aglyn","mdiViewColumn","mdiViewSequential","MuiDivider","MuiStack","createElement","forwardRef","BUNDLE_ID","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","dropClearedProps","generatePresetId","DIVIDER_STYLES","line","dashed","borderStyle","buildDivider","divider","direction","undefined","Object","prototype","hasOwnProperty","call","style","horizontal","startsWith","orientation","flexItem","sx","FLEX_DISPLAYS","Set","hasNonFlexDisplay","Array","isArray","some","display","notFlex","value","has","values","Stack","justifyContent","alignItems","flexWrap","useFlexGap","repeatDataset","repeatLimit","repeatFilter","repeatSort","props","ref","ID","schema","$id","pluginId","displayName","description","category","ComponentCategory","LAYOUT","icon","path","color","attributes","name","label","component","FieldComponentType","SELECT","options","TEXT_FIELD","type","SWITCH","presets","NodeType","PRESET","data","componentId"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/stack.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 mdiViewColumn,\n mdiViewSequential,\n} from '@aglyn/shared-data-mdi'\nimport MuiDivider from '@mui/material/Divider'\nimport MuiStack, { type StackProps } from '@mui/material/Stack'\nimport type { CSSProperties, ReactElement } from 'react'\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 * The dividers the `divider` attribute can name (AGL-2486).\n *\n * MUI's own `divider` prop takes a NODE, which an attributes panel cannot\n * author — so the persisted value is a style name and this file builds the\n * element. Anything else (an author's stray string, a paste) renders no\n * divider rather than the literal text between every pair of children.\n */\nconst DIVIDER_STYLES = {\n line: {},\n dashed: { borderStyle: 'dashed' },\n} as const\n\nexport type StackDivider = keyof typeof DIVIDER_STYLES\n\n// justifyContent/alignItems/flexWrap are not direct StackProps in MUI v6+;\n// pass them through sx.\ntype StackWithFlexProps = Omit<StackProps, 'divider'> & {\n justifyContent?: CSSProperties['justifyContent']\n alignItems?: CSSProperties['alignItems']\n flexWrap?: CSSProperties['flexWrap']\n /** Divider STYLE name, not a node — see {@link DIVIDER_STYLES}. */\n divider?: StackDivider | string\n /**\n * A repeat's directives (AGL-103, AGL-181). The published page's\n * composition consumes them before anything renders; a surface that renders\n * the stored node as written, like a component editor, still hands them over.\n */\n repeatDataset?: string\n repeatLimit?: number | string\n repeatFilter?: string\n repeatSort?: string\n}\n\n/**\n * A Stack's divider runs ACROSS the flow, so its orientation is the\n * opposite of the stack's own axis. A responsive `direction` (an array or\n * object) is not authorable here, so only the string form is inspected;\n * anything else falls back to MUI's default horizontal rule.\n */\nfunction buildDivider(\n divider: unknown,\n direction: unknown,\n): ReactElement | undefined {\n if (typeof divider !== 'string') return undefined\n // `hasOwnProperty`, not a truthiness test on the lookup: `\"constructor\"`\n // and friends resolve through Object.prototype and would sail past one.\n if (!Object.prototype.hasOwnProperty.call(DIVIDER_STYLES, divider)) {\n return undefined\n }\n const style = DIVIDER_STYLES[divider as StackDivider]\n const horizontal =\n typeof direction === 'string' && direction.startsWith('row')\n return createElement(MuiDivider, {\n orientation: horizontal ? 'vertical' : 'horizontal',\n // Without it a vertical divider collapses to zero height in a flex row.\n flexItem: horizontal,\n sx: style,\n })\n}\n\n/**\n * Displays that make a Stack the flex container MUI's `spacing` assumes.\n */\nconst FLEX_DISPLAYS = new Set(['flex', 'inline-flex'])\n\n/**\n * Whether an author's `sx` takes the Stack out of flex at any breakpoint\n * (AGL-3214).\n *\n * A function `sx` cannot be read without a theme, so it counts as flex and\n * the stack keeps MUI's own behaviour.\n */\nfunction hasNonFlexDisplay(sx: unknown): boolean {\n if (Array.isArray(sx)) return sx.some(hasNonFlexDisplay)\n if (!sx || typeof sx !== 'object') return false\n const display = (sx as Record<string, unknown>).display\n const notFlex = (value: unknown) =>\n typeof value === 'string' && !FLEX_DISPLAYS.has(value)\n if (typeof display === 'string') return notFlex(display)\n // Responsive, in either of the forms the styles panel writes: an array of\n // breakpoint values, or a `{ xs, md }` map.\n if (Array.isArray(display)) return display.some(notFlex)\n if (display && typeof display === 'object')\n return Object.values(display).some(notFlex)\n return false\n}\n\nconst Stack = forwardRef<HTMLDivElement, StackWithFlexProps>(\n // repeatDataset/repeatLimit are compose-time attributes (AGL-103): the\n // tenant expands them before render; strip so they never hit the DOM.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n ({ justifyContent, alignItems, flexWrap, divider, useFlexGap, repeatDataset, repeatLimit, repeatFilter, repeatSort, sx, ...props }, ref) =>\n createElement(MuiStack, {\n ref,\n sx: [\n { justifyContent, alignItems, flexWrap },\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ],\n // The stored value is a style NAME; MUI wants a node (AGL-2486).\n divider: buildDivider(divider, props.direction),\n // A cleared `direction` persists as null, and MUI resolves it as a\n // responsive value — `null.xs` throws during SSR and 500s the page.\n // Same class as the AGL-1226 button colour, different sharp edge.\n // Last, so an author's element wins over anything `props` carried\n // (AGL-2525). A stack IS the nav row on most sites; before this it\n // could only be wrapped in one.\n ...applySemanticElement(dropClearedProps(props) as Record<string, unknown>),\n // After the spread, so the element picker cannot carry a `useFlexGap`\n // past it. `spacing` reaches children as `margin-left` unless this is\n // on, and those margins assume flex: on a grid they land INSIDE the\n // track, so every item but the first sits a spacing-step right of its\n // column and the left gutter goes ragged (AGL-3214). `gap` is correct\n // for grid, multi-column and flex alike, and an author's own `sx` gap\n // still wins over it. A cleared switch persists as null, which is why\n // this reads `??` and not `||` — an author's explicit OFF stands.\n useFlexGap: useFlexGap ?? (hasNonFlexDisplay(sx) || undefined),\n }),\n)\n\n// Component ids are persisted in screen documents; keep the legacy ids.\nexport const ID: Aglyn.ComponentId = 'muiStack'\n\nexport const schema: Aglyn.ComponentSchema = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Stack',\n description:\n 'Lays children out in a row or column with even spacing — the workhorse for most layouts.',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: {\n path: mdiViewColumn.path,\n sx: { color: '#2196f3' },\n },\n attributes: [\n semanticElementAttribute('this stack'),\n semanticElementLabelAttribute(),\n {\n name: 'direction',\n label: 'Direction',\n description:\n 'Defines the directional flow using the `flex-direction` style property. It is applied for all screen sizes.',\n component: Aglyn.FieldComponentType.SELECT,\n // \"Default\" deleted (AGL-1453): unpersistable, and a second name for\n // `column`, MUI Stack's own default, already on the list.\n options: [\n { value: 'column', label: 'Column' },\n { value: 'column-reverse', label: 'Column Reversed' },\n { value: 'row', label: 'Row' },\n { value: 'row-reverse', label: 'Row Reversed' },\n ],\n },\n {\n name: 'justifyContent',\n label: 'Justify Content',\n description:\n 'Defines how the browser distributes space between and around content items along the main-axis of the container.',\n component: Aglyn.FieldComponentType.SELECT,\n // \"Default\" deleted (AGL-1453). Unpersistable, and a second name for\n // `flex-start`: CSS's initial `justify-content` is `normal`, which on a\n // flex container — which a Stack always is — behaves as `flex-start`.\n //\n // Deleted rather than sentinelled for a second reason specific to this\n // prop: `justifyContent` is destructured out ABOVE and pushed into\n // `sx`, so it never passes through `dropClearedProps`. It is the one\n // attribute on this component the guard does not cover, so the right\n // move is to stop minting values it would have to catch.\n options: [\n { value: 'flex-start', label: 'Flex Start' },\n { value: 'center', label: 'Center' },\n { value: 'flex-end', label: 'Flex End' },\n { value: 'space-between', label: 'Space Between' },\n { value: 'space-around', label: 'Space Around' },\n { value: 'space-evenly', label: 'Space Evenly' },\n ],\n },\n {\n name: 'alignItems',\n label: 'Align Items',\n description:\n 'Defines how the browser distributes space between and around ' +\n 'content items along the cross-axis of the container — the axis ' +\n 'across the Direction.',\n component: Aglyn.FieldComponentType.SELECT,\n // No \"Default\" sentinel (AGL-1453): `stretch` is CSS's own initial\n // `align-items` and is already on the list, and like `justifyContent`\n // this prop is pushed into `sx` rather than through\n // `dropClearedProps`, so an unpersistable `''` would not be caught.\n options: [\n { value: 'stretch', label: 'Stretch' },\n { value: 'flex-start', label: 'Flex Start' },\n { value: 'center', label: 'Center' },\n { value: 'flex-end', label: 'Flex End' },\n { value: 'baseline', label: 'Baseline' },\n ],\n },\n {\n name: 'spacing',\n label: 'Spacing',\n description: 'Defines the space/gap between its immediate children.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n },\n {\n name: 'useFlexGap',\n label: 'Use flex gap',\n description:\n 'Space children with the CSS `gap` property instead of margins. ' +\n 'Required for Spacing to survive wrapping, and it leaves child ' +\n 'margins alone — but `gap` is unsupported in some older browsers.',\n component: Aglyn.FieldComponentType.SWITCH,\n },\n {\n name: 'flexWrap',\n label: 'Wrap',\n description:\n 'Whether children that do not fit move onto a new line. Turn on ' +\n 'Use flex gap as well, or Spacing is applied as margins and the ' +\n 'wrapped rows get an uneven gap.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'nowrap', label: 'No Wrap' },\n { value: 'wrap', label: 'Wrap' },\n { value: 'wrap-reverse', label: 'Wrap Reversed' },\n ],\n },\n {\n name: 'divider',\n label: 'Divider',\n description:\n 'Draws a rule between each pair of children, across the ' +\n 'Direction. Clear the field for no divider.',\n component: Aglyn.FieldComponentType.SELECT,\n // MUI's own prop takes a node; the persisted value is a style name and\n // the component builds the element. No `''` option (AGL-1453) — \"no\n // divider\" is the field's ✕, which persists as cleared.\n options: [\n { value: 'line', label: 'Line' },\n { value: 'dashed', label: 'Dashed' },\n ],\n },\n // No Repeat fields: every element's Attributes panel draws the same Repeat\n // section (AGL-3111), writing the props a Stack has always stored.\n colorSchemeAttribute(),\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Stack Horizontal',\n icon: {\n path: mdiViewColumn.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: { direction: 'row' },\n },\n },\n {\n $id: generatePresetId(ID, 'vertical'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Stack Vertical',\n icon: {\n path: mdiViewSequential.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: { direction: 'column' },\n },\n },\n]\n\nexport default Stack\n"],"names":["Aglyn","mdiViewColumn","mdiViewSequential","MuiDivider","MuiStack","createElement","forwardRef","BUNDLE_ID","colorSchemeAttribute","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","dropClearedProps","generatePresetId","DIVIDER_STYLES","line","dashed","borderStyle","buildDivider","divider","direction","undefined","Object","prototype","hasOwnProperty","call","style","horizontal","startsWith","orientation","flexItem","sx","FLEX_DISPLAYS","Set","hasNonFlexDisplay","Array","isArray","some","display","notFlex","value","has","values","Stack","justifyContent","alignItems","flexWrap","useFlexGap","repeatDataset","repeatLimit","repeatFilter","repeatSort","props","ref","ID","schema","$id","pluginId","displayName","description","category","ComponentCategory","LAYOUT","icon","path","color","attributes","name","label","component","FieldComponentType","SELECT","options","TEXT_FIELD","type","SWITCH","presets","NodeType","PRESET","data","componentId"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import * as Aglyn from '@aglyn/aglyn';
|
|
18
|
+
/**
|
|
19
|
+
* "Color scheme" for the layout elements (AGL-3284): Section, Container,
|
|
20
|
+
* Stack, Box and Grid.
|
|
21
|
+
*
|
|
22
|
+
* The renderer's leaf reads the prop and swaps in the site's theme for the
|
|
23
|
+
* pinned scheme around the element, so no component here has to know about
|
|
24
|
+
* it — and none of them ever receives it. It is offered on the wrappers an
|
|
25
|
+
* author builds a band of the page from, not on every element, because the
|
|
26
|
+
* point is "this part of the page", and a wrapper is how a page has parts.
|
|
27
|
+
*
|
|
28
|
+
* "Match the site" is a real, persistable sentinel rather than `''`
|
|
29
|
+
* (AGL-1453): the list does not otherwise name the default, so without it the
|
|
30
|
+
* only way back from "Always dark" would be the field's clear button.
|
|
31
|
+
*/
|
|
32
|
+
export declare function colorSchemeAttribute(): Aglyn.AglynAttributeSchema;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ import * as Aglyn from "@aglyn/aglyn";
|
|
17
|
+
/**
|
|
18
|
+
* "Color scheme" for the layout elements (AGL-3284): Section, Container,
|
|
19
|
+
* Stack, Box and Grid.
|
|
20
|
+
*
|
|
21
|
+
* The renderer's leaf reads the prop and swaps in the site's theme for the
|
|
22
|
+
* pinned scheme around the element, so no component here has to know about
|
|
23
|
+
* it — and none of them ever receives it. It is offered on the wrappers an
|
|
24
|
+
* author builds a band of the page from, not on every element, because the
|
|
25
|
+
* point is "this part of the page", and a wrapper is how a page has parts.
|
|
26
|
+
*
|
|
27
|
+
* "Match the site" is a real, persistable sentinel rather than `''`
|
|
28
|
+
* (AGL-1453): the list does not otherwise name the default, so without it the
|
|
29
|
+
* only way back from "Always dark" would be the field's clear button.
|
|
30
|
+
*/ export function colorSchemeAttribute() {
|
|
31
|
+
return {
|
|
32
|
+
name: Aglyn.NODE_COLOR_SCHEME_PROP,
|
|
33
|
+
label: 'Color scheme',
|
|
34
|
+
description: 'Keep this part of the page light or dark no matter which mode the ' + 'visitor picked. Everything inside follows it — backgrounds, text and ' + 'cards use your site’s colors for that mode.',
|
|
35
|
+
component: Aglyn.FieldComponentType.SELECT,
|
|
36
|
+
options: [
|
|
37
|
+
{
|
|
38
|
+
value: Aglyn.ELEMENT_COLOR_SCHEME_SITE,
|
|
39
|
+
label: 'Match the site'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
value: 'light',
|
|
43
|
+
label: 'Always light'
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
value: 'dark',
|
|
47
|
+
label: 'Always dark'
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=color-scheme-attribute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/utils/color-scheme-attribute.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'\n\n/**\n * \"Color scheme\" for the layout elements (AGL-3284): Section, Container,\n * Stack, Box and Grid.\n *\n * The renderer's leaf reads the prop and swaps in the site's theme for the\n * pinned scheme around the element, so no component here has to know about\n * it — and none of them ever receives it. It is offered on the wrappers an\n * author builds a band of the page from, not on every element, because the\n * point is \"this part of the page\", and a wrapper is how a page has parts.\n *\n * \"Match the site\" is a real, persistable sentinel rather than `''`\n * (AGL-1453): the list does not otherwise name the default, so without it the\n * only way back from \"Always dark\" would be the field's clear button.\n */\nexport function colorSchemeAttribute(): Aglyn.AglynAttributeSchema {\n return {\n name: Aglyn.NODE_COLOR_SCHEME_PROP,\n label: 'Color scheme',\n description:\n 'Keep this part of the page light or dark no matter which mode the ' +\n 'visitor picked. Everything inside follows it — backgrounds, text and ' +\n 'cards use your site’s colors for that mode.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: Aglyn.ELEMENT_COLOR_SCHEME_SITE, label: 'Match the site' },\n { value: 'light', label: 'Always light' },\n { value: 'dark', label: 'Always dark' },\n ],\n } as Aglyn.AglynAttributeSchema\n}\n"],"names":["Aglyn","colorSchemeAttribute","name","NODE_COLOR_SCHEME_PROP","label","description","component","FieldComponentType","SELECT","options","value","ELEMENT_COLOR_SCHEME_SITE"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AAErC;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC;IACd,OAAO;QACLC,MAAMF,MAAMG,sBAAsB;QAClCC,OAAO;QACPC,aACE,uEACA,0EACA;QACFC,WAAWN,MAAMO,kBAAkB,CAACC,MAAM;QAC1CC,SAAS;YACP;gBAAEC,OAAOV,MAAMW,yBAAyB;gBAAEP,OAAO;YAAiB;YAClE;gBAAEM,OAAO;gBAASN,OAAO;YAAe;YACxC;gBAAEM,OAAO;gBAAQN,OAAO;YAAc;SACvC;IACH;AACF"}
|