@canopy-iiif/app 0.10.31 → 0.11.0

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/dev.js CHANGED
@@ -3,6 +3,12 @@ const fsp = fs.promises;
3
3
  const path = require("path");
4
4
  const { spawn, spawnSync } = require("child_process");
5
5
  const http = require("http");
6
+ let sass = null;
7
+ try {
8
+ sass = require("sass");
9
+ } catch (_) {
10
+ sass = null;
11
+ }
6
12
  const {
7
13
  CONTENT_DIR,
8
14
  OUT_DIR,
@@ -29,6 +35,13 @@ const UI_DIST_DIR = path.resolve(path.join(__dirname, "../../ui/dist"));
29
35
  const APP_PACKAGE_ROOT = path.resolve(path.join(__dirname, "..", ".."));
30
36
  const APP_LIB_DIR = path.join(APP_PACKAGE_ROOT, "lib");
31
37
  const APP_UI_DIR = path.join(APP_PACKAGE_ROOT, "ui");
38
+ let loadUiTheme = null;
39
+ try {
40
+ const uiTheme = require(path.join(APP_UI_DIR, "theme.js"));
41
+ if (uiTheme && typeof uiTheme.loadCanopyTheme === "function") {
42
+ loadUiTheme = uiTheme.loadCanopyTheme;
43
+ }
44
+ } catch (_) {}
32
45
  const APP_WATCH_TARGETS = [
33
46
  { dir: APP_LIB_DIR, label: "@canopy-iiif/app/lib" },
34
47
  { dir: APP_UI_DIR, label: "@canopy-iiif/app/ui" },
@@ -1025,6 +1038,7 @@ async function dev() {
1025
1038
  );
1026
1039
  const uiStylesDir = path.join(APP_UI_DIR, "styles");
1027
1040
  const uiStylesCss = path.join(uiStylesDir, "index.css");
1041
+ const uiStylesEntry = path.join(uiStylesDir, "index.scss");
1028
1042
  const pluginFiles = [uiPlugin, uiPreset].filter((p) => {
1029
1043
  try {
1030
1044
  return fs.existsSync(p);
@@ -1056,6 +1070,36 @@ async function dev() {
1056
1070
  });
1057
1071
  } catch (_) {}
1058
1072
  }
1073
+ const rebuildUiStyles = () => {
1074
+ if (!sass || !fs.existsSync(uiStylesEntry)) return false;
1075
+ try {
1076
+ const theme = loadUiTheme ? loadUiTheme({ cwd: process.cwd() }) : null;
1077
+ const source = `${
1078
+ theme && theme.sassConfig ? theme.sassConfig : ""
1079
+ }@use 'index';`;
1080
+ const result = sass.compileString(source, {
1081
+ loadPaths: [uiStylesDir],
1082
+ style: "expanded",
1083
+ });
1084
+ let cssOutput = result && result.css ? result.css : "";
1085
+ const themeCss = theme && theme.css ? theme.css.trim() : "";
1086
+ if (themeCss) {
1087
+ cssOutput = `/* canopy-theme */\n${themeCss}\n/* canopy-theme:end */\n${cssOutput}`;
1088
+ }
1089
+ fs.writeFileSync(uiStylesCss, cssOutput, "utf8");
1090
+ console.log(
1091
+ "[tailwind] rebuilt @canopy-iiif/app/ui styles →",
1092
+ prettyPath(uiStylesCss)
1093
+ );
1094
+ return true;
1095
+ } catch (err) {
1096
+ console.warn(
1097
+ "[tailwind] failed to rebuild @canopy-iiif/app/ui styles:",
1098
+ err && err.message ? err.message : err
1099
+ );
1100
+ return false;
1101
+ }
1102
+ };
1059
1103
  const attachCssWatcher = () => {
1060
1104
  if (uiCssWatcherAttached) {
1061
1105
  if (fs.existsSync(uiStylesCss)) return;
@@ -1080,11 +1124,15 @@ async function dev() {
1080
1124
  } catch (_) {}
1081
1125
  }
1082
1126
  };
1127
+ if (fs.existsSync(uiStylesEntry)) rebuildUiStyles();
1083
1128
  attachCssWatcher();
1084
1129
  const handleUiSassChange = () => {
1130
+ const ok = rebuildUiStyles();
1085
1131
  attachCssWatcher();
1086
1132
  scheduleTailwindRestart(
1087
- "[tailwind] detected @canopy-iiif/app/ui Sass change — restarting Tailwind",
1133
+ ok
1134
+ ? "[tailwind] detected @canopy-iiif/app/ui Sass change — restarting Tailwind"
1135
+ : "[tailwind] Sass compile failed — attempting Tailwind restart",
1088
1136
  "[tailwind] compile after UI Sass change failed"
1089
1137
  );
1090
1138
  };
@@ -1148,16 +1196,66 @@ async function dev() {
1148
1196
  const stylesDir = path.dirname(inputCss);
1149
1197
  if (stylesDir && stylesDir.includes(path.join("app", "styles"))) {
1150
1198
  let cssDebounce = null;
1151
- try {
1152
- fs.watch(stylesDir, { persistent: false }, (evt, fn) => {
1153
- clearTimeout(cssDebounce);
1154
- cssDebounce = setTimeout(() => {
1155
- try { onBuildStart(); } catch (_) {}
1156
- safeCompile("[tailwind] compile after CSS change failed");
1157
- try { onCssChange(); } catch (_) {}
1158
- }, 50);
1159
- });
1160
- } catch (_) {}
1199
+ const triggerCssRebuild = () => {
1200
+ clearTimeout(cssDebounce);
1201
+ cssDebounce = setTimeout(() => {
1202
+ try { onBuildStart(); } catch (_) {}
1203
+ safeCompile("[tailwind] compile after CSS change failed");
1204
+ try { onCssChange(); } catch (_) {}
1205
+ }, 50);
1206
+ };
1207
+ const shouldHandle = (filename) => {
1208
+ if (!filename) return true;
1209
+ return /\.(css|s[ac]ss)$/i.test(String(filename));
1210
+ };
1211
+ const attachRecursiveWatch = () => {
1212
+ try {
1213
+ fs.watch(
1214
+ stylesDir,
1215
+ { persistent: false, recursive: true },
1216
+ (evt, fn) => {
1217
+ if (!shouldHandle(fn)) return;
1218
+ triggerCssRebuild();
1219
+ }
1220
+ );
1221
+ return true;
1222
+ } catch (_) {
1223
+ return false;
1224
+ }
1225
+ };
1226
+ if (!attachRecursiveWatch()) {
1227
+ const watchers = new Map();
1228
+ function watchDir(dir) {
1229
+ if (watchers.has(dir)) return;
1230
+ try {
1231
+ const watcher = fs.watch(
1232
+ dir,
1233
+ { persistent: false },
1234
+ (evt, fn) => {
1235
+ if (shouldHandle(fn)) triggerCssRebuild();
1236
+ scanDir(dir);
1237
+ }
1238
+ );
1239
+ watchers.set(dir, watcher);
1240
+ } catch (_) {}
1241
+ }
1242
+ function scanDir(dir) {
1243
+ let entries = [];
1244
+ try {
1245
+ entries = fs.readdirSync(dir, { withFileTypes: true });
1246
+ } catch (_) {
1247
+ return;
1248
+ }
1249
+ for (const entry of entries) {
1250
+ if (!entry || !entry.isDirectory()) continue;
1251
+ const next = path.join(dir, entry.name);
1252
+ watchDir(next);
1253
+ scanDir(next);
1254
+ }
1255
+ }
1256
+ watchDir(stylesDir);
1257
+ scanDir(stylesDir);
1258
+ }
1161
1259
  }
1162
1260
  } catch (err) {
1163
1261
  console.error("[tailwind] setup failed:", err && err.message ? err.message : err);
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({ iiifContent: rootBase() + '/api/facet/' + (allow.slug) + '/' + pick.valueSlug + '.json' + verQ });
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({ iiifContent: rootBase() + '/api/facet/' + s.labelSlug + '/' + s.valueSlug + '.json' + verQ });
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 entry = `
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
- stdin: {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canopy-iiif/app",
3
- "version": "0.10.31",
3
+ "version": "0.11.0",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Mat Jordan <mat@northwestern.edu>",
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
- var Slider = (props) => {
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(props || {});
1386
+ json = JSON.stringify(resolvedProps || {});
1266
1387
  } catch (_) {
1267
1388
  json = "{}";
1268
1389
  }
1269
- return /* @__PURE__ */ React17.createElement("div", { className: "canopy-slider", "data-canopy-slider": "1" }, /* @__PURE__ */ React17.createElement(
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, { ...props, className: "canopy-slider" });
1398
+ return /* @__PURE__ */ React17.createElement(CloverSlider, { ...resolvedProps });
1278
1399
  };
1279
1400
 
1280
1401
  // ui/src/iiif/Scroll.jsx