@aglyn/plugins-mui 1.0.0-beta.236 → 1.0.0-beta.238
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/package.json +7 -7
- package/src/lib/components/image-lightbox-items.d.ts +53 -0
- package/src/lib/components/image-lightbox-items.js +113 -0
- package/src/lib/components/image-lightbox-items.js.map +1 -0
- package/src/lib/components/image-lightbox.d.ts +35 -0
- package/src/lib/components/image-lightbox.js +303 -0
- package/src/lib/components/image-lightbox.js.map +1 -0
- package/src/lib/components/image-list.d.ts +9 -1
- package/src/lib/components/image-list.js +83 -10
- package/src/lib/components/image-list.js.map +1 -1
- package/src/lib/components/image.d.ts +17 -1
- package/src/lib/components/image.js +129 -7
- package/src/lib/components/image.js.map +1 -1
- package/src/lib/components/video-lightbox.d.ts +6 -0
- package/src/lib/components/video-lightbox.js +56 -77
- package/src/lib/components/video-lightbox.js.map +1 -1
- package/src/lib/components/video.d.ts +2 -1
- package/src/lib/components/video.js +9 -2
- package/src/lib/components/video.js.map +1 -1
- package/src/lib/utils/lightbox-attributes.d.ts +33 -0
- package/src/lib/utils/lightbox-attributes.js +56 -0
- package/src/lib/utils/lightbox-attributes.js.map +1 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
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";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
4
4
|
/**
|
|
5
5
|
* @license
|
|
6
6
|
* Copyright 2026 Aglyn LLC
|
|
@@ -18,14 +18,21 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
18
18
|
* limitations under the License.
|
|
19
19
|
*/ import * as Aglyn from "@aglyn/aglyn";
|
|
20
20
|
import { mdiImageMultiple, mdiImageMultipleOutline } from "@aglyn/shared-data-mdi";
|
|
21
|
+
import { splitLightboxAppearanceProps } from "@aglyn/shared-ui-jsx/components/lightbox/lightbox-appearance";
|
|
21
22
|
import MuiImageList from "@mui/material/ImageList";
|
|
22
23
|
import MuiImageListItem from "@mui/material/ImageListItem";
|
|
23
24
|
import MuiImageListItemBar from "@mui/material/ImageListItemBar";
|
|
24
|
-
import
|
|
25
|
+
import useForkRef from "@mui/utils/useForkRef";
|
|
26
|
+
import { forwardRef, lazy, Suspense, useCallback, useMemo, useRef, useState } from "react";
|
|
25
27
|
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
26
28
|
import { dropClearedProps } from "../utils/drop-cleared-props.js";
|
|
27
29
|
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
30
|
+
import { lightboxAppearanceAttributes, WHEN_LIGHTBOX_ON } from "../utils/lightbox-attributes.js";
|
|
28
31
|
import { toCount } from "../utils/to-count.js";
|
|
32
|
+
import { ImageLightboxGalleryContext, listGalleryOf } from "./image-lightbox-items.js";
|
|
33
|
+
/** The gallery dialog, loaded only once a visitor opens a picture (AGL-3717). */ const ImageLightbox = /*#__PURE__*/ lazy(()=>import("./image-lightbox.js").then((module)=>({
|
|
34
|
+
default: module.ImageLightbox
|
|
35
|
+
})));
|
|
29
36
|
// Component ids are persisted in screen documents; never rename.
|
|
30
37
|
export const IMAGE_LIST_ID = 'muiImageList';
|
|
31
38
|
export const IMAGE_LIST_ITEM_ID = 'muiImageListItem';
|
|
@@ -38,14 +45,44 @@ export { toCount };
|
|
|
38
45
|
*/ const ImageListElement = /*#__PURE__*/ forwardRef((rawProps, ref)=>{
|
|
39
46
|
// Cleared props dropped before the resolvers below read them
|
|
40
47
|
// (AGL-1451); `rest` also spreads straight into MUI.
|
|
41
|
-
const props = dropClearedProps(rawProps);
|
|
42
|
-
const { cols, gap, rowHeight, variant, children } = props, rest = _object_without_properties_loose(props, [
|
|
48
|
+
const { appearance, rest: props } = splitLightboxAppearanceProps(dropClearedProps(rawProps));
|
|
49
|
+
const { cols, gap, rowHeight, variant, children, lightbox, lightboxThumbnails } = props, rest = _object_without_properties_loose(props, [
|
|
43
50
|
"cols",
|
|
44
51
|
"gap",
|
|
45
52
|
"rowHeight",
|
|
46
53
|
"variant",
|
|
47
|
-
"children"
|
|
54
|
+
"children",
|
|
55
|
+
"lightbox",
|
|
56
|
+
"lightboxThumbnails"
|
|
48
57
|
]);
|
|
58
|
+
/**
|
|
59
|
+
* The gallery (AGL-3717). The list does not know its pictures ahead of
|
|
60
|
+
* time and does not need to: every Image inside reads the context below,
|
|
61
|
+
* marks its `<img>` and hands itself here when pressed, and the gallery
|
|
62
|
+
* is read off the list's own DOM at that moment, in the order the visitor
|
|
63
|
+
* sees the tiles.
|
|
64
|
+
*/ const galleryOn = Aglyn.readYesNoValue(lightbox) === true;
|
|
65
|
+
const listRef = useRef(null);
|
|
66
|
+
const rootRef = useForkRef(ref, listRef);
|
|
67
|
+
const [open, setOpen] = useState(false);
|
|
68
|
+
const [gallery, setGallery] = useState({
|
|
69
|
+
pictures: [],
|
|
70
|
+
index: 0
|
|
71
|
+
});
|
|
72
|
+
const api = useMemo(()=>({
|
|
73
|
+
open: (trigger)=>{
|
|
74
|
+
const list = listRef.current;
|
|
75
|
+
if (!list) return;
|
|
76
|
+
const next = listGalleryOf(list, trigger);
|
|
77
|
+
if (!next.pictures.length) return;
|
|
78
|
+
setGallery(next);
|
|
79
|
+
setOpen(true);
|
|
80
|
+
}
|
|
81
|
+
}), []);
|
|
82
|
+
const close = useCallback(()=>setOpen(false), []);
|
|
83
|
+
const prefetch = useCallback(()=>{
|
|
84
|
+
void import("./image-lightbox.js").catch(()=>undefined);
|
|
85
|
+
}, []);
|
|
49
86
|
const resolvedVariant = [
|
|
50
87
|
'standard',
|
|
51
88
|
'quilted',
|
|
@@ -53,19 +90,41 @@ export { toCount };
|
|
|
53
90
|
'woven'
|
|
54
91
|
].includes(variant) ? variant : 'standard';
|
|
55
92
|
const height = toCount(rowHeight);
|
|
56
|
-
|
|
57
|
-
ref:
|
|
93
|
+
const list = /*#__PURE__*/ _jsx(MuiImageList, _extends({
|
|
94
|
+
ref: rootRef,
|
|
58
95
|
variant: resolvedVariant,
|
|
59
96
|
cols: toCount(cols, 3),
|
|
60
97
|
gap: toCount(gap, 4),
|
|
61
98
|
// A masonry list sizes rows from the images themselves; a fixed
|
|
62
99
|
// rowHeight silently defeats the whole variant.
|
|
63
100
|
rowHeight: resolvedVariant === 'masonry' ? 'auto' : height != null ? height : 'auto'
|
|
64
|
-
}, rest, {
|
|
101
|
+
}, rest, galleryOn ? {
|
|
102
|
+
onPointerEnter: prefetch,
|
|
103
|
+
onFocusCapture: prefetch
|
|
104
|
+
} : {}, {
|
|
65
105
|
// MUI types ImageList's children as NonNullable; the renderer
|
|
66
106
|
// always supplies the tile subtree.
|
|
67
|
-
children:
|
|
107
|
+
children: galleryOn ? /*#__PURE__*/ _jsx(ImageLightboxGalleryContext.Provider, {
|
|
108
|
+
value: api,
|
|
109
|
+
children: children
|
|
110
|
+
}) : children
|
|
68
111
|
}));
|
|
112
|
+
if (!galleryOn) return list;
|
|
113
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
114
|
+
children: [
|
|
115
|
+
list,
|
|
116
|
+
gallery.pictures.length ? /*#__PURE__*/ _jsx(Suspense, {
|
|
117
|
+
fallback: null,
|
|
118
|
+
children: /*#__PURE__*/ _jsx(ImageLightbox, {
|
|
119
|
+
open: open,
|
|
120
|
+
onClose: close,
|
|
121
|
+
gallery: gallery,
|
|
122
|
+
appearance: appearance,
|
|
123
|
+
thumbnails: Aglyn.readYesNoValue(lightboxThumbnails) === true
|
|
124
|
+
})
|
|
125
|
+
}) : null
|
|
126
|
+
]
|
|
127
|
+
});
|
|
69
128
|
});
|
|
70
129
|
ImageListElement.displayName = 'AglynImageList';
|
|
71
130
|
/**
|
|
@@ -176,7 +235,21 @@ export const imageListSchema = {
|
|
|
176
235
|
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
177
236
|
type: 'number',
|
|
178
237
|
condition: NOT_MASONRY
|
|
179
|
-
}
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: 'lightbox',
|
|
241
|
+
label: 'Open in a lightbox',
|
|
242
|
+
description: 'Clicking a picture opens a gallery of every picture in the list, ' + 'with previous and next, swipe, arrow keys and a counter. Captions ' + 'come from each tile.',
|
|
243
|
+
component: Aglyn.FieldComponentType.SWITCH
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: 'lightboxThumbnails',
|
|
247
|
+
label: 'Gallery thumbnails',
|
|
248
|
+
description: 'Shows a strip of thumbnails under the gallery picture.',
|
|
249
|
+
component: Aglyn.FieldComponentType.SWITCH,
|
|
250
|
+
condition: WHEN_LIGHTBOX_ON
|
|
251
|
+
},
|
|
252
|
+
...lightboxAppearanceAttributes(WHEN_LIGHTBOX_ON)
|
|
180
253
|
]
|
|
181
254
|
};
|
|
182
255
|
export const imageListItemSchema = {
|
|
@@ -1 +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'\nimport { toCount } from '../utils/to-count'\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// Still exported here, where it was first written: the package's\n// `components/image-list` subpath has always offered it.\nexport { toCount }\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","toCount","IMAGE_LIST_ID","IMAGE_LIST_ITEM_ID","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","value","TEXT_FIELD","type","condition","imageListItemSchema","tile","caption","componentId","nodes","alt","objectFit","imageListPresets","NodeType","PRESET","data"],"mappings":"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"}
|
|
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 {\n type LightboxAppearanceProps,\n splitLightboxAppearanceProps,\n} from '@aglyn/shared-ui-jsx/components/lightbox/lightbox-appearance'\nimport MuiImageList from '@mui/material/ImageList'\nimport MuiImageListItem from '@mui/material/ImageListItem'\nimport MuiImageListItemBar from '@mui/material/ImageListItemBar'\nimport useForkRef from '@mui/utils/useForkRef'\nimport {\n forwardRef,\n lazy,\n type ReactNode,\n Suspense,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\nimport {\n lightboxAppearanceAttributes,\n WHEN_LIGHTBOX_ON,\n} from '../utils/lightbox-attributes'\nimport { toCount } from '../utils/to-count'\nimport {\n type ImageLightboxGalleryApi,\n ImageLightboxGalleryContext,\n type LightboxGallery,\n listGalleryOf,\n} from './image-lightbox-items'\n\n/** The gallery dialog, loaded only once a visitor opens a picture (AGL-3717). */\nconst ImageLightbox = lazy(() =>\n import('./image-lightbox').then((module) => ({\n default: module.ImageLightbox,\n })),\n)\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 extends LightboxAppearanceProps {\n /**\n * Opens a gallery lightbox when a visitor presses any picture in the list\n * (AGL-3717): previous and next, swipe, arrow keys, a counter, captions.\n */\n lightbox?: boolean | string\n /** A strip of thumbnails under the gallery's picture. */\n lightboxThumbnails?: boolean | string\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// Still exported here, where it was first written: the package's\n// `components/image-list` subpath has always offered it.\nexport { toCount }\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 { appearance, rest: props } = splitLightboxAppearanceProps(\n dropClearedProps(rawProps),\n )\n const {\n cols,\n gap,\n rowHeight,\n variant,\n children,\n lightbox,\n lightboxThumbnails,\n ...rest\n } = props\n /**\n * The gallery (AGL-3717). The list does not know its pictures ahead of\n * time and does not need to: every Image inside reads the context below,\n * marks its `<img>` and hands itself here when pressed, and the gallery\n * is read off the list's own DOM at that moment, in the order the visitor\n * sees the tiles.\n */\n const galleryOn = Aglyn.readYesNoValue(lightbox) === true\n const listRef = useRef<HTMLUListElement>(null)\n const rootRef = useForkRef(ref, listRef)\n const [open, setOpen] = useState(false)\n const [gallery, setGallery] = useState<LightboxGallery>({\n pictures: [],\n index: 0,\n })\n const api = useMemo<ImageLightboxGalleryApi>(\n () => ({\n open: (trigger) => {\n const list = listRef.current\n if (!list) return\n const next = listGalleryOf(list, trigger)\n if (!next.pictures.length) return\n setGallery(next)\n setOpen(true)\n },\n }),\n [],\n )\n const close = useCallback(() => setOpen(false), [])\n const prefetch = useCallback(() => {\n void import('./image-lightbox').catch(() => undefined)\n }, [])\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 const list = (\n <MuiImageList\n ref={rootRef}\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 // The dialog's chunk is asked for when a visitor first goes near\n // the gallery, so it is usually there by the time they press.\n {...(galleryOn ? { onPointerEnter: prefetch, onFocusCapture: prefetch } : {})}\n // MUI types ImageList's children as NonNullable; the renderer\n // always supplies the tile subtree.\n children={\n (galleryOn ? (\n <ImageLightboxGalleryContext.Provider value={api}>\n {children}\n </ImageLightboxGalleryContext.Provider>\n ) : (\n children\n )) as NonNullable<ReactNode>\n }\n />\n )\n if (!galleryOn) return list\n return (\n <>\n {list}\n {/* Mounted at the first press, never before: a list of pictures\n fetches no dialog code until a visitor opens one. */}\n {gallery.pictures.length ? (\n <Suspense fallback={null}>\n <ImageLightbox\n open={open}\n onClose={close}\n gallery={gallery}\n appearance={appearance}\n thumbnails={Aglyn.readYesNoValue(lightboxThumbnails) === true}\n />\n </Suspense>\n ) : null}\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 name: 'lightbox',\n label: 'Open in a lightbox',\n description:\n 'Clicking a picture opens a gallery of every picture in the list, ' +\n 'with previous and next, swipe, arrow keys and a counter. Captions ' +\n 'come from each tile.',\n component: Aglyn.FieldComponentType.SWITCH,\n },\n {\n name: 'lightboxThumbnails',\n label: 'Gallery thumbnails',\n description: 'Shows a strip of thumbnails under the gallery picture.',\n component: Aglyn.FieldComponentType.SWITCH,\n condition: WHEN_LIGHTBOX_ON,\n },\n ...lightboxAppearanceAttributes(WHEN_LIGHTBOX_ON),\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","splitLightboxAppearanceProps","MuiImageList","MuiImageListItem","MuiImageListItemBar","useForkRef","forwardRef","lazy","Suspense","useCallback","useMemo","useRef","useState","BUNDLE_ID","dropClearedProps","generatePresetId","lightboxAppearanceAttributes","WHEN_LIGHTBOX_ON","toCount","ImageLightboxGalleryContext","listGalleryOf","ImageLightbox","then","module","default","IMAGE_LIST_ID","IMAGE_LIST_ITEM_ID","ImageListElement","rawProps","ref","appearance","rest","props","cols","gap","rowHeight","variant","children","lightbox","lightboxThumbnails","galleryOn","readYesNoValue","listRef","rootRef","open","setOpen","gallery","setGallery","pictures","index","api","trigger","list","current","next","length","close","prefetch","catch","undefined","resolvedVariant","includes","height","onPointerEnter","onFocusCapture","Provider","value","fallback","onClose","thumbnails","displayName","ImageListItemElement","rows","title","subtitle","barPosition","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","SWITCH","imageListItemSchema","tile","caption","componentId","nodes","alt","objectFit","imageListPresets","NodeType","PRESET","data"],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import * as Aglyn from '@aglyn/aglyn';
|
|
18
|
+
import { type LightboxAppearanceProps } from '@aglyn/shared-ui-jsx/components/lightbox/lightbox-appearance';
|
|
18
19
|
import { type SxProps } from '@mui/material/styles';
|
|
19
20
|
import { type ReactNode } from 'react';
|
|
20
21
|
export declare const ID: Aglyn.ComponentId;
|
|
@@ -70,7 +71,7 @@ export declare const ID: Aglyn.ComponentId;
|
|
|
70
71
|
* it cannot be the LCP element and is skipped.
|
|
71
72
|
*/
|
|
72
73
|
export declare function leadImageNodeIds(root: Aglyn.NodeSchema | undefined): readonly string[];
|
|
73
|
-
export interface ImageProps {
|
|
74
|
+
export interface ImageProps extends LightboxAppearanceProps {
|
|
74
75
|
/**
|
|
75
76
|
* Where the image comes from (AGL-72). Either a **media reference** —
|
|
76
77
|
* `media:{scope}/{mediaId}`, what "Browse media" now stores (AGL-1215) —
|
|
@@ -145,6 +146,21 @@ export interface ImageProps {
|
|
|
145
146
|
intrinsicHeight?: number;
|
|
146
147
|
/** Border radius in px. */
|
|
147
148
|
radius?: number;
|
|
149
|
+
/**
|
|
150
|
+
* Opens the picture full size in a lightbox when pressed (AGL-3717). A
|
|
151
|
+
* linked image follows its link instead; an Image inside an Image List
|
|
152
|
+
* whose lightbox is on opens the list's gallery whatever this says.
|
|
153
|
+
*/
|
|
154
|
+
lightbox?: boolean | string;
|
|
155
|
+
/** A caption under the picture in the lightbox. */
|
|
156
|
+
lightboxCaption?: string;
|
|
157
|
+
/**
|
|
158
|
+
* A gallery name: every Image on the page with the same name opens as one
|
|
159
|
+
* gallery, with previous and next. Empty opens this picture alone.
|
|
160
|
+
*/
|
|
161
|
+
lightboxGallery?: string;
|
|
162
|
+
/** A strip of thumbnails under a gallery's picture. */
|
|
163
|
+
lightboxThumbnails?: boolean | string;
|
|
148
164
|
/** Target screen id — resolved rename-safe like Screen Link (AGL-339). */
|
|
149
165
|
screenId?: string;
|
|
150
166
|
/** External URL, used only when no `screenId` is set. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
2
|
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
3
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
4
4
|
/**
|
|
5
5
|
* @license
|
|
6
6
|
* Copyright 2026 Aglyn LLC
|
|
@@ -19,13 +19,24 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
19
19
|
*/ import * as Aglyn from "@aglyn/aglyn";
|
|
20
20
|
import { mdiImage } from "@aglyn/shared-data-mdi";
|
|
21
21
|
import { AppLink } from "@aglyn/shared-ui-jsx";
|
|
22
|
+
import { splitLightboxAppearanceProps } from "@aglyn/shared-ui-jsx/components/lightbox/lightbox-appearance";
|
|
22
23
|
import Box from "@mui/material/Box";
|
|
23
24
|
import { useTheme } from "@mui/material/styles";
|
|
24
25
|
import useForkRef from "@mui/utils/useForkRef";
|
|
25
|
-
import { forwardRef, useEffect, useState } from "react";
|
|
26
|
+
import { forwardRef, lazy, Suspense, useCallback, useContext, useEffect, useState } from "react";
|
|
26
27
|
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
27
28
|
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
28
29
|
import { imageSizes, layoutBandWidths } from "../utils/image-sizes.js";
|
|
30
|
+
import { lightboxAppearanceAttributes, WHEN_LIGHTBOX_ON } from "../utils/lightbox-attributes.js";
|
|
31
|
+
import { imageGalleryOf, ImageLightboxGalleryContext, LIGHTBOX_ATTRIBUTE, LIGHTBOX_CAPTION_ATTRIBUTE } from "./image-lightbox-items.js";
|
|
32
|
+
/**
|
|
33
|
+
* The picture lightbox, behind a lazy boundary (AGL-3717) for the reason the
|
|
34
|
+
* Video's is (AGL-2744): it names MUI's Dialog, and this module is on every
|
|
35
|
+
* page that shows a picture. It is fetched the first time a visitor points at
|
|
36
|
+
* or focuses a picture that opens, and mounted when they press it.
|
|
37
|
+
*/ const ImageLightbox = /*#__PURE__*/ lazy(()=>import("./image-lightbox.js").then((module)=>({
|
|
38
|
+
default: module.ImageLightbox
|
|
39
|
+
})));
|
|
29
40
|
// Component ids are persisted in screen documents; never rename.
|
|
30
41
|
export const ID = 'image';
|
|
31
42
|
/**
|
|
@@ -170,8 +181,10 @@ export const ID = 'image';
|
|
|
170
181
|
* Image element (AGL-74): renders a plain img with fit/size/radius
|
|
171
182
|
* controls; an empty src shows a labeled placeholder so the element stays
|
|
172
183
|
* visible and selectable in the editor.
|
|
173
|
-
*/ const Image = /*#__PURE__*/ forwardRef((
|
|
174
|
-
|
|
184
|
+
*/ const Image = /*#__PURE__*/ forwardRef((allProps, ref)=>{
|
|
185
|
+
// The lightbox's look rides its own props, never the `<img>` (AGL-3717).
|
|
186
|
+
const { appearance: lightboxAppearance, rest: props } = splitLightboxAppearanceProps(allProps);
|
|
187
|
+
const { src: storedSrc, alt, decorative, title, loading, objectFit, width, height, sizes: authoredSizes, renderedWidths, mediaVersion, intrinsicWidth, intrinsicHeight, radius, screenId, href: externalHref, lightbox, lightboxCaption, lightboxGallery, lightboxThumbnails, // Never forward children to the <img> below — React throws on ANY
|
|
175
188
|
// children value reaching a void element, which 500'd whole pages
|
|
176
189
|
// when a renderer passed empty JSX children through (AGL-579).
|
|
177
190
|
children: _children, // Pull `sx` out of the spread: the literals below are composed AFTER
|
|
@@ -195,6 +208,10 @@ export const ID = 'image';
|
|
|
195
208
|
"radius",
|
|
196
209
|
"screenId",
|
|
197
210
|
"href",
|
|
211
|
+
"lightbox",
|
|
212
|
+
"lightboxCaption",
|
|
213
|
+
"lightboxGallery",
|
|
214
|
+
"lightboxThumbnails",
|
|
198
215
|
"children",
|
|
199
216
|
"sx"
|
|
200
217
|
]);
|
|
@@ -243,6 +260,78 @@ export const ID = 'image';
|
|
|
243
260
|
hostId,
|
|
244
261
|
version: mediaVersion
|
|
245
262
|
});
|
|
263
|
+
/**
|
|
264
|
+
* The lightbox (AGL-3717). A picture opens when its own switch is on, or
|
|
265
|
+
* when it sits in an Image List whose lightbox is on — then the list's
|
|
266
|
+
* gallery is what opens. A linked picture follows its link: one press
|
|
267
|
+
* cannot both navigate and open a dialog.
|
|
268
|
+
*
|
|
269
|
+
* Nothing of the dialog is fetched until a visitor points at or focuses
|
|
270
|
+
* the picture (`armed`), and nothing renders in it until they press.
|
|
271
|
+
*/ const listGallery = useContext(ImageLightboxGalleryContext);
|
|
272
|
+
const linked = Boolean(linkHref && !suppressNavigation);
|
|
273
|
+
const opens = !linked && (Boolean(listGallery) || Aglyn.readYesNoValue(lightbox) === true);
|
|
274
|
+
const [lightboxOpen, setLightboxOpen] = useState(false);
|
|
275
|
+
const [armed, setArmed] = useState(false);
|
|
276
|
+
const [gallery, setGallery] = useState({
|
|
277
|
+
pictures: [],
|
|
278
|
+
index: 0
|
|
279
|
+
});
|
|
280
|
+
const arm = useCallback(()=>{
|
|
281
|
+
if (!listGallery) setArmed(true);
|
|
282
|
+
}, [
|
|
283
|
+
listGallery
|
|
284
|
+
]);
|
|
285
|
+
const closeLightbox = useCallback(()=>setLightboxOpen(false), []);
|
|
286
|
+
const openFrom = (trigger)=>{
|
|
287
|
+
// The canvas is inert (AGL-830): a press there selects the node.
|
|
288
|
+
if (editorInert) return;
|
|
289
|
+
if (listGallery) {
|
|
290
|
+
listGallery.open(trigger);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const next = imageGalleryOf(trigger);
|
|
294
|
+
if (!next.pictures.length) return;
|
|
295
|
+
setGallery(next);
|
|
296
|
+
setArmed(true);
|
|
297
|
+
setLightboxOpen(true);
|
|
298
|
+
};
|
|
299
|
+
const lightboxTriggerProps = opens ? _extends({
|
|
300
|
+
[LIGHTBOX_ATTRIBUTE]: listGallery ? '' : (lightboxGallery != null ? lightboxGallery : '').trim()
|
|
301
|
+
}, (lightboxCaption == null ? void 0 : lightboxCaption.trim()) ? {
|
|
302
|
+
[LIGHTBOX_CAPTION_ATTRIBUTE]: lightboxCaption.trim()
|
|
303
|
+
} : {}, {
|
|
304
|
+
role: 'button',
|
|
305
|
+
tabIndex: 0,
|
|
306
|
+
'aria-haspopup': 'dialog'
|
|
307
|
+
}, decorative || !alt ? {
|
|
308
|
+
'aria-label': 'Open picture'
|
|
309
|
+
} : {}, {
|
|
310
|
+
onPointerEnter: arm,
|
|
311
|
+
onFocus: arm,
|
|
312
|
+
onClick: (event)=>openFrom(event.currentTarget),
|
|
313
|
+
onKeyDown: (event)=>{
|
|
314
|
+
if (event.key !== 'Enter' && event.key !== ' ') return;
|
|
315
|
+
event.preventDefault();
|
|
316
|
+
openFrom(event.currentTarget);
|
|
317
|
+
}
|
|
318
|
+
}) : {};
|
|
319
|
+
const withLightbox = (element)=>opens && armed && !listGallery ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
320
|
+
children: [
|
|
321
|
+
element,
|
|
322
|
+
/*#__PURE__*/ _jsx(Suspense, {
|
|
323
|
+
fallback: null,
|
|
324
|
+
children: /*#__PURE__*/ _jsx(ImageLightbox, {
|
|
325
|
+
open: lightboxOpen,
|
|
326
|
+
onClose: closeLightbox,
|
|
327
|
+
gallery: gallery,
|
|
328
|
+
appearance: lightboxAppearance,
|
|
329
|
+
thumbnails: Aglyn.readYesNoValue(lightboxThumbnails) === true,
|
|
330
|
+
label: (lightboxGallery == null ? void 0 : lightboxGallery.trim()) || undefined
|
|
331
|
+
})
|
|
332
|
+
})
|
|
333
|
+
]
|
|
334
|
+
}) : element;
|
|
246
335
|
const wrapLink = (element)=>linkHref && !suppressNavigation ? /*#__PURE__*/ _jsx(AppLink, {
|
|
247
336
|
componentVariant: "naked",
|
|
248
337
|
href: linkHref,
|
|
@@ -334,7 +423,7 @@ export const ID = 'image';
|
|
|
334
423
|
height: intrinsicHeight
|
|
335
424
|
} : undefined;
|
|
336
425
|
const sizes = srcSet ? resolvedSizes.sizes : undefined;
|
|
337
|
-
return wrapLink(/*#__PURE__*/ _jsx(Box, _extends({
|
|
426
|
+
return withLightbox(wrapLink(/*#__PURE__*/ _jsx(Box, _extends({
|
|
338
427
|
ref: imageRef,
|
|
339
428
|
component: "img",
|
|
340
429
|
src: src,
|
|
@@ -386,7 +475,7 @@ export const ID = 'image';
|
|
|
386
475
|
loading: 'eager'
|
|
387
476
|
}, hero ? {
|
|
388
477
|
fetchPriority: 'high'
|
|
389
|
-
} : {}) : Aglyn.DEFERRED_IMAGE_ATTRIBUTES, intrinsicAttributes, rest, {
|
|
478
|
+
} : {}) : Aglyn.DEFERRED_IMAGE_ATTRIBUTES, intrinsicAttributes, rest, lightboxTriggerProps, {
|
|
390
479
|
sx: [
|
|
391
480
|
{
|
|
392
481
|
display: 'block',
|
|
@@ -395,9 +484,14 @@ export const ID = 'image';
|
|
|
395
484
|
objectFit: objectFit || 'cover',
|
|
396
485
|
borderRadius: radius != null ? `${radius}px` : undefined
|
|
397
486
|
},
|
|
487
|
+
...opens ? [
|
|
488
|
+
{
|
|
489
|
+
cursor: 'zoom-in'
|
|
490
|
+
}
|
|
491
|
+
] : [],
|
|
398
492
|
...nodeSx
|
|
399
493
|
]
|
|
400
|
-
})));
|
|
494
|
+
}))));
|
|
401
495
|
});
|
|
402
496
|
Image.displayName = 'Image';
|
|
403
497
|
/** Alt text and tooltip make no sense on an explicitly decorative image. */ const NOT_DECORATIVE = {
|
|
@@ -530,6 +624,34 @@ export const schema = {
|
|
|
530
624
|
}
|
|
531
625
|
]
|
|
532
626
|
},
|
|
627
|
+
{
|
|
628
|
+
name: 'lightbox',
|
|
629
|
+
description: 'Opens the picture full size in a lightbox when a visitor clicks ' + 'it. A linked image follows its link instead.',
|
|
630
|
+
component: Aglyn.FieldComponentType.SWITCH,
|
|
631
|
+
label: 'Open in a lightbox'
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
name: 'lightboxCaption',
|
|
635
|
+
description: 'A caption shown with the picture in the lightbox.',
|
|
636
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
637
|
+
label: 'Lightbox caption',
|
|
638
|
+
condition: WHEN_LIGHTBOX_ON
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
name: 'lightboxGallery',
|
|
642
|
+
description: 'Give pictures the same gallery name and they open as one gallery, ' + 'with previous and next. Leave empty to open this picture alone.',
|
|
643
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
644
|
+
label: 'Gallery name',
|
|
645
|
+
condition: WHEN_LIGHTBOX_ON
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
name: 'lightboxThumbnails',
|
|
649
|
+
description: 'Shows a strip of thumbnails under a gallery picture.',
|
|
650
|
+
component: Aglyn.FieldComponentType.SWITCH,
|
|
651
|
+
label: 'Gallery thumbnails',
|
|
652
|
+
condition: WHEN_LIGHTBOX_ON
|
|
653
|
+
},
|
|
654
|
+
...lightboxAppearanceAttributes(WHEN_LIGHTBOX_ON),
|
|
533
655
|
{
|
|
534
656
|
name: 'screenId',
|
|
535
657
|
description: 'Optional: navigate to this page when the image is clicked — ' + 'follows the published path like a Page Link.',
|