@aglyn/plugins-mui 1.0.0-beta.143

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +22 -0
  3. package/package.json +47 -0
  4. package/src/index.d.ts +21 -0
  5. package/src/index.js +22 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/accordion.d.ts +96 -0
  8. package/src/lib/components/accordion.js +392 -0
  9. package/src/lib/components/accordion.js.map +1 -0
  10. package/src/lib/components/app-bar.d.ts +32 -0
  11. package/src/lib/components/app-bar.js +86 -0
  12. package/src/lib/components/app-bar.js.map +1 -0
  13. package/src/lib/components/blocks.d.ts +46 -0
  14. package/src/lib/components/blocks.js +1007 -0
  15. package/src/lib/components/blocks.js.map +1 -0
  16. package/src/lib/components/box.d.ts +47 -0
  17. package/src/lib/components/box.js +125 -0
  18. package/src/lib/components/box.js.map +1 -0
  19. package/src/lib/components/breadcrumbs.d.ts +44 -0
  20. package/src/lib/components/breadcrumbs.js +172 -0
  21. package/src/lib/components/breadcrumbs.js.map +1 -0
  22. package/src/lib/components/button.d.ts +89 -0
  23. package/src/lib/components/button.js +272 -0
  24. package/src/lib/components/button.js.map +1 -0
  25. package/src/lib/components/card.d.ts +61 -0
  26. package/src/lib/components/card.js +336 -0
  27. package/src/lib/components/card.js.map +1 -0
  28. package/src/lib/components/collection.d.ts +514 -0
  29. package/src/lib/components/collection.js +2999 -0
  30. package/src/lib/components/collection.js.map +1 -0
  31. package/src/lib/components/container.d.ts +42 -0
  32. package/src/lib/components/container.js +169 -0
  33. package/src/lib/components/container.js.map +1 -0
  34. package/src/lib/components/custom-html.d.ts +78 -0
  35. package/src/lib/components/custom-html.js +219 -0
  36. package/src/lib/components/custom-html.js.map +1 -0
  37. package/src/lib/components/data-table.d.ts +57 -0
  38. package/src/lib/components/data-table.js +216 -0
  39. package/src/lib/components/data-table.js.map +1 -0
  40. package/src/lib/components/document-root.d.ts +77 -0
  41. package/src/lib/components/document-root.js +118 -0
  42. package/src/lib/components/document-root.js.map +1 -0
  43. package/src/lib/components/drawer.d.ts +93 -0
  44. package/src/lib/components/drawer.js +566 -0
  45. package/src/lib/components/drawer.js.map +1 -0
  46. package/src/lib/components/function-controls.d.ts +66 -0
  47. package/src/lib/components/function-controls.js +207 -0
  48. package/src/lib/components/function-controls.js.map +1 -0
  49. package/src/lib/components/function-scope.d.ts +110 -0
  50. package/src/lib/components/function-scope.js +478 -0
  51. package/src/lib/components/function-scope.js.map +1 -0
  52. package/src/lib/components/function-widget.d.ts +75 -0
  53. package/src/lib/components/function-widget.js +307 -0
  54. package/src/lib/components/function-widget.js.map +1 -0
  55. package/src/lib/components/grid.d.ts +91 -0
  56. package/src/lib/components/grid.js +322 -0
  57. package/src/lib/components/grid.js.map +1 -0
  58. package/src/lib/components/icon.d.ts +54 -0
  59. package/src/lib/components/icon.js +163 -0
  60. package/src/lib/components/icon.js.map +1 -0
  61. package/src/lib/components/image-list.d.ts +58 -0
  62. package/src/lib/components/image-list.js +336 -0
  63. package/src/lib/components/image-list.js.map +1 -0
  64. package/src/lib/components/image.d.ts +154 -0
  65. package/src/lib/components/image.js +451 -0
  66. package/src/lib/components/image.js.map +1 -0
  67. package/src/lib/components/inline-text.d.ts +74 -0
  68. package/src/lib/components/inline-text.js +407 -0
  69. package/src/lib/components/inline-text.js.map +1 -0
  70. package/src/lib/components/language-switcher.d.ts +35 -0
  71. package/src/lib/components/language-switcher.js +179 -0
  72. package/src/lib/components/language-switcher.js.map +1 -0
  73. package/src/lib/components/layout-slot.d.ts +68 -0
  74. package/src/lib/components/layout-slot.js +192 -0
  75. package/src/lib/components/layout-slot.js.map +1 -0
  76. package/src/lib/components/link-box-accessible-name.d.ts +79 -0
  77. package/src/lib/components/link-box-accessible-name.js +158 -0
  78. package/src/lib/components/link-box-accessible-name.js.map +1 -0
  79. package/src/lib/components/link-box.d.ts +66 -0
  80. package/src/lib/components/link-box.js +212 -0
  81. package/src/lib/components/link-box.js.map +1 -0
  82. package/src/lib/components/list-item-text.d.ts +22 -0
  83. package/src/lib/components/list-item-text.js +86 -0
  84. package/src/lib/components/list-item-text.js.map +1 -0
  85. package/src/lib/components/list-item.d.ts +32 -0
  86. package/src/lib/components/list-item.js +127 -0
  87. package/src/lib/components/list-item.js.map +1 -0
  88. package/src/lib/components/list.d.ts +34 -0
  89. package/src/lib/components/list.js +108 -0
  90. package/src/lib/components/list.js.map +1 -0
  91. package/src/lib/components/markdown.d.ts +129 -0
  92. package/src/lib/components/markdown.js +853 -0
  93. package/src/lib/components/markdown.js.map +1 -0
  94. package/src/lib/components/nav-menu.d.ts +68 -0
  95. package/src/lib/components/nav-menu.js +683 -0
  96. package/src/lib/components/nav-menu.js.map +1 -0
  97. package/src/lib/components/pagination.d.ts +59 -0
  98. package/src/lib/components/pagination.js +243 -0
  99. package/src/lib/components/pagination.js.map +1 -0
  100. package/src/lib/components/paper.d.ts +47 -0
  101. package/src/lib/components/paper.js +202 -0
  102. package/src/lib/components/paper.js.map +1 -0
  103. package/src/lib/components/plugin-frame.d.ts +64 -0
  104. package/src/lib/components/plugin-frame.js +335 -0
  105. package/src/lib/components/plugin-frame.js.map +1 -0
  106. package/src/lib/components/plugin.d.ts +95 -0
  107. package/src/lib/components/plugin.js +304 -0
  108. package/src/lib/components/plugin.js.map +1 -0
  109. package/src/lib/components/product.d.ts +40 -0
  110. package/src/lib/components/product.js +287 -0
  111. package/src/lib/components/product.js.map +1 -0
  112. package/src/lib/components/reusable-instance.d.ts +57 -0
  113. package/src/lib/components/reusable-instance.js +126 -0
  114. package/src/lib/components/reusable-instance.js.map +1 -0
  115. package/src/lib/components/screen-link.d.ts +85 -0
  116. package/src/lib/components/screen-link.js +324 -0
  117. package/src/lib/components/screen-link.js.map +1 -0
  118. package/src/lib/components/search-box.d.ts +41 -0
  119. package/src/lib/components/search-box.js +125 -0
  120. package/src/lib/components/search-box.js.map +1 -0
  121. package/src/lib/components/section.d.ts +56 -0
  122. package/src/lib/components/section.js +132 -0
  123. package/src/lib/components/section.js.map +1 -0
  124. package/src/lib/components/stack.d.ts +55 -0
  125. package/src/lib/components/stack.js +309 -0
  126. package/src/lib/components/stack.js.map +1 -0
  127. package/src/lib/components/tabs.d.ts +288 -0
  128. package/src/lib/components/tabs.js +788 -0
  129. package/src/lib/components/tabs.js.map +1 -0
  130. package/src/lib/components/theme-mode-switcher.d.ts +38 -0
  131. package/src/lib/components/theme-mode-switcher.js +168 -0
  132. package/src/lib/components/theme-mode-switcher.js.map +1 -0
  133. package/src/lib/components/toolbar.d.ts +37 -0
  134. package/src/lib/components/toolbar.js +117 -0
  135. package/src/lib/components/toolbar.js.map +1 -0
  136. package/src/lib/components/typography.d.ts +33 -0
  137. package/src/lib/components/typography.js +433 -0
  138. package/src/lib/components/typography.js.map +1 -0
  139. package/src/lib/components/video-lightbox-controls.d.ts +131 -0
  140. package/src/lib/components/video-lightbox-controls.js +536 -0
  141. package/src/lib/components/video-lightbox-controls.js.map +1 -0
  142. package/src/lib/components/video-lightbox.d.ts +60 -0
  143. package/src/lib/components/video-lightbox.js +247 -0
  144. package/src/lib/components/video-lightbox.js.map +1 -0
  145. package/src/lib/components/video-playback-beacon.d.ts +80 -0
  146. package/src/lib/components/video-playback-beacon.js +128 -0
  147. package/src/lib/components/video-playback-beacon.js.map +1 -0
  148. package/src/lib/components/video-player-frame.d.ts +58 -0
  149. package/src/lib/components/video-player-frame.js +51 -0
  150. package/src/lib/components/video-player-frame.js.map +1 -0
  151. package/src/lib/components/video.d.ts +220 -0
  152. package/src/lib/components/video.js +874 -0
  153. package/src/lib/components/video.js.map +1 -0
  154. package/src/lib/constants/bundle-common.d.ts +17 -0
  155. package/src/lib/constants/bundle-common.js +18 -0
  156. package/src/lib/constants/bundle-common.js.map +1 -0
  157. package/src/lib/constants/field-presets.d.ts +93 -0
  158. package/src/lib/constants/field-presets.js +248 -0
  159. package/src/lib/constants/field-presets.js.map +1 -0
  160. package/src/lib/plugin.d.ts +80 -0
  161. package/src/lib/plugin.js +599 -0
  162. package/src/lib/plugin.js.map +1 -0
  163. package/src/lib/utils/author-html-label.d.ts +73 -0
  164. package/src/lib/utils/author-html-label.js +89 -0
  165. package/src/lib/utils/author-html-label.js.map +1 -0
  166. package/src/lib/utils/drop-cleared-props.d.ts +18 -0
  167. package/src/lib/utils/drop-cleared-props.js +74 -0
  168. package/src/lib/utils/drop-cleared-props.js.map +1 -0
  169. package/src/lib/utils/element-picker.d.ts +99 -0
  170. package/src/lib/utils/element-picker.js +140 -0
  171. package/src/lib/utils/element-picker.js.map +1 -0
  172. package/src/lib/utils/generate-preset-id.d.ts +19 -0
  173. package/src/lib/utils/generate-preset-id.js +25 -0
  174. package/src/lib/utils/generate-preset-id.js.map +1 -0
  175. package/src/lib/utils/link-target-props.d.ts +53 -0
  176. package/src/lib/utils/link-target-props.js +53 -0
  177. package/src/lib/utils/link-target-props.js.map +1 -0
