@telus-uds/components-base 1.10.0 → 1.12.1

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.
Files changed (117) hide show
  1. package/CHANGELOG.md +37 -3
  2. package/component-docs.json +413 -62
  3. package/lib/BaseProvider/index.js +7 -2
  4. package/lib/Button/ButtonBase.js +18 -14
  5. package/lib/Carousel/Carousel.js +92 -71
  6. package/lib/Carousel/CarouselContext.js +12 -4
  7. package/lib/Carousel/CarouselItem/CarouselItem.js +24 -9
  8. package/lib/Carousel/CarouselStepTracker/CarouselStepTracker.js +56 -0
  9. package/lib/Carousel/CarouselStepTracker/index.js +13 -0
  10. package/lib/Carousel/dictionary.js +23 -0
  11. package/lib/Checkbox/Checkbox.js +7 -3
  12. package/lib/Checkbox/CheckboxGroup.js +1 -1
  13. package/lib/Feedback/Feedback.js +18 -10
  14. package/lib/Icon/IconText.js +5 -0
  15. package/lib/InputLabel/InputLabel.js +11 -5
  16. package/lib/InputSupports/InputSupports.js +10 -3
  17. package/lib/InputSupports/useInputSupports.js +3 -2
  18. package/lib/Link/LinkBase.js +7 -3
  19. package/lib/List/ListItem.js +7 -3
  20. package/lib/Modal/Modal.js +4 -0
  21. package/lib/Notification/Notification.js +7 -2
  22. package/lib/Pagination/Pagination.js +7 -3
  23. package/lib/RadioCard/RadioCard.js +6 -1
  24. package/lib/Select/Select.js +7 -3
  25. package/lib/Skeleton/Skeleton.js +1 -0
  26. package/lib/StepTracker/Step.js +8 -4
  27. package/lib/StepTracker/StepTracker.js +17 -13
  28. package/lib/Tabs/TabsItem.js +4 -0
  29. package/lib/TextInput/TextInput.js +3 -1
  30. package/lib/TextInput/TextInputBase.js +7 -3
  31. package/lib/ThemeProvider/ThemeProvider.js +20 -3
  32. package/lib/ThemeProvider/utils/styles.js +8 -1
  33. package/lib/ThemeProvider/utils/theme-tokens.js +1 -1
  34. package/lib/Typography/Typography.js +6 -2
  35. package/lib/index.js +9 -0
  36. package/lib/utils/index.js +9 -0
  37. package/lib/utils/props/clickProps.js +2 -2
  38. package/lib/utils/props/handlerProps.js +77 -31
  39. package/lib/utils/useScrollBlocking.js +66 -0
  40. package/lib/utils/useScrollBlocking.native.js +11 -0
  41. package/lib-module/BaseProvider/index.js +7 -2
  42. package/lib-module/Button/ButtonBase.js +7 -3
  43. package/lib-module/Carousel/Carousel.js +85 -70
  44. package/lib-module/Carousel/CarouselContext.js +11 -4
  45. package/lib-module/Carousel/CarouselItem/CarouselItem.js +25 -10
  46. package/lib-module/Carousel/CarouselStepTracker/CarouselStepTracker.js +42 -0
  47. package/lib-module/Carousel/CarouselStepTracker/index.js +2 -0
  48. package/lib-module/Carousel/dictionary.js +16 -0
  49. package/lib-module/Checkbox/Checkbox.js +8 -4
  50. package/lib-module/Checkbox/CheckboxGroup.js +1 -1
  51. package/lib-module/Feedback/Feedback.js +19 -11
  52. package/lib-module/Icon/IconText.js +5 -0
  53. package/lib-module/InputLabel/InputLabel.js +12 -6
  54. package/lib-module/InputSupports/InputSupports.js +10 -3
  55. package/lib-module/InputSupports/useInputSupports.js +3 -2
  56. package/lib-module/Link/LinkBase.js +8 -4
  57. package/lib-module/List/ListItem.js +8 -4
  58. package/lib-module/Modal/Modal.js +3 -0
  59. package/lib-module/Notification/Notification.js +8 -3
  60. package/lib-module/Pagination/Pagination.js +8 -4
  61. package/lib-module/RadioCard/RadioCard.js +7 -2
  62. package/lib-module/Select/Select.js +8 -4
  63. package/lib-module/Skeleton/Skeleton.js +1 -0
  64. package/lib-module/StepTracker/Step.js +9 -5
  65. package/lib-module/StepTracker/StepTracker.js +17 -14
  66. package/lib-module/Tabs/TabsItem.js +5 -1
  67. package/lib-module/TextInput/TextInput.js +3 -1
  68. package/lib-module/TextInput/TextInputBase.js +8 -4
  69. package/lib-module/ThemeProvider/ThemeProvider.js +20 -3
  70. package/lib-module/ThemeProvider/utils/styles.js +8 -1
  71. package/lib-module/ThemeProvider/utils/theme-tokens.js +1 -1
  72. package/lib-module/Typography/Typography.js +7 -3
  73. package/lib-module/index.js +1 -0
  74. package/lib-module/utils/index.js +1 -0
  75. package/lib-module/utils/props/clickProps.js +2 -2
  76. package/lib-module/utils/props/handlerProps.js +78 -31
  77. package/lib-module/utils/useScrollBlocking.js +58 -0
  78. package/lib-module/utils/useScrollBlocking.native.js +2 -0
  79. package/package.json +3 -3
  80. package/src/BaseProvider/index.jsx +6 -3
  81. package/src/Button/ButtonBase.jsx +8 -3
  82. package/src/Carousel/Carousel.jsx +106 -74
  83. package/src/Carousel/CarouselContext.jsx +15 -4
  84. package/src/Carousel/CarouselItem/CarouselItem.jsx +26 -8
  85. package/src/Carousel/CarouselStepTracker/CarouselStepTracker.jsx +36 -0
  86. package/src/Carousel/CarouselStepTracker/index.js +3 -0
  87. package/src/Carousel/dictionary.js +16 -0
  88. package/src/Checkbox/Checkbox.jsx +14 -11
  89. package/src/Checkbox/CheckboxGroup.jsx +1 -1
  90. package/src/Feedback/Feedback.jsx +14 -7
  91. package/src/Icon/IconText.jsx +2 -0
  92. package/src/InputLabel/InputLabel.jsx +13 -12
  93. package/src/InputSupports/InputSupports.jsx +18 -3
  94. package/src/InputSupports/useInputSupports.js +2 -2
  95. package/src/Link/LinkBase.jsx +10 -4
  96. package/src/List/ListItem.jsx +9 -4
  97. package/src/Modal/Modal.jsx +3 -1
  98. package/src/Notification/Notification.jsx +5 -3
  99. package/src/Pagination/Pagination.jsx +6 -4
  100. package/src/RadioCard/RadioCard.jsx +3 -2
  101. package/src/Select/Select.jsx +12 -3
  102. package/src/Skeleton/Skeleton.jsx +1 -0
  103. package/src/StepTracker/Step.jsx +12 -4
  104. package/src/StepTracker/StepTracker.jsx +20 -13
  105. package/src/Tabs/TabsItem.jsx +3 -2
  106. package/src/TextInput/TextInput.jsx +1 -1
  107. package/src/TextInput/TextInputBase.jsx +11 -3
  108. package/src/ThemeProvider/ThemeProvider.jsx +16 -3
  109. package/src/ThemeProvider/utils/styles.js +9 -1
  110. package/src/ThemeProvider/utils/theme-tokens.js +1 -1
  111. package/src/Typography/Typography.jsx +11 -12
  112. package/src/index.js +1 -0
  113. package/src/utils/index.js +1 -0
  114. package/src/utils/props/clickProps.js +2 -2
  115. package/src/utils/props/handlerProps.js +64 -16
  116. package/src/utils/useScrollBlocking.js +57 -0
  117. package/src/utils/useScrollBlocking.native.js +2 -0
