@telus-uds/components-base 1.10.0 → 1.11.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +21 -3
  2. package/component-docs.json +346 -51
  3. package/lib/Carousel/Carousel.js +81 -28
  4. package/lib/Carousel/CarouselItem/CarouselItem.js +24 -9
  5. package/lib/Carousel/dictionary.js +23 -0
  6. package/lib/InputSupports/InputSupports.js +10 -3
  7. package/lib/InputSupports/useInputSupports.js +3 -2
  8. package/lib/Modal/Modal.js +4 -0
  9. package/lib/Skeleton/Skeleton.js +1 -0
  10. package/lib/StepTracker/StepTracker.js +10 -10
  11. package/lib/TextInput/TextInput.js +3 -1
  12. package/lib/index.js +9 -0
  13. package/lib/utils/props/clickProps.js +2 -2
  14. package/lib/utils/props/handlerProps.js +77 -31
  15. package/lib/utils/useScrollBlocking.js +66 -0
  16. package/lib/utils/useScrollBlocking.native.js +11 -0
  17. package/lib-module/Carousel/Carousel.js +76 -29
  18. package/lib-module/Carousel/CarouselItem/CarouselItem.js +25 -10
  19. package/lib-module/Carousel/dictionary.js +16 -0
  20. package/lib-module/InputSupports/InputSupports.js +10 -3
  21. package/lib-module/InputSupports/useInputSupports.js +3 -2
  22. package/lib-module/Modal/Modal.js +3 -0
  23. package/lib-module/Skeleton/Skeleton.js +1 -0
  24. package/lib-module/StepTracker/StepTracker.js +9 -10
  25. package/lib-module/TextInput/TextInput.js +3 -1
  26. package/lib-module/index.js +1 -0
  27. package/lib-module/utils/props/clickProps.js +2 -2
  28. package/lib-module/utils/props/handlerProps.js +78 -31
  29. package/lib-module/utils/useScrollBlocking.js +58 -0
  30. package/lib-module/utils/useScrollBlocking.native.js +2 -0
  31. package/package.json +3 -3
  32. package/src/Carousel/Carousel.jsx +93 -30
  33. package/src/Carousel/CarouselItem/CarouselItem.jsx +26 -8
  34. package/src/Carousel/dictionary.js +16 -0
  35. package/src/InputSupports/InputSupports.jsx +18 -3
  36. package/src/InputSupports/useInputSupports.js +2 -2
  37. package/src/Modal/Modal.jsx +3 -1
  38. package/src/Skeleton/Skeleton.jsx +1 -0
  39. package/src/StepTracker/StepTracker.jsx +9 -3
  40. package/src/TextInput/TextInput.jsx +1 -1
  41. package/src/index.js +1 -0
  42. package/src/utils/props/clickProps.js +2 -2
  43. package/src/utils/props/handlerProps.js +64 -16
  44. package/src/utils/useScrollBlocking.js +57 -0
  45. package/src/utils/useScrollBlocking.native.js +2 -0
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _react = require("react");
9
+
10
+ const addScrollBlocking = (preventScrolling, stopPropagation, ref) => {
11
+ var _ref$current;
12
+
13
+ document.body.addEventListener('touchmove', preventScrolling, {
14
+ passive: false
15
+ });
16
+ (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.addEventListener('touchmove', stopPropagation);
17
+ document.body.style.overflow = 'hidden';
18
+ };
19
+
20
+ const removeScrollBlocking = (preventScrolling, stopPropagation, ref) => {
21
+ var _ref$current2;
22
+
23
+ document.body.removeEventListener('touchmove', preventScrolling);
24
+ (_ref$current2 = ref.current) === null || _ref$current2 === void 0 ? void 0 : _ref$current2.removeEventListener('touchmove', stopPropagation);
25
+ document.body.style.overflow = 'inherit';
26
+ };
27
+ /**
28
+ * Disables scrolling when passed `true` or an array where all items are `true`.
29
+ *
30
+ * Returns an optional callback ref. Pass this to an element if it or its children
31
+ * should allow touch-based scrolling within that element's bounds.
32
+ *
33
+ * @param {boolean | boolean[]} conditionProps
34
+ * @returns
35
+ */
36
+
37
+
38
+ const useScrollBlocking = conditionProps => {
39
+ // useRef refs are null on first render and don't trigger a re-render when they get their
40
+ // element. Force re-run when ref mounts to ensure the stopPropagation listener is attached.
41
+ const ref = (0, _react.useRef)();
42
+ const [refIsMounted, setRefIsMounted] = (0, _react.useState)(false);
43
+ const callbackRef = (0, _react.useCallback)(element => {
44
+ ref.current = element;
45
+ setRefIsMounted(Boolean(element));
46
+ }, []);
47
+ const conditionsMet = Array.isArray(conditionProps) ? conditionProps.every(condition => condition) : Boolean(conditionProps);
48
+ const preventScrolling = (0, _react.useCallback)(event => event.preventDefault(), []);
49
+ const stopPropagation = (0, _react.useCallback)(event => event.stopPropagation(), []);
50
+ (0, _react.useEffect)(() => {
51
+ const cleanup = () => removeScrollBlocking(preventScrolling, stopPropagation, ref);
52
+
53
+ if (conditionsMet) {
54
+ addScrollBlocking(preventScrolling, stopPropagation, ref);
55
+ } else {
56
+ cleanup();
57
+ }
58
+
59
+ return cleanup; // preventScrolling and stopPropagation are stable callbacks with no deps, so this
60
+ // will re-run when conditionsMet or refIsMounted flip between true and false.
61
+ }, [preventScrolling, conditionsMet, stopPropagation, refIsMounted]);
62
+ return callbackRef;
63
+ };
64
+
65
+ var _default = useScrollBlocking;
66
+ exports.default = _default;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ // This is a no-op to emphasize that the original hook is web-only
9
+ var _default = () => {};
10
+
11
+ exports.default = _default;
@@ -7,13 +7,14 @@ import Platform from "react-native-web/dist/exports/Platform";
7
7
  import PropTypes from 'prop-types';
8
8
  import { useThemeTokens } from '../ThemeProvider';
9
9
  import { useViewport } from '../ViewportProvider';
10
- import { getTokensPropType, variantProp, selectSystemProps, a11yProps, viewProps } from '../utils';
10
+ import { getTokensPropType, getA11yPropsFromHtmlTag, layoutTags, variantProp, selectSystemProps, a11yProps, viewProps, useCopy } from '../utils';
11
11
  import { useA11yInfo } from '../A11yInfoProvider';
12
12
  import { CarouselProvider } from './CarouselContext';
13
13
  import CarouselItem from './CarouselItem';
14
14
  import StepTracker from '../StepTracker';
15
15
  import StackView from '../StackView';
16
16
  import IconButton from '../IconButton';
17
+ import dictionary from './dictionary';
17
18
  import { jsx as _jsx } from "react/jsx-runtime";
18
19
  import { jsxs as _jsxs } from "react/jsx-runtime";
19
20
  const staticStyles = StyleSheet.create({
@@ -77,14 +78,6 @@ const selectPreviousNextNavigationButtonStyles = (previousNextNavigationButtonWi
77
78
  return styles;
78
79
  };
79
80
 
80
- const defaultPanelNavigationDictionary = {
81
- en: {
82
- stepTrackerLabel: 'Showing %{stepNumber} of %{stepCount}'
83
- },
84
- fr: {
85
- stepTrackerLabel: 'Étape %{stepNumber} sur %{stepCount}: %{stepLabel}'
86
- }
87
- };
88
81
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
89
82
  /**
90
83
  * Carousel is a general-purpose content slider that can be used to render content in terms of slides.
@@ -146,6 +139,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
146
139
  tokens,
147
140
  variant,
148
141
  children,
142
+ itemLabel = 'item',
149
143
  previousNextNavigationPosition = 'inside',
150
144
  previousNextIconSize = 'default',
151
145
  minDistanceToCapture = 5,
@@ -155,9 +149,10 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
155
149
  onIndexChanged,
156
150
  springConfig = undefined,
157
151
  onRenderPanelNavigation,
158
- panelNavigationTextDictionary = defaultPanelNavigationDictionary,
152
+ tag = 'ul',
159
153
  accessibilityRole = 'adjustable',
160
154
  accessibilityLabel = 'carousel',
155
+ copy,
161
156
  ...rest
162
157
  } = _ref;
163
158
  const viewport = useViewport();
@@ -172,6 +167,19 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
172
167
  viewport
173
168
  });
174
169
  const [activeIndex, setActiveIndex] = React.useState(0);
170
+ const [isAnimating, setIsAnimating] = React.useState(false);
171
+ const handleAnimationStart = React.useCallback(function () {
172
+ if (typeof onAnimationStart === 'function') onAnimationStart(...arguments);
173
+ setIsAnimating(true);
174
+ }, [onAnimationStart]);
175
+ const handleAnimationEnd = React.useCallback(function () {
176
+ if (typeof onAnimationEnd === 'function') onAnimationEnd(...arguments);
177
+ setIsAnimating(false);
178
+ }, [onAnimationEnd]);
179
+ const getCopy = useCopy({
180
+ dictionary,
181
+ copy
182
+ });
175
183
  const childrenArray = React.Children.toArray(children);
176
184
  const systemProps = selectProps({ ...rest,
177
185
  accessibilityRole,
@@ -240,20 +248,28 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
240
248
  y: 0
241
249
  });
242
250
  }, [activeIndex, containerLayout.width, pan, animatedX]);
243
- const animate = React.useCallback(toValue => {
251
+ const animate = React.useCallback((toValue, toIndex) => {
252
+ const handleAnimationEndToIndex = function () {
253
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
254
+ args[_key] = arguments[_key];
255
+ }
256
+
257
+ return handleAnimationEnd(toIndex, ...args);
258
+ };
259
+
244
260
  if (reduceMotionEnabled) {
245
261
  Animated.timing(pan, {
246
262
  toValue,
247
263
  duration: 1,
248
264
  useNativeDriver: false
249
- }).start();
265
+ }).start(handleAnimationEndToIndex);
250
266
  } else {
251
267
  Animated.spring(pan, { ...springConfig,
252
268
  toValue,
253
269
  useNativeDriver: false
254
- }).start();
270
+ }).start(handleAnimationEndToIndex);
255
271
  }
256
- }, [pan, springConfig, reduceMotionEnabled]);
272
+ }, [pan, springConfig, reduceMotionEnabled, handleAnimationEnd]);
257
273
  const updateIndex = React.useCallback(function () {
258
274
  let delta = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
259
275
  const toValue = {
@@ -271,24 +287,24 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
271
287
  calcDelta = -1 * activeIndex + delta - 1;
272
288
  }
273
289
 
290
+ const index = activeIndex + calcDelta;
291
+
274
292
  if (skipChanges) {
275
- animate(toValue);
293
+ animate(toValue, index);
276
294
  return calcDelta;
277
295
  }
278
296
 
279
- const index = activeIndex + calcDelta;
280
297
  setActiveIndex(index);
281
298
  toValue.x = containerLayout.width * -1 * calcDelta;
282
- animate(toValue);
299
+ animate(toValue, index);
283
300
  if (onIndexChanged) onIndexChanged(calcDelta);
284
- if (onAnimationEnd) onAnimationEnd(index);
285
301
  return calcDelta;
286
- }, [containerLayout.width, activeIndex, animate, children.length, onIndexChanged, onAnimationEnd]);
302
+ }, [containerLayout.width, activeIndex, animate, children.length, onIndexChanged]);
287
303
  const fixOffsetAndGo = React.useCallback(delta => {
288
304
  updateOffset();
289
- if (onAnimationStart) onAnimationStart(activeIndex);
305
+ handleAnimationStart(activeIndex);
290
306
  updateIndex(delta);
291
- }, [updateIndex, updateOffset, activeIndex, onAnimationStart]);
307
+ }, [updateIndex, updateOffset, activeIndex, handleAnimationStart]);
292
308
  const goToNeighboring = React.useCallback(function () {
293
309
  let toPrev = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
294
310
  fixOffsetAndGo(toPrev ? -1 : 1);
@@ -308,7 +324,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
308
324
  return false;
309
325
  }
310
326
 
311
- if (onAnimationStart) onAnimationStart(activeIndex);
327
+ handleAnimationStart(activeIndex);
312
328
  return Math.abs(gestureState.dx) > minDistanceToCapture;
313
329
  },
314
330
  onPanResponderGrant: () => updateOffset(),
@@ -324,13 +340,13 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
324
340
  animate({
325
341
  x: 0,
326
342
  y: 0
327
- });
343
+ }, 0);
328
344
  } else {
329
345
  const delta = correction > 0 ? -1 : 1;
330
346
  updateIndex(delta);
331
347
  }
332
348
  }
333
- }), [containerLayout.width, updateIndex, updateOffset, animate, isSwipeAllowed, activeIndex, minDistanceForAction, onAnimationStart, minDistanceToCapture, pan.x]);
349
+ }), [containerLayout.width, updateIndex, updateOffset, animate, isSwipeAllowed, activeIndex, minDistanceForAction, handleAnimationStart, minDistanceToCapture, pan.x]);
334
350
  React.useEffect(() => {
335
351
  pan.x.addListener(_ref4 => {
336
352
  let {
@@ -370,6 +386,13 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
370
386
  size: previousNextIconSize,
371
387
  raised: true
372
388
  };
389
+
390
+ const getCopyWithPlaceholders = copyKey => {
391
+ 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
392
+
393
+ return "".concat(copyText[0].toUpperCase()).concat(copyText.slice(1));
394
+ };
395
+
373
396
  return /*#__PURE__*/_jsxs(CarouselProvider, {
374
397
  activeIndex: activeIndex,
375
398
  totalItems: childrenArray.length,
@@ -388,7 +411,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
388
411
  icon: previousIcon,
389
412
  onPress: goToPrev,
390
413
  variant: previousNextIconButtonVariants,
391
- accessibilityLabel: "previous-button"
414
+ accessibilityLabel: getCopyWithPlaceholders('iconButtonLabel').replace('%{targetStep}', activeIndex)
392
415
  })
393
416
  }), /*#__PURE__*/_jsx(View, {
394
417
  style: selectContainerStyles(containerLayout.width),
@@ -401,9 +424,12 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
401
424
  }]
402
425
  }]),
