@lumx/react 3.9.4-alpha.0 → 3.9.4-alpha.2

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/index.js CHANGED
@@ -11806,6 +11806,8 @@ const PAGINATION_ITEMS_MAX = 5;
11806
11806
  * Size of a pagination item. Used to translate wrapper.
11807
11807
  */
11808
11808
  const PAGINATION_ITEM_SIZE = 12;
11809
+ const NEXT_SLIDE_EVENT = 'lumx-next-slide-event';
11810
+ const PREV_SLIDE_EVENT = 'lumx-prev-slide-event';
11809
11811
 
11810
11812
  const DEFAULT_OPTIONS = {
11811
11813
  activeIndex: 0,
@@ -11901,6 +11903,17 @@ const useSlideshowControls = _ref => {
11901
11903
  goTo(-1, loopBack, true);
11902
11904
  }, [goTo, stopAutoPlay]);
11903
11905
 
11906
+ // Listen to custom next/prev slide events
11907
+ useEffect(() => {
11908
+ if (!element) return undefined;
11909
+ element.addEventListener(NEXT_SLIDE_EVENT, onNextClick);
11910
+ element.addEventListener(PREV_SLIDE_EVENT, onPreviousClick);
11911
+ return () => {
11912
+ element.removeEventListener(NEXT_SLIDE_EVENT, onNextClick);
11913
+ element.removeEventListener(PREV_SLIDE_EVENT, onPreviousClick);
11914
+ };
11915
+ }, [element, onNextClick, onPreviousClick]);
11916
+
11904
11917
  // If the activeIndex props changes, update the current slide