@@ -17,11 +17,11 @@ var _StyleSheet = _interopRequireDefault(require("react-native-web/dist/cjs/expo
17
17
 
18
18
  var _Platform = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Platform"));
19
19
 
20
- var _utils = require("../ThemeProvider/utils");
20
+ var _ThemeProvider = require("../ThemeProvider");
21
21
 
22
22
  var _propTypes2 = _interopRequireDefault(require("./propTypes"));
23
23
 
24
- var _utils2 = require("../utils");
24
+ var _utils = require("../utils");
25
25
 
26
26
  var _jsxRuntime = require("react/jsx-runtime");
27
27
 
@@ -31,7 +31,7 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
31
31
 
32
32
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
33
33
 
34
- const [selectProps, selectedSystemPropTypes] = (0, _utils2.selectSystemProps)([_utils2.a11yProps, _utils2.focusHandlerProps, _utils2.linkProps, _utils2.viewProps]);
34
+ const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.focusHandlerProps, _utils.linkProps, _utils.viewProps]);
35
35
 
36
36
  const getOuterBorderOffset = _ref => {
37
37
  let {
@@ -55,7 +55,7 @@ const selectOuterContainerStyles = _ref2 => {
55
55
  alignSelf,
56
56
  backgroundColor: outerBackgroundColor,
57
57
  opacity,
58
- ...(0, _utils.applyOuterBorder)({
58
+ ...(0, _ThemeProvider.applyOuterBorder)({
59
59
  outerBorderGap,
60
60
  outerBorderWidth,
61
61
  outerBorderColor,
@@ -137,7 +137,7 @@ const selectInnerContainerStyles = _ref4 => {
137
137
  paddingBottom: offsetBorder(paddingBottom),
138
138
  backgroundColor,
139
139
  minWidth,
140
- ...(0, _utils.applyShadowToken)(shadow)
140
+ ...(0, _ThemeProvider.applyShadowToken)(shadow)
141
141
  };
142
142
  };
143
143
 
@@ -154,7 +154,7 @@ const selectBorderStyles = _ref5 => {
154
154
  };
155
155
  };
156
156
 
157
- const selectTextStyles = _ref6 => {
157
+ const selectTextStyles = (_ref6, themeOptions) => {
158
158
  let {
159
159
  fontSize,
160
160
  color,
@@ -163,12 +163,13 @@ const selectTextStyles = _ref6 => {
163
163
  fontWeight,
164
164
  textAlign
165
165
  } = _ref6;
166
- return (0, _utils.applyTextStyles)({
166
+ return (0, _ThemeProvider.applyTextStyles)({
167
167
  fontSize,
168
168
  color,
169
169
  lineHeight,
170
170
  fontName,
171
171
  fontWeight,
172
+ themeOptions,
172
173
  textAlign
173
174
  });
174
175
  };
@@ -183,7 +184,7 @@ const selectWebOnlyStyles = (inactive, themeTokens, _ref7) => {
183
184
  maxWidth: "calc(100% + ".concat(getOuterBorderOffset(themeTokens) * 2, "px)"),
184
185
  outline: 'none',
185
186
  // removes the default browser :focus outline
186
- ...(0, _utils2.getCursorStyle)(inactive, accessibilityRole)
187
+ ...(0, _utils.getCursorStyle)(inactive, accessibilityRole)
187
188
  },
188
189
  default: {}
189
190
  });
@@ -206,14 +207,14 @@ const ButtonBase = /*#__PURE__*/(0, _react.forwardRef)((_ref8, ref) => {
206
207
  const {
207
208
  onPress,
208
209
  ...rest
209
- } = _utils2.clickProps.toPressProps(rawRest);
210
+ } = _utils.clickProps.toPressProps(rawRest);
210
211
 
211
212
  const extraButtonState = {
212
213
  inactive,
213
214
  selected
214
215
  };
215
216
 
216
- const resolveButtonTokens = pressableState => (0, _utils2.resolvePressableTokens)(tokens, pressableState, extraButtonState);
217
+ const resolveButtonTokens = pressableState => (0, _utils.resolvePressableTokens)(tokens, pressableState, extraButtonState);
217
218
 
218
219
  const systemProps = selectProps(rest);
219
220
 
@@ -222,10 +223,13 @@ const ButtonBase = /*#__PURE__*/(0, _react.forwardRef)((_ref8, ref) => {
222
223
  return [staticStyles.row, selectWebOnlyStyles(inactive, themeTokens, systemProps), selectOuterContainerStyles(themeTokens), selectOuterWidthStyles(themeTokens)];
223
224
  };
224
225
 
226
+ const {
227
+ themeOptions
228
+ } = (0, _ThemeProvider.useTheme)();
225
229
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Pressable.default, {
226
230
  ref: ref,
227
231
  href: href,
228
- onPress: _utils2.linkProps.handleHref({
232
+ onPress: _utils.linkProps.handleHref({
229
233
  href,
230
234
  onPress
231
235
  }),
@@ -237,7 +241,7 @@ const ButtonBase = /*#__PURE__*/(0, _react.forwardRef)((_ref8, ref) => {
237
241
  const themeTokens = resolveButtonTokens(pressableState);
238
242
  const containerStyles = selectInnerContainerStyles(themeTokens);
239
243
  const borderStyles = selectBorderStyles(themeTokens);
240
- const textStyles = [selectTextStyles(themeTokens), staticStyles.text]; // If the container has a width set, fill it instead of sizing from content.
244
+ const textStyles = [selectTextStyles(themeTokens, themeOptions), staticStyles.text]; // If the container has a width set, fill it instead of sizing from content.
241
245
  // If in future we support text alignments other than center, add here.
242
246
 
243
247
  const stretchStyles = themeTokens.width ? staticStyles.stretch : staticStyles.align;
@@ -251,7 +255,7 @@ const ButtonBase = /*#__PURE__*/(0, _react.forwardRef)((_ref8, ref) => {
251
255
  transition: 'background-color 200ms, border-color 200ms'
252
256
  }
253
257
  })],
254
- children: (0, _utils2.wrapStringsInText)(typeof children === 'function' ? children({ ...(0, _utils2.resolvePressableState)(pressableState, extraButtonState),
258
+ children: (0, _utils.wrapStringsInText)(typeof children === 'function' ? children({ ...(0, _utils.resolvePressableState)(pressableState, extraButtonState),
255
259
  textStyles
256
260
  }) : children, {
257
261
  style: textStyles
@@ -295,6 +299,6 @@ const staticStyles = _StyleSheet.default.create({
295
299
  }
296
300
  });
297
301
 
298
- var _default = (0, _utils2.withLinkRouter)(ButtonBase);
302
+ var _default = (0, _utils.withLinkRouter)(ButtonBase);
299
303
 
300
304
  exports.default = _default;
@@ -31,11 +31,11 @@ var _CarouselContext = require("./CarouselContext");
31
31
 
32
32
  var _CarouselItem = _interopRequireDefault(require("./CarouselItem"));
33
33
 
34
- var _StepTracker = _interopRequireDefault(require("../StepTracker"));
34
+ var _IconButton = _interopRequireDefault(require("../IconButton"));
35
35
 
36
- var _StackView = _interopRequireDefault(require("../StackView"));
36
+ var _CarouselStepTracker = _interopRequireDefault(require("./CarouselStepTracker/CarouselStepTracker"));
37
37
 
38
- var _IconButton = _interopRequireDefault(require("../IconButton"));
38
+ var _dictionary = _interopRequireDefault(require("./dictionary"));
39
39
 
40
40
  var _jsxRuntime = require("react/jsx-runtime");
41
41
 
@@ -52,19 +52,6 @@ const staticStyles = _StyleSheet.default.create({
52
52
  }
53
53
  });
54
54
 
55
- const staticTokens = {
56
- stackView: {
57
- justifyContent: 'center'
58
- },
59
- stepTracker: {
60
- showStepLabel: false,
61
- showStepTrackerLabel: true,
62
- knobCompletedBackgroundColor: 'none',
63
- connectorCompletedColor: 'none',
64
- connectorColor: 'none'
65
- }
66
- };
67
-
68
55
  const selectContainerStyles = width => ({
69
56
  backgroundColor: 'transparent',
70
57
  overflow: 'hidden',
@@ -103,14 +90,6 @@ const selectPreviousNextNavigationButtonStyles = (previousNextNavigationButtonWi
103
90
  return styles;
104
91
  };
105
92
 
106
- const defaultPanelNavigationDictionary = {
107
- en: {
108
- stepTrackerLabel: 'Showing %{stepNumber} of %{stepCount}'
109
- },
110
- fr: {
111
- stepTrackerLabel: 'Étape %{stepNumber} sur %{stepCount}: %{stepLabel}'
112
- }
113
- };
114
93
  const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
115
94
  /**
116
95
  * Carousel is a general-purpose content slider that can be used to render content in terms of slides.
@@ -172,6 +151,7 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
172
151
  tokens,
173
152
  variant,
174
153
  children,
154
+ itemLabel = 'item',
175
155
  previousNextNavigationPosition = 'inside',
176
156
  previousNextIconSize = 'default',
177
157
  minDistanceToCapture = 5,
@@ -180,26 +160,44 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
180
160
  onAnimationEnd,
181
161
  onIndexChanged,
182
162
  springConfig = undefined,
183
- onRenderPanelNavigation,
184
- panelNavigationTextDictionary = defaultPanelNavigationDictionary,
163
+ panelNavigation = /*#__PURE__*/(0, _jsxRuntime.jsx)(_CarouselStepTracker.default, {}),
164
+ tag = 'ul',
185
165
  accessibilityRole = 'adjustable',
186
166
  accessibilityLabel = 'carousel',
167
+ copy,
187
168
  ...rest
188
169
  } = _ref;
189
170
  const viewport = (0, _ViewportProvider.useViewport)();
171
+ const themeTokens = (0, _ThemeProvider.useThemeTokens)('Carousel', tokens, variant, {
172
+ viewport
173
+ });
190
174
  const {
191
175
  previousIcon,
192
176
  nextIcon,
193
177
  showPreviousNextNavigation,
194
178
  showPanelNavigation,
195
- spaceBetweenSlideAndPreviousNextNavigation,
196
- spaceBetweenSlideAndPanelNavigation
197
- } = (0, _ThemeProvider.useThemeTokens)('Carousel', tokens, variant, {
198
- viewport
199
- });
179
+ spaceBetweenSlideAndPreviousNextNavigation
180
+ } = themeTokens;
200
181
 
201
182
  const [activeIndex, setActiveIndex] = _react.default.useState(0);
202
183
 
184
+ const [isAnimating, setIsAnimating] = _react.default.useState(false);
185
+
186
+ const handleAnimationStart = _react.default.useCallback(function () {
187
+ if (typeof onAnimationStart === 'function') onAnimationStart(...arguments);
188
+ setIsAnimating(true);
189
+ }, [onAnimationStart]);
190
+
191
+ const handleAnimationEnd = _react.default.useCallback(function () {
192
+ if (typeof onAnimationEnd === 'function') onAnimationEnd(...arguments);
193
+ setIsAnimating(false);
194
+ }, [onAnimationEnd]);
195
+
196
+ const getCopy = (0, _utils.useCopy)({
197
+ dictionary: _dictionary.default,
198
+ copy
199
+ });
200
+
203
201
  const childrenArray = _react.default.Children.toArray(children);
204
202
 
205
203
  const systemProps = selectProps({ ...rest,
@@ -231,9 +229,6 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
231
229
 
232
230
  const isFirstSlide = !activeIndex;
233
231
  const isLastSlide = activeIndex + 1 >= children.length;
234
- const panelNavigationTokens = { ...staticTokens.stepTracker,
235
- containerPaddingTop: spaceBetweenSlideAndPanelNavigation
236
- };
237
232
 
238
233
  const onContainerLayout = _ref2 => {
239
234
  let {
@@ -276,20 +271,28 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
276
271
  });
277
272
  }, [activeIndex, containerLayout.width, pan, animatedX]);
278
273
 
279
- const animate = _react.default.useCallback(toValue => {
274
+ const animate = _react.default.useCallback((toValue, toIndex) => {
275
+ const handleAnimationEndToIndex = function () {
276
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
277
+ args[_key] = arguments[_key];
278
+ }
279
+
280
+ return handleAnimationEnd(toIndex, ...args);
281
+ };
282
+
280
283
  if (reduceMotionEnabled) {
281
284
  _Animated.default.timing(pan, {
282
285
  toValue,
283
286
  duration: 1,
284
287
  useNativeDriver: false
285
- }).start();
288
+ }).start(handleAnimationEndToIndex);
286
289
  } else {
287
290
  _Animated.default.spring(pan, { ...springConfig,
288
291
  toValue,
289
292
  useNativeDriver: false
290
- }).start();
293
+ }).start(handleAnimationEndToIndex);
291
294
  }
292
- }, [pan, springConfig, reduceMotionEnabled]);
295
+ }, [pan, springConfig, reduceMotionEnabled, handleAnimationEnd]);
293
296
 
294
297
  const updateIndex = _react.default.useCallback(function () {
295
298
  let delta = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
@@ -308,25 +311,25 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
308
311
  calcDelta = -1 * activeIndex + delta - 1;
309
312
  }
310
313
 
314
+ const index = activeIndex + calcDelta;
315
+
311
316
  if (skipChanges) {
312
- animate(toValue);
317
+ animate(toValue, index);
313
318
  return calcDelta;
314
319
  }
315
320
 
316
- const index = activeIndex + calcDelta;
317
321
  setActiveIndex(index);
318
322
  toValue.x = containerLayout.width * -1 * calcDelta;
319
- animate(toValue);
323
+ animate(toValue, index);
320
324
  if (onIndexChanged) onIndexChanged(calcDelta);
321
- if (onAnimationEnd) onAnimationEnd(index);
322
325
  return calcDelta;
323
- }, [containerLayout.width, activeIndex, animate, children.length, onIndexChanged, onAnimationEnd]);
326
+ }, [containerLayout.width, activeIndex, animate, children.length, onIndexChanged]);
324
327
 
325
328
  const fixOffsetAndGo = _react.default.useCallback(delta => {
326
329
  updateOffset();
327
- if (onAnimationStart) onAnimationStart(activeIndex);
330
+ handleAnimationStart(activeIndex);
328
331
  updateIndex(delta);
329
- }, [updateIndex, updateOffset, activeIndex, onAnimationStart]);
332
+ }, [updateIndex, updateOffset, activeIndex, handleAnimationStart]);
330
333
 
331
334
  const goToNeighboring = _react.default.useCallback(function () {
332
335
  let toPrev = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
@@ -349,7 +352,7 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
349
352
  return false;
350
353
  }
351
354
 
352
- if (onAnimationStart) onAnimationStart(activeIndex);
355
+ handleAnimationStart(activeIndex);
353
356
  return Math.abs(gestureState.dx) > minDistanceToCapture;
354
357
  },
355
358
  onPanResponderGrant: () => updateOffset(),
@@ -365,13 +368,13 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
365
368
  animate({
366
369
  x: 0,
367
370
  y: 0
368
- });
371
+ }, 0);
369
372
  } else {
370
373
  const delta = correction > 0 ? -1 : 1;
371
374
  updateIndex(delta);
372
375
  }
373
376
  }
374
- }), [containerLayout.width, updateIndex, updateOffset, animate, isSwipeAllowed, activeIndex, minDistanceForAction, onAnimationStart, minDistanceToCapture, pan.x]);
377
+ }), [containerLayout.width, updateIndex, updateOffset, animate, isSwipeAllowed, activeIndex, minDistanceForAction, handleAnimationStart, minDistanceToCapture, pan.x]);
375
378
 
