@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,324 @@
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 { mdiLinkVariant } from "@aglyn/shared-data-mdi";
21
+ import { AppLink } from "@aglyn/shared-ui-jsx";
22
+ import Button from "@mui/material/Button";
23
+ import Link from "@mui/material/Link";
24
+ import { forwardRef } from "react";
25
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
26
+ import { FIELD_COLOR, FIELD_FULL_WIDTH, FIELD_LINK_TARGET, FIELD_LINK_TARGET_NAME, FIELD_SIZE, FIELD_TEXT_CONTENT } from "../constants/field-presets.js";
27
+ import { withAuthorHtmlLabel } from "../utils/author-html-label.js";
28
+ import { dropClearedProps } from "../utils/drop-cleared-props.js";
29
+ import { generatePresetId } from "../utils/generate-preset-id.js";
30
+ import { linkTargetProps } from "../utils/link-target-props.js";
31
+ // Component ids are persisted in screen documents; never rename.
32
+ export const ID = 'muiScreenLink';
33
+ /**
34
+ * What a button-styled LINK renders as with nothing to point at (canvas,
35
+ * preview, unresolved screen). `role: undefined` is the load-bearing half:
36
+ * MUI's `ButtonBase` stamps `role="button"` onto any non-`<button>` root,
37
+ * and merges the caller's props AFTER its own, so an explicit `undefined`
38
+ * is what removes it.
39
+ */ const STYLED_LINK_PLACEHOLDER = {
40
+ component: 'span',
41
+ role: undefined
42
+ };
43
+ /**
44
+ * Link that targets a screen by id, never a hardcoded path. Degrades to a
45
+ * plain button when the id doesn't resolve (unpublished/deleted screen) and
46
+ * when navigation is suppressed (besigner canvas, preview).
47
+ *
48
+ * `renderAs="link"` renders MUI's `Link` instead of `Button` (AGL-1195).
49
+ * Footer and inline navigation are *text*: as buttons they inherit button
50
+ * typography, uppercase transforms and the wrong role for assistive tech.
51
+ * The button-only props are dropped in that mode rather than passed through
52
+ * — `variant` means the typography variant on a `Link`, so forwarding
53
+ * `"contained"` would silently produce an unstyled element.
54
+ *
55
+ * `renderAs="linkButton"` splits the two halves that used to travel together
56
+ * (AGL-1347). A pill row whose chips all navigate — docs URLs, `mailto:`,
57
+ * social profiles — is a legitimate design, but every chip announced as a
58
+ * button, which tells a screen-reader user to expect an action and costs
59
+ * them the link-list and open-in-new-tab affordances. This mode keeps the
60
+ * button's `variant`/`size`/`fullWidth` and drops the role, exactly as MUI's
61
+ * own `Button component={Link}` does. It is a THIRD value rather than
62
+ * `variant` becoming live in `"link"` mode, because a node switched to Text
63
+ * link keeps whatever `variant` it was authored with (the shipped preset is
64
+ * `variant: 'outlined'`) — honouring those would repaint the site's nav and
65
+ * footer as outlined pills.
66
+ */ const ScreenLink = /*#__PURE__*/ forwardRef((props, ref)=>{
67
+ const { screenId, href: externalHref, renderAs, target, targetName, html } = props, spread = _object_without_properties_loose(props, [
68
+ "screenId",
69
+ "href",
70
+ "renderAs",
71
+ "target",
72
+ "targetName",
73
+ "html"
74
+ ]);
75
+ // A CLEARED attribute persists as null, and null is not "use the default"
76
+ // in React — `color={null}` reaches MUI, which capitalizes it and throws
77
+ // error #7 during SSR, 500ing the page (AGL-1226). This is the site's
78
+ // most-used element (70–77 nodes per page), so the guard runs BEFORE
79
+ // `variant`/`size`/`fullWidth` are split out: they are forwarded as named
80
+ // attributes, and guarding only the spread would leave those three exposed.
81
+ //
82
+ // The formatted label (AGL-2557) is substituted for `children` in the same
83
+ // breath, so all five shapes below carry it without five more spreads —
84
+ // and an unformatted link, which is nearly all of them, gets the very
85
+ // object `dropClearedProps` returned.
86
+ const _withAuthorHtmlLabel = withAuthorHtmlLabel(dropClearedProps(spread), html), { variant, size, fullWidth } = _withAuthorHtmlLabel, rest = _object_without_properties_loose(_withAuthorHtmlLabel, [
87
+ "variant",
88
+ "size",
89
+ "fullWidth"
90
+ ]);
91
+ // Id-vs-URL precedence and the `javascript:`/`data:` guard live in
92
+ // `useLinkTarget` (AGL-1335) — one copy for every linking element, and
93
+ // the only place that knows a `screen:`-prefixed value is a reference.
94
+ const { href, suppressNavigation, editorInert, broken, leavesSite } = Aglyn.useLinkTarget(screenId, externalHref);
95
+ // Resolved rather than spread: `'custom'` is an authoring sentinel, and an
96
+ // anchor carrying `target="custom"` would open a window literally named
97
+ // that. The pair is destructured OUT of `spread` above, so the inert canvas
98
+ // branches below never see either half.
99
+ const targetAttrs = linkTargetProps(target, targetName, leavesSite);
100
+ /**
101
+ * The same dead-target problem Tabs had, on the element there are 326 of
102
+ * (AGL-1893). Here it is less violent — an unresolved Screen Link already
103
+ * degrades to inert content rather than to a fake control — but it is just
104
+ * as silent: unpublish a screen and every link to it quietly stops
105
+ * navigating, with nothing in the editor to say which ones.
106
+ *
107
+ * So the LIVE rendering is deliberately unchanged, and only the authoring
108
+ * surface gains anything: on the besigner canvas the link wears a warning
109
+ * ring and explains itself on hover. A live restyle would be the riskier
110
+ * half of this by far — it would repaint any published CTA whose screen is
111
+ * temporarily unpublished, on sites whose owners never asked.
112
+ */ const flagged = Aglyn.brokenScreenLinkProps(broken, editorInert);
113
+ const asLink = renderAs === 'link';
114
+ // Semantics and appearance are independent choices now (AGL-1347): a
115
+ // styled link takes the button's styling props and none of its role.
116
+ const asStyledLink = renderAs === 'linkButton';
117
+ if (!href || suppressNavigation) {
118
+ // The canvas must not lie about which element the page will ship, so
119
+ // the unresolved/suppressed case mirrors the same three shapes.
120
+ //
121
+ // `sx` is lifted out of the spread so the editor ring can be merged
122
+ // rather than replace the author's styles — the AGL-1284 mistake, in a
123
+ // place where the symptom would be "my link lost all its styling the
124
+ // day its screen was unpublished". The ring goes LAST, and is the one
125
+ // thing here allowed to outrank an authored value: it is a diagnostic
126
+ // on a surface only the author sees, not a style.
127
+ const { sx: authoredSx } = rest, restNoSx = _object_without_properties_loose(rest, [
128
+ "sx"
129
+ ]);
130
+ const inertSx = [
131
+ ...Array.isArray(authoredSx) ? authoredSx : authoredSx ? [
132
+ authoredSx
133
+ ] : [],
134
+ ...broken && editorInert ? [
135
+ Aglyn.BROKEN_SCREEN_LINK_SX
136
+ ] : []
137
+ ];
138
+ if (asLink) {
139
+ return /*#__PURE__*/ _jsx(Link, _extends({
140
+ ref: ref,
141
+ component: "span",
142
+ underline: "hover"
143
+ }, flagged, restNoSx, {
144
+ sx: inertSx
145
+ }));
146
+ }
147
+ return /*#__PURE__*/ _jsx(Button, _extends({
148
+ ref: ref
149
+ }, asStyledLink ? STYLED_LINK_PLACEHOLDER : {}, {
150
+ variant: variant,
151
+ size: size,
152
+ fullWidth: fullWidth
153
+ }, flagged, restNoSx, {
154
+ sx: inertSx
155
+ }));
156
+ }
157
+ return asLink ? /*#__PURE__*/ _jsx(AppLink, _extends({
158
+ ref: ref,
159
+ underline: "hover",
160
+ href: href
161
+ }, targetAttrs, rest)) : /*#__PURE__*/ _jsx(AppLink, _extends({
162
+ ref: ref,
163
+ componentVariant: "button",
164
+ href: href
165
+ }, targetAttrs, {
166
+ // The whole defect in one attribute. `ButtonBase` adds `role="button"`
167
+ // to every non-`<button>` root, so the button LOOK used to drag the
168
+ // button ROLE onto a navigating anchor. It spreads the caller's props
169
+ // after its own, so passing `undefined` here is what clears it — and
170
+ // only for the mode that asked to be a link.
171
+ role: asStyledLink ? undefined : 'button',
172
+ variant: variant,
173
+ size: size,
174
+ fullWidth: fullWidth
175
+ }, rest));
176
+ });
177
+ ScreenLink.displayName = 'ScreenLink';
178
+ /**
179
+ * Shows an attribute in the two modes that wear button styling — Button and
180
+ * Link (button styling). `notMatch` inverts `is`, so an unset `renderAs` —
181
+ * every link authored before AGL-1195 — still counts as a button and keeps
182
+ * its controls, and only Text link hides them.
183
+ */ const BUTTON_STYLED = {
184
+ when: 'renderAs',
185
+ is: 'link',
186
+ notMatch: true
187
+ };
188
+ export const schema = {
189
+ $id: ID,
190
+ pluginId: BUNDLE_ID,
191
+ displayName: 'Screen Link',
192
+ description: 'Links to another screen by id, so it survives a slug change.',
193
+ category: Aglyn.ComponentCategory.NAVIGATION,
194
+ icon: {
195
+ path: mdiLinkVariant.path,
196
+ sx: {
197
+ color: '#2196f3'
198
+ }
199
+ },
200
+ flags: {
201
+ textEditable: Aglyn.FEATURE_FLAG.ENABLED,
202
+ richTextEditable: Aglyn.FEATURE_FLAG.ENABLED
203
+ },
204
+ // Emphasis only (AGL-2557). Every mode of this element ships an anchor or
205
+ // a button, and neither may contain a list or a second control.
206
+ richTextCommands: [
207
+ Aglyn.RICH_TEXT_COMMANDS.EMPHASIS
208
+ ],
209
+ attributes: [
210
+ FIELD_TEXT_CONTENT,
211
+ {
212
+ name: 'screenId',
213
+ description: 'Screen this link navigates to. The address is generated from the ' + 'published path at render time, so it keeps working when the ' + "screen's slug or parent changes.",
214
+ component: Aglyn.FieldComponentType.SCREEN_SELECT,
215
+ label: 'Screen'
216
+ },
217
+ {
218
+ name: 'href',
219
+ description: 'Where this link goes when it points off this site. Ignored while ' + 'Screen names one — that field wins, so clear it to use a URL.',
220
+ component: Aglyn.FieldComponentType.TEXT_FIELD,
221
+ label: 'External URL',
222
+ // A bare `#fragment` saves and goes nowhere (AGL-2867).
223
+ resolveProps: Aglyn.bareFragmentLinkFieldProps
224
+ },
225
+ FIELD_LINK_TARGET,
226
+ FIELD_LINK_TARGET_NAME,
227
+ {
228
+ name: 'renderAs',
229
+ description: 'What this announces as. Button is for calls to action; both link ' + 'options announce as a link, which is what navigation should be — ' + 'pick "Link (button styling)" to keep the button look on something ' + 'that navigates.',
230
+ component: Aglyn.FieldComponentType.SELECT,
231
+ label: 'Render as',
232
+ // `'button'` is a REAL SENTINEL, not a deletion (AGL-1453): `''` here
233
+ // spelled an author's actual choice, and the one they could not make.
234
+ // The attributes form strips `''` before save (AGL-1191), so a link
235
+ // switched to Text link had NO route in this dropdown back to Button —
236
+ // and 213 of the 326 Screen Links in the corpus are in that mode.
237
+ //
238
+ // Safe because `renderAs` never reaches MUI: it is destructured out
239
+ // above and read only as `=== 'link'` / `=== 'linkButton'`, so
240
+ // `'button'` and an absent value take the identical branch. That is
241
+ // also what keeps every link authored before AGL-1195 rendering
242
+ // unchanged.
243
+ options: [
244
+ {
245
+ value: 'button',
246
+ label: 'Button'
247
+ },
248
+ {
249
+ value: 'link',
250
+ label: 'Text link'
251
+ },
252
+ {
253
+ value: 'linkButton',
254
+ label: 'Link (button styling)'
255
+ }
256
+ ]
257
+ },
258
+ // `color` survives both shapes — MUI's Link takes it too.
259
+ FIELD_COLOR,
260
+ // The rest are appearance: the renderer drops them in Text link mode, so
261
+ // leaving them on screen there would offer three controls that silently
262
+ // do nothing — but they are live in Link (button styling), which is the
263
+ // point of that mode. Spread rather than mutate — these presets are
264
+ // shared.
265
+ _extends({}, FIELD_SIZE, {
266
+ condition: BUTTON_STYLED
267
+ }),
268
+ _extends({}, FIELD_FULL_WIDTH, {
269
+ condition: BUTTON_STYLED
270
+ }),
271
+ {
272
+ name: 'variant',
273
+ description: 'How the link is drawn once its style is Button: Contained is a ' + 'filled call to action, Outlined a secondary one, Text the lightest. ' + 'Ignored while the link is styled as plain text.',
274
+ component: Aglyn.FieldComponentType.SELECT,
275
+ label: 'Variant',
276
+ // "Default" deleted (AGL-1453): unpersistable, and a second name for
277
+ // `text`, MUI Button's own default, already on the list.
278
+ options: [
279
+ {
280
+ value: 'text',
281
+ label: 'Text'
282
+ },
283
+ {
284
+ value: 'outlined',
285
+ label: 'Outlined'
286
+ },
287
+ {
288
+ value: 'contained',
289
+ label: 'Contained'
290
+ }
291
+ ],
292
+ condition: BUTTON_STYLED
293
+ }
294
+ ]
295
+ };
296
+ export const presets = [
297
+ {
298
+ $id: generatePresetId(ID),
299
+ type: Aglyn.NodeType.PRESET,
300
+ displayName: 'Screen Link',
301
+ icon: {
302
+ path: mdiLinkVariant.path,
303
+ sx: {
304
+ color: '#2196f3'
305
+ }
306
+ },
307
+ category: Aglyn.ComponentCategory.NAVIGATION,
308
+ data: {
309
+ $id: null,
310
+ componentId: ID,
311
+ pluginId: BUNDLE_ID,
312
+ props: {
313
+ children: 'Screen Link',
314
+ // Same visible-on-any-surface defaults as the button preset; the
315
+ // default text color disappears against a same-hue appbar.
316
+ variant: 'outlined',
317
+ color: 'inherit'
318
+ }
319
+ }
320
+ }
321
+ ];
322
+ export default ScreenLink;
323
+
324
+ //# sourceMappingURL=screen-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/screen-link.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 { mdiLinkVariant } from '@aglyn/shared-data-mdi'\nimport { AppLink } from '@aglyn/shared-ui-jsx'\nimport Button, { type ButtonProps } from '@mui/material/Button'\nimport Link from '@mui/material/Link'\nimport { forwardRef } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport {\n FIELD_COLOR,\n FIELD_FULL_WIDTH,\n FIELD_LINK_TARGET,\n FIELD_LINK_TARGET_NAME,\n FIELD_SIZE,\n FIELD_TEXT_CONTENT,\n} from '../constants/field-presets'\nimport { withAuthorHtmlLabel } from '../utils/author-html-label'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\nimport {\n type LinkTargetChoice,\n linkTargetProps,\n} from '../utils/link-target-props'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiScreenLink'\n\nexport interface ScreenLinkProps extends ButtonProps {\n /**\n * Target screen id. The href is resolved from the host routing map at\n * render time (see `ScreenLinkContext`), so slug renames and re-parenting\n * never break the link — which is what makes navigation inside a shared\n * layout viable.\n */\n screenId?: string\n /** External URL escape hatch, used only when no `screenId` is set. */\n href?: string\n /**\n * Which element this ships as (AGL-1195, AGL-1347). Persisted in screen\n * documents; never rename, and `undefined` must keep meaning `'button'` —\n * every link authored before this existed is one.\n *\n * - `'button'` (or unset) — `<a role=\"button\">` with the button's look.\n * - `'link'` — a plain text link; the button-only props are dropped.\n * - `'linkButton'` — a plain `<a>` with NO role, wearing the button's\n * `variant`/`size`/`fullWidth`. Appearance without semantics: a pill\n * that navigates announces as the link it is.\n */\n renderAs?: 'button' | 'link' | 'linkButton'\n /**\n * Where the link opens. Persisted in screen documents; never rename a\n * value, and `undefined` must keep meaning `'_self'` — every link authored\n * before this existed stays in the tab.\n */\n target?: LinkTargetChoice\n /** Window name used only when `target` is `'custom'`. */\n targetName?: string\n /**\n * Sanitized emphasis markup for the label, written by the inline editor's\n * rich mode (AGL-2557). `children` keeps the plain-text reading of it, and\n * is what every surface that cannot render markup falls back to.\n */\n html?: string\n}\n\n/**\n * What a button-styled LINK renders as with nothing to point at (canvas,\n * preview, unresolved screen). `role: undefined` is the load-bearing half:\n * MUI's `ButtonBase` stamps `role=\"button\"` onto any non-`<button>` root,\n * and merges the caller's props AFTER its own, so an explicit `undefined`\n * is what removes it.\n */\nconst STYLED_LINK_PLACEHOLDER = { component: 'span', role: undefined } as const\n\n/**\n * Link that targets a screen by id, never a hardcoded path. Degrades to a\n * plain button when the id doesn't resolve (unpublished/deleted screen) and\n * when navigation is suppressed (besigner canvas, preview).\n *\n * `renderAs=\"link\"` renders MUI's `Link` instead of `Button` (AGL-1195).\n * Footer and inline navigation are *text*: as buttons they inherit button\n * typography, uppercase transforms and the wrong role for assistive tech.\n * The button-only props are dropped in that mode rather than passed through\n * — `variant` means the typography variant on a `Link`, so forwarding\n * `\"contained\"` would silently produce an unstyled element.\n *\n * `renderAs=\"linkButton\"` splits the two halves that used to travel together\n * (AGL-1347). A pill row whose chips all navigate — docs URLs, `mailto:`,\n * social profiles — is a legitimate design, but every chip announced as a\n * button, which tells a screen-reader user to expect an action and costs\n * them the link-list and open-in-new-tab affordances. This mode keeps the\n * button's `variant`/`size`/`fullWidth` and drops the role, exactly as MUI's\n * own `Button component={Link}` does. It is a THIRD value rather than\n * `variant` becoming live in `\"link\"` mode, because a node switched to Text\n * link keeps whatever `variant` it was authored with (the shipped preset is\n * `variant: 'outlined'`) — honouring those would repaint the site's nav and\n * footer as outlined pills.\n */\nconst ScreenLink = forwardRef<any, ScreenLinkProps>((props, ref) => {\n const {\n screenId,\n href: externalHref,\n renderAs,\n target,\n targetName,\n html,\n ...spread\n } = props\n // A CLEARED attribute persists as null, and null is not \"use the default\"\n // in React — `color={null}` reaches MUI, which capitalizes it and throws\n // error #7 during SSR, 500ing the page (AGL-1226). This is the site's\n // most-used element (70–77 nodes per page), so the guard runs BEFORE\n // `variant`/`size`/`fullWidth` are split out: they are forwarded as named\n // attributes, and guarding only the spread would leave those three exposed.\n //\n // The formatted label (AGL-2557) is substituted for `children` in the same\n // breath, so all five shapes below carry it without five more spreads —\n // and an unformatted link, which is nearly all of them, gets the very\n // object `dropClearedProps` returned.\n const { variant, size, fullWidth, ...rest } = withAuthorHtmlLabel(\n dropClearedProps(spread),\n html,\n )\n // Id-vs-URL precedence and the `javascript:`/`data:` guard live in\n // `useLinkTarget` (AGL-1335) — one copy for every linking element, and\n // the only place that knows a `screen:`-prefixed value is a reference.\n const { href, suppressNavigation, editorInert, broken, leavesSite } =\n Aglyn.useLinkTarget(screenId, externalHref)\n // Resolved rather than spread: `'custom'` is an authoring sentinel, and an\n // anchor carrying `target=\"custom\"` would open a window literally named\n // that. The pair is destructured OUT of `spread` above, so the inert canvas\n // branches below never see either half.\n const targetAttrs = linkTargetProps(target, targetName, leavesSite)\n /**\n * The same dead-target problem Tabs had, on the element there are 326 of\n * (AGL-1893). Here it is less violent — an unresolved Screen Link already\n * degrades to inert content rather than to a fake control — but it is just\n * as silent: unpublish a screen and every link to it quietly stops\n * navigating, with nothing in the editor to say which ones.\n *\n * So the LIVE rendering is deliberately unchanged, and only the authoring\n * surface gains anything: on the besigner canvas the link wears a warning\n * ring and explains itself on hover. A live restyle would be the riskier\n * half of this by far — it would repaint any published CTA whose screen is\n * temporarily unpublished, on sites whose owners never asked.\n */\n const flagged = Aglyn.brokenScreenLinkProps(broken, editorInert)\n const asLink = renderAs === 'link'\n // Semantics and appearance are independent choices now (AGL-1347): a\n // styled link takes the button's styling props and none of its role.\n const asStyledLink = renderAs === 'linkButton'\n\n if (!href || suppressNavigation) {\n // The canvas must not lie about which element the page will ship, so\n // the unresolved/suppressed case mirrors the same three shapes.\n //\n // `sx` is lifted out of the spread so the editor ring can be merged\n // rather than replace the author's styles — the AGL-1284 mistake, in a\n // place where the symptom would be \"my link lost all its styling the\n // day its screen was unpublished\". The ring goes LAST, and is the one\n // thing here allowed to outrank an authored value: it is a diagnostic\n // on a surface only the author sees, not a style.\n const { sx: authoredSx, ...restNoSx } = rest as Record<string, any>\n const inertSx = [\n ...(Array.isArray(authoredSx) ? authoredSx : authoredSx ? [authoredSx] : []),\n ...(broken && editorInert ? [Aglyn.BROKEN_SCREEN_LINK_SX] : []),\n ]\n if (asLink) {\n return (\n <Link\n ref={ref}\n component=\"span\"\n underline=\"hover\"\n {...flagged}\n {...restNoSx}\n sx={inertSx}\n />\n )\n }\n return (\n <Button\n ref={ref}\n {...(asStyledLink ? STYLED_LINK_PLACEHOLDER : {})}\n variant={variant}\n size={size}\n fullWidth={fullWidth}\n {...flagged}\n {...restNoSx}\n sx={inertSx}\n />\n )\n }\n return asLink ? (\n <AppLink\n ref={ref}\n underline=\"hover\"\n href={href}\n {...targetAttrs}\n {...rest}\n />\n ) : (\n <AppLink\n ref={ref}\n componentVariant=\"button\"\n href={href}\n {...targetAttrs}\n // The whole defect in one attribute. `ButtonBase` adds `role=\"button\"`\n // to every non-`<button>` root, so the button LOOK used to drag the\n // button ROLE onto a navigating anchor. It spreads the caller's props\n // after its own, so passing `undefined` here is what clears it — and\n // only for the mode that asked to be a link.\n role={asStyledLink ? undefined : 'button'}\n variant={variant}\n size={size}\n fullWidth={fullWidth}\n {...rest}\n />\n )\n})\nScreenLink.displayName = 'ScreenLink'\n\n/**\n * Shows an attribute in the two modes that wear button styling — Button and\n * Link (button styling). `notMatch` inverts `is`, so an unset `renderAs` —\n * every link authored before AGL-1195 — still counts as a button and keeps\n * its controls, and only Text link hides them.\n */\nconst BUTTON_STYLED = { when: 'renderAs', is: 'link', notMatch: true }\n\nexport const schema: Aglyn.ComponentSchema<ScreenLinkProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Screen Link',\n description: 'Links to another screen by id, so it survives a slug change.',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: {\n path: mdiLinkVariant.path,\n sx: { color: '#2196f3' },\n },\n flags: {\n textEditable: Aglyn.FEATURE_FLAG.ENABLED,\n richTextEditable: Aglyn.FEATURE_FLAG.ENABLED,\n },\n // Emphasis only (AGL-2557). Every mode of this element ships an anchor or\n // a button, and neither may contain a list or a second control.\n richTextCommands: [Aglyn.RICH_TEXT_COMMANDS.EMPHASIS],\n attributes: [\n FIELD_TEXT_CONTENT,\n {\n name: 'screenId',\n description:\n 'Screen this link navigates to. The address is generated from the ' +\n 'published path at render time, so it keeps working when the ' +\n \"screen's slug or parent changes.\",\n component: Aglyn.FieldComponentType.SCREEN_SELECT,\n label: 'Screen',\n },\n {\n name: 'href',\n description:\n 'Where this link goes when it points off this site. Ignored while ' +\n 'Screen names one — that field wins, so clear it to use a URL.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'External URL',\n // A bare `#fragment` saves and goes nowhere (AGL-2867).\n resolveProps: Aglyn.bareFragmentLinkFieldProps,\n },\n FIELD_LINK_TARGET,\n FIELD_LINK_TARGET_NAME,\n {\n name: 'renderAs',\n description:\n 'What this announces as. Button is for calls to action; both link ' +\n 'options announce as a link, which is what navigation should be — ' +\n 'pick \"Link (button styling)\" to keep the button look on something ' +\n 'that navigates.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Render as',\n // `'button'` is a REAL SENTINEL, not a deletion (AGL-1453): `''` here\n // spelled an author's actual choice, and the one they could not make.\n // The attributes form strips `''` before save (AGL-1191), so a link\n // switched to Text link had NO route in this dropdown back to Button —\n // and 213 of the 326 Screen Links in the corpus are in that mode.\n //\n // Safe because `renderAs` never reaches MUI: it is destructured out\n // above and read only as `=== 'link'` / `=== 'linkButton'`, so\n // `'button'` and an absent value take the identical branch. That is\n // also what keeps every link authored before AGL-1195 rendering\n // unchanged.\n options: [\n { value: 'button', label: 'Button' },\n { value: 'link', label: 'Text link' },\n { value: 'linkButton', label: 'Link (button styling)' },\n ],\n },\n // `color` survives both shapes — MUI's Link takes it too.\n FIELD_COLOR,\n // The rest are appearance: the renderer drops them in Text link mode, so\n // leaving them on screen there would offer three controls that silently\n // do nothing — but they are live in Link (button styling), which is the\n // point of that mode. Spread rather than mutate — these presets are\n // shared.\n { ...FIELD_SIZE, condition: BUTTON_STYLED },\n { ...FIELD_FULL_WIDTH, condition: BUTTON_STYLED },\n {\n name: 'variant',\n description:\n 'How the link is drawn once its style is Button: Contained is a ' +\n 'filled call to action, Outlined a secondary one, Text the lightest. ' +\n 'Ignored while the link is styled as plain text.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Variant',\n // \"Default\" deleted (AGL-1453): unpersistable, and a second name for\n // `text`, MUI Button's own default, already on the list.\n options: [\n { value: 'text', label: 'Text' },\n { value: 'outlined', label: 'Outlined' },\n { value: 'contained', label: 'Contained' },\n ],\n condition: BUTTON_STYLED,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Screen Link',\n icon: {\n path: mdiLinkVariant.path,\n sx: { color: '#2196f3' },\n },\n category: Aglyn.ComponentCategory.NAVIGATION,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n children: 'Screen Link',\n // Same visible-on-any-surface defaults as the button preset; the\n // default text color disappears against a same-hue appbar.\n variant: 'outlined',\n color: 'inherit',\n },\n },\n },\n]\n\nexport default ScreenLink\n"],"names":["Aglyn","mdiLinkVariant","AppLink","Button","Link","forwardRef","BUNDLE_ID","FIELD_COLOR","FIELD_FULL_WIDTH","FIELD_LINK_TARGET","FIELD_LINK_TARGET_NAME","FIELD_SIZE","FIELD_TEXT_CONTENT","withAuthorHtmlLabel","dropClearedProps","generatePresetId","linkTargetProps","ID","STYLED_LINK_PLACEHOLDER","component","role","undefined","ScreenLink","props","ref","screenId","href","externalHref","renderAs","target","targetName","html","spread","variant","size","fullWidth","rest","suppressNavigation","editorInert","broken","leavesSite","useLinkTarget","targetAttrs","flagged","brokenScreenLinkProps","asLink","asStyledLink","sx","authoredSx","restNoSx","inertSx","Array","isArray","BROKEN_SCREEN_LINK_SX","underline","componentVariant","displayName","BUTTON_STYLED","when","is","notMatch","schema","$id","pluginId","description","category","ComponentCategory","NAVIGATION","icon","path","color","flags","textEditable","FEATURE_FLAG","ENABLED","richTextEditable","richTextCommands","RICH_TEXT_COMMANDS","EMPHASIS","attributes","name","FieldComponentType","SCREEN_SELECT","label","TEXT_FIELD","resolveProps","bareFragmentLinkFieldProps","SELECT","options","value","condition","presets","type","NodeType","PRESET","data","componentId","children"],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import * as Aglyn from '@aglyn/aglyn';
18
+ export declare const ID: Aglyn.ComponentId;
19
+ export interface SearchBoxProps {
20
+ placeholder?: string;
21
+ /**
22
+ * What the field starts with (AGL-2513). The results page prefills the
23
+ * query it is showing, so a reader can refine it where they are rather
24
+ * than going back for the box they typed into.
25
+ *
26
+ * Uncontrolled on purpose: this component holds no state and issues no
27
+ * request, and a `value` would freeze the field the moment the reader
28
+ * typed into it.
29
+ */
30
+ defaultValue?: string;
31
+ }
32
+ /**
33
+ * Site search box (AGL-88): a plain GET form to the tenant's /search page,
34
+ * so it works with zero JavaScript and is inert in the besigner (the
35
+ * console has no /search route to submit to; navigation there is a no-op
36
+ * form post the editor never triggers).
37
+ */
38
+ declare const SearchBox: import("react").ForwardRefExoticComponent<SearchBoxProps & import("react").RefAttributes<HTMLFormElement>>;
39
+ export declare const schema: Aglyn.ComponentSchema<SearchBoxProps>;
40
+ export declare const presets: Aglyn.PresetSchema[];
41
+ export default SearchBox;
@@ -0,0 +1,125 @@
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 { mdiMagnify } from "@aglyn/shared-data-mdi";
21
+ import IconButton from "@mui/material/IconButton";
22
+ import InputAdornment from "@mui/material/InputAdornment";
23
+ import TextField from "@mui/material/TextField";
24
+ import { MdiIcon } from "@aglyn/shared-ui-jsx";
25
+ import { forwardRef } from "react";
26
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
27
+ import { generatePresetId } from "../utils/generate-preset-id.js";
28
+ // Component ids are persisted in screen documents; never rename.
29
+ export const ID = 'searchBox';
30
+ /**
31
+ * Site search box (AGL-88): a plain GET form to the tenant's /search page,
32
+ * so it works with zero JavaScript and is inert in the besigner (the
33
+ * console has no /search route to submit to; navigation there is a no-op
34
+ * form post the editor never triggers).
35
+ */ const SearchBox = /*#__PURE__*/ forwardRef((props, ref)=>{
36
+ const { placeholder, defaultValue } = props, rest = _object_without_properties_loose(props, [
37
+ "placeholder",
38
+ "defaultValue"
39
+ ]);
40
+ return /*#__PURE__*/ _jsx("form", _extends({
41
+ ref: ref,
42
+ action: "/search",
43
+ method: "get",
44
+ role: "search"
45
+ }, rest, {
46
+ children: /*#__PURE__*/ _jsx(TextField, {
47
+ name: "q",
48
+ size: "small",
49
+ placeholder: placeholder || 'Search…',
50
+ defaultValue: defaultValue || '',
51
+ slotProps: {
52
+ input: {
53
+ endAdornment: /*#__PURE__*/ _jsx(InputAdornment, {
54
+ position: "end",
55
+ children: /*#__PURE__*/ _jsx(IconButton, {
56
+ type: "submit",
57
+ size: "small",
58
+ "aria-label": "search",
59
+ children: /*#__PURE__*/ _jsx(MdiIcon, {
60
+ path: mdiMagnify.path,
61
+ fontSize: "small"
62
+ })
63
+ })
64
+ })
65
+ }
66
+ }
67
+ })
68
+ }));
69
+ });
70
+ SearchBox.displayName = 'AglynSearchBox';
71
+ export const schema = {
72
+ $id: ID,
73
+ pluginId: BUNDLE_ID,
74
+ displayName: 'Search Box',
75
+ description: "A search field that opens the site's search page. It works without JavaScript.",
76
+ category: Aglyn.ComponentCategory.FORMS,
77
+ icon: {
78
+ path: mdiMagnify.path,
79
+ sx: {
80
+ color: '#455a64'
81
+ }
82
+ },
83
+ flags: {
84
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
85
+ },
86
+ attributes: [
87
+ {
88
+ name: 'placeholder',
89
+ description: 'Placeholder text inside the search field.',
90
+ component: Aglyn.FieldComponentType.TEXT_FIELD,
91
+ label: 'Placeholder'
92
+ },
93
+ {
94
+ name: 'defaultValue',
95
+ description: 'Text the field starts with. The search results page fills in the ' + 'query it is showing.',
96
+ component: Aglyn.FieldComponentType.TEXT_FIELD,
97
+ label: 'Starting text'
98
+ }
99
+ ]
100
+ };
101
+ export const presets = [
102
+ {
103
+ $id: generatePresetId(ID),
104
+ type: Aglyn.NodeType.PRESET,
105
+ displayName: 'Search Box',
106
+ pluginId: BUNDLE_ID,
107
+ description: 'Search field that opens the site search page',
108
+ category: Aglyn.ComponentCategory.FORMS,
109
+ icon: {
110
+ path: mdiMagnify.path,
111
+ sx: {
112
+ color: '#455a64'
113
+ }
114
+ },
115
+ data: {
116
+ $id: null,
117
+ componentId: ID,
118
+ pluginId: BUNDLE_ID,
119
+ props: {}
120
+ }
121
+ }
122
+ ];
123
+ export default SearchBox;
124
+
125
+ //# sourceMappingURL=search-box.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/search-box.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiMagnify } from '@aglyn/shared-data-mdi'\nimport IconButton from '@mui/material/IconButton'\nimport InputAdornment from '@mui/material/InputAdornment'\nimport TextField from '@mui/material/TextField'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { forwardRef } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'searchBox'\n\nexport interface SearchBoxProps {\n placeholder?: string\n /**\n * What the field starts with (AGL-2513). The results page prefills the\n * query it is showing, so a reader can refine it where they are rather\n * than going back for the box they typed into.\n *\n * Uncontrolled on purpose: this component holds no state and issues no\n * request, and a `value` would freeze the field the moment the reader\n * typed into it.\n */\n defaultValue?: string\n}\n\n/**\n * Site search box (AGL-88): a plain GET form to the tenant's /search page,\n * so it works with zero JavaScript and is inert in the besigner (the\n * console has no /search route to submit to; navigation there is a no-op\n * form post the editor never triggers).\n */\nconst SearchBox = forwardRef<HTMLFormElement, SearchBoxProps>(\n (props, ref) => {\n const { placeholder, defaultValue, ...rest } = props\n return (\n <form ref={ref} action=\"/search\" method=\"get\" role=\"search\" {...rest}>\n <TextField\n name=\"q\"\n size=\"small\"\n placeholder={placeholder || 'Search…'}\n defaultValue={defaultValue || ''}\n slotProps={{\n input: {\n endAdornment: (\n <InputAdornment position=\"end\">\n <IconButton type=\"submit\" size=\"small\" aria-label=\"search\">\n <MdiIcon path={mdiMagnify.path} fontSize=\"small\" />\n </IconButton>\n </InputAdornment>\n ),\n },\n }}\n />\n </form>\n )\n },\n)\nSearchBox.displayName = 'AglynSearchBox'\n\nexport const schema: Aglyn.ComponentSchema<SearchBoxProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Search Box',\n description:\n \"A search field that opens the site's search page. It works without JavaScript.\",\n category: Aglyn.ComponentCategory.FORMS,\n icon: { path: mdiMagnify.path, sx: { color: '#455a64' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'placeholder',\n description: 'Placeholder text inside the search field.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Placeholder',\n },\n {\n name: 'defaultValue',\n description:\n 'Text the field starts with. The search results page fills in the ' +\n 'query it is showing.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Starting text',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Search Box',\n pluginId: BUNDLE_ID,\n description: 'Search field that opens the site search page',\n category: Aglyn.ComponentCategory.FORMS,\n icon: { path: mdiMagnify.path, sx: { color: '#455a64' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default SearchBox\n"],"names":["Aglyn","mdiMagnify","IconButton","InputAdornment","TextField","MdiIcon","forwardRef","BUNDLE_ID","generatePresetId","ID","SearchBox","props","ref","placeholder","defaultValue","rest","form","action","method","role","name","size","slotProps","input","endAdornment","position","type","aria-label","path","fontSize","displayName","schema","$id","pluginId","description","category","ComponentCategory","FORMS","icon","sx","color","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","component","FieldComponentType","TEXT_FIELD","label","presets","NodeType","PRESET","data","componentId"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,UAAU,QAAQ,yBAAwB;AACnD,OAAOC,gBAAgB,2BAA0B;AACjD,OAAOC,oBAAoB,+BAA8B;AACzD,OAAOC,eAAe,0BAAyB;AAC/C,SAASC,OAAO,QAAQ,uBAAsB;AAC9C,SAASC,UAAU,QAAQ,QAAO;AAClC,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,gBAAgB,QAAQ,iCAA6B;AAE9D,iEAAiE;AACjE,OAAO,MAAMC,KAAwB,YAAW;AAgBhD;;;;;CAKC,GACD,MAAMC,0BAAYJ,WAChB,CAACK,OAAOC;IACN,MAAM,EAAEC,WAAW,EAAEC,YAAY,EAAW,GAAGH,OAATI,wCAASJ;;;;IAC/C,qBACE,KAACK;QAAKJ,KAAKA;QAAKK,QAAO;QAAUC,QAAO;QAAMC,MAAK;OAAaJ;kBAC9D,cAAA,KAACX;YACCgB,MAAK;YACLC,MAAK;YACLR,aAAaA,eAAe;YAC5BC,cAAcA,gBAAgB;YAC9BQ,WAAW;gBACTC,OAAO;oBACLC,4BACE,KAACrB;wBAAesB,UAAS;kCACvB,cAAA,KAACvB;4BAAWwB,MAAK;4BAASL,MAAK;4BAAQM,cAAW;sCAChD,cAAA,KAACtB;gCAAQuB,MAAM3B,WAAW2B,IAAI;gCAAEC,UAAS;;;;gBAIjD;YACF;;;AAIR;AAEFnB,UAAUoB,WAAW,GAAG;AAExB,OAAO,MAAMC,SAAgD;IAC3DC,KAAKvB;IACLwB,UAAU1B;IACVuB,aAAa;IACbI,aACE;IACFC,UAAUnC,MAAMoC,iBAAiB,CAACC,KAAK;IACvCC,MAAM;QAAEV,MAAM3B,WAAW2B,IAAI;QAAEW,IAAI;YAAEC,OAAO;QAAU;IAAE;IACxDC,OAAO;QAAEC,aAAa1C,MAAM2C,YAAY,CAACC,OAAO;IAAC;IACjDC,YAAY;QACV;YACEzB,MAAM;YACNc,aAAa;YACbY,WAAW9C,MAAM+C,kBAAkB,CAACC,UAAU;YAC9CC,OAAO;QACT;QACA;YACE7B,MAAM;YACNc,aACE,sEACA;YACFY,WAAW9C,MAAM+C,kBAAkB,CAACC,UAAU;YAC9CC,OAAO;QACT;KACD;AACH,EAAC;AAED,OAAO,MAAMC,UAAgC;IAC3C;QACElB,KAAKxB,iBAAiBC;QACtBiB,MAAM1B,MAAMmD,QAAQ,CAACC,MAAM;QAC3BtB,aAAa;QACbG,UAAU1B;QACV2B,aAAa;QACbC,UAAUnC,MAAMoC,iBAAiB,CAACC,KAAK;QACvCC,MAAM;YAAEV,MAAM3B,WAAW2B,IAAI;YAAEW,IAAI;gBAAEC,OAAO;YAAU;QAAE;QACxDa,MAAM;YACJrB,KAAK;YACLsB,aAAa7C;YACbwB,UAAU1B;YACVI,OAAO,CAAC;QACV;IACF;CACD,CAAA;AAED,eAAeD,UAAS"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import * as Aglyn from '@aglyn/aglyn';
18
+ export declare const ID: Aglyn.ComponentId;
19
+ /**
20
+ * W3C sectioning/grouping elements the component may render as (AGL-336).
21
+ *
22
+ * ⛔ `main` IS NOT ONE OF THEM (AGL-2486). A published page carries exactly
23
+ * one `main` landmark, placed by composition on the page's content region —
24
+ * the layout's slot, or the screen root when there is no layout, each of which
25
+ * offers its own element picker. An author-selectable `main` on a grouping
26
+ * container that may appear any number of times per page could only ever
27
+ * produce a SECOND one — and two `main` elements is a worse
28
+ * accessibility outcome than none, because the landmark stops naming anything
29
+ * in particular. It was offered in this select, with field help recommending
30
+ * it, which made the duplicate the documented choice rather than a mistake.
31
+ *
32
+ * Removing it degrades rather than breaks: the resolver below falls back to
33
+ * `section` for any value not in this list, so a stored `element: 'main'` on a
34
+ * published screen renders as `<section>` — still a grouping element, still
35
+ * where the author put it, and no longer competing with the layout's landmark.
36
+ */
37
+ export declare const SECTION_ELEMENTS: readonly ["section", "div", "article", "aside", "nav", "header", "footer"];
38
+ export type SectionElement = (typeof SECTION_ELEMENTS)[number];
39
+ export interface SectionProps {
40
+ /** The DOM element rendered; defaults to `section`. */
41
+ element?: SectionElement;
42
+ /** Accessible name announced for landmark elements. */
43
+ ariaLabel?: string;
44
+ children?: JSX.Children;
45
+ }
46
+ /**
47
+ * Semantic grouping container (AGL-336): renders children inside the
48
+ * chosen W3C element so pages keep meaningful document structure
49
+ * (landmarks for assistive tech, better SEO outlines) instead of
50
+ * div-soup. Behaves like any container: droppable, stylable via sx,
51
+ * classes, and interactions.
52
+ */
53
+ declare const Section: import("react").ForwardRefExoticComponent<SectionProps & import("react").RefAttributes<HTMLElement>>;
54
+ export declare const schema: Aglyn.ComponentSchema<SectionProps>;
55
+ export declare const presets: Aglyn.PresetSchema[];
56
+ export default Section;