403
426
  ...panResponder.panHandlers,
427
+ ...getA11yPropsFromHtmlTag(tag),
404
428
  children: childrenArray.map((element, index) => {
429
+ const hidden = !isAnimating && index !== activeIndex;
405
430
  const clonedElement = /*#__PURE__*/React.cloneElement(element, {
406
- elementIndex: index
431
+ elementIndex: index,
432
+ hidden
407
433
  });
408
434
  return /*#__PURE__*/_jsx(React.Fragment, {
409
435
  children: clonedElement
@@ -418,7 +444,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
418
444
  icon: nextIcon,
419
445
  onPress: goToNext,
420
446
  variant: previousNextIconButtonVariants,
421
- accessibilityLabel: "next-button"
447
+ accessibilityLabel: getCopyWithPlaceholders('iconButtonLabel').replace('%{targetStep}', activeIndex + 2)
422
448
  })
423
449
  })]
424
450
  }), showPanelNavigation ? /*#__PURE__*/_jsx(StackView, {
@@ -430,7 +456,11 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
430
456
  }) : /*#__PURE__*/_jsx(StepTracker, {
431
457
  current: activeIndex,
432
458
  steps: childrenArray.map((_, index) => String(index)),
433
- dictionary: panelNavigationTextDictionary,
459
+ copy: {
460
+ // Give StepTracker copy from Carousel's language and dictionary
461
+ stepLabel: getCopyWithPlaceholders('stepLabel'),
462
+ stepTrackerLabel: getCopyWithPlaceholders('stepTrackerLabel')
463
+ },
434
464
  tokens: panelNavigationTokens
435
465
  })