376
379
  _react.default.useEffect(() => {
377
380
  pan.x.addListener(_ref4 => {
@@ -416,11 +419,20 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
416
419
  size: previousNextIconSize,
417
420
  raised: true
418
421
  };
422
+
423
+ const getCopyWithPlaceholders = _react.default.useCallback(copyKey => {
424
+ const copyText = getCopy(copyKey).replace(/%\{itemLabel\}/g, itemLabel).replace(/%\{stepNumber\}/g, activeIndex + 1).replace(/%\{stepCount\}/g, childrenArray.length); // First word might be a lowercase placeholder: capitalize the first letter
425
+
426
+ return "".concat(copyText[0].toUpperCase()).concat(copyText.slice(1));
427
+ }, [activeIndex, childrenArray.length, itemLabel, getCopy]);
428
+
419
429
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_CarouselContext.CarouselProvider, {
420
430
  activeIndex: activeIndex,
421
431
  totalItems: childrenArray.length,
422
432
  width: containerLayout.width,
423
433
  goTo: goTo,
434
+ getCopyWithPlaceholders: getCopyWithPlaceholders,
435
+ themeTokens: themeTokens,
424
436
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
425
437
  style: staticStyles.root,
426
438
  onLayout: onContainerLayout,
@@ -434,7 +446,7 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
434
446
  icon: previousIcon,
435
447
  onPress: goToPrev,
436
448
  variant: previousNextIconButtonVariants,
437
- accessibilityLabel: "previous-button"
449
+ accessibilityLabel: getCopyWithPlaceholders('iconButtonLabel').replace('%{targetStep}', activeIndex)
438
450
  })
439
451
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
440
452
  style: selectContainerStyles(containerLayout.width),
@@ -447,9 +459,13 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
447
459
  }]