11905
11918
  useEffect(() => {
11906
11919
  setActiveIndex(activeIndex);
@@ -12125,11 +12138,11 @@ function useKeyNavigate(element, onNext, onPrevious) {
12125
12138
  }
12126
12139
 
12127
12140
  /**
12128
- * Classname set on elements whose focus was blocked.
12141
+ * Data attribute set on elements whose focus was blocked.
12129
12142
  * This is to easily find elements that have been tempered with,
12130
12143
  * and not elements whose focus was already initially blocked.
12131
- * */
12132
- const BLOCKED_FOCUS_CLASSNAME = 'focus-blocked';
12144
+ */
12145
+ const BLOCKED_FOCUS = 'data-focus-blocked';
12133
12146
 
12134
12147
  /**
12135
12148
  * Manage how slides must behave when visible or not.
@@ -12141,91 +12154,88 @@ const useSlideFocusManagement = _ref => {
12141
12154
  slidesRef
12142
12155
  } = _ref;
12143
12156
  const [slide, setSlide] = React__default.useState(null);
12144
- useEffect(() => {
12145
- var _slidesRef$current;
12157
+ const [focusableElementSet, setFocusableElementSet] = React__default.useState();
12158
+ React__default.useEffect(() => {
12146
12159
  if (!slide) {
12147
12160
  return undefined;
12148
12161
  }
12149
- const isUserActivated = (slidesRef === null || slidesRef === void 0 ? void 0 : (_slidesRef$current = slidesRef.current) === null || _slidesRef$current === void 0 ? void 0 : _slidesRef$current.dataset.lumxUserActivated) === 'true';
12150
- let focusableElements = [];
12151
-
12152
- /**
12153
- * Display given slide to screen readers and, if focus was blocked, restore focus on elements.
12154
- */
12155
- const enableSlide = () => {
12156
- slide.removeAttribute('inert');
12157
- slide.setAttribute('aria-hidden', 'false');
12158
- // Find elements we have blocked focus on
12159
- // (won't be necessary once "inert" gets sufficient browser support)
12160
- focusableElements = Array.from(slide.querySelectorAll(`.${BLOCKED_FOCUS_CLASSNAME}`));
12161
- for (const focusableElement of focusableElements) {
12162
- focusableElement.removeAttribute('tabindex');
12163
- focusableElement.classList.remove(BLOCKED_FOCUS_CLASSNAME);
12162
+ // Update the slide's focusable element list (including the blocked elements)
12163
+ const updateFocusableElements = () => setFocusableElementSet(function () {
12164
+ let set = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Set();
12165
+ // TODO: remove when `inert` gets sufficient browser support
12166
+ const focusedBlocked = Array.from(slide.querySelectorAll(`[${BLOCKED_FOCUS}]`));
12167
+ for (const element of focusedBlocked) {
12168
+ set.add(element);
12164
12169
  }
12165
- };
12170
+ for (const element of getFocusableElements(slide)) {
12171
+ set.add(element);
12172
+ }
12173
+ return set;
12174
+ });
12166
12175
 
12167
- /**
12168
- * Hide given slide from screen readers and block focus on all focusable elements within.
12169
- */
12170
- const blockSlide = () => {
12176
+ // Observe changes in the content of the slide
12177
+ const observer = new MutationObserver(mutationsList => {
12178
+ if (mutationsList.some(mutation => mutation.type === 'childList')) {
12179
+ updateFocusableElements();
12180
+ }
12181
+ });
12182
+ updateFocusableElements();
12183
+ observer.observe(slide, {
12184
+ attributes: true,
12185
+ childList: true,
12186
+ subtree: true
12187
+ });
12188
+ return observer.disconnect();
12189
+ }, [slide]);
12190
+ useEffect(() => {
12191
+ if (!slide || !focusableElementSet) {
12192
+ return;
12193
+ }
12194
+ const focusableElements = Array.from(focusableElementSet);
12195
+ if (!isSlideDisplayed) {
12196
+ /* Block slide */
12171
12197
  slide.setAttribute('inert', '');
12172
12198
  slide.setAttribute('aria-hidden', 'true');
12173
- focusableElements = getFocusableElements(slide);
12199
+
12200
+ // TODO: remove when `inert` gets sufficient browser support
12174
12201
  for (const focusableElement of focusableElements) {
12175
12202
  focusableElement.setAttribute('tabindex', '-1');
12176
- focusableElement.classList.add(BLOCKED_FOCUS_CLASSNAME);
12203
+ focusableElement.setAttribute(BLOCKED_FOCUS, '');
12177
12204
  }
12178
- };
12179
- const handleDisplay = () => {
12180
- if (isSlideDisplayed) {
12181
- enableSlide();
12182
- } else {
12183
- blockSlide();
12184
- }
12185
- };
12205
+ } else {
12206
+ var _slidesRef$current;
12207
+ /* Un-block slide */
12208
+ slide.removeAttribute('inert');
12209
+ slide.removeAttribute('aria-hidden');
12186
12210
 
12187
- // Create an observer instance linked to the callback function
12188
- // (won't be necessary once "inert" gets sufficient browser support)
12189
- const observer = new MutationObserver(mutationsList => {
12190
- for (const mutation of mutationsList) {
12191
- if (mutation.type === 'childList') {
12192
- handleDisplay();
12193
- }
12211
+ // TODO: remove when `inert` gets sufficient browser support
12212
+ for (const focusableElement of focusableElements) {
12213
+ focusableElement.removeAttribute('tabindex');
12214
+ focusableElement.removeAttribute(BLOCKED_FOCUS);
12194
12215
  }
12195
- });
12196
- handleDisplay();
12197
12216
 
12198
- // Change focus on slide displayed
12199
- if (isSlideDisplayed && isUserActivated) {
12200
- var _elementToFocus;
12201
- let elementToFocus = slide;
12217
+ // Change focus on slide displayed
12218
+ const isUserActivated = (slidesRef === null || slidesRef === void 0 ? void 0 : (_slidesRef$current = slidesRef.current) === null || _slidesRef$current === void 0 ? void 0 : _slidesRef$current.dataset.lumxUserActivated) === 'true';
12219
+ if (isUserActivated) {
12220
+ var _elementToFocus;
12221
+ let elementToFocus = slide;
12202
12222
 
12203
- // We have exactly one focusable element => focus it
12204
- if (focusableElements.length === 1) {
12205
- // eslint-disable-next-line prefer-destructuring
12206
- elementToFocus = focusableElements[0];
12207
- }
12223
+ // We have exactly one focusable element => focus it
12224
+ if (focusableElementSet.size === 1) {
12225
+ // eslint-disable-next-line prefer-destructuring
12226
+ elementToFocus = focusableElements[0];
12227
+ }
12208
12228
 
12209
- // We have not focusable element => focus the pagination item
12210
- if (focusableElements.length === 0) {
12211
- elementToFocus = document.querySelector(`[aria-controls="${slide === null || slide === void 0 ? void 0 : slide.id}"]`);
12229
+ // We have not focusable element => focus the pagination item
12230
+ if (focusableElementSet.size === 0) {
12231
+ elementToFocus = document.querySelector(`[aria-controls="${slide === null || slide === void 0 ? void 0 : slide.id}"]`);
12232
+ }
12233
+ (_elementToFocus = elementToFocus) === null || _elementToFocus === void 0 ? void 0 : _elementToFocus.focus({
12234
+ preventScroll: true
12235
+ });
12212
12236
  }
12213
- (_elementToFocus = elementToFocus) === null || _elementToFocus === void 0 ? void 0 : _elementToFocus.focus({
12214
- preventScroll: true
12215
- });
12216
- }
12217
-
12218
- /** If slide is hidden, start observing for elements to block focus */
12219
- if (!isSlideDisplayed) {
12220
- observer.observe(slide, {
12221
- attributes: true,
12222
- childList: true,
12223
- subtree: true
12224
- });
12225
- return () => observer.disconnect();
12226
12237
  }
12227
- return undefined;
12228
- }, [isSlideDisplayed, slide, slidesRef]);
12238
+ }, [focusableElementSet, isSlideDisplayed, slide, slidesRef]);
12229
12239
  return setSlide;
12230
12240
  };
12231
12241
 
@@ -12527,6 +12537,10 @@ const Slides = /*#__PURE__*/forwardRef((props, ref) => {
12527
12537
  return groupBy && groupBy > 1 ? chunk(childrenArray, groupBy) : childrenArray;
12528
12538
  }, [children, groupBy]);
12529
12539
  const slidesRef = React__default.useRef(null);
12540
+ const slide = slidesRef.current;
12541
+ const onNextSlide = React__default.useCallback(() => slide === null || slide === void 0 ? void 0 : slide.dispatchEvent(new CustomEvent(NEXT_SLIDE_EVENT)), [slide]);
12542
+ const onPrevSlide = React__default.useCallback(() => slide === null || slide === void 0 ? void 0 : slide.dispatchEvent(new CustomEvent(NEXT_SLIDE_EVENT)), [slide]);
12543
+ useKeyNavigate(slide, onNextSlide, onPrevSlide);
12530
12544
  return /*#__PURE__*/React__default.createElement("section", _extends({
12531
12545
  id: id,
12532
12546
  ref: useMergeRefs(slidesRef, ref)
@@ -12551,7 +12565,7 @@ const Slides = /*#__PURE__*/forwardRef((props, ref) => {
12551
12565
  }, groups.map((group, index) => /*#__PURE__*/React__default.createElement(SlideshowItemGroup, {
12552
12566
  key: index,
12553
12567
  id: slidesId && buildSlideShowGroupId(slidesId, index),
12554
- label: slideGroupLabel ? slideGroupLabel(index + 1, groups.length) : undefined,
12568
+ label: slideGroupLabel === null || slideGroupLabel === void 0 ? void 0 : slideGroupLabel(index + 1, groups.length),
12555
12569
  isDisplayed: index >= startIndexVisible && index < endIndexVisible,
12556
12570
  slidesRef: slidesRef
12557
12571
  }, group)))), afterSlides);