436
466
  }) : null]
@@ -445,6 +475,14 @@ Carousel.propTypes = { ...selectedSystemPropTypes,
445
475
  */
446
476
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
447
477
 
478
+ /**
479
+ * Lowercase language-appropriate user-facing description of what each Carousel slide represents.
480
+ * This is used when generating item labels. For example, if a carousel contains offers,
481
+ * pass itemLabel="summer offer" (or copy="fr" and an appropriate French translation) to genereate
482
+ * accessible labels such as "Summer offer 1 of 3" and "Show summer offer 2 of 3".
483
+ */
484
+ itemLabel: PropTypes.string,
485
+
448
486
  /**
449
487
  * `inside` renders the previous and next buttons inside the slide
450
488
  * `outside` renders the previous and next buttons outside the slide
@@ -563,7 +601,16 @@ Carousel.propTypes = { ...selectedSystemPropTypes,
563
601
  /**
564
602
  * Provide custom accessibilityLabel for Carousel container
565
603
  */
566
- accessibilityLabel: PropTypes.string
604
+ accessibilityLabel: PropTypes.string,
605
+
606
+ /**
607
+ * HTML tag to use for the Carousel item's immediate parent. Defaults to `'ul'` so that
608
+ * assistive technology tools know to intepret the carousel as a list.
609
+ *
610
+ * Note that if the immediate Carousel children do not all render as `'li'` elements,
611
+ * this should be changed (e.g. pass tag="div") because only 'li' is a valid child of 'ul'.
612
+ */
613
+ tag: PropTypes.oneOf(layoutTags)
567
614
  };
