@canopy-iiif/app 1.10.0 → 1.10.1
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/lib/components/image-story-runtime-entry.js +189 -9
- package/package.json +1 -1
- package/ui/dist/index.mjs +106 -12
- package/ui/dist/index.mjs.map +2 -2
- package/ui/dist/server.mjs +106 -12
- package/ui/dist/server.mjs.map +2 -2
- package/ui/styles/components/_gallery.scss +0 -3
- package/ui/styles/index.css +0 -3
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { mountImageStory } from '../../ui/dist/index.mjs';
|
|
2
2
|
|
|
3
|
+
const IMAGE_STORY_SELECTOR = '[data-canopy-image-story]';
|
|
4
|
+
const nodeStates = new WeakMap();
|
|
5
|
+
const SIZE_EPSILON = 1;
|
|
6
|
+
|
|
3
7
|
function ready(fn) {
|
|
4
8
|
if (typeof document === 'undefined') return;
|
|
5
9
|
if (document.readyState === 'loading') {
|
|
@@ -20,19 +24,161 @@ function parseProps(node) {
|
|
|
20
24
|
}
|
|
21
25
|
}
|
|
22
26
|
|
|
27
|
+
function getNodeState(node) {
|
|
28
|
+
if (!node) return null;
|
|
29
|
+
let state = nodeStates.get(node);
|
|
30
|
+
if (!state) {
|
|
31
|
+
state = {
|
|
32
|
+
mounted: false,
|
|
33
|
+
cleanup: null,
|
|
34
|
+
resizeObserver: null,
|
|
35
|
+
pollId: null,
|
|
36
|
+
watching: false,
|
|
37
|
+
props: null,
|
|
38
|
+
lastSize: null,
|
|
39
|
+
};
|
|
40
|
+
nodeStates.set(node, state);
|
|
41
|
+
}
|
|
42
|
+
return state;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function disconnectWatchers(state) {
|
|
46
|
+
if (!state) return;
|
|
47
|
+
if (state.resizeObserver) {
|
|
48
|
+
try {
|
|
49
|
+
state.resizeObserver.disconnect();
|
|
50
|
+
} catch (_) {}
|
|
51
|
+
state.resizeObserver = null;
|
|
52
|
+
}
|
|
53
|
+
if (state.pollId && typeof window !== 'undefined') {
|
|
54
|
+
window.clearTimeout(state.pollId);
|
|
55
|
+
state.pollId = null;
|
|
56
|
+
}
|
|
57
|
+
state.watching = false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function destroyNode(node, state) {
|
|
61
|
+
const currentState = state || getNodeState(node);
|
|
62
|
+
if (!currentState) return;
|
|
63
|
+
disconnectWatchers(currentState);
|
|
64
|
+
if (currentState.cleanup) {
|
|
65
|
+
try {
|
|
66
|
+
currentState.cleanup();
|
|
67
|
+
} catch (_) {}
|
|
68
|
+
currentState.cleanup = null;
|
|
69
|
+
}
|
|
70
|
+
currentState.mounted = false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function measureSize(node) {
|
|
74
|
+
if (!node) return null;
|
|
75
|
+
const rect = node.getBoundingClientRect();
|
|
76
|
+
const width = rect?.width || node.offsetWidth || node.clientWidth || 0;
|
|
77
|
+
const height = rect?.height || node.offsetHeight || node.clientHeight || 0;
|
|
78
|
+
return { width, height };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function hasUsableSize(node, state) {
|
|
82
|
+
const size = measureSize(node);
|
|
83
|
+
if (!size) return false;
|
|
84
|
+
const usable = size.width > 2 && size.height > 2;
|
|
85
|
+
if (usable && state) {
|
|
86
|
+
state.lastSize = size;
|
|
87
|
+
}
|
|
88
|
+
return usable;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function needsSizeRefresh(node, state) {
|
|
92
|
+
if (!node || !state) return false;
|
|
93
|
+
const size = measureSize(node);
|
|
94
|
+
if (!size) return false;
|
|
95
|
+
if (size.width <= 2 || size.height <= 2) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
if (!state.lastSize) {
|
|
99
|
+
state.lastSize = size;
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
const widthDelta = Math.abs(size.width - state.lastSize.width);
|
|
103
|
+
const heightDelta = Math.abs(size.height - state.lastSize.height);
|
|
104
|
+
if (widthDelta > SIZE_EPSILON || heightDelta > SIZE_EPSILON) {
|
|
105
|
+
state.lastSize = size;
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function attemptMount(node, state) {
|
|
112
|
+
if (!node || !state || state.mounted) return false;
|
|
113
|
+
if (!hasUsableSize(node, state)) return false;
|
|
114
|
+
state.mounted = true;
|
|
115
|
+
disconnectWatchers(state);
|
|
116
|
+
const props = state.props || parseProps(node);
|
|
117
|
+
Promise.resolve(mountImageStory(node, props)).then((destroy) => {
|
|
118
|
+
if (typeof destroy === 'function') {
|
|
119
|
+
state.cleanup = destroy;
|
|
120
|
+
} else {
|
|
121
|
+
state.cleanup = null;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function scheduleWatchers(node, state, tryMount) {
|
|
128
|
+
if (!node || !state || state.watching) return;
|
|
129
|
+
if (typeof window === 'undefined') return;
|
|
130
|
+
state.watching = true;
|
|
131
|
+
if (typeof window !== 'undefined' && typeof window.ResizeObserver === 'function') {
|
|
132
|
+
state.resizeObserver = new window.ResizeObserver(() => {
|
|
133
|
+
if (state.mounted) return;
|
|
134
|
+
tryMount();
|
|
135
|
+
});
|
|
136
|
+
try {
|
|
137
|
+
state.resizeObserver.observe(node);
|
|
138
|
+
} catch (_) {}
|
|
139
|
+
}
|
|
140
|
+
const schedulePoll = () => {
|
|
141
|
+
if (state.mounted) return;
|
|
142
|
+
state.pollId = window.setTimeout(() => {
|
|
143
|
+
state.pollId = null;
|
|
144
|
+
if (!tryMount()) {
|
|
145
|
+
schedulePoll();
|
|
146
|
+
}
|
|
147
|
+
}, 200);
|
|
148
|
+
};
|
|
149
|
+
schedulePoll();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function startMountProcess(node) {
|
|
153
|
+
const state = getNodeState(node);
|
|
154
|
+
if (!state) return;
|
|
155
|
+
state.props = parseProps(node);
|
|
156
|
+
const tryMount = () => attemptMount(node, state);
|
|
157
|
+
if (!tryMount()) {
|
|
158
|
+
scheduleWatchers(node, state, tryMount);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
23
162
|
function mount(node) {
|
|
24
|
-
if (!node
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
163
|
+
if (!node) return;
|
|
164
|
+
const state = getNodeState(node);
|
|
165
|
+
if (!state || state.bound) return;
|
|
166
|
+
state.bound = true;
|
|
167
|
+
startMountProcess(node);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function remount(node) {
|
|
171
|
+
const state = getNodeState(node);
|
|
172
|
+
if (!state) return;
|
|
173
|
+
state.props = parseProps(node);
|
|
174
|
+
destroyNode(node, state);
|
|
175
|
+
startMountProcess(node);
|
|
30
176
|
}
|
|
31
177
|
|
|
32
178
|
function scan() {
|
|
33
179
|
try {
|
|
34
180
|
document
|
|
35
|
-
.querySelectorAll(
|
|
181
|
+
.querySelectorAll(IMAGE_STORY_SELECTOR)
|
|
36
182
|
.forEach((node) => mount(node));
|
|
37
183
|
} catch (_) {}
|
|
38
184
|
}
|
|
@@ -45,11 +191,11 @@ function observe() {
|
|
|
45
191
|
mutation.addedNodes &&
|
|
46
192
|
mutation.addedNodes.forEach((node) => {
|
|
47
193
|
if (!(node instanceof Element)) return;
|
|
48
|
-
if (node.matches && node.matches(
|
|
194
|
+
if (node.matches && node.matches(IMAGE_STORY_SELECTOR)) {
|
|
49
195
|
toMount.push(node);
|
|
50
196
|
}
|
|
51
197
|
const inner = node.querySelectorAll
|
|
52
|
-
? node.querySelectorAll(
|
|
198
|
+
? node.querySelectorAll(IMAGE_STORY_SELECTOR)
|
|
53
199
|
: [];
|
|
54
200
|
inner && inner.forEach && inner.forEach((el) => toMount.push(el));
|
|
55
201
|
});
|
|
@@ -63,7 +209,41 @@ function observe() {
|
|
|
63
209
|
} catch (_) {}
|
|
64
210
|
}
|
|
65
211
|
|
|
212
|
+
function refreshModal(modal) {
|
|
213
|
+
if (!modal || typeof modal.querySelectorAll !== 'function') return;
|
|
214
|
+
const nodes = modal.querySelectorAll(IMAGE_STORY_SELECTOR);
|
|
215
|
+
if (!nodes || !nodes.length) return;
|
|
216
|
+
Array.prototype.forEach.call(nodes, (node) => {
|
|
217
|
+
const state = getNodeState(node);
|
|
218
|
+
if (!state || !state.mounted) return;
|
|
219
|
+
if (needsSizeRefresh(node, state)) {
|
|
220
|
+
remount(node);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function handleGalleryModalChange(event) {
|
|
226
|
+
if (!event || typeof document === 'undefined') return;
|
|
227
|
+
const detail = event.detail || {};
|
|
228
|
+
if (detail.state !== 'open') return;
|
|
229
|
+
let modal = detail.modal;
|
|
230
|
+
if (!modal && detail.modalId) {
|
|
231
|
+
modal = document.getElementById(detail.modalId);
|
|
232
|
+
}
|
|
233
|
+
if (modal) {
|
|
234
|
+
refreshModal(modal);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function bindGalleryListener() {
|
|
239
|
+
if (typeof window === 'undefined' || typeof window.addEventListener !== 'function') {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
window.addEventListener('canopy:gallery:modal-change', handleGalleryModalChange);
|
|
243
|
+
}
|
|
244
|
+
|
|
66
245
|
ready(function onReady() {
|
|
67
246
|
scan();
|
|
68
247
|
observe();
|
|
248
|
+
bindGalleryListener();
|
|
69
249
|
});
|
package/package.json
CHANGED
package/ui/dist/index.mjs
CHANGED
|
@@ -45483,6 +45483,7 @@ async function mountImageStory(element, props = {}) {
|
|
|
45483
45483
|
// ui/src/iiif/ImageStory.jsx
|
|
45484
45484
|
var DEFAULT_IMAGE_STORY_HEIGHT = 600;
|
|
45485
45485
|
var NUMERIC_HEIGHT_PATTERN = /^[+-]?(?:\d+|\d*\.\d+)$/;
|
|
45486
|
+
var SIZE_EPSILON = 1;
|
|
45486
45487
|
function resolveContainerHeight(value) {
|
|
45487
45488
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
45488
45489
|
return `${value}px`;
|
|
@@ -45533,6 +45534,7 @@ var ImageStory = (props = {}) => {
|
|
|
45533
45534
|
let mounted = false;
|
|
45534
45535
|
let resizeObserver = null;
|
|
45535
45536
|
let pollId = null;
|
|
45537
|
+
let lastKnownSize = null;
|
|
45536
45538
|
const payload = sanitizeImageStoryProps({
|
|
45537
45539
|
iiifContent,
|
|
45538
45540
|
disablePanAndZoom,
|
|
@@ -45561,12 +45563,39 @@ var ImageStory = (props = {}) => {
|
|
|
45561
45563
|
pollId = null;
|
|
45562
45564
|
}
|
|
45563
45565
|
};
|
|
45564
|
-
const
|
|
45565
|
-
if (!node) return
|
|
45566
|
+
const measureSize = () => {
|
|
45567
|
+
if (!node) return null;
|
|
45566
45568
|
const rect = node.getBoundingClientRect();
|
|
45567
|
-
const width = (rect == null ? void 0 : rect.width) || node.offsetWidth || node.clientWidth;
|
|
45568
|
-
const height2 = (rect == null ? void 0 : rect.height) || node.offsetHeight || node.clientHeight;
|
|
45569
|
-
return width
|
|
45569
|
+
const width = (rect == null ? void 0 : rect.width) || node.offsetWidth || node.clientWidth || 0;
|
|
45570
|
+
const height2 = (rect == null ? void 0 : rect.height) || node.offsetHeight || node.clientHeight || 0;
|
|
45571
|
+
return { width, height: height2 };
|
|
45572
|
+
};
|
|
45573
|
+
const hasUsableSize = () => {
|
|
45574
|
+
const size = measureSize();
|
|
45575
|
+
if (!size) return false;
|
|
45576
|
+
const usable = size.width > 2 && size.height > 2;
|
|
45577
|
+
if (usable) {
|
|
45578
|
+
lastKnownSize = size;
|
|
45579
|
+
}
|
|
45580
|
+
return usable;
|
|
45581
|
+
};
|
|
45582
|
+
const hasMeaningfulSizeChange = () => {
|
|
45583
|
+
const size = measureSize();
|
|
45584
|
+
if (!size) return false;
|
|
45585
|
+
if (size.width <= 2 || size.height <= 2) {
|
|
45586
|
+
return true;
|
|
45587
|
+
}
|
|
45588
|
+
if (!lastKnownSize) {
|
|
45589
|
+
lastKnownSize = size;
|
|
45590
|
+
return true;
|
|
45591
|
+
}
|
|
45592
|
+
const widthDelta = Math.abs(size.width - lastKnownSize.width);
|
|
45593
|
+
const heightDelta = Math.abs(size.height - lastKnownSize.height);
|
|
45594
|
+
if (widthDelta > SIZE_EPSILON || heightDelta > SIZE_EPSILON) {
|
|
45595
|
+
lastKnownSize = size;
|
|
45596
|
+
return true;
|
|
45597
|
+
}
|
|
45598
|
+
return false;
|
|
45570
45599
|
};
|
|
45571
45600
|
const mountViewer = () => {
|
|
45572
45601
|
if (!node || mounted || cancelled) return false;
|
|
@@ -45582,8 +45611,9 @@ var ImageStory = (props = {}) => {
|
|
|
45582
45611
|
});
|
|
45583
45612
|
return true;
|
|
45584
45613
|
};
|
|
45585
|
-
|
|
45586
|
-
if (
|
|
45614
|
+
const scheduleWatchers = () => {
|
|
45615
|
+
if (mounted || cancelled) return;
|
|
45616
|
+
if (!resizeObserver && typeof window !== "undefined" && typeof window.ResizeObserver === "function") {
|
|
45587
45617
|
resizeObserver = new window.ResizeObserver(() => {
|
|
45588
45618
|
if (mounted || cancelled) return;
|
|
45589
45619
|
mountViewer();
|
|
@@ -45602,12 +45632,48 @@ var ImageStory = (props = {}) => {
|
|
|
45602
45632
|
}
|
|
45603
45633
|
}, 200);
|
|
45604
45634
|
};
|
|
45605
|
-
|
|
45635
|
+
if (!pollId) {
|
|
45636
|
+
schedulePoll();
|
|
45637
|
+
}
|
|
45638
|
+
};
|
|
45639
|
+
const beginMounting = () => {
|
|
45640
|
+
if (!mountViewer()) {
|
|
45641
|
+
scheduleWatchers();
|
|
45642
|
+
}
|
|
45643
|
+
};
|
|
45644
|
+
const remountViewer = () => {
|
|
45645
|
+
if (cancelled) return;
|
|
45646
|
+
if (mounted) {
|
|
45647
|
+
mounted = false;
|
|
45648
|
+
destroyCleanup();
|
|
45649
|
+
}
|
|
45650
|
+
beginMounting();
|
|
45651
|
+
};
|
|
45652
|
+
beginMounting();
|
|
45653
|
+
const handleGalleryModalChange = (event) => {
|
|
45654
|
+
if (!node || !event || typeof document === "undefined") return;
|
|
45655
|
+
const detail = event.detail || {};
|
|
45656
|
+
if (detail.state !== "open") return;
|
|
45657
|
+
const modal = detail.modal || (detail.modalId ? document.getElementById(detail.modalId) : null);
|
|
45658
|
+
if (!modal || !modal.contains(node)) return;
|
|
45659
|
+
if (!mounted) return;
|
|
45660
|
+
if (hasMeaningfulSizeChange()) {
|
|
45661
|
+
remountViewer();
|
|
45662
|
+
}
|
|
45663
|
+
};
|
|
45664
|
+
if (typeof window !== "undefined" && window.addEventListener) {
|
|
45665
|
+
window.addEventListener("canopy:gallery:modal-change", handleGalleryModalChange);
|
|
45606
45666
|
}
|
|
45607
45667
|
return () => {
|
|
45608
45668
|
cancelled = true;
|
|
45609
45669
|
disconnectWatchers();
|
|
45610
45670
|
destroyCleanup();
|
|
45671
|
+
if (typeof window !== "undefined" && window.removeEventListener) {
|
|
45672
|
+
window.removeEventListener(
|
|
45673
|
+
"canopy:gallery:modal-change",
|
|
45674
|
+
handleGalleryModalChange
|
|
45675
|
+
);
|
|
45676
|
+
}
|
|
45611
45677
|
};
|
|
45612
45678
|
}, [iiifContent, disablePanAndZoom, pointOfInterestSvgUrl, viewerOptions]);
|
|
45613
45679
|
return /* @__PURE__ */ React27.createElement(
|
|
@@ -48194,6 +48260,23 @@ var INLINE_SCRIPT = `(() => {
|
|
|
48194
48260
|
const NAV_OPTION_SELECTOR = '[data-canopy-gallery-nav-option]';
|
|
48195
48261
|
const NAV_ITEM_SELECTOR = '[data-canopy-gallery-nav-item]';
|
|
48196
48262
|
|
|
48263
|
+
function emitModalState(modal, state) {
|
|
48264
|
+
if (!modal || typeof window === 'undefined') return;
|
|
48265
|
+
const detail = { modalId: modal.id || '', modal, state };
|
|
48266
|
+
try {
|
|
48267
|
+
const EventCtor = window.CustomEvent || CustomEvent;
|
|
48268
|
+
if (typeof EventCtor === 'function') {
|
|
48269
|
+
window.dispatchEvent(new EventCtor('canopy:gallery:modal-change', { detail }));
|
|
48270
|
+
return;
|
|
48271
|
+
}
|
|
48272
|
+
} catch (_) {}
|
|
48273
|
+
try {
|
|
48274
|
+
const fallback = document.createEvent('CustomEvent');
|
|
48275
|
+
fallback.initCustomEvent('canopy:gallery:modal-change', true, true, detail);
|
|
48276
|
+
window.dispatchEvent(fallback);
|
|
48277
|
+
} catch (_) {}
|
|
48278
|
+
}
|
|
48279
|
+
|
|
48197
48280
|
function isVisible(node) {
|
|
48198
48281
|
return !!(node && (node.offsetWidth || node.offsetHeight || node.getClientRects().length));
|
|
48199
48282
|
}
|
|
@@ -48324,6 +48407,7 @@ var INLINE_SCRIPT = `(() => {
|
|
|
48324
48407
|
lockScroll();
|
|
48325
48408
|
document.addEventListener('keydown', handleKeydown, true);
|
|
48326
48409
|
} else if (activeModal !== modal) {
|
|
48410
|
+
emitModalState(activeModal, 'close');
|
|
48327
48411
|
activeModal.removeAttribute('data-canopy-gallery-active');
|
|
48328
48412
|
}
|
|
48329
48413
|
activeModal = modal;
|
|
@@ -48332,6 +48416,7 @@ var INLINE_SCRIPT = `(() => {
|
|
|
48332
48416
|
if (!focusActiveNav(modal)) {
|
|
48333
48417
|
focusInitial(modal);
|
|
48334
48418
|
}
|
|
48419
|
+
emitModalState(modal, 'open');
|
|
48335
48420
|
return;
|
|
48336
48421
|
}
|
|
48337
48422
|
if (!activeModal) return;
|
|
@@ -48365,6 +48450,7 @@ var INLINE_SCRIPT = `(() => {
|
|
|
48365
48450
|
}
|
|
48366
48451
|
});
|
|
48367
48452
|
}
|
|
48453
|
+
emitModalState(previous, 'close');
|
|
48368
48454
|
}
|
|
48369
48455
|
|
|
48370
48456
|
function modalFromHash() {
|
|
@@ -48823,6 +48909,7 @@ function buildCaptionContent(itemProps) {
|
|
|
48823
48909
|
));
|
|
48824
48910
|
}
|
|
48825
48911
|
function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
|
|
48912
|
+
const { getString, formatString } = useLocale();
|
|
48826
48913
|
const {
|
|
48827
48914
|
props,
|
|
48828
48915
|
modalId,
|
|
@@ -48835,6 +48922,12 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
|
|
|
48835
48922
|
const kicker = props.kicker || props.label || props.eyebrow;
|
|
48836
48923
|
const summary = props.popupDescription || props.modalDescription || props.description || props.summary || null;
|
|
48837
48924
|
const modalTitle = props.popupTitle || props.modalTitle || props.title || `Item ${index + 1}`;
|
|
48925
|
+
const closeButtonText = getString("common.actions.close", "Close");
|
|
48926
|
+
const closeButtonLabel = formatString(
|
|
48927
|
+
"common.phrases.close_content",
|
|
48928
|
+
"Close {content}",
|
|
48929
|
+
{ content: modalTitle }
|
|
48930
|
+
);
|
|
48838
48931
|
return /* @__PURE__ */ React44.createElement(
|
|
48839
48932
|
"div",
|
|
48840
48933
|
{
|
|
@@ -48856,13 +48949,14 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
|
|
|
48856
48949
|
groupName: `${navGroupName || "canopy-gallery"}-${modalId}`
|
|
48857
48950
|
}
|
|
48858
48951
|
), /* @__PURE__ */ React44.createElement(
|
|
48859
|
-
|
|
48952
|
+
Button,
|
|
48860
48953
|
{
|
|
48861
48954
|
className: "canopy-gallery__modal-close",
|
|
48862
48955
|
href: `#${closeTargetId}`,
|
|
48863
|
-
|
|
48864
|
-
|
|
48865
|
-
|
|
48956
|
+
label: closeButtonText,
|
|
48957
|
+
"aria-label": closeButtonLabel,
|
|
48958
|
+
variant: "secondary"
|
|
48959
|
+
}
|
|
48866
48960
|
)), /* @__PURE__ */ React44.createElement("div", { className: "canopy-gallery__modal-panel" }, /* @__PURE__ */ React44.createElement(
|
|
48867
48961
|
"button",
|
|
48868
48962
|
{
|