448
460
  }]),
449
461
  ...panResponder.panHandlers,
462
+ ...(0, _utils.getA11yPropsFromHtmlTag)(tag),
450
463
  children: childrenArray.map((element, index) => {
464
+ const hidden = !isAnimating && index !== activeIndex;
465
+
451
466
  const clonedElement = /*#__PURE__*/_react.default.cloneElement(element, {
452
- elementIndex: index
467
+ elementIndex: index,
468
+ hidden
453
469
  });
454
470
 
455
471
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_react.default.Fragment, {
@@ -465,22 +481,10 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
465
481
  icon: nextIcon,
466
482
  onPress: goToNext,
467
483
  variant: previousNextIconButtonVariants,
468
- accessibilityLabel: "next-button"
484
+ accessibilityLabel: getCopyWithPlaceholders('iconButtonLabel').replace('%{targetStep}', activeIndex + 2)
469
485
  })
470
486
  })]
471
- }), showPanelNavigation ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_StackView.default, {
472
- direction: "row",
473
- tokens: staticTokens.stackView,
474
- children: onRenderPanelNavigation ? onRenderPanelNavigation({
475
- activeIndex,
476
- totalItems: childrenArray.length
477
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_StepTracker.default, {
478
- current: activeIndex,
479
- steps: childrenArray.map((_, index) => String(index)),
480
- dictionary: panelNavigationTextDictionary,
481
- tokens: panelNavigationTokens
482
- })
483
- }) : null]
487
+ }), showPanelNavigation ? panelNavigation : null]
484
488
  });
