@canopy-iiif/app 0.10.31 → 0.10.32
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/build/mdx.js +10 -61
- package/lib/components/slider-runtime-entry.js +86 -0
- package/package.json +1 -1
- package/ui/dist/index.mjs +126 -5
- package/ui/dist/index.mjs.map +4 -4
- package/ui/dist/server.mjs +190 -23
- package/ui/dist/server.mjs.map +4 -4
- package/ui/styles/components/_interstitial-hero.scss +22 -48
- package/ui/styles/index.css +20 -31
package/lib/build/mdx.js
CHANGED
|
@@ -821,6 +821,11 @@ async function ensureFacetsRuntime() {
|
|
|
821
821
|
const entry = `
|
|
822
822
|
function ready(fn){ if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',fn,{once:true}); else fn(); }
|
|
823
823
|
function parseProps(el){ try{ const s=el.querySelector('script[type="application/json"]'); if(s) return JSON.parse(s.textContent||'{}'); }catch(_){ } return {}; }
|
|
824
|
+
function buildSliderProps(iiifContent, options){
|
|
825
|
+
const props = { iiifContent };
|
|
826
|
+
if (options && typeof options === 'object') props.options = options;
|
|
827
|
+
return props;
|
|
828
|
+
}
|
|
824
829
|
function rootBase(){
|
|
825
830
|
try {
|
|
826
831
|
var bp = (window && window.CANOPY_BASE_PATH) ? String(window.CANOPY_BASE_PATH) : '';
|
|
@@ -851,6 +856,7 @@ async function ensureFacetsRuntime() {
|
|
|
851
856
|
const topN = Number(props.top || 3) || 3;
|
|
852
857
|
const ver = await getApiVersion();
|
|
853
858
|
const verQ = ver ? ('?v=' + encodeURIComponent(ver)) : '';
|
|
859
|
+
const sliderOptions = (props && typeof props.sliderOptions === 'object') ? props.sliderOptions : null;
|
|
854
860
|
const res = await fetch(rootBase() + '/api/search/facets.json' + verQ).catch(()=>null);
|
|
855
861
|
if(!res || !res.ok) return;
|
|
856
862
|
const json = await res.json().catch(()=>null);
|
|
@@ -873,7 +879,7 @@ async function ensureFacetsRuntime() {
|
|
|
873
879
|
const wrap = document.createElement('div');
|
|
874
880
|
wrap.setAttribute('data-facet-label', entry.label);
|
|
875
881
|
wrap.setAttribute('class', 'canopy-slider');
|
|
876
|
-
const ph = makeSliderPlaceholder(
|
|
882
|
+
const ph = makeSliderPlaceholder(buildSliderProps(rootBase() + '/api/facet/' + (allow.slug) + '/' + pick.valueSlug + '.json' + verQ, sliderOptions));
|
|
877
883
|
if (ph) wrap.appendChild(ph);
|
|
878
884
|
el.appendChild(wrap);
|
|
879
885
|
});
|
|
@@ -887,7 +893,7 @@ async function ensureFacetsRuntime() {
|
|
|
887
893
|
const wrap = document.createElement('div');
|
|
888
894
|
wrap.setAttribute('data-facet-label', s.label);
|
|
889
895
|
wrap.setAttribute('class', 'canopy-slider');
|
|
890
|
-
const ph = makeSliderPlaceholder(
|
|
896
|
+
const ph = makeSliderPlaceholder(buildSliderProps(rootBase() + '/api/facet/' + s.labelSlug + '/' + s.valueSlug + '.json' + verQ, sliderOptions));
|
|
891
897
|
if (ph) wrap.appendChild(ph);
|
|
892
898
|
el.appendChild(wrap);
|
|
893
899
|
});
|
|
@@ -949,59 +955,7 @@ async function ensureSliderRuntime() {
|
|
|
949
955
|
const scriptsDir = path.join(OUT_DIR, "scripts");
|
|
950
956
|
ensureDirSync(scriptsDir);
|
|
951
957
|
const outFile = path.join(scriptsDir, "canopy-slider.js");
|
|
952
|
-
const
|
|
953
|
-
import CloverSlider from '@samvera/clover-iiif/slider';
|
|
954
|
-
import 'swiper/css';
|
|
955
|
-
import 'swiper/css/navigation';
|
|
956
|
-
import 'swiper/css/pagination';
|
|
957
|
-
|
|
958
|
-
function ready(fn) {
|
|
959
|
-
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn, { once: true });
|
|
960
|
-
else fn();
|
|
961
|
-
}
|
|
962
|
-
function parseProps(el) {
|
|
963
|
-
try {
|
|
964
|
-
const s = el.querySelector('script[type="application/json"]');
|
|
965
|
-
if (s) return JSON.parse(s.textContent || '{}');
|
|
966
|
-
const raw = el.getAttribute('data-props') || '{}';
|
|
967
|
-
return JSON.parse(raw);
|
|
968
|
-
} catch (_) { return {}; }
|
|
969
|
-
}
|
|
970
|
-
function mount(el){
|
|
971
|
-
try{
|
|
972
|
-
if (!el || el.getAttribute('data-canopy-slider-mounted')==='1') return;
|
|
973
|
-
const React = (window && window.React) || null;
|
|
974
|
-
const ReactDOMClient = (window && window.ReactDOMClient) || null;
|
|
975
|
-
const createRoot = ReactDOMClient && ReactDOMClient.createRoot;
|
|
976
|
-
if (!React || !createRoot) return;
|
|
977
|
-
const props = parseProps(el);
|
|
978
|
-
const root = createRoot(el);
|
|
979
|
-
root.render(React.createElement(CloverSlider, props));
|
|
980
|
-
el.setAttribute('data-canopy-slider-mounted','1');
|
|
981
|
-
} catch(_){}
|
|
982
|
-
}
|
|
983
|
-
function scan(){
|
|
984
|
-
try{ document.querySelectorAll('[data-canopy-slider]:not([data-canopy-slider-mounted="1"])').forEach(mount); }catch(_){ }
|
|
985
|
-
}
|
|
986
|
-
function observe(){
|
|
987
|
-
try{
|
|
988
|
-
const obs = new MutationObserver((muts)=>{
|
|
989
|
-
const toMount = [];
|
|
990
|
-
for (const m of muts){
|
|
991
|
-
m.addedNodes && m.addedNodes.forEach((n)=>{
|
|
992
|
-
if (!(n instanceof Element)) return;
|
|
993
|
-
if (n.matches && n.matches('[data-canopy-slider]')) toMount.push(n);
|
|
994
|
-
const inner = n.querySelectorAll ? n.querySelectorAll('[data-canopy-slider]') : [];
|
|
995
|
-
inner && inner.forEach && inner.forEach((x)=> toMount.push(x));
|
|
996
|
-
});
|
|
997
|
-
}
|
|
998
|
-
if (toMount.length) Promise.resolve().then(()=> toMount.forEach(mount));
|
|
999
|
-
});
|
|
1000
|
-
obs.observe(document.documentElement || document.body, { childList: true, subtree: true });
|
|
1001
|
-
}catch(_){ }
|
|
1002
|
-
}
|
|
1003
|
-
ready(function(){ scan(); observe(); });
|
|
1004
|
-
`;
|
|
958
|
+
const entryFile = path.join(__dirname, "../components/slider-runtime-entry.js");
|
|
1005
959
|
const reactShim = `
|
|
1006
960
|
const React = (typeof window !== 'undefined' && window.React) || {};
|
|
1007
961
|
export default React;
|
|
@@ -1079,12 +1033,7 @@ async function ensureSliderRuntime() {
|
|
|
1079
1033
|
};
|
|
1080
1034
|
try {
|
|
1081
1035
|
await esbuild.build({
|
|
1082
|
-
|
|
1083
|
-
contents: entry,
|
|
1084
|
-
resolveDir: process.cwd(),
|
|
1085
|
-
sourcefile: "canopy-slider-entry.js",
|
|
1086
|
-
loader: "js",
|
|
1087
|
-
},
|
|
1036
|
+
entryPoints: [entryFile],
|
|
1088
1037
|
outfile: outFile,
|
|
1089
1038
|
platform: "browser",
|
|
1090
1039
|
format: "iife",
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import CloverSlider from '@samvera/clover-iiif/slider';
|
|
4
|
+
import 'swiper/css';
|
|
5
|
+
import 'swiper/css/navigation';
|
|
6
|
+
import 'swiper/css/pagination';
|
|
7
|
+
import { mergeSliderOptions, normalizeSliderOptions } from '../../ui/src/iiif/sliderOptions.js';
|
|
8
|
+
|
|
9
|
+
function ready(fn) {
|
|
10
|
+
if (document.readyState === 'loading') {
|
|
11
|
+
document.addEventListener('DOMContentLoaded', fn, { once: true });
|
|
12
|
+
} else {
|
|
13
|
+
fn();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function parseProps(el) {
|
|
18
|
+
try {
|
|
19
|
+
const script = el.querySelector('script[type="application/json"]');
|
|
20
|
+
if (script) return JSON.parse(script.textContent || '{}');
|
|
21
|
+
const raw = el.getAttribute('data-props') || '{}';
|
|
22
|
+
return JSON.parse(raw);
|
|
23
|
+
} catch (_) {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function withDefaults(rawProps) {
|
|
29
|
+
const props = rawProps && typeof rawProps === 'object' ? rawProps : {};
|
|
30
|
+
const className = ['canopy-slider', props.className]
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.join(' ');
|
|
33
|
+
const mergedOptions = mergeSliderOptions(props.options);
|
|
34
|
+
return {
|
|
35
|
+
...props,
|
|
36
|
+
className,
|
|
37
|
+
options: normalizeSliderOptions(mergedOptions),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function mount(el) {
|
|
42
|
+
try {
|
|
43
|
+
if (!el || el.getAttribute('data-canopy-slider-mounted') === '1') return;
|
|
44
|
+
const props = withDefaults(parseProps(el));
|
|
45
|
+
const root = createRoot(el);
|
|
46
|
+
root.render(React.createElement(CloverSlider, props));
|
|
47
|
+
el.setAttribute('data-canopy-slider-mounted', '1');
|
|
48
|
+
} catch (_) {}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function scan() {
|
|
52
|
+
try {
|
|
53
|
+
document
|
|
54
|
+
.querySelectorAll('[data-canopy-slider]:not([data-canopy-slider-mounted="1"])')
|
|
55
|
+
.forEach(mount);
|
|
56
|
+
} catch (_) {}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function observe() {
|
|
60
|
+
try {
|
|
61
|
+
const obs = new MutationObserver((mutations) => {
|
|
62
|
+
const toMount = [];
|
|
63
|
+
mutations.forEach((mutation) => {
|
|
64
|
+
mutation.addedNodes &&
|
|
65
|
+
mutation.addedNodes.forEach((node) => {
|
|
66
|
+
if (!(node instanceof Element)) return;
|
|
67
|
+
if (node.matches && node.matches('[data-canopy-slider]')) toMount.push(node);
|
|
68
|
+
const inner = node.querySelectorAll
|
|
69
|
+
? node.querySelectorAll('[data-canopy-slider]')
|
|
70
|
+
: [];
|
|
71
|
+
inner && inner.forEach && inner.forEach((x) => toMount.push(x));
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
if (toMount.length) Promise.resolve().then(() => toMount.forEach(mount));
|
|
75
|
+
});
|
|
76
|
+
obs.observe(document.documentElement || document.body, {
|
|
77
|
+
childList: true,
|
|
78
|
+
subtree: true,
|
|
79
|
+
});
|
|
80
|
+
} catch (_) {}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
ready(function onReady() {
|
|
84
|
+
scan();
|
|
85
|
+
observe();
|
|
86
|
+
});
|
package/package.json
CHANGED
package/ui/dist/index.mjs
CHANGED
|
@@ -1241,7 +1241,120 @@ var Viewer = (props) => {
|
|
|
1241
1241
|
|
|
1242
1242
|
// ui/src/iiif/Slider.jsx
|
|
1243
1243
|
import React17, { useEffect as useEffect3, useState as useState3 } from "react";
|
|
1244
|
-
|
|
1244
|
+
|
|
1245
|
+
// ui/src/iiif/sliderOptions.js
|
|
1246
|
+
var UNIT_TOKEN = "__canopySliderUnit";
|
|
1247
|
+
var UNIT_REM = "rem";
|
|
1248
|
+
var DEFAULT_FONT_SIZE = 16;
|
|
1249
|
+
var cachedRootFontSize = null;
|
|
1250
|
+
var sliderOptions = {
|
|
1251
|
+
breakpoints: {
|
|
1252
|
+
400: {
|
|
1253
|
+
slidesPerView: 2,
|
|
1254
|
+
spaceBetween: rem(1)
|
|
1255
|
+
},
|
|
1256
|
+
640: {
|
|
1257
|
+
slidesPerView: 3,
|
|
1258
|
+
spaceBetween: rem(1.618)
|
|
1259
|
+
},
|
|
1260
|
+
1024: {
|
|
1261
|
+
slidesPerView: 4,
|
|
1262
|
+
spaceBetween: rem(1.618)
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
function rem(value) {
|
|
1267
|
+
const numeric = typeof value === "number" ? value : parseFloat(value);
|
|
1268
|
+
return {
|
|
1269
|
+
[UNIT_TOKEN]: UNIT_REM,
|
|
1270
|
+
value: Number.isFinite(numeric) ? numeric : 0
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
function cloneBreakpoints(source) {
|
|
1274
|
+
if (!source || typeof source !== "object") return void 0;
|
|
1275
|
+
const clone = {};
|
|
1276
|
+
Object.entries(source).forEach(([key, entry]) => {
|
|
1277
|
+
clone[key] = entry && typeof entry === "object" ? { ...entry } : {};
|
|
1278
|
+
});
|
|
1279
|
+
return clone;
|
|
1280
|
+
}
|
|
1281
|
+
function cloneOptions(options = {}) {
|
|
1282
|
+
const clone = { ...options };
|
|
1283
|
+
if (options.breakpoints && typeof options.breakpoints === "object") {
|
|
1284
|
+
clone.breakpoints = cloneBreakpoints(options.breakpoints);
|
|
1285
|
+
}
|
|
1286
|
+
return clone;
|
|
1287
|
+
}
|
|
1288
|
+
function mergeSliderOptions(overrides) {
|
|
1289
|
+
const base = cloneOptions(sliderOptions);
|
|
1290
|
+
const incoming = cloneOptions(overrides || {});
|
|
1291
|
+
const merged = {
|
|
1292
|
+
...base,
|
|
1293
|
+
...incoming
|
|
1294
|
+
};
|
|
1295
|
+
if (base.breakpoints || incoming.breakpoints) {
|
|
1296
|
+
merged.breakpoints = {
|
|
1297
|
+
...base.breakpoints || {},
|
|
1298
|
+
...incoming.breakpoints || {}
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
return merged;
|
|
1302
|
+
}
|
|
1303
|
+
function hasBrowserEnv() {
|
|
1304
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
1305
|
+
}
|
|
1306
|
+
function measureRootFontSize() {
|
|
1307
|
+
if (!hasBrowserEnv()) return DEFAULT_FONT_SIZE;
|
|
1308
|
+
if (cachedRootFontSize !== null) return cachedRootFontSize;
|
|
1309
|
+
let size = DEFAULT_FONT_SIZE;
|
|
1310
|
+
try {
|
|
1311
|
+
const root = window.document && window.document.documentElement;
|
|
1312
|
+
if (root && window.getComputedStyle) {
|
|
1313
|
+
const computed = window.getComputedStyle(root).fontSize;
|
|
1314
|
+
const parsed = parseFloat(computed);
|
|
1315
|
+
if (Number.isFinite(parsed)) size = parsed;
|
|
1316
|
+
}
|
|
1317
|
+
} catch (_) {
|
|
1318
|
+
size = DEFAULT_FONT_SIZE;
|
|
1319
|
+
}
|
|
1320
|
+
cachedRootFontSize = size;
|
|
1321
|
+
return size;
|
|
1322
|
+
}
|
|
1323
|
+
function convertSpacing(value) {
|
|
1324
|
+
if (!hasBrowserEnv()) return value;
|
|
1325
|
+
if (value && typeof value === "object" && value[UNIT_TOKEN] === UNIT_REM) {
|
|
1326
|
+
const remValue = typeof value.value === "number" ? value.value : parseFloat(value.value);
|
|
1327
|
+
if (!Number.isFinite(remValue)) return value;
|
|
1328
|
+
return remValue * measureRootFontSize();
|
|
1329
|
+
}
|
|
1330
|
+
return value;
|
|
1331
|
+
}
|
|
1332
|
+
function normalizeBreakpoints(breakpoints) {
|
|
1333
|
+
if (!breakpoints || typeof breakpoints !== "object") return breakpoints;
|
|
1334
|
+
const normalized = {};
|
|
1335
|
+
Object.entries(breakpoints).forEach(([key, entry]) => {
|
|
1336
|
+
const clone = entry && typeof entry === "object" ? { ...entry } : {};
|
|
1337
|
+
if (Object.prototype.hasOwnProperty.call(clone, "spaceBetween")) {
|
|
1338
|
+
clone.spaceBetween = convertSpacing(clone.spaceBetween);
|
|
1339
|
+
}
|
|
1340
|
+
normalized[key] = clone;
|
|
1341
|
+
});
|
|
1342
|
+
return normalized;
|
|
1343
|
+
}
|
|
1344
|
+
function normalizeSliderOptions(options) {
|
|
1345
|
+
const clone = cloneOptions(options || {});
|
|
1346
|
+
if (!hasBrowserEnv()) return clone;
|
|
1347
|
+
if (Object.prototype.hasOwnProperty.call(clone, "spaceBetween")) {
|
|
1348
|
+
clone.spaceBetween = convertSpacing(clone.spaceBetween);
|
|
1349
|
+
}
|
|
1350
|
+
if (clone.breakpoints) {
|
|
1351
|
+
clone.breakpoints = normalizeBreakpoints(clone.breakpoints);
|
|
1352
|
+
}
|
|
1353
|
+
return clone;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
// ui/src/iiif/Slider.jsx
|
|
1357
|
+
var Slider = (props = {}) => {
|
|
1245
1358
|
const [CloverSlider, setCloverSlider] = useState3(null);
|
|
1246
1359
|
useEffect3(() => {
|
|
1247
1360
|
let mounted = true;
|
|
@@ -1249,7 +1362,6 @@ var Slider = (props) => {
|
|
|
1249
1362
|
if (canUseDom) {
|
|
1250
1363
|
import("@samvera/clover-iiif/slider").then((mod) => {
|
|
1251
1364
|
if (!mounted) return;
|
|
1252
|
-
console.log(mod);
|
|
1253
1365
|
const Comp = mod && (mod.default || mod.Slider || mod);
|
|
1254
1366
|
setCloverSlider(() => Comp);
|
|
1255
1367
|
}).catch(() => {
|
|
@@ -1259,14 +1371,23 @@ var Slider = (props) => {
|
|
|
1259
1371
|
mounted = false;
|
|
1260
1372
|
};
|
|
1261
1373
|
}, []);
|
|
1374
|
+
const { className, ...rest } = props || {};
|
|
1375
|
+
const sliderClassName = ["canopy-slider", className].filter(Boolean).join(" ");
|
|
1376
|
+
const mergedOptions = mergeSliderOptions(rest.options);
|
|
1377
|
+
const normalizedOptions = normalizeSliderOptions(mergedOptions);
|
|
1378
|
+
const resolvedProps = {
|
|
1379
|
+
...rest,
|
|
1380
|
+
className: sliderClassName,
|
|
1381
|
+
options: normalizedOptions
|
|
1382
|
+
};
|
|
1262
1383
|
if (!CloverSlider) {
|
|
1263
1384
|
let json = "{}";
|
|
1264
1385
|
try {
|
|
1265
|
-
json = JSON.stringify(
|
|
1386
|
+
json = JSON.stringify(resolvedProps || {});
|
|
1266
1387
|
} catch (_) {
|
|
1267
1388
|
json = "{}";
|
|
1268
1389
|
}
|
|
1269
|
-
return /* @__PURE__ */ React17.createElement("div", { className:
|
|
1390
|
+
return /* @__PURE__ */ React17.createElement("div", { className: sliderClassName, "data-canopy-slider": "1" }, /* @__PURE__ */ React17.createElement(
|
|
1270
1391
|
"script",
|
|
1271
1392
|
{
|
|
1272
1393
|
type: "application/json",
|
|
@@ -1274,7 +1395,7 @@ var Slider = (props) => {
|
|
|
1274
1395
|
}
|
|
1275
1396
|
));
|
|
1276
1397
|
}
|
|
1277
|
-
return /* @__PURE__ */ React17.createElement(CloverSlider, { ...
|
|
1398
|
+
return /* @__PURE__ */ React17.createElement(CloverSlider, { ...resolvedProps });
|
|
1278
1399
|
};
|
|
1279
1400
|
|
|
1280
1401
|
// ui/src/iiif/Scroll.jsx
|