@aglyn/plugins-mui 1.0.0-beta.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +22 -0
- package/package.json +47 -0
- package/src/index.d.ts +21 -0
- package/src/index.js +22 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/accordion.d.ts +96 -0
- package/src/lib/components/accordion.js +392 -0
- package/src/lib/components/accordion.js.map +1 -0
- package/src/lib/components/app-bar.d.ts +32 -0
- package/src/lib/components/app-bar.js +86 -0
- package/src/lib/components/app-bar.js.map +1 -0
- package/src/lib/components/blocks.d.ts +46 -0
- package/src/lib/components/blocks.js +1007 -0
- package/src/lib/components/blocks.js.map +1 -0
- package/src/lib/components/box.d.ts +47 -0
- package/src/lib/components/box.js +125 -0
- package/src/lib/components/box.js.map +1 -0
- package/src/lib/components/breadcrumbs.d.ts +44 -0
- package/src/lib/components/breadcrumbs.js +172 -0
- package/src/lib/components/breadcrumbs.js.map +1 -0
- package/src/lib/components/button.d.ts +89 -0
- package/src/lib/components/button.js +272 -0
- package/src/lib/components/button.js.map +1 -0
- package/src/lib/components/card.d.ts +61 -0
- package/src/lib/components/card.js +336 -0
- package/src/lib/components/card.js.map +1 -0
- package/src/lib/components/collection.d.ts +514 -0
- package/src/lib/components/collection.js +2999 -0
- package/src/lib/components/collection.js.map +1 -0
- package/src/lib/components/container.d.ts +42 -0
- package/src/lib/components/container.js +169 -0
- package/src/lib/components/container.js.map +1 -0
- package/src/lib/components/custom-html.d.ts +78 -0
- package/src/lib/components/custom-html.js +219 -0
- package/src/lib/components/custom-html.js.map +1 -0
- package/src/lib/components/data-table.d.ts +57 -0
- package/src/lib/components/data-table.js +216 -0
- package/src/lib/components/data-table.js.map +1 -0
- package/src/lib/components/document-root.d.ts +77 -0
- package/src/lib/components/document-root.js +118 -0
- package/src/lib/components/document-root.js.map +1 -0
- package/src/lib/components/drawer.d.ts +93 -0
- package/src/lib/components/drawer.js +566 -0
- package/src/lib/components/drawer.js.map +1 -0
- package/src/lib/components/function-controls.d.ts +66 -0
- package/src/lib/components/function-controls.js +207 -0
- package/src/lib/components/function-controls.js.map +1 -0
- package/src/lib/components/function-scope.d.ts +110 -0
- package/src/lib/components/function-scope.js +478 -0
- package/src/lib/components/function-scope.js.map +1 -0
- package/src/lib/components/function-widget.d.ts +75 -0
- package/src/lib/components/function-widget.js +307 -0
- package/src/lib/components/function-widget.js.map +1 -0
- package/src/lib/components/grid.d.ts +91 -0
- package/src/lib/components/grid.js +322 -0
- package/src/lib/components/grid.js.map +1 -0
- package/src/lib/components/icon.d.ts +54 -0
- package/src/lib/components/icon.js +163 -0
- package/src/lib/components/icon.js.map +1 -0
- package/src/lib/components/image-list.d.ts +58 -0
- package/src/lib/components/image-list.js +336 -0
- package/src/lib/components/image-list.js.map +1 -0
- package/src/lib/components/image.d.ts +154 -0
- package/src/lib/components/image.js +451 -0
- package/src/lib/components/image.js.map +1 -0
- package/src/lib/components/inline-text.d.ts +74 -0
- package/src/lib/components/inline-text.js +407 -0
- package/src/lib/components/inline-text.js.map +1 -0
- package/src/lib/components/language-switcher.d.ts +35 -0
- package/src/lib/components/language-switcher.js +179 -0
- package/src/lib/components/language-switcher.js.map +1 -0
- package/src/lib/components/layout-slot.d.ts +68 -0
- package/src/lib/components/layout-slot.js +192 -0
- package/src/lib/components/layout-slot.js.map +1 -0
- package/src/lib/components/link-box-accessible-name.d.ts +79 -0
- package/src/lib/components/link-box-accessible-name.js +158 -0
- package/src/lib/components/link-box-accessible-name.js.map +1 -0
- package/src/lib/components/link-box.d.ts +66 -0
- package/src/lib/components/link-box.js +212 -0
- package/src/lib/components/link-box.js.map +1 -0
- package/src/lib/components/list-item-text.d.ts +22 -0
- package/src/lib/components/list-item-text.js +86 -0
- package/src/lib/components/list-item-text.js.map +1 -0
- package/src/lib/components/list-item.d.ts +32 -0
- package/src/lib/components/list-item.js +127 -0
- package/src/lib/components/list-item.js.map +1 -0
- package/src/lib/components/list.d.ts +34 -0
- package/src/lib/components/list.js +108 -0
- package/src/lib/components/list.js.map +1 -0
- package/src/lib/components/markdown.d.ts +129 -0
- package/src/lib/components/markdown.js +853 -0
- package/src/lib/components/markdown.js.map +1 -0
- package/src/lib/components/nav-menu.d.ts +68 -0
- package/src/lib/components/nav-menu.js +683 -0
- package/src/lib/components/nav-menu.js.map +1 -0
- package/src/lib/components/pagination.d.ts +59 -0
- package/src/lib/components/pagination.js +243 -0
- package/src/lib/components/pagination.js.map +1 -0
- package/src/lib/components/paper.d.ts +47 -0
- package/src/lib/components/paper.js +202 -0
- package/src/lib/components/paper.js.map +1 -0
- package/src/lib/components/plugin-frame.d.ts +64 -0
- package/src/lib/components/plugin-frame.js +335 -0
- package/src/lib/components/plugin-frame.js.map +1 -0
- package/src/lib/components/plugin.d.ts +95 -0
- package/src/lib/components/plugin.js +304 -0
- package/src/lib/components/plugin.js.map +1 -0
- package/src/lib/components/product.d.ts +40 -0
- package/src/lib/components/product.js +287 -0
- package/src/lib/components/product.js.map +1 -0
- package/src/lib/components/reusable-instance.d.ts +57 -0
- package/src/lib/components/reusable-instance.js +126 -0
- package/src/lib/components/reusable-instance.js.map +1 -0
- package/src/lib/components/screen-link.d.ts +85 -0
- package/src/lib/components/screen-link.js +324 -0
- package/src/lib/components/screen-link.js.map +1 -0
- package/src/lib/components/search-box.d.ts +41 -0
- package/src/lib/components/search-box.js +125 -0
- package/src/lib/components/search-box.js.map +1 -0
- package/src/lib/components/section.d.ts +56 -0
- package/src/lib/components/section.js +132 -0
- package/src/lib/components/section.js.map +1 -0
- package/src/lib/components/stack.d.ts +55 -0
- package/src/lib/components/stack.js +309 -0
- package/src/lib/components/stack.js.map +1 -0
- package/src/lib/components/tabs.d.ts +288 -0
- package/src/lib/components/tabs.js +788 -0
- package/src/lib/components/tabs.js.map +1 -0
- package/src/lib/components/theme-mode-switcher.d.ts +38 -0
- package/src/lib/components/theme-mode-switcher.js +168 -0
- package/src/lib/components/theme-mode-switcher.js.map +1 -0
- package/src/lib/components/toolbar.d.ts +37 -0
- package/src/lib/components/toolbar.js +117 -0
- package/src/lib/components/toolbar.js.map +1 -0
- package/src/lib/components/typography.d.ts +33 -0
- package/src/lib/components/typography.js +433 -0
- package/src/lib/components/typography.js.map +1 -0
- package/src/lib/components/video-lightbox-controls.d.ts +131 -0
- package/src/lib/components/video-lightbox-controls.js +536 -0
- package/src/lib/components/video-lightbox-controls.js.map +1 -0
- package/src/lib/components/video-lightbox.d.ts +60 -0
- package/src/lib/components/video-lightbox.js +247 -0
- package/src/lib/components/video-lightbox.js.map +1 -0
- package/src/lib/components/video-playback-beacon.d.ts +80 -0
- package/src/lib/components/video-playback-beacon.js +128 -0
- package/src/lib/components/video-playback-beacon.js.map +1 -0
- package/src/lib/components/video-player-frame.d.ts +58 -0
- package/src/lib/components/video-player-frame.js +51 -0
- package/src/lib/components/video-player-frame.js.map +1 -0
- package/src/lib/components/video.d.ts +220 -0
- package/src/lib/components/video.js +874 -0
- package/src/lib/components/video.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +17 -0
- package/src/lib/constants/bundle-common.js +18 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/constants/field-presets.d.ts +93 -0
- package/src/lib/constants/field-presets.js +248 -0
- package/src/lib/constants/field-presets.js.map +1 -0
- package/src/lib/plugin.d.ts +80 -0
- package/src/lib/plugin.js +599 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/utils/author-html-label.d.ts +73 -0
- package/src/lib/utils/author-html-label.js +89 -0
- package/src/lib/utils/author-html-label.js.map +1 -0
- package/src/lib/utils/drop-cleared-props.d.ts +18 -0
- package/src/lib/utils/drop-cleared-props.js +74 -0
- package/src/lib/utils/drop-cleared-props.js.map +1 -0
- package/src/lib/utils/element-picker.d.ts +99 -0
- package/src/lib/utils/element-picker.js +140 -0
- package/src/lib/utils/element-picker.js.map +1 -0
- package/src/lib/utils/generate-preset-id.d.ts +19 -0
- package/src/lib/utils/generate-preset-id.js +25 -0
- package/src/lib/utils/generate-preset-id.js.map +1 -0
- package/src/lib/utils/link-target-props.d.ts +53 -0
- package/src/lib/utils/link-target-props.js +53 -0
- package/src/lib/utils/link-target-props.js.map +1 -0
|
@@ -0,0 +1,336 @@
|
|
|
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 { mdiImageMultiple, mdiImageMultipleOutline } from "@aglyn/shared-data-mdi";
|
|
21
|
+
import MuiImageList from "@mui/material/ImageList";
|
|
22
|
+
import MuiImageListItem from "@mui/material/ImageListItem";
|
|
23
|
+
import MuiImageListItemBar from "@mui/material/ImageListItemBar";
|
|
24
|
+
import { forwardRef } from "react";
|
|
25
|
+
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
26
|
+
import { dropClearedProps } from "../utils/drop-cleared-props.js";
|
|
27
|
+
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
28
|
+
// Component ids are persisted in screen documents; never rename.
|
|
29
|
+
export const IMAGE_LIST_ID = 'muiImageList';
|
|
30
|
+
export const IMAGE_LIST_ITEM_ID = 'muiImageListItem';
|
|
31
|
+
/** Number fields round-trip as strings; MUI's grid math needs numbers. */ export function toCount(value, fallback) {
|
|
32
|
+
if (value == null || value === '') return fallback;
|
|
33
|
+
const parsed = Number(value);
|
|
34
|
+
if (!Number.isFinite(parsed) || parsed < 0) return fallback;
|
|
35
|
+
return Math.round(parsed);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Image list (https://mui.com/material-ui/react-image-list/): a masonry
|
|
39
|
+
* or quilted grid of images, denser than a Grid of cards.
|
|
40
|
+
*/ const ImageListElement = /*#__PURE__*/ forwardRef((rawProps, ref)=>{
|
|
41
|
+
// Cleared props dropped before the resolvers below read them
|
|
42
|
+
// (AGL-1451); `rest` also spreads straight into MUI.
|
|
43
|
+
const props = dropClearedProps(rawProps);
|
|
44
|
+
const { cols, gap, rowHeight, variant, children } = props, rest = _object_without_properties_loose(props, [
|
|
45
|
+
"cols",
|
|
46
|
+
"gap",
|
|
47
|
+
"rowHeight",
|
|
48
|
+
"variant",
|
|
49
|
+
"children"
|
|
50
|
+
]);
|
|
51
|
+
const resolvedVariant = [
|
|
52
|
+
'standard',
|
|
53
|
+
'quilted',
|
|
54
|
+
'masonry',
|
|
55
|
+
'woven'
|
|
56
|
+
].includes(variant) ? variant : 'standard';
|
|
57
|
+
const height = toCount(rowHeight);
|
|
58
|
+
return /*#__PURE__*/ _jsx(MuiImageList, _extends({
|
|
59
|
+
ref: ref,
|
|
60
|
+
variant: resolvedVariant,
|
|
61
|
+
cols: toCount(cols, 3),
|
|
62
|
+
gap: toCount(gap, 4),
|
|
63
|
+
// A masonry list sizes rows from the images themselves; a fixed
|
|
64
|
+
// rowHeight silently defeats the whole variant.
|
|
65
|
+
rowHeight: resolvedVariant === 'masonry' ? 'auto' : height != null ? height : 'auto'
|
|
66
|
+
}, rest, {
|
|
67
|
+
// MUI types ImageList's children as NonNullable; the renderer
|
|
68
|
+
// always supplies the tile subtree.
|
|
69
|
+
children: children
|
|
70
|
+
}));
|
|
71
|
+
});
|
|
72
|
+
ImageListElement.displayName = 'AglynImageList';
|
|
73
|
+
/**
|
|
74
|
+
* One tile. The image itself is an ordinary Image element dropped
|
|
75
|
+
* inside, so tiles keep the media-CDN srcSet, lazy loading and
|
|
76
|
+
* empty-source placeholder (AGL-74/175) rather than a second, worse
|
|
77
|
+
* image implementation living here.
|
|
78
|
+
*/ export const ImageListItemElement = /*#__PURE__*/ forwardRef((rawProps, ref)=>{
|
|
79
|
+
const props = dropClearedProps(rawProps);
|
|
80
|
+
const { cols, rows, title, subtitle, barPosition, children } = props, rest = _object_without_properties_loose(props, [
|
|
81
|
+
"cols",
|
|
82
|
+
"rows",
|
|
83
|
+
"title",
|
|
84
|
+
"subtitle",
|
|
85
|
+
"barPosition",
|
|
86
|
+
"children"
|
|
87
|
+
]);
|
|
88
|
+
return /*#__PURE__*/ _jsxs(MuiImageListItem, _extends({
|
|
89
|
+
ref: ref,
|
|
90
|
+
cols: toCount(cols, 1),
|
|
91
|
+
rows: toCount(rows, 1)
|
|
92
|
+
}, rest, {
|
|
93
|
+
children: [
|
|
94
|
+
children,
|
|
95
|
+
title || subtitle ? /*#__PURE__*/ _jsx(MuiImageListItemBar, {
|
|
96
|
+
title: title || undefined,
|
|
97
|
+
subtitle: subtitle || undefined,
|
|
98
|
+
position: barPosition || 'bottom'
|
|
99
|
+
}) : null
|
|
100
|
+
]
|
|
101
|
+
}));
|
|
102
|
+
});
|
|
103
|
+
ImageListItemElement.displayName = 'AglynImageListItem';
|
|
104
|
+
/** Row height is meaningless on masonry — MUI forces `auto` there. */ const NOT_MASONRY = {
|
|
105
|
+
when: 'variant',
|
|
106
|
+
is: 'masonry',
|
|
107
|
+
notMatch: true
|
|
108
|
+
};
|
|
109
|
+
export const imageListSchema = {
|
|
110
|
+
$id: IMAGE_LIST_ID,
|
|
111
|
+
pluginId: BUNDLE_ID,
|
|
112
|
+
displayName: 'Image List',
|
|
113
|
+
description: 'Dense grid of images — standard, quilted, masonry or woven.',
|
|
114
|
+
category: Aglyn.ComponentCategory.MEDIA,
|
|
115
|
+
icon: {
|
|
116
|
+
path: mdiImageMultiple.path,
|
|
117
|
+
sx: {
|
|
118
|
+
color: '#7b1fa2'
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
restrictChildren: [
|
|
122
|
+
Aglyn.LinealDirectiveFlag.LIMIT_TO,
|
|
123
|
+
{
|
|
124
|
+
components: [
|
|
125
|
+
IMAGE_LIST_ITEM_ID
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
attributes: [
|
|
130
|
+
{
|
|
131
|
+
name: 'variant',
|
|
132
|
+
label: 'Variant',
|
|
133
|
+
description: 'Standard is a plain grid; quilted lets tiles span columns and ' + 'rows; masonry keeps each image’s own aspect ratio; woven ' + 'alternates tile sizes.',
|
|
134
|
+
component: Aglyn.FieldComponentType.SELECT,
|
|
135
|
+
// A real sentinel, not a deletion (AGL-1451): `standard` is one of
|
|
136
|
+
// MUI's four named variants and the resolver above already accepts
|
|
137
|
+
// it by name, so the option is a genuine choice — and the one an
|
|
138
|
+
// author needs in order to move a list BACK off quilted or masonry.
|
|
139
|
+
// Spelled `''` it could not persist (AGL-1191), so that move
|
|
140
|
+
// silently reverted.
|
|
141
|
+
options: [
|
|
142
|
+
{
|
|
143
|
+
value: 'standard',
|
|
144
|
+
label: 'Standard (default)'
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
value: 'quilted',
|
|
148
|
+
label: 'Quilted'
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
value: 'masonry',
|
|
152
|
+
label: 'Masonry'
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
value: 'woven',
|
|
156
|
+
label: 'Woven'
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: 'cols',
|
|
162
|
+
label: 'Columns',
|
|
163
|
+
description: 'Number of columns. Default 3.',
|
|
164
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
165
|
+
type: 'number'
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'gap',
|
|
169
|
+
label: 'Gap',
|
|
170
|
+
description: 'Space between tiles, in px. Default 4.',
|
|
171
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
172
|
+
type: 'number'
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: 'rowHeight',
|
|
176
|
+
label: 'Row height',
|
|
177
|
+
description: 'Row height in px. Leave blank to size rows from the images.',
|
|
178
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
179
|
+
type: 'number',
|
|
180
|
+
condition: NOT_MASONRY
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
};
|
|
184
|
+
export const imageListItemSchema = {
|
|
185
|
+
$id: IMAGE_LIST_ITEM_ID,
|
|
186
|
+
pluginId: BUNDLE_ID,
|
|
187
|
+
displayName: 'Image List Item',
|
|
188
|
+
description: 'One tile of an image list, with an optional caption bar.',
|
|
189
|
+
category: Aglyn.ComponentCategory.MEDIA,
|
|
190
|
+
icon: {
|
|
191
|
+
path: mdiImageMultipleOutline.path,
|
|
192
|
+
sx: {
|
|
193
|
+
color: '#7b1fa2'
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
attributes: [
|
|
197
|
+
{
|
|
198
|
+
name: 'title',
|
|
199
|
+
label: 'Caption',
|
|
200
|
+
description: 'Caption bar text. Leave both caption fields blank for no bar.',
|
|
201
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'subtitle',
|
|
205
|
+
label: 'Caption subtitle',
|
|
206
|
+
description: 'Second line of the caption bar.',
|
|
207
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
name: 'barPosition',
|
|
211
|
+
label: 'Caption position',
|
|
212
|
+
description: 'Where the caption bar sits relative to the image.',
|
|
213
|
+
component: Aglyn.FieldComponentType.SELECT,
|
|
214
|
+
// `bottom` is MUI's own position value and the `|| 'bottom'`
|
|
215
|
+
// fallback below already resolves to it, so the sentinel is the
|
|
216
|
+
// value the code was reaching for anyway (AGL-1451).
|
|
217
|
+
options: [
|
|
218
|
+
{
|
|
219
|
+
value: 'bottom',
|
|
220
|
+
label: 'Bottom (default)'
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
value: 'top',
|
|
224
|
+
label: 'Top'
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
value: 'below',
|
|
228
|
+
label: 'Below the image'
|
|
229
|
+
}
|
|
230
|
+
]
|
|
231
|
+
},
|
|
232
|
+
// The spans are read only by the quilted layout, but the variant
|
|
233
|
+
// that decides that lives on the PARENT list. A `condition` is
|
|
234
|
+
// evaluated against this node's own attribute form and cannot see
|
|
235
|
+
// it, so these stay visible and say so in their help text — a
|
|
236
|
+
// condition here would hide them permanently.
|
|
237
|
+
{
|
|
238
|
+
name: 'cols',
|
|
239
|
+
label: 'Column span',
|
|
240
|
+
description: 'How many columns this tile spans. Only the parent list’s ' + 'Quilted variant reads this.',
|
|
241
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
242
|
+
type: 'number'
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
name: 'rows',
|
|
246
|
+
label: 'Row span',
|
|
247
|
+
description: 'How many rows this tile spans. Only the parent list’s Quilted ' + 'variant reads this.',
|
|
248
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
249
|
+
type: 'number'
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
};
|
|
253
|
+
const tile = (caption)=>({
|
|
254
|
+
$id: null,
|
|
255
|
+
componentId: IMAGE_LIST_ITEM_ID,
|
|
256
|
+
pluginId: BUNDLE_ID,
|
|
257
|
+
props: {
|
|
258
|
+
title: caption
|
|
259
|
+
},
|
|
260
|
+
nodes: [
|
|
261
|
+
{
|
|
262
|
+
$id: null,
|
|
263
|
+
componentId: 'image',
|
|
264
|
+
pluginId: BUNDLE_ID,
|
|
265
|
+
props: {
|
|
266
|
+
alt: caption,
|
|
267
|
+
height: '160px',
|
|
268
|
+
objectFit: 'cover'
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
});
|
|
273
|
+
export const imageListPresets = [
|
|
274
|
+
{
|
|
275
|
+
$id: generatePresetId(IMAGE_LIST_ID),
|
|
276
|
+
type: Aglyn.NodeType.PRESET,
|
|
277
|
+
displayName: 'Image List',
|
|
278
|
+
pluginId: BUNDLE_ID,
|
|
279
|
+
description: 'Three-column gallery with captioned tiles',
|
|
280
|
+
category: Aglyn.ComponentCategory.MEDIA,
|
|
281
|
+
icon: imageListSchema.icon,
|
|
282
|
+
data: {
|
|
283
|
+
$id: null,
|
|
284
|
+
componentId: IMAGE_LIST_ID,
|
|
285
|
+
pluginId: BUNDLE_ID,
|
|
286
|
+
props: {
|
|
287
|
+
cols: 3,
|
|
288
|
+
gap: 8,
|
|
289
|
+
rowHeight: 160
|
|
290
|
+
},
|
|
291
|
+
nodes: [
|
|
292
|
+
tile('First image'),
|
|
293
|
+
tile('Second image'),
|
|
294
|
+
tile('Third image')
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
$id: generatePresetId(IMAGE_LIST_ID, 'masonry'),
|
|
300
|
+
type: Aglyn.NodeType.PRESET,
|
|
301
|
+
displayName: 'Image List Masonry',
|
|
302
|
+
pluginId: BUNDLE_ID,
|
|
303
|
+
description: 'Gallery that keeps each image’s own aspect ratio',
|
|
304
|
+
category: Aglyn.ComponentCategory.MEDIA,
|
|
305
|
+
icon: imageListSchema.icon,
|
|
306
|
+
data: {
|
|
307
|
+
$id: null,
|
|
308
|
+
componentId: IMAGE_LIST_ID,
|
|
309
|
+
pluginId: BUNDLE_ID,
|
|
310
|
+
props: {
|
|
311
|
+
variant: 'masonry',
|
|
312
|
+
cols: 3,
|
|
313
|
+
gap: 8
|
|
314
|
+
},
|
|
315
|
+
nodes: [
|
|
316
|
+
tile(''),
|
|
317
|
+
tile(''),
|
|
318
|
+
tile(''),
|
|
319
|
+
tile('')
|
|
320
|
+
]
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
$id: generatePresetId(IMAGE_LIST_ITEM_ID),
|
|
325
|
+
type: Aglyn.NodeType.PRESET,
|
|
326
|
+
displayName: 'Image List Item',
|
|
327
|
+
pluginId: BUNDLE_ID,
|
|
328
|
+
description: 'One more tile to add to an existing image list',
|
|
329
|
+
category: Aglyn.ComponentCategory.MEDIA,
|
|
330
|
+
icon: imageListItemSchema.icon,
|
|
331
|
+
data: tile('')
|
|
332
|
+
}
|
|
333
|
+
];
|
|
334
|
+
export default ImageListElement;
|
|
335
|
+
|
|
336
|
+
//# sourceMappingURL=image-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/image-list.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 { mdiImageMultiple, mdiImageMultipleOutline } from '@aglyn/shared-data-mdi'\nimport MuiImageList from '@mui/material/ImageList'\nimport MuiImageListItem from '@mui/material/ImageListItem'\nimport MuiImageListItemBar from '@mui/material/ImageListItemBar'\nimport { forwardRef, type ReactNode } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const IMAGE_LIST_ID: Aglyn.ComponentId = 'muiImageList'\nexport const IMAGE_LIST_ITEM_ID: Aglyn.ComponentId = 'muiImageListItem'\n\nexport type ImageListVariant = 'standard' | 'quilted' | 'masonry' | 'woven'\n\nexport interface ImageListElementProps {\n cols?: number | string\n gap?: number | string\n /** Row height in px, or blank for `auto`. */\n rowHeight?: number | string\n variant?: ImageListVariant\n children?: ReactNode\n}\n\nexport interface ImageListItemElementProps {\n /** Columns this tile spans (quilted lists). */\n cols?: number | string\n /** Rows this tile spans (quilted lists). */\n rows?: number | string\n /** Caption bar text; the bar is omitted entirely when both are blank. */\n title?: string\n subtitle?: string\n barPosition?: 'below' | 'top' | 'bottom'\n children?: ReactNode\n}\n\n/** Number fields round-trip as strings; MUI's grid math needs numbers. */\nexport function toCount(value: unknown, fallback?: number): number | undefined {\n if (value == null || value === '') return fallback\n const parsed = Number(value)\n if (!Number.isFinite(parsed) || parsed < 0) return fallback\n return Math.round(parsed)\n}\n\n/**\n * Image list (https://mui.com/material-ui/react-image-list/): a masonry\n * or quilted grid of images, denser than a Grid of cards.\n */\nconst ImageListElement = forwardRef<HTMLUListElement, ImageListElementProps>(\n (rawProps, ref) => {\n // Cleared props dropped before the resolvers below read them\n // (AGL-1451); `rest` also spreads straight into MUI.\n const props = dropClearedProps(rawProps)\n const { cols, gap, rowHeight, variant, children, ...rest } = props\n const resolvedVariant: ImageListVariant = (\n ['standard', 'quilted', 'masonry', 'woven'] as const\n ).includes(variant as ImageListVariant)\n ? (variant as ImageListVariant)\n : 'standard'\n const height = toCount(rowHeight)\n return (\n <MuiImageList\n ref={ref}\n variant={resolvedVariant}\n cols={toCount(cols, 3)}\n gap={toCount(gap, 4)}\n // A masonry list sizes rows from the images themselves; a fixed\n // rowHeight silently defeats the whole variant.\n rowHeight={resolvedVariant === 'masonry' ? 'auto' : height ?? 'auto'}\n {...rest}\n // MUI types ImageList's children as NonNullable; the renderer\n // always supplies the tile subtree.\n children={children as NonNullable<ReactNode>}\n />\n )\n },\n)\nImageListElement.displayName = 'AglynImageList'\n\n/**\n * One tile. The image itself is an ordinary Image element dropped\n * inside, so tiles keep the media-CDN srcSet, lazy loading and\n * empty-source placeholder (AGL-74/175) rather than a second, worse\n * image implementation living here.\n */\nexport const ImageListItemElement = forwardRef<\n HTMLLIElement,\n ImageListItemElementProps\n>((rawProps, ref) => {\n const props = dropClearedProps(rawProps)\n const { cols, rows, title, subtitle, barPosition, children, ...rest } = props\n return (\n <MuiImageListItem\n ref={ref}\n cols={toCount(cols, 1)}\n rows={toCount(rows, 1)}\n {...rest}\n >\n {children}\n {title || subtitle ? (\n <MuiImageListItemBar\n title={title || undefined}\n subtitle={subtitle || undefined}\n position={barPosition || 'bottom'}\n />\n ) : null}\n </MuiImageListItem>\n )\n})\nImageListItemElement.displayName = 'AglynImageListItem'\n\n/** Row height is meaningless on masonry — MUI forces `auto` there. */\nconst NOT_MASONRY = { when: 'variant', is: 'masonry', notMatch: true }\n\nexport const imageListSchema: Aglyn.ComponentSchema<ImageListElementProps> = {\n $id: IMAGE_LIST_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Image List',\n description: 'Dense grid of images — standard, quilted, masonry or woven.',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: { path: mdiImageMultiple.path, sx: { color: '#7b1fa2' } },\n restrictChildren: [\n Aglyn.LinealDirectiveFlag.LIMIT_TO,\n { components: [IMAGE_LIST_ITEM_ID] },\n ],\n attributes: [\n {\n name: 'variant',\n label: 'Variant',\n description:\n 'Standard is a plain grid; quilted lets tiles span columns and ' +\n 'rows; masonry keeps each image’s own aspect ratio; woven ' +\n 'alternates tile sizes.',\n component: Aglyn.FieldComponentType.SELECT,\n // A real sentinel, not a deletion (AGL-1451): `standard` is one of\n // MUI's four named variants and the resolver above already accepts\n // it by name, so the option is a genuine choice — and the one an\n // author needs in order to move a list BACK off quilted or masonry.\n // Spelled `''` it could not persist (AGL-1191), so that move\n // silently reverted.\n options: [\n { value: 'standard', label: 'Standard (default)' },\n { value: 'quilted', label: 'Quilted' },\n { value: 'masonry', label: 'Masonry' },\n { value: 'woven', label: 'Woven' },\n ],\n },\n {\n name: 'cols',\n label: 'Columns',\n description: 'Number of columns. Default 3.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n },\n {\n name: 'gap',\n label: 'Gap',\n description: 'Space between tiles, in px. Default 4.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n },\n {\n name: 'rowHeight',\n label: 'Row height',\n description:\n 'Row height in px. Leave blank to size rows from the images.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: NOT_MASONRY,\n },\n ],\n}\n\nexport const imageListItemSchema: Aglyn.ComponentSchema<ImageListItemElementProps> =\n {\n $id: IMAGE_LIST_ITEM_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Image List Item',\n description: 'One tile of an image list, with an optional caption bar.',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: { path: mdiImageMultipleOutline.path, sx: { color: '#7b1fa2' } },\n attributes: [\n {\n name: 'title',\n label: 'Caption',\n description:\n 'Caption bar text. Leave both caption fields blank for no bar.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'subtitle',\n label: 'Caption subtitle',\n description: 'Second line of the caption bar.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'barPosition',\n label: 'Caption position',\n description: 'Where the caption bar sits relative to the image.',\n component: Aglyn.FieldComponentType.SELECT,\n // `bottom` is MUI's own position value and the `|| 'bottom'`\n // fallback below already resolves to it, so the sentinel is the\n // value the code was reaching for anyway (AGL-1451).\n options: [\n { value: 'bottom', label: 'Bottom (default)' },\n { value: 'top', label: 'Top' },\n { value: 'below', label: 'Below the image' },\n ],\n },\n // The spans are read only by the quilted layout, but the variant\n // that decides that lives on the PARENT list. A `condition` is\n // evaluated against this node's own attribute form and cannot see\n // it, so these stay visible and say so in their help text — a\n // condition here would hide them permanently.\n {\n name: 'cols',\n label: 'Column span',\n description:\n 'How many columns this tile spans. Only the parent list’s ' +\n 'Quilted variant reads this.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n },\n {\n name: 'rows',\n label: 'Row span',\n description:\n 'How many rows this tile spans. Only the parent list’s Quilted ' +\n 'variant reads this.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n },\n ],\n }\n\nconst tile = (caption: string) => ({\n $id: null,\n componentId: IMAGE_LIST_ITEM_ID,\n pluginId: BUNDLE_ID,\n props: { title: caption },\n nodes: [\n {\n $id: null,\n componentId: 'image',\n pluginId: BUNDLE_ID,\n props: { alt: caption, height: '160px', objectFit: 'cover' },\n },\n ],\n})\n\nexport const imageListPresets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(IMAGE_LIST_ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Image List',\n pluginId: BUNDLE_ID,\n description: 'Three-column gallery with captioned tiles',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: imageListSchema.icon,\n data: {\n $id: null,\n componentId: IMAGE_LIST_ID,\n pluginId: BUNDLE_ID,\n props: { cols: 3, gap: 8, rowHeight: 160 },\n nodes: [tile('First image'), tile('Second image'), tile('Third image')],\n },\n },\n {\n $id: generatePresetId(IMAGE_LIST_ID, 'masonry'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Image List Masonry',\n pluginId: BUNDLE_ID,\n description: 'Gallery that keeps each image’s own aspect ratio',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: imageListSchema.icon,\n data: {\n $id: null,\n componentId: IMAGE_LIST_ID,\n pluginId: BUNDLE_ID,\n props: { variant: 'masonry', cols: 3, gap: 8 },\n nodes: [tile(''), tile(''), tile(''), tile('')],\n },\n },\n {\n $id: generatePresetId(IMAGE_LIST_ITEM_ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Image List Item',\n pluginId: BUNDLE_ID,\n description: 'One more tile to add to an existing image list',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: imageListItemSchema.icon,\n data: tile(''),\n },\n]\n\nexport default ImageListElement\n"],"names":["Aglyn","mdiImageMultiple","mdiImageMultipleOutline","MuiImageList","MuiImageListItem","MuiImageListItemBar","forwardRef","BUNDLE_ID","dropClearedProps","generatePresetId","IMAGE_LIST_ID","IMAGE_LIST_ITEM_ID","toCount","value","fallback","parsed","Number","isFinite","Math","round","ImageListElement","rawProps","ref","props","cols","gap","rowHeight","variant","children","rest","resolvedVariant","includes","height","displayName","ImageListItemElement","rows","title","subtitle","barPosition","undefined","position","NOT_MASONRY","when","is","notMatch","imageListSchema","$id","pluginId","description","category","ComponentCategory","MEDIA","icon","path","sx","color","restrictChildren","LinealDirectiveFlag","LIMIT_TO","components","attributes","name","label","component","FieldComponentType","SELECT","options","TEXT_FIELD","type","condition","imageListItemSchema","tile","caption","componentId","nodes","alt","objectFit","imageListPresets","NodeType","PRESET","data"],"mappings":"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"}
|
|
@@ -0,0 +1,154 @@
|
|
|
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
|
+
/**
|
|
22
|
+
* The node ids of the images that load eagerly: the first image the LAYOUT
|
|
23
|
+
* chain renders and the first image the SCREEN renders, each in document
|
|
24
|
+
* order (AGL-2486).
|
|
25
|
+
*
|
|
26
|
+
* Every image used to render `loading="lazy"` — the hero included. That is
|
|
27
|
+
* the worst possible default for the one image that is almost always the LCP
|
|
28
|
+
* element: a lazy image is not fetched until layout has run and the browser
|
|
29
|
+
* has decided it is near the viewport, and it is fetched at LOW priority when
|
|
30
|
+
* it finally is. Lighthouse reports that as "LCP request discovery", and it is
|
|
31
|
+
* also why an image four sections down could finish before the one the reader
|
|
32
|
+
* is looking at: with everything lazy and everything low, nothing outranked
|
|
33
|
+
* anything, so the order was whatever the network felt like.
|
|
34
|
+
*
|
|
35
|
+
* So the lead images get `loading="eager"` and the rest get
|
|
36
|
+
* `fetchpriority="low"`, which is the browser-level knob that stops
|
|
37
|
+
* below-the-fold images competing with the ones above them.
|
|
38
|
+
*
|
|
39
|
+
* ONE lead image was not enough. On any site whose header carries a logo, the
|
|
40
|
+
* first image in document order is that logo, so the screen's own hero — the
|
|
41
|
+
* element Lighthouse names as the LCP on aglyn.com's solution pages at
|
|
42
|
+
* 375x812 — stayed `lazy` + `low`: undiscovered until layout, then fetched
|
|
43
|
+
* behind every script on the page (measured 2026-09-08: 1.5 s of load delay
|
|
44
|
+
* and 1.5 s of load time for a 13 KB image). Composition namespaces layout
|
|
45
|
+
* nodes by origin ({@link Aglyn.isLayoutComposedNodeId}), so the walk keeps
|
|
46
|
+
* one lead PER ORIGIN: the layout's first image (the logo) and the screen's
|
|
47
|
+
* first image (the hero). A layout image further down — a mega-menu
|
|
48
|
+
* illustration, the footer mark — is still deferred, as is every later
|
|
49
|
+
* screen image. In the besigner canvas nothing is layout-composed, so the
|
|
50
|
+
* screen's first image is the only lead, exactly as before.
|
|
51
|
+
*
|
|
52
|
+
* Neither lead gets `fetchpriority="high"`, and the reasoning is at the
|
|
53
|
+
* `fetchPriority` prop below. Short version: "first image of its origin" is
|
|
54
|
+
* still not "the LCP element", and a ranking claim needs evidence this
|
|
55
|
+
* function does not have.
|
|
56
|
+
*
|
|
57
|
+
* Resolved from the tree rather than a render-order counter on purpose: the
|
|
58
|
+
* renderer walks the tree in document order on the server AND on hydrate, but
|
|
59
|
+
* a mutable counter would double-count under React's concurrent re-renders
|
|
60
|
+
* and hand the priority to a different image on the client than the one the
|
|
61
|
+
* HTML gave it. A pure function of the tree cannot disagree with itself — and
|
|
62
|
+
* it is deliberately NOT memoized on the root object, because the canvas
|
|
63
|
+
* mutates that tree in place while an author works.
|
|
64
|
+
*
|
|
65
|
+
* The walk STOPS once both leads are known — on a page with a header logo
|
|
66
|
+
* and a hero that is O(nodes above the hero), a dozen or two on a normal
|
|
67
|
+
* page — and at the first image on a screen with no layout.
|
|
68
|
+
*
|
|
69
|
+
* An image with no `src` renders a placeholder box and no `<img>` at all, so
|
|
70
|
+
* it cannot be the LCP element and is skipped.
|
|
71
|
+
*/
|
|
72
|
+
export declare function leadImageNodeIds(root: Aglyn.NodeSchema | undefined): readonly string[];
|
|
73
|
+
export interface ImageProps {
|
|
74
|
+
/**
|
|
75
|
+
* Where the image comes from (AGL-72). Either a **media reference** —
|
|
76
|
+
* `media:{scope}/{mediaId}`, what "Browse media" now stores (AGL-1215) —
|
|
77
|
+
* or any URL, which covers both the legacy values already in published
|
|
78
|
+
* documents and an author-typed hotlink. `resolveMediaSrc` decides.
|
|
79
|
+
*/
|
|
80
|
+
src?: string;
|
|
81
|
+
alt?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Explicit decorative choice (AGL-1305): ON forces `alt=""` (and drops
|
|
84
|
+
* the tooltip) no matter what the alt field says, so screen readers skip
|
|
85
|
+
* the image. Distinct from simply leaving alt unset, which also renders
|
|
86
|
+
* `alt=""` today but records no intent.
|
|
87
|
+
*/
|
|
88
|
+
decorative?: boolean;
|
|
89
|
+
/** Tooltip shown on hover — the native img `title` attribute. */
|
|
90
|
+
title?: string;
|
|
91
|
+
/** Native loading hint; unset stays lazy, exactly as before AGL-1305. */
|
|
92
|
+
loading?: 'lazy' | 'eager';
|
|
93
|
+
objectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down';
|
|
94
|
+
/** CSS width (e.g. "100%", "320px"); defaults to 100%. */
|
|
95
|
+
width?: string;
|
|
96
|
+
/** CSS height (e.g. "240px"); defaults to auto. */
|
|
97
|
+
height?: string;
|
|
98
|
+
/**
|
|
99
|
+
* The asset's own pixel dimensions, copied off the media document when the
|
|
100
|
+
* image was picked (AGL-2486), and read from the asset again when the page
|
|
101
|
+
* is composed, so a replace with a different shape reaches every page that
|
|
102
|
+
* places it (AGL-2833).
|
|
103
|
+
*
|
|
104
|
+
* NOT author controls, which is why neither appears in the schema below:
|
|
105
|
+
* they describe the file, and the CSS `width`/`height` above describe the
|
|
106
|
+
* placement. The pair becomes the `<img>`'s intrinsic `width`/`height`
|
|
107
|
+
* attributes, which is the only thing that lets the browser reserve the
|
|
108
|
+
* right box before the bytes arrive — with `width: 100%; height: auto` the
|
|
109
|
+
* element is otherwise zero-height until the image decodes, and every image
|
|
110
|
+
* on the page shifts the layout as it lands.
|
|
111
|
+
*
|
|
112
|
+
* An attribute pair is a RATIO here, not a size: CSS wins for the used
|
|
113
|
+
* dimensions either way, so a stale value costs nothing but a reservation
|
|
114
|
+
* of the wrong shape. Both must be present and positive or neither is
|
|
115
|
+
* emitted — one alone gives the browser no ratio and would be read as a
|
|
116
|
+
* real dimension.
|
|
117
|
+
*
|
|
118
|
+
* Read from the node like any other prop, so this element never fetches a
|
|
119
|
+
* media document: the composition has already laid the asset's current
|
|
120
|
+
* pair over the pick's (`media-asset-facts.ts`), and the pick's copy is
|
|
121
|
+
* what renders wherever that read cannot answer. `srcSet` still selects
|
|
122
|
+
* which variant is downloaded; these only say what shape it will be.
|
|
123
|
+
*/
|
|
124
|
+
intrinsicWidth?: number;
|
|
125
|
+
/** See `intrinsicWidth` — the two are only ever used as a pair. */
|
|
126
|
+
intrinsicHeight?: number;
|
|
127
|
+
/** Border radius in px. */
|
|
128
|
+
radius?: number;
|
|
129
|
+
/** Target screen id — resolved rename-safe like Screen Link (AGL-339). */
|
|
130
|
+
screenId?: string;
|
|
131
|
+
/** External URL, used only when no `screenId` is set. */
|
|
132
|
+
href?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Authored node styles, handed over by the renderer rather than typed into
|
|
135
|
+
* an attribute — recomposed below so the author's Styles-panel values are
|
|
136
|
+
* merged rather than replaced (AGL-1240).
|
|
137
|
+
*/
|
|
138
|
+
sx?: SxProps;
|
|
139
|
+
/**
|
|
140
|
+
* Accepted and dropped: an `<img>` is a void element and React throws on
|
|
141
|
+
* ANY children value reaching one, which 500'd whole pages (AGL-579).
|
|
142
|
+
* Declared because the implementation deliberately discards it (AGL-1323).
|
|
143
|
+
*/
|
|
144
|
+
children?: ReactNode;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Image element (AGL-74): renders a plain img with fit/size/radius
|
|
148
|
+
* controls; an empty src shows a labeled placeholder so the element stays
|
|
149
|
+
* visible and selectable in the editor.
|
|
150
|
+
*/
|
|
151
|
+
declare const Image: import("react").ForwardRefExoticComponent<ImageProps & import("react").RefAttributes<HTMLElement>>;
|
|
152
|
+
export declare const schema: Aglyn.ComponentSchema<ImageProps>;
|
|
153
|
+
export declare const presets: Aglyn.PresetSchema[];
|
|
154
|
+
export default Image;
|