485
489
  });
486
490
 
@@ -493,6 +497,14 @@ Carousel.propTypes = { ...selectedSystemPropTypes,
493
497
  */
494
498
  children: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.node), _propTypes.default.node]).isRequired,
495
499
 
500
+ /**
501
+ * Lowercase language-appropriate user-facing description of what each Carousel slide represents.
502
+ * This is used when generating item labels. For example, if a carousel contains offers,
503
+ * pass itemLabel="summer offer" (or copy="fr" and an appropriate French translation) to genereate
504
+ * accessible labels such as "Summer offer 1 of 3" and "Show summer offer 2 of 3".
505
+ */
506
+ itemLabel: _propTypes.default.string,
507
+
496
508
  /**
497
509
  * `inside` renders the previous and next buttons inside the slide
498
510
  * `outside` renders the previous and next buttons outside the slide
@@ -540,20 +552,20 @@ Carousel.propTypes = { ...selectedSystemPropTypes,
540
552
  onIndexChanged: _propTypes.default.func,
541
553
 
542
554
  /**
543
- * Use this to render a custom panel navigation element instead of dots navigation
544
- * This function is also provided with an object with the following properties
545
- * activeIndex: index of current slide
546
- * totalItems: total number of slides
555
+ * Use this to render a custom panel navigation element instead of the default StepTracker's based navigation
556
+ * You can make use of `useCarousel` within your custom panel navigation component to hook into various Carousel states such as:
557
+ * - activeIndex: index of current slide
558
+ * - totalItems: total number of slides
547
559
  * Use it as follows:
548
560
  * ```js
549
561
  * <Carousel
550
- * onRenderPanelNavigation={({ totalItems, activeIndex }) => <Text>Showing {activeIndex + 1}</Text>}
562
+ * panelNavigation={<CustomPanelNavigation />}
551
563
  * >
552
564
  * <Carousel.Item>First Slide</Carousel.Item>
553
565
  * </Carousel>
554
566
  * ```
555
567
  */