568
615
  Carousel.Item = CarouselItem;
569
616
  Carousel.displayName = 'Carousel';
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import View from "react-native-web/dist/exports/View";
4
4
  import Platform from "react-native-web/dist/exports/Platform";
5
- import { selectSystemProps, a11yProps, viewProps } from '../../utils';
5
+ import { layoutTags, getA11yPropsFromHtmlTag, selectSystemProps, a11yProps, viewProps } from '../../utils';
6
6
  import { useCarousel } from '../CarouselContext';
7
7
  import { jsx as _jsx } from "react/jsx-runtime";
8
8
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
@@ -15,23 +15,29 @@ const CarouselItem = _ref => {
15
15
  let {
16
16
  children,
17
17
  elementIndex,
18
+ tag = 'li',
19
+ hidden,
18
20
  ...rest
19
21
  } = _ref;
20
22
  const {
21
23
  width,
22
- activeIndex,
23
- totalItems
24
+ activeIndex
24
25
  } = useCarousel();
25
26
  const selectedProps = selectProps({ ...rest,
26
- // `group` role crashes the app on Android so setting it to `none` for Android
27
- accessibilityRole: Platform.OS === 'android' ? 'none' : 'group',
28
- accessibilityLabel: "Showing ".concat(elementIndex + 1, " of ").concat(totalItems)
27
+ ...getA11yPropsFromHtmlTag(tag, rest.accessibilityRole)
29
28
  });
30
29
  const focusabilityProps = activeIndex === elementIndex ? {} : a11yProps.nonFocusableProps;
30
+ const style = {
31
+ width
32
+ };
33
+
34
+ if (hidden && Platform.OS === 'web') {
35
+ // On web, visibility: hidden makes all children non-focusable. It doesn't exist on native.
36
+ style.visibility = 'hidden';
37
+ }
38
+
31
39
  return /*#__PURE__*/_jsx(View, {
32
- style: {
33
- width
34
- },
40
+ style: style,
35
41
  ...selectedProps,
36
42
  ...focusabilityProps,
37
43
  children: children
@@ -54,7 +60,16 @@ CarouselItem.propTypes = { ...selectedSystemPropTypes,
54
60
  /**
55
61
  * Content of the slide
56
62
  */
57
- children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired
63
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
64
+
65
+ /**
66
+ * Sets the HTML tag of the outer container. By default `'li'` so that assistive technology sees
67
+ * the Carousel as a list of items.
68
+ *
69
+ * Carousel's innermost container defaults to `'ul'` which can be overridden. If the tag of either
70
+ * `Carousel` or `Carousel.Item` is overriden, the other should be too, to avoid producing invalid HTML.
71
+ */
72
+ tag: PropTypes.oneOf(layoutTags)
58
73
  };
59
74
  CarouselItem.displayName = 'Carousel.Item';
60
75
  export default CarouselItem;
@@ -0,0 +1,16 @@
1
+ // 'stepLabel' and 'stepTrackerLabel' are passed down to StepTracker
2
+ export default {
3
+ en: {
4
+ carouselLabel: '%{stepCount} items',
5
+ iconButtonLabel: 'Show %{itemLabel} %{targetStep} of %{stepCount}',
6
+ stepLabel: '%{itemLabel} %{stepNumber}',
7
+ stepTrackerLabel: '%{itemLabel} %{stepNumber} of %{stepCount}'
8
+ },
9
+ fr: {
10
+ // TODO: French translations here
11
+ carouselLabel: '(fr) %{stepCount} items',
12
+ iconButtonLabel: '(fr) Show %{itemLabel} %{targetStep} of %{stepCount}',
13
+ stepLabel: '(fr) %{itemLabel} %{stepNumber}',
14
+ stepTrackerLabel: '(fr) %{itemLabel} %{stepNumber} of %{stepCount}'
15
+ }
16
+ };
@@ -16,7 +16,8 @@ const InputSupports = /*#__PURE__*/forwardRef((_ref, ref) => {
16
16
  hintPosition = 'inline',
17
17
  feedback,
18
18
  tooltip,
19
- validation
19
+ validation,
20
+ nativeID
20
21
  } = _ref;
21
22
  const {
22
23
  space
@@ -30,7 +31,8 @@ const InputSupports = /*#__PURE__*/forwardRef((_ref, ref) => {
30
31
  feedback,
31
32
  hint,
32
33
  label,
33
- validation
34
+ validation,
35
+ nativeID
34
36
  });
35
37
  return /*#__PURE__*/_jsxs(StackView, {
36
38
  space: space,
@@ -91,6 +93,11 @@ InputSupports.propTypes = {
91
93
  /**
92
94
  * Use to visually mark an input as valid or invalid.
93
95
  */
94
- validation: PropTypes.oneOf(['error', 'success'])
96
+ validation: PropTypes.oneOf(['error', 'success']),
97
+
98
+ /**
99
+ * ID for DOM element on web
100
+ */
101
+ nativeID: PropTypes.string
95
102
  };
96
103
  export default InputSupports;
@@ -7,7 +7,8 @@ const useInputSupports = _ref => {
7
7
  label,
8
8
  feedback,
9
9
  validation,
10
- hint
10
+ hint,
11
+ nativeID
11
12
  } = _ref;
12
13
  const hasValidationError = validation === 'error';
13
14
  const inputId = useUniqueId('input');
@@ -22,7 +23,7 @@ const useInputSupports = _ref => {
22
23
  accessibilityInvalid: hasValidationError
23
24
  };
24
25
  return {
25
- inputId,
26
+ inputId: nativeID || inputId,
26
27
  hintId,
27
28
  feedbackId,
28
29
  a11yProps
@@ -10,6 +10,7 @@ import { a11yProps, copyPropTypes, getTokensPropType, selectSystemProps, useCopy
10
10
  import { useViewport } from '../ViewportProvider';
11
11
  import IconButton from '../IconButton';
12
12
  import dictionary from './dictionary';
13
+ import useScrollBlocking from '../utils/useScrollBlocking';
13
14
  import { jsx as _jsx } from "react/jsx-runtime";
14
15
  import { jsxs as _jsxs } from "react/jsx-runtime";
15
16
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
@@ -110,6 +111,7 @@ const Modal = /*#__PURE__*/forwardRef((_ref5, ref) => {
110
111
  viewport,
111
112
  maxWidth
112
113
  });
114
+ const modalRef = useScrollBlocking(isOpen);
113
115
  const {
114
116
  closeIcon: CloseIconComponent
115
117
  } = themeTokens;
@@ -140,6 +142,7 @@ const Modal = /*#__PURE__*/forwardRef((_ref5, ref) => {
140
142
  ...selectProps(rest),
141
143
  children: /*#__PURE__*/_jsxs(View, {
142
144
  style: [staticStyles.positioningContainer],
145
+ ref: modalRef,
143
146
  children: [/*#__PURE__*/_jsx(View, {
144
147
  style: [staticStyles.sizingContainer, selectContainerStyles(themeTokens)],
145
148
  pointerEvents: "box-none" // don't capture backdrop press events
@@ -19,6 +19,7 @@ const selectSkeletonStyles = _ref => {
19
19
  return {
20
20
  backgroundColor: color,
21
21
  borderRadius: radius,
22
+ maxWidth: '100%',
22
23
  ...fadeAnimation
23
24
  };
24
25
  };
@@ -154,19 +154,18 @@ const StepTracker = /*#__PURE__*/forwardRef((_ref4, ref) => {
154
154
  })
155
155
  });
156
156
  });
157
- StepTracker.displayName = 'StepTracker';
157
+ StepTracker.displayName = 'StepTracker'; // If a language dictionary entry is provided, it must contain every key
158
+
159
+ const dictionaryContentShape = PropTypes.shape({
160
+ stepLabel: PropTypes.string.isRequired,
161
+ stepTrackerLabel: PropTypes.string.isRequired
162
+ });
158
163
  StepTracker.propTypes = { ...selectedSystemPropTypes,
159
164
  current: PropTypes.number,
160
- copy: PropTypes.oneOf(['en', 'fr']),
165
+ copy: PropTypes.oneOfType([PropTypes.oneOf(['en', 'fr']), dictionaryContentShape]),
161
166
  dictionary: PropTypes.shape({
162
- en: PropTypes.shape({
163
- stepLabel: PropTypes.string,
164
- stepTrackerLabel: PropTypes.string
165
- }),
166
- fr: PropTypes.shape({
167
- stepLabel: PropTypes.string,
168
- stepTrackerLabel: PropTypes.string
169
- })
167
+ en: dictionaryContentShape,
168
+ fr: dictionaryContentShape
170
169
  }),
171
170
  steps: PropTypes.arrayOf(PropTypes.string),
172
171
  tokens: getTokensPropType('StepTracker'),
@@ -40,7 +40,9 @@ const TextInput = /*#__PURE__*/forwardRef((_ref, ref) => {
40
40
  validation: supportsProps.validation
41
41
  }
42
42
  };
43
- return /*#__PURE__*/_jsx(InputSupports, { ...supportsProps,
43
+ return /*#__PURE__*/_jsx(InputSupports, {
44
+ nativeID: selectedProps.nativeID,
45
+ ...supportsProps,
44
46
  children: _ref2 => {
45
47
  let {
46
48
  inputId,
@@ -17,6 +17,7 @@ export { default as Icon } from './Icon';
17
17
  export * from './Icon';
18
18
  export { default as IconButton } from './IconButton';
19
19
  export { default as InputLabel } from './InputLabel';
20
+ export { default as InputSupports } from './InputSupports';
20
21
  export * from './Link';
21
22
  export { default as List, ListItem, ListBase } from './List';
22
23
  export { default as Modal } from './Modal';
@@ -1,8 +1,8 @@
1
1
  import PropTypes from 'prop-types';
2
2
  const clickHandlerMapping = {
3
3
  onClick: 'onPress',
4
- mouseDown: 'onPressIn',
5
- mouseUp: 'onPressOut'
4
+ onMouseDown: 'onPressIn',
5
+ onMouseUp: 'onPressOut'
6
6
  };
7
7
  export default {
8
8
  /**