@telus-uds/components-base 1.83.0 → 1.84.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/CHANGELOG.md +20 -2
- package/lib/Button/ButtonGroup.js +9 -0
- package/lib/Carousel/Carousel.js +314 -145
- package/lib/ExpandCollapse/ExpandCollapse.js +18 -9
- package/lib/ExpandCollapse/Panel.js +12 -0
- package/lib/ExpandCollapse/dictionary.js +17 -0
- package/lib/Icon/IconText.js +3 -3
- package/lib/Modal/WebModal.js +5 -3
- package/lib-module/Button/ButtonGroup.js +9 -0
- package/lib-module/Carousel/Carousel.js +312 -145
- package/lib-module/ExpandCollapse/ExpandCollapse.js +18 -9
- package/lib-module/ExpandCollapse/Panel.js +13 -1
- package/lib-module/ExpandCollapse/dictionary.js +10 -0
- package/lib-module/Icon/IconText.js +3 -3
- package/lib-module/Modal/WebModal.js +5 -3
- package/package.json +2 -2
- package/src/Button/ButtonGroup.jsx +9 -0
- package/src/Carousel/Carousel.jsx +338 -133
- package/src/ExpandCollapse/ExpandCollapse.jsx +13 -5
- package/src/ExpandCollapse/Panel.jsx +27 -5
- package/src/ExpandCollapse/dictionary.js +10 -0
- package/src/Icon/IconText.jsx +5 -3
- package/src/Modal/WebModal.jsx +8 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState, useRef, useEffect, useCallback, useMemo, forwardRef } from 'react';
|
|
2
2
|
import View from "react-native-web/dist/exports/View";
|
|
3
3
|
import Animated from "react-native-web/dist/exports/Animated";
|
|
4
4
|
import PanResponder from "react-native-web/dist/exports/PanResponder";
|
|
@@ -22,6 +22,11 @@ import CarouselTabsPanelItem from './CarouselTabs/CarouselTabsPanelItem';
|
|
|
22
22
|
import dictionary from './dictionary';
|
|
23
23
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
24
24
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
25
|
+
const TRANSITION_MODES = {
|
|
26
|
+
MANUAL: 'manual',
|
|
27
|
+
AUTOMATIC: 'automatic',
|
|
28
|
+
SWIPE: 'swipe'
|
|
29
|
+
};
|
|
25
30
|
const staticStyles = StyleSheet.create({
|
|
26
31
|
root: {
|
|
27
32
|
backgroundColor: 'transparent',
|
|
@@ -30,6 +35,12 @@ const staticStyles = StyleSheet.create({
|
|
|
30
35
|
position: 'relative',
|
|
31
36
|
top: 0,
|
|
32
37
|
left: 0
|
|
38
|
+
},
|
|
39
|
+
animationControlButton: {
|
|
40
|
+
position: 'absolute',
|
|
41
|
+
zIndex: 1,
|
|
42
|
+
right: Platform.OS === 'web' ? undefined : 40,
|
|
43
|
+
top: 40
|
|
33
44
|
}
|
|
34
45
|
});
|
|
35
46
|
const selectContainerStyles = width => ({
|
|
@@ -42,12 +53,29 @@ const selectSwipeAreaStyles = (count, width) => ({
|
|
|
42
53
|
justifyContent: 'space-between',
|
|
43
54
|
flexDirection: 'row'
|
|
44
55
|
});
|
|
56
|
+
const getDynamicPositionProperty = areStylesAppliedOnPreviousButton => areStylesAppliedOnPreviousButton ? 'left' : 'right';
|
|
57
|
+
const selectControlButtonPositionStyles = _ref => {
|
|
58
|
+
let {
|
|
59
|
+
positionVariant,
|
|
60
|
+
buttonWidth,
|
|
61
|
+
positionProperty = getDynamicPositionProperty(),
|
|
62
|
+
spaceBetweenSlideAndButton
|
|
63
|
+
} = _ref;
|
|
64
|
+
const styles = {};
|
|
65
|
+
if (positionVariant === 'edge') {
|
|
66
|
+
styles[positionProperty] = -1 * (buttonWidth / 2);
|
|
67
|
+
} else if (positionVariant === 'inside') {
|
|
68
|
+
styles[positionProperty] = 0;
|
|
69
|
+
} else if (positionVariant === 'outside') {
|
|
70
|
+
styles[positionProperty] = -1 * (spaceBetweenSlideAndButton + buttonWidth);
|
|
71
|
+
}
|
|
72
|
+
return styles;
|
|
73
|
+
};
|
|
45
74
|
const selectPreviousNextNavigationButtonStyles = (previousNextNavigationButtonWidth, previousNextNavigationPosition, spaceBetweenSlideAndPreviousNextNavigation, isFirstSlide, isLastSlide, areStylesAppliedOnPreviousButton) => {
|
|
46
75
|
const styles = {
|
|
47
76
|
zIndex: 1,
|
|
48
77
|
position: 'absolute'
|
|
49
78
|
};
|
|
50
|
-
const dynamicPositionProperty = areStylesAppliedOnPreviousButton ? 'left' : 'right';
|
|
51
79
|
if (isFirstSlide) {
|
|
52
80
|
styles.visibility = areStylesAppliedOnPreviousButton ? 'hidden' : 'visible';
|
|
53
81
|
} else if (isLastSlide) {
|
|
@@ -55,19 +83,20 @@ const selectPreviousNextNavigationButtonStyles = (previousNextNavigationButtonWi
|
|
|
55
83
|
} else {
|
|
56
84
|
styles.visibility = 'visible';
|
|
57
85
|
}
|
|
58
|
-
|
|
59
|
-
styles
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
86
|
+
return {
|
|
87
|
+
...styles,
|
|
88
|
+
...selectControlButtonPositionStyles({
|
|
89
|
+
positionVariant: previousNextNavigationPosition,
|
|
90
|
+
buttonWidth: previousNextNavigationButtonWidth,
|
|
91
|
+
positionProperty: getDynamicPositionProperty(areStylesAppliedOnPreviousButton),
|
|
92
|
+
spaceBetweenSlideAndButton: spaceBetweenSlideAndPreviousNextNavigation
|
|
93
|
+
})
|
|
94
|
+
};
|
|
66
95
|
};
|
|
67
|
-
const selectIconStyles =
|
|
96
|
+
const selectIconStyles = _ref2 => {
|
|
68
97
|
let {
|
|
69
98
|
iconBackgroundColor
|
|
70
|
-
} =
|
|
99
|
+
} = _ref2;
|
|
71
100
|
return {
|
|
72
101
|
backgroundColor: iconBackgroundColor
|
|
73
102
|
};
|
|
@@ -128,7 +157,7 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
|
|
|
128
157
|
- `spaceBetweenSlideAndPreviousNextNavigation` - Horizontal space between slide and previous/next navigational buttons
|
|
129
158
|
- `spaceBetweenSlideAndPanelNavigation` - Vertical space between slide area and panel navigation area
|
|
130
159
|
*/
|
|
131
|
-
const Carousel = /*#__PURE__*/
|
|
160
|
+
const Carousel = /*#__PURE__*/forwardRef((_ref3, ref) => {
|
|
132
161
|
let {
|
|
133
162
|
tokens,
|
|
134
163
|
variant,
|
|
@@ -158,8 +187,21 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
158
187
|
accessibilityLabel,
|
|
159
188
|
accessibilityLiveRegion = 'polite',
|
|
160
189
|
copy,
|
|
190
|
+
slideDuration = 0,
|
|
191
|
+
transitionDuration = 0,
|
|
192
|
+
autoPlay = false,
|
|
161
193
|
...rest
|
|
162
|
-
} =
|
|
194
|
+
} = _ref3;
|
|
195
|
+
let childrenArray = unpackFragment(children);
|
|
196
|
+
const autoPlayFeatureEnabled = autoPlay && slideDuration > 0 && transitionDuration > 0 && childrenArray.length > 1;
|
|
197
|
+
// if `Carousel` only has one `Carousel.Item`, convert this to a single-item array
|
|
198
|
+
if (!Array.isArray(childrenArray)) {
|
|
199
|
+
childrenArray = [childrenArray];
|
|
200
|
+
}
|
|
201
|
+
const getCopy = useCopy({
|
|
202
|
+
dictionary,
|
|
203
|
+
copy
|
|
204
|
+
});
|
|
163
205
|
const viewport = useViewport();
|
|
164
206
|
const themeTokens = useThemeTokens('Carousel', tokens, variant, {
|
|
165
207
|
viewport
|
|
@@ -167,84 +209,53 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
167
209
|
const {
|
|
168
210
|
previousIcon,
|
|
169
211
|
nextIcon,
|
|
212
|
+
playIcon,
|
|
213
|
+
pauseIcon,
|
|
170
214
|
showPreviousNextNavigation,
|
|
171
215
|
showPanelNavigation,
|
|
172
216
|
showPanelTabs,
|
|
173
217
|
spaceBetweenSlideAndPreviousNextNavigation
|
|
174
218
|
} = themeTokens;
|
|
175
|
-
const [activeIndex, setActiveIndex] =
|
|
176
|
-
const
|
|
177
|
-
const handleAnimationStart = React.useCallback(function () {
|
|
178
|
-
if (typeof onAnimationStart === 'function') onAnimationStart(...arguments);
|
|
179
|
-
setIsAnimating(true);
|
|
180
|
-
}, [onAnimationStart]);
|
|
181
|
-
const handleAnimationEnd = React.useCallback(function () {
|
|
182
|
-
if (typeof onAnimationEnd === 'function') onAnimationEnd(...arguments);
|
|
183
|
-
setIsAnimating(false);
|
|
184
|
-
}, [onAnimationEnd]);
|
|
185
|
-
const getCopy = useCopy({
|
|
186
|
-
dictionary,
|
|
187
|
-
copy
|
|
188
|
-
});
|
|
189
|
-
let childrenArray = unpackFragment(children);
|
|
190
|
-
// if `Carousel` only has one `Carousel.Item`, convert this to a single-item array
|
|
191
|
-
if (!Array.isArray(childrenArray)) {
|
|
192
|
-
childrenArray = [childrenArray];
|
|
193
|
-
}
|
|
194
|
-
const systemProps = selectProps({
|
|
195
|
-
...rest,
|
|
196
|
-
accessibilityRole,
|
|
197
|
-
accessibilityLabel,
|
|
198
|
-
accessibilityValue: {
|
|
199
|
-
min: 1,
|
|
200
|
-
max: childrenArray.length,
|
|
201
|
-
now: activeIndex + 1
|
|
202
|
-
}
|
|
203
|
-
});
|
|
219
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
220
|
+
const activeIndexRef = useRef(activeIndex);
|
|
204
221
|
const {
|
|
205
222
|
reduceMotionEnabled
|
|
206
223
|
} = useA11yInfo();
|
|
224
|
+
const reduceMotionRef = useRef(reduceMotionEnabled);
|
|
207
225
|
const [containerLayout, setContainerLayout] = React.useState({
|
|
208
226
|
x: 0,
|
|
209
227
|
y: 0,
|
|
210
228
|
width: 0
|
|
211
229
|
});
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
const
|
|
230
|
+
const containerLayoutRef = useRef(containerLayout);
|
|
231
|
+
const [previousNextNavigationButtonWidth, setPreviousNextNavigationButtonWidth] = useState(0);
|
|
232
|
+
const firstFocusRef = useRef(null);
|
|
233
|
+
const pan = useRef(new Animated.ValueXY()).current;
|
|
234
|
+
const animatedX = useRef(0);
|
|
235
|
+
const animatedY = useRef(0);
|
|
236
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
237
|
+
/**
|
|
238
|
+
* While having the same starting point, `isAutoPlayEnabled` and `isCarouselPlaying` are different states
|
|
239
|
+
*
|
|
240
|
+
* `isAutoPlayEnabled` is a state to determine if the autoplay feature is enabled or disabled
|
|
241
|
+
* `isCarouselPlaying` is a state to determine if the carousel is currently playing or paused
|
|
242
|
+
*/
|
|
243
|
+
const [isAutoPlayEnabled, setIsAutoPlayEnabled] = useState(autoPlayFeatureEnabled);
|
|
244
|
+
const [isCarouselPlaying, setisCarouselPlaying] = useState(autoPlayFeatureEnabled);
|
|
245
|
+
const isSwiping = useRef(false);
|
|
246
|
+
const autoPlayRef = useRef(null);
|
|
217
247
|
const isFirstSlide = !activeIndex;
|
|
218
|
-
const isLastSlide = activeIndex + 1 >=
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
return setContainerLayout(prevState => ({
|
|
230
|
-
...prevState,
|
|
231
|
-
x,
|
|
232
|
-
y,
|
|
233
|
-
width
|
|
234
|
-
}));
|
|
235
|
-
};
|
|
236
|
-
const onPreviousNextNavigationButtonLayout = _ref4 => {
|
|
237
|
-
let {
|
|
238
|
-
nativeEvent: {
|
|
239
|
-
layout: {
|
|
240
|
-
width
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
} = _ref4;
|
|
244
|
-
return setPreviousNextNavigationButtonWidth(width);
|
|
245
|
-
};
|
|
246
|
-
const updateOffset = React.useCallback(() => {
|
|
247
|
-
animatedX.current = containerLayout.width * activeIndex * -1;
|
|
248
|
+
const isLastSlide = activeIndex + 1 >= childrenArray.length;
|
|
249
|
+
const handleAnimationStart = useCallback(function () {
|
|
250
|
+
if (typeof onAnimationStart === 'function') onAnimationStart(...arguments);
|
|
251
|
+
setIsAnimating(true);
|
|
252
|
+
}, [onAnimationStart]);
|
|
253
|
+
const handleAnimationEnd = useCallback(function () {
|
|
254
|
+
if (typeof onAnimationEnd === 'function') onAnimationEnd(...arguments);
|
|
255
|
+
setIsAnimating(false);
|
|
256
|
+
}, [onAnimationEnd]);
|
|
257
|
+
const updateOffset = useCallback(() => {
|
|
258
|
+
animatedX.current = containerLayoutRef.current.width * activeIndexRef.current * -1;
|
|
248
259
|
animatedY.current = 0;
|
|
249
260
|
pan.setOffset({
|
|
250
261
|
x: animatedX.current,
|
|
@@ -254,20 +265,27 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
254
265
|
x: 0,
|
|
255
266
|
y: 0
|
|
256
267
|
});
|
|
257
|
-
}, [
|
|
258
|
-
const animate =
|
|
268
|
+
}, [pan, animatedX]);
|
|
269
|
+
const animate = useCallback((toValue, toIndex) => {
|
|
259
270
|
const handleAnimationEndToIndex = function () {
|
|
260
271
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
261
272
|
args[_key] = arguments[_key];
|
|
262
273
|
}
|
|
263
274
|
return handleAnimationEnd(toIndex, ...args);
|
|
264
275
|
};
|
|
265
|
-
if (
|
|
276
|
+
if (reduceMotionRef.current || isSwiping.current) {
|
|
266
277
|
Animated.timing(pan, {
|
|
267
278
|
toValue,
|
|
268
279
|
duration: 1,
|
|
269
280
|
useNativeDriver: false
|
|
270
281
|
}).start(handleAnimationEndToIndex);
|
|
282
|
+
} else if (isAutoPlayEnabled) {
|
|
283
|
+
Animated.timing(pan, {
|
|
284
|
+
...springConfig,
|
|
285
|
+
toValue,
|
|
286
|
+
useNativeDriver: false,
|
|
287
|
+
duration: transitionDuration * 1000
|
|
288
|
+
}).start(handleAnimationEndToIndex);
|
|
271
289
|
} else {
|
|
272
290
|
Animated.spring(pan, {
|
|
273
291
|
...springConfig,
|
|
@@ -275,45 +293,157 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
275
293
|
useNativeDriver: false
|
|
276
294
|
}).start(handleAnimationEndToIndex);
|
|
277
295
|
}
|
|
278
|
-
}, [pan, springConfig,
|
|
279
|
-
const
|
|
296
|
+
}, [pan, springConfig, handleAnimationEnd, transitionDuration, isAutoPlayEnabled]);
|
|
297
|
+
const stopAutoplay = useCallback(() => {
|
|
298
|
+
if (autoPlayRef !== null && autoPlayRef !== void 0 && autoPlayRef.current) {
|
|
299
|
+
clearTimeout(autoPlayRef === null || autoPlayRef === void 0 ? void 0 : autoPlayRef.current);
|
|
300
|
+
}
|
|
301
|
+
}, []);
|
|
302
|
+
const updateIndex = useCallback(function () {
|
|
280
303
|
let delta = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
304
|
+
let transitionMode = arguments.length > 1 ? arguments[1] : undefined;
|
|
281
305
|
const toValue = {
|
|
282
306
|
x: 0,
|
|
283
307
|
y: 0
|
|
284
308
|
};
|
|
285
309
|
let skipChanges = !delta;
|
|
286
310
|
let calcDelta = delta;
|
|
287
|
-
if (
|
|
288
|
-
skipChanges =
|
|
289
|
-
calcDelta =
|
|
290
|
-
} else if (
|
|
291
|
-
skipChanges =
|
|
292
|
-
calcDelta = -1 *
|
|
311
|
+
if (activeIndexRef.current <= 0 && delta < 0) {
|
|
312
|
+
skipChanges = transitionMode !== TRANSITION_MODES.AUTOMATIC;
|
|
313
|
+
calcDelta = childrenArray.length + delta;
|
|
314
|
+
} else if (activeIndexRef.current + 1 >= childrenArray.length && delta > 0) {
|
|
315
|
+
skipChanges = transitionMode !== TRANSITION_MODES.AUTOMATIC;
|
|
316
|
+
calcDelta = -1 * activeIndexRef.current + delta - 1;
|
|
293
317
|
}
|
|
294
|
-
const index =
|
|
318
|
+
const index = activeIndexRef.current + calcDelta;
|
|
295
319
|
if (skipChanges) {
|
|
296
320
|
animate(toValue, index);
|
|
297
321
|
return calcDelta;
|
|
298
322
|
}
|
|
323
|
+
stopAutoplay();
|
|
299
324
|
setActiveIndex(index);
|
|
300
|
-
toValue.x =
|
|
325
|
+
toValue.x = containerLayoutRef.current.width * -1 * calcDelta;
|
|
301
326
|
animate(toValue, index);
|
|
327
|
+
if (isCarouselPlaying) {
|
|
328
|
+
stopAutoplay();
|
|
329
|
+
if (index === 0 && activeIndexRef.current + 1 === childrenArray.length && transitionMode === TRANSITION_MODES.AUTOMATIC) {
|
|
330
|
+
setisCarouselPlaying(false);
|
|
331
|
+
} else if (isAutoPlayEnabled) {
|
|
332
|
+
autoPlayRef.current = setTimeout(() => {
|
|
333
|
+
var _firstFocusRef$curren;
|
|
334
|
+
updateOffset();
|
|
335
|
+
handleAnimationStart(activeIndexRef.current);
|
|
336
|
+
updateIndex(slideDuration < 0 ? -1 : 1, TRANSITION_MODES.AUTOMATIC);
|
|
337
|
+
if (refocus) (_firstFocusRef$curren = firstFocusRef.current) === null || _firstFocusRef$curren === void 0 ? void 0 : _firstFocusRef$curren.focus();
|
|
338
|
+
}, Math.abs(slideDuration) * 1000);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
302
341
|
if (onIndexChanged) onIndexChanged(calcDelta, index);
|
|
303
342
|
return calcDelta;
|
|
304
|
-
}, [
|
|
305
|
-
const
|
|
306
|
-
|
|
343
|
+
}, [handleAnimationStart, refocus, slideDuration, updateOffset, animate, childrenArray.length, onIndexChanged, isCarouselPlaying, stopAutoplay, isAutoPlayEnabled]);
|
|
344
|
+
const startAutoplay = useCallback(() => {
|
|
345
|
+
stopAutoplay();
|
|
346
|
+
if (isAutoPlayEnabled) {
|
|
347
|
+
autoPlayRef.current = setTimeout(() => {
|
|
348
|
+
var _firstFocusRef$curren2;
|
|
349
|
+
updateOffset();
|
|
350
|
+
handleAnimationStart(activeIndexRef.current);
|
|
351
|
+
updateIndex(slideDuration < 0 ? -1 : 1, TRANSITION_MODES.AUTOMATIC);
|
|
352
|
+
if (refocus && Platform.OS === 'web') (_firstFocusRef$curren2 = firstFocusRef.current) === null || _firstFocusRef$curren2 === void 0 ? void 0 : _firstFocusRef$curren2.focus();
|
|
353
|
+
}, Math.abs(slideDuration) * 1000);
|
|
354
|
+
}
|
|
355
|
+
}, [handleAnimationStart, refocus, updateIndex, updateOffset, slideDuration, stopAutoplay, isAutoPlayEnabled]);
|
|
356
|
+
const fixOffsetAndGo = useCallback((delta, transitionMode) => {
|
|
357
|
+
var _firstFocusRef$curren3;
|
|
307
358
|
updateOffset();
|
|
308
|
-
handleAnimationStart(
|
|
309
|
-
updateIndex(delta);
|
|
310
|
-
if (refocus) (_firstFocusRef$
|
|
311
|
-
}, [updateIndex, updateOffset,
|
|
312
|
-
const goToNeighboring =
|
|
359
|
+
handleAnimationStart(activeIndexRef.current);
|
|
360
|
+
updateIndex(delta, transitionMode);
|
|
361
|
+
if (refocus && Platform.OS === 'web') (_firstFocusRef$curren3 = firstFocusRef.current) === null || _firstFocusRef$curren3 === void 0 ? void 0 : _firstFocusRef$curren3.focus();
|
|
362
|
+
}, [updateIndex, updateOffset, handleAnimationStart, refocus]);
|
|
363
|
+
const goToNeighboring = useCallback(function () {
|
|
313
364
|
let toPrev = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
314
|
-
|
|
365
|
+
let transitionMode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : TRANSITION_MODES.MANUAL;
|
|
366
|
+
fixOffsetAndGo(toPrev ? -1 : 1, transitionMode);
|
|
315
367
|
}, [fixOffsetAndGo]);
|
|
316
|
-
|
|
368
|
+
useEffect(() => {
|
|
369
|
+
activeIndexRef.current = activeIndex;
|
|
370
|
+
}, [activeIndex]);
|
|
371
|
+
useEffect(() => {
|
|
372
|
+
reduceMotionRef.current = reduceMotionEnabled;
|
|
373
|
+
}, [reduceMotionEnabled]);
|
|
374
|
+
useEffect(() => {
|
|
375
|
+
containerLayoutRef.current = containerLayout;
|
|
376
|
+
}, [containerLayout]);
|
|
377
|
+
useEffect(() => {
|
|
378
|
+
pan.x.addListener(_ref4 => {
|
|
379
|
+
let {
|
|
380
|
+
value
|
|
381
|
+
} = _ref4;
|
|
382
|
+
animatedX.current = value;
|
|
383
|
+
});
|
|
384
|
+
pan.y.addListener(_ref5 => {
|
|
385
|
+
let {
|
|
386
|
+
value
|
|
387
|
+
} = _ref5;
|
|
388
|
+
animatedY.current = value;
|
|
389
|
+
});
|
|
390
|
+
if (isCarouselPlaying) {
|
|
391
|
+
startAutoplay();
|
|
392
|
+
}
|
|
393
|
+
return () => {
|
|
394
|
+
stopAutoplay();
|
|
395
|
+
pan.x.removeAllListeners();
|
|
396
|
+
pan.y.removeAllListeners();
|
|
397
|
+
};
|
|
398
|
+
}, [pan.x, pan.y, startAutoplay, stopAutoplay, isCarouselPlaying]);
|
|
399
|
+
useEffect(() => {
|
|
400
|
+
const subscription = Dimensions.addEventListener('change', () => {
|
|
401
|
+
updateOffset();
|
|
402
|
+
});
|
|
403
|
+
return () => {
|
|
404
|
+
if (subscription.remove) {
|
|
405
|
+
subscription.remove();
|
|
406
|
+
} else {
|
|
407
|
+
Dimensions.removeEventListener('change', updateOffset);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
}, [updateOffset]);
|
|
411
|
+
useEffect(() => {
|
|
412
|
+
setIsAutoPlayEnabled(autoPlay && slideDuration > 0 && transitionDuration > 0 && childrenArray.length > 1);
|
|
413
|
+
}, [autoPlay, slideDuration, transitionDuration, childrenArray.length]);
|
|
414
|
+
useEffect(() => {
|
|
415
|
+
return () => {
|
|
416
|
+
stopAutoplay();
|
|
417
|
+
};
|
|
418
|
+
}, [stopAutoplay]);
|
|
419
|
+
const onContainerLayout = _ref6 => {
|
|
420
|
+
let {
|
|
421
|
+
nativeEvent: {
|
|
422
|
+
layout: {
|
|
423
|
+
x,
|
|
424
|
+
y,
|
|
425
|
+
width
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
} = _ref6;
|
|
429
|
+
return setContainerLayout(prevState => ({
|
|
430
|
+
...prevState,
|
|
431
|
+
x,
|
|
432
|
+
y,
|
|
433
|
+
width
|
|
434
|
+
}));
|
|
435
|
+
};
|
|
436
|
+
const onPreviousNextNavigationButtonLayout = _ref7 => {
|
|
437
|
+
let {
|
|
438
|
+
nativeEvent: {
|
|
439
|
+
layout: {
|
|
440
|
+
width
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
} = _ref7;
|
|
444
|
+
return setPreviousNextNavigationButtonWidth(width);
|
|
445
|
+
};
|
|
446
|
+
const isSwipeAllowed = useCallback(() => {
|
|
317
447
|
if (childrenArray.length === 1) {
|
|
318
448
|
return false;
|
|
319
449
|
}
|
|
@@ -322,72 +452,59 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
322
452
|
}
|
|
323
453
|
return true;
|
|
324
454
|
}, [viewport, childrenArray.length]);
|
|
325
|
-
const panResponder =
|
|
455
|
+
const panResponder = useMemo(() => PanResponder.create({
|
|
326
456
|
onPanResponderTerminationRequest: () => false,
|
|
327
457
|
onMoveShouldSetResponderCapture: () => true,
|
|
328
458
|
onMoveShouldSetPanResponderCapture: (_, gestureState) => {
|
|
329
459
|
if (!isSwipeAllowed()) {
|
|
330
460
|
return false;
|
|
331
461
|
}
|
|
332
|
-
handleAnimationStart(
|
|
333
|
-
|
|
462
|
+
handleAnimationStart(activeIndexRef.current);
|
|
463
|
+
const allow = Math.abs(gestureState.dx) > minDistanceToCapture;
|
|
464
|
+
if (allow) {
|
|
465
|
+
isSwiping.current = true;
|
|
466
|
+
stopAutoplay();
|
|
467
|
+
}
|
|
468
|
+
return allow;
|
|
469
|
+
},
|
|
470
|
+
onPanResponderGrant: () => {
|
|
471
|
+
updateOffset();
|
|
334
472
|
},
|
|
335
|
-
onPanResponderGrant: () => updateOffset(),
|
|
336
473
|
onPanResponderMove: Animated.event([null, {
|
|
337
474
|
dx: pan.x
|
|
338
475
|
}], {
|
|
339
476
|
useNativeDriver: false
|
|
340
477
|
}),
|
|
341
478
|
onPanResponderRelease: (_, gesture) => {
|
|
479
|
+
if (isCarouselPlaying) {
|
|
480
|
+
startAutoplay();
|
|
481
|
+
}
|
|
342
482
|
const correction = gesture.moveX - gesture.x0;
|
|
343
|
-
if (Math.abs(correction) <
|
|
483
|
+
if (Math.abs(correction) < containerLayoutRef.current.width * minDistanceForAction) {
|
|
344
484
|
animate({
|
|
345
485
|
x: 0,
|
|
346
486
|
y: 0
|
|
347
487
|
}, 0);
|
|
348
488
|
} else {
|
|
349
489
|
const delta = correction > 0 ? -1 : 1;
|
|
350
|
-
updateIndex(delta);
|
|
490
|
+
updateIndex(delta, TRANSITION_MODES.SWIPE);
|
|
351
491
|
}
|
|
492
|
+
isSwiping.current = false;
|
|
352
493
|
}
|
|
353
|
-
}), [
|
|
354
|
-
|
|
355
|
-
pan.x.addListener(_ref5 => {
|
|
356
|
-
let {
|
|
357
|
-
value
|
|
358
|
-
} = _ref5;
|
|
359
|
-
animatedX.current = value;
|
|
360
|
-
});
|
|
361
|
-
pan.y.addListener(_ref6 => {
|
|
362
|
-
let {
|
|
363
|
-
value
|
|
364
|
-
} = _ref6;
|
|
365
|
-
animatedY.current = value;
|
|
366
|
-
});
|
|
367
|
-
return () => {
|
|
368
|
-
pan.x.removeAllListeners();
|
|
369
|
-
pan.y.removeAllListeners();
|
|
370
|
-
};
|
|
371
|
-
}, [pan.x, pan.y]);
|
|
372
|
-
React.useEffect(() => {
|
|
373
|
-
const subscription = Dimensions.addEventListener('change', () => {
|
|
374
|
-
updateOffset();
|
|
375
|
-
});
|
|
376
|
-
return () => subscription === null || subscription === void 0 ? void 0 : subscription.remove();
|
|
377
|
-
});
|
|
378
|
-
const goToNext = React.useCallback(() => {
|
|
494
|
+
}), [updateIndex, updateOffset, animate, isSwipeAllowed, minDistanceForAction, handleAnimationStart, minDistanceToCapture, pan.x, startAutoplay, stopAutoplay, isCarouselPlaying]);
|
|
495
|
+
const goToNext = useCallback(() => {
|
|
379
496
|
goToNeighboring();
|
|
380
497
|
}, [goToNeighboring]);
|
|
381
|
-
const goToPrev =
|
|
498
|
+
const goToPrev = useCallback(() => {
|
|
382
499
|
goToNeighboring(true);
|
|
383
500
|
}, [goToNeighboring]);
|
|
384
|
-
const goTo =
|
|
501
|
+
const goTo = useCallback(function () {
|
|
385
502
|
let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
386
|
-
const delta = index -
|
|
503
|
+
const delta = index - activeIndexRef.current;
|
|
387
504
|
if (delta) {
|
|
388
|
-
fixOffsetAndGo(delta);
|
|
505
|
+
fixOffsetAndGo(delta, TRANSITION_MODES.MANUAL);
|
|
389
506
|
}
|
|
390
|
-
}, [fixOffsetAndGo
|
|
507
|
+
}, [fixOffsetAndGo]);
|
|
391
508
|
|
|
392
509
|
// @TODO: - these are Allium-theme variants and won't have any effect in themes that don't implement them.
|
|
393
510
|
// Normally we avoid setting variants of subcomponents, however this could be re-considered.
|
|
@@ -397,7 +514,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
397
514
|
raised: !(variant !== null && variant !== void 0 && variant.inverse) && true,
|
|
398
515
|
inverse: variant === null || variant === void 0 ? void 0 : variant.inverse
|
|
399
516
|
};
|
|
400
|
-
const getCopyWithPlaceholders =
|
|
517
|
+
const getCopyWithPlaceholders = useCallback(copyKey => {
|
|
401
518
|
const copyText = getCopy(copyKey).replace(/%\{title\}/g, title).replace(/%\{itemLabel\}/g, itemLabel).replace(/%\{stepNumber\}/g, activeIndex + 1).replace(/%\{stepCount\}/g, childrenArray.length);
|
|
402
519
|
|
|
403
520
|
// First word might be a lowercase placeholder: capitalize the first letter
|
|
@@ -420,6 +537,17 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
420
537
|
}
|
|
421
538
|
}
|
|
422
539
|
};
|
|
540
|
+
const systemProps = selectProps({
|
|
541
|
+
...rest,
|
|
542
|
+
accessibilityRole,
|
|
543
|
+
accessibilityLabel,
|
|
544
|
+
accessibilityValue: {
|
|
545
|
+
min: 1,
|
|
546
|
+
max: childrenArray.length,
|
|
547
|
+
now: activeIndex + 1
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
|
|
423
551
|
// If container isn't used for focus, give it a label of title if none is passed in,
|
|
424
552
|
// otherwise read the current position on focus
|
|
425
553
|
const containerAccessibilityLabel = systemProps.accessibilityLabel ?? isFirstFocusContainer ? `${title ? `${title} ` : ''}${getCopyWithPlaceholders('stepTrackerLabel')}` : title;
|
|
@@ -431,6 +559,14 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
431
559
|
focusable: true
|
|
432
560
|
})
|
|
433
561
|
};
|
|
562
|
+
const onAnimationControlButtonPress = useCallback(() => {
|
|
563
|
+
if (isCarouselPlaying) {
|
|
564
|
+
stopAutoplay();
|
|
565
|
+
} else {
|
|
566
|
+
startAutoplay();
|
|
567
|
+
}
|
|
568
|
+
setisCarouselPlaying(prevState => !prevState);
|
|
569
|
+
}, [isCarouselPlaying, stopAutoplay, startAutoplay]);
|
|
434
570
|
return /*#__PURE__*/_jsxs(CarouselProvider, {
|
|
435
571
|
activeIndex: activeIndex,
|
|
436
572
|
goTo: goTo,
|
|
@@ -447,7 +583,19 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
447
583
|
ref: ref,
|
|
448
584
|
...systemProps,
|
|
449
585
|
...containerProps,
|
|
450
|
-
children: [
|
|
586
|
+
children: [isAutoPlayEnabled ? /*#__PURE__*/_jsx(View, {
|
|
587
|
+
style: [staticStyles.animationControlButton, selectControlButtonPositionStyles({
|
|
588
|
+
positionVariant: previousNextNavigationPosition,
|
|
589
|
+
buttonWidth: previousNextNavigationButtonWidth,
|
|
590
|
+
positionProperty: getDynamicPositionProperty(),
|
|
591
|
+
spaceBetweenSlideAndButton: spaceBetweenSlideAndPreviousNextNavigation
|
|
592
|
+
})],
|
|
593
|
+
children: /*#__PURE__*/_jsx(IconButton, {
|
|
594
|
+
icon: isCarouselPlaying ? pauseIcon : playIcon,
|
|
595
|
+
variant: previousNextIconButtonVariants,
|
|
596
|
+
onPress: onAnimationControlButtonPress
|
|
597
|
+
})
|
|
598
|
+
}) : null, showPreviousNextNavigation && childrenArray.length > 1 ? /*#__PURE__*/_jsx(View, {
|
|
451
599
|
style: selectPreviousNextNavigationButtonStyles(previousNextNavigationButtonWidth, previousNextNavigationPosition, spaceBetweenSlideAndPreviousNextNavigation, isFirstSlide, isLastSlide, true),
|
|
452
600
|
testID: "previous-button-container",
|
|
453
601
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
@@ -471,7 +619,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
471
619
|
}), /*#__PURE__*/_jsx(View, {
|
|
472
620
|
style: selectContainerStyles(containerLayout.width),
|
|
473
621
|
children: /*#__PURE__*/_jsx(Animated.View, {
|
|
474
|
-
style: StyleSheet.flatten([selectSwipeAreaStyles(
|
|
622
|
+
style: StyleSheet.flatten([selectSwipeAreaStyles(childrenArray.length, containerLayout.width), {
|
|
475
623
|
transform: [{
|
|
476
624
|
translateX: pan.x
|
|
477
625
|
}, {
|
|
@@ -564,7 +712,7 @@ Carousel.propTypes = {
|
|
|
564
712
|
* This function is also provided with a parameter indicating changed index (either 1, or -1)
|
|
565
713
|
* Use it as follows:
|
|
566
714
|
* ```js
|
|
567
|
-
* const onIndexChangedCallback =
|
|
715
|
+
* const onIndexChangedCallback = useCallback((changedIndex, currentActiveIndex) => {
|
|
568
716
|
* console.log(changedIndex)
|
|
569
717
|
* }, []) // pass local dependencies as per your component
|
|
570
718
|
* <Carousel
|
|
@@ -615,7 +763,7 @@ Carousel.propTypes = {
|
|
|
615
763
|
* This function is also provided with a parameter indicating the current slide index before animation starts
|
|
616
764
|
* Use it as follows:
|
|
617
765
|
* ```js
|
|
618
|
-
* const onAnimationStartCallback =
|
|
766
|
+
* const onAnimationStartCallback = useCallback((currentIndex) => {
|
|
619
767
|
* console.log(currentIndex)
|
|
620
768
|
* }, []) // pass local dependencies as per your component
|
|
621
769
|
* <Carousel
|
|
@@ -632,7 +780,7 @@ Carousel.propTypes = {
|
|
|
632
780
|
* This function is also provided with a parameter indicating the updated slide index after animation ends
|
|
633
781
|
* Use it as follows:
|
|
634
782
|
* ```js
|
|
635
|
-
* const onAnimationEndCallback =
|
|
783
|
+
* const onAnimationEndCallback = useCallback((changedIndex) => {
|
|
636
784
|
* console.log(changedIndex)
|
|
637
785
|
* }, []) // pass local dependencies as per your component
|
|
638
786
|
* <Carousel
|
|
@@ -670,7 +818,26 @@ Carousel.propTypes = {
|
|
|
670
818
|
* Note that if the immediate Carousel children do not all render as `'li'` elements,
|
|
671
819
|
* this should be changed (e.g. pass tag="div") because only 'li' is a valid child of 'ul'.
|
|
672
820
|
*/
|
|
673
|
-
tag: PropTypes.oneOf(layoutTags)
|
|
821
|
+
tag: PropTypes.oneOf(layoutTags),
|
|
822
|
+
/**
|
|
823
|
+
* If set to `true`, the Carousel will automatically transition between slides
|
|
824
|
+
* and show the play/pause button
|
|
825
|
+
* - Default value is `false`
|
|
826
|
+
* - `slideDuration` and `transitionDuration` are required to be set for this to work
|
|
827
|
+
*/
|
|
828
|
+
autoPlay: PropTypes.bool,
|
|
829
|
+
/**
|
|
830
|
+
* Duration of the time in seconds spent on each slide
|
|
831
|
+
* - Default value is `0`
|
|
832
|
+
* - `autoPlay` and `transitionDuration` are required to be set for this to work
|
|
833
|
+
*/
|
|
834
|
+
slideDuration: PropTypes.number,
|
|
835
|
+
/**
|
|
836
|
+
* Duration of the time in seconds between each slide transition
|
|
837
|
+
* - Default value is `0`
|
|
838
|
+
* - `autoPlay` and `slideDuration` are required to be set for this to work
|
|
839
|
+
*/
|
|
840
|
+
transitionDuration: PropTypes.number
|
|
674
841
|
};
|
|
675
842
|
Carousel.Item = CarouselItem;
|
|
676
843
|
Carousel.displayName = 'Carousel';
|