556
- onRenderPanelNavigation: _propTypes.default.func,
568
+ panelNavigation: _propTypes.default.element,
557
569
 
558
570
  /**
559
571
  * When slide animation start
@@ -611,7 +623,16 @@ Carousel.propTypes = { ...selectedSystemPropTypes,
611
623
  /**
612
624
  * Provide custom accessibilityLabel for Carousel container
613
625
  */
614
- accessibilityLabel: _propTypes.default.string
626
+ accessibilityLabel: _propTypes.default.string,
627
+
628
+ /**
629
+ * HTML tag to use for the Carousel item's immediate parent. Defaults to `'ul'` so that
630
+ * assistive technology tools know to intepret the carousel as a list.
631
+ *
632
+ * Note that if the immediate Carousel children do not all render as `'li'` elements,
633
+ * this should be changed (e.g. pass tag="div") because only 'li' is a valid child of 'ul'.
634
+ */
635
+ tag: _propTypes.default.oneOf(_utils.layoutTags)
615
636
  };
616
637
  Carousel.Item = _CarouselItem.default;
617
638
  Carousel.displayName = 'Carousel';
@@ -10,6 +10,8 @@ var _react = _interopRequireDefault(require("react"));
10
10
 
11
11
  var _propTypes = _interopRequireDefault(require("prop-types"));
