@canopy-iiif/app 1.8.8 → 1.8.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canopy-iiif/app",
3
- "version": "1.8.8",
3
+ "version": "1.8.9",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Mat Jordan <mat@northwestern.edu>",
package/ui/dist/index.mjs CHANGED
@@ -4236,6 +4236,9 @@ var INLINE_SCRIPT = `(() => {
4236
4236
  return window.setTimeout(cb, 0);
4237
4237
  };
4238
4238
  let activeModal = null;
4239
+ const NAV_SELECTOR = '[data-canopy-gallery-nav]';
4240
+ const NAV_OPTION_SELECTOR = '[data-canopy-gallery-nav-option]';
4241
+ const NAV_ITEM_SELECTOR = '[data-canopy-gallery-nav-item]';
4239
4242
 
4240
4243
  function isVisible(node) {
4241
4244
  return !!(node && (node.offsetWidth || node.offsetHeight || node.getClientRects().length));
@@ -4264,6 +4267,40 @@ var INLINE_SCRIPT = `(() => {
4264
4267
  }
4265
4268
  }
4266
4269
 
4270
+ function resetModalScroll(modal) {
4271
+ if (!modal) return;
4272
+ const panel = modal.querySelector('.canopy-gallery__modal-panel');
4273
+ if (panel) {
4274
+ panel.scrollTop = 0;
4275
+ panel.scrollLeft = 0;
4276
+ }
4277
+ }
4278
+
4279
+ function getOptionItem(option) {
4280
+ if (!option || typeof option.closest !== 'function') return null;
4281
+ return option.closest(NAV_ITEM_SELECTOR);
4282
+ }
4283
+
4284
+ function focusActiveNav(modal) {
4285
+ if (!modal) return false;
4286
+ const nav = modal.querySelector(NAV_SELECTOR);
4287
+ if (!nav) return false;
4288
+ const activeOption =
4289
+ nav.querySelector(NAV_OPTION_SELECTOR + ':checked') ||
4290
+ nav.querySelector(NAV_OPTION_SELECTOR);
4291
+ if (!activeOption) return false;
4292
+ raf(() => {
4293
+ try {
4294
+ activeOption.focus({preventScroll: true});
4295
+ } catch (_) {
4296
+ try {
4297
+ activeOption.focus();
4298
+ } catch (err) {}
4299
+ }
4300
+ });
4301
+ return true;
4302
+ }
4303
+
4267
4304
  function focusInitial(modal) {
4268
4305
  if (!modal) return;
4269
4306
  const focusables = getFocusable(modal);
@@ -4337,7 +4374,10 @@ var INLINE_SCRIPT = `(() => {
4337
4374
  }
4338
4375
  activeModal = modal;
4339
4376
  modal.setAttribute('data-canopy-gallery-active', '1');
4340
- focusInitial(modal);
4377
+ resetModalScroll(modal);
4378
+ if (!focusActiveNav(modal)) {
4379
+ focusInitial(modal);
4380
+ }
4341
4381
  return;
4342
4382
  }
4343
4383
  if (!activeModal) return;
@@ -4390,9 +4430,266 @@ var INLINE_SCRIPT = `(() => {
4390
4430
  }
4391
4431
  }
4392
4432
 
4393
- window.addEventListener('hashchange', syncFromHash);
4394
- window.addEventListener('pageshow', syncFromHash);
4433
+ function initGalleryNav(nav) {
4434
+ if (!nav || nav.getAttribute('data-canopy-gallery-nav-bound') === '1') {
4435
+ return;
4436
+ }
4437
+ const viewport =
4438
+ nav.querySelector('[data-canopy-gallery-nav-viewport]') ||
4439
+ nav.querySelector('[data-canopy-gallery-nav-track]');
4440
+ if (!viewport) return;
4441
+ const optionNodes = nav.querySelectorAll(NAV_OPTION_SELECTOR);
4442
+ const navOptions = optionNodes ? Array.prototype.slice.call(optionNodes) : [];
4443
+ if (!navOptions.length) return;
4444
+ nav.setAttribute('data-canopy-gallery-nav-bound', '1');
4445
+ const prevBtn = nav.querySelector('[data-canopy-gallery-nav-prev]');
4446
+ const nextBtn = nav.querySelector('[data-canopy-gallery-nav-next]');
4447
+
4448
+ function updateButtons() {
4449
+ if (prevBtn) prevBtn.disabled = false;
4450
+ if (nextBtn) nextBtn.disabled = false;
4451
+ }
4452
+
4453
+ function getOptionLabel(option) {
4454
+ if (!option) return null;
4455
+ let label = option.nextElementSibling;
4456
+ if (label && label.tagName && label.tagName.toLowerCase() === 'label') {
4457
+ return label;
4458
+ }
4459
+ if (option.id) {
4460
+ try {
4461
+ label = nav.querySelector('label[for="' + escapeSelector(option.id) + '"]');
4462
+ if (label) return label;
4463
+ } catch (_) {}
4464
+ }
4465
+ return null;
4466
+ }
4467
+
4468
+ function getTargetIdFromOption(option) {
4469
+ if (!option) return '';
4470
+ const dataId = option.getAttribute('data-canopy-gallery-nav-modal');
4471
+ if (dataId) return String(dataId);
4472
+ const value = option.value || option.getAttribute('value') || '';
4473
+ return String(value);
4474
+ }
4475
+
4476
+ function focusOption(option) {
4477
+ if (!option) return;
4478
+ try {
4479
+ option.focus({preventScroll: true});
4480
+ } catch (_) {
4481
+ try {
4482
+ option.focus();
4483
+ } catch (err) {}
4484
+ }
4485
+ }
4486
+
4487
+ function getActiveIndex() {
4488
+ const currentId = window.location.hash.replace(/^#/, '');
4489
+ if (!currentId) return 0;
4490
+ for (let i = 0; i < navOptions.length; i += 1) {
4491
+ if (getTargetIdFromOption(navOptions[i]) === currentId) {
4492
+ return i;
4493
+ }
4494
+ }
4495
+ return 0;
4496
+ }
4497
+
4498
+ function scrollOptionIntoView(option) {
4499
+ const label = getOptionLabel(option);
4500
+ const target = label || option;
4501
+ if (!target) return;
4502
+ try {
4503
+ target.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'center'});
4504
+ } catch (_) {
4505
+ try {
4506
+ target.scrollIntoView();
4507
+ } catch (err) {}
4508
+ }
4509
+ }
4510
+
4511
+ function activateOption(option, opts = {}) {
4512
+ if (!option) return;
4513
+ const targetId = getTargetIdFromOption(option);
4514
+ if (!targetId) return;
4515
+ const targetHash = '#' + targetId;
4516
+ syncActiveState({targetHash, reveal: true, focus: !!opts.focus});
4517
+ if (window.location.hash === targetHash) {
4518
+ try {
4519
+ window.location.hash = targetHash;
4520
+ } catch (_) {}
4521
+ } else {
4522
+ window.location.hash = targetHash;
4523
+ }
4524
+ }
4525
+
4526
+ function openByOffset(direction) {
4527
+ const total = navOptions.length;
4528
+ if (!total) return;
4529
+ const currentIndex = getActiveIndex();
4530
+ const nextIndex = (currentIndex + direction + total) % total;
4531
+ const nextOption = navOptions[nextIndex];
4532
+ if (!nextOption) return;
4533
+ activateOption(nextOption, {focus: true});
4534
+ }
4535
+
4536
+ function syncActiveState(options) {
4537
+ const targetHash =
4538
+ (options && options.targetHash) || window.location.hash || '';
4539
+ const normalized = String(targetHash)
4540
+ .split('#')
4541
+ .pop()
4542
+ .replace(/^#/, '');
4543
+ let activeIndex = -1;
4544
+ let activeOption = null;
4545
+ navOptions.forEach((option, index) => {
4546
+ const linkTarget = getTargetIdFromOption(option);
4547
+ const isActive = normalized && linkTarget === normalized;
4548
+ const label = getOptionLabel(option);
4549
+ const navItem = getOptionItem(option);
4550
+ if (isActive) {
4551
+ activeIndex = index;
4552
+ activeOption = option;
4553
+ option.checked = true;
4554
+ option.setAttribute('checked', 'checked');
4555
+ option.setAttribute('data-canopy-gallery-nav-active', '1');
4556
+ option.setAttribute('data-canopy-gallery-nav-selected', '1');
4557
+ option.tabIndex = 0;
4558
+ if (label) {
4559
+ label.setAttribute('data-canopy-gallery-nav-active', '1');
4560
+ }
4561
+ if (navItem) {
4562
+ navItem.setAttribute('data-canopy-gallery-nav-selected', '1');
4563
+ }
4564
+ } else {
4565
+ option.checked = false;
4566
+ option.removeAttribute('checked');
4567
+ option.removeAttribute('data-canopy-gallery-nav-active');
4568
+ option.removeAttribute('data-canopy-gallery-nav-selected');
4569
+ option.tabIndex = -1;
4570
+ if (label) {
4571
+ label.removeAttribute('data-canopy-gallery-nav-active');
4572
+ }
4573
+ if (navItem) {
4574
+ navItem.removeAttribute('data-canopy-gallery-nav-selected');
4575
+ }
4576
+ }
4577
+ });
4578
+ if (options && options.reveal && activeIndex >= 0) {
4579
+ scrollOptionIntoView(navOptions[activeIndex]);
4580
+ }
4581
+ if (options && options.focus && activeIndex >= 0) {
4582
+ focusOption(activeOption);
4583
+ }
4584
+ }
4585
+
4586
+ if (prevBtn) {
4587
+ prevBtn.addEventListener('click', function (event) {
4588
+ event.preventDefault();
4589
+ openByOffset(-1);
4590
+ });
4591
+ }
4592
+ if (nextBtn) {
4593
+ nextBtn.addEventListener('click', function (event) {
4594
+ event.preventDefault();
4595
+ openByOffset(1);
4596
+ });
4597
+ }
4598
+
4599
+ viewport.addEventListener('scroll', function () {
4600
+ raf(updateButtons);
4601
+ });
4602
+ window.addEventListener('resize', function () {
4603
+ raf(updateButtons);
4604
+ });
4605
+
4606
+ nav.addEventListener('keydown', function (event) {
4607
+ const target = event.target || event.srcElement;
4608
+ const isOption =
4609
+ target && target.hasAttribute && target.hasAttribute('data-canopy-gallery-nav-option');
4610
+ if (!isOption) return;
4611
+ if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {
4612
+ event.preventDefault();
4613
+ openByOffset(1);
4614
+ return;
4615
+ }
4616
+ if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {
4617
+ event.preventDefault();
4618
+ openByOffset(-1);
4619
+ return;
4620
+ }
4621
+ if (event.key === 'Tab' && !event.shiftKey) {
4622
+ const actions = nav.closest('.canopy-gallery__modal-actions');
4623
+ const closeBtn = actions && actions.querySelector('.canopy-gallery__modal-close');
4624
+ if (closeBtn) {
4625
+ event.preventDefault();
4626
+ try {
4627
+ closeBtn.focus({preventScroll: true});
4628
+ } catch (_) {
4629
+ try {
4630
+ closeBtn.focus();
4631
+ } catch (err) {}
4632
+ }
4633
+ }
4634
+ }
4635
+ });
4636
+
4637
+ nav.addEventListener('change', function (event) {
4638
+ const target = event.target || event.srcElement;
4639
+ if (!target || typeof target.matches !== 'function') return;
4640
+ if (!target.matches(NAV_OPTION_SELECTOR)) return;
4641
+ activateOption(target, {focus: true});
4642
+ });
4643
+
4644
+ updateButtons();
4645
+ syncActiveState({reveal: true});
4646
+ nav.__canopyGalleryNavUpdate = updateButtons;
4647
+ nav.__canopyGalleryNavRefresh = function (options) {
4648
+ syncActiveState({
4649
+ reveal: options && options.reveal,
4650
+ focus: options && options.focus,
4651
+ });
4652
+ };
4653
+ }
4654
+
4655
+ function bindGalleryNavs() {
4656
+ const navs = document.querySelectorAll('[data-canopy-gallery-nav]');
4657
+ if (!navs || !navs.length) return;
4658
+ Array.prototype.forEach.call(navs, initGalleryNav);
4659
+ refreshGalleryNavs({reveal: true});
4660
+ }
4661
+
4662
+ function refreshGalleryNavs(options) {
4663
+ const opts = options || {};
4664
+ const navs = document.querySelectorAll('[data-canopy-gallery-nav-bound="1"]');
4665
+ if (!navs || !navs.length) return;
4666
+ Array.prototype.forEach.call(navs, function (nav) {
4667
+ if (typeof nav.__canopyGalleryNavUpdate === 'function') {
4668
+ raf(nav.__canopyGalleryNavUpdate);
4669
+ }
4670
+ if (typeof nav.__canopyGalleryNavRefresh === 'function') {
4671
+ raf(function () {
4672
+ nav.__canopyGalleryNavRefresh({
4673
+ reveal: !!opts.reveal,
4674
+ focus: !!opts.focus,
4675
+ });
4676
+ });
4677
+ }
4678
+ });
4679
+ }
4680
+
4681
+ window.addEventListener('hashchange', function () {
4682
+ syncFromHash();
4683
+ refreshGalleryNavs({reveal: true});
4684
+ });
4685
+ window.addEventListener('pageshow', function () {
4686
+ syncFromHash();
4687
+ bindGalleryNavs();
4688
+ refreshGalleryNavs({reveal: true});
4689
+ });
4395
4690
  syncFromHash();
4691
+ bindGalleryNavs();
4692
+ refreshGalleryNavs({reveal: true});
4396
4693
  })()`;
4397
4694
  var galleryInstanceCounter = 0;
4398
4695
  function nextGalleryInstanceId() {
@@ -4529,7 +4826,7 @@ function buildCaptionContent(itemProps) {
4529
4826
  "canopy-gallery__meta canopy-gallery__meta--caption"
4530
4827
  ));
4531
4828
  }
4532
- function GalleryModal({ item, total, closeTargetId, prevTarget, nextTarget }) {
4829
+ function GalleryModal({ item, closeTargetId, navItems, navGroupName }) {
4533
4830
  const {
4534
4831
  props,
4535
4832
  modalId,
@@ -4542,7 +4839,6 @@ function GalleryModal({ item, total, closeTargetId, prevTarget, nextTarget }) {
4542
4839
  const kicker = props.kicker || props.label || props.eyebrow;
4543
4840
  const summary = props.popupDescription || props.modalDescription || props.description || props.summary || null;
4544
4841
  const modalTitle = props.popupTitle || props.modalTitle || props.title || `Item ${index + 1}`;
4545
- const preview = renderPreview(props);
4546
4842
  return /* @__PURE__ */ React40.createElement(
4547
4843
  "div",
4548
4844
  {
@@ -4556,17 +4852,14 @@ function GalleryModal({ item, total, closeTargetId, prevTarget, nextTarget }) {
4556
4852
  "data-canopy-gallery-modal": "true",
4557
4853
  "data-canopy-gallery-close": closeTargetId
4558
4854
  },
4559
- /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-scrim" }, /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-panel" }, /* @__PURE__ */ React40.createElement("header", { className: "canopy-gallery__modal-header" }, preview ? /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-thumb", "aria-hidden": "true" }, preview) : null, /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-text" }, kicker ? /* @__PURE__ */ React40.createElement("p", { className: "canopy-gallery__modal-kicker" }, kicker) : null, /* @__PURE__ */ React40.createElement("h3", { id: modalTitleId, className: "canopy-gallery__modal-title" }, modalTitle), summary ? /* @__PURE__ */ React40.createElement(
4560
- "p",
4855
+ /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-scrim" }, /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-panel" }, /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-actions" }, /* @__PURE__ */ React40.createElement(
4856
+ GalleryThumbnailNav,
4561
4857
  {
4562
- id: modalDescriptionId || void 0,
4563
- className: "canopy-gallery__modal-summary"
4564
- },
4565
- summary
4566
- ) : null, renderMetaList(
4567
- props.meta,
4568
- "canopy-gallery__meta canopy-gallery__meta--modal"
4569
- ))), /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-body" }, props.children, manifests && manifests.length ? /* @__PURE__ */ React40.createElement("section", { className: "canopy-gallery__referenced" }, /* @__PURE__ */ React40.createElement("h4", null, "Referenced works"), /* @__PURE__ */ React40.createElement("ul", { role: "list" }, manifests.map((manifest) => /* @__PURE__ */ React40.createElement("li", { key: manifest.id || manifest.href }, /* @__PURE__ */ React40.createElement("a", { href: manifest.href }, manifest.title || manifest.href))))) : null), /* @__PURE__ */ React40.createElement("footer", { className: "canopy-gallery__modal-footer" }, /* @__PURE__ */ React40.createElement(
4858
+ items: navItems,
4859
+ activeModalId: modalId,
4860
+ groupName: `${navGroupName || "canopy-gallery"}-${modalId}`
4861
+ }
4862
+ ), /* @__PURE__ */ React40.createElement(
4570
4863
  "a",
4571
4864
  {
4572
4865
  className: "canopy-gallery__modal-close",
@@ -4574,31 +4867,17 @@ function GalleryModal({ item, total, closeTargetId, prevTarget, nextTarget }) {
4574
4867
  "aria-label": `Close popup for ${modalTitle}`
4575
4868
  },
4576
4869
  "Close"
4577
- ), total > 1 ? /* @__PURE__ */ React40.createElement(
4578
- "nav",
4870
+ )), /* @__PURE__ */ React40.createElement("header", { className: "canopy-gallery__modal-header" }, /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-text" }, kicker ? /* @__PURE__ */ React40.createElement("p", { className: "canopy-gallery__modal-kicker" }, kicker) : null, /* @__PURE__ */ React40.createElement("h3", { id: modalTitleId, className: "canopy-gallery__modal-title" }, modalTitle), summary ? /* @__PURE__ */ React40.createElement(
4871
+ "p",
4579
4872
  {
4580
- className: "canopy-gallery__modal-nav",
4581
- "aria-label": "Gallery popup navigation"
4873
+ id: modalDescriptionId || void 0,
4874
+ className: "canopy-gallery__modal-summary"
4582
4875
  },
4583
- /* @__PURE__ */ React40.createElement(
4584
- "a",
4585
- {
4586
- className: "canopy-gallery__modal-nav-link canopy-gallery__modal-nav-link--prev",
4587
- href: `#${prevTarget}`,
4588
- "aria-label": `Show previous popup before ${modalTitle}`
4589
- },
4590
- "Prev"
4591
- ),
4592
- /* @__PURE__ */ React40.createElement(
4593
- "a",
4594
- {
4595
- className: "canopy-gallery__modal-nav-link canopy-gallery__modal-nav-link--next",
4596
- href: `#${nextTarget}`,
4597
- "aria-label": `Show next popup after ${modalTitle}`
4598
- },
4599
- "Next"
4600
- )
4601
- ) : null)))
4876
+ summary
4877
+ ) : null, renderMetaList(
4878
+ props.meta,
4879
+ "canopy-gallery__meta canopy-gallery__meta--modal"
4880
+ ))), /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modal-body" }, props.children, manifests && manifests.length ? /* @__PURE__ */ React40.createElement("section", { className: "canopy-gallery__referenced" }, /* @__PURE__ */ React40.createElement("h4", null, "Referenced works"), /* @__PURE__ */ React40.createElement("ul", { role: "list" }, manifests.map((manifest) => /* @__PURE__ */ React40.createElement("li", { key: manifest.id || manifest.href }, /* @__PURE__ */ React40.createElement("a", { href: manifest.href }, manifest.title || manifest.href))))) : null)))
4602
4881
  );
