@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.
- package/LICENSE +201 -0
- package/README.md +22 -0
- package/package.json +47 -0
- package/src/index.d.ts +21 -0
- package/src/index.js +22 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/accordion.d.ts +96 -0
- package/src/lib/components/accordion.js +392 -0
- package/src/lib/components/accordion.js.map +1 -0
- package/src/lib/components/app-bar.d.ts +32 -0
- package/src/lib/components/app-bar.js +86 -0
- package/src/lib/components/app-bar.js.map +1 -0
- package/src/lib/components/blocks.d.ts +46 -0
- package/src/lib/components/blocks.js +1007 -0
- package/src/lib/components/blocks.js.map +1 -0
- package/src/lib/components/box.d.ts +47 -0
- package/src/lib/components/box.js +125 -0
- package/src/lib/components/box.js.map +1 -0
- package/src/lib/components/breadcrumbs.d.ts +44 -0
- package/src/lib/components/breadcrumbs.js +172 -0
- package/src/lib/components/breadcrumbs.js.map +1 -0
- package/src/lib/components/button.d.ts +89 -0
- package/src/lib/components/button.js +272 -0
- package/src/lib/components/button.js.map +1 -0
- package/src/lib/components/card.d.ts +61 -0
- package/src/lib/components/card.js +336 -0
- package/src/lib/components/card.js.map +1 -0
- package/src/lib/components/collection.d.ts +514 -0
- package/src/lib/components/collection.js +2999 -0
- package/src/lib/components/collection.js.map +1 -0
- package/src/lib/components/container.d.ts +42 -0
- package/src/lib/components/container.js +169 -0
- package/src/lib/components/container.js.map +1 -0
- package/src/lib/components/custom-html.d.ts +78 -0
- package/src/lib/components/custom-html.js +219 -0
- package/src/lib/components/custom-html.js.map +1 -0
- package/src/lib/components/data-table.d.ts +57 -0
- package/src/lib/components/data-table.js +216 -0
- package/src/lib/components/data-table.js.map +1 -0
- package/src/lib/components/document-root.d.ts +77 -0
- package/src/lib/components/document-root.js +118 -0
- package/src/lib/components/document-root.js.map +1 -0
- package/src/lib/components/drawer.d.ts +93 -0
- package/src/lib/components/drawer.js +566 -0
- package/src/lib/components/drawer.js.map +1 -0
- package/src/lib/components/function-controls.d.ts +66 -0
- package/src/lib/components/function-controls.js +207 -0
- package/src/lib/components/function-controls.js.map +1 -0
- package/src/lib/components/function-scope.d.ts +110 -0
- package/src/lib/components/function-scope.js +478 -0
- package/src/lib/components/function-scope.js.map +1 -0
- package/src/lib/components/function-widget.d.ts +75 -0
- package/src/lib/components/function-widget.js +307 -0
- package/src/lib/components/function-widget.js.map +1 -0
- package/src/lib/components/grid.d.ts +91 -0
- package/src/lib/components/grid.js +322 -0
- package/src/lib/components/grid.js.map +1 -0
- package/src/lib/components/icon.d.ts +54 -0
- package/src/lib/components/icon.js +163 -0
- package/src/lib/components/icon.js.map +1 -0
- package/src/lib/components/image-list.d.ts +58 -0
- package/src/lib/components/image-list.js +336 -0
- package/src/lib/components/image-list.js.map +1 -0
- package/src/lib/components/image.d.ts +154 -0
- package/src/lib/components/image.js +451 -0
- package/src/lib/components/image.js.map +1 -0
- package/src/lib/components/inline-text.d.ts +74 -0
- package/src/lib/components/inline-text.js +407 -0
- package/src/lib/components/inline-text.js.map +1 -0
- package/src/lib/components/language-switcher.d.ts +35 -0
- package/src/lib/components/language-switcher.js +179 -0
- package/src/lib/components/language-switcher.js.map +1 -0
- package/src/lib/components/layout-slot.d.ts +68 -0
- package/src/lib/components/layout-slot.js +192 -0
- package/src/lib/components/layout-slot.js.map +1 -0
- package/src/lib/components/link-box-accessible-name.d.ts +79 -0
- package/src/lib/components/link-box-accessible-name.js +158 -0
- package/src/lib/components/link-box-accessible-name.js.map +1 -0
- package/src/lib/components/link-box.d.ts +66 -0
- package/src/lib/components/link-box.js +212 -0
- package/src/lib/components/link-box.js.map +1 -0
- package/src/lib/components/list-item-text.d.ts +22 -0
- package/src/lib/components/list-item-text.js +86 -0
- package/src/lib/components/list-item-text.js.map +1 -0
- package/src/lib/components/list-item.d.ts +32 -0
- package/src/lib/components/list-item.js +127 -0
- package/src/lib/components/list-item.js.map +1 -0
- package/src/lib/components/list.d.ts +34 -0
- package/src/lib/components/list.js +108 -0
- package/src/lib/components/list.js.map +1 -0
- package/src/lib/components/markdown.d.ts +129 -0
- package/src/lib/components/markdown.js +853 -0
- package/src/lib/components/markdown.js.map +1 -0
- package/src/lib/components/nav-menu.d.ts +68 -0
- package/src/lib/components/nav-menu.js +683 -0
- package/src/lib/components/nav-menu.js.map +1 -0
- package/src/lib/components/pagination.d.ts +59 -0
- package/src/lib/components/pagination.js +243 -0
- package/src/lib/components/pagination.js.map +1 -0
- package/src/lib/components/paper.d.ts +47 -0
- package/src/lib/components/paper.js +202 -0
- package/src/lib/components/paper.js.map +1 -0
- package/src/lib/components/plugin-frame.d.ts +64 -0
- package/src/lib/components/plugin-frame.js +335 -0
- package/src/lib/components/plugin-frame.js.map +1 -0
- package/src/lib/components/plugin.d.ts +95 -0
- package/src/lib/components/plugin.js +304 -0
- package/src/lib/components/plugin.js.map +1 -0
- package/src/lib/components/product.d.ts +40 -0
- package/src/lib/components/product.js +287 -0
- package/src/lib/components/product.js.map +1 -0
- package/src/lib/components/reusable-instance.d.ts +57 -0
- package/src/lib/components/reusable-instance.js +126 -0
- package/src/lib/components/reusable-instance.js.map +1 -0
- package/src/lib/components/screen-link.d.ts +85 -0
- package/src/lib/components/screen-link.js +324 -0
- package/src/lib/components/screen-link.js.map +1 -0
- package/src/lib/components/search-box.d.ts +41 -0
- package/src/lib/components/search-box.js +125 -0
- package/src/lib/components/search-box.js.map +1 -0
- package/src/lib/components/section.d.ts +56 -0
- package/src/lib/components/section.js +132 -0
- package/src/lib/components/section.js.map +1 -0
- package/src/lib/components/stack.d.ts +55 -0
- package/src/lib/components/stack.js +309 -0
- package/src/lib/components/stack.js.map +1 -0
- package/src/lib/components/tabs.d.ts +288 -0
- package/src/lib/components/tabs.js +788 -0
- package/src/lib/components/tabs.js.map +1 -0
- package/src/lib/components/theme-mode-switcher.d.ts +38 -0
- package/src/lib/components/theme-mode-switcher.js +168 -0
- package/src/lib/components/theme-mode-switcher.js.map +1 -0
- package/src/lib/components/toolbar.d.ts +37 -0
- package/src/lib/components/toolbar.js +117 -0
- package/src/lib/components/toolbar.js.map +1 -0
- package/src/lib/components/typography.d.ts +33 -0
- package/src/lib/components/typography.js +433 -0
- package/src/lib/components/typography.js.map +1 -0
- package/src/lib/components/video-lightbox-controls.d.ts +131 -0
- package/src/lib/components/video-lightbox-controls.js +536 -0
- package/src/lib/components/video-lightbox-controls.js.map +1 -0
- package/src/lib/components/video-lightbox.d.ts +60 -0
- package/src/lib/components/video-lightbox.js +247 -0
- package/src/lib/components/video-lightbox.js.map +1 -0
- package/src/lib/components/video-playback-beacon.d.ts +80 -0
- package/src/lib/components/video-playback-beacon.js +128 -0
- package/src/lib/components/video-playback-beacon.js.map +1 -0
- package/src/lib/components/video-player-frame.d.ts +58 -0
- package/src/lib/components/video-player-frame.js +51 -0
- package/src/lib/components/video-player-frame.js.map +1 -0
- package/src/lib/components/video.d.ts +220 -0
- package/src/lib/components/video.js +874 -0
- package/src/lib/components/video.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +17 -0
- package/src/lib/constants/bundle-common.js +18 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/constants/field-presets.d.ts +93 -0
- package/src/lib/constants/field-presets.js +248 -0
- package/src/lib/constants/field-presets.js.map +1 -0
- package/src/lib/plugin.d.ts +80 -0
- package/src/lib/plugin.js +599 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/utils/author-html-label.d.ts +73 -0
- package/src/lib/utils/author-html-label.js +89 -0
- package/src/lib/utils/author-html-label.js.map +1 -0
- package/src/lib/utils/drop-cleared-props.d.ts +18 -0
- package/src/lib/utils/drop-cleared-props.js +74 -0
- package/src/lib/utils/drop-cleared-props.js.map +1 -0
- package/src/lib/utils/element-picker.d.ts +99 -0
- package/src/lib/utils/element-picker.js +140 -0
- package/src/lib/utils/element-picker.js.map +1 -0
- package/src/lib/utils/generate-preset-id.d.ts +19 -0
- package/src/lib/utils/generate-preset-id.js +25 -0
- package/src/lib/utils/generate-preset-id.js.map +1 -0
- package/src/lib/utils/link-target-props.d.ts +53 -0
- package/src/lib/utils/link-target-props.js +53 -0
- package/src/lib/utils/link-target-props.js.map +1 -0
|
@@ -0,0 +1,73 @@
|
|
|
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 type { ReactNode } from 'react';
|
|
18
|
+
/**
|
|
19
|
+
* The formatted label of a CONTROL — a Button, a Screen Link, an Accordion
|
|
20
|
+
* Summary (AGL-2557).
|
|
21
|
+
*
|
|
22
|
+
* ## The three parts that have to travel together
|
|
23
|
+
*
|
|
24
|
+
* The inline editor's rich mode commits sanitized markup into an `html` prop
|
|
25
|
+
* and keeps `children` as the plain-text fallback. Until this existed,
|
|
26
|
+
* `typography.tsx` was the only component that read `html` back, so setting
|
|
27
|
+
* the editor's flag anywhere else would have shipped a toolbar whose output
|
|
28
|
+
* was discarded: bold while typing, plain the moment it committed. A
|
|
29
|
+
* component earns the flag by declaring the prop, rendering it through here,
|
|
30
|
+
* and only then turning the flag on.
|
|
31
|
+
*
|
|
32
|
+
* ## Sanitized on EVERY render (AGL-497)
|
|
33
|
+
*
|
|
34
|
+
* The editor sanitizes at commit, and that is not where the guarantee comes
|
|
35
|
+
* from. Screen node props are written straight through the Firebase client
|
|
36
|
+
* SDK, so a host editor can plant arbitrary `html` on a node without the
|
|
37
|
+
* editor ever seeing it — and it would then execute on the published site
|
|
38
|
+
* AND on the besigner canvas at app.aglyn.com. `sanitizeAuthorHtml` is pure
|
|
39
|
+
* and needs no DOM (AGL-1901), so the server and the first client render
|
|
40
|
+
* compute the same bytes and hydration is clean by construction.
|
|
41
|
+
*
|
|
42
|
+
* ## Why the narrowed allowlist
|
|
43
|
+
*
|
|
44
|
+
* A control's content model is phrasing content with no interactive
|
|
45
|
+
* descendant, so this passes {@link Aglyn.INLINE_AUTHOR_HTML_ELEMENTS}: no
|
|
46
|
+
* lists, no blocks, no nested anchor. That is a rendering requirement, not a
|
|
47
|
+
* tidiness one — the parser closes a `<button>` on a `<div>` start tag and
|
|
48
|
+
* promotes the rest to a sibling, which is a React hydration mismatch on the
|
|
49
|
+
* tenant. The toolbar declines to OFFER those commands for these components
|
|
50
|
+
* (`richTextCommands`), and this is what holds the line for markup that
|
|
51
|
+
* arrived some other way.
|
|
52
|
+
*
|
|
53
|
+
* ## Why `<aglyn-text>` and not a `<span>`
|
|
54
|
+
*
|
|
55
|
+
* The canvas edits a leaf's own `<aglyn-text>` when it renders one, and
|
|
56
|
+
* falls back to the leaf root otherwise (AGL-2556). For a composite like
|
|
57
|
+
* Accordion Summary the root is the `<button>`, and in-place editing EMPTIES
|
|
58
|
+
* whatever it is handed — which would take MUI's content wrapper, and its
|
|
59
|
+
* `textAlign: 'start'`, with it for the length of the edit. Rendering the
|
|
60
|
+
* formatted label into the same element the plain label uses keeps one edit
|
|
61
|
+
* target for both modes.
|
|
62
|
+
*/
|
|
63
|
+
export declare function authorHtmlLabel(html: unknown): ReactNode | null;
|
|
64
|
+
/**
|
|
65
|
+
* `props` with the formatted label substituted for its children, or `props`
|
|
66
|
+
* itself when the node carries no `html`.
|
|
67
|
+
*
|
|
68
|
+
* Returned BY IDENTITY in the unformatted case, which is the overwhelmingly
|
|
69
|
+
* common one — a Screen Link is the busiest element on a published page at
|
|
70
|
+
* 70–77 nodes — so an element nobody has formatted allocates nothing and
|
|
71
|
+
* renders the tree it always did.
|
|
72
|
+
*/
|
|
73
|
+
export declare function withAuthorHtmlLabel<P extends object>(props: P, html: unknown): P;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @license
|
|
5
|
+
* Copyright 2026 Aglyn LLC
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/ import * as Aglyn from "@aglyn/aglyn";
|
|
19
|
+
import { AglynText } from "@aglyn/shared-ui-jsx";
|
|
20
|
+
/**
|
|
21
|
+
* The formatted label of a CONTROL — a Button, a Screen Link, an Accordion
|
|
22
|
+
* Summary (AGL-2557).
|
|
23
|
+
*
|
|
24
|
+
* ## The three parts that have to travel together
|
|
25
|
+
*
|
|
26
|
+
* The inline editor's rich mode commits sanitized markup into an `html` prop
|
|
27
|
+
* and keeps `children` as the plain-text fallback. Until this existed,
|
|
28
|
+
* `typography.tsx` was the only component that read `html` back, so setting
|
|
29
|
+
* the editor's flag anywhere else would have shipped a toolbar whose output
|
|
30
|
+
* was discarded: bold while typing, plain the moment it committed. A
|
|
31
|
+
* component earns the flag by declaring the prop, rendering it through here,
|
|
32
|
+
* and only then turning the flag on.
|
|
33
|
+
*
|
|
34
|
+
* ## Sanitized on EVERY render (AGL-497)
|
|
35
|
+
*
|
|
36
|
+
* The editor sanitizes at commit, and that is not where the guarantee comes
|
|
37
|
+
* from. Screen node props are written straight through the Firebase client
|
|
38
|
+
* SDK, so a host editor can plant arbitrary `html` on a node without the
|
|
39
|
+
* editor ever seeing it — and it would then execute on the published site
|
|
40
|
+
* AND on the besigner canvas at app.aglyn.com. `sanitizeAuthorHtml` is pure
|
|
41
|
+
* and needs no DOM (AGL-1901), so the server and the first client render
|
|
42
|
+
* compute the same bytes and hydration is clean by construction.
|
|
43
|
+
*
|
|
44
|
+
* ## Why the narrowed allowlist
|
|
45
|
+
*
|
|
46
|
+
* A control's content model is phrasing content with no interactive
|
|
47
|
+
* descendant, so this passes {@link Aglyn.INLINE_AUTHOR_HTML_ELEMENTS}: no
|
|
48
|
+
* lists, no blocks, no nested anchor. That is a rendering requirement, not a
|
|
49
|
+
* tidiness one — the parser closes a `<button>` on a `<div>` start tag and
|
|
50
|
+
* promotes the rest to a sibling, which is a React hydration mismatch on the
|
|
51
|
+
* tenant. The toolbar declines to OFFER those commands for these components
|
|
52
|
+
* (`richTextCommands`), and this is what holds the line for markup that
|
|
53
|
+
* arrived some other way.
|
|
54
|
+
*
|
|
55
|
+
* ## Why `<aglyn-text>` and not a `<span>`
|
|
56
|
+
*
|
|
57
|
+
* The canvas edits a leaf's own `<aglyn-text>` when it renders one, and
|
|
58
|
+
* falls back to the leaf root otherwise (AGL-2556). For a composite like
|
|
59
|
+
* Accordion Summary the root is the `<button>`, and in-place editing EMPTIES
|
|
60
|
+
* whatever it is handed — which would take MUI's content wrapper, and its
|
|
61
|
+
* `textAlign: 'start'`, with it for the length of the edit. Rendering the
|
|
62
|
+
* formatted label into the same element the plain label uses keeps one edit
|
|
63
|
+
* target for both modes.
|
|
64
|
+
*/ export function authorHtmlLabel(html) {
|
|
65
|
+
if (typeof html !== 'string' || !html) return null;
|
|
66
|
+
return /*#__PURE__*/ _jsx(AglynText, {
|
|
67
|
+
dangerouslySetInnerHTML: {
|
|
68
|
+
__html: Aglyn.sanitizeAuthorHtml(html, undefined, {
|
|
69
|
+
allowedElements: Aglyn.INLINE_AUTHOR_HTML_ELEMENTS
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* `props` with the formatted label substituted for its children, or `props`
|
|
76
|
+
* itself when the node carries no `html`.
|
|
77
|
+
*
|
|
78
|
+
* Returned BY IDENTITY in the unformatted case, which is the overwhelmingly
|
|
79
|
+
* common one — a Screen Link is the busiest element on a published page at
|
|
80
|
+
* 70–77 nodes — so an element nobody has formatted allocates nothing and
|
|
81
|
+
* renders the tree it always did.
|
|
82
|
+
*/ export function withAuthorHtmlLabel(props, html) {
|
|
83
|
+
const label = authorHtmlLabel(html);
|
|
84
|
+
return label ? _extends({}, props, {
|
|
85
|
+
children: label
|
|
86
|
+
}) : props;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//# sourceMappingURL=author-html-label.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/utils/author-html-label.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 { AglynText } from '@aglyn/shared-ui-jsx'\nimport type { ReactNode } from 'react'\n\n/**\n * The formatted label of a CONTROL — a Button, a Screen Link, an Accordion\n * Summary (AGL-2557).\n *\n * ## The three parts that have to travel together\n *\n * The inline editor's rich mode commits sanitized markup into an `html` prop\n * and keeps `children` as the plain-text fallback. Until this existed,\n * `typography.tsx` was the only component that read `html` back, so setting\n * the editor's flag anywhere else would have shipped a toolbar whose output\n * was discarded: bold while typing, plain the moment it committed. A\n * component earns the flag by declaring the prop, rendering it through here,\n * and only then turning the flag on.\n *\n * ## Sanitized on EVERY render (AGL-497)\n *\n * The editor sanitizes at commit, and that is not where the guarantee comes\n * from. Screen node props are written straight through the Firebase client\n * SDK, so a host editor can plant arbitrary `html` on a node without the\n * editor ever seeing it — and it would then execute on the published site\n * AND on the besigner canvas at app.aglyn.com. `sanitizeAuthorHtml` is pure\n * and needs no DOM (AGL-1901), so the server and the first client render\n * compute the same bytes and hydration is clean by construction.\n *\n * ## Why the narrowed allowlist\n *\n * A control's content model is phrasing content with no interactive\n * descendant, so this passes {@link Aglyn.INLINE_AUTHOR_HTML_ELEMENTS}: no\n * lists, no blocks, no nested anchor. That is a rendering requirement, not a\n * tidiness one — the parser closes a `<button>` on a `<div>` start tag and\n * promotes the rest to a sibling, which is a React hydration mismatch on the\n * tenant. The toolbar declines to OFFER those commands for these components\n * (`richTextCommands`), and this is what holds the line for markup that\n * arrived some other way.\n *\n * ## Why `<aglyn-text>` and not a `<span>`\n *\n * The canvas edits a leaf's own `<aglyn-text>` when it renders one, and\n * falls back to the leaf root otherwise (AGL-2556). For a composite like\n * Accordion Summary the root is the `<button>`, and in-place editing EMPTIES\n * whatever it is handed — which would take MUI's content wrapper, and its\n * `textAlign: 'start'`, with it for the length of the edit. Rendering the\n * formatted label into the same element the plain label uses keeps one edit\n * target for both modes.\n */\nexport function authorHtmlLabel(html: unknown): ReactNode | null {\n if (typeof html !== 'string' || !html) return null\n return (\n <AglynText\n dangerouslySetInnerHTML={{\n __html: Aglyn.sanitizeAuthorHtml(html, undefined, {\n allowedElements: Aglyn.INLINE_AUTHOR_HTML_ELEMENTS,\n }),\n }}\n />\n )\n}\n\n/**\n * `props` with the formatted label substituted for its children, or `props`\n * itself when the node carries no `html`.\n *\n * Returned BY IDENTITY in the unformatted case, which is the overwhelmingly\n * common one — a Screen Link is the busiest element on a published page at\n * 70–77 nodes — so an element nobody has formatted allocates nothing and\n * renders the tree it always did.\n */\nexport function withAuthorHtmlLabel<P extends object>(\n props: P,\n html: unknown,\n): P {\n const label = authorHtmlLabel(html)\n return label ? ({ ...props, children: label } as P) : props\n}\n"],"names":["Aglyn","AglynText","authorHtmlLabel","html","dangerouslySetInnerHTML","__html","sanitizeAuthorHtml","undefined","allowedElements","INLINE_AUTHOR_HTML_ELEMENTS","withAuthorHtmlLabel","props","label","children"],"mappings":";;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,SAAS,QAAQ,uBAAsB;AAGhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4CC,GACD,OAAO,SAASC,gBAAgBC,IAAa;IAC3C,IAAI,OAAOA,SAAS,YAAY,CAACA,MAAM,OAAO;IAC9C,qBACE,KAACF;QACCG,yBAAyB;YACvBC,QAAQL,MAAMM,kBAAkB,CAACH,MAAMI,WAAW;gBAChDC,iBAAiBR,MAAMS,2BAA2B;YACpD;QACF;;AAGN;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASC,oBACdC,KAAQ,EACRR,IAAa;IAEb,MAAMS,QAAQV,gBAAgBC;IAC9B,OAAOS,QAAS,aAAKD;QAAOE,UAAUD;SAAgBD;AACxD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
export declare function dropClearedProps<T extends Record<string, any>>(props: T): T;
|
|
18
|
+
export default dropClearedProps;
|
|
@@ -0,0 +1,74 @@
|
|
|
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
|
+
* Drops props an author CLEARED, so MUI's own defaults apply (AGL-1226).
|
|
18
|
+
*
|
|
19
|
+
* The besigner persists a cleared attribute as `null` (or `''`), and React
|
|
20
|
+
* only falls back to a default for `undefined` — an explicit `null` is a
|
|
21
|
+
* value. So `<Button color={null}>` does NOT become `color="primary"`; the
|
|
22
|
+
* null travels all the way into MUI, which builds its class names with
|
|
23
|
+
* `` `color${capitalize(color)}` `` and throws:
|
|
24
|
+
*
|
|
25
|
+
* Minified MUI error #7 — capitalize(string) expects a string argument
|
|
26
|
+
*
|
|
27
|
+
* That is a SERVER-SIDE THROW during render, so the whole page 500s. It took
|
|
28
|
+
* down every `/product/*` page on the public marketing site, uncached
|
|
29
|
+
* (`x-vercel-cache: MISS` every time), for as long as one button carried a
|
|
30
|
+
* cleared colour.
|
|
31
|
+
*
|
|
32
|
+
* Stripping the key instead is what the author meant by clearing it: fall
|
|
33
|
+
* back to the component's default. Applied at the wrapper boundary rather
|
|
34
|
+
* than fixing the two offending documents, because a data fix leaves every
|
|
35
|
+
* other site one cleared dropdown away from the same 500.
|
|
36
|
+
*
|
|
37
|
+
* `0` and `false` are kept — those are real values an author can mean.
|
|
38
|
+
*
|
|
39
|
+
* `data-*` and `aria-*` are kept whatever their value. Only an authored
|
|
40
|
+
* ATTRIBUTE can be cleared, and neither of those is one: they are stamped by
|
|
41
|
+
* the renderer, and the canvas writes its flags PRESENCE-BASED — `''` for on,
|
|
42
|
+
* `undefined` for off — which is the same empty string a cleared select
|
|
43
|
+
* persists as. Dropping them took out every presence flag on every component
|
|
44
|
+
* that funnels through here: `data-aglyn-revealed`, so a panel carrying the
|
|
45
|
+
* hidden class could never be shown for designing; `data-aglyn-selected-within`,
|
|
46
|
+
* which is how a nav menu and a drawer know to open while they are being
|
|
47
|
+
* authored; and `data-aglyn-bound`, the outline on an element whose props
|
|
48
|
+
* carry bindings. They are also incapable of the crash above — both go
|
|
49
|
+
* straight to the DOM, where an empty attribute is ordinary HTML and nothing
|
|
50
|
+
* calls `capitalize()` on the value.
|
|
51
|
+
*/ function isRendererAttribute(key) {
|
|
52
|
+
return key.startsWith('data-') || key.startsWith('aria-');
|
|
53
|
+
}
|
|
54
|
+
export function dropClearedProps(props) {
|
|
55
|
+
let cleared = false;
|
|
56
|
+
for(const key in props){
|
|
57
|
+
const value = props[key];
|
|
58
|
+
if ((value === null || value === '') && !isRendererAttribute(key)) {
|
|
59
|
+
cleared = true;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!cleared) return props;
|
|
64
|
+
const next = {};
|
|
65
|
+
for(const key in props){
|
|
66
|
+
const value = props[key];
|
|
67
|
+
if ((value === null || value === '') && !isRendererAttribute(key)) continue;
|
|
68
|
+
next[key] = value;
|
|
69
|
+
}
|
|
70
|
+
return next;
|
|
71
|
+
}
|
|
72
|
+
export default dropClearedProps;
|
|
73
|
+
|
|
74
|
+
//# sourceMappingURL=drop-cleared-props.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/utils/drop-cleared-props.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Drops props an author CLEARED, so MUI's own defaults apply (AGL-1226).\n *\n * The besigner persists a cleared attribute as `null` (or `''`), and React\n * only falls back to a default for `undefined` — an explicit `null` is a\n * value. So `<Button color={null}>` does NOT become `color=\"primary\"`; the\n * null travels all the way into MUI, which builds its class names with\n * `` `color${capitalize(color)}` `` and throws:\n *\n * Minified MUI error #7 — capitalize(string) expects a string argument\n *\n * That is a SERVER-SIDE THROW during render, so the whole page 500s. It took\n * down every `/product/*` page on the public marketing site, uncached\n * (`x-vercel-cache: MISS` every time), for as long as one button carried a\n * cleared colour.\n *\n * Stripping the key instead is what the author meant by clearing it: fall\n * back to the component's default. Applied at the wrapper boundary rather\n * than fixing the two offending documents, because a data fix leaves every\n * other site one cleared dropdown away from the same 500.\n *\n * `0` and `false` are kept — those are real values an author can mean.\n *\n * `data-*` and `aria-*` are kept whatever their value. Only an authored\n * ATTRIBUTE can be cleared, and neither of those is one: they are stamped by\n * the renderer, and the canvas writes its flags PRESENCE-BASED — `''` for on,\n * `undefined` for off — which is the same empty string a cleared select\n * persists as. Dropping them took out every presence flag on every component\n * that funnels through here: `data-aglyn-revealed`, so a panel carrying the\n * hidden class could never be shown for designing; `data-aglyn-selected-within`,\n * which is how a nav menu and a drawer know to open while they are being\n * authored; and `data-aglyn-bound`, the outline on an element whose props\n * carry bindings. They are also incapable of the crash above — both go\n * straight to the DOM, where an empty attribute is ordinary HTML and nothing\n * calls `capitalize()` on the value.\n */\nfunction isRendererAttribute(key: string): boolean {\n return key.startsWith('data-') || key.startsWith('aria-')\n}\n\nexport function dropClearedProps<T extends Record<string, any>>(props: T): T {\n let cleared = false\n for (const key in props) {\n const value = props[key]\n if ((value === null || value === '') && !isRendererAttribute(key)) {\n cleared = true\n break\n }\n }\n if (!cleared) return props\n const next: Record<string, any> = {}\n for (const key in props) {\n const value = props[key]\n if ((value === null || value === '') && !isRendererAttribute(key)) continue\n next[key] = value\n }\n return next as T\n}\n\nexport default dropClearedProps\n"],"names":["isRendererAttribute","key","startsWith","dropClearedProps","props","cleared","value","next"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCC,GACD,SAASA,oBAAoBC,GAAW;IACtC,OAAOA,IAAIC,UAAU,CAAC,YAAYD,IAAIC,UAAU,CAAC;AACnD;AAEA,OAAO,SAASC,iBAAgDC,KAAQ;IACtE,IAAIC,UAAU;IACd,IAAK,MAAMJ,OAAOG,MAAO;QACvB,MAAME,QAAQF,KAAK,CAACH,IAAI;QACxB,IAAI,AAACK,CAAAA,UAAU,QAAQA,UAAU,EAAC,KAAM,CAACN,oBAAoBC,MAAM;YACjEI,UAAU;YACV;QACF;IACF;IACA,IAAI,CAACA,SAAS,OAAOD;IACrB,MAAMG,OAA4B,CAAC;IACnC,IAAK,MAAMN,OAAOG,MAAO;QACvB,MAAME,QAAQF,KAAK,CAACH,IAAI;QACxB,IAAI,AAACK,CAAAA,UAAU,QAAQA,UAAU,EAAC,KAAM,CAACN,oBAAoBC,MAAM;QACnEM,IAAI,CAACN,IAAI,GAAGK;IACd;IACA,OAAOC;AACT;AAEA,eAAeJ,iBAAgB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import * as Aglyn from '@aglyn/aglyn';
|
|
18
|
+
/**
|
|
19
|
+
* THE ELEMENT PICKER EVERY CONTAINER GETS (AGL-2525).
|
|
20
|
+
*
|
|
21
|
+
* Section owned the semantic elements alone, so an author who wanted their nav
|
|
22
|
+
* row to BE the `nav` had to wrap it in a second element to say so — and on
|
|
23
|
+
* `aglyn.com` nobody did, which is why the published page had no navigation
|
|
24
|
+
* landmark at all. Wrapping to name a thing is the same shape of
|
|
25
|
+
* element-nobody-authored that AGL-2521 removed from component placements,
|
|
26
|
+
* arriving by a different route.
|
|
27
|
+
*
|
|
28
|
+
* ⛔ `main` IS NOT ON THIS LIST. A page carries exactly one, placed by
|
|
29
|
+
* `stampDocumentLandmark` on the Document layer or the Layout Slot — the two
|
|
30
|
+
* nodes that appear at most once per document. Everything using this picker can
|
|
31
|
+
* be placed any number of times, so an author-selected `main` here could only
|
|
32
|
+
* ever be the second one.
|
|
33
|
+
*
|
|
34
|
+
* An allow-list rather than free text: the value is persisted and rendered
|
|
35
|
+
* verbatim, so a typed one would put `script` into every visitor's page.
|
|
36
|
+
*/
|
|
37
|
+
export declare const SEMANTIC_ELEMENTS: readonly ["div", "section", "article", "aside", "nav", "header", "footer"];
|
|
38
|
+
export type SemanticElement = (typeof SEMANTIC_ELEMENTS)[number];
|
|
39
|
+
/**
|
|
40
|
+
* The element to render, or `undefined` to leave the component's own default
|
|
41
|
+
* alone.
|
|
42
|
+
*
|
|
43
|
+
* Returning `undefined` rather than `'div'` is what lets this be added to a
|
|
44
|
+
* component that does NOT default to a div — App Bar renders `header` unless
|
|
45
|
+
* told otherwise, and a resolver that answered `'div'` for "unset" would have
|
|
46
|
+
* silently stripped the banner landmark off every site's chrome the moment the
|
|
47
|
+
* picker appeared.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveSemanticElement(value: unknown): SemanticElement | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* The elements that BECOME a landmark, and so want a name (AGL-2525).
|
|
52
|
+
*
|
|
53
|
+
* `div` is the odd one out: it has no role, so an `aria-label` on it names
|
|
54
|
+
* nothing. Everything else is announced as a region, and a page with two of
|
|
55
|
+
* the same kind — a header nav and a footer nav, say — is a page where
|
|
56
|
+
* "navigation, navigation" is all a screen-reader user hears without one.
|
|
57
|
+
*/
|
|
58
|
+
export declare const LANDMARK_ELEMENTS: ("article" | "aside" | "footer" | "header" | "nav" | "section")[];
|
|
59
|
+
/**
|
|
60
|
+
* Consume the picker's props and return what the underlying MUI component
|
|
61
|
+
* should receive.
|
|
62
|
+
*
|
|
63
|
+
* Takes the whole props bag rather than one value because both keys have to
|
|
64
|
+
* be REMOVED as well as translated: `ariaLabel` spread onto a DOM element is
|
|
65
|
+
* an unknown React prop, warned about on the canvas and serialized onto the
|
|
66
|
+
* published page, which is the shape of the `propValues` leak in AGL-2486.
|
|
67
|
+
*/
|
|
68
|
+
export declare function applySemanticElement<P extends Record<string, unknown>>(props: P): Omit<P, 'component' | 'ariaLabel'> & {
|
|
69
|
+
component?: SemanticElement;
|
|
70
|
+
'aria-label'?: string;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Spreadable `component` prop: present only when the author chose one, so an
|
|
74
|
+
* unset picker is indistinguishable from never having had one.
|
|
75
|
+
*/
|
|
76
|
+
export declare function semanticElementProp(value: unknown): {
|
|
77
|
+
component?: SemanticElement;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* The attribute schema. `subject` names what renders, e.g. "this stack".
|
|
81
|
+
*
|
|
82
|
+
* Labelled `Component`, the name Box, Typography, the Document layer and the
|
|
83
|
+
* Layout Slot already use — Section and Inline text keep `element` as their
|
|
84
|
+
* stored KEY because their values are persisted in published screens, but the
|
|
85
|
+
* panel says one thing everywhere (AGL-2514).
|
|
86
|
+
*/
|
|
87
|
+
export declare function semanticElementAttribute(subject: string): Aglyn.AglynAttributeSchema;
|
|
88
|
+
/**
|
|
89
|
+
* The name for the landmark the picker just made, shown only once one exists.
|
|
90
|
+
*
|
|
91
|
+
* Gated on the element rather than always visible because on a `div` — the
|
|
92
|
+
* default, and what most of these elements stay — the field would do nothing
|
|
93
|
+
* at all, and a control that silently does nothing is worse than no control.
|
|
94
|
+
*
|
|
95
|
+
* This is the half Section already had and the picker did not. Naming stops
|
|
96
|
+
* being optional the moment a page has two landmarks of a kind: a site nav and
|
|
97
|
+
* a footer nav both announce as "navigation" until one of them says which.
|
|
98
|
+
*/
|
|
99
|
+
export declare function semanticElementLabelAttribute(): Aglyn.AglynAttributeSchema;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
3
|
+
/**
|
|
4
|
+
* @license
|
|
5
|
+
* Copyright 2026 Aglyn LLC
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/ import * as Aglyn from "@aglyn/aglyn";
|
|
19
|
+
/**
|
|
20
|
+
* THE ELEMENT PICKER EVERY CONTAINER GETS (AGL-2525).
|
|
21
|
+
*
|
|
22
|
+
* Section owned the semantic elements alone, so an author who wanted their nav
|
|
23
|
+
* row to BE the `nav` had to wrap it in a second element to say so — and on
|
|
24
|
+
* `aglyn.com` nobody did, which is why the published page had no navigation
|
|
25
|
+
* landmark at all. Wrapping to name a thing is the same shape of
|
|
26
|
+
* element-nobody-authored that AGL-2521 removed from component placements,
|
|
27
|
+
* arriving by a different route.
|
|
28
|
+
*
|
|
29
|
+
* ⛔ `main` IS NOT ON THIS LIST. A page carries exactly one, placed by
|
|
30
|
+
* `stampDocumentLandmark` on the Document layer or the Layout Slot — the two
|
|
31
|
+
* nodes that appear at most once per document. Everything using this picker can
|
|
32
|
+
* be placed any number of times, so an author-selected `main` here could only
|
|
33
|
+
* ever be the second one.
|
|
34
|
+
*
|
|
35
|
+
* An allow-list rather than free text: the value is persisted and rendered
|
|
36
|
+
* verbatim, so a typed one would put `script` into every visitor's page.
|
|
37
|
+
*/ export const SEMANTIC_ELEMENTS = [
|
|
38
|
+
'div',
|
|
39
|
+
'section',
|
|
40
|
+
'article',
|
|
41
|
+
'aside',
|
|
42
|
+
'nav',
|
|
43
|
+
'header',
|
|
44
|
+
'footer'
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* The element to render, or `undefined` to leave the component's own default
|
|
48
|
+
* alone.
|
|
49
|
+
*
|
|
50
|
+
* Returning `undefined` rather than `'div'` is what lets this be added to a
|
|
51
|
+
* component that does NOT default to a div — App Bar renders `header` unless
|
|
52
|
+
* told otherwise, and a resolver that answered `'div'` for "unset" would have
|
|
53
|
+
* silently stripped the banner landmark off every site's chrome the moment the
|
|
54
|
+
* picker appeared.
|
|
55
|
+
*/ export function resolveSemanticElement(value) {
|
|
56
|
+
return SEMANTIC_ELEMENTS.includes(String(value != null ? value : '')) ? value : undefined;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The elements that BECOME a landmark, and so want a name (AGL-2525).
|
|
60
|
+
*
|
|
61
|
+
* `div` is the odd one out: it has no role, so an `aria-label` on it names
|
|
62
|
+
* nothing. Everything else is announced as a region, and a page with two of
|
|
63
|
+
* the same kind — a header nav and a footer nav, say — is a page where
|
|
64
|
+
* "navigation, navigation" is all a screen-reader user hears without one.
|
|
65
|
+
*/ export const LANDMARK_ELEMENTS = SEMANTIC_ELEMENTS.filter((element)=>element !== 'div');
|
|
66
|
+
/**
|
|
67
|
+
* Consume the picker's props and return what the underlying MUI component
|
|
68
|
+
* should receive.
|
|
69
|
+
*
|
|
70
|
+
* Takes the whole props bag rather than one value because both keys have to
|
|
71
|
+
* be REMOVED as well as translated: `ariaLabel` spread onto a DOM element is
|
|
72
|
+
* an unknown React prop, warned about on the canvas and serialized onto the
|
|
73
|
+
* published page, which is the shape of the `propValues` leak in AGL-2486.
|
|
74
|
+
*/ export function applySemanticElement(props) {
|
|
75
|
+
const { component, ariaLabel } = props, rest = _object_without_properties_loose(props, [
|
|
76
|
+
"component",
|
|
77
|
+
"ariaLabel"
|
|
78
|
+
]);
|
|
79
|
+
const element = resolveSemanticElement(component);
|
|
80
|
+
const label = typeof ariaLabel === 'string' ? ariaLabel.trim() : '';
|
|
81
|
+
return _extends({}, rest, element ? {
|
|
82
|
+
component: element
|
|
83
|
+
} : {}, element && element !== 'div' && label ? {
|
|
84
|
+
'aria-label': label
|
|
85
|
+
} : {});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Spreadable `component` prop: present only when the author chose one, so an
|
|
89
|
+
* unset picker is indistinguishable from never having had one.
|
|
90
|
+
*/ export function semanticElementProp(value) {
|
|
91
|
+
const element = resolveSemanticElement(value);
|
|
92
|
+
return element ? {
|
|
93
|
+
component: element
|
|
94
|
+
} : {};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The attribute schema. `subject` names what renders, e.g. "this stack".
|
|
98
|
+
*
|
|
99
|
+
* Labelled `Component`, the name Box, Typography, the Document layer and the
|
|
100
|
+
* Layout Slot already use — Section and Inline text keep `element` as their
|
|
101
|
+
* stored KEY because their values are persisted in published screens, but the
|
|
102
|
+
* panel says one thing everywhere (AGL-2514).
|
|
103
|
+
*/ export function semanticElementAttribute(subject) {
|
|
104
|
+
return {
|
|
105
|
+
name: 'component',
|
|
106
|
+
label: 'Component',
|
|
107
|
+
description: `The DOM element ${subject} renders as. Use section/article/aside/nav/` + 'header/footer to give the region meaning for assistive tech and search ' + 'engines; div for purely visual grouping. "main" is not offered — the ' + 'page’s content region carries that one.',
|
|
108
|
+
component: Aglyn.FieldComponentType.SELECT,
|
|
109
|
+
options: SEMANTIC_ELEMENTS.map((value)=>({
|
|
110
|
+
value,
|
|
111
|
+
label: value
|
|
112
|
+
}))
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The name for the landmark the picker just made, shown only once one exists.
|
|
117
|
+
*
|
|
118
|
+
* Gated on the element rather than always visible because on a `div` — the
|
|
119
|
+
* default, and what most of these elements stay — the field would do nothing
|
|
120
|
+
* at all, and a control that silently does nothing is worse than no control.
|
|
121
|
+
*
|
|
122
|
+
* This is the half Section already had and the picker did not. Naming stops
|
|
123
|
+
* being optional the moment a page has two landmarks of a kind: a site nav and
|
|
124
|
+
* a footer nav both announce as "navigation" until one of them says which.
|
|
125
|
+
*/ export function semanticElementLabelAttribute() {
|
|
126
|
+
return {
|
|
127
|
+
name: 'ariaLabel',
|
|
128
|
+
label: 'Accessible label',
|
|
129
|
+
description: 'Names this region for screen readers. Required in practice once a ' + 'page has two landmarks of the same kind — a site nav and a footer ' + 'nav are both announced as "navigation" until one of them says which.',
|
|
130
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
131
|
+
condition: {
|
|
132
|
+
when: 'component',
|
|
133
|
+
is: [
|
|
134
|
+
...LANDMARK_ELEMENTS
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
//# sourceMappingURL=element-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/utils/element-picker.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\n\n/**\n * THE ELEMENT PICKER EVERY CONTAINER GETS (AGL-2525).\n *\n * Section owned the semantic elements alone, so an author who wanted their nav\n * row to BE the `nav` had to wrap it in a second element to say so — and on\n * `aglyn.com` nobody did, which is why the published page had no navigation\n * landmark at all. Wrapping to name a thing is the same shape of\n * element-nobody-authored that AGL-2521 removed from component placements,\n * arriving by a different route.\n *\n * ⛔ `main` IS NOT ON THIS LIST. A page carries exactly one, placed by\n * `stampDocumentLandmark` on the Document layer or the Layout Slot — the two\n * nodes that appear at most once per document. Everything using this picker can\n * be placed any number of times, so an author-selected `main` here could only\n * ever be the second one.\n *\n * An allow-list rather than free text: the value is persisted and rendered\n * verbatim, so a typed one would put `script` into every visitor's page.\n */\nexport const SEMANTIC_ELEMENTS = [\n 'div',\n 'section',\n 'article',\n 'aside',\n 'nav',\n 'header',\n 'footer',\n] as const\nexport type SemanticElement = (typeof SEMANTIC_ELEMENTS)[number]\n\n/**\n * The element to render, or `undefined` to leave the component's own default\n * alone.\n *\n * Returning `undefined` rather than `'div'` is what lets this be added to a\n * component that does NOT default to a div — App Bar renders `header` unless\n * told otherwise, and a resolver that answered `'div'` for \"unset\" would have\n * silently stripped the banner landmark off every site's chrome the moment the\n * picker appeared.\n */\nexport function resolveSemanticElement(value: unknown): SemanticElement | undefined {\n return (SEMANTIC_ELEMENTS as readonly string[]).includes(String(value ?? ''))\n ? (value as SemanticElement)\n : undefined\n}\n\n/**\n * The elements that BECOME a landmark, and so want a name (AGL-2525).\n *\n * `div` is the odd one out: it has no role, so an `aria-label` on it names\n * nothing. Everything else is announced as a region, and a page with two of\n * the same kind — a header nav and a footer nav, say — is a page where\n * \"navigation, navigation\" is all a screen-reader user hears without one.\n */\nexport const LANDMARK_ELEMENTS = SEMANTIC_ELEMENTS.filter(\n (element) => element !== 'div',\n)\n\n/**\n * Consume the picker's props and return what the underlying MUI component\n * should receive.\n *\n * Takes the whole props bag rather than one value because both keys have to\n * be REMOVED as well as translated: `ariaLabel` spread onto a DOM element is\n * an unknown React prop, warned about on the canvas and serialized onto the\n * published page, which is the shape of the `propValues` leak in AGL-2486.\n */\nexport function applySemanticElement<P extends Record<string, unknown>>(\n props: P,\n): Omit<P, 'component' | 'ariaLabel'> & {\n component?: SemanticElement\n 'aria-label'?: string\n} {\n const { component, ariaLabel, ...rest } = props as P & {\n component?: unknown\n ariaLabel?: unknown\n }\n const element = resolveSemanticElement(component)\n const label = typeof ariaLabel === 'string' ? ariaLabel.trim() : ''\n return {\n ...(rest as Omit<P, 'component' | 'ariaLabel'>),\n ...(element ? { component: element } : {}),\n // Only on a landmark: a name on a role-less `div` is announced by\n // nothing and is one more attribute in every visitor's markup.\n ...(element && element !== 'div' && label ? { 'aria-label': label } : {}),\n }\n}\n\n/**\n * Spreadable `component` prop: present only when the author chose one, so an\n * unset picker is indistinguishable from never having had one.\n */\nexport function semanticElementProp(\n value: unknown,\n): { component?: SemanticElement } {\n const element = resolveSemanticElement(value)\n return element ? { component: element } : {}\n}\n\n/**\n * The attribute schema. `subject` names what renders, e.g. \"this stack\".\n *\n * Labelled `Component`, the name Box, Typography, the Document layer and the\n * Layout Slot already use — Section and Inline text keep `element` as their\n * stored KEY because their values are persisted in published screens, but the\n * panel says one thing everywhere (AGL-2514).\n */\nexport function semanticElementAttribute(\n subject: string,\n): Aglyn.AglynAttributeSchema {\n return {\n name: 'component',\n label: 'Component',\n description:\n `The DOM element ${subject} renders as. Use section/article/aside/nav/` +\n 'header/footer to give the region meaning for assistive tech and search ' +\n 'engines; div for purely visual grouping. \"main\" is not offered — the ' +\n 'page’s content region carries that one.',\n component: Aglyn.FieldComponentType.SELECT,\n options: SEMANTIC_ELEMENTS.map((value) => ({ value, label: value })),\n } as Aglyn.AglynAttributeSchema\n}\n\n/**\n * The name for the landmark the picker just made, shown only once one exists.\n *\n * Gated on the element rather than always visible because on a `div` — the\n * default, and what most of these elements stay — the field would do nothing\n * at all, and a control that silently does nothing is worse than no control.\n *\n * This is the half Section already had and the picker did not. Naming stops\n * being optional the moment a page has two landmarks of a kind: a site nav and\n * a footer nav both announce as \"navigation\" until one of them says which.\n */\nexport function semanticElementLabelAttribute(): Aglyn.AglynAttributeSchema {\n return {\n name: 'ariaLabel',\n label: 'Accessible label',\n description:\n 'Names this region for screen readers. Required in practice once a ' +\n 'page has two landmarks of the same kind — a site nav and a footer ' +\n 'nav are both announced as \"navigation\" until one of them says which.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n condition: { when: 'component', is: [...LANDMARK_ELEMENTS] },\n } as Aglyn.AglynAttributeSchema\n}\n"],"names":["Aglyn","SEMANTIC_ELEMENTS","resolveSemanticElement","value","includes","String","undefined","LANDMARK_ELEMENTS","filter","element","applySemanticElement","props","component","ariaLabel","rest","label","trim","semanticElementProp","semanticElementAttribute","subject","name","description","FieldComponentType","SELECT","options","map","semanticElementLabelAttribute","TEXT_FIELD","condition","when","is"],"mappings":";;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AAErC;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,MAAMC,oBAAoB;IAC/B;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAS;AAGV;;;;;;;;;CASC,GACD,OAAO,SAASC,uBAAuBC,KAAc;IACnD,OAAO,AAACF,kBAAwCG,QAAQ,CAACC,OAAOF,gBAAAA,QAAS,OACpEA,QACDG;AACN;AAEA;;;;;;;CAOC,GACD,OAAO,MAAMC,oBAAoBN,kBAAkBO,MAAM,CACvD,CAACC,UAAYA,YAAY,OAC1B;AAED;;;;;;;;CAQC,GACD,OAAO,SAASC,qBACdC,KAAQ;IAKR,MAAM,EAAEC,SAAS,EAAEC,SAAS,EAAW,GAAGF,OAATG,wCAASH;;;;IAI1C,MAAMF,UAAUP,uBAAuBU;IACvC,MAAMG,QAAQ,OAAOF,cAAc,WAAWA,UAAUG,IAAI,KAAK;IACjE,OAAO,aACDF,MACAL,UAAU;QAAEG,WAAWH;IAAQ,IAAI,CAAC,GAGpCA,WAAWA,YAAY,SAASM,QAAQ;QAAE,cAAcA;IAAM,IAAI,CAAC;AAE3E;AAEA;;;CAGC,GACD,OAAO,SAASE,oBACdd,KAAc;IAEd,MAAMM,UAAUP,uBAAuBC;IACvC,OAAOM,UAAU;QAAEG,WAAWH;IAAQ,IAAI,CAAC;AAC7C;AAEA;;;;;;;CAOC,GACD,OAAO,SAASS,yBACdC,OAAe;IAEf,OAAO;QACLC,MAAM;QACNL,OAAO;QACPM,aACE,CAAC,gBAAgB,EAAEF,QAAQ,2CAA2C,CAAC,GACvE,4EACA,0EACA;QACFP,WAAWZ,MAAMsB,kBAAkB,CAACC,MAAM;QAC1CC,SAASvB,kBAAkBwB,GAAG,CAAC,CAACtB,QAAW,CAAA;gBAAEA;gBAAOY,OAAOZ;YAAM,CAAA;IACnE;AACF;AAEA;;;;;;;;;;CAUC,GACD,OAAO,SAASuB;IACd,OAAO;QACLN,MAAM;QACNL,OAAO;QACPM,aACE,uEACA,uEACA;QACFT,WAAWZ,MAAMsB,kBAAkB,CAACK,UAAU;QAC9CC,WAAW;YAAEC,MAAM;YAAaC,IAAI;mBAAIvB;aAAkB;QAAC;IAC7D;AACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 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 type { ComponentId } from '@aglyn/aglyn';
|
|
18
|
+
export declare const generatePresetId: (componentId: ComponentId, ...other: string[]) => ComponentId;
|
|
19
|
+
export default generatePresetId;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
17
|
+
export const generatePresetId = (componentId, ...other)=>{
|
|
18
|
+
return `${BUNDLE_ID}:${[
|
|
19
|
+
componentId,
|
|
20
|
+
...other
|
|
21
|
+
].join('.')}`;
|
|
22
|
+
};
|
|
23
|
+
export default generatePresetId;
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=generate-preset-id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/utils/generate-preset-id.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 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 type { ComponentId } from '@aglyn/aglyn'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\nexport const generatePresetId = (\n componentId: ComponentId,\n ...other: string[]\n): ComponentId => {\n return `${BUNDLE_ID}:${[componentId, ...other].join('.')}`\n}\n\nexport default generatePresetId\n"],"names":["BUNDLE_ID","generatePresetId","componentId","other","join"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAGD,SAASA,SAAS,QAAQ,gCAA4B;AAEtD,OAAO,MAAMC,mBAAmB,CAC9BC,aACA,GAAGC;IAEH,OAAO,GAAGH,UAAU,CAAC,EAAE;QAACE;WAAgBC;KAAM,CAACC,IAAI,CAAC,MAAM;AAC5D,EAAC;AAED,eAAeH,iBAAgB"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Where a link opens, as authored. Persisted in screen documents; never
|
|
19
|
+
* rename a value.
|
|
20
|
+
*
|
|
21
|
+
* - `'_self'` (or unset) — stays in the current tab, the browser default.
|
|
22
|
+
* - `'_blank'` — a new tab.
|
|
23
|
+
* - `'custom'` — a NAMED window, read from the companion `targetName` prop.
|
|
24
|
+
* Not an anchor value itself; it is the sentinel that reveals the name
|
|
25
|
+
* field, and never reaches the DOM.
|
|
26
|
+
*/
|
|
27
|
+
export type LinkTargetChoice = '_self' | '_blank' | 'custom';
|
|
28
|
+
/** The anchor attributes a {@link LinkTargetChoice} resolves to. */
|
|
29
|
+
export interface LinkTargetProps {
|
|
30
|
+
target?: string;
|
|
31
|
+
rel?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolves the authored target pair to the attributes an anchor should carry.
|
|
35
|
+
*
|
|
36
|
+
* Returns NOTHING for the default choice rather than an explicit
|
|
37
|
+
* `target="_self"`: the two behave identically, and an absent attribute is
|
|
38
|
+
* what every link authored before this existed already renders — so adding
|
|
39
|
+
* the control moves no published markup.
|
|
40
|
+
*
|
|
41
|
+
* `rel` rides along because a target that opens elsewhere hands the new
|
|
42
|
+
* context a live `window.opener` handle back into this page. `noreferrer` is
|
|
43
|
+
* added only when the destination leaves the site: stripping the referrer
|
|
44
|
+
* from a link to one of the site's own screens would make the landing page
|
|
45
|
+
* read as direct traffic in its own analytics, which is a reporting defect,
|
|
46
|
+
* not a safety win.
|
|
47
|
+
*
|
|
48
|
+
* A cleared attribute persists as `null` or `''`, and a custom choice with
|
|
49
|
+
* an empty name is an author mid-edit — both fall back to the default rather
|
|
50
|
+
* than stamping an empty `target` on the anchor.
|
|
51
|
+
*/
|
|
52
|
+
export declare function linkTargetProps(target: LinkTargetChoice | string | null | undefined, targetName: string | null | undefined, leavesSite: boolean): LinkTargetProps;
|
|
53
|
+
export default linkTargetProps;
|