@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,407 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ import { jsx as _jsx } from "react/jsx-runtime";
4
+ /**
5
+ * @license
6
+ * Copyright 2026 Aglyn LLC
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */ import * as Aglyn from "@aglyn/aglyn";
20
+ import { mdiFormatColorHighlight, mdiFormatColorText } from "@aglyn/shared-data-mdi";
21
+ import MuiBox from "@mui/material/Box";
22
+ import { forwardRef } from "react";
23
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
24
+ import { FIELD_TEXT_CONTENT } from "../constants/field-presets.js";
25
+ import { authorHtmlLabel } from "../utils/author-html-label.js";
26
+ import { generatePresetId } from "../utils/generate-preset-id.js";
27
+ // Component ids are persisted in screen documents; never rename.
28
+ export const ID = 'muiInlineText';
29
+ /**
30
+ * Inline elements the run may render as. An allow-list rather than a
31
+ * free-text field, for the same reason Box's is (AGL-1201): `element` is
32
+ * persisted and rendered verbatim into every visitor's page, so a typed
33
+ * value would let an author put `script`/`iframe` there.
34
+ *
35
+ * All five are phrasing content, so a run is always legal inside a
36
+ * paragraph — which is the whole point of the element.
37
+ */ export const INLINE_TEXT_ELEMENTS = [
38
+ 'span',
39
+ 'strong',
40
+ 'em',
41
+ 'mark',
42
+ 'small'
43
+ ];
44
+ /**
45
+ * Theme palette paths, never raw hexes: the design's `text/muted` and
46
+ * `text/primary` tokens ARE `text.secondary` / `text.primary`, and a
47
+ * hardcoded `#757575` would ignore the site's theme (and dark mode).
48
+ *
49
+ * Every value is a real sentinel — an option value of `''` is stripped
50
+ * before save and the pick silently reverts on reload (AGL-1191), so
51
+ * "inherit" has to be spelled out rather than left blank.
52
+ */ const TONE_COLOR = {
53
+ inherit: undefined,
54
+ primary: 'text.primary',
55
+ secondary: 'text.secondary',
56
+ disabled: 'text.disabled',
57
+ accent: 'primary.main',
58
+ accentAlt: 'secondary.main',
59
+ success: 'success.main',
60
+ warning: 'warning.main',
61
+ error: 'error.main'
62
+ };
63
+ /** Named weights so the field is a pick, not a number to remember. */ const FONT_WEIGHT = {
64
+ inherit: undefined,
65
+ regular: 400,
66
+ medium: 500,
67
+ semibold: 600,
68
+ bold: 700
69
+ };
70
+ /**
71
+ * `text-decoration` PROPAGATES — it is not inherited. An ancestor's
72
+ * underline (a Screen Link, a struck-through block) is painted straight
73
+ * across every in-flow inline descendant, and `text-decoration: none` on
74
+ * the descendant CANNOT remove it. Only an element that is not an in-flow
75
+ * non-atomic inline box escapes the propagation, which is why "None" also
76
+ * switches the run to `inline-block`: an atomic inline box is not painted
77
+ * through.
78
+ *
79
+ * That costs line-breaking — an inline-block will not break across lines —
80
+ * so it is opt-in rather than the default, and the field says so. The
81
+ * default, `inherit`, is a plain `display: inline` run that flows and wraps
82
+ * with the rest of the sentence.
83
+ */ const DECORATION_SX = {
84
+ inherit: {},
85
+ none: {
86
+ display: 'inline-block',
87
+ textDecoration: 'none'
88
+ },
89
+ underline: {
90
+ textDecoration: 'underline'
91
+ },
92
+ lineThrough: {
93
+ textDecoration: 'line-through'
94
+ }
95
+ };
96
+ /**
97
+ * One run of text inside a sentence (AGL-1235).
98
+ *
99
+ * The gap this fills: `muiTypography` is `textEditable`, therefore a leaf —
100
+ * `nodeAcceptsChildren` reports false, so no span can be nested inside it.
101
+ * A statement whose argument lives in an emphasised phrase ("Aglyn commerce
102
+ * is **part of the platform**") could not be authored at all; the whole line
103
+ * was one flat colour.
104
+ *
105
+ * This is a leaf too, deliberately: the shape that renders correctly is a
106
+ * block container holding SIBLING inline runs, not a nested span. Sibling
107
+ * runs flow and wrap as a single paragraph, so the sentence breaks
108
+ * naturally with the emphasis landing in the right place. Drop a Box as
109
+ * `p`, then one of these per style change.
110
+ */ const InlineText = /*#__PURE__*/ forwardRef((props, ref)=>{
111
+ var _DECORATION_SX_decoration, _authorHtmlLabel;
112
+ const { element, tone, weight, decoration, children, sx, html } = props, rest = _object_without_properties_loose(props, [
113
+ "element",
114
+ "tone",
115
+ "weight",
116
+ "decoration",
117
+ "children",
118
+ "sx",
119
+ "html"
120
+ ]);
121
+ const component = INLINE_TEXT_ELEMENTS.includes(element) ? element : 'span';
122
+ // Node styles ride the renderer-merged sx; recompose rather than spread
123
+ // (the stack.ts/link-box.tsx pattern). Writing an `sx` literal after the
124
+ // props spread would REPLACE the author's styles silently — the defect
125
+ // class `aglyn/no-sx-after-spread` guards (AGL-1240/1284).
126
+ const nodeSx = Array.isArray(sx) ? sx : sx ? [
127
+ sx
128
+ ] : [];
129
+ // A cleared attribute persists as null, so every lookup below must miss
130
+ // rather than throw; `Record[null]` is simply undefined.
131
+ const color = TONE_COLOR[tone];
132
+ const fontWeight = FONT_WEIGHT[weight];
133
+ return /*#__PURE__*/ _jsx(MuiBox, _extends({
134
+ ref: ref,
135
+ component: component
136
+ }, rest, {
137
+ // Order matters: the baseline first, then the declared attributes,
138
+ // then the author's node styles last so the Styles panel always wins.
139
+ sx: [
140
+ {
141
+ display: 'inline'
142
+ },
143
+ color ? {
144
+ color
145
+ } : {},
146
+ fontWeight ? {
147
+ fontWeight
148
+ } : {},
149
+ (_DECORATION_SX_decoration = DECORATION_SX[decoration]) != null ? _DECORATION_SX_decoration : {},
150
+ ...nodeSx
151
+ ],
152
+ children: (_authorHtmlLabel = authorHtmlLabel(html)) != null ? _authorHtmlLabel : children
153
+ }));
154
+ });
155
+ InlineText.displayName = 'AglynInlineText';
156
+ export const schema = {
157
+ $id: ID,
158
+ pluginId: BUNDLE_ID,
159
+ displayName: 'Inline Text',
160
+ description: 'One run of text inside a sentence — put several side by side in a ' + 'paragraph to emphasise a phrase without breaking the line.',
161
+ category: Aglyn.ComponentCategory.TEXT,
162
+ icon: {
163
+ path: mdiFormatColorText.path,
164
+ sx: {
165
+ color: '#057822'
166
+ }
167
+ },
168
+ flags: {
169
+ // The run IS its text: edited inline on the canvas, like Typography.
170
+ textEditable: Aglyn.FEATURE_FLAG.ENABLED,
171
+ richTextEditable: Aglyn.FEATURE_FLAG.ENABLED
172
+ },
173
+ // Emphasis only (AGL-2557), for a different reason than the controls: this
174
+ // run is not interactive, it is `display: inline`. Every element it may
175
+ // render as is phrasing content — that is the guarantee INLINE_TEXT_ELEMENTS
176
+ // exists to make — so a list inside one is a block in an inline box, which
177
+ // the parser lifts straight back out of the enclosing paragraph. Links stay
178
+ // with Screen Link, whose job is a resolved target rather than a typed href.
179
+ richTextCommands: [
180
+ Aglyn.RICH_TEXT_COMMANDS.EMPHASIS
181
+ ],
182
+ attributes: [
183
+ FIELD_TEXT_CONTENT,
184
+ {
185
+ name: 'element',
186
+ label: 'Component',
187
+ description: 'The DOM element this run renders as. `strong` and `em` carry ' + 'meaning for screen readers and search engines; `mark` marks a ' + 'highlighted phrase; `span` is purely visual.',
188
+ component: Aglyn.FieldComponentType.SELECT,
189
+ options: INLINE_TEXT_ELEMENTS.map((value)=>({
190
+ value,
191
+ label: value
192
+ }))
193
+ },
194
+ {
195
+ name: 'tone',
196
+ label: 'Color',
197
+ description: "Palette token for this run. Two-tone text is a muted sentence " + 'with one run set to Primary (or Accent) — theme tokens, so it ' + 'still reads correctly in dark mode.',
198
+ component: Aglyn.FieldComponentType.SELECT,
199
+ options: [
200
+ {
201
+ value: 'inherit',
202
+ label: 'Inherit'
203
+ },
204
+ {
205
+ value: 'primary',
206
+ label: 'Text primary'
207
+ },
208
+ {
209
+ value: 'secondary',
210
+ label: 'Text muted'
211
+ },
212
+ {
213
+ value: 'disabled',
214
+ label: 'Text disabled'
215
+ },
216
+ {
217
+ value: 'accent',
218
+ label: 'Accent'
219
+ },
220
+ {
221
+ value: 'accentAlt',
222
+ label: 'Accent alternate'
223
+ },
224
+ {
225
+ value: 'success',
226
+ label: 'Success'
227
+ },
228
+ {
229
+ value: 'warning',
230
+ label: 'Warning'
231
+ },
232
+ {
233
+ value: 'error',
234
+ label: 'Error'
235
+ }
236
+ ]
237
+ },
238
+ {
239
+ name: 'weight',
240
+ label: 'Weight',
241
+ description: 'Font weight for this run only.',
242
+ component: Aglyn.FieldComponentType.SELECT,
243
+ options: [
244
+ {
245
+ value: 'inherit',
246
+ label: 'Inherit'
247
+ },
248
+ {
249
+ value: 'regular',
250
+ label: 'Regular'
251
+ },
252
+ {
253
+ value: 'medium',
254
+ label: 'Medium'
255
+ },
256
+ {
257
+ value: 'semibold',
258
+ label: 'Semi bold'
259
+ },
260
+ {
261
+ value: 'bold',
262
+ label: 'Bold'
263
+ }
264
+ ]
265
+ },
266
+ {
267
+ name: 'decoration',
268
+ label: 'Underline / strike',
269
+ description: 'Inherit follows the surrounding text, including a link\'s ' + 'underline — an underline PROPAGATES down and cannot be switched ' + 'off from inside. None does switch it off, at the cost of the run ' + 'no longer breaking across lines, so keep it to a short phrase.',
270
+ component: Aglyn.FieldComponentType.SELECT,
271
+ options: [
272
+ {
273
+ value: 'inherit',
274
+ label: 'Inherit'
275
+ },
276
+ {
277
+ value: 'none',
278
+ label: 'None (does not wrap)'
279
+ },
280
+ {
281
+ value: 'underline',
282
+ label: 'Underline'
283
+ },
284
+ {
285
+ value: 'lineThrough',
286
+ label: 'Strikethrough'
287
+ }
288
+ ]
289
+ }
290
+ ]
291
+ };
292
+ export const presets = [
293
+ {
294
+ $id: generatePresetId(ID),
295
+ type: Aglyn.NodeType.PRESET,
296
+ displayName: 'Inline Text',
297
+ pluginId: BUNDLE_ID,
298
+ description: 'One run of text inside a sentence',
299
+ category: Aglyn.ComponentCategory.TEXT,
300
+ icon: schema.icon,
301
+ data: {
302
+ $id: null,
303
+ componentId: ID,
304
+ pluginId: BUNDLE_ID,
305
+ props: {
306
+ element: 'span',
307
+ children: 'Inline text'
308
+ }
309
+ }
310
+ },
311
+ {
312
+ $id: generatePresetId(ID, 'emphasis'),
313
+ type: Aglyn.NodeType.PRESET,
314
+ displayName: 'Emphasised Text',
315
+ pluginId: BUNDLE_ID,
316
+ description: 'A phrase picked out of a muted sentence',
317
+ category: Aglyn.ComponentCategory.TEXT,
318
+ icon: {
319
+ path: mdiFormatColorHighlight.path,
320
+ sx: {
321
+ color: '#057822'
322
+ }
323
+ },
324
+ data: {
325
+ $id: null,
326
+ componentId: ID,
327
+ pluginId: BUNDLE_ID,
328
+ props: {
329
+ element: 'strong',
330
+ tone: 'primary',
331
+ weight: 'bold',
332
+ children: 'the emphasised phrase'
333
+ }
334
+ }
335
+ },
336
+ {
337
+ // The whole shape in one drop (AGL-1235): the reason the emphasis was
338
+ // never authored is that assembling it by hand meant a container, three
339
+ // runs and a colour on each. This is that assembly, ready to retype.
340
+ $id: generatePresetId(ID, 'statement'),
341
+ type: Aglyn.NodeType.PRESET,
342
+ displayName: 'Two-tone Statement',
343
+ pluginId: BUNDLE_ID,
344
+ description: 'A muted sentence with one phrase emphasised',
345
+ category: Aglyn.ComponentCategory.TEXT,
346
+ icon: {
347
+ path: mdiFormatColorHighlight.path,
348
+ sx: {
349
+ color: '#057822'
350
+ }
351
+ },
352
+ data: {
353
+ $id: null,
354
+ // A real `<p>`, not a div: the runs are phrasing content, so the
355
+ // paragraph is the honest container and screen readers get a
356
+ // sentence rather than three unrelated fragments.
357
+ componentId: 'muiBox',
358
+ pluginId: BUNDLE_ID,
359
+ props: {
360
+ component: 'p'
361
+ },
362
+ // Node-level sx (AGL-1346) — the record the Styles panel edits.
363
+ sx: {
364
+ marginTop: 0,
365
+ marginRight: 0,
366
+ marginBottom: 0,
367
+ marginLeft: 0
368
+ },
369
+ nodes: [
370
+ {
371
+ $id: null,
372
+ componentId: ID,
373
+ pluginId: BUNDLE_ID,
374
+ props: {
375
+ element: 'span',
376
+ tone: 'secondary',
377
+ children: 'Everything you build is '
378
+ }
379
+ },
380
+ {
381
+ $id: null,
382
+ componentId: ID,
383
+ pluginId: BUNDLE_ID,
384
+ props: {
385
+ element: 'strong',
386
+ tone: 'primary',
387
+ weight: 'bold',
388
+ children: 'part of the platform'
389
+ }
390
+ },
391
+ {
392
+ $id: null,
393
+ componentId: ID,
394
+ pluginId: BUNDLE_ID,
395
+ props: {
396
+ element: 'span',
397
+ tone: 'secondary',
398
+ children: ', not bolted onto it.'
399
+ }
400
+ }
401
+ ]
402
+ }
403
+ }
404
+ ];
405
+ export default InlineText;
406
+
407
+ //# sourceMappingURL=inline-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/inline-text.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiFormatColorHighlight, mdiFormatColorText } from '@aglyn/shared-data-mdi'\nimport MuiBox from '@mui/material/Box'\nimport type { SxProps } from '@mui/material/styles'\nimport { forwardRef, type ReactNode } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { FIELD_TEXT_CONTENT } from '../constants/field-presets'\nimport { authorHtmlLabel } from '../utils/author-html-label'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiInlineText'\n\n/**\n * Inline elements the run may render as. An allow-list rather than a\n * free-text field, for the same reason Box's is (AGL-1201): `element` is\n * persisted and rendered verbatim into every visitor's page, so a typed\n * value would let an author put `script`/`iframe` there.\n *\n * All five are phrasing content, so a run is always legal inside a\n * paragraph — which is the whole point of the element.\n */\nexport const INLINE_TEXT_ELEMENTS = [\n 'span',\n 'strong',\n 'em',\n 'mark',\n 'small',\n] as const\nexport type InlineTextElement = (typeof INLINE_TEXT_ELEMENTS)[number]\n\n/**\n * Theme palette paths, never raw hexes: the design's `text/muted` and\n * `text/primary` tokens ARE `text.secondary` / `text.primary`, and a\n * hardcoded `#757575` would ignore the site's theme (and dark mode).\n *\n * Every value is a real sentinel — an option value of `''` is stripped\n * before save and the pick silently reverts on reload (AGL-1191), so\n * \"inherit\" has to be spelled out rather than left blank.\n */\nconst TONE_COLOR: Record<string, string> = {\n inherit: undefined,\n primary: 'text.primary',\n secondary: 'text.secondary',\n disabled: 'text.disabled',\n accent: 'primary.main',\n accentAlt: 'secondary.main',\n success: 'success.main',\n warning: 'warning.main',\n error: 'error.main',\n}\n\n/** Named weights so the field is a pick, not a number to remember. */\nconst FONT_WEIGHT: Record<string, number> = {\n inherit: undefined,\n regular: 400,\n medium: 500,\n semibold: 600,\n bold: 700,\n}\n\n/**\n * `text-decoration` PROPAGATES — it is not inherited. An ancestor's\n * underline (a Screen Link, a struck-through block) is painted straight\n * across every in-flow inline descendant, and `text-decoration: none` on\n * the descendant CANNOT remove it. Only an element that is not an in-flow\n * non-atomic inline box escapes the propagation, which is why \"None\" also\n * switches the run to `inline-block`: an atomic inline box is not painted\n * through.\n *\n * That costs line-breaking — an inline-block will not break across lines —\n * so it is opt-in rather than the default, and the field says so. The\n * default, `inherit`, is a plain `display: inline` run that flows and wraps\n * with the rest of the sentence.\n */\nconst DECORATION_SX: Record<string, Record<string, string>> = {\n inherit: {},\n none: { display: 'inline-block', textDecoration: 'none' },\n underline: { textDecoration: 'underline' },\n lineThrough: { textDecoration: 'line-through' },\n}\n\nexport interface InlineTextProps {\n /** The DOM element rendered; defaults to `span`. */\n element?: InlineTextElement\n /** Palette token key from {@link TONE_COLOR}. */\n tone?: string\n /** Named weight key from {@link FONT_WEIGHT}. */\n weight?: string\n /** Decoration behaviour key from {@link DECORATION_SX}. */\n decoration?: string\n /**\n * Authored node styles, handed over by the renderer rather than typed\n * into an attribute. Declared because the merge below reads it —\n * undeclared, no typed caller could style a run (AGL-1323).\n */\n sx?: SxProps\n /**\n * Sanitized emphasis markup for the run, written by the inline editor's\n * rich mode (AGL-2557). `children` keeps the plain-text reading of it, and\n * is what every surface that cannot render markup falls back to.\n */\n html?: string\n /** The text of this run; edited inline on the canvas. */\n children?: ReactNode\n}\n\n/**\n * One run of text inside a sentence (AGL-1235).\n *\n * The gap this fills: `muiTypography` is `textEditable`, therefore a leaf —\n * `nodeAcceptsChildren` reports false, so no span can be nested inside it.\n * A statement whose argument lives in an emphasised phrase (\"Aglyn commerce\n * is **part of the platform**\") could not be authored at all; the whole line\n * was one flat colour.\n *\n * This is a leaf too, deliberately: the shape that renders correctly is a\n * block container holding SIBLING inline runs, not a nested span. Sibling\n * runs flow and wrap as a single paragraph, so the sentence breaks\n * naturally with the emphasis landing in the right place. Drop a Box as\n * `p`, then one of these per style change.\n */\nconst InlineText = forwardRef<HTMLElement, InlineTextProps>((props, ref) => {\n const { element, tone, weight, decoration, children, sx, html, ...rest } =\n props\n const component = INLINE_TEXT_ELEMENTS.includes(element as InlineTextElement)\n ? (element as InlineTextElement)\n : 'span'\n // Node styles ride the renderer-merged sx; recompose rather than spread\n // (the stack.ts/link-box.tsx pattern). Writing an `sx` literal after the\n // props spread would REPLACE the author's styles silently — the defect\n // class `aglyn/no-sx-after-spread` guards (AGL-1240/1284).\n const nodeSx = Array.isArray(sx) ? sx : sx ? [sx] : []\n // A cleared attribute persists as null, so every lookup below must miss\n // rather than throw; `Record[null]` is simply undefined.\n const color = TONE_COLOR[tone]\n const fontWeight = FONT_WEIGHT[weight]\n return (\n <MuiBox\n ref={ref}\n component={component}\n {...rest}\n // Order matters: the baseline first, then the declared attributes,\n // then the author's node styles last so the Styles panel always wins.\n sx={[\n { display: 'inline' },\n color ? { color } : {},\n fontWeight ? { fontWeight } : {},\n DECORATION_SX[decoration] ?? {},\n ...nodeSx,\n ]}\n >\n {authorHtmlLabel(html) ?? children}\n </MuiBox>\n )\n})\nInlineText.displayName = 'AglynInlineText'\n\nexport const schema: Aglyn.ComponentSchema<InlineTextProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Inline Text',\n description:\n 'One run of text inside a sentence — put several side by side in a ' +\n 'paragraph to emphasise a phrase without breaking the line.',\n category: Aglyn.ComponentCategory.TEXT,\n icon: { path: mdiFormatColorText.path, sx: { color: '#057822' } },\n flags: {\n // The run IS its text: edited inline on the canvas, like Typography.\n textEditable: Aglyn.FEATURE_FLAG.ENABLED,\n richTextEditable: Aglyn.FEATURE_FLAG.ENABLED,\n },\n // Emphasis only (AGL-2557), for a different reason than the controls: this\n // run is not interactive, it is `display: inline`. Every element it may\n // render as is phrasing content — that is the guarantee INLINE_TEXT_ELEMENTS\n // exists to make — so a list inside one is a block in an inline box, which\n // the parser lifts straight back out of the enclosing paragraph. Links stay\n // with Screen Link, whose job is a resolved target rather than a typed href.\n richTextCommands: [Aglyn.RICH_TEXT_COMMANDS.EMPHASIS],\n attributes: [\n FIELD_TEXT_CONTENT,\n {\n name: 'element',\n label: 'Component',\n description:\n 'The DOM element this run renders as. `strong` and `em` carry ' +\n 'meaning for screen readers and search engines; `mark` marks a ' +\n 'highlighted phrase; `span` is purely visual.',\n component: Aglyn.FieldComponentType.SELECT,\n options: INLINE_TEXT_ELEMENTS.map((value) => ({ value, label: value })),\n },\n {\n name: 'tone',\n label: 'Color',\n description:\n \"Palette token for this run. Two-tone text is a muted sentence \" +\n 'with one run set to Primary (or Accent) — theme tokens, so it ' +\n 'still reads correctly in dark mode.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'primary', label: 'Text primary' },\n { value: 'secondary', label: 'Text muted' },\n { value: 'disabled', label: 'Text disabled' },\n { value: 'accent', label: 'Accent' },\n { value: 'accentAlt', label: 'Accent alternate' },\n { value: 'success', label: 'Success' },\n { value: 'warning', label: 'Warning' },\n { value: 'error', label: 'Error' },\n ],\n },\n {\n name: 'weight',\n label: 'Weight',\n description: 'Font weight for this run only.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'regular', label: 'Regular' },\n { value: 'medium', label: 'Medium' },\n { value: 'semibold', label: 'Semi bold' },\n { value: 'bold', label: 'Bold' },\n ],\n },\n {\n name: 'decoration',\n label: 'Underline / strike',\n description:\n 'Inherit follows the surrounding text, including a link\\'s ' +\n 'underline — an underline PROPAGATES down and cannot be switched ' +\n 'off from inside. None does switch it off, at the cost of the run ' +\n 'no longer breaking across lines, so keep it to a short phrase.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { value: 'inherit', label: 'Inherit' },\n { value: 'none', label: 'None (does not wrap)' },\n { value: 'underline', label: 'Underline' },\n { value: 'lineThrough', label: 'Strikethrough' },\n ],\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Inline Text',\n pluginId: BUNDLE_ID,\n description: 'One run of text inside a sentence',\n category: Aglyn.ComponentCategory.TEXT,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { element: 'span', children: 'Inline text' },\n },\n },\n {\n $id: generatePresetId(ID, 'emphasis'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Emphasised Text',\n pluginId: BUNDLE_ID,\n description: 'A phrase picked out of a muted sentence',\n category: Aglyn.ComponentCategory.TEXT,\n icon: { path: mdiFormatColorHighlight.path, sx: { color: '#057822' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'strong',\n tone: 'primary',\n weight: 'bold',\n children: 'the emphasised phrase',\n },\n },\n },\n {\n // The whole shape in one drop (AGL-1235): the reason the emphasis was\n // never authored is that assembling it by hand meant a container, three\n // runs and a colour on each. This is that assembly, ready to retype.\n $id: generatePresetId(ID, 'statement'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Two-tone Statement',\n pluginId: BUNDLE_ID,\n description: 'A muted sentence with one phrase emphasised',\n category: Aglyn.ComponentCategory.TEXT,\n icon: { path: mdiFormatColorHighlight.path, sx: { color: '#057822' } },\n data: {\n $id: null,\n // A real `<p>`, not a div: the runs are phrasing content, so the\n // paragraph is the honest container and screen readers get a\n // sentence rather than three unrelated fragments.\n componentId: 'muiBox',\n pluginId: BUNDLE_ID,\n props: { component: 'p' },\n // Node-level sx (AGL-1346) — the record the Styles panel edits.\n sx: { marginTop: 0, marginRight: 0, marginBottom: 0, marginLeft: 0 },\n nodes: [\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'span',\n tone: 'secondary',\n children: 'Everything you build is ',\n },\n },\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'strong',\n tone: 'primary',\n weight: 'bold',\n children: 'part of the platform',\n },\n },\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n element: 'span',\n tone: 'secondary',\n children: ', not bolted onto it.',\n },\n },\n ],\n },\n },\n]\n\nexport default InlineText\n"],"names":["Aglyn","mdiFormatColorHighlight","mdiFormatColorText","MuiBox","forwardRef","BUNDLE_ID","FIELD_TEXT_CONTENT","authorHtmlLabel","generatePresetId","ID","INLINE_TEXT_ELEMENTS","TONE_COLOR","inherit","undefined","primary","secondary","disabled","accent","accentAlt","success","warning","error","FONT_WEIGHT","regular","medium","semibold","bold","DECORATION_SX","none","display","textDecoration","underline","lineThrough","InlineText","props","ref","element","tone","weight","decoration","children","sx","html","rest","component","includes","nodeSx","Array","isArray","color","fontWeight","displayName","schema","$id","pluginId","description","category","ComponentCategory","TEXT","icon","path","flags","textEditable","FEATURE_FLAG","ENABLED","richTextEditable","richTextCommands","RICH_TEXT_COMMANDS","EMPHASIS","attributes","name","label","FieldComponentType","SELECT","options","map","value","presets","type","NodeType","PRESET","data","componentId","marginTop","marginRight","marginBottom","marginLeft","nodes"],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import * as Aglyn from '@aglyn/aglyn';
18
+ export declare const ID: Aglyn.ComponentId;
19
+ export interface LanguageSwitcherProps {
20
+ /** 'text' shows locale codes; 'buttons' renders outlined buttons. */
21
+ variant?: 'text' | 'buttons';
22
+ /** Uppercase the locale codes (EN / ES). */
23
+ uppercase?: boolean;
24
+ }
25
+ /**
26
+ * Language switcher (AGL-164): renders one link per translation of the
27
+ * CURRENT screen, resolved from ScreenLinkContext (`localeVariants` +
28
+ * routing map), so it works inside shared layouts. Shows a placeholder in
29
+ * the editor when the screen has no variants; renders nothing on the live
30
+ * site in that case.
31
+ */
32
+ declare const LanguageSwitcher: import("react").ForwardRefExoticComponent<LanguageSwitcherProps & import("react").RefAttributes<HTMLElement>>;
33
+ export declare const schema: Aglyn.ComponentSchema<LanguageSwitcherProps>;
34
+ export declare const presets: Aglyn.PresetSchema[];
35
+ export default LanguageSwitcher;
@@ -0,0 +1,179 @@
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 { mdiTranslate } from "@aglyn/shared-data-mdi";
21
+ import { AppLink } from "@aglyn/shared-ui-jsx";
22
+ import Button from "@mui/material/Button";
23
+ import Stack from "@mui/material/Stack";
24
+ import { forwardRef, useContext } from "react";
25
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
26
+ import { generatePresetId } from "../utils/generate-preset-id.js";
27
+ // Component ids are persisted in screen documents; never rename.
28
+ export const ID = 'languageSwitcher';
29
+ /**
30
+ * Language switcher (AGL-164): renders one link per translation of the
31
+ * CURRENT screen, resolved from ScreenLinkContext (`localeVariants` +
32
+ * routing map), so it works inside shared layouts. Shows a placeholder in
33
+ * the editor when the screen has no variants; renders nothing on the live
34
+ * site in that case.
35
+ */ const LanguageSwitcher = /*#__PURE__*/ forwardRef((props, ref)=>{
36
+ const { variant, uppercase } = props, rest = _object_without_properties_loose(props, [
37
+ "variant",
38
+ "uppercase"
39
+ ]);
40
+ // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).
41
+ const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [
42
+ props['sx']
43
+ ];
44
+ const { screens, localeVariants, currentLocale, suppressNavigation } = useContext(Aglyn.ScreenLinkContext);
45
+ const entries = Object.entries(localeVariants != null ? localeVariants : {}).filter(([, screenId])=>(screens == null ? void 0 : screens[screenId]) != null);
46
+ const format = (locale)=>uppercase === false ? locale : locale.toUpperCase();
47
+ if (!entries.length) {
48
+ // Editor-only placeholder; invisible on the live site.
49
+ if (!suppressNavigation) return null;
50
+ return /*#__PURE__*/ _jsx(Stack, _extends({
51
+ ref: ref,
52
+ direction: "row",
53
+ spacing: 1
54
+ }, rest, {
55
+ sx: [
56
+ {
57
+ alignItems: 'center',
58
+ border: '1px dashed',
59
+ borderColor: 'divider',
60
+ borderRadius: 1,
61
+ px: 1.5,
62
+ py: 0.5,
63
+ color: 'text.secondary',
64
+ fontSize: 12,
65
+ fontFamily: 'system-ui, sans-serif'
66
+ },
67
+ ...nodeSx
68
+ ],
69
+ children: 'Language switcher — set screen translations'
70
+ }));
71
+ }
72
+ return /*#__PURE__*/ _jsxs(Stack, _extends({
73
+ ref: ref,
74
+ direction: "row",
75
+ spacing: 0.5
76
+ }, rest, {
77
+ sx: [
78
+ {
79
+ alignItems: 'center'
80
+ },
81
+ ...nodeSx
82
+ ],
83
+ children: [
84
+ currentLocale ? /*#__PURE__*/ _jsx(Button, {
85
+ size: "small",
86
+ variant: "text",
87
+ disabled: true,
88
+ children: format(currentLocale)
89
+ }) : null,
90
+ entries.map(([locale, screenId])=>{
91
+ const path = screens == null ? void 0 : screens[screenId];
92
+ const href = path != null ? Aglyn.screenRoutePathToUrl(path) : undefined;
93
+ if (!href || suppressNavigation) {
94
+ return /*#__PURE__*/ _jsx(Button, {
95
+ size: "small",
96
+ variant: "text",
97
+ children: format(locale)
98
+ }, locale);
99
+ }
100
+ return /*#__PURE__*/ _jsx(AppLink, {
101
+ componentVariant: "button",
102
+ href: href,
103
+ size: "small",
104
+ variant: variant === 'buttons' ? 'outlined' : 'text',
105
+ children: format(locale)
106
+ }, locale);
107
+ })
108
+ ]
109
+ }));
110
+ });
111
+ LanguageSwitcher.displayName = 'LanguageSwitcher';
112
+ export const schema = {
113
+ $id: ID,
114
+ pluginId: BUNDLE_ID,
115
+ displayName: 'Language Switcher',
116
+ description: "Links between this screen's translations. It hides itself when there are none.",
117
+ category: Aglyn.ComponentCategory.NAVIGATION,
118
+ icon: {
119
+ path: mdiTranslate.path,
120
+ sx: {
121
+ color: '#2196f3'
122
+ }
123
+ },
124
+ flags: {
125
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
126
+ },
127
+ attributes: [
128
+ {
129
+ name: 'variant',
130
+ description: 'How the language links render.',
131
+ component: Aglyn.FieldComponentType.SELECT,
132
+ label: 'Style',
133
+ // `text` is half of the declared `'text' | 'buttons'` union and the
134
+ // value the render already falls back to; as `''` the option was
135
+ // unpersistable (AGL-1191) and outside its own prop type (AGL-1451).
136
+ options: [
137
+ {
138
+ value: 'text',
139
+ label: 'Text (default)'
140
+ },
141
+ {
142
+ value: 'buttons',
143
+ label: 'Outlined buttons'
144
+ }
145
+ ]
146
+ },
147
+ {
148
+ name: 'uppercase',
149
+ description: 'Show locale codes uppercased (EN, ES).',
150
+ component: Aglyn.FieldComponentType.CHECKBOX,
151
+ label: 'Uppercase'
152
+ }
153
+ ]
154
+ };
155
+ export const presets = [
156
+ {
157
+ $id: generatePresetId(ID),
158
+ type: Aglyn.NodeType.PRESET,
159
+ displayName: 'Language Switcher',
160
+ pluginId: BUNDLE_ID,
161
+ description: 'Links between this screen’s translations',
162
+ category: Aglyn.ComponentCategory.NAVIGATION,
163
+ icon: {
164
+ path: mdiTranslate.path,
165
+ sx: {
166
+ color: '#2196f3'
167
+ }
168
+ },
169
+ data: {
170
+ $id: null,
171
+ componentId: ID,
172
+ pluginId: BUNDLE_ID,
173
+ props: {}
174
+ }
175
+ }
176
+ ];
177
+ export default LanguageSwitcher;
178
+
179
+ //# sourceMappingURL=language-switcher.js.map