@aglyn/plugins-mui 1.0.0-beta.230 → 1.0.0-beta.232
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/card.js +13 -6
- package/src/lib/components/card.js.map +1 -1
- package/src/lib/components/data-table.js +9 -12
- package/src/lib/components/data-table.js.map +1 -1
- package/src/lib/components/icon.js +2 -1
- package/src/lib/components/icon.js.map +1 -1
- package/src/lib/components/inline-text.d.ts +5 -5
- package/src/lib/components/inline-text.js +5 -5
- package/src/lib/components/inline-text.js.map +1 -1
- package/src/lib/components/layout-slot.js +9 -12
- package/src/lib/components/layout-slot.js.map +1 -1
- package/src/lib/components/stack.js +3 -1
- package/src/lib/components/stack.js.map +1 -1
- package/src/lib/components/typography.js +79 -3
- package/src/lib/components/typography.js.map +1 -1
- package/src/lib/plugin.js +3 -3
- package/src/lib/plugin.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aglyn/plugins-mui",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.232",
|
|
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.232",
|
|
29
|
+
"@aglyn/shared-data-enums": "1.0.0-beta.232",
|
|
30
|
+
"@aglyn/shared-data-mdi": "1.0.0-beta.232",
|
|
31
|
+
"@aglyn/shared-ui-jsx": "1.0.0-beta.232",
|
|
32
|
+
"@aglyn/shared-ui-theme": "1.0.0-beta.232",
|
|
33
|
+
"@aglyn/shared-util-vendor": "1.0.0-beta.232",
|
|
34
34
|
"@swc/helpers": "0.5.23",
|
|
35
35
|
"mobx": "^7.0.5",
|
|
36
36
|
"mobx-react-lite": "^5.1.0"
|
|
@@ -49,13 +49,20 @@ export const CARD_ACTIONS_ID = 'muiCardActions';
|
|
|
49
49
|
"children"
|
|
50
50
|
]);
|
|
51
51
|
const outlined = variant === 'outlined';
|
|
52
|
+
// A variant or an elevation the author did not set is left to the site's
|
|
53
|
+
// theme (AGL-3660): a Card dropped from the drawer takes the card style
|
|
54
|
+
// the theme's MuiCard defaults give it, as every Card the site has does.
|
|
55
|
+
const chosen = outlined ? 'outlined' : variant === 'elevation' ? 'elevation' : undefined;
|
|
56
|
+
// Same trap as Paper: a string elevation indexes MUI's shadow array and
|
|
57
|
+
// yields a completely flat card.
|
|
58
|
+
const depth = outlined ? undefined : toElevation(elevation);
|
|
52
59
|
return /*#__PURE__*/ _jsx(MuiCard, _extends({
|
|
53
|
-
ref: ref
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
elevation:
|
|
58
|
-
}, applySemanticElement(rest), {
|
|
60
|
+
ref: ref
|
|
61
|
+
}, chosen ? {
|
|
62
|
+
variant: chosen
|
|
63
|
+
} : {}, depth !== undefined ? {
|
|
64
|
+
elevation: depth
|
|
65
|
+
} : {}, applySemanticElement(rest), {
|
|
59
66
|
children: children
|
|
60
67
|
}));
|
|
61
68
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/card.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 { mdiCardOutline, mdiCardText, mdiGestureTap } from '@aglyn/shared-data-mdi'\nimport MuiCard from '@mui/material/Card'\nimport MuiCardActions from '@mui/material/CardActions'\nimport MuiCardContent from '@mui/material/CardContent'\nimport MuiCardHeader from '@mui/material/CardHeader'\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'\nimport { toElevation } from './paper'\n\n// Component ids are persisted in screen documents; never rename.\nexport const CARD_ID: Aglyn.ComponentId = 'muiCard'\nexport const CARD_HEADER_ID: Aglyn.ComponentId = 'muiCardHeader'\nexport const CARD_CONTENT_ID: Aglyn.ComponentId = 'muiCardContent'\nexport const CARD_ACTIONS_ID: Aglyn.ComponentId = 'muiCardActions'\n\nexport interface CardElementProps {\n variant?: 'elevation' | 'outlined'\n /** Shadow depth, 0–24; ignored on the outlined variant. */\n elevation?: number | string\n children?: ReactNode\n}\n\nexport interface CardHeaderElementProps {\n title?: string\n subheader?: string\n}\n\nexport interface CardActionsElementProps {\n /** If true, the 8px gap between action buttons is removed. */\n disableSpacing?: boolean\n children?: ReactNode\n}\n\n/**\n * Card (https://mui.com/material-ui/react-card/) — a Paper with card\n * padding conventions. Composed from separate Header/Content/Actions\n * elements rather than a single element with a dozen text props, so the\n * pieces are individually selectable, stylable and reorderable on the\n * canvas like everything else.\n */\nconst CardElement = forwardRef<HTMLDivElement, CardElementProps>(\n (rawProps, ref) => {\n // See PaperElement: cleared props are dropped before anything reads\n // them, so `rest` cannot carry a `null` into MUI (AGL-1451).\n const props = dropClearedProps(rawProps)\n const { variant, elevation, children, ...rest } = props\n const outlined = variant === 'outlined'\n return (\n <MuiCard\n ref={ref}\n variant={outlined ? 'outlined' : 'elevation'}\n // Same trap as Paper: a string elevation indexes MUI's shadow\n // array and yields a completely flat card.\n elevation={outlined ? undefined : toElevation(elevation)}\n {...applySemanticElement(rest as Record<string, unknown>)}\n >\n {children}\n </MuiCard>\n )\n },\n)\nCardElement.displayName = 'AglynCard'\n\n/**\n * Card header. `title`/`subheader` are plain strings: MUI wraps each in\n * its own Typography, and passing children instead would drop the\n * heading/subheading type scale a card header exists to provide.\n */\nexport const CardHeaderElement = forwardRef<\n HTMLDivElement,\n CardHeaderElementProps\n>((props, ref) => {\n const { title, subheader, ...rest } = props as CardHeaderElementProps & {\n children?: unknown\n }\n // A header with neither string is invisible and unselectable on the\n // canvas; a placeholder keeps the node reachable.\n delete (rest as { children?: unknown }).children\n return (\n <MuiCardHeader\n ref={ref}\n title={title || (subheader ? undefined : 'Card title')}\n subheader={subheader || undefined}\n {...rest}\n />\n )\n})\nCardHeaderElement.displayName = 'AglynCardHeader'\n\nexport const CardContentElement = forwardRef<\n HTMLDivElement,\n { children?: ReactNode }\n>((props, ref) => <MuiCardContent ref={ref} {...props} />)\nCardContentElement.displayName = 'AglynCardContent'\n\nexport const CardActionsElement = forwardRef<\n HTMLDivElement,\n CardActionsElementProps\n>((props, ref) => <MuiCardActions ref={ref} {...props} />)\nCardActionsElement.displayName = 'AglynCardActions'\n\n/** Elevation only means anything on the (default) `elevation` variant. */\nconst ELEVATION_ONLY = { when: 'variant', is: 'outlined', notMatch: true }\n\nexport const cardSchema: Aglyn.ComponentSchema<CardElementProps> = {\n $id: CARD_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Card',\n description:\n 'Surface that groups a header, content and actions about one subject.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: { path: mdiCardOutline.path, sx: { color: '#2196f3' } },\n attributes: [\n semanticElementAttribute('this card'),\n semanticElementLabelAttribute(),\n {\n name: 'variant',\n label: 'Variant',\n description:\n 'Elevation raises the card with a shadow; outlined draws a border ' +\n 'instead and has no shadow.',\n component: Aglyn.FieldComponentType.SELECT,\n // Same call as Paper (AGL-1451): a real sentinel, because `elevation`\n // is MUI's own value for the other half of this two-way choice and is\n // what the Elevation control is conditioned on. `''` could not\n // persist (AGL-1191).\n options: [\n { value: 'elevation', label: 'Elevation (default)' },\n { value: 'outlined', label: 'Outlined' },\n ],\n },\n {\n name: 'elevation',\n label: 'Elevation',\n description: 'Shadow depth from 0 (flat) to 24.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: ELEVATION_ONLY,\n },\n ],\n}\n\nexport const cardHeaderSchema: Aglyn.ComponentSchema<CardHeaderElementProps> = {\n $id: CARD_HEADER_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Card Header',\n description: 'The title and subheader at the top of a card.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: { path: mdiCardText.path, sx: { color: '#2196f3' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'title',\n label: 'Title',\n description: 'The card heading.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'subheader',\n label: 'Subheader',\n description: 'Secondary line under the title.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n ],\n}\n\nexport const cardContentSchema: Aglyn.ComponentSchema = {\n $id: CARD_CONTENT_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Card Content',\n description: 'The padded body region of a card.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: { path: mdiCardText.path, sx: { color: '#2196f3' } },\n}\n\nexport const cardActionsSchema: Aglyn.ComponentSchema<CardActionsElementProps> =\n {\n $id: CARD_ACTIONS_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Card Actions',\n description: 'The button row at the bottom of a card.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: { path: mdiGestureTap.path, sx: { color: '#2196f3' } },\n attributes: [\n {\n name: 'disableSpacing',\n label: 'Disable spacing?',\n description: 'If true, the gap between action buttons is removed.',\n component: Aglyn.FieldComponentType.SWITCH,\n },\n ],\n }\n\nexport const cardPresets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(CARD_ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Card',\n pluginId: BUNDLE_ID,\n description: 'Image, heading, body text and an action button',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: cardSchema.icon,\n data: {\n $id: null,\n componentId: CARD_ID,\n pluginId: BUNDLE_ID,\n props: {},\n // Node-level sx (AGL-1346) — the record the Styles panel edits.\n sx: { maxWidth: 360 },\n nodes: [\n // The existing Image element rather than MUI's CardMedia: it\n // already carries the media-CDN srcSet, the lazy loading and the\n // empty-source placeholder (AGL-74/175), none of which is worth\n // re-implementing for a card.\n {\n $id: null,\n componentId: 'image',\n pluginId: BUNDLE_ID,\n props: { alt: '', height: '160px', objectFit: 'cover' },\n },\n {\n $id: null,\n componentId: CARD_HEADER_ID,\n pluginId: BUNDLE_ID,\n props: { title: 'Card title', subheader: 'Supporting line' },\n },\n {\n $id: null,\n componentId: CARD_CONTENT_ID,\n pluginId: BUNDLE_ID,\n nodes: [\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: {\n variant: 'body2',\n children:\n 'A short description of whatever this card is about.',\n },\n },\n ],\n },\n {\n $id: null,\n componentId: CARD_ACTIONS_ID,\n pluginId: BUNDLE_ID,\n nodes: [\n {\n $id: null,\n componentId: 'muiScreenLink',\n pluginId: BUNDLE_ID,\n // `'button'`, not `''` (AGL-1453). This preset was MINTING the\n // unpersistable value: every card dropped on a canvas planted a\n // `renderAs: ''` that no longer matches any option. Renders\n // identically — both take the non-link branch.\n props: {\n children: 'Learn more',\n renderAs: 'button',\n size: 'small',\n },\n },\n ],\n },\n ],\n },\n },\n {\n $id: generatePresetId(CARD_ID, 'outlined'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Card Outlined',\n pluginId: BUNDLE_ID,\n description: 'Text-only card with a border instead of a shadow',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: cardSchema.icon,\n data: {\n $id: null,\n componentId: CARD_ID,\n pluginId: BUNDLE_ID,\n props: { variant: 'outlined' },\n sx: { maxWidth: 360 },\n nodes: [\n {\n $id: null,\n componentId: CARD_CONTENT_ID,\n pluginId: BUNDLE_ID,\n nodes: [\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: { variant: 'h6', children: 'Card title' },\n },\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: {\n variant: 'body2',\n children: 'A short description of this card.',\n },\n },\n ],\n },\n ],\n },\n },\n]\n\nexport default CardElement\n"],"names":["Aglyn","mdiCardOutline","mdiCardText","mdiGestureTap","MuiCard","MuiCardActions","MuiCardContent","MuiCardHeader","forwardRef","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","BUNDLE_ID","dropClearedProps","generatePresetId","toElevation","CARD_ID","CARD_HEADER_ID","CARD_CONTENT_ID","CARD_ACTIONS_ID","CardElement","rawProps","ref","props","variant","elevation","children","rest","outlined","undefined","displayName","CardHeaderElement","title","subheader","CardContentElement","CardActionsElement","ELEVATION_ONLY","when","is","notMatch","cardSchema","$id","pluginId","description","category","ComponentCategory","SURFACE","icon","path","sx","color","attributes","name","label","component","FieldComponentType","SELECT","options","value","TEXT_FIELD","type","condition","cardHeaderSchema","flags","selfClosing","FEATURE_FLAG","ENABLED","cardContentSchema","cardActionsSchema","SWITCH","cardPresets","NodeType","PRESET","data","componentId","maxWidth","nodes","alt","height","objectFit","renderAs","size"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,cAAc,EAAEC,WAAW,EAAEC,aAAa,QAAQ,yBAAwB;AACnF,OAAOC,aAAa,qBAAoB;AACxC,OAAOC,oBAAoB,4BAA2B;AACtD,OAAOC,oBAAoB,4BAA2B;AACtD,OAAOC,mBAAmB,2BAA0B;AACpD,SAASC,UAAU,QAAwB,QAAO;AAClD,SACEC,oBAAoB,EACpBC,wBAAwB,EACxBC,6BAA6B,QACxB,6BAAyB;AAChC,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,gBAAgB,QAAQ,iCAA6B;AAC9D,SAASC,gBAAgB,QAAQ,iCAA6B;AAC9D,SAASC,WAAW,QAAQ,aAAS;AAErC,iEAAiE;AACjE,OAAO,MAAMC,UAA6B,UAAS;AACnD,OAAO,MAAMC,iBAAoC,gBAAe;AAChE,OAAO,MAAMC,kBAAqC,iBAAgB;AAClE,OAAO,MAAMC,kBAAqC,iBAAgB;AAoBlE;;;;;;CAMC,GACD,MAAMC,4BAAcZ,WAClB,CAACa,UAAUC;IACT,oEAAoE;IACpE,6DAA6D;IAC7D,MAAMC,QAAQV,iBAAiBQ;IAC/B,MAAM,EAAEG,OAAO,EAAEC,SAAS,EAAEC,QAAQ,EAAW,GAAGH,OAATI,wCAASJ;;;;;IAClD,MAAMK,WAAWJ,YAAY;IAC7B,qBACE,KAACpB;QACCkB,KAAKA;QACLE,SAASI,WAAW,aAAa;QACjC,8DAA8D;QAC9D,2CAA2C;QAC3CH,WAAWG,WAAWC,YAAYd,YAAYU;OAC1ChB,qBAAqBkB;kBAExBD;;AAGP;AAEFN,YAAYU,WAAW,GAAG;AAE1B;;;;CAIC,GACD,OAAO,MAAMC,kCAAoBvB,WAG/B,CAACe,OAAOD;IACR,MAAM,EAAEU,KAAK,EAAEC,SAAS,EAAW,GAAGV,OAATI,wCAASJ;;;;IAGtC,oEAAoE;IACpE,kDAAkD;IAClD,OAAO,AAACI,KAAgCD,QAAQ;IAChD,qBACE,KAACnB;QACCe,KAAKA;QACLU,OAAOA,SAAUC,CAAAA,YAAYJ,YAAY,YAAW;QACpDI,WAAWA,aAAaJ;OACpBF;AAGV,GAAE;AACFI,kBAAkBD,WAAW,GAAG;AAEhC,OAAO,MAAMI,mCAAqB1B,WAGhC,CAACe,OAAOD,oBAAQ,KAAChB;QAAegB,KAAKA;OAASC,SAAU;AAC1DW,mBAAmBJ,WAAW,GAAG;AAEjC,OAAO,MAAMK,mCAAqB3B,WAGhC,CAACe,OAAOD,oBAAQ,KAACjB;QAAeiB,KAAKA;OAASC,SAAU;AAC1DY,mBAAmBL,WAAW,GAAG;AAEjC,wEAAwE,GACxE,MAAMM,iBAAiB;IAAEC,MAAM;IAAWC,IAAI;IAAYC,UAAU;AAAK;AAEzE,OAAO,MAAMC,aAAsD;IACjEC,KAAKzB;IACL0B,UAAU9B;IACVkB,aAAa;IACba,aACE;IACFC,UAAU5C,MAAM6C,iBAAiB,CAACC,OAAO;IACzCC,MAAM;QAAEC,MAAM/C,eAAe+C,IAAI;QAAEC,IAAI;YAAEC,OAAO;QAAU;IAAE;IAC5DC,YAAY;QACVzC,yBAAyB;QACzBC;QACA;YACEyC,MAAM;YACNC,OAAO;YACPV,aACE,sEACA;YACFW,WAAWtD,MAAMuD,kBAAkB,CAACC,MAAM;YAC1C,sEAAsE;YACtE,sEAAsE;YACtE,+DAA+D;YAC/D,sBAAsB;YACtBC,SAAS;gBACP;oBAAEC,OAAO;oBAAaL,OAAO;gBAAsB;gBACnD;oBAAEK,OAAO;oBAAYL,OAAO;gBAAW;aACxC;QACH;QACA;YACED,MAAM;YACNC,OAAO;YACPV,aAAa;YACbW,WAAWtD,MAAMuD,kBAAkB,CAACI,UAAU;YAC9CC,MAAM;YACNC,WAAWzB;QACb;KACD;AACH,EAAC;AAED,OAAO,MAAM0B,mBAAkE;IAC7ErB,KAAKxB;IACLyB,UAAU9B;IACVkB,aAAa;IACba,aAAa;IACbC,UAAU5C,MAAM6C,iBAAiB,CAACC,OAAO;IACzCC,MAAM;QAAEC,MAAM9C,YAAY8C,IAAI;QAAEC,IAAI;YAAEC,OAAO;QAAU;IAAE;IACzDa,OAAO;QAAEC,aAAahE,MAAMiE,YAAY,CAACC,OAAO;IAAC;IACjDf,YAAY;QACV;YACEC,MAAM;YACNC,OAAO;YACPV,aAAa;YACbW,WAAWtD,MAAMuD,kBAAkB,CAACI,UAAU;QAChD;QACA;YACEP,MAAM;YACNC,OAAO;YACPV,aAAa;YACbW,WAAWtD,MAAMuD,kBAAkB,CAACI,UAAU;QAChD;KACD;AACH,EAAC;AAED,OAAO,MAAMQ,oBAA2C;IACtD1B,KAAKvB;IACLwB,UAAU9B;IACVkB,aAAa;IACba,aAAa;IACbC,UAAU5C,MAAM6C,iBAAiB,CAACC,OAAO;IACzCC,MAAM;QAAEC,MAAM9C,YAAY8C,IAAI;QAAEC,IAAI;YAAEC,OAAO;QAAU;IAAE;AAC3D,EAAC;AAED,OAAO,MAAMkB,oBACX;IACE3B,KAAKtB;IACLuB,UAAU9B;IACVkB,aAAa;IACba,aAAa;IACbC,UAAU5C,MAAM6C,iBAAiB,CAACC,OAAO;IACzCC,MAAM;QAAEC,MAAM7C,cAAc6C,IAAI;QAAEC,IAAI;YAAEC,OAAO;QAAU;IAAE;IAC3DC,YAAY;QACV;YACEC,MAAM;YACNC,OAAO;YACPV,aAAa;YACbW,WAAWtD,MAAMuD,kBAAkB,CAACc,MAAM;QAC5C;KACD;AACH,EAAC;AAEH,OAAO,MAAMC,cAAoC;IAC/C;QACE7B,KAAK3B,iBAAiBE;QACtB4C,MAAM5D,MAAMuE,QAAQ,CAACC,MAAM;QAC3B1C,aAAa;QACbY,UAAU9B;QACV+B,aAAa;QACbC,UAAU5C,MAAM6C,iBAAiB,CAACC,OAAO;QACzCC,MAAMP,WAAWO,IAAI;QACrB0B,MAAM;YACJhC,KAAK;YACLiC,aAAa1D;YACb0B,UAAU9B;YACVW,OAAO,CAAC;YACR,gEAAgE;YAChE0B,IAAI;gBAAE0B,UAAU;YAAI;YACpBC,OAAO;gBACL,6DAA6D;gBAC7D,iEAAiE;gBACjE,gEAAgE;gBAChE,8BAA8B;gBAC9B;oBACEnC,KAAK;oBACLiC,aAAa;oBACbhC,UAAU9B;oBACVW,OAAO;wBAAEsD,KAAK;wBAAIC,QAAQ;wBAASC,WAAW;oBAAQ;gBACxD;gBACA;oBACEtC,KAAK;oBACLiC,aAAazD;oBACbyB,UAAU9B;oBACVW,OAAO;wBAAES,OAAO;wBAAcC,WAAW;oBAAkB;gBAC7D;gBACA;oBACEQ,KAAK;oBACLiC,aAAaxD;oBACbwB,UAAU9B;oBACVgE,OAAO;wBACL;4BACEnC,KAAK;4BACLiC,aAAa;4BACbhC,UAAU9B;4BACVW,OAAO;gCACLC,SAAS;gCACTE,UACE;4BACJ;wBACF;qBACD;gBACH;gBACA;oBACEe,KAAK;oBACLiC,aAAavD;oBACbuB,UAAU9B;oBACVgE,OAAO;wBACL;4BACEnC,KAAK;4BACLiC,aAAa;4BACbhC,UAAU9B;4BACV,+DAA+D;4BAC/D,gEAAgE;4BAChE,4DAA4D;4BAC5D,+CAA+C;4BAC/CW,OAAO;gCACLG,UAAU;gCACVsD,UAAU;gCACVC,MAAM;4BACR;wBACF;qBACD;gBACH;aACD;QACH;IACF;IACA;QACExC,KAAK3B,iBAAiBE,SAAS;QAC/B4C,MAAM5D,MAAMuE,QAAQ,CAACC,MAAM;QAC3B1C,aAAa;QACbY,UAAU9B;QACV+B,aAAa;QACbC,UAAU5C,MAAM6C,iBAAiB,CAACC,OAAO;QACzCC,MAAMP,WAAWO,IAAI;QACrB0B,MAAM;YACJhC,KAAK;YACLiC,aAAa1D;YACb0B,UAAU9B;YACVW,OAAO;gBAAEC,SAAS;YAAW;YAC7ByB,IAAI;gBAAE0B,UAAU;YAAI;YACpBC,OAAO;gBACL;oBACEnC,KAAK;oBACLiC,aAAaxD;oBACbwB,UAAU9B;oBACVgE,OAAO;wBACL;4BACEnC,KAAK;4BACLiC,aAAa;4BACbhC,UAAU9B;4BACVW,OAAO;gCAAEC,SAAS;gCAAME,UAAU;4BAAa;wBACjD;wBACA;4BACEe,KAAK;4BACLiC,aAAa;4BACbhC,UAAU9B;4BACVW,OAAO;gCACLC,SAAS;gCACTE,UAAU;4BACZ;wBACF;qBACD;gBACH;aACD;QACH;IACF;CACD,CAAA;AAED,eAAeN,YAAW"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/card.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 { mdiCardOutline, mdiCardText, mdiGestureTap } from '@aglyn/shared-data-mdi'\nimport MuiCard from '@mui/material/Card'\nimport MuiCardActions from '@mui/material/CardActions'\nimport MuiCardContent from '@mui/material/CardContent'\nimport MuiCardHeader from '@mui/material/CardHeader'\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'\nimport { toElevation } from './paper'\n\n// Component ids are persisted in screen documents; never rename.\nexport const CARD_ID: Aglyn.ComponentId = 'muiCard'\nexport const CARD_HEADER_ID: Aglyn.ComponentId = 'muiCardHeader'\nexport const CARD_CONTENT_ID: Aglyn.ComponentId = 'muiCardContent'\nexport const CARD_ACTIONS_ID: Aglyn.ComponentId = 'muiCardActions'\n\nexport interface CardElementProps {\n variant?: 'elevation' | 'outlined'\n /** Shadow depth, 0–24; ignored on the outlined variant. */\n elevation?: number | string\n children?: ReactNode\n}\n\nexport interface CardHeaderElementProps {\n title?: string\n subheader?: string\n}\n\nexport interface CardActionsElementProps {\n /** If true, the 8px gap between action buttons is removed. */\n disableSpacing?: boolean\n children?: ReactNode\n}\n\n/**\n * Card (https://mui.com/material-ui/react-card/) — a Paper with card\n * padding conventions. Composed from separate Header/Content/Actions\n * elements rather than a single element with a dozen text props, so the\n * pieces are individually selectable, stylable and reorderable on the\n * canvas like everything else.\n */\nconst CardElement = forwardRef<HTMLDivElement, CardElementProps>(\n (rawProps, ref) => {\n // See PaperElement: cleared props are dropped before anything reads\n // them, so `rest` cannot carry a `null` into MUI (AGL-1451).\n const props = dropClearedProps(rawProps)\n const { variant, elevation, children, ...rest } = props\n const outlined = variant === 'outlined'\n // A variant or an elevation the author did not set is left to the site's\n // theme (AGL-3660): a Card dropped from the drawer takes the card style\n // the theme's MuiCard defaults give it, as every Card the site has does.\n const chosen = outlined ? 'outlined' : variant === 'elevation' ? 'elevation' : undefined\n // Same trap as Paper: a string elevation indexes MUI's shadow array and\n // yields a completely flat card.\n const depth = outlined ? undefined : toElevation(elevation)\n return (\n <MuiCard\n ref={ref}\n {...(chosen ? { variant: chosen } : {})}\n {...(depth !== undefined ? { elevation: depth } : {})}\n {...applySemanticElement(rest as Record<string, unknown>)}\n >\n {children}\n </MuiCard>\n )\n },\n)\nCardElement.displayName = 'AglynCard'\n\n/**\n * Card header. `title`/`subheader` are plain strings: MUI wraps each in\n * its own Typography, and passing children instead would drop the\n * heading/subheading type scale a card header exists to provide.\n */\nexport const CardHeaderElement = forwardRef<\n HTMLDivElement,\n CardHeaderElementProps\n>((props, ref) => {\n const { title, subheader, ...rest } = props as CardHeaderElementProps & {\n children?: unknown\n }\n // A header with neither string is invisible and unselectable on the\n // canvas; a placeholder keeps the node reachable.\n delete (rest as { children?: unknown }).children\n return (\n <MuiCardHeader\n ref={ref}\n title={title || (subheader ? undefined : 'Card title')}\n subheader={subheader || undefined}\n {...rest}\n />\n )\n})\nCardHeaderElement.displayName = 'AglynCardHeader'\n\nexport const CardContentElement = forwardRef<\n HTMLDivElement,\n { children?: ReactNode }\n>((props, ref) => <MuiCardContent ref={ref} {...props} />)\nCardContentElement.displayName = 'AglynCardContent'\n\nexport const CardActionsElement = forwardRef<\n HTMLDivElement,\n CardActionsElementProps\n>((props, ref) => <MuiCardActions ref={ref} {...props} />)\nCardActionsElement.displayName = 'AglynCardActions'\n\n/** Elevation only means anything on the (default) `elevation` variant. */\nconst ELEVATION_ONLY = { when: 'variant', is: 'outlined', notMatch: true }\n\nexport const cardSchema: Aglyn.ComponentSchema<CardElementProps> = {\n $id: CARD_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Card',\n description:\n 'Surface that groups a header, content and actions about one subject.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: { path: mdiCardOutline.path, sx: { color: '#2196f3' } },\n attributes: [\n semanticElementAttribute('this card'),\n semanticElementLabelAttribute(),\n {\n name: 'variant',\n label: 'Variant',\n description:\n 'Elevation raises the card with a shadow; outlined draws a border ' +\n 'instead and has no shadow.',\n component: Aglyn.FieldComponentType.SELECT,\n // Same call as Paper (AGL-1451): a real sentinel, because `elevation`\n // is MUI's own value for the other half of this two-way choice and is\n // what the Elevation control is conditioned on. `''` could not\n // persist (AGL-1191).\n options: [\n { value: 'elevation', label: 'Elevation (default)' },\n { value: 'outlined', label: 'Outlined' },\n ],\n },\n {\n name: 'elevation',\n label: 'Elevation',\n description: 'Shadow depth from 0 (flat) to 24.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: ELEVATION_ONLY,\n },\n ],\n}\n\nexport const cardHeaderSchema: Aglyn.ComponentSchema<CardHeaderElementProps> = {\n $id: CARD_HEADER_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Card Header',\n description: 'The title and subheader at the top of a card.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: { path: mdiCardText.path, sx: { color: '#2196f3' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'title',\n label: 'Title',\n description: 'The card heading.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'subheader',\n label: 'Subheader',\n description: 'Secondary line under the title.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n ],\n}\n\nexport const cardContentSchema: Aglyn.ComponentSchema = {\n $id: CARD_CONTENT_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Card Content',\n description: 'The padded body region of a card.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: { path: mdiCardText.path, sx: { color: '#2196f3' } },\n}\n\nexport const cardActionsSchema: Aglyn.ComponentSchema<CardActionsElementProps> =\n {\n $id: CARD_ACTIONS_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Card Actions',\n description: 'The button row at the bottom of a card.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: { path: mdiGestureTap.path, sx: { color: '#2196f3' } },\n attributes: [\n {\n name: 'disableSpacing',\n label: 'Disable spacing?',\n description: 'If true, the gap between action buttons is removed.',\n component: Aglyn.FieldComponentType.SWITCH,\n },\n ],\n }\n\nexport const cardPresets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(CARD_ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Card',\n pluginId: BUNDLE_ID,\n description: 'Image, heading, body text and an action button',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: cardSchema.icon,\n data: {\n $id: null,\n componentId: CARD_ID,\n pluginId: BUNDLE_ID,\n props: {},\n // Node-level sx (AGL-1346) — the record the Styles panel edits.\n sx: { maxWidth: 360 },\n nodes: [\n // The existing Image element rather than MUI's CardMedia: it\n // already carries the media-CDN srcSet, the lazy loading and the\n // empty-source placeholder (AGL-74/175), none of which is worth\n // re-implementing for a card.\n {\n $id: null,\n componentId: 'image',\n pluginId: BUNDLE_ID,\n props: { alt: '', height: '160px', objectFit: 'cover' },\n },\n {\n $id: null,\n componentId: CARD_HEADER_ID,\n pluginId: BUNDLE_ID,\n props: { title: 'Card title', subheader: 'Supporting line' },\n },\n {\n $id: null,\n componentId: CARD_CONTENT_ID,\n pluginId: BUNDLE_ID,\n nodes: [\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: {\n variant: 'body2',\n children:\n 'A short description of whatever this card is about.',\n },\n },\n ],\n },\n {\n $id: null,\n componentId: CARD_ACTIONS_ID,\n pluginId: BUNDLE_ID,\n nodes: [\n {\n $id: null,\n componentId: 'muiScreenLink',\n pluginId: BUNDLE_ID,\n // `'button'`, not `''` (AGL-1453). This preset was MINTING the\n // unpersistable value: every card dropped on a canvas planted a\n // `renderAs: ''` that no longer matches any option. Renders\n // identically — both take the non-link branch.\n props: {\n children: 'Learn more',\n renderAs: 'button',\n size: 'small',\n },\n },\n ],\n },\n ],\n },\n },\n {\n $id: generatePresetId(CARD_ID, 'outlined'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Card Outlined',\n pluginId: BUNDLE_ID,\n description: 'Text-only card with a border instead of a shadow',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: cardSchema.icon,\n data: {\n $id: null,\n componentId: CARD_ID,\n pluginId: BUNDLE_ID,\n props: { variant: 'outlined' },\n sx: { maxWidth: 360 },\n nodes: [\n {\n $id: null,\n componentId: CARD_CONTENT_ID,\n pluginId: BUNDLE_ID,\n nodes: [\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: { variant: 'h6', children: 'Card title' },\n },\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: {\n variant: 'body2',\n children: 'A short description of this card.',\n },\n },\n ],\n },\n ],\n },\n },\n]\n\nexport default CardElement\n"],"names":["Aglyn","mdiCardOutline","mdiCardText","mdiGestureTap","MuiCard","MuiCardActions","MuiCardContent","MuiCardHeader","forwardRef","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","BUNDLE_ID","dropClearedProps","generatePresetId","toElevation","CARD_ID","CARD_HEADER_ID","CARD_CONTENT_ID","CARD_ACTIONS_ID","CardElement","rawProps","ref","props","variant","elevation","children","rest","outlined","chosen","undefined","depth","displayName","CardHeaderElement","title","subheader","CardContentElement","CardActionsElement","ELEVATION_ONLY","when","is","notMatch","cardSchema","$id","pluginId","description","category","ComponentCategory","SURFACE","icon","path","sx","color","attributes","name","label","component","FieldComponentType","SELECT","options","value","TEXT_FIELD","type","condition","cardHeaderSchema","flags","selfClosing","FEATURE_FLAG","ENABLED","cardContentSchema","cardActionsSchema","SWITCH","cardPresets","NodeType","PRESET","data","componentId","maxWidth","nodes","alt","height","objectFit","renderAs","size"],"mappings":"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"}
|
|
@@ -32,6 +32,13 @@ import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
|
32
32
|
// Component ids are persisted in screen documents; never rename.
|
|
33
33
|
export const DATA_TABLE_ID = 'dataTable';
|
|
34
34
|
/** What a screen reader announces on reaching the grid's scroll box. */ const TABLE_REGION_LABEL = 'Table';
|
|
35
|
+
// The component and its preset show the same drawer glyph.
|
|
36
|
+
const TABLE_ICON = {
|
|
37
|
+
path: mdiTable.path,
|
|
38
|
+
sx: {
|
|
39
|
+
color: '#0288d1'
|
|
40
|
+
}
|
|
41
|
+
};
|
|
35
42
|
/**
|
|
36
43
|
* A comparison table (AGL-2543).
|
|
37
44
|
*
|
|
@@ -150,12 +157,7 @@ export const dataTableSchema = {
|
|
|
150
157
|
displayName: 'Table',
|
|
151
158
|
description: 'A grid of rows and columns — a feature matrix, a spec sheet, a comparison.',
|
|
152
159
|
category: Aglyn.ComponentCategory.BLOCKS,
|
|
153
|
-
icon:
|
|
154
|
-
path: mdiTable.path,
|
|
155
|
-
sx: {
|
|
156
|
-
color: '#0288d1'
|
|
157
|
-
}
|
|
158
|
-
},
|
|
160
|
+
icon: TABLE_ICON,
|
|
159
161
|
flags: {
|
|
160
162
|
selfClosing: Aglyn.FEATURE_FLAG.ENABLED
|
|
161
163
|
},
|
|
@@ -188,12 +190,7 @@ export const dataTablePresets = [
|
|
|
188
190
|
pluginId: BUNDLE_ID,
|
|
189
191
|
description: 'Comparison grid with a header row',
|
|
190
192
|
category: Aglyn.ComponentCategory.BLOCKS,
|
|
191
|
-
icon:
|
|
192
|
-
path: mdiTable.path,
|
|
193
|
-
sx: {
|
|
194
|
-
color: '#0288d1'
|
|
195
|
-
}
|
|
196
|
-
},
|
|
193
|
+
icon: TABLE_ICON,
|
|
197
194
|
data: {
|
|
198
195
|
$id: null,
|
|
199
196
|
componentId: DATA_TABLE_ID,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/data-table.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 {\n normalizeEmphasisColumn,\n parseDataTableRows,\n readDataTableAlignments,\n} from '@aglyn/shared-data-enums'\nimport { mdiTable } from '@aglyn/shared-data-mdi'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport {\n scrollRegionProps,\n scrollableTableSx,\n} from '@aglyn/shared-ui-jsx/utils/scroll-overflow'\nimport Box from '@mui/material/Box'\nimport TableBody from '@mui/material/TableBody'\nimport TableCell from '@mui/material/TableCell'\nimport TableHead from '@mui/material/TableHead'\nimport TableRow from '@mui/material/TableRow'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const DATA_TABLE_ID: Aglyn.ComponentId = 'dataTable'\n\n/** What a screen reader announces on reaching the grid's scroll box. */\nconst TABLE_REGION_LABEL = 'Table'\n\nexport interface DataTableProps {\n /**\n * The grid, pipe-delimited, one row per line — and its column alignment,\n * as a markdown divider row. See `@aglyn/shared-data-enums`'s `data-table` utilities.\n */\n rows?: string\n /** Render the first row as a header. */\n headerRow?: boolean\n /** 1-based column to emphasise, or 0/absent for none. */\n emphasizeColumn?: number | string\n}\n\n/**\n * A comparison table (AGL-2543).\n *\n * The feature matrix is the load-bearing block on a competitor comparison\n * page, and the palette had no way to build one: searching `table` returned\n * **Table of Contents** and **Pricing Table**, neither of which is a general\n * grid. The only route was to author markdown pipe syntax inside a Markdown\n * element — which renders correctly and is exactly the audience the besigner\n * exists to spare.\n *\n * Three things the Markdown route could not give, and the reason this is an\n * element rather than a docs note:\n *\n * - **Header emphasis**, without asking an author to remember that the first\n * row is special.\n * - **A highlighted column** — the \"ours\" column on a comparison page is the\n * entire point of the block, and markdown has no way to say it.\n * - **A grid to edit**, rather than pipe syntax in a text box — see the\n * `DATA_TABLE` field this element's `rows` attribute asks for.\n *\n * Narrow-screen behaviour is NOT one of them (AGL-2568). Both routes draw the\n * same block, so both take the same treatment from `scroll-overflow`: the\n * grid scrolls inside its own box once it is too wide to read, and says so.\n */\nconst DataTable = forwardRef<HTMLDivElement, DataTableProps>((props, ref) => {\n const { rows, headerRow = true, emphasizeColumn, ...rest } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n const grid = parseDataTableRows(rows)\n const width = grid[0]?.length ?? 0\n const alignments = readDataTableAlignments(rows, width)\n const emphasis = normalizeEmphasisColumn(emphasizeColumn, width)\n\n if (grid.length === 0) {\n // The hint is for the author, so only editing surfaces draw it; a\n // published page renders the bare element.\n if (!suppressNavigation) return <Box ref={ref} {...rest} />\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n padding: 2,\n border: '1px dashed',\n borderColor: 'divider',\n color: 'text.secondary',\n fontSize: 12,\n fontFamily: 'system-ui, sans-serif',\n },\n ...nodeSx,\n ]}\n >\n {'Table — add rows in Attributes'}\n </Box>\n )\n }\n\n const [first, ...body] = grid\n const dataRows = headerRow ? body : grid\n // An emphasised column reads as emphasised in BOTH halves of the table: a\n // header cell that is bold anyway would otherwise show no highlight at all,\n // which is the one row an author looks at first.\n const cellSx = (columnIndex: number) =>\n emphasis === columnIndex + 1\n ? { backgroundColor: 'action.hover', fontWeight: 600 }\n : undefined\n\n return (\n <ScrollTable\n ref={ref}\n size=\"small\"\n // The box scrolls the grid, and the grid is sized so that it can\n // (AGL-2568). The box's `overflow-x` is half of it: it does nothing at\n // all while the table inside is `width: 100%`, because a table of prose\n // cells that cannot exceed its box never overflows it — it crushes its\n // columns instead. `max-content` is the other half, and the box's fade\n // is what makes an overlay-scrollbar platform admit that it scrolled.\n sx={scrollableTableSx}\n ContainerProps={{\n ...rest,\n ...scrollRegionProps(TABLE_REGION_LABEL),\n // The node's styles merge after the box's own, never instead of them.\n sx: nodeSx,\n }}\n >\n {headerRow ? (\n <TableHead>\n <TableRow>\n {first.map((cell, columnIndex) => (\n <TableCell\n key={columnIndex}\n align={alignments[columnIndex]}\n sx={{ fontWeight: 700, ...cellSx(columnIndex) }}\n >\n {cell}\n </TableCell>\n ))}\n </TableRow>\n </TableHead>\n ) : null}\n <TableBody>\n {dataRows.map((row, rowIndex) => (\n <TableRow key={rowIndex}>\n {row.map((cell, columnIndex) => (\n <TableCell\n key={columnIndex}\n align={alignments[columnIndex]}\n sx={cellSx(columnIndex)}\n >\n {cell}\n </TableCell>\n ))}\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n )\n})\nDataTable.displayName = 'AglynDataTable'\n\nexport default DataTable\n\nexport const dataTableSchema: Aglyn.ComponentSchema<DataTableProps> = {\n $id: DATA_TABLE_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Table',\n description:\n 'A grid of rows and columns — a feature matrix, a spec sheet, a comparison.',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiTable.path, sx: { color: '#0288d1' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'rows',\n description:\n 'The table contents. Paste a markdown table to import one you already have.',\n component: Aglyn.FieldComponentType.DATA_TABLE,\n label: 'Rows',\n },\n {\n name: 'headerRow',\n description: 'Render the first row as a header.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n label: 'First row is a header',\n },\n {\n name: 'emphasizeColumn',\n description:\n 'Highlight one column — on a comparison table, usually your own. 0 for none.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Emphasize column',\n },\n ],\n}\n\nexport const dataTablePresets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(DATA_TABLE_ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Table',\n pluginId: BUNDLE_ID,\n description: 'Comparison grid with a header row',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiTable.path, sx: { color: '#0288d1' } },\n data: {\n $id: null,\n componentId: DATA_TABLE_ID,\n pluginId: BUNDLE_ID,\n props: {\n headerRow: true,\n emphasizeColumn: 2,\n rows: [\n 'Feature | Us | Them',\n '--- | :---: | :---:',\n 'Open source | Yes | No',\n 'Self-hostable | Yes | No',\n 'One platform | Yes | No',\n ].join('\\n'),\n },\n },\n },\n]\n"],"names":["Aglyn","normalizeEmphasisColumn","parseDataTableRows","readDataTableAlignments","mdiTable","ScrollTable","scrollRegionProps","scrollableTableSx","Box","TableBody","TableCell","TableHead","TableRow","forwardRef","useContext","BUNDLE_ID","generatePresetId","DATA_TABLE_ID","TABLE_REGION_LABEL","DataTable","props","ref","grid","rows","headerRow","emphasizeColumn","rest","nodeSx","Array","isArray","suppressNavigation","ScreenLinkContext","width","length","alignments","emphasis","sx","padding","border","borderColor","color","fontSize","fontFamily","first","body","dataRows","cellSx","columnIndex","backgroundColor","fontWeight","undefined","size","ContainerProps","map","cell","align","row","rowIndex","displayName","dataTableSchema","$id","pluginId","description","category","ComponentCategory","BLOCKS","icon","path","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","name","component","FieldComponentType","DATA_TABLE","label","CHECKBOX","TEXT_FIELD","dataTablePresets","type","NodeType","PRESET","data","componentId","join"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/data-table.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 {\n normalizeEmphasisColumn,\n parseDataTableRows,\n readDataTableAlignments,\n} from '@aglyn/shared-data-enums'\nimport { mdiTable } from '@aglyn/shared-data-mdi'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport {\n scrollRegionProps,\n scrollableTableSx,\n} from '@aglyn/shared-ui-jsx/utils/scroll-overflow'\nimport Box from '@mui/material/Box'\nimport TableBody from '@mui/material/TableBody'\nimport TableCell from '@mui/material/TableCell'\nimport TableHead from '@mui/material/TableHead'\nimport TableRow from '@mui/material/TableRow'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const DATA_TABLE_ID: Aglyn.ComponentId = 'dataTable'\n\n/** What a screen reader announces on reaching the grid's scroll box. */\nconst TABLE_REGION_LABEL = 'Table'\n\n// The component and its preset show the same drawer glyph.\nconst TABLE_ICON = { path: mdiTable.path, sx: { color: '#0288d1' } }\n\nexport interface DataTableProps {\n /**\n * The grid, pipe-delimited, one row per line — and its column alignment,\n * as a markdown divider row. See `@aglyn/shared-data-enums`'s `data-table` utilities.\n */\n rows?: string\n /** Render the first row as a header. */\n headerRow?: boolean\n /** 1-based column to emphasise, or 0/absent for none. */\n emphasizeColumn?: number | string\n}\n\n/**\n * A comparison table (AGL-2543).\n *\n * The feature matrix is the load-bearing block on a competitor comparison\n * page, and the palette had no way to build one: searching `table` returned\n * **Table of Contents** and **Pricing Table**, neither of which is a general\n * grid. The only route was to author markdown pipe syntax inside a Markdown\n * element — which renders correctly and is exactly the audience the besigner\n * exists to spare.\n *\n * Three things the Markdown route could not give, and the reason this is an\n * element rather than a docs note:\n *\n * - **Header emphasis**, without asking an author to remember that the first\n * row is special.\n * - **A highlighted column** — the \"ours\" column on a comparison page is the\n * entire point of the block, and markdown has no way to say it.\n * - **A grid to edit**, rather than pipe syntax in a text box — see the\n * `DATA_TABLE` field this element's `rows` attribute asks for.\n *\n * Narrow-screen behaviour is NOT one of them (AGL-2568). Both routes draw the\n * same block, so both take the same treatment from `scroll-overflow`: the\n * grid scrolls inside its own box once it is too wide to read, and says so.\n */\nconst DataTable = forwardRef<HTMLDivElement, DataTableProps>((props, ref) => {\n const { rows, headerRow = true, emphasizeColumn, ...rest } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n const grid = parseDataTableRows(rows)\n const width = grid[0]?.length ?? 0\n const alignments = readDataTableAlignments(rows, width)\n const emphasis = normalizeEmphasisColumn(emphasizeColumn, width)\n\n if (grid.length === 0) {\n // The hint is for the author, so only editing surfaces draw it; a\n // published page renders the bare element.\n if (!suppressNavigation) return <Box ref={ref} {...rest} />\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n padding: 2,\n border: '1px dashed',\n borderColor: 'divider',\n color: 'text.secondary',\n fontSize: 12,\n fontFamily: 'system-ui, sans-serif',\n },\n ...nodeSx,\n ]}\n >\n {'Table — add rows in Attributes'}\n </Box>\n )\n }\n\n const [first, ...body] = grid\n const dataRows = headerRow ? body : grid\n // An emphasised column reads as emphasised in BOTH halves of the table: a\n // header cell that is bold anyway would otherwise show no highlight at all,\n // which is the one row an author looks at first.\n const cellSx = (columnIndex: number) =>\n emphasis === columnIndex + 1\n ? { backgroundColor: 'action.hover', fontWeight: 600 }\n : undefined\n\n return (\n <ScrollTable\n ref={ref}\n size=\"small\"\n // The box scrolls the grid, and the grid is sized so that it can\n // (AGL-2568). The box's `overflow-x` is half of it: it does nothing at\n // all while the table inside is `width: 100%`, because a table of prose\n // cells that cannot exceed its box never overflows it — it crushes its\n // columns instead. `max-content` is the other half, and the box's fade\n // is what makes an overlay-scrollbar platform admit that it scrolled.\n sx={scrollableTableSx}\n ContainerProps={{\n ...rest,\n ...scrollRegionProps(TABLE_REGION_LABEL),\n // The node's styles merge after the box's own, never instead of them.\n sx: nodeSx,\n }}\n >\n {headerRow ? (\n <TableHead>\n <TableRow>\n {first.map((cell, columnIndex) => (\n <TableCell\n key={columnIndex}\n align={alignments[columnIndex]}\n sx={{ fontWeight: 700, ...cellSx(columnIndex) }}\n >\n {cell}\n </TableCell>\n ))}\n </TableRow>\n </TableHead>\n ) : null}\n <TableBody>\n {dataRows.map((row, rowIndex) => (\n <TableRow key={rowIndex}>\n {row.map((cell, columnIndex) => (\n <TableCell\n key={columnIndex}\n align={alignments[columnIndex]}\n sx={cellSx(columnIndex)}\n >\n {cell}\n </TableCell>\n ))}\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n )\n})\nDataTable.displayName = 'AglynDataTable'\n\nexport default DataTable\n\nexport const dataTableSchema: Aglyn.ComponentSchema<DataTableProps> = {\n $id: DATA_TABLE_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Table',\n description:\n 'A grid of rows and columns — a feature matrix, a spec sheet, a comparison.',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: TABLE_ICON,\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'rows',\n description:\n 'The table contents. Paste a markdown table to import one you already have.',\n component: Aglyn.FieldComponentType.DATA_TABLE,\n label: 'Rows',\n },\n {\n name: 'headerRow',\n description: 'Render the first row as a header.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n label: 'First row is a header',\n },\n {\n name: 'emphasizeColumn',\n description:\n 'Highlight one column — on a comparison table, usually your own. 0 for none.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Emphasize column',\n },\n ],\n}\n\nexport const dataTablePresets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(DATA_TABLE_ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Table',\n pluginId: BUNDLE_ID,\n description: 'Comparison grid with a header row',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: TABLE_ICON,\n data: {\n $id: null,\n componentId: DATA_TABLE_ID,\n pluginId: BUNDLE_ID,\n props: {\n headerRow: true,\n emphasizeColumn: 2,\n rows: [\n 'Feature | Us | Them',\n '--- | :---: | :---:',\n 'Open source | Yes | No',\n 'Self-hostable | Yes | No',\n 'One platform | Yes | No',\n ].join('\\n'),\n },\n },\n },\n]\n"],"names":["Aglyn","normalizeEmphasisColumn","parseDataTableRows","readDataTableAlignments","mdiTable","ScrollTable","scrollRegionProps","scrollableTableSx","Box","TableBody","TableCell","TableHead","TableRow","forwardRef","useContext","BUNDLE_ID","generatePresetId","DATA_TABLE_ID","TABLE_REGION_LABEL","TABLE_ICON","path","sx","color","DataTable","props","ref","grid","rows","headerRow","emphasizeColumn","rest","nodeSx","Array","isArray","suppressNavigation","ScreenLinkContext","width","length","alignments","emphasis","padding","border","borderColor","fontSize","fontFamily","first","body","dataRows","cellSx","columnIndex","backgroundColor","fontWeight","undefined","size","ContainerProps","map","cell","align","row","rowIndex","displayName","dataTableSchema","$id","pluginId","description","category","ComponentCategory","BLOCKS","icon","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","name","component","FieldComponentType","DATA_TABLE","label","CHECKBOX","TEXT_FIELD","dataTablePresets","type","NodeType","PRESET","data","componentId","join"],"mappings":"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"}
|
|
@@ -91,7 +91,8 @@ export const ID = 'icon';
|
|
|
91
91
|
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
92
92
|
path: icon.path,
|
|
93
93
|
sx: _extends({
|
|
94
|
-
|
|
94
|
+
// A size stored as text (an AI-built page stores every prop as text) is still pixels.
|
|
95
|
+
fontSize: Number(size) > 0 ? Number(size) : 24
|
|
95
96
|
}, color ? {
|
|
96
97
|
color
|
|
97
98
|
} : {})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/icon.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { getMdiIconPath, mdiShapePlus } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport Box from '@mui/material/Box'\nimport type { SxProps } from '@mui/material/styles'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'icon'\n\nexport interface IconProps {\n /** mdi icon id from the picker (AGL-146). */\n iconId?: string\n /**\n * Resolved SVG path for `iconId`, denormalized at author time (AGL-1212).\n * Render surfaces read this and never load the icon catalog.\n */\n iconPath?: string\n /** Icon size in px; defaults to 24. */\n size?: number\n /** CSS color; defaults to the inherited text color. */\n color?: string\n /**\n * Authored node styles, handed over by the renderer rather than typed\n * into an attribute — recomposed below so the Styles panel's values are\n * merged rather than replaced (AGL-1284).\n */\n sx?: SxProps\n}\n\n/**\n * Icon element (AGL-146): renders a picked mdi icon with size/color\n * controls; an empty pick shows a labeled placeholder so the element stays\n * selectable in the editor.\n *\n * Path resolution order (AGL-1212): the persisted `iconPath` first, then the\n * in-memory catalog for documents authored before paths were stored. The\n * catalog is ~2.9 MB and is only loaded by picker surfaces, so on the tenant\n * site and in preview the second lookup misses — which is why it must NOT go\n * through `getMdiIconFromId`, whose `DEFAULT_ICON` fallback carries a real\n * path and rendered a \"help\" glyph on every published page.\n */\nconst Icon = forwardRef<HTMLElement, IconProps>((props, ref) => {\n const { iconId, iconPath, size, color, ...rest } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n const path = iconPath || getMdiIconPath(iconId)\n const icon = path ? { path } : undefined\n if (!icon?.path) {\n // The labeled box is for the author, so only editing surfaces draw it; a\n // published page renders the bare element, as the span a picked icon is.\n if (!suppressNavigation) return <Box ref={ref} component=\"span\" {...rest} />\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n width: 48,\n height: 48,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n border: '1px dashed',\n borderColor: 'divider',\n borderRadius: 1,\n color: 'text.secondary',\n fontSize: 10,\n fontFamily: 'system-ui, sans-serif',\n },\n ...nodeSx,\n ]}\n >\n {'Icon'}\n </Box>\n )\n }\n return (\n <Box ref={ref} component=\"span\" sx={{ display: 'inline-flex' }} {...rest}>\n <MdiIcon\n path={icon.path}\n sx={{\n
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/icon.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { getMdiIconPath, mdiShapePlus } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport Box from '@mui/material/Box'\nimport type { SxProps } from '@mui/material/styles'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'icon'\n\nexport interface IconProps {\n /** mdi icon id from the picker (AGL-146). */\n iconId?: string\n /**\n * Resolved SVG path for `iconId`, denormalized at author time (AGL-1212).\n * Render surfaces read this and never load the icon catalog.\n */\n iconPath?: string\n /** Icon size in px; defaults to 24. */\n size?: number\n /** CSS color; defaults to the inherited text color. */\n color?: string\n /**\n * Authored node styles, handed over by the renderer rather than typed\n * into an attribute — recomposed below so the Styles panel's values are\n * merged rather than replaced (AGL-1284).\n */\n sx?: SxProps\n}\n\n/**\n * Icon element (AGL-146): renders a picked mdi icon with size/color\n * controls; an empty pick shows a labeled placeholder so the element stays\n * selectable in the editor.\n *\n * Path resolution order (AGL-1212): the persisted `iconPath` first, then the\n * in-memory catalog for documents authored before paths were stored. The\n * catalog is ~2.9 MB and is only loaded by picker surfaces, so on the tenant\n * site and in preview the second lookup misses — which is why it must NOT go\n * through `getMdiIconFromId`, whose `DEFAULT_ICON` fallback carries a real\n * path and rendered a \"help\" glyph on every published page.\n */\nconst Icon = forwardRef<HTMLElement, IconProps>((props, ref) => {\n const { iconId, iconPath, size, color, ...rest } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n const path = iconPath || getMdiIconPath(iconId)\n const icon = path ? { path } : undefined\n if (!icon?.path) {\n // The labeled box is for the author, so only editing surfaces draw it; a\n // published page renders the bare element, as the span a picked icon is.\n if (!suppressNavigation) return <Box ref={ref} component=\"span\" {...rest} />\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n width: 48,\n height: 48,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n border: '1px dashed',\n borderColor: 'divider',\n borderRadius: 1,\n color: 'text.secondary',\n fontSize: 10,\n fontFamily: 'system-ui, sans-serif',\n },\n ...nodeSx,\n ]}\n >\n {'Icon'}\n </Box>\n )\n }\n return (\n <Box ref={ref} component=\"span\" sx={{ display: 'inline-flex' }} {...rest}>\n <MdiIcon\n path={icon.path}\n sx={{\n // A size stored as text (an AI-built page stores every prop as text) is still pixels.\n fontSize: Number(size) > 0 ? Number(size) : 24,\n ...(color ? { color } : {}),\n }}\n />\n </Box>\n )\n})\nIcon.displayName = 'Icon'\n\nexport const schema: Aglyn.ComponentSchema<IconProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Icon',\n description:\n 'A single icon from the library, at the size and color you pick.',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: {\n path: mdiShapePlus.path,\n sx: { color: '#7b1fa2' },\n },\n flags: {\n // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n selfClosing: Aglyn.FEATURE_FLAG.ENABLED,\n },\n attributes: [\n {\n name: 'iconId',\n description: 'Pick any icon from the library.',\n component: Aglyn.FieldComponentType.ICON_PICKER,\n label: 'Icon',\n },\n {\n name: 'size',\n description: 'Icon size in pixels (default 24).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Size (px)',\n type: 'number',\n },\n {\n name: 'color',\n description: 'CSS color, e.g. #7b1fa2; empty inherits the text color.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Color',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Icon',\n pluginId: BUNDLE_ID,\n description: 'A single icon from the mdi library',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: {\n path: mdiShapePlus.path,\n sx: { color: '#7b1fa2' },\n },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default Icon\n"],"names":["Aglyn","getMdiIconPath","mdiShapePlus","MdiIcon","Box","forwardRef","useContext","BUNDLE_ID","generatePresetId","ID","Icon","props","ref","iconId","iconPath","size","color","rest","nodeSx","Array","isArray","suppressNavigation","ScreenLinkContext","path","icon","undefined","component","sx","width","height","display","alignItems","justifyContent","border","borderColor","borderRadius","fontSize","fontFamily","Number","displayName","schema","$id","pluginId","description","category","ComponentCategory","MEDIA","flags","lazyHydration","FEATURE_FLAG","ENABLED","selfClosing","attributes","name","FieldComponentType","ICON_PICKER","label","TEXT_FIELD","type","presets","NodeType","PRESET","data","componentId"],"mappings":"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"}
|
|
@@ -56,11 +56,11 @@ export interface InlineTextProps {
|
|
|
56
56
|
/**
|
|
57
57
|
* One run of text inside a sentence (AGL-1235).
|
|
58
58
|
*
|
|
59
|
-
* The gap this fills:
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
59
|
+
* The gap this fills: a statement whose argument lives in an emphasised
|
|
60
|
+
* phrase ("Aglyn commerce is **part of the platform**") — a run of its own
|
|
61
|
+
* colour or weight inside one line. A Typography can hold elements too
|
|
62
|
+
* (AGL-3672), but only after its own text, so it cannot put the emphasis
|
|
63
|
+
* mid-sentence.
|
|
64
64
|
*
|
|
65
65
|
* This is a leaf too, deliberately: the shape that renders correctly is a
|
|
66
66
|
* block container holding SIBLING inline runs, not a nested span. Sibling
|
|
@@ -96,11 +96,11 @@ export const ID = 'muiInlineText';
|
|
|
96
96
|
/**
|
|
97
97
|
* One run of text inside a sentence (AGL-1235).
|
|
98
98
|
*
|
|
99
|
-
* The gap this fills:
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
99
|
+
* The gap this fills: a statement whose argument lives in an emphasised
|
|
100
|
+
* phrase ("Aglyn commerce is **part of the platform**") — a run of its own
|
|
101
|
+
* colour or weight inside one line. A Typography can hold elements too
|
|
102
|
+
* (AGL-3672), but only after its own text, so it cannot put the emphasis
|
|
103
|
+
* mid-sentence.
|
|
104
104
|
*
|
|
105
105
|
* This is a leaf too, deliberately: the shape that renders correctly is a
|
|
106
106
|
* block container holding SIBLING inline runs, not a nested span. Sibling
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/inline-text.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 { mdiFormatColorHighlight, mdiFormatColorText } from '@aglyn/shared-data-mdi'\nimport MuiBox from '@mui/material/Box'\nimport type { SxProps } from '@mui/material/styles'\nimport { forwardRef, type ReactNode } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { FIELD_TEXT_CONTENT } from '../constants/field-presets'\nimport { authorHtmlLabel } from '../utils/author-html-label'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiInlineText'\n\n/**\n * Inline elements the run may render as. An allow-list rather than a\n * free-text field, for the same reason Box's is (AGL-1201): `element` is\n * persisted and rendered verbatim into every visitor's page, so a typed\n * value would let an author put `script`/`iframe` there.\n *\n * All five are phrasing content, so a run is always legal inside a\n * paragraph — which is the whole point of the element.\n */\nexport const INLINE_TEXT_ELEMENTS = [\n 'span',\n 'strong',\n 'em',\n 'mark',\n 'small',\n] as const\nexport type InlineTextElement = (typeof INLINE_TEXT_ELEMENTS)[number]\n\n/**\n * Theme palette paths, never raw hexes: the design's `text/muted` and\n * `text/primary` tokens ARE `text.secondary` / `text.primary`, and a\n * hardcoded `#757575` would ignore the site's theme (and dark mode).\n *\n * Every value is a real sentinel — an option value of `''` is stripped\n * before save and the pick silently reverts on reload (AGL-1191), so\n * \"inherit\" has to be spelled out rather than left blank.\n */\nconst TONE_COLOR: Record<string, string> = {\n inherit: undefined,\n primary: 'text.primary',\n secondary: 'text.secondary',\n disabled: 'text.disabled',\n accent: 'primary.main',\n accentAlt: 'secondary.main',\n success: 'success.main',\n warning: 'warning.main',\n error: 'error.main',\n}\n\n/** Named weights so the field is a pick, not a number to remember. */\nconst FONT_WEIGHT: Record<string, number> = {\n inherit: undefined,\n regular: 400,\n medium: 500,\n semibold: 600,\n bold: 700,\n}\n\n/**\n * `text-decoration` PROPAGATES — it is not inherited. An ancestor's\n * underline (a Screen Link, a struck-through block) is painted straight\n * across every in-flow inline descendant, and `text-decoration: none` on\n * the descendant CANNOT remove it. Only an element that is not an in-flow\n * non-atomic inline box escapes the propagation, which is why \"None\" also\n * switches the run to `inline-block`: an atomic inline box is not painted\n * through.\n *\n * That costs line-breaking — an inline-block will not break across lines —\n * so it is opt-in rather than the default, and the field says so. The\n * default, `inherit`, is a plain `display: inline` run that flows and wraps\n * with the rest of the sentence.\n */\nconst DECORATION_SX: Record<string, Record<string, string>> = {\n inherit: {},\n none: { display: 'inline-block', textDecoration: 'none' },\n underline: { textDecoration: 'underline' },\n lineThrough: { textDecoration: 'line-through' },\n}\n\nexport interface InlineTextProps {\n /** The DOM element rendered; defaults to `span`. */\n element?: InlineTextElement\n /** Palette token key from {@link TONE_COLOR}. */\n tone?: string\n /** Named weight key from {@link FONT_WEIGHT}. */\n weight?: string\n /** Decoration behaviour key from {@link DECORATION_SX}. */\n decoration?: string\n /**\n * Authored node styles, handed over by the renderer rather than typed\n * into an attribute. Declared because the merge below reads it —\n * undeclared, no typed caller could style a run (AGL-1323).\n */\n sx?: SxProps\n /**\n * Sanitized emphasis markup for the run, written by the inline editor's\n * rich mode (AGL-2557). `children` keeps the plain-text reading of it, and\n * is what every surface that cannot render markup falls back to.\n */\n html?: string\n /** The text of this run; edited inline on the canvas. */\n children?: ReactNode\n}\n\n/**\n * One run of text inside a sentence (AGL-1235).\n *\n * The gap this fills: `muiTypography` is `textEditable`, therefore a leaf —\n * `nodeAcceptsChildren` reports false, so no span can be nested inside it.\n * A statement whose argument lives in an emphasised phrase (\"Aglyn commerce\n * is **part of the platform**\") could not be authored at all; the whole line\n * was one flat colour.\n *\n * This is a leaf too, deliberately: the shape that renders correctly is a\n * block container holding SIBLING inline runs, not a nested span. Sibling\n * runs flow and wrap as a single paragraph, so the sentence breaks\n * naturally with the emphasis landing in the right place. Drop a Box as\n * `p`, then one of these per style change.\n */\nconst InlineText = forwardRef<HTMLElement, InlineTextProps>((props, ref) => {\n const { element, tone, weight, decoration, children, sx, html, ...rest } =\n props\n const component = INLINE_TEXT_ELEMENTS.includes(element as InlineTextElement)\n ? (element as InlineTextElement)\n : 'span'\n // Node styles ride the renderer-merged sx; recompose rather than spread\n // (the stack.ts/link-box.tsx pattern). Writing an `sx` literal after the\n // props spread would REPLACE the author's styles silently — the defect\n // class `aglyn/no-sx-after-spread` guards (AGL-1240/1284).\n const nodeSx = Array.isArray(sx) ? sx : sx ? [sx] : []\n // A cleared attribute persists as null, so every lookup below must miss\n // rather than throw; `Record[null]` is simply undefined.\n const color = TONE_COLOR[tone]\n const fontWeight = FONT_WEIGHT[weight]\n return (\n <MuiBox\n ref={ref}\n component={component}\n {...rest}\n // Order matters: the baseline first, then the declared attributes,\n // then the author's node styles last so the Styles panel always wins.\n sx={[\n { display: 'inline' },\n color ? { color } : {},\n fontWeight ? { fontWeight } : {},\n DECORATION_SX[decoration] ?? {},\n ...nodeSx,\n ]}\n >\n {authorHtmlLabel(html) ?? children}\n </MuiBox>\n )\n})\nInlineText.displayName = 'AglynInlineText'\n\nexport const schema: Aglyn.ComponentSchema<InlineTextProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Inline Text',\n description:\n 'One run of text inside a sentence — put several side by side in a ' +\n 'paragraph to emphasize a phrase without breaking the line.',\n category: Aglyn.ComponentCategory.TEXT,\n icon: { path: mdiFormatColorText.path, sx: { color: '#057822' } },\n flags: {\n // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n // The run IS its text: edited inline on the canvas, like Typography.\n textEditable: Aglyn.FEATURE_FLAG.ENABLED,\n richTextEditable: Aglyn.FEATURE_FLAG.ENABLED,\n },\n // Emphasis only (AGL-2557), for a different reason than the controls: this\n // run is not interactive, it is `display: inline`. Every element it may\n // render as is phrasing content — that is the guarantee INLINE_TEXT_ELEMENTS\n // exists to make — so a list inside one is a block in an inline box, which\n // the parser lifts straight back out of the enclosing paragraph. Links stay\n // with Screen Link, whose job is a resolved target rather than a typed href.\n richTextCommands: [Aglyn.RICH_TEXT_COMMANDS.EMPHASIS],\n attributes: [\n FIELD_TEXT_CONTENT,\n {\n name: 'element',\n label: 'Component',\n description:\n 'The DOM element this run renders as. `strong` and `em` carry ' +\n 'meaning for screen readers and search engines; `mark` marks a ' +\n 'highlighted phrase; `span` is purely visual.',\n component: Aglyn.FieldComponentType.SELECT,\n options: INLINE_TEXT_ELEMENTS.map((value) => ({ value, label: value })),\n },\n {\n name: 'tone',\n label: 'Color',\n description:\n \"Palette token for this run. Two-tone text is a muted sentence \" +\n 'with one run set to Primary (or Accent) — theme tokens, so it ' +\n 'still reads correctly in dark mode.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'primary', label: 'Text primary' },\n { value: 'secondary', label: 'Text muted' },\n { value: 'disabled', label: 'Text disabled' },\n { value: 'accent', label: 'Accent' },\n { value: 'accentAlt', label: 'Accent alternate' },\n { value: 'success', label: 'Success' },\n { value: 'warning', label: 'Warning' },\n { value: 'error', label: 'Error' },\n ],\n },\n {\n name: 'weight',\n label: 'Weight',\n description: 'Font weight for this run only.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'regular', label: 'Regular' },\n { value: 'medium', label: 'Medium' },\n { value: 'semibold', label: 'Semi bold' },\n { value: 'bold', label: 'Bold' },\n ],\n },\n {\n name: 'decoration',\n label: 'Underline / strike',\n description:\n 'Inherit follows the surrounding text, including a link\\'s ' +\n 'underline — an underline PROPAGATES down and cannot be switched ' +\n 'off from inside. None does switch it off, at the cost of the run ' +\n 'no longer breaking across lines, so keep it to a short phrase.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'none', label: 'None (does not wrap)' },\n { value: 'underline', label: 'Underline' },\n { value: 'lineThrough', label: 'Strikethrough' },\n ],\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Inline Text',\n pluginId: BUNDLE_ID,\n description: 'One run of text inside a sentence',\n category: Aglyn.ComponentCategory.TEXT,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { element: 'span', children: 'Inline text' },\n },\n },\n {\n $id: generatePresetId(ID, 'emphasis'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Emphasized Text',\n pluginId: BUNDLE_ID,\n description: 'A phrase picked out of a muted sentence',\n category: Aglyn.ComponentCategory.TEXT,\n icon: { path: mdiFormatColorHighlight.path, sx: { color: '#057822' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'strong',\n tone: 'primary',\n weight: 'bold',\n children: 'the emphasized phrase',\n },\n },\n },\n {\n // The whole shape in one drop (AGL-1235): the reason the emphasis was\n // never authored is that assembling it by hand meant a container, three\n // runs and a colour on each. This is that assembly, ready to retype.\n $id: generatePresetId(ID, 'statement'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Two-tone Statement',\n pluginId: BUNDLE_ID,\n description: 'A muted sentence with one phrase emphasized',\n category: Aglyn.ComponentCategory.TEXT,\n icon: { path: mdiFormatColorHighlight.path, sx: { color: '#057822' } },\n data: {\n $id: null,\n // A real `<p>`, not a div: the runs are phrasing content, so the\n // paragraph is the honest container and screen readers get a\n // sentence rather than three unrelated fragments.\n componentId: 'muiBox',\n pluginId: BUNDLE_ID,\n props: { component: 'p' },\n // Node-level sx (AGL-1346) — the record the Styles panel edits.\n sx: { marginTop: 0, marginRight: 0, marginBottom: 0, marginLeft: 0 },\n nodes: [\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'span',\n tone: 'secondary',\n children: 'Everything you build is ',\n },\n },\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'strong',\n tone: 'primary',\n weight: 'bold',\n children: 'part of the platform',\n },\n },\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'span',\n tone: 'secondary',\n children: ', not bolted onto it.',\n },\n },\n ],\n },\n },\n]\n\nexport default InlineText\n"],"names":["Aglyn","mdiFormatColorHighlight","mdiFormatColorText","MuiBox","forwardRef","BUNDLE_ID","FIELD_TEXT_CONTENT","authorHtmlLabel","generatePresetId","ID","INLINE_TEXT_ELEMENTS","TONE_COLOR","inherit","undefined","primary","secondary","disabled","accent","accentAlt","success","warning","error","FONT_WEIGHT","regular","medium","semibold","bold","DECORATION_SX","none","display","textDecoration","underline","lineThrough","InlineText","props","ref","element","tone","weight","decoration","children","sx","html","rest","component","includes","nodeSx","Array","isArray","color","fontWeight","displayName","schema","$id","pluginId","description","category","ComponentCategory","TEXT","icon","path","flags","lazyHydration","FEATURE_FLAG","ENABLED","textEditable","richTextEditable","richTextCommands","RICH_TEXT_COMMANDS","EMPHASIS","attributes","name","label","FieldComponentType","SELECT","options","map","value","presets","type","NodeType","PRESET","data","componentId","marginTop","marginRight","marginBottom","marginLeft","nodes"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/inline-text.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 { mdiFormatColorHighlight, mdiFormatColorText } from '@aglyn/shared-data-mdi'\nimport MuiBox from '@mui/material/Box'\nimport type { SxProps } from '@mui/material/styles'\nimport { forwardRef, type ReactNode } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { FIELD_TEXT_CONTENT } from '../constants/field-presets'\nimport { authorHtmlLabel } from '../utils/author-html-label'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiInlineText'\n\n/**\n * Inline elements the run may render as. An allow-list rather than a\n * free-text field, for the same reason Box's is (AGL-1201): `element` is\n * persisted and rendered verbatim into every visitor's page, so a typed\n * value would let an author put `script`/`iframe` there.\n *\n * All five are phrasing content, so a run is always legal inside a\n * paragraph — which is the whole point of the element.\n */\nexport const INLINE_TEXT_ELEMENTS = [\n 'span',\n 'strong',\n 'em',\n 'mark',\n 'small',\n] as const\nexport type InlineTextElement = (typeof INLINE_TEXT_ELEMENTS)[number]\n\n/**\n * Theme palette paths, never raw hexes: the design's `text/muted` and\n * `text/primary` tokens ARE `text.secondary` / `text.primary`, and a\n * hardcoded `#757575` would ignore the site's theme (and dark mode).\n *\n * Every value is a real sentinel — an option value of `''` is stripped\n * before save and the pick silently reverts on reload (AGL-1191), so\n * \"inherit\" has to be spelled out rather than left blank.\n */\nconst TONE_COLOR: Record<string, string> = {\n inherit: undefined,\n primary: 'text.primary',\n secondary: 'text.secondary',\n disabled: 'text.disabled',\n accent: 'primary.main',\n accentAlt: 'secondary.main',\n success: 'success.main',\n warning: 'warning.main',\n error: 'error.main',\n}\n\n/** Named weights so the field is a pick, not a number to remember. */\nconst FONT_WEIGHT: Record<string, number> = {\n inherit: undefined,\n regular: 400,\n medium: 500,\n semibold: 600,\n bold: 700,\n}\n\n/**\n * `text-decoration` PROPAGATES — it is not inherited. An ancestor's\n * underline (a Screen Link, a struck-through block) is painted straight\n * across every in-flow inline descendant, and `text-decoration: none` on\n * the descendant CANNOT remove it. Only an element that is not an in-flow\n * non-atomic inline box escapes the propagation, which is why \"None\" also\n * switches the run to `inline-block`: an atomic inline box is not painted\n * through.\n *\n * That costs line-breaking — an inline-block will not break across lines —\n * so it is opt-in rather than the default, and the field says so. The\n * default, `inherit`, is a plain `display: inline` run that flows and wraps\n * with the rest of the sentence.\n */\nconst DECORATION_SX: Record<string, Record<string, string>> = {\n inherit: {},\n none: { display: 'inline-block', textDecoration: 'none' },\n underline: { textDecoration: 'underline' },\n lineThrough: { textDecoration: 'line-through' },\n}\n\nexport interface InlineTextProps {\n /** The DOM element rendered; defaults to `span`. */\n element?: InlineTextElement\n /** Palette token key from {@link TONE_COLOR}. */\n tone?: string\n /** Named weight key from {@link FONT_WEIGHT}. */\n weight?: string\n /** Decoration behaviour key from {@link DECORATION_SX}. */\n decoration?: string\n /**\n * Authored node styles, handed over by the renderer rather than typed\n * into an attribute. Declared because the merge below reads it —\n * undeclared, no typed caller could style a run (AGL-1323).\n */\n sx?: SxProps\n /**\n * Sanitized emphasis markup for the run, written by the inline editor's\n * rich mode (AGL-2557). `children` keeps the plain-text reading of it, and\n * is what every surface that cannot render markup falls back to.\n */\n html?: string\n /** The text of this run; edited inline on the canvas. */\n children?: ReactNode\n}\n\n/**\n * One run of text inside a sentence (AGL-1235).\n *\n * The gap this fills: a statement whose argument lives in an emphasised\n * phrase (\"Aglyn commerce is **part of the platform**\") — a run of its own\n * colour or weight inside one line. A Typography can hold elements too\n * (AGL-3672), but only after its own text, so it cannot put the emphasis\n * mid-sentence.\n *\n * This is a leaf too, deliberately: the shape that renders correctly is a\n * block container holding SIBLING inline runs, not a nested span. Sibling\n * runs flow and wrap as a single paragraph, so the sentence breaks\n * naturally with the emphasis landing in the right place. Drop a Box as\n * `p`, then one of these per style change.\n */\nconst InlineText = forwardRef<HTMLElement, InlineTextProps>((props, ref) => {\n const { element, tone, weight, decoration, children, sx, html, ...rest } =\n props\n const component = INLINE_TEXT_ELEMENTS.includes(element as InlineTextElement)\n ? (element as InlineTextElement)\n : 'span'\n // Node styles ride the renderer-merged sx; recompose rather than spread\n // (the stack.ts/link-box.tsx pattern). Writing an `sx` literal after the\n // props spread would REPLACE the author's styles silently — the defect\n // class `aglyn/no-sx-after-spread` guards (AGL-1240/1284).\n const nodeSx = Array.isArray(sx) ? sx : sx ? [sx] : []\n // A cleared attribute persists as null, so every lookup below must miss\n // rather than throw; `Record[null]` is simply undefined.\n const color = TONE_COLOR[tone]\n const fontWeight = FONT_WEIGHT[weight]\n return (\n <MuiBox\n ref={ref}\n component={component}\n {...rest}\n // Order matters: the baseline first, then the declared attributes,\n // then the author's node styles last so the Styles panel always wins.\n sx={[\n { display: 'inline' },\n color ? { color } : {},\n fontWeight ? { fontWeight } : {},\n DECORATION_SX[decoration] ?? {},\n ...nodeSx,\n ]}\n >\n {authorHtmlLabel(html) ?? children}\n </MuiBox>\n )\n})\nInlineText.displayName = 'AglynInlineText'\n\nexport const schema: Aglyn.ComponentSchema<InlineTextProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Inline Text',\n description:\n 'One run of text inside a sentence — put several side by side in a ' +\n 'paragraph to emphasize a phrase without breaking the line.',\n category: Aglyn.ComponentCategory.TEXT,\n icon: { path: mdiFormatColorText.path, sx: { color: '#057822' } },\n flags: {\n // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n // The run IS its text: edited inline on the canvas, like Typography.\n textEditable: Aglyn.FEATURE_FLAG.ENABLED,\n richTextEditable: Aglyn.FEATURE_FLAG.ENABLED,\n },\n // Emphasis only (AGL-2557), for a different reason than the controls: this\n // run is not interactive, it is `display: inline`. Every element it may\n // render as is phrasing content — that is the guarantee INLINE_TEXT_ELEMENTS\n // exists to make — so a list inside one is a block in an inline box, which\n // the parser lifts straight back out of the enclosing paragraph. Links stay\n // with Screen Link, whose job is a resolved target rather than a typed href.\n richTextCommands: [Aglyn.RICH_TEXT_COMMANDS.EMPHASIS],\n attributes: [\n FIELD_TEXT_CONTENT,\n {\n name: 'element',\n label: 'Component',\n description:\n 'The DOM element this run renders as. `strong` and `em` carry ' +\n 'meaning for screen readers and search engines; `mark` marks a ' +\n 'highlighted phrase; `span` is purely visual.',\n component: Aglyn.FieldComponentType.SELECT,\n options: INLINE_TEXT_ELEMENTS.map((value) => ({ value, label: value })),\n },\n {\n name: 'tone',\n label: 'Color',\n description:\n \"Palette token for this run. Two-tone text is a muted sentence \" +\n 'with one run set to Primary (or Accent) — theme tokens, so it ' +\n 'still reads correctly in dark mode.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'primary', label: 'Text primary' },\n { value: 'secondary', label: 'Text muted' },\n { value: 'disabled', label: 'Text disabled' },\n { value: 'accent', label: 'Accent' },\n { value: 'accentAlt', label: 'Accent alternate' },\n { value: 'success', label: 'Success' },\n { value: 'warning', label: 'Warning' },\n { value: 'error', label: 'Error' },\n ],\n },\n {\n name: 'weight',\n label: 'Weight',\n description: 'Font weight for this run only.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'regular', label: 'Regular' },\n { value: 'medium', label: 'Medium' },\n { value: 'semibold', label: 'Semi bold' },\n { value: 'bold', label: 'Bold' },\n ],\n },\n {\n name: 'decoration',\n label: 'Underline / strike',\n description:\n 'Inherit follows the surrounding text, including a link\\'s ' +\n 'underline — an underline PROPAGATES down and cannot be switched ' +\n 'off from inside. None does switch it off, at the cost of the run ' +\n 'no longer breaking across lines, so keep it to a short phrase.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'none', label: 'None (does not wrap)' },\n { value: 'underline', label: 'Underline' },\n { value: 'lineThrough', label: 'Strikethrough' },\n ],\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Inline Text',\n pluginId: BUNDLE_ID,\n description: 'One run of text inside a sentence',\n category: Aglyn.ComponentCategory.TEXT,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { element: 'span', children: 'Inline text' },\n },\n },\n {\n $id: generatePresetId(ID, 'emphasis'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Emphasized Text',\n pluginId: BUNDLE_ID,\n description: 'A phrase picked out of a muted sentence',\n category: Aglyn.ComponentCategory.TEXT,\n icon: { path: mdiFormatColorHighlight.path, sx: { color: '#057822' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'strong',\n tone: 'primary',\n weight: 'bold',\n children: 'the emphasized phrase',\n },\n },\n },\n {\n // The whole shape in one drop (AGL-1235): the reason the emphasis was\n // never authored is that assembling it by hand meant a container, three\n // runs and a colour on each. This is that assembly, ready to retype.\n $id: generatePresetId(ID, 'statement'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Two-tone Statement',\n pluginId: BUNDLE_ID,\n description: 'A muted sentence with one phrase emphasized',\n category: Aglyn.ComponentCategory.TEXT,\n icon: { path: mdiFormatColorHighlight.path, sx: { color: '#057822' } },\n data: {\n $id: null,\n // A real `<p>`, not a div: the runs are phrasing content, so the\n // paragraph is the honest container and screen readers get a\n // sentence rather than three unrelated fragments.\n componentId: 'muiBox',\n pluginId: BUNDLE_ID,\n props: { component: 'p' },\n // Node-level sx (AGL-1346) — the record the Styles panel edits.\n sx: { marginTop: 0, marginRight: 0, marginBottom: 0, marginLeft: 0 },\n nodes: [\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'span',\n tone: 'secondary',\n children: 'Everything you build is ',\n },\n },\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'strong',\n tone: 'primary',\n weight: 'bold',\n children: 'part of the platform',\n },\n },\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'span',\n tone: 'secondary',\n children: ', not bolted onto it.',\n },\n },\n ],\n },\n },\n]\n\nexport default InlineText\n"],"names":["Aglyn","mdiFormatColorHighlight","mdiFormatColorText","MuiBox","forwardRef","BUNDLE_ID","FIELD_TEXT_CONTENT","authorHtmlLabel","generatePresetId","ID","INLINE_TEXT_ELEMENTS","TONE_COLOR","inherit","undefined","primary","secondary","disabled","accent","accentAlt","success","warning","error","FONT_WEIGHT","regular","medium","semibold","bold","DECORATION_SX","none","display","textDecoration","underline","lineThrough","InlineText","props","ref","element","tone","weight","decoration","children","sx","html","rest","component","includes","nodeSx","Array","isArray","color","fontWeight","displayName","schema","$id","pluginId","description","category","ComponentCategory","TEXT","icon","path","flags","lazyHydration","FEATURE_FLAG","ENABLED","textEditable","richTextEditable","richTextCommands","RICH_TEXT_COMMANDS","EMPHASIS","attributes","name","label","FieldComponentType","SELECT","options","map","value","presets","type","NodeType","PRESET","data","componentId","marginTop","marginRight","marginBottom","marginLeft","nodes"],"mappings":"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"}
|
|
@@ -25,6 +25,13 @@ import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
|
25
25
|
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
26
26
|
// Component ids are persisted in layout documents; never rename.
|
|
27
27
|
export const ID = 'layoutSlot';
|
|
28
|
+
// The component and its preset show the same drawer glyph.
|
|
29
|
+
const SLOT_ICON = {
|
|
30
|
+
path: mdiPageLayoutBody.path,
|
|
31
|
+
sx: {
|
|
32
|
+
color: '#9c27b0'
|
|
33
|
+
}
|
|
34
|
+
};
|
|
28
35
|
/**
|
|
29
36
|
* Elements the slot may render as (AGL-2486).
|
|
30
37
|
*
|
|
@@ -130,12 +137,7 @@ export const schema = {
|
|
|
130
137
|
displayName: 'Layout Slot',
|
|
131
138
|
description: "Marks where each bound page's content renders inside this layout. One per layout.",
|
|
132
139
|
category: Aglyn.ComponentCategory.LAYOUT,
|
|
133
|
-
icon:
|
|
134
|
-
path: mdiPageLayoutBody.path,
|
|
135
|
-
sx: {
|
|
136
|
-
color: '#9c27b0'
|
|
137
|
-
}
|
|
138
|
-
},
|
|
140
|
+
icon: SLOT_ICON,
|
|
139
141
|
// The slot's children come from screen composition, never from the canvas.
|
|
140
142
|
restrictChildren: [
|
|
141
143
|
Aglyn.LinealDirectiveFlag.LIMIT_TO,
|
|
@@ -176,12 +178,7 @@ export const presets = [
|
|
|
176
178
|
$id: generatePresetId(ID),
|
|
177
179
|
type: Aglyn.NodeType.PRESET,
|
|
178
180
|
displayName: 'Layout Slot',
|
|
179
|
-
icon:
|
|
180
|
-
path: mdiPageLayoutBody.path,
|
|
181
|
-
sx: {
|
|
182
|
-
color: '#9c27b0'
|
|
183
|
-
}
|
|
184
|
-
},
|
|
181
|
+
icon: SLOT_ICON,
|
|
185
182
|
category: Aglyn.ComponentCategory.LAYOUT,
|
|
186
183
|
data: {
|
|
187
184
|
$id: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/layout-slot.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, { type BoxProps } from '@mui/material/Box'\nimport { alpha } from '@mui/material/styles'\nimport { Children, forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in layout documents; never rename.\nexport const ID: Aglyn.ComponentId = 'layoutSlot'\n\n/**\n * Elements the slot may render as (AGL-2486).\n *\n * `main` is here, and is the DEFAULT composition assigns, because the slot is\n * by construction the page content between the layout's chrome — which is the\n * definition of the landmark. It is the one place on the platform that may\n * choose it: `SECTION_ELEMENTS` and `ALLOWED_AUTHOR_HTML_ELEMENTS` both drop\n * `main` so a document can never carry two, and `stampDocumentLandmark`\n * decides which single node gets it.\n */\nexport const LAYOUT_SLOT_ELEMENTS = [\n 'main',\n 'div',\n 'section',\n 'article',\n] as const\nexport type LayoutSlotElement = (typeof LAYOUT_SLOT_ELEMENTS)[number]\n\nexport interface LayoutSlotProps extends Omit<BoxProps, 'component'> {\n /**\n * The DOM element the slot renders as. Left unset, composition fills in\n * `main` — see {@link LAYOUT_SLOT_ELEMENTS}. Unknown values degrade to\n * `div` rather than reaching the DOM as an invented tag.\n *\n * Named `component` like Box's and Typography's, not `element` like\n * Section's: the attribute means the same thing everywhere it appears.\n * Narrower than the `ElementType` Box accepts — a canvas attribute is a\n * persisted STRING, and an allow-list is what keeps `script` out of it —\n * so `BoxProps`' own `component` is omitted rather than widened.\n */\n component?: LayoutSlotElement | string\n /**\n * Editor-only caption under the slot marker. Layouts render different\n * kinds of content — a doc body, a narrow article measure, a full page —\n * and naming it is the difference between four identical dashed boxes and\n * a layout you can read at a glance.\n */\n caption?: string\n}\n\n/**\n * The slot marker is EDITOR CHROME, so it holds the brand accent literally\n * rather than reading `secondary` from the theme: the canvas renders under\n * the host's palette, so a token would repaint the editor's own furniture\n * whenever a subscriber restyles their site — and it already rendered pink\n * instead of the design's blue.\n */\nconst SLOT_ACCENT = '#00B0FF'\n/** Shown when a layout hasn't named its slot. */\nexport const DEFAULT_SLOT_CAPTION = 'Page content renders here'\n\n/**\n * Content outlet for shared layouts: marks where a bound screen's nodes are\n * grafted into the layout tree at composition time. With children (composed\n * or previewed) it is a plain passthrough region; empty, it renders a\n * dashed placeholder so layout designers can see the slot on the canvas.\n *\n * The placeholder is editor chrome, so it is drawn on editing surfaces only.\n * A published screen with no content of its own still composes an empty\n * slot, and that renders as the plain region.\n */\nconst LayoutSlot = forwardRef<HTMLDivElement, LayoutSlotProps>(\n (props, ref) => {\n const { children, sx, caption, component, ...rest } = props\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n const hasChildren = Children.count(children) > 0\n const element = (LAYOUT_SLOT_ELEMENTS as readonly string[]).includes(\n String(component ?? ''),\n )\n ? (component as LayoutSlotElement)\n : 'div'\n\n if (hasChildren || !suppressNavigation) {\n return (\n <Box\n ref={ref}\n component={element}\n data-aglyn-layout-slot=\"\"\n sx={sx}\n {...rest}\n >\n {children}\n </Box>\n )\n }\n\n return (\n <Box\n ref={ref}\n data-aglyn-layout-slot=\"\"\n sx={[\n {\n minHeight: 160,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 0.5,\n borderWidth: 2,\n borderStyle: 'dashed',\n // The slot is not an ordinary dashed container — it is the one\n // region a layout does NOT own. Brand blue on a faint tint says\n // that at a glance, and matches the design's slot convention.\n borderColor: SLOT_ACCENT,\n backgroundColor: alpha(SLOT_ACCENT, 0.06),\n borderRadius: 1,\n color: 'text.secondary',\n fontFamily: 'sans-serif',\n fontSize: 13,\n textAlign: 'center',\n p: 2,\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n {...rest}\n >\n <Box\n component=\"span\"\n sx={{ color: SLOT_ACCENT, fontWeight: 700 }}\n >\n {'◇ layout-slot'}\n </Box>\n <Box component=\"span\">{caption || DEFAULT_SLOT_CAPTION}</Box>\n </Box>\n )\n },\n)\nLayoutSlot.displayName = 'LayoutSlot'\n\nexport const schema: Aglyn.ComponentSchema<LayoutSlotProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Layout Slot',\n description:\n \"Marks where each bound page's content renders inside this layout. One per layout.\",\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: {\n path: mdiPageLayoutBody.path,\n sx: { color: '#9c27b0' },\n },\n // The slot's children come from screen composition, never from the canvas.\n restrictChildren: [Aglyn.LinealDirectiveFlag.LIMIT_TO, { components: [] }],\n flags: {\n // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n // Not `childrenInRoot` — it draws its own placeholder when it has\n // no children, which is what a held root looks like.\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n cloning: Aglyn.FEATURE_FLAG.DISABLED,\n dropping: Aglyn.FEATURE_FLAG.DISABLED,\n },\n attributes: [\n {\n name: 'caption',\n label: 'Slot caption',\n description:\n 'Editor-only label for what renders here — e.g. \"Doc body renders ' +\n 'here\". Never shown on the published site.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n placeholder: DEFAULT_SLOT_CAPTION,\n },\n {\n name: 'component',\n label: 'Component',\n description:\n 'The DOM element the page content renders inside. Blank is ' +\n '\"main\" — the page-content landmark assistive tech skips the ' +\n 'chrome with. Choose another only if this layout’s slot is not the ' +\n 'page’s main content.',\n component: Aglyn.FieldComponentType.SELECT,\n options: LAYOUT_SLOT_ELEMENTS.map((value) => ({\n value,\n label: value,\n })),\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Layout Slot',\n icon: {\n path: mdiPageLayoutBody.path,\n sx: { color: '#9c27b0' },\n },\n category: Aglyn.ComponentCategory.LAYOUT,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default LayoutSlot\n"],"names":["Aglyn","mdiPageLayoutBody","Box","alpha","Children","forwardRef","useContext","BUNDLE_ID","generatePresetId","ID","LAYOUT_SLOT_ELEMENTS","SLOT_ACCENT","DEFAULT_SLOT_CAPTION","LayoutSlot","props","ref","children","sx","caption","component","rest","suppressNavigation","ScreenLinkContext","hasChildren","count","element","includes","String","data-aglyn-layout-slot","minHeight","display","flexDirection","alignItems","justifyContent","gap","borderWidth","borderStyle","borderColor","backgroundColor","borderRadius","color","fontFamily","fontSize","textAlign","p","Array","isArray","fontWeight","displayName","schema","$id","pluginId","description","category","ComponentCategory","LAYOUT","icon","path","restrictChildren","LinealDirectiveFlag","LIMIT_TO","components","flags","lazyHydration","FEATURE_FLAG","ENABLED","cloning","DISABLED","dropping","attributes","name","label","FieldComponentType","TEXT_FIELD","placeholder","SELECT","options","map","value","presets","type","NodeType","PRESET","data","componentId"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/layout-slot.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, { type BoxProps } from '@mui/material/Box'\nimport { alpha } from '@mui/material/styles'\nimport { Children, forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in layout documents; never rename.\nexport const ID: Aglyn.ComponentId = 'layoutSlot'\n\n// The component and its preset show the same drawer glyph.\nconst SLOT_ICON = { path: mdiPageLayoutBody.path, sx: { color: '#9c27b0' } }\n\n/**\n * Elements the slot may render as (AGL-2486).\n *\n * `main` is here, and is the DEFAULT composition assigns, because the slot is\n * by construction the page content between the layout's chrome — which is the\n * definition of the landmark. It is the one place on the platform that may\n * choose it: `SECTION_ELEMENTS` and `ALLOWED_AUTHOR_HTML_ELEMENTS` both drop\n * `main` so a document can never carry two, and `stampDocumentLandmark`\n * decides which single node gets it.\n */\nexport const LAYOUT_SLOT_ELEMENTS = [\n 'main',\n 'div',\n 'section',\n 'article',\n] as const\nexport type LayoutSlotElement = (typeof LAYOUT_SLOT_ELEMENTS)[number]\n\nexport interface LayoutSlotProps extends Omit<BoxProps, 'component'> {\n /**\n * The DOM element the slot renders as. Left unset, composition fills in\n * `main` — see {@link LAYOUT_SLOT_ELEMENTS}. Unknown values degrade to\n * `div` rather than reaching the DOM as an invented tag.\n *\n * Named `component` like Box's and Typography's, not `element` like\n * Section's: the attribute means the same thing everywhere it appears.\n * Narrower than the `ElementType` Box accepts — a canvas attribute is a\n * persisted STRING, and an allow-list is what keeps `script` out of it —\n * so `BoxProps`' own `component` is omitted rather than widened.\n */\n component?: LayoutSlotElement | string\n /**\n * Editor-only caption under the slot marker. Layouts render different\n * kinds of content — a doc body, a narrow article measure, a full page —\n * and naming it is the difference between four identical dashed boxes and\n * a layout you can read at a glance.\n */\n caption?: string\n}\n\n/**\n * The slot marker is EDITOR CHROME, so it holds the brand accent literally\n * rather than reading `secondary` from the theme: the canvas renders under\n * the host's palette, so a token would repaint the editor's own furniture\n * whenever a subscriber restyles their site — and it already rendered pink\n * instead of the design's blue.\n */\nconst SLOT_ACCENT = '#00B0FF'\n/** Shown when a layout hasn't named its slot. */\nexport const DEFAULT_SLOT_CAPTION = 'Page content renders here'\n\n/**\n * Content outlet for shared layouts: marks where a bound screen's nodes are\n * grafted into the layout tree at composition time. With children (composed\n * or previewed) it is a plain passthrough region; empty, it renders a\n * dashed placeholder so layout designers can see the slot on the canvas.\n *\n * The placeholder is editor chrome, so it is drawn on editing surfaces only.\n * A published screen with no content of its own still composes an empty\n * slot, and that renders as the plain region.\n */\nconst LayoutSlot = forwardRef<HTMLDivElement, LayoutSlotProps>(\n (props, ref) => {\n const { children, sx, caption, component, ...rest } = props\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n const hasChildren = Children.count(children) > 0\n const element = (LAYOUT_SLOT_ELEMENTS as readonly string[]).includes(\n String(component ?? ''),\n )\n ? (component as LayoutSlotElement)\n : 'div'\n\n if (hasChildren || !suppressNavigation) {\n return (\n <Box\n ref={ref}\n component={element}\n data-aglyn-layout-slot=\"\"\n sx={sx}\n {...rest}\n >\n {children}\n </Box>\n )\n }\n\n return (\n <Box\n ref={ref}\n data-aglyn-layout-slot=\"\"\n sx={[\n {\n minHeight: 160,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 0.5,\n borderWidth: 2,\n borderStyle: 'dashed',\n // The slot is not an ordinary dashed container — it is the one\n // region a layout does NOT own. Brand blue on a faint tint says\n // that at a glance, and matches the design's slot convention.\n borderColor: SLOT_ACCENT,\n backgroundColor: alpha(SLOT_ACCENT, 0.06),\n borderRadius: 1,\n color: 'text.secondary',\n fontFamily: 'sans-serif',\n fontSize: 13,\n textAlign: 'center',\n p: 2,\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n {...rest}\n >\n <Box\n component=\"span\"\n sx={{ color: SLOT_ACCENT, fontWeight: 700 }}\n >\n {'◇ layout-slot'}\n </Box>\n <Box component=\"span\">{caption || DEFAULT_SLOT_CAPTION}</Box>\n </Box>\n )\n },\n)\nLayoutSlot.displayName = 'LayoutSlot'\n\nexport const schema: Aglyn.ComponentSchema<LayoutSlotProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Layout Slot',\n description:\n \"Marks where each bound page's content renders inside this layout. One per layout.\",\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: SLOT_ICON,\n // The slot's children come from screen composition, never from the canvas.\n restrictChildren: [Aglyn.LinealDirectiveFlag.LIMIT_TO, { components: [] }],\n flags: {\n // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n // Not `childrenInRoot` — it draws its own placeholder when it has\n // no children, which is what a held root looks like.\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n cloning: Aglyn.FEATURE_FLAG.DISABLED,\n dropping: Aglyn.FEATURE_FLAG.DISABLED,\n },\n attributes: [\n {\n name: 'caption',\n label: 'Slot caption',\n description:\n 'Editor-only label for what renders here — e.g. \"Doc body renders ' +\n 'here\". Never shown on the published site.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n placeholder: DEFAULT_SLOT_CAPTION,\n },\n {\n name: 'component',\n label: 'Component',\n description:\n 'The DOM element the page content renders inside. Blank is ' +\n '\"main\" — the page-content landmark assistive tech skips the ' +\n 'chrome with. Choose another only if this layout’s slot is not the ' +\n 'page’s main content.',\n component: Aglyn.FieldComponentType.SELECT,\n options: LAYOUT_SLOT_ELEMENTS.map((value) => ({\n value,\n label: value,\n })),\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Layout Slot',\n icon: SLOT_ICON,\n category: Aglyn.ComponentCategory.LAYOUT,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default LayoutSlot\n"],"names":["Aglyn","mdiPageLayoutBody","Box","alpha","Children","forwardRef","useContext","BUNDLE_ID","generatePresetId","ID","SLOT_ICON","path","sx","color","LAYOUT_SLOT_ELEMENTS","SLOT_ACCENT","DEFAULT_SLOT_CAPTION","LayoutSlot","props","ref","children","caption","component","rest","suppressNavigation","ScreenLinkContext","hasChildren","count","element","includes","String","data-aglyn-layout-slot","minHeight","display","flexDirection","alignItems","justifyContent","gap","borderWidth","borderStyle","borderColor","backgroundColor","borderRadius","fontFamily","fontSize","textAlign","p","Array","isArray","fontWeight","displayName","schema","$id","pluginId","description","category","ComponentCategory","LAYOUT","icon","restrictChildren","LinealDirectiveFlag","LIMIT_TO","components","flags","lazyHydration","FEATURE_FLAG","ENABLED","cloning","DISABLED","dropping","attributes","name","label","FieldComponentType","TEXT_FIELD","placeholder","SELECT","options","map","value","presets","type","NodeType","PRESET","data","componentId"],"mappings":"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"}
|
|
@@ -116,7 +116,9 @@ const Stack = forwardRef(// repeatDataset/repeatLimit are compose-time attribute
|
|
|
116
116
|
],
|
|
117
117
|
// The stored value is a style NAME; MUI wants a node (AGL-2486).
|
|
118
118
|
divider: buildDivider(divider, props.direction)
|
|
119
|
-
}, applySemanticElement(dropClearedProps(props)), {
|
|
119
|
+
}, applySemanticElement(dropClearedProps(props)), typeof props.spacing === 'string' && props.spacing.trim() && Number.isFinite(Number(props.spacing)) ? {
|
|
120
|
+
spacing: Number(props.spacing)
|
|
121
|
+
} : {}, {
|
|
120
122
|
// After the spread, so the element picker cannot carry a `useFlexGap`
|
|
121
123
|
// past it. `spacing` reaches children as `margin-left` unless this is
|
|
122
124
|
// on, and those margins assume flex: on a grid they land INSIDE the
|
|
@@ -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 { 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 // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n flags: { lazyHydration: Aglyn.FEATURE_FLAG.ENABLED },\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","flags","lazyHydration","FEATURE_FLAG","ENABLED","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 // A spacing stored as text — every AI-built page stores its props as\n // text — is still a step on the spacing scale: MUI reads \"2\" as a CSS\n // length and spaces nothing (AGL-3660).\n ...(typeof props.spacing === 'string' && props.spacing.trim() && Number.isFinite(Number(props.spacing))\n ? { spacing: Number(props.spacing) }\n : {}),\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 // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n flags: { lazyHydration: Aglyn.FEATURE_FLAG.ENABLED },\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","spacing","trim","Number","isFinite","ID","schema","$id","pluginId","displayName","flags","lazyHydration","FEATURE_FLAG","ENABLED","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,6 +1,6 @@
|
|
|
1
1
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
2
|
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
3
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
4
|
/**
|
|
5
5
|
* @license
|
|
6
6
|
* Copyright 2026 Aglyn LLC
|
|
@@ -18,8 +18,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
18
18
|
* limitations under the License.
|
|
19
19
|
*/ import * as Aglyn from "@aglyn/aglyn";
|
|
20
20
|
import { mdiAlphabetical, mdiFormatHeader1, mdiFormatHeader2, mdiFormatHeader3, mdiFormatHeader4, mdiFormatHeader5, mdiFormatHeader6, mdiFormatText } from "@aglyn/shared-data-mdi";
|
|
21
|
+
import { AglynText } from "@aglyn/shared-ui-jsx";
|
|
21
22
|
import Typography from "@mui/material/Typography";
|
|
22
|
-
import { forwardRef } from "react";
|
|
23
|
+
import { Children, createContext, forwardRef, isValidElement, useContext } from "react";
|
|
23
24
|
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
24
25
|
import { FIELD_TEXT_CONTENT } from "../constants/field-presets.js";
|
|
25
26
|
import { dropClearedProps } from "../utils/drop-cleared-props.js";
|
|
@@ -165,7 +166,14 @@ export const schema = {
|
|
|
165
166
|
// Static: may sit in a subtree that keeps its server HTML (AGL-3581).
|
|
166
167
|
lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,
|
|
167
168
|
textEditable: Aglyn.FEATURE_FLAG.ENABLED,
|
|
168
|
-
richTextEditable: Aglyn.FEATURE_FLAG.ENABLED
|
|
169
|
+
richTextEditable: Aglyn.FEATURE_FLAG.ENABLED,
|
|
170
|
+
// Holds other elements after its own text (AGL-3672). The text keeps its
|
|
171
|
+
// own `<aglyn-text>`, which is all the in-place editor rewrites, so an
|
|
172
|
+
// edit never touches the elements beside it.
|
|
173
|
+
dropping: Aglyn.FEATURE_FLAG.ENABLED,
|
|
174
|
+
// One React child per child node, so the component can tell its
|
|
175
|
+
// elements from its text — see `AglynTypography`.
|
|
176
|
+
positionalChildren: Aglyn.FEATURE_FLAG.ENABLED
|
|
169
177
|
},
|
|
170
178
|
attributes: [
|
|
171
179
|
FIELD_TEXT_CONTENT,
|
|
@@ -390,6 +398,27 @@ export const presets = [
|
|
|
390
398
|
VARIANT_ELEMENT[(_rest_variant = rest.variant) != null ? _rest_variant : 'body1']) != null ? _ref : 'span';
|
|
391
399
|
return Aglyn.authorHtmlBreaksContainer(sanitized, element) ? 'div' : undefined;
|
|
392
400
|
}
|
|
401
|
+
/** The elements a Typography may not sit inside of another as. */ const BLOCK_TEXT_ELEMENTS = new Set([
|
|
402
|
+
'p',
|
|
403
|
+
'h1',
|
|
404
|
+
'h2',
|
|
405
|
+
'h3',
|
|
406
|
+
'h4',
|
|
407
|
+
'h5',
|
|
408
|
+
'h6'
|
|
409
|
+
]);
|
|
410
|
+
/**
|
|
411
|
+
* True inside the child elements of a Typography. A paragraph or heading
|
|
412
|
+
* nested in another is not one the parser keeps: `<p>` closes on any `<p>`
|
|
413
|
+
* start tag and a heading on any heading, so the inner element lands beside
|
|
414
|
+
* the outer one and React hydrates against a page it did not describe. A
|
|
415
|
+
* nested Typography renders as a `<span>` instead — it continues the
|
|
416
|
+
* sentence it was dropped into, which is what nesting text means.
|
|
417
|
+
*/ const TypographyNestingContext = /*#__PURE__*/ createContext(false);
|
|
418
|
+
/** A child NODE, as the renderer hands it over: an element carrying `node`. */ function isChildNode(child) {
|
|
419
|
+
var _child_props;
|
|
420
|
+
return /*#__PURE__*/ isValidElement(child) && ((_child_props = child.props) == null ? void 0 : _child_props.node) != null;
|
|
421
|
+
}
|
|
393
422
|
const AglynTypography = /*#__PURE__*/ forwardRef(function AglynTypography(props, ref) {
|
|
394
423
|
const { html, children } = props, spread = _object_without_properties_loose(props, [
|
|
395
424
|
"html",
|
|
@@ -398,6 +427,9 @@ const AglynTypography = /*#__PURE__*/ forwardRef(function AglynTypography(props,
|
|
|
398
427
|
// A cleared `align` persists as null and MUI capitalizes it — an SSR throw
|
|
399
428
|
// that 500s the page (AGL-1226, same shape as the button colour).
|
|
400
429
|
const rest = dropClearedProps(spread);
|
|
430
|
+
const nested = useContext(TypographyNestingContext);
|
|
431
|
+
const parts = Children.toArray(children);
|
|
432
|
+
const childNodes = parts.filter(isChildNode);
|
|
401
433
|
const hasHtml = typeof html === 'string' && Boolean(html);
|
|
402
434
|
// Sanitized DURING render, on the server and in the browser alike
|
|
403
435
|
// (AGL-1901). The effect this replaced existed because DOMPurify needs a
|
|
@@ -408,6 +440,16 @@ const AglynTypography = /*#__PURE__*/ forwardRef(function AglynTypography(props,
|
|
|
408
440
|
// DOM dependency, so both sides now compute the same bytes from the same
|
|
409
441
|
// prop and agree on the CONTENT instead of on the absence of it.
|
|
410
442
|
const sanitized = hasHtml ? sanitizeTypographyHtml(html) : null;
|
|
443
|
+
if (childNodes.length > 0 || nested) {
|
|
444
|
+
return /*#__PURE__*/ _jsx(HoldingTypography, {
|
|
445
|
+
ref: ref,
|
|
446
|
+
rest: rest,
|
|
447
|
+
sanitized: sanitized,
|
|
448
|
+
nested: nested,
|
|
449
|
+
text: parts.filter((part)=>!isChildNode(part)),
|
|
450
|
+
childNodes: childNodes
|
|
451
|
+
});
|
|
452
|
+
}
|
|
411
453
|
if (sanitized !== null) {
|
|
412
454
|
// A `<p>` cannot hold the block content a rich-text body may contain —
|
|
413
455
|
// see `blockSafeComponent`. `undefined` leaves MUI's own choice alone.
|
|
@@ -430,6 +472,40 @@ const AglynTypography = /*#__PURE__*/ forwardRef(function AglynTypography(props,
|
|
|
430
472
|
children: children
|
|
431
473
|
}));
|
|
432
474
|
});
|
|
475
|
+
/**
|
|
476
|
+
* A Typography that holds elements, or sits inside one that does
|
|
477
|
+
* (AGL-3672). Its own text comes first, then the elements dropped into it.
|
|
478
|
+
*
|
|
479
|
+
* The element changes only where the parser would otherwise rewrite the
|
|
480
|
+
* page: a holder that would be a `<p>` becomes a `<div>`, since the elements
|
|
481
|
+
* inside may be blocks and a block start tag closes a `<p>`; a nested one
|
|
482
|
+
* that would be a paragraph or heading becomes a `<span>`. A rich-text body
|
|
483
|
+
* goes in its own `<aglyn-text>` rather than over the whole element, so the
|
|
484
|
+
* children survive both the render and an in-place edit.
|
|
485
|
+
*/ const HoldingTypography = /*#__PURE__*/ forwardRef(function HoldingTypography(props, ref) {
|
|
486
|
+
var _ref, _rest_component, _rest_variant, _ref1;
|
|
487
|
+
const { rest, sanitized, nested, text, childNodes } = props;
|
|
488
|
+
const element = (_ref = (_rest_component = rest.component) != null ? _rest_component : VARIANT_ELEMENT[(_rest_variant = rest.variant) != null ? _rest_variant : 'body1']) != null ? _ref : 'span';
|
|
489
|
+
const component = (_ref1 = sanitized !== null ? blockSafeComponent(sanitized, rest) : undefined) != null ? _ref1 : nested && BLOCK_TEXT_ELEMENTS.has(element) ? 'span' : childNodes.length > 0 && element === 'p' ? 'div' : undefined;
|
|
490
|
+
return /*#__PURE__*/ _jsxs(Typography, _extends({
|
|
491
|
+
ref: ref,
|
|
492
|
+
variantMapping: VARIANT_ELEMENT
|
|
493
|
+
}, rest, component ? {
|
|
494
|
+
component
|
|
495
|
+
} : {}, {
|
|
496
|
+
children: [
|
|
497
|
+
sanitized !== null ? /*#__PURE__*/ _jsx(AglynText, {
|
|
498
|
+
dangerouslySetInnerHTML: {
|
|
499
|
+
__html: sanitized
|
|
500
|
+
}
|
|
501
|
+
}) : text,
|
|
502
|
+
childNodes.length > 0 && /*#__PURE__*/ _jsx(TypographyNestingContext.Provider, {
|
|
503
|
+
value: true,
|
|
504
|
+
children: childNodes
|
|
505
|
+
})
|
|
506
|
+
]
|
|
507
|
+
}));
|
|
508
|
+
});
|
|
433
509
|
export default AglynTypography;
|
|
434
510
|
|
|
435
511
|
//# sourceMappingURL=typography.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/typography.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 {\n mdiAlphabetical,\n mdiFormatHeader1,\n mdiFormatHeader2,\n mdiFormatHeader3,\n mdiFormatHeader4,\n mdiFormatHeader5,\n mdiFormatHeader6,\n mdiFormatText,\n} from '@aglyn/shared-data-mdi'\nimport Typography, { type TypographyProps } from '@mui/material/Typography'\nimport { forwardRef } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { FIELD_TEXT_CONTENT } from '../constants/field-presets'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; keep the legacy ids.\nexport const ID: Aglyn.ComponentId = 'muiTypography'\n// The brand's own rungs sit alongside MUI's. They were added to the theme\n// (AGL-1308 for the body scale, for the display rung) but never to\n// this list, so the only way to reach one was to hand-write its pixels into\n// the Styles panel — which is the very thing the tokens exist to stop.\n// Display first: the list reads largest to smallest.\n//\n// Exported because it is the theme's rung list, not this element's: any block\n// that offers a type step has to offer the SAME one, or a rung added to the\n// theme becomes reachable from the Typography element and nowhere else.\nexport const typographyVariants = [\n {\n value: 'displayXl',\n label: 'Display XL',\n icon: { path: mdiFormatHeader1.path },\n },\n { value: 'h1', label: 'Heading 1', icon: { path: mdiFormatHeader1.path } },\n { value: 'h2', label: 'Heading 2', icon: { path: mdiFormatHeader2.path } },\n { value: 'h3', label: 'Heading 3', icon: { path: mdiFormatHeader3.path } },\n { value: 'h4', label: 'Heading 4', icon: { path: mdiFormatHeader4.path } },\n { value: 'h5', label: 'Heading 5', icon: { path: mdiFormatHeader5.path } },\n { value: 'h6', label: 'Heading 6', icon: { path: mdiFormatHeader6.path } },\n {\n value: 'subtitle1',\n label: 'Subtitle 1',\n icon: { path: mdiFormatText.path },\n },\n {\n value: 'subtitle2',\n label: 'Subtitle 2',\n icon: { path: mdiFormatText.path },\n },\n { value: 'body1', label: 'Body 1', icon: { path: mdiFormatText.path } },\n { value: 'body2', label: 'Body 2', icon: { path: mdiFormatText.path } },\n { value: 'lede', label: 'Lede', icon: { path: mdiFormatText.path } },\n { value: 'overline', label: 'Overline', icon: { path: mdiFormatText.path } },\n { value: 'caption', label: 'Caption', icon: { path: mdiFormatText.path } },\n {\n value: 'bodyCompact',\n label: 'Body compact',\n icon: { path: mdiFormatText.path },\n },\n { value: 'micro', label: 'Micro', icon: { path: mdiFormatText.path } },\n]\n\nexport const schema: Aglyn.ComponentSchema = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Typography',\n description: \"A block of text in one of the theme's type styles.\",\n category: Aglyn.ComponentCategory.TEXT,\n icon: {\n path: mdiAlphabetical.path,\n sx: { color: '#057822' },\n },\n flags: {\n // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n textEditable: Aglyn.FEATURE_FLAG.ENABLED,\n richTextEditable: Aglyn.FEATURE_FLAG.ENABLED,\n },\n attributes: [\n FIELD_TEXT_CONTENT,\n // FIELD_COLOR,\n {\n name: 'variant',\n description:\n 'Which typography step from the site theme this text uses — h1–h6, ' +\n 'body, subtitle, caption, overline. It sets size, weight and line ' +\n 'height together; it does NOT change the HTML element, which is the ' +\n 'field below.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Variant',\n // \"Default\" deleted (AGL-1453): unpersistable, and a second name for\n // `body1`, MUI's own default, already in `typographyVariants`.\n options: [...typographyVariants],\n },\n {\n name: 'component',\n description: 'The html element to use.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Component',\n // \"Default\" deleted rather than given a sentinel (AGL-1453), and this\n // is the prop that shows why a sentinel is not always available: MUI\n // derives the element from `variantMapping[variant]`, so \"Default\"\n // resolves to a DIFFERENT tag per variant — `h2` for a Heading 2, `p`\n // for Body 1. No single value on this list expresses that, and picking\n // one would pin the tag and change the document outline. Unset is the\n // only thing that means \"let the variant decide\", and the field's ✕ is\n // how an author says it.\n options: [\n { value: 'h1', label: 'Heading 1' },\n { value: 'h2', label: 'Heading 2' },\n { value: 'h3', label: 'Heading 3' },\n { value: 'h4', label: 'Heading 4' },\n { value: 'h5', label: 'Heading 5' },\n { value: 'h6', label: 'Heading 6' },\n { value: 'p', label: 'Paragraph' },\n { value: 'div', label: 'Div' },\n { value: 'span', label: 'Span' },\n ],\n },\n {\n name: 'align',\n description: 'The text alignment',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Alignment',\n // \"Default\" deleted (AGL-1453): unpersistable, and a second name for\n // `inherit`, MUI Typography's own default, already on the list.\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'left', label: 'Left' },\n { value: 'center', label: 'Center' },\n { value: 'right', label: 'Right' },\n { value: 'justify', label: 'Justified' },\n ],\n },\n {\n name: 'noWrap',\n description: 'If true, the text will not wrap/fold.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Disable wrapping?',\n },\n {\n name: 'gutterBottom',\n description: 'If true, the text will have a space beneath.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Gutter bottom?',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n ...typographyVariants.map((item): Aglyn.PresetSchema => ({\n $id: generatePresetId(ID, item.value),\n type: Aglyn.NodeType.PRESET,\n displayName: item.label,\n pluginId: BUNDLE_ID,\n description: `Element with ${item.label} styles`,\n category: Aglyn.ComponentCategory.TEXT,\n icon: {\n sx: { color: '#057822' },\n ...item.icon,\n },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n variant: item.value,\n children: item.label,\n },\n },\n })),\n]\n\n/**\n * Typography that renders rich text (AGL-54): when the node carries an\n * `html` prop it renders as innerHTML; otherwise plain `children`.\n *\n * The `html` prop is re-sanitized on EVERY render (AGL-497). The inline\n * editor sanitizes at commit, but screen node props are written directly via\n * the Firebase client SDK, so a host editor can plant arbitrary `html`\n * (bypassing the editor) that would execute on the public site AND in the\n * besigner canvas on app.aglyn.com.\n *\n * The sanitizer is `Aglyn.sanitizeAuthorHtml` (AGL-1901), which needs no DOM\n * and so runs on the server too — the DOMPurify call this replaced could\n * not, which is why the content used to be deferred to an effect and left\n * every rich-text body out of the server response. The allowlist it enforces\n * is a subset of the old DOMPurify config's, pinned pair by pair in\n * `rich-text-hydration.spec.tsx`.\n */\nfunction sanitizeTypographyHtml(html: string): string {\n return Aglyn.sanitizeAuthorHtml(html)\n}\n\n/**\n * MUI's own `defaultVariantMapping`, plus its `span` fallback — the element\n * Typography will actually render for a given variant. Copied rather than\n * imported because MUI does not export it; `author-html-round-trip.spec.tsx`\n * asserts this table still matches what MUI actually renders, so a MUI upgrade that\n * changed the mapping fails there rather than silently reopening the\n * reparenting hazard below.\n */\n/**\n * The element each variant renders as, and the ONE place that decides\n *.\n *\n * MUI's own `variantMapping` sends `subtitle1` and `subtitle2` to `<h6>`.\n * That is a typographic choice made in a component library, and on a page\n * builder it is a document-outline decision made by somebody who has never\n * seen the page: a subtitle is a label, not a section, and every one on every\n * Aglyn site was silently inserting an `<h6>` into the heading order. It is\n * what Lighthouse's `heading-order` was reporting — a \"Open source &\n * self-hostable\" card label rendering ahead of the page's own `<h1>`, from a\n * node whose author had selected Subtitle 1 and nothing else.\n *\n * Subtitles render as `<p>` here. An author who wants a heading still says so\n * with the Component field, which is the control for exactly that question\n * and is unchanged.\n *\n * Passed to MUI as `variantMapping` rather than only consulted by\n * `blockSafeComponent`, so the table cannot describe one thing while the\n * element is another.\n */\nconst VARIANT_ELEMENT: Record<string, string> = {\n h1: 'h1', h2: 'h2', h3: 'h3', h4: 'h4', h5: 'h5', h6: 'h6',\n subtitle1: 'p', subtitle2: 'p', body1: 'p', body2: 'p', inherit: 'p',\n}\n\n/**\n * The element the rich-text body is put INSIDE, which may have to be a\n * `<div>` rather than the one the variant implies (AGL-1901).\n *\n * The parser closes a `<p>` on any block start tag, and a heading on any\n * other heading. So a body with an `<h2>` in it, served inside the `<p>` MUI\n * renders for `body1`, arrives at the browser as\n * `<p class=\"MuiTypography-root\"></p><h2>…</h2>` — the container emptied and\n * the body promoted to a sibling. React then hydrates against a DOM that is\n * not the one it described and reports a mismatch: the live React #418 shape\n * on tenant (AGL-1926), which this change must not add to.\n *\n * This never mattered before because the server `<p>` was EMPTY and the body\n * arrived through an `innerHTML` assignment, which parses in the CONTEXT of\n * the `<p>` and so does not reparent. Serving the body is what makes the\n * container's element type load-bearing.\n *\n * `authorHtmlBreaksContainer` holds the rule, next to the table of tags it\n * depends on. Returns `'div'` to override, or `undefined` to leave MUI's\n * choice alone; the decision is a pure function of props, so the server and\n * the client make it identically.\n */\nfunction blockSafeComponent(\n sanitized: string,\n rest: TypographyProps,\n): 'div' | undefined {\n const element =\n (rest.component as string | undefined) ??\n // MUI's own default variant is `body1`, which maps to `p` — the case that\n // matters, since a Typography with no variant set is the shape nearly\n // every rich-text node has. (`paragraph` is gone in MUI v7, so the\n // variant mapping is the only other input.)\n VARIANT_ELEMENT[(rest.variant as string) ?? 'body1'] ??\n 'span'\n return Aglyn.authorHtmlBreaksContainer(sanitized, element) ? 'div' : undefined\n}\n\nconst AglynTypography = forwardRef<\n HTMLElement,\n TypographyProps & { html?: string }\n>(function AglynTypography(props, ref) {\n const { html, children, ...spread } = props\n // A cleared `align` persists as null and MUI capitalizes it — an SSR throw\n // that 500s the page (AGL-1226, same shape as the button colour).\n const rest = dropClearedProps(spread)\n const hasHtml = typeof html === 'string' && Boolean(html)\n // Sanitized DURING render, on the server and in the browser alike\n // (AGL-1901). The effect this replaced existed because DOMPurify needs a\n // DOM: the server rendered nothing, so the first client render had to\n // render nothing too or hydration would mismatch (AGL-1268) — the two\n // sides agreed only by both being empty, and the body never reached a\n // crawler. `sanitizeAuthorHtml` is a pure function of the string with no\n // DOM dependency, so both sides now compute the same bytes from the same\n // prop and agree on the CONTENT instead of on the absence of it.\n const sanitized = hasHtml ? sanitizeTypographyHtml(html as string) : null\n if (sanitized !== null) {\n // A `<p>` cannot hold the block content a rich-text body may contain —\n // see `blockSafeComponent`. `undefined` leaves MUI's own choice alone.\n const component = blockSafeComponent(sanitized, rest as TypographyProps)\n return (\n <Typography\n ref={ref}\n variantMapping={VARIANT_ELEMENT}\n {...rest}\n {...(component ? { component } : {})}\n dangerouslySetInnerHTML={{ __html: sanitized }}\n />\n )\n }\n return (\n <Typography ref={ref} variantMapping={VARIANT_ELEMENT} {...rest}>\n {children}\n </Typography>\n )\n})\n\nexport default AglynTypography\n"],"names":["Aglyn","mdiAlphabetical","mdiFormatHeader1","mdiFormatHeader2","mdiFormatHeader3","mdiFormatHeader4","mdiFormatHeader5","mdiFormatHeader6","mdiFormatText","Typography","forwardRef","BUNDLE_ID","FIELD_TEXT_CONTENT","dropClearedProps","generatePresetId","ID","typographyVariants","value","label","icon","path","schema","$id","pluginId","displayName","description","category","ComponentCategory","TEXT","sx","color","flags","lazyHydration","FEATURE_FLAG","ENABLED","textEditable","richTextEditable","attributes","name","component","FieldComponentType","SELECT","options","SWITCH","presets","map","item","type","NodeType","PRESET","data","componentId","props","variant","children","sanitizeTypographyHtml","html","sanitizeAuthorHtml","VARIANT_ELEMENT","h1","h2","h3","h4","h5","h6","subtitle1","subtitle2","body1","body2","inherit","blockSafeComponent","sanitized","rest","element","authorHtmlBreaksContainer","undefined","AglynTypography","ref","spread","hasHtml","Boolean","variantMapping","dangerouslySetInnerHTML","__html"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/typography.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 {\n mdiAlphabetical,\n mdiFormatHeader1,\n mdiFormatHeader2,\n mdiFormatHeader3,\n mdiFormatHeader4,\n mdiFormatHeader5,\n mdiFormatHeader6,\n mdiFormatText,\n} from '@aglyn/shared-data-mdi'\nimport { AglynText } from '@aglyn/shared-ui-jsx'\nimport Typography, { type TypographyProps } from '@mui/material/Typography'\nimport {\n Children,\n createContext,\n forwardRef,\n isValidElement,\n useContext,\n type ReactNode,\n} from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { FIELD_TEXT_CONTENT } from '../constants/field-presets'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; keep the legacy ids.\nexport const ID: Aglyn.ComponentId = 'muiTypography'\n// The brand's own rungs sit alongside MUI's. They were added to the theme\n// (AGL-1308 for the body scale, for the display rung) but never to\n// this list, so the only way to reach one was to hand-write its pixels into\n// the Styles panel — which is the very thing the tokens exist to stop.\n// Display first: the list reads largest to smallest.\n//\n// Exported because it is the theme's rung list, not this element's: any block\n// that offers a type step has to offer the SAME one, or a rung added to the\n// theme becomes reachable from the Typography element and nowhere else.\nexport const typographyVariants = [\n {\n value: 'displayXl',\n label: 'Display XL',\n icon: { path: mdiFormatHeader1.path },\n },\n { value: 'h1', label: 'Heading 1', icon: { path: mdiFormatHeader1.path } },\n { value: 'h2', label: 'Heading 2', icon: { path: mdiFormatHeader2.path } },\n { value: 'h3', label: 'Heading 3', icon: { path: mdiFormatHeader3.path } },\n { value: 'h4', label: 'Heading 4', icon: { path: mdiFormatHeader4.path } },\n { value: 'h5', label: 'Heading 5', icon: { path: mdiFormatHeader5.path } },\n { value: 'h6', label: 'Heading 6', icon: { path: mdiFormatHeader6.path } },\n {\n value: 'subtitle1',\n label: 'Subtitle 1',\n icon: { path: mdiFormatText.path },\n },\n {\n value: 'subtitle2',\n label: 'Subtitle 2',\n icon: { path: mdiFormatText.path },\n },\n { value: 'body1', label: 'Body 1', icon: { path: mdiFormatText.path } },\n { value: 'body2', label: 'Body 2', icon: { path: mdiFormatText.path } },\n { value: 'lede', label: 'Lede', icon: { path: mdiFormatText.path } },\n { value: 'overline', label: 'Overline', icon: { path: mdiFormatText.path } },\n { value: 'caption', label: 'Caption', icon: { path: mdiFormatText.path } },\n {\n value: 'bodyCompact',\n label: 'Body compact',\n icon: { path: mdiFormatText.path },\n },\n { value: 'micro', label: 'Micro', icon: { path: mdiFormatText.path } },\n]\n\nexport const schema: Aglyn.ComponentSchema = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Typography',\n description: \"A block of text in one of the theme's type styles.\",\n category: Aglyn.ComponentCategory.TEXT,\n icon: {\n path: mdiAlphabetical.path,\n sx: { color: '#057822' },\n },\n flags: {\n // Static: may sit in a subtree that keeps its server HTML (AGL-3581).\n lazyHydration: Aglyn.FEATURE_FLAG.ENABLED,\n textEditable: Aglyn.FEATURE_FLAG.ENABLED,\n richTextEditable: Aglyn.FEATURE_FLAG.ENABLED,\n // Holds other elements after its own text (AGL-3672). The text keeps its\n // own `<aglyn-text>`, which is all the in-place editor rewrites, so an\n // edit never touches the elements beside it.\n dropping: Aglyn.FEATURE_FLAG.ENABLED,\n // One React child per child node, so the component can tell its\n // elements from its text — see `AglynTypography`.\n positionalChildren: Aglyn.FEATURE_FLAG.ENABLED,\n },\n attributes: [\n FIELD_TEXT_CONTENT,\n // FIELD_COLOR,\n {\n name: 'variant',\n description:\n 'Which typography step from the site theme this text uses — h1–h6, ' +\n 'body, subtitle, caption, overline. It sets size, weight and line ' +\n 'height together; it does NOT change the HTML element, which is the ' +\n 'field below.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Variant',\n // \"Default\" deleted (AGL-1453): unpersistable, and a second name for\n // `body1`, MUI's own default, already in `typographyVariants`.\n options: [...typographyVariants],\n },\n {\n name: 'component',\n description: 'The html element to use.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Component',\n // \"Default\" deleted rather than given a sentinel (AGL-1453), and this\n // is the prop that shows why a sentinel is not always available: MUI\n // derives the element from `variantMapping[variant]`, so \"Default\"\n // resolves to a DIFFERENT tag per variant — `h2` for a Heading 2, `p`\n // for Body 1. No single value on this list expresses that, and picking\n // one would pin the tag and change the document outline. Unset is the\n // only thing that means \"let the variant decide\", and the field's ✕ is\n // how an author says it.\n options: [\n { value: 'h1', label: 'Heading 1' },\n { value: 'h2', label: 'Heading 2' },\n { value: 'h3', label: 'Heading 3' },\n { value: 'h4', label: 'Heading 4' },\n { value: 'h5', label: 'Heading 5' },\n { value: 'h6', label: 'Heading 6' },\n { value: 'p', label: 'Paragraph' },\n { value: 'div', label: 'Div' },\n { value: 'span', label: 'Span' },\n ],\n },\n {\n name: 'align',\n description: 'The text alignment',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Alignment',\n // \"Default\" deleted (AGL-1453): unpersistable, and a second name for\n // `inherit`, MUI Typography's own default, already on the list.\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'left', label: 'Left' },\n { value: 'center', label: 'Center' },\n { value: 'right', label: 'Right' },\n { value: 'justify', label: 'Justified' },\n ],\n },\n {\n name: 'noWrap',\n description: 'If true, the text will not wrap/fold.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Disable wrapping?',\n },\n {\n name: 'gutterBottom',\n description: 'If true, the text will have a space beneath.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Gutter bottom?',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n ...typographyVariants.map((item): Aglyn.PresetSchema => ({\n $id: generatePresetId(ID, item.value),\n type: Aglyn.NodeType.PRESET,\n displayName: item.label,\n pluginId: BUNDLE_ID,\n description: `Element with ${item.label} styles`,\n category: Aglyn.ComponentCategory.TEXT,\n icon: {\n sx: { color: '#057822' },\n ...item.icon,\n },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n variant: item.value,\n children: item.label,\n },\n },\n })),\n]\n\n/**\n * Typography that renders rich text (AGL-54): when the node carries an\n * `html` prop it renders as innerHTML; otherwise plain `children`.\n *\n * The `html` prop is re-sanitized on EVERY render (AGL-497). The inline\n * editor sanitizes at commit, but screen node props are written directly via\n * the Firebase client SDK, so a host editor can plant arbitrary `html`\n * (bypassing the editor) that would execute on the public site AND in the\n * besigner canvas on app.aglyn.com.\n *\n * The sanitizer is `Aglyn.sanitizeAuthorHtml` (AGL-1901), which needs no DOM\n * and so runs on the server too — the DOMPurify call this replaced could\n * not, which is why the content used to be deferred to an effect and left\n * every rich-text body out of the server response. The allowlist it enforces\n * is a subset of the old DOMPurify config's, pinned pair by pair in\n * `rich-text-hydration.spec.tsx`.\n */\nfunction sanitizeTypographyHtml(html: string): string {\n return Aglyn.sanitizeAuthorHtml(html)\n}\n\n/**\n * MUI's own `defaultVariantMapping`, plus its `span` fallback — the element\n * Typography will actually render for a given variant. Copied rather than\n * imported because MUI does not export it; `author-html-round-trip.spec.tsx`\n * asserts this table still matches what MUI actually renders, so a MUI upgrade that\n * changed the mapping fails there rather than silently reopening the\n * reparenting hazard below.\n */\n/**\n * The element each variant renders as, and the ONE place that decides\n *.\n *\n * MUI's own `variantMapping` sends `subtitle1` and `subtitle2` to `<h6>`.\n * That is a typographic choice made in a component library, and on a page\n * builder it is a document-outline decision made by somebody who has never\n * seen the page: a subtitle is a label, not a section, and every one on every\n * Aglyn site was silently inserting an `<h6>` into the heading order. It is\n * what Lighthouse's `heading-order` was reporting — a \"Open source &\n * self-hostable\" card label rendering ahead of the page's own `<h1>`, from a\n * node whose author had selected Subtitle 1 and nothing else.\n *\n * Subtitles render as `<p>` here. An author who wants a heading still says so\n * with the Component field, which is the control for exactly that question\n * and is unchanged.\n *\n * Passed to MUI as `variantMapping` rather than only consulted by\n * `blockSafeComponent`, so the table cannot describe one thing while the\n * element is another.\n */\nconst VARIANT_ELEMENT: Record<string, string> = {\n h1: 'h1', h2: 'h2', h3: 'h3', h4: 'h4', h5: 'h5', h6: 'h6',\n subtitle1: 'p', subtitle2: 'p', body1: 'p', body2: 'p', inherit: 'p',\n}\n\n/**\n * The element the rich-text body is put INSIDE, which may have to be a\n * `<div>` rather than the one the variant implies (AGL-1901).\n *\n * The parser closes a `<p>` on any block start tag, and a heading on any\n * other heading. So a body with an `<h2>` in it, served inside the `<p>` MUI\n * renders for `body1`, arrives at the browser as\n * `<p class=\"MuiTypography-root\"></p><h2>…</h2>` — the container emptied and\n * the body promoted to a sibling. React then hydrates against a DOM that is\n * not the one it described and reports a mismatch: the live React #418 shape\n * on tenant (AGL-1926), which this change must not add to.\n *\n * This never mattered before because the server `<p>` was EMPTY and the body\n * arrived through an `innerHTML` assignment, which parses in the CONTEXT of\n * the `<p>` and so does not reparent. Serving the body is what makes the\n * container's element type load-bearing.\n *\n * `authorHtmlBreaksContainer` holds the rule, next to the table of tags it\n * depends on. Returns `'div'` to override, or `undefined` to leave MUI's\n * choice alone; the decision is a pure function of props, so the server and\n * the client make it identically.\n */\nfunction blockSafeComponent(\n sanitized: string,\n rest: TypographyProps,\n): 'div' | undefined {\n const element =\n (rest.component as string | undefined) ??\n // MUI's own default variant is `body1`, which maps to `p` — the case that\n // matters, since a Typography with no variant set is the shape nearly\n // every rich-text node has. (`paragraph` is gone in MUI v7, so the\n // variant mapping is the only other input.)\n VARIANT_ELEMENT[(rest.variant as string) ?? 'body1'] ??\n 'span'\n return Aglyn.authorHtmlBreaksContainer(sanitized, element) ? 'div' : undefined\n}\n\n/** The elements a Typography may not sit inside of another as. */\nconst BLOCK_TEXT_ELEMENTS = new Set(['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'])\n\n/**\n * True inside the child elements of a Typography. A paragraph or heading\n * nested in another is not one the parser keeps: `<p>` closes on any `<p>`\n * start tag and a heading on any heading, so the inner element lands beside\n * the outer one and React hydrates against a page it did not describe. A\n * nested Typography renders as a `<span>` instead — it continues the\n * sentence it was dropped into, which is what nesting text means.\n */\nconst TypographyNestingContext = createContext(false)\n\n/** A child NODE, as the renderer hands it over: an element carrying `node`. */\nfunction isChildNode(child: ReactNode): boolean {\n return isValidElement(child) && (child.props as any)?.node != null\n}\n\nconst AglynTypography = forwardRef<\n HTMLElement,\n TypographyProps & { html?: string }\n>(function AglynTypography(props, ref) {\n const { html, children, ...spread } = props\n // A cleared `align` persists as null and MUI capitalizes it — an SSR throw\n // that 500s the page (AGL-1226, same shape as the button colour).\n const rest = dropClearedProps(spread)\n const nested = useContext(TypographyNestingContext)\n const parts = Children.toArray(children)\n const childNodes = parts.filter(isChildNode)\n const hasHtml = typeof html === 'string' && Boolean(html)\n // Sanitized DURING render, on the server and in the browser alike\n // (AGL-1901). The effect this replaced existed because DOMPurify needs a\n // DOM: the server rendered nothing, so the first client render had to\n // render nothing too or hydration would mismatch (AGL-1268) — the two\n // sides agreed only by both being empty, and the body never reached a\n // crawler. `sanitizeAuthorHtml` is a pure function of the string with no\n // DOM dependency, so both sides now compute the same bytes from the same\n // prop and agree on the CONTENT instead of on the absence of it.\n const sanitized = hasHtml ? sanitizeTypographyHtml(html as string) : null\n if (childNodes.length > 0 || nested) {\n return (\n <HoldingTypography\n ref={ref}\n rest={rest as TypographyProps}\n sanitized={sanitized}\n nested={nested}\n text={parts.filter((part) => !isChildNode(part))}\n childNodes={childNodes}\n />\n )\n }\n if (sanitized !== null) {\n // A `<p>` cannot hold the block content a rich-text body may contain —\n // see `blockSafeComponent`. `undefined` leaves MUI's own choice alone.\n const component = blockSafeComponent(sanitized, rest as TypographyProps)\n return (\n <Typography\n ref={ref}\n variantMapping={VARIANT_ELEMENT}\n {...rest}\n {...(component ? { component } : {})}\n dangerouslySetInnerHTML={{ __html: sanitized }}\n />\n )\n }\n return (\n <Typography ref={ref} variantMapping={VARIANT_ELEMENT} {...rest}>\n {children}\n </Typography>\n )\n})\n\n/**\n * A Typography that holds elements, or sits inside one that does\n * (AGL-3672). Its own text comes first, then the elements dropped into it.\n *\n * The element changes only where the parser would otherwise rewrite the\n * page: a holder that would be a `<p>` becomes a `<div>`, since the elements\n * inside may be blocks and a block start tag closes a `<p>`; a nested one\n * that would be a paragraph or heading becomes a `<span>`. A rich-text body\n * goes in its own `<aglyn-text>` rather than over the whole element, so the\n * children survive both the render and an in-place edit.\n */\nconst HoldingTypography = forwardRef<\n HTMLElement,\n {\n rest: TypographyProps\n sanitized: string | null\n nested: boolean\n text: ReactNode[]\n childNodes: ReactNode[]\n }\n>(function HoldingTypography(props, ref) {\n const { rest, sanitized, nested, text, childNodes } = props\n const element =\n (rest.component as string | undefined) ??\n VARIANT_ELEMENT[(rest.variant as string) ?? 'body1'] ??\n 'span'\n const component =\n (sanitized !== null ? blockSafeComponent(sanitized, rest) : undefined) ??\n (nested && BLOCK_TEXT_ELEMENTS.has(element)\n ? 'span'\n : childNodes.length > 0 && element === 'p'\n ? 'div'\n : undefined)\n return (\n <Typography\n ref={ref}\n variantMapping={VARIANT_ELEMENT}\n {...rest}\n {...(component ? { component } : {})}\n >\n {sanitized !== null ? (\n <AglynText dangerouslySetInnerHTML={{ __html: sanitized }} />\n ) : (\n text\n )}\n {childNodes.length > 0 && (\n <TypographyNestingContext.Provider value={true}>\n {childNodes}\n </TypographyNestingContext.Provider>\n )}\n </Typography>\n )\n})\n\nexport default AglynTypography\n"],"names":["Aglyn","mdiAlphabetical","mdiFormatHeader1","mdiFormatHeader2","mdiFormatHeader3","mdiFormatHeader4","mdiFormatHeader5","mdiFormatHeader6","mdiFormatText","AglynText","Typography","Children","createContext","forwardRef","isValidElement","useContext","BUNDLE_ID","FIELD_TEXT_CONTENT","dropClearedProps","generatePresetId","ID","typographyVariants","value","label","icon","path","schema","$id","pluginId","displayName","description","category","ComponentCategory","TEXT","sx","color","flags","lazyHydration","FEATURE_FLAG","ENABLED","textEditable","richTextEditable","dropping","positionalChildren","attributes","name","component","FieldComponentType","SELECT","options","SWITCH","presets","map","item","type","NodeType","PRESET","data","componentId","props","variant","children","sanitizeTypographyHtml","html","sanitizeAuthorHtml","VARIANT_ELEMENT","h1","h2","h3","h4","h5","h6","subtitle1","subtitle2","body1","body2","inherit","blockSafeComponent","sanitized","rest","element","authorHtmlBreaksContainer","undefined","BLOCK_TEXT_ELEMENTS","Set","TypographyNestingContext","isChildNode","child","node","AglynTypography","ref","spread","nested","parts","toArray","childNodes","filter","hasHtml","Boolean","length","HoldingTypography","text","part","variantMapping","dangerouslySetInnerHTML","__html","has","Provider"],"mappings":"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"}
|
package/src/lib/plugin.js
CHANGED
|
@@ -109,9 +109,9 @@ const themeModeSwitcher = viaTier('themeModeSwitcher');
|
|
|
109
109
|
schema: 'schema',
|
|
110
110
|
presets: 'presets'
|
|
111
111
|
},
|
|
112
|
-
// The inline text run (AGL-1235):
|
|
113
|
-
//
|
|
114
|
-
//
|
|
112
|
+
// The inline text run (AGL-1235): one styled phrase inside a sentence.
|
|
113
|
+
// Typography also holds elements now (AGL-3672), but a run is still the
|
|
114
|
+
// element that flows and wraps as part of the line.
|
|
115
115
|
muiInlineText: {
|
|
116
116
|
module: inlineText,
|
|
117
117
|
component: 'default',
|
package/src/lib/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/mui/src/lib/plugin.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 {\n registerPluginInstallPresetMapper,\n registerPluginInstallPresetsMapper,\n} from '@aglyn/aglyn'\nimport {\n muiPluginInstallToPreset,\n muiPluginInstallToPresets,\n} from './components/plugin-install-presets'\nimport * as Aglyn from '@aglyn/aglyn'\nimport { runInAction } from 'mobx'\nimport { BUNDLE_ID } from './constants/bundle-common'\n\n/**\n * One thunk per component module, named here because several ids share one:\n * `card.tsx` and `accordion.tsx` each export several elements, and a module is\n * imported once however many of its components a surface asks for.\n *\n * Every thunk goes through the element tier (AGL-3401). The common elements\n * are part of it; the rest are `import()`s written inside it, so they can\n * rely on what it loaded instead of each carrying a copy. `element-tier.ts`\n * has the reasoning, and which elements are which.\n */\ntype ElementTier = typeof import('./element-tier')\ntype TierElement = keyof ElementTier['CORE_ELEMENTS']\ntype LazyElement = Exclude<keyof ElementTier, 'CORE_ELEMENTS'>\n\ntype ElementModule = Promise<Record<string, unknown>>\n\n/**\n * One load of the tier, however many thunks ask at once. The bundler shares\n * a module across concurrent imports anyway; a loader that hands out a\n * module while it is still evaluating does not — jiti, which the AI palette\n * and page-axe generators load this bundle through, resolved the second of\n * sixty concurrent imports to the tier's exports before `CORE_ELEMENTS` was\n * assigned.\n */\nlet tierLoad: Promise<ElementTier> | undefined\nconst elementTier = (): Promise<ElementTier> =>\n (tierLoad ??= import('./element-tier'))\nconst inTier =\n (name: TierElement): MuiComponentSource['module'] =>\n () =>\n elementTier().then(\n (tier): Record<string, unknown> => tier.CORE_ELEMENTS[name],\n )\nconst viaTier =\n (name: LazyElement): MuiComponentSource['module'] =>\n () =>\n elementTier().then((tier): ElementModule => tier[name]())\n\nconst appBar = inTier('appBar')\nconst toolbar = inTier('toolbar')\nconst layoutSlot = inTier('layoutSlot')\nconst documentRoot = inTier('documentRoot')\nconst section = inTier('section')\nconst container = inTier('container')\nconst box = inTier('box')\nconst stack = inTier('stack')\nconst grid = inTier('grid')\nconst paper = inTier('paper')\nconst typography = inTier('typography')\nconst inlineText = inTier('inlineText')\nconst button = inTier('button')\nconst screenLink = inTier('screenLink')\nconst linkBox = inTier('linkBox')\nconst image = inTier('image')\nconst icon = inTier('icon')\n\nconst list = viaTier('list')\nconst listItem = viaTier('listItem')\nconst listItemText = viaTier('listItemText')\nconst blocks = viaTier('blocks')\nconst dataTable = viaTier('dataTable')\nconst collectionEntries = viaTier('collectionEntries')\nconst collectionEntryBody = viaTier('collectionEntryBody')\nconst collectionRelated = viaTier('collectionRelated')\nconst collectionShare = viaTier('collectionShare')\nconst collectionEntryMeta = viaTier('collectionEntryMeta')\nconst collectionEntryAuthor = viaTier('collectionEntryAuthor')\nconst collectionAuthorProfile = viaTier('collectionAuthorProfile')\nconst collectionCategories = viaTier('collectionCategories')\nconst collectionSearch = viaTier('collectionSearch')\nconst video = viaTier('video')\nconst languageSwitcher = viaTier('languageSwitcher')\nconst reusableInstance = viaTier('reusableInstance')\nconst navMenu = viaTier('navMenu')\nconst drawer = viaTier('drawer')\nconst product = viaTier('product')\nconst plugin = viaTier('plugin')\nconst customHtml = viaTier('customHtml')\nconst searchBox = viaTier('searchBox')\nconst markdown = viaTier('markdown')\nconst card = viaTier('card')\nconst accordion = viaTier('accordion')\nconst tabs = viaTier('tabs')\nconst imageList = viaTier('imageList')\nconst pagination = viaTier('pagination')\nconst breadcrumbs = viaTier('breadcrumbs')\nconst themeModeSwitcher = viaTier('themeModeSwitcher')\n\n/** One entry of the bundle: what the registry is handed for a component. */\nexport interface MuiBundleEntry {\n component: any\n schema: Aglyn.ComponentSchema<any>\n presets?: Aglyn.PresetSchema[]\n}\n\n/**\n * Where a component id's code lives, and what it is called there (AGL-3141).\n *\n * An id names a module AND an export on it, never a module alone: several\n * modules export more than one element, and the registry needs the component,\n * its schema and — for the element that carries them — its presets by name.\n */\nexport interface MuiComponentSource {\n /** The module, as a thunk, so the bundler gives it a chunk of its own. */\n module: () => Promise<Record<string, unknown>>\n /** The component's export name on that module. */\n component: string\n /** Its schema's export name. */\n schema: string\n /** The export carrying its presets, for the element that ships them. */\n presets?: string\n /**\n * An export that loads what SOME instances of the element render, before\n * any of them does (AGL-3438) — `(everything: boolean) => Promise | void`.\n *\n * For a module the element fetches only when an instance's props ask for\n * it, the way Collection Entries fetches its search box. The element alone\n * knows when a render must not wait for that fetch; `everything` tells it\n * the whole library is loading, which is what the console and the besigner\n * ask for. The bundle is handed over once the load it returns has settled.\n */\n prepare?: string\n}\n\n/**\n * Every component this bundle can register (AGL-140, AGL-3141).\n *\n * One entry per component keeps register/unregister symmetric — the old\n * hand-maintained lists had drifted, and several components were never\n * unregistered on destroy. It replaces a single array built from sixty static\n * imports, which put every element on every published page while the page\n * rendered about nineteen of them.\n *\n * Exported so the bundle is assertable (AGL-1201): duplicate component or\n * preset ids collapse silently inside the registry's keyed records, so they\n * can only be caught before registration.\n */\nexport const MUI_COMPONENT_SOURCES: Readonly<\n Record<string, MuiComponentSource>\n> = {\n muiAppBar: {\n module: appBar,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiToolbar: {\n module: toolbar,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiTypography: {\n module: typography,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // The inline text run (AGL-1235): Typography is `textEditable` and so a\n // leaf, which left no way to emphasize a phrase inside a sentence — every\n // statement rendered as one flat color.\n muiInlineText: {\n module: inlineText,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiButton: {\n module: button,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiContainer: {\n module: container,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n layoutSlot: {\n module: layoutSlot,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiList: {\n module: list,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiListItem: {\n module: listItem,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiListItemText: {\n module: listItemText,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // form, formField moved to @aglyn/plugins-forms (AGL-395).\n videoEmbed: {\n module: blocks,\n component: 'VideoEmbed',\n schema: 'videoEmbedSchema',\n presets: 'blockPresets',\n },\n socialLinks: {\n module: blocks,\n component: 'SocialLinks',\n schema: 'socialLinksSchema',\n },\n // A real data grid (AGL-2543): the feature matrix a comparison page is\n // built around, which the palette had no element for at all.\n dataTable: {\n module: dataTable,\n component: 'default',\n schema: 'dataTableSchema',\n presets: 'dataTablePresets',\n },\n // Content collections (AGL-551/582): entries repeater, markdown entry\n // body, related posts, share bar, entry meta.\n collectionEntries: {\n module: collectionEntries,\n component: 'CollectionEntries',\n schema: 'collectionEntriesSchema',\n presets: 'collectionPresets',\n prepare: 'prepareEntriesSearch',\n },\n collectionEntryBody: {\n module: collectionEntryBody,\n component: 'CollectionEntryBody',\n schema: 'collectionEntryBodySchema',\n },\n collectionRelated: {\n module: collectionRelated,\n component: 'CollectionRelated',\n schema: 'collectionRelatedSchema',\n },\n collectionShare: {\n module: collectionShare,\n component: 'CollectionShare',\n schema: 'collectionShareSchema',\n },\n collectionEntryMeta: {\n module: collectionEntryMeta,\n component: 'CollectionEntryMeta',\n schema: 'collectionEntryMetaSchema',\n },\n // The author card that closes an article (AGL-2486): the byline block\n // prints a name, and the record behind it also has a portrait and a bio.\n collectionEntryAuthor: {\n module: collectionEntryAuthor,\n component: 'CollectionEntryAuthor',\n schema: 'collectionEntryAuthorSchema',\n },\n // The subject of an author's own page (AGL-2518): the same person the\n // card above draws as a footnote, with the role fields it has no room for.\n contentAuthorProfile: {\n module: collectionAuthorProfile,\n component: 'ContentAuthorProfile',\n schema: 'contentAuthorProfileSchema',\n },\n // Category pills (AGL-1321): real anchors to /{collection}/category/{slug}.\n collectionCategories: {\n module: collectionCategories,\n component: 'CollectionCategories',\n schema: 'collectionCategoriesSchema',\n },\n // The toolbar search box (AGL-1516): the entries block's own field cannot\n // leave it, so the frame's pills-left / search-right row needs a block.\n collectionSearch: {\n module: collectionSearch,\n component: 'CollectionSearch',\n schema: 'collectionSearchSchema',\n },\n image: {\n module: image,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n video: {\n module: video,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n icon: {\n module: icon,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // booking moved to @aglyn/plugins-bookings (AGL-395).\n // eventList moved to @aglyn/plugins-events-calendar (AGL-313).\n languageSwitcher: {\n module: languageSwitcher,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n reusableInstance: {\n module: reusableInstance,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiScreenLink: {\n module: screenLink,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // The linking container (AGL-1231): every other link element is a leaf,\n // so a tile whose icon and description also belong to the target had no\n // way to be authored.\n muiLinkBox: {\n module: linkBox,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // Nav menu system (AGL-562): dropdown, mega menu, drawer + menu button.\n muiNavMenu: {\n module: navMenu,\n component: 'default',\n schema: 'navMenuSchema',\n presets: 'navMenuPresets',\n },\n muiMegaMenu: {\n module: navMenu,\n component: 'MegaMenu',\n schema: 'megaMenuSchema',\n },\n muiDrawer: {\n module: drawer,\n component: 'default',\n schema: 'drawerSchema',\n presets: 'drawerPresets',\n },\n muiDrawerToggle: {\n module: drawer,\n component: 'DrawerToggle',\n schema: 'drawerToggleSchema',\n },\n product: {\n module: product,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n marketplacePlugin: {\n module: plugin,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n 'custom-html': {\n module: customHtml,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n searchBox: {\n module: searchBox,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // Long-form documents (AGL-1162): one markdown element carrying the whole\n // page, and an \"On this page\" aside derived from its headings.\n markdown: {\n module: markdown,\n component: 'Markdown',\n schema: 'markdownSchema',\n presets: 'markdownPresets',\n },\n tableOfContents: {\n module: markdown,\n component: 'TableOfContents',\n schema: 'tableOfContentsSchema',\n },\n section: {\n module: section,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiStack: {\n module: stack,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // Layout & surface primitives (AGL-1201).\n muiBox: {\n module: box,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // The canvas ROOT (AGL-2486): registered so the Document layer has a\n // schema — an element picker — instead of falling through to the\n // renderer's unstyled div. No preset: it is not an element anybody drops.\n div: {\n module: documentRoot,\n component: 'default',\n schema: 'schema',\n },\n muiGrid: {\n module: grid,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiPaper: {\n module: paper,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiCard: {\n module: card,\n component: 'default',\n schema: 'cardSchema',\n presets: 'cardPresets',\n },\n muiCardHeader: {\n module: card,\n component: 'CardHeaderElement',\n schema: 'cardHeaderSchema',\n },\n muiCardContent: {\n module: card,\n component: 'CardContentElement',\n schema: 'cardContentSchema',\n },\n muiCardActions: {\n module: card,\n component: 'CardActionsElement',\n schema: 'cardActionsSchema',\n },\n muiAccordion: {\n module: accordion,\n component: 'default',\n schema: 'accordionSchema',\n presets: 'accordionPresets',\n },\n muiAccordionSummary: {\n module: accordion,\n component: 'AccordionSummaryElement',\n schema: 'accordionSummarySchema',\n },\n muiAccordionDetails: {\n module: accordion,\n component: 'AccordionDetailsElement',\n schema: 'accordionDetailsSchema',\n },\n muiTabs: {\n module: tabs,\n component: 'default',\n schema: 'tabsSchema',\n presets: 'tabsPresets',\n },\n muiTabPanel: {\n module: tabs,\n component: 'TabPanelElement',\n schema: 'tabPanelSchema',\n },\n muiImageList: {\n module: imageList,\n component: 'default',\n schema: 'imageListSchema',\n presets: 'imageListPresets',\n },\n muiImageListItem: {\n module: imageList,\n component: 'ImageListItemElement',\n schema: 'imageListItemSchema',\n },\n muiPagination: {\n module: pagination,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiBreadcrumbs: {\n module: breadcrumbs,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n themeModeSwitcher: {\n module: themeModeSwitcher,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n}\n\n/**\n * The bundle entries for `componentIds` — every component when none are\n * named, which is what the console and the besigner ask for because their\n * palette shows every element.\n *\n * Both paths go through the same map, so there is one statement of where a\n * component comes from. An id the map does not know is dropped rather than\n * resolved to an undefined component: a page whose document carries an\n * element this bundle does not own is a document for another plugin's\n * element, not a reason to register a blank.\n */\nexport async function loadMuiBundle(\n componentIds?: readonly string[],\n): Promise<MuiBundleEntry[]> {\n const ids = (componentIds ?? Object.keys(MUI_COMPONENT_SOURCES)).filter(\n (id) => id in MUI_COMPONENT_SOURCES,\n )\n // Keyed on the THUNK, so a module that exports several elements is\n // imported once for all the ids that name it rather than once per id.\n const pending = new Map<\n MuiComponentSource['module'],\n Promise<Record<string, unknown>>\n >()\n const modules = await Promise.all(\n ids.map((id) => {\n const source = MUI_COMPONENT_SOURCES[id] as MuiComponentSource\n let load = pending.get(source.module)\n if (!load) {\n load = source.module()\n pending.set(source.module, load)\n }\n return load\n }),\n )\n // Each module's on-demand parts, once per module, before anything renders.\n const everything = componentIds === undefined\n const prepared = new Set<unknown>()\n await Promise.all(\n ids.map((id, index) => {\n const source = MUI_COMPONENT_SOURCES[id] as MuiComponentSource\n const mod = modules[index] as Record<string, unknown>\n if (!source.prepare || prepared.has(mod)) return undefined\n prepared.add(mod)\n const prepare = mod[source.prepare] as\n | ((everything: boolean) => Promise<unknown> | void)\n | undefined\n // A failed fetch is the render's to report, not the registration's:\n // the element asks again when it renders, and a block that still\n // cannot have it fails alone instead of taking the page with it.\n return Promise.resolve(prepare?.(everything)).catch(() => undefined)\n }),\n )\n return ids.map((id, index) => {\n const source = MUI_COMPONENT_SOURCES[id] as MuiComponentSource\n const mod = modules[index] as Record<string, unknown>\n return {\n component: mod[source.component],\n schema: mod[source.schema] as Aglyn.ComponentSchema<any>,\n ...(source.presets\n ? { presets: mod[source.presets] as Aglyn.PresetSchema[] }\n : {}),\n }\n })\n}\n\n/**\n * Every component registered so far, by id.\n *\n * A second page places elements the first did not, and reaches this bundle\n * again with them; the map is what tells the two apart, and what `load` and\n * `destroy` read so a reload registers everything asked for so far and\n * unregistration stays symmetric with registration.\n */\nconst registeredById = new Map<string, MuiBundleEntry>()\n\nfunction registerEntries(entries: readonly MuiBundleEntry[]): void {\n // One mobx transaction (AGL-371): a single observer notification\n // for the whole batch instead of one per component/preset.\n runInAction(() => {\n for (const entry of entries) {\n Aglyn.components.registerComponent(entry.component, entry.schema)\n }\n for (const entry of entries) {\n if (entry.presets?.length) {\n Aglyn.components.registerPreset(entry.presets)\n }\n }\n })\n}\n\n/**\n * Registers the core MUI component library with the `@aglyn/aglyn` global\n * plugin registry (`AglynNodeRenderer`, `Aglyn.canvas`, ...). This is the\n * platform's core component bundle; feature bundles (commerce,\n * events-calendar, email) declare a dependency on it.\n *\n * `use.componentIds` narrows it to the elements the surface places\n * (AGL-3116/AGL-3141), so a published page fetches those modules and no\n * others. A caller that names nothing gets the whole library, which is what\n * the console and the besigner need and what any surface that cannot say\n * what it places must be given: an element whose component never registered\n * renders NOTHING, silently (AGL-52).\n */\nexport async function registerMuiPlugin(use?: Aglyn.PluginUse): Promise<void> {\n // Install→preset mapper (AGL-419): the console's drawer registration\n // consumes it through core, never importing this plugin.\n registerPluginInstallPresetMapper(muiPluginInstallToPreset)\n // Declared canvas elements become their own palette entries (AGL-1031).\n registerPluginInstallPresetsMapper(muiPluginInstallToPresets)\n\n const wanted = (use?.componentIds ?? Object.keys(MUI_COMPONENT_SOURCES))\n .filter((id) => id in MUI_COMPONENT_SOURCES)\n .filter((id) => !registeredById.has(id))\n const existing = Aglyn.plugins.getDependency(BUNDLE_ID)\n if (existing && !wanted.length) return\n\n const entries = wanted.length ? await loadMuiBundle(wanted) : []\n for (const entry of entries) {\n registeredById.set(entry.schema.$id as string, entry)\n }\n\n // The dependency is added even when this page places nothing of it: a\n // feature bundle declares mui as a dependency and stays WAITING — its own\n // components never registering — until mui is in the manager.\n //\n // Re-read after the imports rather than trusting the check above: the\n // manager runs `load()` from `addDependency` synchronously, so the first\n // caller to get here creates the dependency and every later one takes the\n // branch that registers what it added into a bundle already LOADED.\n if (Aglyn.plugins.getDependency(BUNDLE_ID)) {\n if (entries.length) registerEntries(entries)\n return\n }\n\n Aglyn.plugins.addDependency({\n $id: BUNDLE_ID,\n displayName: 'Material UI',\n description: 'Material UI elements',\n title: 'Material UI',\n dependencies: {},\n load(): void {\n registerEntries([...registeredById.values()])\n },\n destroy(): void {\n const entries = [...registeredById.values()]\n runInAction(() => {\n for (const entry of entries) {\n if (entry.presets?.length) {\n Aglyn.components.unregisterPreset(\n entry.presets.map((preset) => preset.$id),\n )\n }\n }\n for (const entry of entries) {\n Aglyn.components.unregisterComponent(entry.schema.$id)\n }\n })\n },\n })\n}\n"],"names":["registerPluginInstallPresetMapper","registerPluginInstallPresetsMapper","muiPluginInstallToPreset","muiPluginInstallToPresets","Aglyn","runInAction","BUNDLE_ID","tierLoad","elementTier","inTier","name","then","tier","CORE_ELEMENTS","viaTier","appBar","toolbar","layoutSlot","documentRoot","section","container","box","stack","grid","paper","typography","inlineText","button","screenLink","linkBox","image","icon","list","listItem","listItemText","blocks","dataTable","collectionEntries","collectionEntryBody","collectionRelated","collectionShare","collectionEntryMeta","collectionEntryAuthor","collectionAuthorProfile","collectionCategories","collectionSearch","video","languageSwitcher","reusableInstance","navMenu","drawer","product","plugin","customHtml","searchBox","markdown","card","accordion","tabs","imageList","pagination","breadcrumbs","themeModeSwitcher","MUI_COMPONENT_SOURCES","muiAppBar","module","component","schema","presets","muiToolbar","muiTypography","muiInlineText","muiButton","muiContainer","muiList","muiListItem","muiListItemText","videoEmbed","socialLinks","prepare","contentAuthorProfile","muiScreenLink","muiLinkBox","muiNavMenu","muiMegaMenu","muiDrawer","muiDrawerToggle","marketplacePlugin","tableOfContents","muiStack","muiBox","div","muiGrid","muiPaper","muiCard","muiCardHeader","muiCardContent","muiCardActions","muiAccordion","muiAccordionSummary","muiAccordionDetails","muiTabs","muiTabPanel","muiImageList","muiImageListItem","muiPagination","muiBreadcrumbs","loadMuiBundle","componentIds","ids","Object","keys","filter","id","pending","Map","modules","Promise","all","map","source","load","get","set","everything","undefined","prepared","Set","index","mod","has","add","resolve","catch","registeredById","registerEntries","entries","entry","components","registerComponent","length","registerPreset","registerMuiPlugin","use","wanted","existing","plugins","getDependency","$id","addDependency","displayName","description","title","dependencies","values","destroy","unregisterPreset","preset","unregisterComponent"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,iCAAiC,EACjCC,kCAAkC,QAC7B,eAAc;AACrB,SACEC,wBAAwB,EACxBC,yBAAyB,QACpB,yCAAqC;AAC5C,YAAYC,WAAW,eAAc;AACrC,SAASC,WAAW,QAAQ,OAAM;AAClC,SAASC,SAAS,QAAQ,+BAA2B;AAkBrD;;;;;;;CAOC,GACD,IAAIC;AACJ,MAAMC,cAAc,IACjBD,mBAAAA,WAAAA,WAAa,MAAM,CAAC;AACvB,MAAME,SACJ,CAACC,OACD,IACEF,cAAcG,IAAI,CAChB,CAACC,OAAkCA,KAAKC,aAAa,CAACH,KAAK;AAEjE,MAAMI,UACJ,CAACJ,OACD,IACEF,cAAcG,IAAI,CAAC,CAACC,OAAwBA,IAAI,CAACF,KAAK;AAE1D,MAAMK,SAASN,OAAO;AACtB,MAAMO,UAAUP,OAAO;AACvB,MAAMQ,aAAaR,OAAO;AAC1B,MAAMS,eAAeT,OAAO;AAC5B,MAAMU,UAAUV,OAAO;AACvB,MAAMW,YAAYX,OAAO;AACzB,MAAMY,MAAMZ,OAAO;AACnB,MAAMa,QAAQb,OAAO;AACrB,MAAMc,OAAOd,OAAO;AACpB,MAAMe,QAAQf,OAAO;AACrB,MAAMgB,aAAahB,OAAO;AAC1B,MAAMiB,aAAajB,OAAO;AAC1B,MAAMkB,SAASlB,OAAO;AACtB,MAAMmB,aAAanB,OAAO;AAC1B,MAAMoB,UAAUpB,OAAO;AACvB,MAAMqB,QAAQrB,OAAO;AACrB,MAAMsB,OAAOtB,OAAO;AAEpB,MAAMuB,OAAOlB,QAAQ;AACrB,MAAMmB,WAAWnB,QAAQ;AACzB,MAAMoB,eAAepB,QAAQ;AAC7B,MAAMqB,SAASrB,QAAQ;AACvB,MAAMsB,YAAYtB,QAAQ;AAC1B,MAAMuB,oBAAoBvB,QAAQ;AAClC,MAAMwB,sBAAsBxB,QAAQ;AACpC,MAAMyB,oBAAoBzB,QAAQ;AAClC,MAAM0B,kBAAkB1B,QAAQ;AAChC,MAAM2B,sBAAsB3B,QAAQ;AACpC,MAAM4B,wBAAwB5B,QAAQ;AACtC,MAAM6B,0BAA0B7B,QAAQ;AACxC,MAAM8B,uBAAuB9B,QAAQ;AACrC,MAAM+B,mBAAmB/B,QAAQ;AACjC,MAAMgC,QAAQhC,QAAQ;AACtB,MAAMiC,mBAAmBjC,QAAQ;AACjC,MAAMkC,mBAAmBlC,QAAQ;AACjC,MAAMmC,UAAUnC,QAAQ;AACxB,MAAMoC,SAASpC,QAAQ;AACvB,MAAMqC,UAAUrC,QAAQ;AACxB,MAAMsC,SAAStC,QAAQ;AACvB,MAAMuC,aAAavC,QAAQ;AAC3B,MAAMwC,YAAYxC,QAAQ;AAC1B,MAAMyC,WAAWzC,QAAQ;AACzB,MAAM0C,OAAO1C,QAAQ;AACrB,MAAM2C,YAAY3C,QAAQ;AAC1B,MAAM4C,OAAO5C,QAAQ;AACrB,MAAM6C,YAAY7C,QAAQ;AAC1B,MAAM8C,aAAa9C,QAAQ;AAC3B,MAAM+C,cAAc/C,QAAQ;AAC5B,MAAMgD,oBAAoBhD,QAAQ;AAsClC;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMiD,wBAET;IACFC,WAAW;QACTC,QAAQlD;QACRmD,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAC,YAAY;QACVJ,QAAQjD;QACRkD,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAE,eAAe;QACbL,QAAQxC;QACRyC,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA,wEAAwE;IACxE,0EAA0E;IAC1E,wCAAwC;IACxCG,eAAe;QACbN,QAAQvC;QACRwC,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAI,WAAW;QACTP,QAAQtC;QACRuC,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAK,cAAc;QACZR,QAAQ7C;QACR8C,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAnD,YAAY;QACVgD,QAAQhD;QACRiD,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAM,SAAS;QACPT,QAAQjC;QACRkC,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAO,aAAa;QACXV,QAAQhC;QACRiC,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAQ,iBAAiB;QACfX,QAAQ/B;QACRgC,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA,2DAA2D;IAC3DS,YAAY;QACVZ,QAAQ9B;QACR+B,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAU,aAAa;QACXb,QAAQ9B;QACR+B,WAAW;QACXC,QAAQ;IACV;IACA,uEAAuE;IACvE,6DAA6D;IAC7D/B,WAAW;QACT6B,QAAQ7B;QACR8B,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA,sEAAsE;IACtE,8CAA8C;IAC9C/B,mBAAmB;QACjB4B,QAAQ5B;QACR6B,WAAW;QACXC,QAAQ;QACRC,SAAS;QACTW,SAAS;IACX;IACAzC,qBAAqB;QACnB2B,QAAQ3B;QACR4B,WAAW;QACXC,QAAQ;IACV;IACA5B,mBAAmB;QACjB0B,QAAQ1B;QACR2B,WAAW;QACXC,QAAQ;IACV;IACA3B,iBAAiB;QACfyB,QAAQzB;QACR0B,WAAW;QACXC,QAAQ;IACV;IACA1B,qBAAqB;QACnBwB,QAAQxB;QACRyB,WAAW;QACXC,QAAQ;IACV;IACA,sEAAsE;IACtE,yEAAyE;IACzEzB,uBAAuB;QACrBuB,QAAQvB;QACRwB,WAAW;QACXC,QAAQ;IACV;IACA,sEAAsE;IACtE,2EAA2E;IAC3Ea,sBAAsB;QACpBf,QAAQtB;QACRuB,WAAW;QACXC,QAAQ;IACV;IACA,4EAA4E;IAC5EvB,sBAAsB;QACpBqB,QAAQrB;QACRsB,WAAW;QACXC,QAAQ;IACV;IACA,0EAA0E;IAC1E,wEAAwE;IACxEtB,kBAAkB;QAChBoB,QAAQpB;QACRqB,WAAW;QACXC,QAAQ;IACV;IACArC,OAAO;QACLmC,QAAQnC;QACRoC,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAtB,OAAO;QACLmB,QAAQnB;QACRoB,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACArC,MAAM;QACJkC,QAAQlC;QACRmC,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA,sDAAsD;IACtD,+DAA+D;IAC/DrB,kBAAkB;QAChBkB,QAAQlB;QACRmB,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACApB,kBAAkB;QAChBiB,QAAQjB;QACRkB,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAa,eAAe;QACbhB,QAAQrC;QACRsC,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA,wEAAwE;IACxE,wEAAwE;IACxE,sBAAsB;IACtBc,YAAY;QACVjB,QAAQpC;QACRqC,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA,wEAAwE;IACxEe,YAAY;QACVlB,QAAQhB;QACRiB,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAgB,aAAa;QACXnB,QAAQhB;QACRiB,WAAW;QACXC,QAAQ;IACV;IACAkB,WAAW;QACTpB,QAAQf;QACRgB,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAkB,iBAAiB;QACfrB,QAAQf;QACRgB,WAAW;QACXC,QAAQ;IACV;IACAhB,SAAS;QACPc,QAAQd;QACRe,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAmB,mBAAmB;QACjBtB,QAAQb;QACRc,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA,eAAe;QACbH,QAAQZ;QACRa,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAd,WAAW;QACTW,QAAQX;QACRY,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA,0EAA0E;IAC1E,+DAA+D;IAC/Db,UAAU;QACRU,QAAQV;QACRW,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAoB,iBAAiB;QACfvB,QAAQV;QACRW,WAAW;QACXC,QAAQ;IACV;IACAhD,SAAS;QACP8C,QAAQ9C;QACR+C,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAqB,UAAU;QACRxB,QAAQ3C;QACR4C,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA,0CAA0C;IAC1CsB,QAAQ;QACNzB,QAAQ5C;QACR6C,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA,qEAAqE;IACrE,iEAAiE;IACjE,0EAA0E;IAC1EuB,KAAK;QACH1B,QAAQ/C;QACRgD,WAAW;QACXC,QAAQ;IACV;IACAyB,SAAS;QACP3B,QAAQ1C;QACR2C,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAyB,UAAU;QACR5B,QAAQzC;QACR0C,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA0B,SAAS;QACP7B,QAAQT;QACRU,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA2B,eAAe;QACb9B,QAAQT;QACRU,WAAW;QACXC,QAAQ;IACV;IACA6B,gBAAgB;QACd/B,QAAQT;QACRU,WAAW;QACXC,QAAQ;IACV;IACA8B,gBAAgB;QACdhC,QAAQT;QACRU,WAAW;QACXC,QAAQ;IACV;IACA+B,cAAc;QACZjC,QAAQR;QACRS,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACA+B,qBAAqB;QACnBlC,QAAQR;QACRS,WAAW;QACXC,QAAQ;IACV;IACAiC,qBAAqB;QACnBnC,QAAQR;QACRS,WAAW;QACXC,QAAQ;IACV;IACAkC,SAAS;QACPpC,QAAQP;QACRQ,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAkC,aAAa;QACXrC,QAAQP;QACRQ,WAAW;QACXC,QAAQ;IACV;IACAoC,cAAc;QACZtC,QAAQN;QACRO,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAoC,kBAAkB;QAChBvC,QAAQN;QACRO,WAAW;QACXC,QAAQ;IACV;IACAsC,eAAe;QACbxC,QAAQL;QACRM,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAsC,gBAAgB;QACdzC,QAAQJ;QACRK,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;IACAN,mBAAmB;QACjBG,QAAQH;QACRI,WAAW;QACXC,QAAQ;QACRC,SAAS;IACX;AACF,EAAC;AAED;;;;;;;;;;CAUC,GACD,OAAO,eAAeuC,cACpBC,YAAgC;IAEhC,MAAMC,MAAM,CAACD,uBAAAA,eAAgBE,OAAOC,IAAI,CAAChD,wBAAwBiD,MAAM,CACrE,CAACC,KAAOA,MAAMlD;IAEhB,mEAAmE;IACnE,sEAAsE;IACtE,MAAMmD,UAAU,IAAIC;IAIpB,MAAMC,UAAU,MAAMC,QAAQC,GAAG,CAC/BT,IAAIU,GAAG,CAAC,CAACN;QACP,MAAMO,SAASzD,qBAAqB,CAACkD,GAAG;QACxC,IAAIQ,OAAOP,QAAQQ,GAAG,CAACF,OAAOvD,MAAM;QACpC,IAAI,CAACwD,MAAM;YACTA,OAAOD,OAAOvD,MAAM;YACpBiD,QAAQS,GAAG,CAACH,OAAOvD,MAAM,EAAEwD;QAC7B;QACA,OAAOA;IACT;IAEF,2EAA2E;IAC3E,MAAMG,aAAahB,iBAAiBiB;IACpC,MAAMC,WAAW,IAAIC;IACrB,MAAMV,QAAQC,GAAG,CACfT,IAAIU,GAAG,CAAC,CAACN,IAAIe;QACX,MAAMR,SAASzD,qBAAqB,CAACkD,GAAG;QACxC,MAAMgB,MAAMb,OAAO,CAACY,MAAM;QAC1B,IAAI,CAACR,OAAOzC,OAAO,IAAI+C,SAASI,GAAG,CAACD,MAAM,OAAOJ;QACjDC,SAASK,GAAG,CAACF;QACb,MAAMlD,UAAUkD,GAAG,CAACT,OAAOzC,OAAO,CAAC;QAGnC,oEAAoE;QACpE,iEAAiE;QACjE,iEAAiE;QACjE,OAAOsC,QAAQe,OAAO,CAACrD,2BAAAA,QAAU6C,aAAaS,KAAK,CAAC,IAAMR;IAC5D;IAEF,OAAOhB,IAAIU,GAAG,CAAC,CAACN,IAAIe;QAClB,MAAMR,SAASzD,qBAAqB,CAACkD,GAAG;QACxC,MAAMgB,MAAMb,OAAO,CAACY,MAAM;QAC1B,OAAO;YACL9D,WAAW+D,GAAG,CAACT,OAAOtD,SAAS,CAAC;YAChCC,QAAQ8D,GAAG,CAACT,OAAOrD,MAAM,CAAC;WACtBqD,OAAOpD,OAAO,GACd;YAAEA,SAAS6D,GAAG,CAACT,OAAOpD,OAAO,CAAC;QAAyB,IACvD,CAAC;IAET;AACF;AAEA;;;;;;;CAOC,GACD,MAAMkE,iBAAiB,IAAInB;AAE3B,SAASoB,gBAAgBC,OAAkC;IACzD,iEAAiE;IACjE,2DAA2D;IAC3DnI,YAAY;QACV,KAAK,MAAMoI,SAASD,QAAS;YAC3BpI,MAAMsI,UAAU,CAACC,iBAAiB,CAACF,MAAMvE,SAAS,EAAEuE,MAAMtE,MAAM;QAClE;QACA,KAAK,MAAMsE,SAASD,QAAS;gBACvBC;YAAJ,KAAIA,iBAAAA,MAAMrE,OAAO,qBAAbqE,eAAeG,MAAM,EAAE;gBACzBxI,MAAMsI,UAAU,CAACG,cAAc,CAACJ,MAAMrE,OAAO;YAC/C;QACF;IACF;AACF;AAEA;;;;;;;;;;;;CAYC,GACD,OAAO,eAAe0E,kBAAkBC,GAAqB;;IAC3D,qEAAqE;IACrE,yDAAyD;IACzD/I,kCAAkCE;IAClC,wEAAwE;IACxED,mCAAmCE;IAEnC,MAAM6I,SAAS,SAACD,uBAAAA,IAAKnC,YAAY,mBAAIE,OAAOC,IAAI,CAAChD,wBAC9CiD,MAAM,CAAC,CAACC,KAAOA,MAAMlD,uBACrBiD,MAAM,CAAC,CAACC,KAAO,CAACqB,eAAeJ,GAAG,CAACjB;IACtC,MAAMgC,WAAW7I,MAAM8I,OAAO,CAACC,aAAa,CAAC7I;IAC7C,IAAI2I,YAAY,CAACD,OAAOJ,MAAM,EAAE;IAEhC,MAAMJ,UAAUQ,OAAOJ,MAAM,GAAG,MAAMjC,cAAcqC,UAAU,EAAE;IAChE,KAAK,MAAMP,SAASD,QAAS;QAC3BF,eAAeX,GAAG,CAACc,MAAMtE,MAAM,CAACiF,GAAG,EAAYX;IACjD;IAEA,sEAAsE;IACtE,0EAA0E;IAC1E,8DAA8D;IAC9D,EAAE;IACF,sEAAsE;IACtE,yEAAyE;IACzE,0EAA0E;IAC1E,oEAAoE;IACpE,IAAIrI,MAAM8I,OAAO,CAACC,aAAa,CAAC7I,YAAY;QAC1C,IAAIkI,QAAQI,MAAM,EAAEL,gBAAgBC;QACpC;IACF;IAEApI,MAAM8I,OAAO,CAACG,aAAa,CAAC;QAC1BD,KAAK9I;QACLgJ,aAAa;QACbC,aAAa;QACbC,OAAO;QACPC,cAAc,CAAC;QACfhC;YACEc,gBAAgB;mBAAID,eAAeoB,MAAM;aAAG;QAC9C;QACAC;YACE,MAAMnB,UAAU;mBAAIF,eAAeoB,MAAM;aAAG;YAC5CrJ,YAAY;gBACV,KAAK,MAAMoI,SAASD,QAAS;wBACvBC;oBAAJ,KAAIA,iBAAAA,MAAMrE,OAAO,qBAAbqE,eAAeG,MAAM,EAAE;wBACzBxI,MAAMsI,UAAU,CAACkB,gBAAgB,CAC/BnB,MAAMrE,OAAO,CAACmD,GAAG,CAAC,CAACsC,SAAWA,OAAOT,GAAG;oBAE5C;gBACF;gBACA,KAAK,MAAMX,SAASD,QAAS;oBAC3BpI,MAAMsI,UAAU,CAACoB,mBAAmB,CAACrB,MAAMtE,MAAM,CAACiF,GAAG;gBACvD;YACF;QACF;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/mui/src/lib/plugin.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 {\n registerPluginInstallPresetMapper,\n registerPluginInstallPresetsMapper,\n} from '@aglyn/aglyn'\nimport {\n muiPluginInstallToPreset,\n muiPluginInstallToPresets,\n} from './components/plugin-install-presets'\nimport * as Aglyn from '@aglyn/aglyn'\nimport { runInAction } from 'mobx'\nimport { BUNDLE_ID } from './constants/bundle-common'\n\n/**\n * One thunk per component module, named here because several ids share one:\n * `card.tsx` and `accordion.tsx` each export several elements, and a module is\n * imported once however many of its components a surface asks for.\n *\n * Every thunk goes through the element tier (AGL-3401). The common elements\n * are part of it; the rest are `import()`s written inside it, so they can\n * rely on what it loaded instead of each carrying a copy. `element-tier.ts`\n * has the reasoning, and which elements are which.\n */\ntype ElementTier = typeof import('./element-tier')\ntype TierElement = keyof ElementTier['CORE_ELEMENTS']\ntype LazyElement = Exclude<keyof ElementTier, 'CORE_ELEMENTS'>\n\ntype ElementModule = Promise<Record<string, unknown>>\n\n/**\n * One load of the tier, however many thunks ask at once. The bundler shares\n * a module across concurrent imports anyway; a loader that hands out a\n * module while it is still evaluating does not — jiti, which the AI palette\n * and page-axe generators load this bundle through, resolved the second of\n * sixty concurrent imports to the tier's exports before `CORE_ELEMENTS` was\n * assigned.\n */\nlet tierLoad: Promise<ElementTier> | undefined\nconst elementTier = (): Promise<ElementTier> =>\n (tierLoad ??= import('./element-tier'))\nconst inTier =\n (name: TierElement): MuiComponentSource['module'] =>\n () =>\n elementTier().then(\n (tier): Record<string, unknown> => tier.CORE_ELEMENTS[name],\n )\nconst viaTier =\n (name: LazyElement): MuiComponentSource['module'] =>\n () =>\n elementTier().then((tier): ElementModule => tier[name]())\n\nconst appBar = inTier('appBar')\nconst toolbar = inTier('toolbar')\nconst layoutSlot = inTier('layoutSlot')\nconst documentRoot = inTier('documentRoot')\nconst section = inTier('section')\nconst container = inTier('container')\nconst box = inTier('box')\nconst stack = inTier('stack')\nconst grid = inTier('grid')\nconst paper = inTier('paper')\nconst typography = inTier('typography')\nconst inlineText = inTier('inlineText')\nconst button = inTier('button')\nconst screenLink = inTier('screenLink')\nconst linkBox = inTier('linkBox')\nconst image = inTier('image')\nconst icon = inTier('icon')\n\nconst list = viaTier('list')\nconst listItem = viaTier('listItem')\nconst listItemText = viaTier('listItemText')\nconst blocks = viaTier('blocks')\nconst dataTable = viaTier('dataTable')\nconst collectionEntries = viaTier('collectionEntries')\nconst collectionEntryBody = viaTier('collectionEntryBody')\nconst collectionRelated = viaTier('collectionRelated')\nconst collectionShare = viaTier('collectionShare')\nconst collectionEntryMeta = viaTier('collectionEntryMeta')\nconst collectionEntryAuthor = viaTier('collectionEntryAuthor')\nconst collectionAuthorProfile = viaTier('collectionAuthorProfile')\nconst collectionCategories = viaTier('collectionCategories')\nconst collectionSearch = viaTier('collectionSearch')\nconst video = viaTier('video')\nconst languageSwitcher = viaTier('languageSwitcher')\nconst reusableInstance = viaTier('reusableInstance')\nconst navMenu = viaTier('navMenu')\nconst drawer = viaTier('drawer')\nconst product = viaTier('product')\nconst plugin = viaTier('plugin')\nconst customHtml = viaTier('customHtml')\nconst searchBox = viaTier('searchBox')\nconst markdown = viaTier('markdown')\nconst card = viaTier('card')\nconst accordion = viaTier('accordion')\nconst tabs = viaTier('tabs')\nconst imageList = viaTier('imageList')\nconst pagination = viaTier('pagination')\nconst breadcrumbs = viaTier('breadcrumbs')\nconst themeModeSwitcher = viaTier('themeModeSwitcher')\n\n/** One entry of the bundle: what the registry is handed for a component. */\nexport interface MuiBundleEntry {\n component: any\n schema: Aglyn.ComponentSchema<any>\n presets?: Aglyn.PresetSchema[]\n}\n\n/**\n * Where a component id's code lives, and what it is called there (AGL-3141).\n *\n * An id names a module AND an export on it, never a module alone: several\n * modules export more than one element, and the registry needs the component,\n * its schema and — for the element that carries them — its presets by name.\n */\nexport interface MuiComponentSource {\n /** The module, as a thunk, so the bundler gives it a chunk of its own. */\n module: () => Promise<Record<string, unknown>>\n /** The component's export name on that module. */\n component: string\n /** Its schema's export name. */\n schema: string\n /** The export carrying its presets, for the element that ships them. */\n presets?: string\n /**\n * An export that loads what SOME instances of the element render, before\n * any of them does (AGL-3438) — `(everything: boolean) => Promise | void`.\n *\n * For a module the element fetches only when an instance's props ask for\n * it, the way Collection Entries fetches its search box. The element alone\n * knows when a render must not wait for that fetch; `everything` tells it\n * the whole library is loading, which is what the console and the besigner\n * ask for. The bundle is handed over once the load it returns has settled.\n */\n prepare?: string\n}\n\n/**\n * Every component this bundle can register (AGL-140, AGL-3141).\n *\n * One entry per component keeps register/unregister symmetric — the old\n * hand-maintained lists had drifted, and several components were never\n * unregistered on destroy. It replaces a single array built from sixty static\n * imports, which put every element on every published page while the page\n * rendered about nineteen of them.\n *\n * Exported so the bundle is assertable (AGL-1201): duplicate component or\n * preset ids collapse silently inside the registry's keyed records, so they\n * can only be caught before registration.\n */\nexport const MUI_COMPONENT_SOURCES: Readonly<\n Record<string, MuiComponentSource>\n> = {\n muiAppBar: {\n module: appBar,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiToolbar: {\n module: toolbar,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiTypography: {\n module: typography,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // The inline text run (AGL-1235): one styled phrase inside a sentence.\n // Typography also holds elements now (AGL-3672), but a run is still the\n // element that flows and wraps as part of the line.\n muiInlineText: {\n module: inlineText,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiButton: {\n module: button,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiContainer: {\n module: container,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n layoutSlot: {\n module: layoutSlot,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiList: {\n module: list,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiListItem: {\n module: listItem,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiListItemText: {\n module: listItemText,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // form, formField moved to @aglyn/plugins-forms (AGL-395).\n videoEmbed: {\n module: blocks,\n component: 'VideoEmbed',\n schema: 'videoEmbedSchema',\n presets: 'blockPresets',\n },\n socialLinks: {\n module: blocks,\n component: 'SocialLinks',\n schema: 'socialLinksSchema',\n },\n // A real data grid (AGL-2543): the feature matrix a comparison page is\n // built around, which the palette had no element for at all.\n dataTable: {\n module: dataTable,\n component: 'default',\n schema: 'dataTableSchema',\n presets: 'dataTablePresets',\n },\n // Content collections (AGL-551/582): entries repeater, markdown entry\n // body, related posts, share bar, entry meta.\n collectionEntries: {\n module: collectionEntries,\n component: 'CollectionEntries',\n schema: 'collectionEntriesSchema',\n presets: 'collectionPresets',\n prepare: 'prepareEntriesSearch',\n },\n collectionEntryBody: {\n module: collectionEntryBody,\n component: 'CollectionEntryBody',\n schema: 'collectionEntryBodySchema',\n },\n collectionRelated: {\n module: collectionRelated,\n component: 'CollectionRelated',\n schema: 'collectionRelatedSchema',\n },\n collectionShare: {\n module: collectionShare,\n component: 'CollectionShare',\n schema: 'collectionShareSchema',\n },\n collectionEntryMeta: {\n module: collectionEntryMeta,\n component: 'CollectionEntryMeta',\n schema: 'collectionEntryMetaSchema',\n },\n // The author card that closes an article (AGL-2486): the byline block\n // prints a name, and the record behind it also has a portrait and a bio.\n collectionEntryAuthor: {\n module: collectionEntryAuthor,\n component: 'CollectionEntryAuthor',\n schema: 'collectionEntryAuthorSchema',\n },\n // The subject of an author's own page (AGL-2518): the same person the\n // card above draws as a footnote, with the role fields it has no room for.\n contentAuthorProfile: {\n module: collectionAuthorProfile,\n component: 'ContentAuthorProfile',\n schema: 'contentAuthorProfileSchema',\n },\n // Category pills (AGL-1321): real anchors to /{collection}/category/{slug}.\n collectionCategories: {\n module: collectionCategories,\n component: 'CollectionCategories',\n schema: 'collectionCategoriesSchema',\n },\n // The toolbar search box (AGL-1516): the entries block's own field cannot\n // leave it, so the frame's pills-left / search-right row needs a block.\n collectionSearch: {\n module: collectionSearch,\n component: 'CollectionSearch',\n schema: 'collectionSearchSchema',\n },\n image: {\n module: image,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n video: {\n module: video,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n icon: {\n module: icon,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // booking moved to @aglyn/plugins-bookings (AGL-395).\n // eventList moved to @aglyn/plugins-events-calendar (AGL-313).\n languageSwitcher: {\n module: languageSwitcher,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n reusableInstance: {\n module: reusableInstance,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiScreenLink: {\n module: screenLink,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // The linking container (AGL-1231): every other link element is a leaf,\n // so a tile whose icon and description also belong to the target had no\n // way to be authored.\n muiLinkBox: {\n module: linkBox,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // Nav menu system (AGL-562): dropdown, mega menu, drawer + menu button.\n muiNavMenu: {\n module: navMenu,\n component: 'default',\n schema: 'navMenuSchema',\n presets: 'navMenuPresets',\n },\n muiMegaMenu: {\n module: navMenu,\n component: 'MegaMenu',\n schema: 'megaMenuSchema',\n },\n muiDrawer: {\n module: drawer,\n component: 'default',\n schema: 'drawerSchema',\n presets: 'drawerPresets',\n },\n muiDrawerToggle: {\n module: drawer,\n component: 'DrawerToggle',\n schema: 'drawerToggleSchema',\n },\n product: {\n module: product,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n marketplacePlugin: {\n module: plugin,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n 'custom-html': {\n module: customHtml,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n searchBox: {\n module: searchBox,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // Long-form documents (AGL-1162): one markdown element carrying the whole\n // page, and an \"On this page\" aside derived from its headings.\n markdown: {\n module: markdown,\n component: 'Markdown',\n schema: 'markdownSchema',\n presets: 'markdownPresets',\n },\n tableOfContents: {\n module: markdown,\n component: 'TableOfContents',\n schema: 'tableOfContentsSchema',\n },\n section: {\n module: section,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiStack: {\n module: stack,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // Layout & surface primitives (AGL-1201).\n muiBox: {\n module: box,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n // The canvas ROOT (AGL-2486): registered so the Document layer has a\n // schema — an element picker — instead of falling through to the\n // renderer's unstyled div. No preset: it is not an element anybody drops.\n div: {\n module: documentRoot,\n component: 'default',\n schema: 'schema',\n },\n muiGrid: {\n module: grid,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiPaper: {\n module: paper,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiCard: {\n module: card,\n component: 'default',\n schema: 'cardSchema',\n presets: 'cardPresets',\n },\n muiCardHeader: {\n module: card,\n component: 'CardHeaderElement',\n schema: 'cardHeaderSchema',\n },\n muiCardContent: {\n module: card,\n component: 'CardContentElement',\n schema: 'cardContentSchema',\n },\n muiCardActions: {\n module: card,\n component: 'CardActionsElement',\n schema: 'cardActionsSchema',\n },\n muiAccordion: {\n module: accordion,\n component: 'default',\n schema: 'accordionSchema',\n presets: 'accordionPresets',\n },\n muiAccordionSummary: {\n module: accordion,\n component: 'AccordionSummaryElement',\n schema: 'accordionSummarySchema',\n },\n muiAccordionDetails: {\n module: accordion,\n component: 'AccordionDetailsElement',\n schema: 'accordionDetailsSchema',\n },\n muiTabs: {\n module: tabs,\n component: 'default',\n schema: 'tabsSchema',\n presets: 'tabsPresets',\n },\n muiTabPanel: {\n module: tabs,\n component: 'TabPanelElement',\n schema: 'tabPanelSchema',\n },\n muiImageList: {\n module: imageList,\n component: 'default',\n schema: 'imageListSchema',\n presets: 'imageListPresets',\n },\n muiImageListItem: {\n module: imageList,\n component: 'ImageListItemElement',\n schema: 'imageListItemSchema',\n },\n muiPagination: {\n module: pagination,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n muiBreadcrumbs: {\n module: breadcrumbs,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n themeModeSwitcher: {\n module: themeModeSwitcher,\n component: 'default',\n schema: 'schema',\n presets: 'presets',\n },\n}\n\n/**\n * The bundle entries for `componentIds` — every component when none are\n * named, which is what the console and the besigner ask for because their\n * palette shows every element.\n *\n * Both paths go through the same map, so there is one statement of where a\n * component comes from. An id the map does not know is dropped rather than\n * resolved to an undefined component: a page whose document carries an\n * element this bundle does not own is a document for another plugin's\n * element, not a reason to register a blank.\n */\nexport async function loadMuiBundle(\n componentIds?: readonly string[],\n): Promise<MuiBundleEntry[]> {\n const ids = (componentIds ?? Object.keys(MUI_COMPONENT_SOURCES)).filter(\n (id) => id in MUI_COMPONENT_SOURCES,\n )\n // Keyed on the THUNK, so a module that exports several elements is\n // imported once for all the ids that name it rather than once per id.\n const pending = new Map<\n MuiComponentSource['module'],\n Promise<Record<string, unknown>>\n >()\n const modules = await Promise.all(\n ids.map((id) => {\n const source = MUI_COMPONENT_SOURCES[id] as MuiComponentSource\n let load = pending.get(source.module)\n if (!load) {\n load = source.module()\n pending.set(source.module, load)\n }\n return load\n }),\n )\n // Each module's on-demand parts, once per module, before anything renders.\n const everything = componentIds === undefined\n const prepared = new Set<unknown>()\n await Promise.all(\n ids.map((id, index) => {\n const source = MUI_COMPONENT_SOURCES[id] as MuiComponentSource\n const mod = modules[index] as Record<string, unknown>\n if (!source.prepare || prepared.has(mod)) return undefined\n prepared.add(mod)\n const prepare = mod[source.prepare] as\n | ((everything: boolean) => Promise<unknown> | void)\n | undefined\n // A failed fetch is the render's to report, not the registration's:\n // the element asks again when it renders, and a block that still\n // cannot have it fails alone instead of taking the page with it.\n return Promise.resolve(prepare?.(everything)).catch(() => undefined)\n }),\n )\n return ids.map((id, index) => {\n const source = MUI_COMPONENT_SOURCES[id] as MuiComponentSource\n const mod = modules[index] as Record<string, unknown>\n return {\n component: mod[source.component],\n schema: mod[source.schema] as Aglyn.ComponentSchema<any>,\n ...(source.presets\n ? { presets: mod[source.presets] as Aglyn.PresetSchema[] }\n : {}),\n }\n })\n}\n\n/**\n * Every component registered so far, by id.\n *\n * A second page places elements the first did not, and reaches this bundle\n * again with them; the map is what tells the two apart, and what `load` and\n * `destroy` read so a reload registers everything asked for so far and\n * unregistration stays symmetric with registration.\n */\nconst registeredById = new Map<string, MuiBundleEntry>()\n\nfunction registerEntries(entries: readonly MuiBundleEntry[]): void {\n // One mobx transaction (AGL-371): a single observer notification\n // for the whole batch instead of one per component/preset.\n runInAction(() => {\n for (const entry of entries) {\n Aglyn.components.registerComponent(entry.component, entry.schema)\n }\n for (const entry of entries) {\n if (entry.presets?.length) {\n Aglyn.components.registerPreset(entry.presets)\n }\n }\n })\n}\n\n/**\n * Registers the core MUI component library with the `@aglyn/aglyn` global\n * plugin registry (`AglynNodeRenderer`, `Aglyn.canvas`, ...). This is the\n * platform's core component bundle; feature bundles (commerce,\n * events-calendar, email) declare a dependency on it.\n *\n * `use.componentIds` narrows it to the elements the surface places\n * (AGL-3116/AGL-3141), so a published page fetches those modules and no\n * others. A caller that names nothing gets the whole library, which is what\n * the console and the besigner need and what any surface that cannot say\n * what it places must be given: an element whose component never registered\n * renders NOTHING, silently (AGL-52).\n */\nexport async function registerMuiPlugin(use?: Aglyn.PluginUse): Promise<void> {\n // Install→preset mapper (AGL-419): the console's drawer registration\n // consumes it through core, never importing this plugin.\n registerPluginInstallPresetMapper(muiPluginInstallToPreset)\n // Declared canvas elements become their own palette entries (AGL-1031).\n registerPluginInstallPresetsMapper(muiPluginInstallToPresets)\n\n const wanted = (use?.componentIds ?? Object.keys(MUI_COMPONENT_SOURCES))\n .filter((id) => id in MUI_COMPONENT_SOURCES)\n .filter((id) => !registeredById.has(id))\n const existing = Aglyn.plugins.getDependency(BUNDLE_ID)\n if (existing && !wanted.length) return\n\n const entries = wanted.length ? await loadMuiBundle(wanted) : []\n for (const entry of entries) {\n registeredById.set(entry.schema.$id as string, entry)\n }\n\n // The dependency is added even when this page places nothing of it: a\n // feature bundle declares mui as a dependency and stays WAITING — its own\n // components never registering — until mui is in the manager.\n //\n // Re-read after the imports rather than trusting the check above: the\n // manager runs `load()` from `addDependency` synchronously, so the first\n // caller to get here creates the dependency and every later one takes the\n // branch that registers what it added into a bundle already LOADED.\n if (Aglyn.plugins.getDependency(BUNDLE_ID)) {\n if (entries.length) registerEntries(entries)\n return\n }\n\n Aglyn.plugins.addDependency({\n $id: BUNDLE_ID,\n displayName: 'Material UI',\n description: 'Material UI elements',\n title: 'Material UI',\n dependencies: {},\n load(): void {\n registerEntries([...registeredById.values()])\n },\n destroy(): void {\n const entries = [...registeredById.values()]\n runInAction(() => {\n for (const entry of entries) {\n if (entry.presets?.length) {\n Aglyn.components.unregisterPreset(\n entry.presets.map((preset) => preset.$id),\n )\n }\n }\n for (const entry of entries) {\n Aglyn.components.unregisterComponent(entry.schema.$id)\n }\n })\n },\n })\n}\n"],"names":["registerPluginInstallPresetMapper","registerPluginInstallPresetsMapper","muiPluginInstallToPreset","muiPluginInstallToPresets","Aglyn","runInAction","BUNDLE_ID","tierLoad","elementTier","inTier","name","then","tier","CORE_ELEMENTS","viaTier","appBar","toolbar","layoutSlot","documentRoot","section","container","box","stack","grid","paper","typography","inlineText","button","screenLink","linkBox","image","icon","list","listItem","listItemText","blocks","dataTable","collectionEntries","collectionEntryBody","collectionRelated","collectionShare","collectionEntryMeta","collectionEntryAuthor","collectionAuthorProfile","collectionCategories","collectionSearch","video","languageSwitcher","reusableInstance","navMenu","drawer","product","plugin","customHtml","searchBox","markdown","card","accordion","tabs","imageList","pagination","breadcrumbs","themeModeSwitcher","MUI_COMPONENT_SOURCES","muiAppBar","module","component","schema","presets","muiToolbar","muiTypography","muiInlineText","muiButton","muiContainer","muiList","muiListItem","muiListItemText","videoEmbed","socialLinks","prepare","contentAuthorProfile","muiScreenLink","muiLinkBox","muiNavMenu","muiMegaMenu","muiDrawer","muiDrawerToggle","marketplacePlugin","tableOfContents","muiStack","muiBox","div","muiGrid","muiPaper","muiCard","muiCardHeader","muiCardContent","muiCardActions","muiAccordion","muiAccordionSummary","muiAccordionDetails","muiTabs","muiTabPanel","muiImageList","muiImageListItem","muiPagination","muiBreadcrumbs","loadMuiBundle","componentIds","ids","Object","keys","filter","id","pending","Map","modules","Promise","all","map","source","load","get","set","everything","undefined","prepared","Set","index","mod","has","add","resolve","catch","registeredById","registerEntries","entries","entry","components","registerComponent","length","registerPreset","registerMuiPlugin","use","wanted","existing","plugins","getDependency","$id","addDependency","displayName","description","title","dependencies","values","destroy","unregisterPreset","preset","unregisterComponent"],"mappings":"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"}
|