@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 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/language-switcher.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 { mdiTranslate } from '@aglyn/shared-data-mdi'\nimport { AppLink } from '@aglyn/shared-ui-jsx'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'languageSwitcher'\n\nexport interface LanguageSwitcherProps {\n /** 'text' shows locale codes; 'buttons' renders outlined buttons. */\n variant?: 'text' | 'buttons'\n /** Uppercase the locale codes (EN / ES). */\n uppercase?: boolean\n}\n\n/**\n * Language switcher (AGL-164): renders one link per translation of the\n * CURRENT screen, resolved from ScreenLinkContext (`localeVariants` +\n * routing map), so it works inside shared layouts. Shows a placeholder in\n * the editor when the screen has no variants; renders nothing on the live\n * site in that case.\n */\nconst LanguageSwitcher = forwardRef<HTMLElement, LanguageSwitcherProps>(\n (props, ref) => {\n const { variant, uppercase, ...rest } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { screens, localeVariants, currentLocale, suppressNavigation } =\n useContext(Aglyn.ScreenLinkContext)\n const entries = Object.entries(localeVariants ?? {}).filter(\n ([, screenId]) => screens?.[screenId] != null,\n )\n const format = (locale: string) =>\n uppercase === false ? locale : locale.toUpperCase()\n\n if (!entries.length) {\n // Editor-only placeholder; invisible on the live site.\n if (!suppressNavigation) return null\n return (\n <Stack\n ref={ref as any}\n direction=\"row\"\n spacing={1}\n {...rest}\n sx={[\n {\n alignItems: 'center',\n border: '1px dashed',\n borderColor: 'divider',\n borderRadius: 1,\n px: 1.5,\n py: 0.5,\n color: 'text.secondary',\n fontSize: 12,\n fontFamily: 'system-ui, sans-serif',\n },\n ...nodeSx,\n ]}\n >\n {'Language switcher — set screen translations'}\n </Stack>\n )\n }\n\n return (\n <Stack\n ref={ref as any}\n direction=\"row\"\n spacing={0.5}\n {...rest}\n sx={[{ alignItems: 'center' }, ...nodeSx]}\n >\n {currentLocale ? (\n <Button size=\"small\" variant=\"text\" disabled>\n {format(currentLocale)}\n </Button>\n ) : null}\n {entries.map(([locale, screenId]) => {\n const path = screens?.[screenId]\n const href =\n path != null ? Aglyn.screenRoutePathToUrl(path) : undefined\n if (!href || suppressNavigation) {\n return (\n <Button key={locale} size=\"small\" variant=\"text\">\n {format(locale)}\n </Button>\n )\n }\n return (\n <AppLink\n key={locale}\n componentVariant=\"button\"\n href={href}\n size=\"small\"\n variant={variant === 'buttons' ? 'outlined' : 'text'}\n >\n {format(locale)}\n </AppLink>\n )\n })}\n </Stack>\n )\n },\n)\nLanguageSwitcher.displayName = 'LanguageSwitcher'\n\nexport const schema: Aglyn.ComponentSchema<LanguageSwitcherProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Language Switcher',\n description:\n \"Links between this screen's translations. It hides itself when there are none.\",\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: {\n path: mdiTranslate.path,\n sx: { color: '#2196f3' },\n },\n flags: {\n selfClosing: Aglyn.FEATURE_FLAG.ENABLED,\n },\n attributes: [\n {\n name: 'variant',\n description: 'How the language links render.',\n component: Aglyn.FieldComponentType.SELECT,\n label: 'Style',\n // `text` is half of the declared `'text' | 'buttons'` union and the\n // value the render already falls back to; as `''` the option was\n // unpersistable (AGL-1191) and outside its own prop type (AGL-1451).\n options: [\n { value: 'text', label: 'Text (default)' },\n { value: 'buttons', label: 'Outlined buttons' },\n ],\n },\n {\n name: 'uppercase',\n description: 'Show locale codes uppercased (EN, ES).',\n component: Aglyn.FieldComponentType.CHECKBOX,\n label: 'Uppercase',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Language Switcher',\n pluginId: BUNDLE_ID,\n description: 'Links between this screen’s translations',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: {\n path: mdiTranslate.path,\n sx: { color: '#2196f3' },\n },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default LanguageSwitcher\n"],"names":["Aglyn","mdiTranslate","AppLink","Button","Stack","forwardRef","useContext","BUNDLE_ID","generatePresetId","ID","LanguageSwitcher","props","ref","variant","uppercase","rest","nodeSx","Array","isArray","screens","localeVariants","currentLocale","suppressNavigation","ScreenLinkContext","entries","Object","filter","screenId","format","locale","toUpperCase","length","direction","spacing","sx","alignItems","border","borderColor","borderRadius","px","py","color","fontSize","fontFamily","size","disabled","map","path","href","screenRoutePathToUrl","undefined","componentVariant","displayName","schema","$id","pluginId","description","category","ComponentCategory","NAVIGATION","icon","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","name","component","FieldComponentType","SELECT","label","options","value","CHECKBOX","presets","type","NodeType","PRESET","data","componentId"],"mappings":"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"}
@@ -0,0 +1,68 @@
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
+ import { type BoxProps } from '@mui/material/Box';
19
+ export declare const ID: Aglyn.ComponentId;
20
+ /**
21
+ * Elements the slot may render as (AGL-2486).
22
+ *
23
+ * `main` is here, and is the DEFAULT composition assigns, because the slot is
24
+ * by construction the page content between the layout's chrome — which is the
25
+ * definition of the landmark. It is the one place on the platform that may
26
+ * choose it: `SECTION_ELEMENTS` and `ALLOWED_AUTHOR_HTML_ELEMENTS` both drop
27
+ * `main` so a document can never carry two, and `stampDocumentLandmark`
28
+ * decides which single node gets it.
29
+ */
30
+ export declare const LAYOUT_SLOT_ELEMENTS: readonly ["main", "div", "section", "article"];
31
+ export type LayoutSlotElement = (typeof LAYOUT_SLOT_ELEMENTS)[number];
32
+ export interface LayoutSlotProps extends Omit<BoxProps, 'component'> {
33
+ /**
34
+ * The DOM element the slot renders as. Left unset, composition fills in
35
+ * `main` — see {@link LAYOUT_SLOT_ELEMENTS}. Unknown values degrade to
36
+ * `div` rather than reaching the DOM as an invented tag.
37
+ *
38
+ * Named `component` like Box's and Typography's, not `element` like
39
+ * Section's: the attribute means the same thing everywhere it appears.
40
+ * Narrower than the `ElementType` Box accepts — a canvas attribute is a
41
+ * persisted STRING, and an allow-list is what keeps `script` out of it —
42
+ * so `BoxProps`' own `component` is omitted rather than widened.
43
+ */
44
+ component?: LayoutSlotElement | string;
45
+ /**
46
+ * Editor-only caption under the slot marker. Layouts render different
47
+ * kinds of content — a doc body, a narrow article measure, a full page —
48
+ * and naming it is the difference between four identical dashed boxes and
49
+ * a layout you can read at a glance.
50
+ */
51
+ caption?: string;
52
+ }
53
+ /** Shown when a layout hasn't named its slot. */
54
+ export declare const DEFAULT_SLOT_CAPTION = "Screen content renders here";
55
+ /**
56
+ * Content outlet for shared layouts: marks where a bound screen's nodes are
57
+ * grafted into the layout tree at composition time. With children (composed
58
+ * or previewed) it is a plain passthrough region; empty, it renders a
59
+ * dashed placeholder so layout designers can see the slot on the canvas.
60
+ *
61
+ * The placeholder is editor chrome, so it is drawn on editing surfaces only.
62
+ * A published screen with no content of its own still composes an empty
63
+ * slot, and that renders as the plain region.
64
+ */
65
+ declare const LayoutSlot: import("react").ForwardRefExoticComponent<Omit<LayoutSlotProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
66
+ export declare const schema: Aglyn.ComponentSchema<LayoutSlotProps>;
67
+ export declare const presets: Aglyn.PresetSchema[];
68
+ export default LayoutSlot;
@@ -0,0 +1,192 @@
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, jsxs as _jsxs } 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 { mdiPageLayoutBody } from "@aglyn/shared-data-mdi";
21
+ import Box from "@mui/material/Box";
22
+ import { alpha } from "@mui/material/styles";
23
+ import { Children, forwardRef, useContext } from "react";
24
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
25
+ import { generatePresetId } from "../utils/generate-preset-id.js";
26
+ // Component ids are persisted in layout documents; never rename.
27
+ export const ID = 'layoutSlot';
28
+ /**
29
+ * Elements the slot may render as (AGL-2486).
30
+ *
31
+ * `main` is here, and is the DEFAULT composition assigns, because the slot is
32
+ * by construction the page content between the layout's chrome — which is the
33
+ * definition of the landmark. It is the one place on the platform that may
34
+ * choose it: `SECTION_ELEMENTS` and `ALLOWED_AUTHOR_HTML_ELEMENTS` both drop
35
+ * `main` so a document can never carry two, and `stampDocumentLandmark`
36
+ * decides which single node gets it.
37
+ */ export const LAYOUT_SLOT_ELEMENTS = [
38
+ 'main',
39
+ 'div',
40
+ 'section',
41
+ 'article'
42
+ ];
43
+ /**
44
+ * The slot marker is EDITOR CHROME, so it holds the brand accent literally
45
+ * rather than reading `secondary` from the theme: the canvas renders under
46
+ * the host's palette, so a token would repaint the editor's own furniture
47
+ * whenever a subscriber restyles their site — and it already rendered pink
48
+ * instead of the design's blue.
49
+ */ const SLOT_ACCENT = '#00B0FF';
50
+ /** Shown when a layout hasn't named its slot. */ export const DEFAULT_SLOT_CAPTION = 'Screen content renders here';
51
+ /**
52
+ * Content outlet for shared layouts: marks where a bound screen's nodes are
53
+ * grafted into the layout tree at composition time. With children (composed
54
+ * or previewed) it is a plain passthrough region; empty, it renders a
55
+ * dashed placeholder so layout designers can see the slot on the canvas.
56
+ *
57
+ * The placeholder is editor chrome, so it is drawn on editing surfaces only.
58
+ * A published screen with no content of its own still composes an empty
59
+ * slot, and that renders as the plain region.
60
+ */ const LayoutSlot = /*#__PURE__*/ forwardRef((props, ref)=>{
61
+ const { children, sx, caption, component } = props, rest = _object_without_properties_loose(props, [
62
+ "children",
63
+ "sx",
64
+ "caption",
65
+ "component"
66
+ ]);
67
+ const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext);
68
+ const hasChildren = Children.count(children) > 0;
69
+ const element = LAYOUT_SLOT_ELEMENTS.includes(String(component != null ? component : '')) ? component : 'div';
70
+ if (hasChildren || !suppressNavigation) {
71
+ return /*#__PURE__*/ _jsx(Box, _extends({
72
+ ref: ref,
73
+ component: element,
74
+ "data-aglyn-layout-slot": "",
75
+ sx: sx
76
+ }, rest, {
77
+ children: children
78
+ }));
79
+ }
80
+ return /*#__PURE__*/ _jsxs(Box, _extends({
81
+ ref: ref,
82
+ "data-aglyn-layout-slot": "",
83
+ sx: [
84
+ {
85
+ minHeight: 160,
86
+ display: 'flex',
87
+ flexDirection: 'column',
88
+ alignItems: 'center',
89
+ justifyContent: 'center',
90
+ gap: 0.5,
91
+ borderWidth: 2,
92
+ borderStyle: 'dashed',
93
+ // The slot is not an ordinary dashed container — it is the one
94
+ // region a layout does NOT own. Brand blue on a faint tint says
95
+ // that at a glance, and matches the design's slot convention.
96
+ borderColor: SLOT_ACCENT,
97
+ backgroundColor: alpha(SLOT_ACCENT, 0.06),
98
+ borderRadius: 1,
99
+ color: 'text.secondary',
100
+ fontFamily: 'sans-serif',
101
+ fontSize: 13,
102
+ textAlign: 'center',
103
+ p: 2
104
+ },
105
+ ...Array.isArray(sx) ? sx : [
106
+ sx
107
+ ]
108
+ ]
109
+ }, rest, {
110
+ children: [
111
+ /*#__PURE__*/ _jsx(Box, {
112
+ component: "span",
113
+ sx: {
114
+ color: SLOT_ACCENT,
115
+ fontWeight: 700
116
+ },
117
+ children: '◇ layout-slot'
118
+ }),
119
+ /*#__PURE__*/ _jsx(Box, {
120
+ component: "span",
121
+ children: caption || DEFAULT_SLOT_CAPTION
122
+ })
123
+ ]
124
+ }));
125
+ });
126
+ LayoutSlot.displayName = 'LayoutSlot';
127
+ export const schema = {
128
+ $id: ID,
129
+ pluginId: BUNDLE_ID,
130
+ displayName: 'Layout Slot',
131
+ description: "Marks where each bound screen's content renders inside this layout. One per layout.",
132
+ category: Aglyn.ComponentCategory.LAYOUT,
133
+ icon: {
134
+ path: mdiPageLayoutBody.path,
135
+ sx: {
136
+ color: '#9c27b0'
137
+ }
138
+ },
139
+ // The slot's children come from screen composition, never from the canvas.
140
+ restrictChildren: [
141
+ Aglyn.LinealDirectiveFlag.LIMIT_TO,
142
+ {
143
+ components: []
144
+ }
145
+ ],
146
+ flags: {
147
+ cloning: Aglyn.FEATURE_FLAG.DISABLED,
148
+ dropping: Aglyn.FEATURE_FLAG.DISABLED
149
+ },
150
+ attributes: [
151
+ {
152
+ name: 'caption',
153
+ label: 'Slot caption',
154
+ description: 'Editor-only label for what renders here — e.g. "Doc body renders ' + 'here". Never shown on the published site.',
155
+ component: Aglyn.FieldComponentType.TEXT_FIELD,
156
+ placeholder: DEFAULT_SLOT_CAPTION
157
+ },
158
+ {
159
+ name: 'component',
160
+ label: 'Component',
161
+ description: 'The DOM element the screen content renders inside. Blank is ' + '"main" — the page-content landmark assistive tech skips the ' + 'chrome with. Choose another only if this layout’s slot is not the ' + 'page’s main content.',
162
+ component: Aglyn.FieldComponentType.SELECT,
163
+ options: LAYOUT_SLOT_ELEMENTS.map((value)=>({
164
+ value,
165
+ label: value
166
+ }))
167
+ }
168
+ ]
169
+ };
170
+ export const presets = [
171
+ {
172
+ $id: generatePresetId(ID),
173
+ type: Aglyn.NodeType.PRESET,
174
+ displayName: 'Layout Slot',
175
+ icon: {
176
+ path: mdiPageLayoutBody.path,
177
+ sx: {
178
+ color: '#9c27b0'
179
+ }
180
+ },
181
+ category: Aglyn.ComponentCategory.LAYOUT,
182
+ data: {
183
+ $id: null,
184
+ componentId: ID,
185
+ pluginId: BUNDLE_ID,
186
+ props: {}
187
+ }
188
+ }
189
+ ];
190
+ export default LayoutSlot;
191
+
192
+ //# sourceMappingURL=layout-slot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/layout-slot.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiPageLayoutBody } from '@aglyn/shared-data-mdi'\nimport Box, { type BoxProps } from '@mui/material/Box'\nimport { alpha } from '@mui/material/styles'\nimport { Children, forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in layout documents; never rename.\nexport const ID: Aglyn.ComponentId = 'layoutSlot'\n\n/**\n * Elements the slot may render as (AGL-2486).\n *\n * `main` is here, and is the DEFAULT composition assigns, because the slot is\n * by construction the page content between the layout's chrome — which is the\n * definition of the landmark. It is the one place on the platform that may\n * choose it: `SECTION_ELEMENTS` and `ALLOWED_AUTHOR_HTML_ELEMENTS` both drop\n * `main` so a document can never carry two, and `stampDocumentLandmark`\n * decides which single node gets it.\n */\nexport const LAYOUT_SLOT_ELEMENTS = [\n 'main',\n 'div',\n 'section',\n 'article',\n] as const\nexport type LayoutSlotElement = (typeof LAYOUT_SLOT_ELEMENTS)[number]\n\nexport interface LayoutSlotProps extends Omit<BoxProps, 'component'> {\n /**\n * The DOM element the slot renders as. Left unset, composition fills in\n * `main` — see {@link LAYOUT_SLOT_ELEMENTS}. Unknown values degrade to\n * `div` rather than reaching the DOM as an invented tag.\n *\n * Named `component` like Box's and Typography's, not `element` like\n * Section's: the attribute means the same thing everywhere it appears.\n * Narrower than the `ElementType` Box accepts — a canvas attribute is a\n * persisted STRING, and an allow-list is what keeps `script` out of it —\n * so `BoxProps`' own `component` is omitted rather than widened.\n */\n component?: LayoutSlotElement | string\n /**\n * Editor-only caption under the slot marker. Layouts render different\n * kinds of content — a doc body, a narrow article measure, a full page —\n * and naming it is the difference between four identical dashed boxes and\n * a layout you can read at a glance.\n */\n caption?: string\n}\n\n/**\n * The slot marker is EDITOR CHROME, so it holds the brand accent literally\n * rather than reading `secondary` from the theme: the canvas renders under\n * the host's palette, so a token would repaint the editor's own furniture\n * whenever a subscriber restyles their site — and it already rendered pink\n * instead of the design's blue.\n */\nconst SLOT_ACCENT = '#00B0FF'\n/** Shown when a layout hasn't named its slot. */\nexport const DEFAULT_SLOT_CAPTION = 'Screen content renders here'\n\n/**\n * Content outlet for shared layouts: marks where a bound screen's nodes are\n * grafted into the layout tree at composition time. With children (composed\n * or previewed) it is a plain passthrough region; empty, it renders a\n * dashed placeholder so layout designers can see the slot on the canvas.\n *\n * The placeholder is editor chrome, so it is drawn on editing surfaces only.\n * A published screen with no content of its own still composes an empty\n * slot, and that renders as the plain region.\n */\nconst LayoutSlot = forwardRef<HTMLDivElement, LayoutSlotProps>(\n (props, ref) => {\n const { children, sx, caption, component, ...rest } = props\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n const hasChildren = Children.count(children) > 0\n const element = (LAYOUT_SLOT_ELEMENTS as readonly string[]).includes(\n String(component ?? ''),\n )\n ? (component as LayoutSlotElement)\n : 'div'\n\n if (hasChildren || !suppressNavigation) {\n return (\n <Box\n ref={ref}\n component={element}\n data-aglyn-layout-slot=\"\"\n sx={sx}\n {...rest}\n >\n {children}\n </Box>\n )\n }\n\n return (\n <Box\n ref={ref}\n data-aglyn-layout-slot=\"\"\n sx={[\n {\n minHeight: 160,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 0.5,\n borderWidth: 2,\n borderStyle: 'dashed',\n // The slot is not an ordinary dashed container — it is the one\n // region a layout does NOT own. Brand blue on a faint tint says\n // that at a glance, and matches the design's slot convention.\n borderColor: SLOT_ACCENT,\n backgroundColor: alpha(SLOT_ACCENT, 0.06),\n borderRadius: 1,\n color: 'text.secondary',\n fontFamily: 'sans-serif',\n fontSize: 13,\n textAlign: 'center',\n p: 2,\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n {...rest}\n >\n <Box\n component=\"span\"\n sx={{ color: SLOT_ACCENT, fontWeight: 700 }}\n >\n {'◇ layout-slot'}\n </Box>\n <Box component=\"span\">{caption || DEFAULT_SLOT_CAPTION}</Box>\n </Box>\n )\n },\n)\nLayoutSlot.displayName = 'LayoutSlot'\n\nexport const schema: Aglyn.ComponentSchema<LayoutSlotProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Layout Slot',\n description:\n \"Marks where each bound screen's content renders inside this layout. One per layout.\",\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: {\n path: mdiPageLayoutBody.path,\n sx: { color: '#9c27b0' },\n },\n // The slot's children come from screen composition, never from the canvas.\n restrictChildren: [Aglyn.LinealDirectiveFlag.LIMIT_TO, { components: [] }],\n flags: {\n cloning: Aglyn.FEATURE_FLAG.DISABLED,\n dropping: Aglyn.FEATURE_FLAG.DISABLED,\n },\n attributes: [\n {\n name: 'caption',\n label: 'Slot caption',\n description:\n 'Editor-only label for what renders here — e.g. \"Doc body renders ' +\n 'here\". Never shown on the published site.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n placeholder: DEFAULT_SLOT_CAPTION,\n },\n {\n name: 'component',\n label: 'Component',\n description:\n 'The DOM element the screen content renders inside. Blank is ' +\n '\"main\" — the page-content landmark assistive tech skips the ' +\n 'chrome with. Choose another only if this layout’s slot is not the ' +\n 'page’s main content.',\n component: Aglyn.FieldComponentType.SELECT,\n options: LAYOUT_SLOT_ELEMENTS.map((value) => ({\n value,\n label: value,\n })),\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Layout Slot',\n icon: {\n path: mdiPageLayoutBody.path,\n sx: { color: '#9c27b0' },\n },\n category: Aglyn.ComponentCategory.LAYOUT,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default LayoutSlot\n"],"names":["Aglyn","mdiPageLayoutBody","Box","alpha","Children","forwardRef","useContext","BUNDLE_ID","generatePresetId","ID","LAYOUT_SLOT_ELEMENTS","SLOT_ACCENT","DEFAULT_SLOT_CAPTION","LayoutSlot","props","ref","children","sx","caption","component","rest","suppressNavigation","ScreenLinkContext","hasChildren","count","element","includes","String","data-aglyn-layout-slot","minHeight","display","flexDirection","alignItems","justifyContent","gap","borderWidth","borderStyle","borderColor","backgroundColor","borderRadius","color","fontFamily","fontSize","textAlign","p","Array","isArray","fontWeight","displayName","schema","$id","pluginId","description","category","ComponentCategory","LAYOUT","icon","path","restrictChildren","LinealDirectiveFlag","LIMIT_TO","components","flags","cloning","FEATURE_FLAG","DISABLED","dropping","attributes","name","label","FieldComponentType","TEXT_FIELD","placeholder","SELECT","options","map","value","presets","type","NodeType","PRESET","data","componentId"],"mappings":"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"}
@@ -0,0 +1,79 @@
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
+ * How a Link Container's link gets its accessible name (AGL-2886).
19
+ *
20
+ * An `<a>` is named by the text inside it. A Link Container holding only an
21
+ * Icon has none, so a screen reader announces "link" and nothing else
22
+ * (WCAG 2.4.4, 4.1.2). Two attributes answer that, and this module holds both
23
+ * halves of them: what the anchor renders, and the warning the Attributes
24
+ * panel shows while neither has been used.
25
+ */
26
+ import * as Aglyn from '@aglyn/aglyn';
27
+ /** The Link Container attribute that marks it as a second link. */
28
+ export declare const REDUNDANT_ATTRIBUTE = "redundant";
29
+ /**
30
+ * The anchor attributes that name the link, or take it out of the
31
+ * accessibility tree and the tab order.
32
+ *
33
+ * Redundant wins over a label. A link hidden from assistive tech announces no
34
+ * name, so the label would be an attribute every visitor downloads for
35
+ * nothing. Read through `readYesNoValue` because a switch bound to a Yes / no
36
+ * property can arrive as the string `'false'`, which plain truthiness reads
37
+ * as a yes.
38
+ *
39
+ * `tabIndex` goes with `aria-hidden` because either alone is a defect: a
40
+ * hidden link that still takes focus leaves a keyboard user on a stop that
41
+ * announces nothing, and a skipped link that is still announced is the
42
+ * duplicate this option exists to remove.
43
+ */
44
+ export declare function linkContainerA11yProps(ariaLabel: unknown, redundant: unknown): {
45
+ 'aria-label'?: string;
46
+ 'aria-hidden'?: 'true';
47
+ tabIndex?: number;
48
+ };
49
+ /**
50
+ * Whether what is inside a Link Container gives its link a name, or `true`
51
+ * when that cannot be decided from the document.
52
+ *
53
+ * Walks every descendant. A hidden element is skipped, because the page
54
+ * renders it with `display: none` and that removes it from the accessibility
55
+ * tree. A child the lookup cannot find is an unknown, not a silence.
56
+ */
57
+ export declare function linkContentNamesLink(node: Aglyn.NodeSchema<any>, getNode: Aglyn.AttributeFieldContext['getNode']): boolean;
58
+ /** What the Accessible label field says while the link has no name. */
59
+ export declare const UNNAMED_LINK_CONTAINER_WARNING: string;
60
+ /**
61
+ * The Accessible label field's `resolveProps`: the warning above as its
62
+ * helper text while the link would render with no name, and the field's own
63
+ * description otherwise.
64
+ *
65
+ * Silent without the panel's context, since it cannot see what is inside the
66
+ * box, and silent while Duplicate of another link holds a binding, since each
67
+ * page that places the component decides that for itself.
68
+ */
69
+ export declare function linkContainerLabelFieldProps(_props: unknown, field: {
70
+ input?: {
71
+ value?: unknown;
72
+ };
73
+ }, formOptions?: {
74
+ getState?: () => {
75
+ values?: Record<string, unknown>;
76
+ };
77
+ }, context?: Aglyn.AttributeFieldContext): {
78
+ helperText?: string;
79
+ };
@@ -0,0 +1,158 @@
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
+ * How a Link Container's link gets its accessible name (AGL-2886).
18
+ *
19
+ * An `<a>` is named by the text inside it. A Link Container holding only an
20
+ * Icon has none, so a screen reader announces "link" and nothing else
21
+ * (WCAG 2.4.4, 4.1.2). Two attributes answer that, and this module holds both
22
+ * halves of them: what the anchor renders, and the warning the Attributes
23
+ * panel shows while neither has been used.
24
+ */ import * as Aglyn from "@aglyn/aglyn";
25
+ import { ID as boxId } from "./box.js";
26
+ import { ID as containerId } from "./container.js";
27
+ import { ID as gridId } from "./grid.js";
28
+ import { ID as iconId } from "./icon.js";
29
+ import { ID as imageId } from "./image.js";
30
+ import { ID as inlineTextId } from "./inline-text.js";
31
+ import { ID as paperId } from "./paper.js";
32
+ import { ID as sectionId } from "./section.js";
33
+ import { ID as stackId } from "./stack.js";
34
+ import { ID as typographyId } from "./typography.js";
35
+ /** The Link Container attribute that marks it as a second link. */ export const REDUNDANT_ATTRIBUTE = 'redundant';
36
+ /**
37
+ * The anchor attributes that name the link, or take it out of the
38
+ * accessibility tree and the tab order.
39
+ *
40
+ * Redundant wins over a label. A link hidden from assistive tech announces no
41
+ * name, so the label would be an attribute every visitor downloads for
42
+ * nothing. Read through `readYesNoValue` because a switch bound to a Yes / no
43
+ * property can arrive as the string `'false'`, which plain truthiness reads
44
+ * as a yes.
45
+ *
46
+ * `tabIndex` goes with `aria-hidden` because either alone is a defect: a
47
+ * hidden link that still takes focus leaves a keyboard user on a stop that
48
+ * announces nothing, and a skipped link that is still announced is the
49
+ * duplicate this option exists to remove.
50
+ */ export function linkContainerA11yProps(ariaLabel, redundant) {
51
+ if (Aglyn.readYesNoValue(redundant) === true) {
52
+ return {
53
+ 'aria-hidden': 'true',
54
+ tabIndex: -1
55
+ };
56
+ }
57
+ const label = typeof ariaLabel === 'string' ? ariaLabel.trim() : '';
58
+ return label ? {
59
+ 'aria-label': label
60
+ } : {};
61
+ }
62
+ /**
63
+ * Elements that add no words of their own to a link they sit inside.
64
+ *
65
+ * An Icon draws an SVG glyph with no text alternative, and a layout container
66
+ * is only the box around its children. Image and the two text elements are
67
+ * listed because their words live in props the walk below reads directly
68
+ * (`alt`, `children`, `html`), so one of them holding none is as silent as an
69
+ * Icon.
70
+ *
71
+ * An element NOT listed, holding none of those props, is taken to name the
72
+ * link. A reusable component keeps its words in its definition, a collection
73
+ * or product element takes them from data, and List Item Text keeps its lines
74
+ * in props of its own. A warning about any of those would be a guess, and a
75
+ * warning that is wrong about correct content teaches an author to ignore the
76
+ * one that is right.
77
+ */ const WORDLESS_ELEMENTS = new Set([
78
+ boxId,
79
+ containerId,
80
+ gridId,
81
+ iconId,
82
+ imageId,
83
+ inlineTextId,
84
+ paperId,
85
+ sectionId,
86
+ stackId,
87
+ typographyId
88
+ ]);
89
+ const hasText = (value)=>typeof value === 'string' && value.trim().length > 0;
90
+ /**
91
+ * Whether an element inside the link carries words of its own.
92
+ *
93
+ * A binding counts: `{{…}}` is not blank, and what it resolves to is not
94
+ * known until the page renders. An image's alt text counts unless the image
95
+ * is marked decorative, because the renderer drops the alt then.
96
+ */ function carriesWords(props) {
97
+ if (!props) return false;
98
+ if (hasText(props['children']) || hasText(props['html'])) return true;
99
+ if (hasText(props['ariaLabel'])) return true;
100
+ return hasText(props['alt']) && Aglyn.readYesNoValue(props['decorative']) !== true;
101
+ }
102
+ /**
103
+ * Whether what is inside a Link Container gives its link a name, or `true`
104
+ * when that cannot be decided from the document.
105
+ *
106
+ * Walks every descendant. A hidden element is skipped, because the page
107
+ * renders it with `display: none` and that removes it from the accessibility
108
+ * tree. A child the lookup cannot find is an unknown, not a silence.
109
+ */ export function linkContentNamesLink(node, getNode) {
110
+ var _node_nodes;
111
+ var _node_props;
112
+ // The renderer draws a node's own `children` string inside the element.
113
+ if (hasText((_node_props = node.props) == null ? void 0 : _node_props['children'])) {
114
+ return true;
115
+ }
116
+ const pending = [
117
+ ...(_node_nodes = node.nodes) != null ? _node_nodes : []
118
+ ];
119
+ const visited = new Set();
120
+ while(pending.length){
121
+ var _child_nodes;
122
+ const id = pending.pop();
123
+ if (visited.has(id)) continue;
124
+ visited.add(id);
125
+ const child = getNode(id);
126
+ if (!child) return true;
127
+ if (child.hidden) continue;
128
+ if (carriesWords(child.props)) {
129
+ return true;
130
+ }
131
+ if (!WORDLESS_ELEMENTS.has(String(child.componentId))) return true;
132
+ pending.push(...(_child_nodes = child.nodes) != null ? _child_nodes : []);
133
+ }
134
+ return false;
135
+ }
136
+ /** What the Accessible label field says while the link has no name. */ export const UNNAMED_LINK_CONTAINER_WARNING = 'Nothing inside this box can be read aloud, so screen readers announce ' + 'it as just "link". Describe where it goes here, or turn on Duplicate of ' + 'another link if a link beside it already goes to the same place.';
137
+ /**
138
+ * The Accessible label field's `resolveProps`: the warning above as its
139
+ * helper text while the link would render with no name, and the field's own
140
+ * description otherwise.
141
+ *
142
+ * Silent without the panel's context, since it cannot see what is inside the
143
+ * box, and silent while Duplicate of another link holds a binding, since each
144
+ * page that places the component decides that for itself.
145
+ */ export function linkContainerLabelFieldProps(_props, field, formOptions, context) {
146
+ var _field_input, _formOptions_getState_values, _formOptions_getState, _formOptions_getState1;
147
+ if (!(context == null ? void 0 : context.node) || hasText(field == null ? void 0 : (_field_input = field.input) == null ? void 0 : _field_input.value)) return {};
148
+ const redundant = formOptions == null ? void 0 : (_formOptions_getState1 = formOptions.getState) == null ? void 0 : (_formOptions_getState = _formOptions_getState1.call(formOptions)) == null ? void 0 : (_formOptions_getState_values = _formOptions_getState.values) == null ? void 0 : _formOptions_getState_values[REDUNDANT_ATTRIBUTE];
149
+ const marked = Aglyn.readYesNoValue(redundant);
150
+ if (marked === true || marked === undefined && redundant != null) {
151
+ return {};
152
+ }
153
+ return linkContentNamesLink(context.node, context.getNode) ? {} : {
154
+ helperText: UNNAMED_LINK_CONTAINER_WARNING
155
+ };
156
+ }
157
+
158
+ //# sourceMappingURL=link-box-accessible-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/link-box-accessible-name.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 * How a Link Container's link gets its accessible name (AGL-2886).\n *\n * An `<a>` is named by the text inside it. A Link Container holding only an\n * Icon has none, so a screen reader announces \"link\" and nothing else\n * (WCAG 2.4.4, 4.1.2). Two attributes answer that, and this module holds both\n * halves of them: what the anchor renders, and the warning the Attributes\n * panel shows while neither has been used.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { ID as boxId } from './box'\nimport { ID as containerId } from './container'\nimport { ID as gridId } from './grid'\nimport { ID as iconId } from './icon'\nimport { ID as imageId } from './image'\nimport { ID as inlineTextId } from './inline-text'\nimport { ID as paperId } from './paper'\nimport { ID as sectionId } from './section'\nimport { ID as stackId } from './stack'\nimport { ID as typographyId } from './typography'\n\n/** The Link Container attribute that marks it as a second link. */\nexport const REDUNDANT_ATTRIBUTE = 'redundant'\n\n/**\n * The anchor attributes that name the link, or take it out of the\n * accessibility tree and the tab order.\n *\n * Redundant wins over a label. A link hidden from assistive tech announces no\n * name, so the label would be an attribute every visitor downloads for\n * nothing. Read through `readYesNoValue` because a switch bound to a Yes / no\n * property can arrive as the string `'false'`, which plain truthiness reads\n * as a yes.\n *\n * `tabIndex` goes with `aria-hidden` because either alone is a defect: a\n * hidden link that still takes focus leaves a keyboard user on a stop that\n * announces nothing, and a skipped link that is still announced is the\n * duplicate this option exists to remove.\n */\nexport function linkContainerA11yProps(\n ariaLabel: unknown,\n redundant: unknown,\n): { 'aria-label'?: string; 'aria-hidden'?: 'true'; tabIndex?: number } {\n if (Aglyn.readYesNoValue(redundant) === true) {\n return { 'aria-hidden': 'true', tabIndex: -1 }\n }\n const label = typeof ariaLabel === 'string' ? ariaLabel.trim() : ''\n return label ? { 'aria-label': label } : {}\n}\n\n/**\n * Elements that add no words of their own to a link they sit inside.\n *\n * An Icon draws an SVG glyph with no text alternative, and a layout container\n * is only the box around its children. Image and the two text elements are\n * listed because their words live in props the walk below reads directly\n * (`alt`, `children`, `html`), so one of them holding none is as silent as an\n * Icon.\n *\n * An element NOT listed, holding none of those props, is taken to name the\n * link. A reusable component keeps its words in its definition, a collection\n * or product element takes them from data, and List Item Text keeps its lines\n * in props of its own. A warning about any of those would be a guess, and a\n * warning that is wrong about correct content teaches an author to ignore the\n * one that is right.\n */\nconst WORDLESS_ELEMENTS: ReadonlySet<string> = new Set([\n boxId,\n containerId,\n gridId,\n iconId,\n imageId,\n inlineTextId,\n paperId,\n sectionId,\n stackId,\n typographyId,\n])\n\nconst hasText = (value: unknown): boolean =>\n typeof value === 'string' && value.trim().length > 0\n\n/**\n * Whether an element inside the link carries words of its own.\n *\n * A binding counts: `{{…}}` is not blank, and what it resolves to is not\n * known until the page renders. An image's alt text counts unless the image\n * is marked decorative, because the renderer drops the alt then.\n */\nfunction carriesWords(props: Record<string, unknown> | undefined): boolean {\n if (!props) return false\n if (hasText(props['children']) || hasText(props['html'])) return true\n if (hasText(props['ariaLabel'])) return true\n return (\n hasText(props['alt']) && Aglyn.readYesNoValue(props['decorative']) !== true\n )\n}\n\n/**\n * Whether what is inside a Link Container gives its link a name, or `true`\n * when that cannot be decided from the document.\n *\n * Walks every descendant. A hidden element is skipped, because the page\n * renders it with `display: none` and that removes it from the accessibility\n * tree. A child the lookup cannot find is an unknown, not a silence.\n */\nexport function linkContentNamesLink(\n node: Aglyn.NodeSchema<any>,\n getNode: Aglyn.AttributeFieldContext['getNode'],\n): boolean {\n // The renderer draws a node's own `children` string inside the element.\n if (hasText((node.props as Record<string, unknown> | undefined)?.['children'])) {\n return true\n }\n const pending = [...(node.nodes ?? [])]\n const visited = new Set<string>()\n while (pending.length) {\n const id = pending.pop() as string\n if (visited.has(id)) continue\n visited.add(id)\n const child = getNode(id)\n if (!child) return true\n if (child.hidden) continue\n if (carriesWords(child.props as Record<string, unknown> | undefined)) {\n return true\n }\n if (!WORDLESS_ELEMENTS.has(String(child.componentId))) return true\n pending.push(...(child.nodes ?? []))\n }\n return false\n}\n\n/** What the Accessible label field says while the link has no name. */\nexport const UNNAMED_LINK_CONTAINER_WARNING =\n 'Nothing inside this box can be read aloud, so screen readers announce ' +\n 'it as just \"link\". Describe where it goes here, or turn on Duplicate of ' +\n 'another link if a link beside it already goes to the same place.'\n\n/**\n * The Accessible label field's `resolveProps`: the warning above as its\n * helper text while the link would render with no name, and the field's own\n * description otherwise.\n *\n * Silent without the panel's context, since it cannot see what is inside the\n * box, and silent while Duplicate of another link holds a binding, since each\n * page that places the component decides that for itself.\n */\nexport function linkContainerLabelFieldProps(\n _props: unknown,\n field: { input?: { value?: unknown } },\n formOptions?: { getState?: () => { values?: Record<string, unknown> } },\n context?: Aglyn.AttributeFieldContext,\n): { helperText?: string } {\n if (!context?.node || hasText(field?.input?.value)) return {}\n const redundant = formOptions?.getState?.()?.values?.[REDUNDANT_ATTRIBUTE]\n const marked = Aglyn.readYesNoValue(redundant)\n if (marked === true || (marked === undefined && redundant != null)) {\n return {}\n }\n return linkContentNamesLink(context.node, context.getNode)\n ? {}\n : { helperText: UNNAMED_LINK_CONTAINER_WARNING }\n}\n"],"names":["Aglyn","ID","boxId","containerId","gridId","iconId","imageId","inlineTextId","paperId","sectionId","stackId","typographyId","REDUNDANT_ATTRIBUTE","linkContainerA11yProps","ariaLabel","redundant","readYesNoValue","tabIndex","label","trim","WORDLESS_ELEMENTS","Set","hasText","value","length","carriesWords","props","linkContentNamesLink","node","getNode","pending","nodes","visited","child","id","pop","has","add","hidden","String","componentId","push","UNNAMED_LINK_CONTAINER_WARNING","linkContainerLabelFieldProps","_props","field","formOptions","context","input","getState","values","marked","undefined","helperText"],"mappings":"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"}
@@ -0,0 +1,66 @@
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
+ import type { SxProps } from '@mui/material/styles';
19
+ import { type ReactNode } from 'react';
20
+ export declare const ID: Aglyn.ComponentId;
21
+ export interface LinkBoxProps {
22
+ /** Target screen id, resolved from the host routing map at render time. */
23
+ screenId?: string;
24
+ /** External URL escape hatch, used only when no `screenId` is set. */
25
+ href?: string;
26
+ /** Opens in a new tab. External destinations only. */
27
+ newTab?: boolean;
28
+ /** The link's name for assistive tech, when its content supplies none. */
29
+ ariaLabel?: string;
30
+ /**
31
+ * The box repeats a link beside it to the same destination, so it is
32
+ * hidden from assistive tech and left out of the tab order.
33
+ */
34
+ redundant?: boolean;
35
+ /**
36
+ * Authored node styles, handed over by the renderer rather than typed into
37
+ * an attribute. Declared because the merge below reads it: undeclared, no
38
+ * typed caller could style a tile (AGL-1323).
39
+ */
40
+ sx?: SxProps;
41
+ children?: ReactNode;
42
+ }
43
+ /**
44
+ * A container that IS the link — icon, heading and description inside one
45
+ * anchor, instead of a tile whose only clickable part is its title.
46
+ *
47
+ * Every other linking element in the plugin is a leaf: Screen Link and
48
+ * Button both render their `children` as inline text, so `nodeAcceptsChildren`
49
+ * reports false and the canvas will not let anything be dropped inside them.
50
+ * That left no way to author a card, a mega-menu tile, or a linked logo —
51
+ * the shapes where the whole box is meant to be one target (AGL-1231).
52
+ *
53
+ * Nothing interactive may be nested inside: an `<a>` inside an `<a>` is
54
+ * invalid HTML and browsers unnest it, which silently moves half the tile
55
+ * back out of the link. Convert an inner Screen Link to plain Text when you
56
+ * wrap it in one of these.
57
+ *
58
+ * The link is named by the text inside it, so a box holding only an icon
59
+ * needs `ariaLabel` — or `redundant`, when a link beside it already goes to
60
+ * the same place (AGL-2886). Both land on the anchor in every branch below,
61
+ * so the canvas carries the same attributes the published page does.
62
+ */
63
+ declare const LinkBox: import("react").ForwardRefExoticComponent<LinkBoxProps & import("react").RefAttributes<HTMLElement>>;
64
+ export declare const schema: Aglyn.ComponentSchema<LinkBoxProps>;
65
+ export declare const presets: Aglyn.PresetSchema[];
66
+ export default LinkBox;