@@ -0,0 +1,202 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ import { jsx as _jsx } from "react/jsx-runtime";
4
+ /**
5
+ * @license
6
+ * Copyright 2026 Aglyn LLC
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */ import * as Aglyn from "@aglyn/aglyn";
20
+ import { mdiFileDocumentOutline } from "@aglyn/shared-data-mdi";
21
+ import MuiPaper from "@mui/material/Paper";
22
+ import { forwardRef } from "react";
23
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
24
+ import { applySemanticElement, semanticElementAttribute, semanticElementLabelAttribute } from "../utils/element-picker.js";
25
+ import { dropClearedProps } from "../utils/drop-cleared-props.js";
26
+ import { generatePresetId } from "../utils/generate-preset-id.js";
27
+ // Component ids are persisted in screen documents; never rename.
28
+ export const ID = 'muiPaper';
29
+ /** MUI's shadow scale tops out at 24; anything above renders unshadowed. */ export const MAX_ELEVATION = 24;
30
+ /**
31
+ * Coerces a persisted elevation to the number MUI's shadow lookup needs.
32
+ *
33
+ * Number-typed attribute fields round-trip through the document as
34
+ * strings often enough that this can't be assumed away: `elevation="3"`
35
+ * indexes MUI's shadow array with a string and yields `undefined`, i.e. a
36
+ * paper the author gave a shadow renders completely flat.
37
+ */ export function toElevation(value) {
38
+ if (value === '' || value == null) return undefined;
39
+ const parsed = Number(value);
40
+ if (!Number.isFinite(parsed)) return undefined;
41
+ return Math.min(Math.max(Math.round(parsed), 0), MAX_ELEVATION);
42
+ }
43
+ /**
44
+ * Surface primitive (https://mui.com/material-ui/react-paper/): the
45
+ * themed background + shadow that Card, Accordion and Drawer are all
46
+ * built on, exposed on its own for panels and callouts.
47
+ */ const PaperElement = /*#__PURE__*/ forwardRef((rawProps, ref)=>{
48
+ // Cleared props dropped before anything reads them (AGL-1451): `square`
49
+ // and everything else in `rest` spread straight into MUI, where a `null`
50
+ // from the field's ✕ (AGL-1226) is a value rather than an absence.
51
+ const props = dropClearedProps(rawProps);
52
+ const { elevation, variant, children } = props, rest = _object_without_properties_loose(props, [
53
+ "elevation",
54
+ "variant",
55
+ "children"
56
+ ]);
57
+ const resolved = toElevation(elevation);
58
+ return /*#__PURE__*/ _jsx(MuiPaper, _extends({
59
+ ref: ref,
60
+ // `outlined` has no shadow; passing an elevation alongside it is
61
+ // silently ignored by MUI, so don't pretend otherwise.
62
+ variant: variant === 'outlined' ? 'outlined' : 'elevation',
63
+ elevation: variant === 'outlined' ? undefined : resolved
64
+ }, applySemanticElement(rest), {
65
+ children: children
66
+ }));
67
+ });
68
+ PaperElement.displayName = 'AglynPaper';
69
+ /** Elevation only means anything on the (default) `elevation` variant. */ const ELEVATION_ONLY = {
70
+ when: 'variant',
71
+ is: 'outlined',
72
+ notMatch: true
73
+ };
74
+ export const schema = {
75
+ $id: ID,
76
+ pluginId: BUNDLE_ID,
77
+ displayName: 'Paper',
78
+ description: 'Themed surface with a shadow or an outline.',
79
+ category: Aglyn.ComponentCategory.SURFACE,
80
+ icon: {
81
+ path: mdiFileDocumentOutline.path,
82
+ sx: {
83
+ color: '#2196f3'
84
+ }
85
+ },
86
+ attributes: [
87
+ semanticElementAttribute('this surface'),
88
+ semanticElementLabelAttribute(),
89
+ {
90
+ name: 'variant',
91
+ label: 'Variant',
92
+ description: 'Elevation raises the surface with a shadow; outlined draws a ' + '1px border instead and has no shadow.',
93
+ component: Aglyn.FieldComponentType.SELECT,
94
+ // A real sentinel rather than a deletion (AGL-1451): unlike Container,
95
+ // "elevation" is not a second name for something else in the list —
96
+ // it is MUI's own variant value, the other half of a two-way choice,
97
+ // and the one the Elevation control below is conditioned on. It was
98
+ // spelled `''`, which the attributes form strips on change (AGL-1191),
99
+ // so picking it reverted the field on save.
100
+ options: [
101
+ {
102
+ value: 'elevation',
103
+ label: 'Elevation (default)'
104
+ },
105
+ {
106
+ value: 'outlined',
107
+ label: 'Outlined'
108
+ }
109
+ ]
110
+ },
111
+ {
112
+ name: 'elevation',
113
+ label: 'Elevation',
114
+ description: 'Shadow depth from 0 (flat) to 24. In dark mode MUI also lightens ' + 'the background as this rises.',
115
+ component: Aglyn.FieldComponentType.TEXT_FIELD,
116
+ type: 'number',
117
+ // Offering a shadow control on the outlined variant would be a
118
+ // control that silently does nothing.
119
+ condition: ELEVATION_ONLY
120
+ },
121
+ {
122
+ name: 'square',
123
+ label: 'Square corners?',
124
+ description: 'If true, the corners are not rounded.',
125
+ component: Aglyn.FieldComponentType.SWITCH
126
+ }
127
+ ]
128
+ };
129
+ export const presets = [
130
+ {
131
+ $id: generatePresetId(ID),
132
+ type: Aglyn.NodeType.PRESET,
133
+ displayName: 'Paper',
134
+ pluginId: BUNDLE_ID,
135
+ description: 'Raised surface for panels and callouts',
136
+ category: Aglyn.ComponentCategory.SURFACE,
137
+ icon: schema.icon,
138
+ data: {
139
+ $id: null,
140
+ componentId: ID,
141
+ pluginId: BUNDLE_ID,
142
+ props: {
143
+ elevation: 1
144
+ },
145
+ // Node-level sx (AGL-1346) — the record the Styles panel edits.
146
+ sx: {
147
+ paddingTop: 2,
148
+ paddingRight: 2,
149
+ paddingBottom: 2,
150
+ paddingLeft: 2
151
+ },
152
+ nodes: [
153
+ {
154
+ $id: null,
155
+ componentId: 'muiTypography',
156
+ pluginId: BUNDLE_ID,
157
+ props: {
158
+ variant: 'body1',
159
+ children: 'Paper is a themed surface. Drop anything inside it.'
160
+ }
161
+ }
162
+ ]
163
+ }
164
+ },
165
+ {
166
+ $id: generatePresetId(ID, 'outlined'),
167
+ type: Aglyn.NodeType.PRESET,
168
+ displayName: 'Paper Outlined',
169
+ pluginId: BUNDLE_ID,
170
+ description: 'Flat surface with a border instead of a shadow',
171
+ category: Aglyn.ComponentCategory.SURFACE,
172
+ icon: schema.icon,
173
+ data: {
174
+ $id: null,
175
+ componentId: ID,
176
+ pluginId: BUNDLE_ID,
177
+ props: {
178
+ variant: 'outlined'
179
+ },
180
+ sx: {
181
+ paddingTop: 2,
182
+ paddingRight: 2,
183
+ paddingBottom: 2,
184
+ paddingLeft: 2
185
+ },
186
+ nodes: [
187
+ {
188
+ $id: null,
189
+ componentId: 'muiTypography',
190
+ pluginId: BUNDLE_ID,
191
+ props: {
192
+ variant: 'body1',
193
+ children: 'Outlined paper has a border and no shadow.'
194
+ }
195
+ }
196
+ ]
197
+ }
198
+ }
199
+ ];
200
+ export default PaperElement;
201
+
202
+ //# sourceMappingURL=paper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/paper.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 { mdiFileDocumentOutline } from '@aglyn/shared-data-mdi'\nimport MuiPaper from '@mui/material/Paper'\nimport { forwardRef, type ReactNode } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport {\n applySemanticElement,\n semanticElementAttribute,\n semanticElementLabelAttribute,\n} from '../utils/element-picker'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiPaper'\n\nexport interface PaperElementProps {\n /** Shadow depth, 0–24. Ignored by MUI when `variant` is `outlined`. */\n elevation?: number | string\n variant?: 'elevation' | 'outlined'\n /** If true, corners are not rounded. */\n square?: boolean\n children?: ReactNode\n}\n\n/** MUI's shadow scale tops out at 24; anything above renders unshadowed. */\nexport const MAX_ELEVATION = 24\n\n/**\n * Coerces a persisted elevation to the number MUI's shadow lookup needs.\n *\n * Number-typed attribute fields round-trip through the document as\n * strings often enough that this can't be assumed away: `elevation=\"3\"`\n * indexes MUI's shadow array with a string and yields `undefined`, i.e. a\n * paper the author gave a shadow renders completely flat.\n */\nexport function toElevation(value: unknown): number | undefined {\n if (value === '' || value == null) return undefined\n const parsed = Number(value)\n if (!Number.isFinite(parsed)) return undefined\n return Math.min(Math.max(Math.round(parsed), 0), MAX_ELEVATION)\n}\n\n/**\n * Surface primitive (https://mui.com/material-ui/react-paper/): the\n * themed background + shadow that Card, Accordion and Drawer are all\n * built on, exposed on its own for panels and callouts.\n */\nconst PaperElement = forwardRef<HTMLDivElement, PaperElementProps>(\n (rawProps, ref) => {\n // Cleared props dropped before anything reads them (AGL-1451): `square`\n // and everything else in `rest` spread straight into MUI, where a `null`\n // from the field's ✕ (AGL-1226) is a value rather than an absence.\n const props = dropClearedProps(rawProps)\n const { elevation, variant, children, ...rest } = props\n const resolved = toElevation(elevation)\n return (\n <MuiPaper\n ref={ref}\n // `outlined` has no shadow; passing an elevation alongside it is\n // silently ignored by MUI, so don't pretend otherwise.\n variant={variant === 'outlined' ? 'outlined' : 'elevation'}\n elevation={variant === 'outlined' ? undefined : resolved}\n {...applySemanticElement(rest as Record<string, unknown>)}\n >\n {children}\n </MuiPaper>\n )\n },\n)\nPaperElement.displayName = 'AglynPaper'\n\n/** Elevation only means anything on the (default) `elevation` variant. */\nconst ELEVATION_ONLY = { when: 'variant', is: 'outlined', notMatch: true }\n\nexport const schema: Aglyn.ComponentSchema<PaperElementProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Paper',\n description: 'Themed surface with a shadow or an outline.',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: { path: mdiFileDocumentOutline.path, sx: { color: '#2196f3' } },\n attributes: [\n semanticElementAttribute('this surface'),\n semanticElementLabelAttribute(),\n {\n name: 'variant',\n label: 'Variant',\n description:\n 'Elevation raises the surface with a shadow; outlined draws a ' +\n '1px border instead and has no shadow.',\n component: Aglyn.FieldComponentType.SELECT,\n // A real sentinel rather than a deletion (AGL-1451): unlike Container,\n // \"elevation\" is not a second name for something else in the list —\n // it is MUI's own variant value, the other half of a two-way choice,\n // and the one the Elevation control below is conditioned on. It was\n // spelled `''`, which the attributes form strips on change (AGL-1191),\n // so picking it reverted the field on save.\n options: [\n { value: 'elevation', label: 'Elevation (default)' },\n { value: 'outlined', label: 'Outlined' },\n ],\n },\n {\n name: 'elevation',\n label: 'Elevation',\n description:\n 'Shadow depth from 0 (flat) to 24. In dark mode MUI also lightens ' +\n 'the background as this rises.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n // Offering a shadow control on the outlined variant would be a\n // control that silently does nothing.\n condition: ELEVATION_ONLY,\n },\n {\n name: 'square',\n label: 'Square corners?',\n description: 'If true, the corners are not rounded.',\n component: Aglyn.FieldComponentType.SWITCH,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Paper',\n pluginId: BUNDLE_ID,\n description: 'Raised surface for panels and callouts',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { elevation: 1 },\n // Node-level sx (AGL-1346) — the record the Styles panel edits.\n sx: { paddingTop: 2, paddingRight: 2, paddingBottom: 2, paddingLeft: 2 },\n nodes: [\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: {\n variant: 'body1',\n children: 'Paper is a themed surface. Drop anything inside it.',\n },\n },\n ],\n },\n },\n {\n $id: generatePresetId(ID, 'outlined'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Paper Outlined',\n pluginId: BUNDLE_ID,\n description: 'Flat surface with a border instead of a shadow',\n category: Aglyn.ComponentCategory.SURFACE,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { variant: 'outlined' },\n sx: { paddingTop: 2, paddingRight: 2, paddingBottom: 2, paddingLeft: 2 },\n nodes: [\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: {\n variant: 'body1',\n children: 'Outlined paper has a border and no shadow.',\n },\n },\n ],\n },\n },\n]\n\nexport default PaperElement\n"],"names":["Aglyn","mdiFileDocumentOutline","MuiPaper","forwardRef","BUNDLE_ID","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","dropClearedProps","generatePresetId","ID","MAX_ELEVATION","toElevation","value","undefined","parsed","Number","isFinite","Math","min","max","round","PaperElement","rawProps","ref","props","elevation","variant","children","rest","resolved","displayName","ELEVATION_ONLY","when","is","notMatch","schema","$id","pluginId","description","category","ComponentCategory","SURFACE","icon","path","sx","color","attributes","name","label","component","FieldComponentType","SELECT","options","TEXT_FIELD","type","condition","SWITCH","presets","NodeType","PRESET","data","componentId","paddingTop","paddingRight","paddingBottom","paddingLeft","nodes"],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import * as Aglyn from '@aglyn/aglyn';
2
+ import type { SxProps } from '@mui/material/styles';
3
+ /**
4
+ * Host-side sandboxed plugin runtime (AGL-45), per AGL-43 §2. Renders an
5
+ * installed executable plugin inside a cross-origin sandboxed iframe and
6
+ * talks to it only through the capability-scoped postMessage bridge — the
7
+ * plugin never runs in the console/tenant realm, so it has no ambient
8
+ * access to host Firestore, auth, storage, or the DOM. Renders a safe
9
+ * placeholder (never the plugin) whenever it can't run safely: no plugin
10
+ * origin configured, the origin isn't cross-origin to this app, or the
11
+ * version is revoked (kill switch).
12
+ *
13
+ * SANDBOX NOTE: `allow-scripts allow-same-origin` is correct HERE and only
14
+ * here because `src` is a DEDICATED cross-origin (`pluginOrigin`). For a
15
+ * cross-origin frame, `allow-same-origin` grants the frame ITS OWN
16
+ * (plugin) origin's privileges — not the parent's — so it stays walled off
17
+ * from the app while still being able to load its own bundle and honor the
18
+ * plugin-origin CSP's `connect-src`. The combination is only unsafe for a
19
+ * SAME-origin frame; `isCrossOrigin` below refuses that case.
20
+ *
21
+ * SERVER RENDER: the origin comparison needs `window.location.origin`, so a
22
+ * server render cannot make it and neither render that has to agree with the
23
+ * server makes it. Both emit the frame with no `src` — the plugin URL is
24
+ * attached on the render after mount, once the origin has actually been
25
+ * checked. That keeps the server HTML and the first client render identical
26
+ * whatever `pluginOrigin` is set to, and it keeps an unverified origin out of
27
+ * the markup a browser would start loading before any of this code runs.
28
+ */
29
+ export interface PluginFrameProps {
30
+ /** Dedicated plugin origin, e.g. `https://plugins.aglyn.app`. */
31
+ pluginOrigin?: string;
32
+ /** Host id, for scoping host-mediated fetch (AGL-191). */
33
+ hostId?: string;
34
+ listingId: string;
35
+ /**
36
+ * Which DECLARED element of the plugin to render (AGL-1031).
37
+ *
38
+ * A FRAME prop, never a member of `pluginProps`: those are filtered against
39
+ * the manifest allowlist, so an element id routed through them would be
40
+ * dropped for every plugin that had not thought to declare `elementId` as a
41
+ * settable prop — silently, and only for declared elements. It is host
42
+ * metadata like `version` and `sha256`, and travels with them.
43
+ */
44
+ elementId?: string;
45
+ version: string;
46
+ sha256: string;
47
+ /** Manifest capabilities (event allowlist, declared size). */
48
+ capabilities?: Aglyn.PluginCapabilities;
49
+ /** Props to pass in; filtered to the manifest allowlist before sending. */
50
+ pluginProps?: Record<string, unknown>;
51
+ /** True when the pinned version is revoked (from the revocations doc). */
52
+ revoked?: boolean;
53
+ scheme?: 'light' | 'dark';
54
+ title?: string;
55
+ /**
56
+ * Authored node styles, handed over by the renderer rather than typed
57
+ * into an attribute — recomposed below so the Styles panel's values are
58
+ * merged rather than replaced (AGL-1284).
59
+ */
60
+ sx?: SxProps;
61
+ }
62
+ declare const PluginFrame: import("react").ForwardRefExoticComponent<PluginFrameProps & import("react").RefAttributes<HTMLIFrameElement>>;
63
+ export { PluginFrame };
64
+ export default PluginFrame;
@@ -0,0 +1,335 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
19
+ import { jsx as _jsx } from "react/jsx-runtime";
20
+ import * as Aglyn from "@aglyn/aglyn";
21
+ import Box from "@mui/material/Box";
22
+ import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
23
+ /**
24
+ * Does `pluginOrigin` resolve to an origin other than the app's own?
25
+ *
26
+ * True is the only answer that lets the frame render: the sandbox pair in
27
+ * the SANDBOX NOTE is containment exactly while the frame's origin differs
28
+ * from the page's, and is a no-op when it doesn't.
29
+ *
30
+ * Browser-only, and unavoidably so. The app's origin is
31
+ * `window.location.origin` and no constant stands in for it — a site answers
32
+ * on both its platform address and any custom domain attached to it, and the
33
+ * console, a preview, a self-host container and a dev server each run this
34
+ * under a different one. Callers ask only once mounted; the `catch` refuses
35
+ * an unparsable origin, and refuses a call made without a `window` for the
36
+ * same reason — an origin nothing compared is not an origin anything cleared.
37
+ */ function isCrossOrigin(pluginOrigin) {
38
+ try {
39
+ return new URL(pluginOrigin).origin !== window.location.origin;
40
+ } catch (unused) {
41
+ return false;
42
+ }
43
+ }
44
+ const Placeholder = /*#__PURE__*/ forwardRef(({ message, height }, ref)=>/*#__PURE__*/ _jsx(Box, {
45
+ ref: ref,
46
+ sx: {
47
+ minHeight: height != null ? height : 120,
48
+ display: 'flex',
49
+ alignItems: 'center',
50
+ justifyContent: 'center',
51
+ border: '1px dashed',
52
+ borderColor: 'divider',
53
+ borderRadius: 1,
54
+ color: 'text.secondary',
55
+ fontSize: 13,
56
+ fontFamily: 'system-ui, sans-serif',
57
+ p: 2,
58
+ textAlign: 'center'
59
+ },
60
+ children: message
61
+ }));
62
+ Placeholder.displayName = 'PluginFramePlaceholder';
63
+ const PluginFrame = /*#__PURE__*/ forwardRef((props, ref)=>{
64
+ var _ref;
65
+ var _capabilities_size;
66
+ const { pluginOrigin, hostId, listingId, elementId, version, sha256, capabilities, pluginProps, revoked, scheme, title } = props, rest = _object_without_properties_loose(props, [
67
+ "pluginOrigin",
68
+ "hostId",
69
+ "listingId",
70
+ "elementId",
71
+ "version",
72
+ "sha256",
73
+ "capabilities",
74
+ "pluginProps",
75
+ "revoked",
76
+ "scheme",
77
+ "title"
78
+ ]);
79
+ // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).
80
+ const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [
81
+ props['sx']
82
+ ];
83
+ const frameRef = useRef(null);
84
+ const [state, setState] = useState('loading');
85
+ const [height, setHeight] = useState((_ref = capabilities == null ? void 0 : (_capabilities_size = capabilities.size) == null ? void 0 : _capabilities_size.height) != null ? _ref : 120);
86
+ /**
87
+ * Whether this render is running in a browser, where `isCrossOrigin` can
88
+ * be answered.
89
+ *
90
+ * Every other input here is a prop or a build-time env and so reads the
91
+ * same on both sides; the origin comparison is the one that doesn't, and
92
+ * a render that branches on it disagrees with the server for any
93
+ * `pluginOrigin` that is same-origin to the app. Deferring it to the
94
+ * render after mount costs nothing visible: the frame is hidden until the
95
+ * guest posts `ready`, and the listener that hears `ready` is registered
96
+ * in an effect, so no plugin has ever painted before this point either.
97
+ */ const [mounted, setMounted] = useState(false);
98
+ useEffect(()=>setMounted(true), []);
99
+ const allowedEvents = capabilities == null ? void 0 : capabilities.events;
100
+ const allowedProps = capabilities == null ? void 0 : capabilities.props;
101
+ const filteredProps = useMemo(()=>Aglyn.filterPluginProps(pluginProps, allowedProps), [
102
+ pluginProps,
103
+ allowedProps
104
+ ]);
105
+ // Stable dependency for the props-update effect.
106
+ const filteredPropsKey = useMemo(()=>JSON.stringify(filteredProps), [
107
+ filteredProps
108
+ ]);
109
+ /**
110
+ * Three answers, not two: `null` while the check is still unanswerable,
111
+ * `false` once the browser has refused the origin. Collapsing them would
112
+ * put the refusal placeholder in the server HTML of every correctly
113
+ * configured site, which is the same mismatch pointing the other way.
114
+ */ const crossOrigin = mounted && pluginOrigin ? isCrossOrigin(pluginOrigin) : null;
115
+ const originUsable = !revoked && crossOrigin === true;
116
+ // Undefined, never `''`: an empty `src` is still an `src`, and the frame
117
+ // must carry no address at all until the origin behind it has cleared.
118
+ const src = useMemo(()=>{
119
+ if (!originUsable) return undefined;
120
+ const url = new URL('/load', String(pluginOrigin));
121
+ url.searchParams.set('listing', listingId);
122
+ url.searchParams.set('v', version);
123
+ url.searchParams.set('sha', sha256);
124
+ if (elementId) url.searchParams.set('element', elementId);
125
+ // The framing host (AGL-884): the origin resolves this to the site's
126
+ // VERIFIED custom domain and widens frame-ancestors to exactly that —
127
+ // never to caller-supplied origins.
128
+ if (hostId) url.searchParams.set('host', hostId);
129
+ return url.toString();
130
+ }, [
131
+ originUsable,
132
+ pluginOrigin,
133
+ hostId,
134
+ listingId,
135
+ elementId,
136
+ version,
137
+ sha256
138
+ ]);
139
+ // Bridge: validate every inbound message by origin + source + schema,
140
+ // then honor resize / surface events / flag errors. Never eval or graft
141
+ // anything from the frame — only sized output and named events.
142
+ useEffect(()=>{
143
+ if (!originUsable) return;
144
+ const expectedOrigin = new URL(String(pluginOrigin)).origin;
145
+ const handleMessage = (event)=>{
146
+ var _frameRef_current;
147
+ if (event.origin !== expectedOrigin) return;
148
+ if (event.source !== ((_frameRef_current = frameRef.current) == null ? void 0 : _frameRef_current.contentWindow)) return;
149
+ const message = Aglyn.parseGuestMessage(event.data, allowedEvents);
150
+ if (!message) return;
151
+ switch(message.type){
152
+ case 'ready':
153
+ var _frameRef_current_contentWindow, _frameRef_current1;
154
+ setState('ready');
155
+ (_frameRef_current1 = frameRef.current) == null ? void 0 : (_frameRef_current_contentWindow = _frameRef_current1.contentWindow) == null ? void 0 : _frameRef_current_contentWindow.postMessage(_extends({
156
+ type: 'init',
157
+ v: Aglyn.PLUGIN_BRIDGE_VERSION,
158
+ props: filteredProps
159
+ }, scheme ? {
160
+ scheme
161
+ } : {}), expectedOrigin);
162
+ break;
163
+ case 'resize':
164
+ setHeight(Math.max(24, message.height));
165
+ break;
166
+ case 'event':
167
+ var _Aglyn_emitter_emit, _Aglyn_emitter;
168
+ (_Aglyn_emitter = Aglyn.emitter) == null ? void 0 : (_Aglyn_emitter_emit = _Aglyn_emitter.emit) == null ? void 0 : _Aglyn_emitter_emit.call(_Aglyn_emitter, `plugin:${listingId}:${message.name}`, {
169
+ listingId,
170
+ name: message.name,
171
+ payload: message.payload
172
+ });
173
+ break;
174
+ case 'fetch-request':
175
+ {
176
+ // Host-mediated fetch (AGL-191): proxy through the host API,
177
+ // which re-checks the manifest allowlist server-side. Reply on
178
+ // the same id; a disallowed/failed call resolves ok:false.
179
+ const requestId = message.id;
180
+ const respond = (payload)=>{
181
+ var _frameRef_current_contentWindow, _frameRef_current;
182
+ return (_frameRef_current = frameRef.current) == null ? void 0 : (_frameRef_current_contentWindow = _frameRef_current.contentWindow) == null ? void 0 : _frameRef_current_contentWindow.postMessage(_extends({
183
+ type: 'fetch-response',
184
+ v: Aglyn.PLUGIN_BRIDGE_VERSION,
185
+ id: requestId
186
+ }, payload), expectedOrigin);
187
+ };
188
+ if (!hostId) {
189
+ respond({
190
+ ok: false,
191
+ status: 0,
192
+ error: 'No host context'
193
+ });
194
+ break;
195
+ }
196
+ void fetch('/api/plugins/fetch', {
197
+ method: 'POST',
198
+ headers: {
199
+ 'Content-Type': 'application/json'
200
+ },
201
+ body: JSON.stringify({
202
+ hostId,
203
+ listingId,
204
+ url: message.url,
205
+ method: message.method,
206
+ body: message.body
207
+ })
208
+ }).then((response)=>response.json()).then((payload)=>{
209
+ var _ref;
210
+ return respond({
211
+ ok: Boolean(payload == null ? void 0 : payload.ok),
212
+ status: Number((_ref = payload == null ? void 0 : payload.status) != null ? _ref : 0),
213
+ body: payload == null ? void 0 : payload.body,
214
+ error: payload == null ? void 0 : payload.error
215
+ });
216
+ }).catch(()=>respond({
217
+ ok: false,
218
+ status: 0,
219
+ error: 'Fetch failed'
220
+ }));
221
+ break;
222
+ }
223
+ case 'error':
224
+ setState('error');
225
+ break;
226
+ }
227
+ };
228
+ window.addEventListener('message', handleMessage);
229
+ return ()=>window.removeEventListener('message', handleMessage);
230
+ // filteredProps is re-sent by the effect below; init uses the latest.
231
+ // eslint-disable-next-line react-hooks/exhaustive-deps
232
+ }, [
233
+ originUsable,
234
+ pluginOrigin,
235
+ hostId,
236
+ listingId,
237
+ allowedEvents,
238
+ scheme,
239
+ src
240
+ ]);
241
+ // Push prop updates to an already-ready frame.
242
+ useEffect(()=>{
243
+ var _frameRef_current_contentWindow, _frameRef_current;
244
+ if (state !== 'ready' || !originUsable) return;
245
+ const expectedOrigin = new URL(String(pluginOrigin)).origin;
246
+ (_frameRef_current = frameRef.current) == null ? void 0 : (_frameRef_current_contentWindow = _frameRef_current.contentWindow) == null ? void 0 : _frameRef_current_contentWindow.postMessage({
247
+ type: 'props',
248
+ v: Aglyn.PLUGIN_BRIDGE_VERSION,
249
+ props: filteredProps
250
+ }, expectedOrigin);
251
+ // filteredPropsKey captures the serialized props identity.
252
+ // eslint-disable-next-line react-hooks/exhaustive-deps
253
+ }, [
254
+ filteredPropsKey,
255
+ state,
256
+ originUsable,
257
+ pluginOrigin
258
+ ]);
259
+ if (revoked) {
260
+ return /*#__PURE__*/ _jsx(Placeholder, {
261
+ message: "This plugin has been disabled by the platform."
262
+ });
263
+ }
264
+ if (!pluginOrigin) {
265
+ return /*#__PURE__*/ _jsx(Placeholder, {
266
+ message: "Plugins are not enabled on this deployment."
267
+ });
268
+ }
269
+ // A refusal the browser actually made. `null` — not yet checked — falls
270
+ // through to the frame below, which carries no `src` until it clears.
271
+ if (crossOrigin === false) {
272
+ return /*#__PURE__*/ _jsx(Placeholder, {
273
+ message: "Plugin cannot be loaded safely here."
274
+ });
275
+ }
276
+ return /*#__PURE__*/ _jsx(Box, {
277
+ sx: {
278
+ position: 'relative',
279
+ width: '100%'
280
+ },
281
+ children: state === 'error' ? /*#__PURE__*/ _jsx(Placeholder, {
282
+ message: "This plugin failed to load.",
283
+ height: height
284
+ }) : /*#__PURE__*/ _jsx(Box, _extends({
285
+ component: "iframe",
286
+ ref: (node)=>{
287
+ frameRef.current = node;
288
+ if (typeof ref === 'function') ref(node);
289
+ else if (ref) ref.current = node;
290
+ },
291
+ src: src,
292
+ title: title != null ? title : 'Plugin',
293
+ loading: "lazy",
294
+ onError: ()=>setState('error')
295
+ }, rest, {
296
+ // AFTER the spread, deliberately (AGL-2484). See SANDBOX NOTE —
297
+ // this pair is safe only because `src` is a dedicated
298
+ // cross-origin, and JSX resolves a duplicate attribute by taking
299
+ // the LAST one, so listing them before `{...rest}` made the
300
+ // frame's only containment overridable by whatever a caller
301
+ // happened to spread in. No caller passes either today and
302
+ // `PluginFrameProps` declares neither; the props here do arrive
303
+ // from renderers that forward author-controlled bags, which is
304
+ // how "no caller does this" stops being true.
305
+ sandbox: "allow-scripts allow-same-origin",
306
+ referrerPolicy: "no-referrer",
307
+ // MERGE, never replace (AGL-1284). The spread in the old literal
308
+ // LOOKED like a merge and merged nothing — it folded in a local
309
+ // conditional, not the node's `sx`, so every style an author set
310
+ // on a plugin element was discarded. Order matters: the frame's
311
+ // own box goes first so the author can override it, and the
312
+ // load-time hide goes LAST so an authored `visibility` can never
313
+ // reveal a frame that has not finished loading.
314
+ sx: [
315
+ {
316
+ width: '100%',
317
+ height,
318
+ border: 0,
319
+ display: 'block'
320
+ },
321
+ ...nodeSx,
322
+ ...state === 'loading' ? [
323
+ {
324
+ visibility: 'hidden'
325
+ }
326
+ ] : []
327
+ ]
328
+ }))
329
+ });
330
+ });
331
+ PluginFrame.displayName = 'AglynPluginFrame';
332
+ export { PluginFrame };
333
+ export default PluginFrame;
334
+
335
+ //# sourceMappingURL=plugin-frame.js.map