@canopy-iiif/app 1.10.0 → 1.10.3
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 +129 -16
- package/ui/dist/index.mjs.map +3 -3
- package/ui/dist/server.mjs +129 -16
- package/ui/dist/server.mjs.map +2 -2
- package/ui/styles/components/_gallery.scss +0 -3
- package/ui/styles/components/_timeline.scss +52 -10
- package/ui/styles/index.css +51 -13
package/ui/dist/server.mjs
CHANGED
|
@@ -656,6 +656,7 @@ async function mountImageStory(element, props = {}) {
|
|
|
656
656
|
// ui/src/iiif/ImageStory.jsx
|
|
657
657
|
var DEFAULT_IMAGE_STORY_HEIGHT = 600;
|
|
658
658
|
var NUMERIC_HEIGHT_PATTERN = /^[+-]?(?:\d+|\d*\.\d+)$/;
|
|
659
|
+
var SIZE_EPSILON = 1;
|
|
659
660
|
function resolveContainerHeight(value) {
|
|
660
661
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
661
662
|
return `${value}px`;
|
|
@@ -706,6 +707,7 @@ var ImageStory = (props = {}) => {
|
|
|
706
707
|
let mounted = false;
|
|
707
708
|
let resizeObserver = null;
|
|
708
709
|
let pollId = null;
|
|
710
|
+
let lastKnownSize = null;
|
|
709
711
|
const payload = sanitizeImageStoryProps({
|
|
710
712
|
iiifContent,
|
|
711
713
|
disablePanAndZoom,
|
|
@@ -734,12 +736,39 @@ var ImageStory = (props = {}) => {
|
|
|
734
736
|
pollId = null;
|
|
735
737
|
}
|
|
736
738
|
};
|
|
737
|
-
const
|
|
738
|
-
if (!node) return
|
|
739
|
+
const measureSize = () => {
|
|
740
|
+
if (!node) return null;
|
|
739
741
|
const rect = node.getBoundingClientRect();
|
|
740
|
-
const width = (rect == null ? void 0 : rect.width) || node.offsetWidth || node.clientWidth;
|
|
741
|
-
const height2 = (rect == null ? void 0 : rect.height) || node.offsetHeight || node.clientHeight;
|
|
742
|
-
return width
|
|
742
|
+
const width = (rect == null ? void 0 : rect.width) || node.offsetWidth || node.clientWidth || 0;
|
|
743
|
+
const height2 = (rect == null ? void 0 : rect.height) || node.offsetHeight || node.clientHeight || 0;
|
|
744
|
+
return { width, height: height2 };
|
|
745
|
+
};
|
|
746
|
+
const hasUsableSize = () => {
|
|
747
|
+
const size = measureSize();
|
|
748
|
+
if (!size) return false;
|
|
749
|
+
const usable = size.width > 2 && size.height > 2;
|
|
750
|
+
if (usable) {
|
|
751
|
+
lastKnownSize = size;
|
|
752
|
+
}
|
|
753
|
+
return usable;
|
|
754
|
+
};
|
|
755
|
+
const hasMeaningfulSizeChange = () => {
|
|
756
|
+
const size = measureSize();
|
|
757
|
+
if (!size) return false;
|
|
758
|
+
if (size.width <= 2 || size.height <= 2) {
|
|
759
|
+
return true;
|
|
760
|
+
}
|
|
761
|
+
if (!lastKnownSize) {
|
|
762
|
+
lastKnownSize = size;
|
|
763
|
+
return true;
|
|
764
|
+
}
|
|
765
|
+
const widthDelta = Math.abs(size.width - lastKnownSize.width);
|
|
766
|
+
const heightDelta = Math.abs(size.height - lastKnownSize.height);
|
|
767
|
+
if (widthDelta > SIZE_EPSILON || heightDelta > SIZE_EPSILON) {
|
|
768
|
+
lastKnownSize = size;
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
return false;
|
|
743
772
|
};
|
|
744
773
|
const mountViewer = () => {
|
|
745
774
|
if (!node || mounted || cancelled) return false;
|
|
@@ -755,8 +784,9 @@ var ImageStory = (props = {}) => {
|
|
|
755
784
|
});
|
|
756
785
|
return true;
|
|
757
786
|
};
|
|
758
|
-
|
|
759
|
-
if (
|
|
787
|
+
const scheduleWatchers = () => {
|
|
788
|
+
if (mounted || cancelled) return;
|
|
789
|
+
if (!resizeObserver && typeof window !== "undefined" && typeof window.ResizeObserver === "function") {
|
|
760
790
|
resizeObserver = new window.ResizeObserver(() => {
|
|
761
791
|
if (mounted || cancelled) return;
|
|
762
792
|
mountViewer();
|
|
@@ -775,12 +805,48 @@ var ImageStory = (props = {}) => {
|
|
|
775
805
|
}
|
|
776
806
|
}, 200);
|
|
777
807
|
};
|
|
778
|
-
|
|
808
|
+
if (!pollId) {
|
|
809
|
+
schedulePoll();
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
const beginMounting = () => {
|
|
813
|
+
if (!mountViewer()) {
|
|
814
|
+
scheduleWatchers();
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
const remountViewer = () => {
|
|
818
|
+
if (cancelled) return;
|
|
819
|
+
if (mounted) {
|
|
820
|
+
mounted = false;
|
|
821
|
+
destroyCleanup();
|
|
822
|
+
}
|
|
823
|
+
beginMounting();
|
|
824
|
+
};
|
|
825
|
+
beginMounting();
|
|
826
|
+
const handleGalleryModalChange = (event) => {
|
|
827
|
+
if (!node || !event || typeof document === "undefined") return;
|
|
828
|
+
const detail = event.detail || {};
|
|
829
|
+
if (detail.state !== "open") return;
|
|
830
|
+
const modal = detail.modal || (detail.modalId ? document.getElementById(detail.modalId) : null);
|
|
831
|
+
if (!modal || !modal.contains(node)) return;
|
|
832
|
+
if (!mounted) return;
|
|
833
|
+
if (hasMeaningfulSizeChange()) {
|
|
834
|
+
remountViewer();
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
if (typeof window !== "undefined" && window.addEventListener) {
|
|
838
|
+
window.addEventListener("canopy:gallery:modal-change", handleGalleryModalChange);
|
|
779
839
|
}
|
|
780
840
|
return () => {
|
|
781
841
|
cancelled = true;
|
|
782
842
|
disconnectWatchers();
|
|
783
843
|
destroyCleanup();
|
|
844
|
+
if (typeof window !== "undefined" && window.removeEventListener) {
|
|
845
|
+
window.removeEventListener(
|
|
846
|
+
"canopy:gallery:modal-change",
|
|
847
|
+
handleGalleryModalChange
|
|
848
|
+
);
|
|
849
|
+
}
|
|
784
850
|
};
|
|
785
851
|
}, [iiifContent, disablePanAndZoom, pointOfInterestSvgUrl, viewerOptions]);
|
|
786
852
|
return /* @__PURE__ */ React6.createElement(
|
|
@@ -4630,6 +4696,15 @@ function ReferencedManifestCard({
|
|
|
4630
4696
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
4631
4697
|
var DEFAULT_TRACK_HEIGHT = 640;
|
|
4632
4698
|
var MIN_HEIGHT_PER_POINT = 220;
|
|
4699
|
+
var SCALE_MODES = {
|
|
4700
|
+
TIME: "time",
|
|
4701
|
+
UNIFORM: "uniform"
|
|
4702
|
+
};
|
|
4703
|
+
var ALIGN_OPTIONS = {
|
|
4704
|
+
CENTER: "center",
|
|
4705
|
+
LEFT: "left",
|
|
4706
|
+
RIGHT: "right"
|
|
4707
|
+
};
|
|
4633
4708
|
function getThresholdMs(threshold, granularity) {
|
|
4634
4709
|
const value = Number(threshold);
|
|
4635
4710
|
if (!Number.isFinite(value) || value <= 0) return 0;
|
|
@@ -4819,6 +4894,8 @@ function Timeline({
|
|
|
4819
4894
|
locale: localeProp = "en-US",
|
|
4820
4895
|
height = DEFAULT_TRACK_HEIGHT,
|
|
4821
4896
|
threshold: thresholdProp = null,
|
|
4897
|
+
scale = SCALE_MODES.TIME,
|
|
4898
|
+
align = ALIGN_OPTIONS.CENTER,
|
|
4822
4899
|
steps = null,
|
|
4823
4900
|
points: pointsProp,
|
|
4824
4901
|
__canopyTimeline: payload = null,
|
|
@@ -4853,20 +4930,24 @@ function Timeline({
|
|
|
4853
4930
|
);
|
|
4854
4931
|
const spanStart = effectiveRange.startDate.getTime();
|
|
4855
4932
|
const span = effectiveRange.span;
|
|
4933
|
+
const scaleValue = scale === SCALE_MODES.UNIFORM ? SCALE_MODES.UNIFORM : SCALE_MODES.TIME;
|
|
4934
|
+
const useUniformSpacing = scaleValue === SCALE_MODES.UNIFORM;
|
|
4935
|
+
const alignValue = align === ALIGN_OPTIONS.LEFT ? ALIGN_OPTIONS.LEFT : align === ALIGN_OPTIONS.RIGHT ? ALIGN_OPTIONS.RIGHT : ALIGN_OPTIONS.CENTER;
|
|
4936
|
+
const enforcedSide = alignValue === ALIGN_OPTIONS.LEFT ? "right" : alignValue === ALIGN_OPTIONS.RIGHT ? "left" : null;
|
|
4856
4937
|
const pointsWithPosition = React37.useMemo(() => {
|
|
4857
4938
|
if (!sanitizedPoints.length) return [];
|
|
4858
4939
|
return sanitizedPoints.map((point, index) => {
|
|
4859
4940
|
const timestamp = point.meta.timestamp;
|
|
4860
4941
|
const fallbackProgress = sanitizedPoints.length > 1 ? index / (sanitizedPoints.length - 1) : 0;
|
|
4861
|
-
const progress = Number.isFinite(timestamp) ? clampProgress((timestamp - spanStart) / span) : fallbackProgress;
|
|
4862
|
-
const side = point.side || (index % 2 === 0 ? "left" : "right");
|
|
4942
|
+
const progress = useUniformSpacing ? fallbackProgress : Number.isFinite(timestamp) ? clampProgress((timestamp - spanStart) / span) : fallbackProgress;
|
|
4943
|
+
const side = enforcedSide || point.side || (index % 2 === 0 ? "left" : "right");
|
|
4863
4944
|
return {
|
|
4864
4945
|
...point,
|
|
4865
4946
|
progress,
|
|
4866
4947
|
side
|
|
4867
4948
|
};
|
|
4868
4949
|
});
|
|
4869
|
-
}, [sanitizedPoints, spanStart, span]);
|
|
4950
|
+
}, [sanitizedPoints, spanStart, span, useUniformSpacing, enforcedSide]);
|
|
4870
4951
|
const [activeId, setActiveId] = React37.useState(
|
|
4871
4952
|
() => getActivePointId(pointsWithPosition)
|
|
4872
4953
|
);
|
|
@@ -4913,7 +4994,11 @@ function Timeline({
|
|
|
4913
4994
|
});
|
|
4914
4995
|
}, []);
|
|
4915
4996
|
const trackHeight = resolveTrackHeight(height, pointsWithPosition.length);
|
|
4916
|
-
const containerClasses = [
|
|
4997
|
+
const containerClasses = [
|
|
4998
|
+
"canopy-timeline",
|
|
4999
|
+
alignValue ? `canopy-timeline--align-${alignValue}` : "",
|
|
5000
|
+
className
|
|
5001
|
+
].filter(Boolean).join(" ");
|
|
4917
5002
|
const rangeLabel = formatRangeLabel(effectiveRange);
|
|
4918
5003
|
function renderPointEntry(point) {
|
|
4919
5004
|
if (!point) return null;
|
|
@@ -5677,6 +5762,23 @@ var INLINE_SCRIPT2 = `(() => {
|
|
|
5677
5762
|
const NAV_OPTION_SELECTOR = '[data-canopy-gallery-nav-option]';
|
|
5678
5763
|
const NAV_ITEM_SELECTOR = '[data-canopy-gallery-nav-item]';
|
|
5679
5764
|
|
|
5765
|
+
function emitModalState(modal, state) {
|
|
5766
|
+
if (!modal || typeof window === 'undefined') return;
|
|
5767
|
+
const detail = { modalId: modal.id || '', modal, state };
|
|
5768
|
+
try {
|
|
5769
|
+
const EventCtor = window.CustomEvent || CustomEvent;
|
|
5770
|
+
if (typeof EventCtor === 'function') {
|
|
5771
|
+
window.dispatchEvent(new EventCtor('canopy:gallery:modal-change', { detail }));
|
|
5772
|
+
return;
|
|
5773
|
+
}
|
|
5774
|
+
} catch (_) {}
|
|
5775
|
+
try {
|
|
5776
|
+
const fallback = document.createEvent('CustomEvent');
|
|
5777
|
+
fallback.initCustomEvent('canopy:gallery:modal-change', true, true, detail);
|
|
5778
|
+
window.dispatchEvent(fallback);
|
|
5779
|
+
} catch (_) {}
|
|
5780
|
+
}
|
|
5781
|
+
|
|
5680
5782
|
function isVisible(node) {
|
|
5681
5783
|
return !!(node && (node.offsetWidth || node.offsetHeight || node.getClientRects().length));
|
|
5682
5784
|
}
|
|
@@ -5807,6 +5909,7 @@ var INLINE_SCRIPT2 = `(() => {
|
|
|
5807
5909
|
lockScroll();
|
|
5808
5910
|
document.addEventListener('keydown', handleKeydown, true);
|
|
5809
5911
|
} else if (activeModal !== modal) {
|
|
5912
|
+
emitModalState(activeModal, 'close');
|
|
5810
5913
|
activeModal.removeAttribute('data-canopy-gallery-active');
|
|
5811
5914
|
}
|
|
5812
5915
|
activeModal = modal;
|
|
@@ -5815,6 +5918,7 @@ var INLINE_SCRIPT2 = `(() => {
|
|
|
5815
5918
|
if (!focusActiveNav(modal)) {
|
|
5816
5919
|
focusInitial(modal);
|
|
5817
5920
|
}
|
|
5921
|
+
emitModalState(modal, 'open');
|
|
5818
5922
|
return;
|
|
5819
5923
|
}
|
|
5820
5924
|
if (!activeModal) return;
|
|
@@ -5848,6 +5952,7 @@ var INLINE_SCRIPT2 = `(() => {
|
|
|
5848
5952
|
}
|
|
5849
5953
|
});
|
|
5850
5954
|
}
|
|
5955
|
+
emitModalState(previous, 'close');
|
|
5851
5956
|
}
|
|
5852
5957
|
|
|
5853
5958
|
function modalFromHash() {
|
|
@@ -6306,6 +6411,7 @@ function buildCaptionContent(itemProps) {
|
|
|
6306
6411
|
));
|
|
6307
6412
|
}
|
|
6308
6413
|
function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
|
|
6414
|
+
const { getString, formatString } = useLocale();
|
|
6309
6415
|
const {
|
|
6310
6416
|
props,
|
|
6311
6417
|
modalId,
|
|
@@ -6318,6 +6424,12 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
|
|
|
6318
6424
|
const kicker = props.kicker || props.label || props.eyebrow;
|
|
6319
6425
|
const summary = props.popupDescription || props.modalDescription || props.description || props.summary || null;
|
|
6320
6426
|
const modalTitle = props.popupTitle || props.modalTitle || props.title || `Item ${index + 1}`;
|
|
6427
|
+
const closeButtonText = getString("common.actions.close", "Close");
|
|
6428
|
+
const closeButtonLabel = formatString(
|
|
6429
|
+
"common.phrases.close_content",
|
|
6430
|
+
"Close {content}",
|
|
6431
|
+
{ content: modalTitle }
|
|
6432
|
+
);
|
|
6321
6433
|
return /* @__PURE__ */ React41.createElement(
|
|
6322
6434
|
"div",
|
|
6323
6435
|
{
|
|
@@ -6339,13 +6451,14 @@ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
|
|
|
6339
6451
|
groupName: `${navGroupName || "canopy-gallery"}-${modalId}`
|
|
6340
6452
|
}
|
|
6341
6453
|
), /* @__PURE__ */ React41.createElement(
|
|
6342
|
-
|
|
6454
|
+
Button,
|
|
6343
6455
|
{
|
|
6344
6456
|
className: "canopy-gallery__modal-close",
|
|
6345
6457
|
href: `#${closeTargetId}`,
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6458
|
+
label: closeButtonText,
|
|
6459
|
+
"aria-label": closeButtonLabel,
|
|
6460
|
+
variant: "secondary"
|
|
6461
|
+
}
|
|
6349
6462
|
)), /* @__PURE__ */ React41.createElement("div", { className: "canopy-gallery__modal-panel" }, /* @__PURE__ */ React41.createElement(
|
|
6350
6463
|
"button",
|
|
6351
6464
|
{
|