4603
4882
  }
4604
4883
  function GalleryFigure({ item }) {
@@ -4625,6 +4904,109 @@ function GalleryFigure({ item }) {
4625
4904
  )
4626
4905
  );
4627
4906
  }
4907
+ function GalleryThumbnailNav({ items, activeModalId, groupName }) {
4908
+ if (!items || items.length < 2) return null;
4909
+ const radioGroup = groupName || "canopy-gallery-nav";
4910
+ return /* @__PURE__ */ React40.createElement(
4911
+ "nav",
4912
+ {
4913
+ className: "canopy-gallery__nav",
4914
+ "aria-label": "Gallery navigation",
4915
+ "data-canopy-gallery-nav": "true"
4916
+ },
4917
+ /* @__PURE__ */ React40.createElement(
4918
+ "div",
4919
+ {
4920
+ className: "canopy-gallery__nav-viewport",
4921
+ "data-canopy-gallery-nav-viewport": "true"
4922
+ },
4923
+ /* @__PURE__ */ React40.createElement(
4924
+ "ul",
4925
+ {
4926
+ className: "canopy-gallery__nav-list",
4927
+ role: "list",
4928
+ "data-canopy-gallery-nav-track": "true"
4929
+ },
4930
+ items.map((item, index) => {
4931
+ const optionId = `${radioGroup}-${item.modalId || index}`;
4932
+ const isActive = item.modalId === activeModalId;
4933
+ return /* @__PURE__ */ React40.createElement(
4934
+ "li",
4935
+ {
4936
+ key: `${item.key}-nav`,
4937
+ className: "canopy-gallery__nav-item",
4938
+ "data-canopy-gallery-nav-item": "true",
4939
+ "data-canopy-gallery-nav-selected": isActive ? "1" : void 0
4940
+ },
4941
+ /* @__PURE__ */ React40.createElement(
4942
+ "input",
4943
+ {
4944
+ type: "radio",
4945
+ className: "canopy-gallery__nav-radio",
4946
+ id: optionId,
4947
+ name: radioGroup,
4948
+ value: item.modalId,
4949
+ checked: isActive ? true : void 0,
4950
+ readOnly: true,
4951
+ "data-canopy-gallery-nav-option": "true",
4952
+ "data-canopy-gallery-nav-modal": item.modalId,
4953
+ tabIndex: isActive ? 0 : -1,
4954
+ "data-canopy-gallery-nav-selected": isActive ? "1" : void 0
4955
+ }
4956
+ ),
4957
+ /* @__PURE__ */ React40.createElement(
4958
+ "label",
4959
+ {
4960
+ className: "canopy-gallery__nav-link",
4961
+ htmlFor: optionId,
4962
+ "data-canopy-gallery-nav-active": isActive ? "1" : void 0
4963
+ },
4964
+ /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__nav-thumb" }, renderPreview(item.props)),
4965
+ /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__nav-label" }, item.props.title || `Item ${item.index + 1}`)
4966
+ )
4967
+ );
4968
+ })
4969
+ )
4970
+ ),
4971
+ /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__nav-controls" }, /* @__PURE__ */ React40.createElement(
4972
+ "button",
4973
+ {
4974
+ type: "button",
4975
+ className: "canopy-gallery__nav-button canopy-gallery__nav-button--prev",
4976
+ "aria-label": "Scroll left through gallery thumbnails",
4977
+ "data-canopy-gallery-nav-prev": "true"
4978
+ },
4979
+ /* @__PURE__ */ React40.createElement(
4980
+ "span",
4981
+ {
4982
+ className: "canopy-gallery__nav-button-icon",
4983
+ "aria-hidden": "true",
4984
+ role: "presentation"
4985
+ },
4986
+ "<"
4987
+ ),
4988
+ /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Previous item")
4989
+ ), /* @__PURE__ */ React40.createElement(
4990
+ "button",
4991
+ {
4992
+ type: "button",
4993
+ className: "canopy-gallery__nav-button canopy-gallery__nav-button--next",
4994
+ "aria-label": "Scroll right through gallery thumbnails",
4995
+ "data-canopy-gallery-nav-next": "true"
4996
+ },
4997
+ /* @__PURE__ */ React40.createElement(
4998
+ "span",
4999
+ {
5000
+ className: "canopy-gallery__nav-button-icon",
5001
+ "aria-hidden": "true",
5002
+ role: "presentation"
5003
+ },
5004
+ ">"
5005
+ ),
5006
+ /* @__PURE__ */ React40.createElement("span", { className: "canopy-gallery__visually-hidden" }, "Next item")
5007
+ ))
5008
+ );
5009
+ }
4628
5010
  function GalleryContent({ children, flex = false }) {
4629
5011
  const contentClassName = [
4630
5012
  "canopy-gallery-item__content",
@@ -4665,6 +5047,7 @@ function Gallery({
4665
5047
  popupMode === "medium" ? "canopy-gallery--popup-medium" : "canopy-gallery--popup-full",
4666
5048
  className
4667
5049
  ].filter(Boolean).join(" ");
5050
+ const navGroupName = `${galleryId}-nav`;
4668
5051
  return /* @__PURE__ */ React40.createElement("section", { className: rootClassName, style, "data-canopy-gallery": "true" }, /* @__PURE__ */ React40.createElement(
4669
5052
  "div",
4670
5053
  {
@@ -4673,22 +5056,16 @@ function Gallery({
4673
5056
  "aria-hidden": "true",
4674
5057
  tabIndex: -1
4675
5058
  }
4676
- ), (title || description) && /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__header" }, title ? /* @__PURE__ */ React40.createElement(HeadingTag, { className: "canopy-gallery__heading" }, title) : null, description ? /* @__PURE__ */ React40.createElement("p", { className: "canopy-gallery__description" }, description) : null), /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__grid" }, orderedItems.map((item) => /* @__PURE__ */ React40.createElement(GalleryFigure, { key: item.key, item }))), /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modals" }, orderedItems.map((item, index) => {
4677
- const total = orderedItems.length;
4678
- const prevIndex = (index - 1 + total) % total;
4679
- const nextIndex = (index + 1) % total;
4680
- return /* @__PURE__ */ React40.createElement(
4681
- GalleryModal,
4682
- {
4683
- key: `${item.modalId}-modal`,
4684
- item,
4685
- total,
4686
- closeTargetId,
4687
- prevTarget: orderedItems[prevIndex].modalId,
4688
- nextTarget: orderedItems[nextIndex].modalId
4689
- }
4690
- );
4691
- })), /* @__PURE__ */ React40.createElement(
5059
+ ), (title || description) && /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__header" }, title ? /* @__PURE__ */ React40.createElement(HeadingTag, { className: "canopy-gallery__heading" }, title) : null, description ? /* @__PURE__ */ React40.createElement("p", { className: "canopy-gallery__description" }, description) : null), /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__grid" }, orderedItems.map((item) => /* @__PURE__ */ React40.createElement(GalleryFigure, { key: item.key, item }))), /* @__PURE__ */ React40.createElement("div", { className: "canopy-gallery__modals" }, orderedItems.map((item) => /* @__PURE__ */ React40.createElement(
5060
+ GalleryModal,
5061
+ {
5062
+ key: `${item.modalId}-modal`,
5063
+ item,
5064
+ closeTargetId,
5065
+ navItems: orderedItems,
5066
+ navGroupName
5067
+ }
5068
+ ))), /* @__PURE__ */ React40.createElement(
4692
5069
  "script",
4693
5070
  {
4694
5071
  "data-canopy-gallery-script": "true",