12
12
 
13
+ var _utils = require("../utils");
14
+
13
15
  var _jsxRuntime = require("react/jsx-runtime");
14
16
 
15
17
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -22,15 +24,19 @@ const CarouselProvider = _ref => {
22
24
  activeIndex,
23
25
  totalItems,
24
26
  width,
25
- goTo
27
+ goTo,
28
+ getCopyWithPlaceholders,
29
+ themeTokens
26
30
  } = _ref;
27
31
 
28
32
  const value = _react.default.useMemo(() => ({
29
33
  activeIndex,
30
34
  totalItems,
31
35
  width,
32
- goTo
33
- }), [activeIndex, totalItems, width, goTo]);
36
+ goTo,
37
+ getCopyWithPlaceholders,
38
+ themeTokens
39
+ }), [activeIndex, totalItems, width, goTo, getCopyWithPlaceholders, themeTokens]);
34
40
 
35
41
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(CarouselContext.Provider, {
36
42
  value: value,
@@ -55,5 +61,7 @@ CarouselProvider.propTypes = {
55
61
  activeIndex: _propTypes.default.number.isRequired,
56
62
  totalItems: _propTypes.default.number.isRequired,
57
63
  width: _propTypes.default.number.isRequired,
58
- goTo: _propTypes.default.func.isRequired
64
+ goTo: _propTypes.default.func.isRequired,
65
+ getCopyWithPlaceholders: _propTypes.default.func.isRequired,
66
+ themeTokens: (0, _utils.getTokensPropType)('Carousel')
59
67
  };
@@ -31,23 +31,29 @@ const CarouselItem = _ref => {
31
31
  let {
32
32
  children,
33
33
  elementIndex,
34
+ tag = 'li',
35
+ hidden,
34
36
  ...rest
35
37
  } = _ref;
36
38
  const {
37
39
  width,
38
- activeIndex,
39
- totalItems
40
+ activeIndex
40
41
  } = (0, _CarouselContext.useCarousel)();
41
42
  const selectedProps = selectProps({ ...rest,
42
- // `group` role crashes the app on Android so setting it to `none` for Android
43
- accessibilityRole: _Platform.default.OS === 'android' ? 'none' : 'group',
44
- accessibilityLabel: "Showing ".concat(elementIndex + 1, " of ").concat(totalItems)
43
+ ...(0, _utils.getA11yPropsFromHtmlTag)(tag, rest.accessibilityRole)
45
44
  });
46
45
  const focusabilityProps = activeIndex === elementIndex ? {} : _utils.a11yProps.nonFocusableProps;
46
+ const style = {
47
+ width
48
+ };
49
+
50
+ if (hidden && _Platform.default.OS === 'web') {
51
+ // On web, visibility: hidden makes all children non-focusable. It doesn't exist on native.
52
+ style.visibility = 'hidden';
53
+ }
54
+
47
55
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
48
- style: {
49
- width
50
- },
56
+ style: style,
51
57
  ...selectedProps,
52
58
  ...focusabilityProps,
53
59
  children: children
@@ -70,7 +76,16 @@ CarouselItem.propTypes = { ...selectedSystemPropTypes,
70
76
  /**
71
77
  * Content of the slide
72
78
  */
73
- children: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.node), _propTypes.default.node]).isRequired
79
+ children: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.node), _propTypes.default.node]).isRequired,
80
+
81
+ /**
82
+ * Sets the HTML tag of the outer container. By default `'li'` so that assistive technology sees
83
+ * the Carousel as a list of items.
84
+ *
85
+ * Carousel's innermost container defaults to `'ul'` which can be overridden. If the tag of either
86
+ * `Carousel` or `Carousel.Item` is overriden, the other should be too, to avoid producing invalid HTML.
87
+ */
88
+ tag: _propTypes.default.oneOf(_utils.layoutTags)
74
89
  };
