@lumx/react 3.20.1-alpha.29 → 3.20.1-alpha.30
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/_internal/Button-4b67daa8.js +98 -0
- package/_internal/Button-4b67daa8.js.map +1 -0
- package/_internal/ButtonRoot-a70baf82.js +118 -0
- package/_internal/ButtonRoot-a70baf82.js.map +1 -0
- package/_internal/Chip-70af04b4.js +144 -0
- package/_internal/Chip-70af04b4.js.map +1 -0
- package/_internal/ClickAwayProvider-1204f237.js +95 -0
- package/_internal/ClickAwayProvider-1204f237.js.map +1 -0
- package/_internal/DisabledStateContext-ea04260d.js +29 -0
- package/_internal/DisabledStateContext-ea04260d.js.map +1 -0
- package/_internal/HeadingLevelProvider-ebdcb0c7.js +61 -0
- package/_internal/HeadingLevelProvider-ebdcb0c7.js.map +1 -0
- package/_internal/IconButton-8d61f5be.js +77 -0
- package/_internal/IconButton-8d61f5be.js.map +1 -0
- package/_internal/ImageCaption-db44ec9e.js +75 -0
- package/_internal/ImageCaption-db44ec9e.js.map +1 -0
- package/_internal/List-c75646f2.js +818 -0
- package/_internal/List-c75646f2.js.map +1 -0
- package/_internal/PopoverDialog-35b2d87d.js +657 -0
- package/_internal/PopoverDialog-35b2d87d.js.map +1 -0
- package/_internal/Portal-3f86608e.js +45 -0
- package/_internal/Portal-3f86608e.js.map +1 -0
- package/_internal/RawClickable-2c2b6a89.js +52 -0
- package/_internal/RawClickable-2c2b6a89.js.map +1 -0
- package/_internal/Slides-ce641b5f.js +679 -0
- package/_internal/Slides-ce641b5f.js.map +1 -0
- package/_internal/ThemeContext-3181f000.js +14 -0
- package/_internal/ThemeContext-3181f000.js.map +1 -0
- package/_internal/Thumbnail-02bd6869.js +314 -0
- package/_internal/Thumbnail-02bd6869.js.map +1 -0
- package/_internal/components/alert-dialog-a24330ed.js +166 -0
- package/_internal/components/alert-dialog-a24330ed.js.map +1 -0
- package/_internal/components/autocomplete-70749e51.js +262 -0
- package/_internal/components/autocomplete-70749e51.js.map +1 -0
- package/_internal/components/avatar-ed9f4869.js +84 -0
- package/_internal/components/avatar-ed9f4869.js.map +1 -0
- package/_internal/components/badge-ccf47147.js +82 -0
- package/_internal/components/badge-ccf47147.js.map +1 -0
- package/_internal/components/button-9f710830.js +48 -0
- package/_internal/components/button-9f710830.js.map +1 -0
- package/_internal/components/checkbox-8ab51ef9.js +142 -0
- package/_internal/components/checkbox-8ab51ef9.js.map +1 -0
- package/_internal/components/chip-19e40755.js +103 -0
- package/_internal/components/chip-19e40755.js.map +1 -0
- package/_internal/components/comment-block-bb6a0603.js +139 -0
- package/_internal/components/comment-block-bb6a0603.js.map +1 -0
- package/_internal/components/date-picker-e4209b01.js +2 -0
- package/_internal/components/date-picker-e4209b01.js.map +1 -0
- package/_internal/components/dialog-30336ccb.js +239 -0
- package/_internal/components/dialog-30336ccb.js.map +1 -0
- package/_internal/components/divider-0e93aa3d.js +51 -0
- package/_internal/components/divider-0e93aa3d.js.map +1 -0
- package/_internal/components/drag-handle-ba2e7e67.js +52 -0
- package/_internal/components/drag-handle-ba2e7e67.js.map +1 -0
- package/_internal/components/dropdown-d18122d7.js +148 -0
- package/_internal/components/dropdown-d18122d7.js.map +1 -0
- package/_internal/components/expansion-panel-0b263437.js +169 -0
- package/_internal/components/expansion-panel-0b263437.js.map +1 -0
- package/_internal/components/flag-8f9a498a.js +60 -0
- package/_internal/components/flag-8f9a498a.js.map +1 -0
- package/_internal/components/flex-box-15be92f6.js +57 -0
- package/_internal/components/flex-box-15be92f6.js.map +1 -0
- package/_internal/components/generic-block-5d843f1e.js +128 -0
- package/_internal/components/generic-block-5d843f1e.js.map +1 -0
- package/_internal/components/grid-8c08dc4b.js +105 -0
- package/_internal/components/grid-8c08dc4b.js.map +1 -0
- package/_internal/components/grid-column-85e305e7.js +59 -0
- package/_internal/components/grid-column-85e305e7.js.map +1 -0
- package/_internal/components/heading-7bfafd7d.js +54 -0
- package/_internal/components/heading-7bfafd7d.js.map +1 -0
- package/_internal/components/icon-ee15673b.js +103 -0
- package/_internal/components/icon-ee15673b.js.map +1 -0
- package/_internal/components/image-block-3479abda.js +111 -0
- package/_internal/components/image-block-3479abda.js.map +1 -0
- package/_internal/components/image-lightbox-1d7ca133.js +758 -0
- package/_internal/components/image-lightbox-1d7ca133.js.map +1 -0
- package/_internal/components/inline-list-5ba8bb0f.js +75 -0
- package/_internal/components/inline-list-5ba8bb0f.js.map +1 -0
- package/_internal/components/input-helper-2e4e49fd.js +72 -0
- package/_internal/components/input-helper-2e4e49fd.js.map +1 -0
- package/_internal/components/input-label-30d199c3.js +60 -0
- package/_internal/components/input-label-30d199c3.js.map +1 -0
- package/_internal/components/lightbox-c5f9afd0.js +156 -0
- package/_internal/components/lightbox-c5f9afd0.js.map +1 -0
- package/_internal/components/link-43ee103e.js +73 -0
- package/_internal/components/link-43ee103e.js.map +1 -0
- package/_internal/components/link-preview-db0ee2d6.js +118 -0
- package/_internal/components/link-preview-db0ee2d6.js.map +1 -0
- package/_internal/components/list-2f256244.js +72 -0
- package/_internal/components/list-2f256244.js.map +1 -0
- package/_internal/components/message-f7674e0e.js +101 -0
- package/_internal/components/message-f7674e0e.js.map +1 -0
- package/_internal/components/mosaic-3effd0cf.js +95 -0
- package/_internal/components/mosaic-3effd0cf.js.map +1 -0
- package/_internal/components/navigation-3a5dc270.js +227 -0
- package/_internal/components/navigation-3a5dc270.js.map +1 -0
- package/_internal/components/notification-098c5600.js +146 -0
- package/_internal/components/notification-098c5600.js.map +1 -0
- package/_internal/components/popover-dfcddda4.js +3 -0
- package/_internal/components/popover-dfcddda4.js.map +1 -0
- package/_internal/components/post-block-69797e4d.js +110 -0
- package/_internal/components/post-block-69797e4d.js.map +1 -0
- package/_internal/components/progress-44bb0301.js +183 -0
- package/_internal/components/progress-44bb0301.js.map +1 -0
- package/_internal/components/progress-tracker-e0981fcc.js +309 -0
- package/_internal/components/progress-tracker-e0981fcc.js.map +1 -0
- package/_internal/components/radio-button-929c7bee.js +150 -0
- package/_internal/components/radio-button-929c7bee.js.map +1 -0
- package/_internal/components/select-64bc72a0.js +458 -0
- package/_internal/components/select-64bc72a0.js.map +1 -0
- package/_internal/components/side-navigation-c610c689.js +166 -0
- package/_internal/components/side-navigation-c610c689.js.map +1 -0
- package/_internal/components/skeleton-1ea8c82a.js +167 -0
- package/_internal/components/skeleton-1ea8c82a.js.map +1 -0
- package/_internal/components/slider-78cfaa67.js +312 -0
- package/_internal/components/slider-78cfaa67.js.map +1 -0
- package/_internal/components/slideshow-d8a943a7.js +151 -0
- package/_internal/components/slideshow-d8a943a7.js.map +1 -0
- package/_internal/components/switch-25b65051.js +122 -0
- package/_internal/components/switch-25b65051.js.map +1 -0
- package/_internal/components/table-ec20c66c.js +296 -0
- package/_internal/components/table-ec20c66c.js.map +1 -0
- package/_internal/components/tabs-89c055bd.js +299 -0
- package/_internal/components/tabs-89c055bd.js.map +1 -0
- package/_internal/components/text-d04d0f1b.js +2 -0
- package/_internal/components/text-d04d0f1b.js.map +1 -0
- package/_internal/components/text-field-8f13957e.js +361 -0
- package/_internal/components/text-field-8f13957e.js.map +1 -0
- package/_internal/components/thumbnail-1255957f.js +42 -0
- package/_internal/components/thumbnail-1255957f.js.map +1 -0
- package/_internal/components/toolbar-e7c984e6.js +62 -0
- package/_internal/components/toolbar-e7c984e6.js.map +1 -0
- package/_internal/components/tooltip-dcb43bbe.js +328 -0
- package/_internal/components/tooltip-dcb43bbe.js.map +1 -0
- package/_internal/components/uploader-7ef4db39.js +154 -0
- package/_internal/components/uploader-7ef4db39.js.map +1 -0
- package/_internal/components/user-block-24d97650.js +145 -0
- package/_internal/components/user-block-24d97650.js.map +1 -0
- package/_internal/constants-43721918.js +2170 -0
- package/_internal/constants-43721918.js.map +1 -0
- package/_internal/constants-d0e3f49e.js +24 -0
- package/_internal/constants-d0e3f49e.js.map +1 -0
- package/_internal/context-9d1336a1.js +19 -0
- package/_internal/context-9d1336a1.js.map +1 -0
- package/_internal/forwardRef-8bce732e.js +9 -0
- package/_internal/forwardRef-8bce732e.js.map +1 -0
- package/_internal/getFocusableElements-230173a8.js +13 -0
- package/_internal/getFocusableElements-230173a8.js.map +1 -0
- package/_internal/index-25c9e8c2.js +118 -0
- package/_internal/index-25c9e8c2.js.map +1 -0
- package/_internal/index-25d2a45e.js +437 -0
- package/_internal/index-25d2a45e.js.map +1 -0
- package/_internal/isComponent-b9762ff1.js +18 -0
- package/_internal/isComponent-b9762ff1.js.map +1 -0
- package/_internal/isComponentType-e806b848.js +9 -0
- package/_internal/isComponentType-e806b848.js.map +1 -0
- package/_internal/mergeRefs-f0d7d6ea.js +30 -0
- package/_internal/mergeRefs-f0d7d6ea.js.map +1 -0
- package/_internal/state-db358714.js +130 -0
- package/_internal/state-db358714.js.map +1 -0
- package/_internal/useBooleanState-2a3d237c.js +12 -0
- package/_internal/useBooleanState-2a3d237c.js.map +1 -0
- package/_internal/useCallbackOnEscape-b956a85d.js +64 -0
- package/_internal/useCallbackOnEscape-b956a85d.js.map +1 -0
- package/_internal/useDisableBodyScroll-36bd7352.js +219 -0
- package/_internal/useDisableBodyScroll-36bd7352.js.map +1 -0
- package/_internal/useDisableStateProps-69e16b7c.js +36 -0
- package/_internal/useDisableStateProps-69e16b7c.js.map +1 -0
- package/_internal/useFocusTrap-2dbae79e.js +112 -0
- package/_internal/useFocusTrap-2dbae79e.js.map +1 -0
- package/_internal/useId-3a1facc0.js +18 -0
- package/_internal/useId-3a1facc0.js.map +1 -0
- package/_internal/useRovingTabIndex-7daf0f24.js +77 -0
- package/_internal/useRovingTabIndex-7daf0f24.js.map +1 -0
- package/_internal/useTransitionVisibility-321fdbfa.js +50 -0
- package/_internal/useTransitionVisibility-321fdbfa.js.map +1 -0
- package/_internal/wrapChildrenIconWithSpaces-50d705e6.js +20 -0
- package/_internal/wrapChildrenIconWithSpaces-50d705e6.js.map +1 -0
- package/index.js +63 -14033
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/utils/index.js +3 -158
- package/utils/index.js.map +1 -1
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import { getRootClassName, handleBasicClasses } from '@lumx/core/js/utils/className';
|
|
3
|
+
import { f as forwardRef } from './forwardRef-8bce732e.js';
|
|
4
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
import React__default, { useRef, useEffect, useState, useCallback, useMemo, Children } from 'react';
|
|
6
|
+
import { mdiChevronLeft } from '@lumx/icons/esm/chevron-left';
|
|
7
|
+
import { mdiChevronRight } from '@lumx/icons/esm/chevron-right';
|
|
8
|
+
import { mdiPlayCircleOutline } from '@lumx/icons/esm/play-circle-outline';
|
|
9
|
+
import { mdiPauseCircleOutline } from '@lumx/icons/esm/pause-circle-outline';
|
|
10
|
+
import { W as WINDOW } from './constants-d0e3f49e.js';
|
|
11
|
+
import { u as useId } from './useId-3a1facc0.js';
|
|
12
|
+
import { u as useRovingTabIndex } from './useRovingTabIndex-7daf0f24.js';
|
|
13
|
+
import { u as useTheme } from './ThemeContext-3181f000.js';
|
|
14
|
+
import { range } from '@lumx/core/js/utils/collection/range';
|
|
15
|
+
import { detectHorizontalSwipe } from '@lumx/core/js/utils';
|
|
16
|
+
import { Theme, Emphasis } from '@lumx/core/js/constants';
|
|
17
|
+
import { I as IconButton } from './IconButton-8d61f5be.js';
|
|
18
|
+
import { chunk } from '@lumx/core/js/utils/collection/chunk';
|
|
19
|
+
import { m as mergeRefs } from './mergeRefs-f0d7d6ea.js';
|
|
20
|
+
import { g as getFocusableElements } from './getFocusableElements-230173a8.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Making setInterval Declarative with React Hooks.
|
|
24
|
+
* Credits: https://overreacted.io/making-setinterval-declarative-with-react-hooks/
|
|
25
|
+
*
|
|
26
|
+
* @param callback Function called by setInterval.
|
|
27
|
+
* @param delay Delay for setInterval.
|
|
28
|
+
*/
|
|
29
|
+
function useInterval(callback, delay) {
|
|
30
|
+
const savedCallback = useRef();
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
savedCallback.current = callback;
|
|
33
|
+
});
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (delay === null) return undefined;
|
|
36
|
+
function tick() {
|
|
37
|
+
savedCallback.current?.();
|
|
38
|
+
}
|
|
39
|
+
const id = setInterval(tick, delay);
|
|
40
|
+
return () => clearInterval(id);
|
|
41
|
+
}, [delay]);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Autoplay default interval in ms.
|
|
46
|
+
*/
|
|
47
|
+
const AUTOPLAY_DEFAULT_INTERVAL = 5000;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Full width size in percent.
|
|
51
|
+
*/
|
|
52
|
+
const FULL_WIDTH_PERCENT = 100;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Edge from the active index.
|
|
56
|
+
*/
|
|
57
|
+
const EDGE_FROM_ACTIVE_INDEX = 2;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Max number of pagination items.
|
|
61
|
+
*/
|
|
62
|
+
const PAGINATION_ITEMS_MAX = 5;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Size of a pagination item. Used to translate wrapper.
|
|
66
|
+
*/
|
|
67
|
+
const PAGINATION_ITEM_SIZE = 12;
|
|
68
|
+
|
|
69
|
+
const DEFAULT_OPTIONS = {
|
|
70
|
+
activeIndex: 0,
|
|
71
|
+
groupBy: 1,
|
|
72
|
+
interval: AUTOPLAY_DEFAULT_INTERVAL
|
|
73
|
+
};
|
|
74
|
+
const useSlideshowControls = ({
|
|
75
|
+
activeIndex = DEFAULT_OPTIONS.activeIndex,
|
|
76
|
+
groupBy = DEFAULT_OPTIONS.groupBy,
|
|
77
|
+
interval = DEFAULT_OPTIONS.interval,
|
|
78
|
+
autoPlay,
|
|
79
|
+
defaultActiveIndex,
|
|
80
|
+
onChange,
|
|
81
|
+
itemsCount,
|
|
82
|
+
id,
|
|
83
|
+
slidesId
|
|
84
|
+
}) => {
|
|
85
|
+
const [currentIndex, setCurrentIndex] = useState(activeIndex);
|
|
86
|
+
// Use state instead of a ref to make the slideshow controls update directly when the element is set.
|
|
87
|
+
const [element, setElement] = useState(null);
|
|
88
|
+
|
|
89
|
+
// Number of slides when using groupBy prop.
|
|
90
|
+
const slidesCount = Math.ceil(itemsCount / Math.min(groupBy, itemsCount));
|
|
91
|
+
|
|
92
|
+
// Change current index to display next slide.
|
|
93
|
+
const goToNextSlide = useCallback((loopback = true) => {
|
|
94
|
+
setCurrentIndex(index => {
|
|
95
|
+
if (loopback && index === slidesCount - 1) {
|
|
96
|
+
// Loopback to the start.
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
if (index < slidesCount - 1) {
|
|
100
|
+
// Next slide.
|
|
101
|
+
return index + 1;
|
|
102
|
+
}
|
|
103
|
+
return index;
|
|
104
|
+
});
|
|
105
|
+
}, [slidesCount, setCurrentIndex]);
|
|
106
|
+
|
|
107
|
+
// Change current index to display previous slide.
|
|
108
|
+
const goToPreviousSlide = useCallback((loopback = true) => {
|
|
109
|
+
setCurrentIndex(index => {
|
|
110
|
+
if (loopback && index === 0) {
|
|
111
|
+
// Loopback to the end.
|
|
112
|
+
return slidesCount - 1;
|
|
113
|
+
}
|
|
114
|
+
if (index > 0) {
|
|
115
|
+
// Previous slide.
|
|
116
|
+
return index - 1;
|
|
117
|
+
}
|
|
118
|
+
return index;
|
|
119
|
+
});
|
|
120
|
+
}, [slidesCount, setCurrentIndex]);
|
|
121
|
+
|
|
122
|
+
// Auto play
|
|
123
|
+
const [isAutoPlaying, setIsAutoPlaying] = useState(Boolean(autoPlay));
|
|
124
|
+
const [isForcePaused, setIsForcePaused] = useState(false);
|
|
125
|
+
const isSlideshowAutoPlaying = isForcePaused ? false : isAutoPlaying;
|
|
126
|
+
// Start
|
|
127
|
+
useInterval(goToNextSlide, isSlideshowAutoPlaying && slidesCount > 1 ? interval : null);
|
|
128
|
+
|
|
129
|
+
// Reset current index if it become invalid.
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
if (currentIndex > slidesCount - 1) {
|
|
132
|
+
setCurrentIndex(defaultActiveIndex);
|
|
133
|
+
}
|
|
134
|
+
}, [currentIndex, slidesCount, defaultActiveIndex]);
|
|
135
|
+
const startAutoPlay = () => {
|
|
136
|
+
setIsAutoPlaying(Boolean(autoPlay));
|
|
137
|
+
};
|
|
138
|
+
const stopAutoPlay = () => {
|
|
139
|
+
setIsAutoPlaying(false);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// Handle click on a bullet to go to a specific slide.
|
|
143
|
+
const onPaginationClick = useCallback(index => {
|
|
144
|
+
stopAutoPlay();
|
|
145
|
+
setIsForcePaused(true);
|
|
146
|
+
if (index >= 0 && index < slidesCount) {
|
|
147
|
+
setCurrentIndex(index);
|
|
148
|
+
}
|
|
149
|
+
}, [slidesCount, setCurrentIndex]);
|
|
150
|
+
|
|
151
|
+
// Handle click or keyboard event to go to next slide.
|
|
152
|
+
const onNextClick = useCallback((loopback = true) => {
|
|
153
|
+
stopAutoPlay();
|
|
154
|
+
setIsForcePaused(true);
|
|
155
|
+
goToNextSlide(loopback);
|
|
156
|
+
}, [goToNextSlide]);
|
|
157
|
+
|
|
158
|
+
// Handle click or keyboard event to go to previous slide.
|
|
159
|
+
const onPreviousClick = useCallback((loopback = true) => {
|
|
160
|
+
stopAutoPlay();
|
|
161
|
+
setIsForcePaused(true);
|
|
162
|
+
goToPreviousSlide(loopback);
|
|
163
|
+
}, [goToPreviousSlide]);
|
|
164
|
+
|
|
165
|
+
// If the activeIndex props changes, update the current slide
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
setCurrentIndex(activeIndex);
|
|
168
|
+
}, [activeIndex]);
|
|
169
|
+
|
|
170
|
+
// If the slide changes, with autoplay for example, trigger "onChange"
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
if (!onChange) return;
|
|
173
|
+
onChange(currentIndex);
|
|
174
|
+
}, [currentIndex, onChange]);
|
|
175
|
+
const generatedSlideshowId = useId();
|
|
176
|
+
const slideshowId = id || generatedSlideshowId;
|
|
177
|
+
const generatedSlidesId = useId();
|
|
178
|
+
const slideshowSlidesId = slidesId || generatedSlidesId;
|
|
179
|
+
const toggleAutoPlay = () => {
|
|
180
|
+
if (isSlideshowAutoPlaying) {
|
|
181
|
+
stopAutoPlay();
|
|
182
|
+
} else {
|
|
183
|
+
startAutoPlay();
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
const toggleForcePause = () => {
|
|
187
|
+
const shouldBePaused = !isForcePaused;
|
|
188
|
+
setIsForcePaused(shouldBePaused);
|
|
189
|
+
if (!shouldBePaused) {
|
|
190
|
+
startAutoPlay();
|
|
191
|
+
} else {
|
|
192
|
+
stopAutoPlay();
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// Start index and end index of visible slides.
|
|
197
|
+
const startIndexVisible = currentIndex * groupBy;
|
|
198
|
+
const endIndexVisible = startIndexVisible + groupBy;
|
|
199
|
+
return {
|
|
200
|
+
startIndexVisible,
|
|
201
|
+
endIndexVisible,
|
|
202
|
+
setSlideshow: setElement,
|
|
203
|
+
slideshow: element,
|
|
204
|
+
slideshowId,
|
|
205
|
+
slideshowSlidesId,
|
|
206
|
+
onPreviousClick,
|
|
207
|
+
onNextClick,
|
|
208
|
+
onPaginationClick,
|
|
209
|
+
isAutoPlaying: isSlideshowAutoPlaying,
|
|
210
|
+
toggleAutoPlay,
|
|
211
|
+
activeIndex: currentIndex,
|
|
212
|
+
slidesCount,
|
|
213
|
+
setActiveIndex: setCurrentIndex,
|
|
214
|
+
startAutoPlay,
|
|
215
|
+
stopAutoPlay,
|
|
216
|
+
isForcePaused,
|
|
217
|
+
toggleForcePause
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Classname set on elements whose focus was blocked.
|
|
223
|
+
* This is to easily find elements that have been tempered with,
|
|
224
|
+
* and not elements whose focus was already initially blocked.
|
|
225
|
+
* */
|
|
226
|
+
const BLOCKED_FOCUS_CLASSNAME = 'focus-blocked';
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Manage how slides must behave when visible or not.
|
|
230
|
+
* When not visible, they should be hidden from screen readers and not focusable.
|
|
231
|
+
*/
|
|
232
|
+
const useSlideFocusManagement = ({
|
|
233
|
+
isSlideDisplayed,
|
|
234
|
+
slideRef
|
|
235
|
+
}) => {
|
|
236
|
+
useEffect(() => {
|
|
237
|
+
const element = slideRef?.current;
|
|
238
|
+
if (!element) {
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Display given slide to screen readers and, if focus was blocked, restore focus on elements.
|
|
244
|
+
*/
|
|
245
|
+
const enableSlide = () => {
|
|
246
|
+
// Hide from screen readers
|
|
247
|
+
element.setAttribute('aria-hidden', 'false');
|
|
248
|
+
// Find elements we have blocked focus on
|
|
249
|
+
element.querySelectorAll(`.${BLOCKED_FOCUS_CLASSNAME}`).forEach(focusableElement => {
|
|
250
|
+
focusableElement.removeAttribute('tabindex');
|
|
251
|
+
focusableElement.classList.remove(BLOCKED_FOCUS_CLASSNAME);
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Hide given slide from screen readers and block focus on all focusable elements within.
|
|
257
|
+
*/
|
|
258
|
+
const blockSlide = () => {
|
|
259
|
+
element.setAttribute('aria-hidden', 'true');
|
|
260
|
+
getFocusableElements(element).forEach(focusableElement => {
|
|
261
|
+
focusableElement.setAttribute('tabindex', '-1');
|
|
262
|
+
focusableElement.classList.add(BLOCKED_FOCUS_CLASSNAME);
|
|
263
|
+
});
|
|
264
|
+
};
|
|
265
|
+
const handleDisplay = () => {
|
|
266
|
+
if (!element) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (isSlideDisplayed) {
|
|
270
|
+
enableSlide();
|
|
271
|
+
} else {
|
|
272
|
+
blockSlide();
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// Callback function to execute when mutations are observed
|
|
277
|
+
const callback = mutationsList => {
|
|
278
|
+
if (element) {
|
|
279
|
+
for (const mutation of mutationsList) {
|
|
280
|
+
if (mutation.type === 'childList') {
|
|
281
|
+
handleDisplay();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// Create an observer instance linked to the callback function
|
|
288
|
+
const observer = new MutationObserver(callback);
|
|
289
|
+
if (element) {
|
|
290
|
+
handleDisplay();
|
|
291
|
+
|
|
292
|
+
/** If slide is hidden, start observing for elements to block focus */
|
|
293
|
+
if (!isSlideDisplayed) {
|
|
294
|
+
observer.observe(element, {
|
|
295
|
+
attributes: true,
|
|
296
|
+
childList: true,
|
|
297
|
+
subtree: true
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return () => {
|
|
302
|
+
if (!isSlideDisplayed) {
|
|
303
|
+
observer.disconnect();
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
}, [isSlideDisplayed, slideRef]);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Component display name.
|
|
311
|
+
*/
|
|
312
|
+
const COMPONENT_NAME$3 = 'SlideshowItemGroup';
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Component default class name and class prefix.
|
|
316
|
+
*/
|
|
317
|
+
const CLASSNAME$3 = getRootClassName(COMPONENT_NAME$3);
|
|
318
|
+
const buildSlideShowGroupId = (slidesId, index) => `${slidesId}-slide-${index}`;
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* SlideshowItemGroup component.
|
|
322
|
+
*
|
|
323
|
+
* @param props Component props.
|
|
324
|
+
* @param ref Component ref.
|
|
325
|
+
* @return React element.
|
|
326
|
+
*/
|
|
327
|
+
const SlideshowItemGroup = forwardRef((props, ref) => {
|
|
328
|
+
const {
|
|
329
|
+
className,
|
|
330
|
+
children,
|
|
331
|
+
role = 'group',
|
|
332
|
+
label,
|
|
333
|
+
isDisplayed,
|
|
334
|
+
...forwardedProps
|
|
335
|
+
} = props;
|
|
336
|
+
const groupRef = React__default.useRef(null);
|
|
337
|
+
useSlideFocusManagement({
|
|
338
|
+
isSlideDisplayed: isDisplayed,
|
|
339
|
+
slideRef: groupRef
|
|
340
|
+
});
|
|
341
|
+
return /*#__PURE__*/jsx("div", {
|
|
342
|
+
ref: mergeRefs(groupRef, ref),
|
|
343
|
+
role: role,
|
|
344
|
+
className: classNames(className, CLASSNAME$3),
|
|
345
|
+
"aria-roledescription": "slide",
|
|
346
|
+
"aria-label": label,
|
|
347
|
+
...forwardedProps,
|
|
348
|
+
children: children
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
SlideshowItemGroup.displayName = COMPONENT_NAME$3;
|
|
352
|
+
SlideshowItemGroup.className = CLASSNAME$3;
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Component display name.
|
|
356
|
+
*/
|
|
357
|
+
const COMPONENT_NAME$2 = 'SlideshowItem';
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Component default class name and class prefix.
|
|
361
|
+
*/
|
|
362
|
+
const CLASSNAME$2 = getRootClassName(COMPONENT_NAME$2);
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* SlideshowItem component.
|
|
366
|
+
*
|
|
367
|
+
* @param props Component props.
|
|
368
|
+
* @param ref Component ref.
|
|
369
|
+
* @return React element.
|
|
370
|
+
*/
|
|
371
|
+
const SlideshowItem = forwardRef((props, ref) => {
|
|
372
|
+
const {
|
|
373
|
+
className,
|
|
374
|
+
children,
|
|
375
|
+
...forwardedProps
|
|
376
|
+
} = props;
|
|
377
|
+
return /*#__PURE__*/jsx("div", {
|
|
378
|
+
ref: ref,
|
|
379
|
+
className: classNames(className, CLASSNAME$2),
|
|
380
|
+
...forwardedProps,
|
|
381
|
+
children: children
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
SlideshowItem.displayName = COMPONENT_NAME$2;
|
|
385
|
+
SlideshowItem.className = CLASSNAME$2;
|
|
386
|
+
|
|
387
|
+
const isTouchDevice = () => 'ontouchstart' in window;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Listen swipe to navigate left and right.
|
|
391
|
+
*/
|
|
392
|
+
function useSwipeNavigate(element, onNext, onPrevious) {
|
|
393
|
+
useEffect(() => {
|
|
394
|
+
if (!element || !isTouchDevice()) return undefined;
|
|
395
|
+
return detectHorizontalSwipe(element, swipe => {
|
|
396
|
+
const callback = swipe === 'right' ? onPrevious : onNext;
|
|
397
|
+
callback?.();
|
|
398
|
+
});
|
|
399
|
+
}, [onPrevious, onNext, element]);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Calculate the currently visible pagination "bullet" range.
|
|
404
|
+
*/
|
|
405
|
+
function usePaginationVisibleRange(activeIndex, slideCount) {
|
|
406
|
+
const previousVisibleRangeRef = useRef();
|
|
407
|
+
return useMemo(() => {
|
|
408
|
+
const lastSlide = slideCount - 1;
|
|
409
|
+
const {
|
|
410
|
+
current: previousVisibleRange
|
|
411
|
+
} = previousVisibleRangeRef;
|
|
412
|
+
let newVisibleRange;
|
|
413
|
+
if (activeIndex === previousVisibleRange?.max && activeIndex < lastSlide) {
|
|
414
|
+
newVisibleRange = {
|
|
415
|
+
min: previousVisibleRange.min + 1,
|
|
416
|
+
max: previousVisibleRange.max + 1
|
|
417
|
+
};
|
|
418
|
+
} else if (activeIndex === previousVisibleRange?.min && activeIndex > 0) {
|
|
419
|
+
newVisibleRange = {
|
|
420
|
+
min: previousVisibleRange.min - 1,
|
|
421
|
+
max: previousVisibleRange.max - 1
|
|
422
|
+
};
|
|
423
|
+
} else {
|
|
424
|
+
const deltaItems = PAGINATION_ITEMS_MAX - 1;
|
|
425
|
+
let min = activeIndex - EDGE_FROM_ACTIVE_INDEX;
|
|
426
|
+
let max = activeIndex + EDGE_FROM_ACTIVE_INDEX;
|
|
427
|
+
if (activeIndex > lastSlide - EDGE_FROM_ACTIVE_INDEX) {
|
|
428
|
+
min = lastSlide - deltaItems;
|
|
429
|
+
max = lastSlide;
|
|
430
|
+
} else if (activeIndex < deltaItems) {
|
|
431
|
+
min = 0;
|
|
432
|
+
max = deltaItems;
|
|
433
|
+
}
|
|
434
|
+
newVisibleRange = {
|
|
435
|
+
min,
|
|
436
|
+
max
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
previousVisibleRangeRef.current = newVisibleRange;
|
|
440
|
+
return newVisibleRange;
|
|
441
|
+
}, [activeIndex, slideCount]);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Component display name.
|
|
446
|
+
*/
|
|
447
|
+
const COMPONENT_NAME$1 = 'SlideshowControls';
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Component default class name and class prefix.
|
|
451
|
+
*/
|
|
452
|
+
const CLASSNAME$1 = getRootClassName(COMPONENT_NAME$1);
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Component default props.
|
|
456
|
+
*/
|
|
457
|
+
const DEFAULT_PROPS = {
|
|
458
|
+
activeIndex: 0
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* SlideshowControls component.
|
|
463
|
+
*
|
|
464
|
+
* @param props Component props.
|
|
465
|
+
* @param ref Component ref.
|
|
466
|
+
* @return React element.
|
|
467
|
+
*/
|
|
468
|
+
const InternalSlideshowControls = forwardRef((props, ref) => {
|
|
469
|
+
const defaultTheme = useTheme() || Theme.light;
|
|
470
|
+
const {
|
|
471
|
+
activeIndex = DEFAULT_PROPS.activeIndex,
|
|
472
|
+
className,
|
|
473
|
+
nextButtonProps,
|
|
474
|
+
onNextClick,
|
|
475
|
+
onPaginationClick,
|
|
476
|
+
onPreviousClick,
|
|
477
|
+
parentRef,
|
|
478
|
+
previousButtonProps,
|
|
479
|
+
paginationProps,
|
|
480
|
+
slidesCount,
|
|
481
|
+
theme = defaultTheme,
|
|
482
|
+
isAutoPlaying = false,
|
|
483
|
+
playButtonProps,
|
|
484
|
+
paginationItemLabel,
|
|
485
|
+
paginationItemProps,
|
|
486
|
+
...forwardedProps
|
|
487
|
+
} = props;
|
|
488
|
+
let parent;
|
|
489
|
+
if (WINDOW) {
|
|
490
|
+
// Checking window object to avoid errors in SSR.
|
|
491
|
+
parent = parentRef instanceof HTMLElement ? parentRef : parentRef?.current;
|
|
492
|
+
}
|
|
493
|
+
const paginationRef = React__default.useRef(null);
|
|
494
|
+
// Listen to touch swipe navigate left & right.
|
|
495
|
+
useSwipeNavigate(parent,
|
|
496
|
+
// Go next without loopback.
|
|
497
|
+
useCallback(() => onNextClick?.(false), [onNextClick]),
|
|
498
|
+
// Go previous without loopback.
|
|
499
|
+
useCallback(() => onPreviousClick?.(false), [onPreviousClick]));
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Add roving tab index pattern to pagination items and activate slide on focus.
|
|
503
|
+
*/
|
|
504
|
+
useRovingTabIndex({
|
|
505
|
+
parentRef: paginationRef,
|
|
506
|
+
elementSelector: 'button',
|
|
507
|
+
keepTabIndex: true,
|
|
508
|
+
onElementFocus: element => {
|
|
509
|
+
element.click();
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Pagination "bullet" range.
|
|
514
|
+
const visibleRange = usePaginationVisibleRange(activeIndex, slidesCount);
|
|
515
|
+
|
|
516
|
+
// Inline style of wrapper element.
|
|
517
|
+
const wrapperStyle = {
|
|
518
|
+
transform: `translateX(-${PAGINATION_ITEM_SIZE * visibleRange.min}px)`
|
|
519
|
+
};
|
|
520
|
+
return /*#__PURE__*/jsxs("div", {
|
|
521
|
+
ref: ref,
|
|
522
|
+
...forwardedProps,
|
|
523
|
+
className: classNames(className, handleBasicClasses({
|
|
524
|
+
prefix: CLASSNAME$1,
|
|
525
|
+
theme
|
|
526
|
+
}), {
|
|
527
|
+
[`${CLASSNAME$1}--has-infinite-pagination`]: slidesCount > PAGINATION_ITEMS_MAX
|
|
528
|
+
}),
|
|
529
|
+
children: [/*#__PURE__*/jsx(IconButton, {
|
|
530
|
+
...previousButtonProps,
|
|
531
|
+
icon: mdiChevronLeft,
|
|
532
|
+
className: `${CLASSNAME$1}__navigation`,
|
|
533
|
+
color: theme === Theme.dark ? 'light' : 'dark',
|
|
534
|
+
emphasis: Emphasis.low,
|
|
535
|
+
onClick: onPreviousClick
|
|
536
|
+
}), /*#__PURE__*/jsx("div", {
|
|
537
|
+
ref: paginationRef,
|
|
538
|
+
className: `${CLASSNAME$1}__pagination`,
|
|
539
|
+
children: /*#__PURE__*/jsx("div", {
|
|
540
|
+
className: `${CLASSNAME$1}__pagination-items`,
|
|
541
|
+
style: wrapperStyle,
|
|
542
|
+
role: "tablist",
|
|
543
|
+
...paginationProps,
|
|
544
|
+
children: useMemo(() => range(slidesCount).map(index => {
|
|
545
|
+
const isOnEdge = index !== 0 && index !== slidesCount - 1 && (index === visibleRange.min || index === visibleRange.max);
|
|
546
|
+
const isActive = activeIndex === index;
|
|
547
|
+
const isOutRange = index < visibleRange.min || index > visibleRange.max;
|
|
548
|
+
const {
|
|
549
|
+
className: itemClassName = undefined,
|
|
550
|
+
label = undefined,
|
|
551
|
+
...itemProps
|
|
552
|
+
} = paginationItemProps ? paginationItemProps(index) : {};
|
|
553
|
+
const ariaLabel = label || paginationItemLabel?.(index) || `${index + 1} / ${slidesCount}`;
|
|
554
|
+
return /*#__PURE__*/jsx("button", {
|
|
555
|
+
className: classNames(handleBasicClasses({
|
|
556
|
+
prefix: `${CLASSNAME$1}__pagination-item`,
|
|
557
|
+
isActive,
|
|
558
|
+
isOnEdge,
|
|
559
|
+
isOutRange
|
|
560
|
+
}), itemClassName),
|
|
561
|
+
type: "button",
|
|
562
|
+
tabIndex: isActive ? undefined : -1,
|
|
563
|
+
role: "tab",
|
|
564
|
+
"aria-selected": isActive,
|
|
565
|
+
onClick: () => onPaginationClick?.(index),
|
|
566
|
+
"aria-label": ariaLabel,
|
|
567
|
+
...itemProps
|
|
568
|
+
}, index);
|
|
569
|
+
}), [slidesCount, visibleRange.min, visibleRange.max, activeIndex, paginationItemProps, paginationItemLabel, onPaginationClick])
|
|
570
|
+
})
|
|
571
|
+
}), playButtonProps ? /*#__PURE__*/jsx(IconButton, {
|
|
572
|
+
...playButtonProps,
|
|
573
|
+
icon: isAutoPlaying ? mdiPauseCircleOutline : mdiPlayCircleOutline,
|
|
574
|
+
className: `${CLASSNAME$1}__play`,
|
|
575
|
+
color: theme === Theme.dark ? 'light' : 'dark',
|
|
576
|
+
emphasis: Emphasis.low
|
|
577
|
+
}) : null, /*#__PURE__*/jsx(IconButton, {
|
|
578
|
+
...nextButtonProps,
|
|
579
|
+
icon: mdiChevronRight,
|
|
580
|
+
className: `${CLASSNAME$1}__navigation`,
|
|
581
|
+
color: theme === Theme.dark ? 'light' : 'dark',
|
|
582
|
+
emphasis: Emphasis.low,
|
|
583
|
+
onClick: onNextClick
|
|
584
|
+
})]
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
InternalSlideshowControls.displayName = COMPONENT_NAME$1;
|
|
588
|
+
InternalSlideshowControls.className = CLASSNAME$1;
|
|
589
|
+
InternalSlideshowControls.defaultProps = DEFAULT_PROPS;
|
|
590
|
+
const SlideshowControls = Object.assign(InternalSlideshowControls, {
|
|
591
|
+
useSlideshowControls,
|
|
592
|
+
useSlideshowControlsDefaultOptions: DEFAULT_OPTIONS
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Component display name.
|
|
597
|
+
*/
|
|
598
|
+
const COMPONENT_NAME = 'Slideshow';
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Component default class name and class prefix.
|
|
602
|
+
*/
|
|
603
|
+
const CLASSNAME = getRootClassName(COMPONENT_NAME);
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Slides component.
|
|
607
|
+
*
|
|
608
|
+
* @param props Component props.
|
|
609
|
+
* @param ref Component ref.
|
|
610
|
+
* @return React element.
|
|
611
|
+
*/
|
|
612
|
+
const Slides = forwardRef((props, ref) => {
|
|
613
|
+
const defaultTheme = useTheme();
|
|
614
|
+
const {
|
|
615
|
+
activeIndex,
|
|
616
|
+
id,
|
|
617
|
+
className,
|
|
618
|
+
theme = defaultTheme,
|
|
619
|
+
fillHeight,
|
|
620
|
+
groupBy,
|
|
621
|
+
isAutoPlaying,
|
|
622
|
+
toggleAutoPlay,
|
|
623
|
+
slidesId,
|
|
624
|
+
children,
|
|
625
|
+
afterSlides,
|
|
626
|
+
hasControls,
|
|
627
|
+
slideGroupLabel,
|
|
628
|
+
...forwardedProps
|
|
629
|
+
} = props;
|
|
630
|
+
const wrapperRef = React__default.useRef(null);
|
|
631
|
+
const startIndexVisible = activeIndex;
|
|
632
|
+
const endIndexVisible = startIndexVisible + 1;
|
|
633
|
+
|
|
634
|
+
// Inline style of wrapper element.
|
|
635
|
+
const wrapperStyle = {
|
|
636
|
+
transform: `translateX(-${FULL_WIDTH_PERCENT * activeIndex}%)`
|
|
637
|
+
};
|
|
638
|
+
const groups = React__default.useMemo(() => {
|
|
639
|
+
const childrenArray = Children.toArray(children);
|
|
640
|
+
return groupBy && groupBy > 1 ? chunk(childrenArray, groupBy) : childrenArray;
|
|
641
|
+
}, [children, groupBy]);
|
|
642
|
+
return /*#__PURE__*/jsxs("section", {
|
|
643
|
+
id: id,
|
|
644
|
+
ref: ref,
|
|
645
|
+
...forwardedProps,
|
|
646
|
+
className: classNames(className, handleBasicClasses({
|
|
647
|
+
prefix: CLASSNAME,
|
|
648
|
+
theme
|
|
649
|
+
}), {
|
|
650
|
+
[`${CLASSNAME}--fill-height`]: fillHeight,
|
|
651
|
+
[`${CLASSNAME}--group-by-${groupBy}`]: Boolean(groupBy)
|
|
652
|
+
}),
|
|
653
|
+
"aria-roledescription": "carousel",
|
|
654
|
+
children: [/*#__PURE__*/jsx("div", {
|
|
655
|
+
id: slidesId,
|
|
656
|
+
className: `${CLASSNAME}__slides`,
|
|
657
|
+
onMouseEnter: toggleAutoPlay,
|
|
658
|
+
onMouseLeave: toggleAutoPlay,
|
|
659
|
+
"aria-live": isAutoPlaying ? 'off' : 'polite',
|
|
660
|
+
children: /*#__PURE__*/jsx("div", {
|
|
661
|
+
ref: wrapperRef,
|
|
662
|
+
className: `${CLASSNAME}__wrapper`,
|
|
663
|
+
style: wrapperStyle,
|
|
664
|
+
children: groups.map((group, index) => /*#__PURE__*/jsx(SlideshowItemGroup, {
|
|
665
|
+
id: slidesId && buildSlideShowGroupId(slidesId, index),
|
|
666
|
+
role: hasControls ? 'tabpanel' : 'group',
|
|
667
|
+
label: slideGroupLabel ? slideGroupLabel(index + 1, groups.length) : undefined,
|
|
668
|
+
isDisplayed: index >= startIndexVisible && index < endIndexVisible,
|
|
669
|
+
children: group
|
|
670
|
+
}, index))
|
|
671
|
+
})
|
|
672
|
+
}), afterSlides]
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
Slides.displayName = COMPONENT_NAME;
|
|
676
|
+
Slides.className = CLASSNAME;
|
|
677
|
+
|
|
678
|
+
export { DEFAULT_OPTIONS as D, SlideshowItem as S, SlideshowControls as a, Slides as b, buildSlideShowGroupId as c };
|
|
679
|
+
//# sourceMappingURL=Slides-ce641b5f.js.map
|