75
90
  CarouselItem.displayName = 'Carousel.Item';
76
91
  var _default = CarouselItem;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _react = _interopRequireDefault(require("react"));
9
+
10
+ var _CarouselContext = require("../CarouselContext");
11
+
12
+ var _StepTracker = _interopRequireDefault(require("../../StepTracker"));
13
+
14
+ var _StackView = _interopRequireDefault(require("../../StackView"));
15
+
16
+ var _jsxRuntime = require("react/jsx-runtime");
17
+
18
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
+
20
+ const CarouselStepTracker = () => {
21
+ const {
22
+ activeIndex,
23
+ totalItems,
24
+ getCopyWithPlaceholders,
25
+ themeTokens
26
+ } = (0, _CarouselContext.useCarousel)();
27
+ const stackViewTokens = {
28
+ justifyContent: 'center'
29
+ };
30
+ const stepTrackerTokens = {
31
+ showStepLabel: false,
32
+ showStepTrackerLabel: true,
33
+ knobCompletedBackgroundColor: 'none',
34
+ connectorCompletedColor: 'none',
35
+ connectorColor: 'none',
36
+ containerPaddingTop: themeTokens.spaceBetweenSlideAndPanelNavigation
37
+ };
38
+ const steps = Array.from(Array(totalItems)).map((_, index) => String(index));
39
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_StackView.default, {
40
+ direction: "row",
41
+ tokens: stackViewTokens,
42
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_StepTracker.default, {
43
+ current: activeIndex,
44
+ steps: steps,
45
+ copy: {
46
+ // Give StepTracker copy from Carousel's language and dictionary
47
+ stepLabel: getCopyWithPlaceholders('stepLabel'),
48
+ stepTrackerLabel: getCopyWithPlaceholders('stepTrackerLabel')
49
+ },
50
+ tokens: stepTrackerTokens
51
+ })
52
+ });
53
+ };
54
+
55
+ var _default = CarouselStepTracker;
56
+ exports.default = _default;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _CarouselStepTracker = _interopRequireDefault(require("./CarouselStepTracker"));
9
+
10
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
+
12
+ var _default = _CarouselStepTracker.default;
13
+ exports.default = _default;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ // 'stepLabel' and 'stepTrackerLabel' are passed down to StepTracker
8
+ var _default = {
9
+ en: {
10
+ carouselLabel: '%{stepCount} items',
11
+ iconButtonLabel: 'Show %{itemLabel} %{targetStep} of %{stepCount}',
12
+ stepLabel: '%{itemLabel} %{stepNumber}',
13
+ stepTrackerLabel: '%{itemLabel} %{stepNumber} of %{stepCount}'
14
+ },
15
+ fr: {
16
+ // TODO: French translations here
17
+ carouselLabel: '(fr) %{stepCount} items',
18
+ iconButtonLabel: '(fr) Show %{itemLabel} %{targetStep} of %{stepCount}',
19
+ stepLabel: '(fr) %{itemLabel} %{stepNumber}',
20
+ stepTrackerLabel: '(fr) %{itemLabel} %{stepNumber} of %{stepCount}'
21
+ }
22
+ };
23
+ exports.default = _default;