@telus-uds/components-base 1.14.3 → 1.15.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 (139) hide show
  1. package/CHANGELOG.md +15 -2
  2. package/__tests17__/A11yText/A11yText.test.jsx +34 -0
  3. package/__tests17__/ActivityIndicator/ActivityIndicator.test.jsx +68 -0
  4. package/__tests17__/ActivityIndicator/__snapshots__/ActivityIndicator.test.jsx.snap +299 -0
  5. package/__tests17__/Box/Box.test.jsx +111 -0
  6. package/__tests17__/Button/Button.test.jsx +86 -0
  7. package/__tests17__/Button/ButtonBase.test.jsx +82 -0
  8. package/__tests17__/Button/ButtonGroup.test.jsx +347 -0
  9. package/__tests17__/Button/ButtonLink.test.jsx +61 -0
  10. package/__tests17__/Card/Card.test.jsx +63 -0
  11. package/__tests17__/Carousel/Carousel.test.jsx +128 -0
  12. package/__tests17__/Carousel/CarouselTabs.test.jsx +142 -0
  13. package/__tests17__/Checkbox/Checkbox.test.jsx +94 -0
  14. package/__tests17__/Checkbox/CheckboxGroup.test.jsx +246 -0
  15. package/__tests17__/Divider/Divider.test.jsx +91 -0
  16. package/__tests17__/ExpandCollapse/ExpandCollapse.test.jsx +109 -0
  17. package/__tests17__/Feedback/Feedback.test.jsx +42 -0
  18. package/__tests17__/FlexGrid/Col.test.jsx +261 -0
  19. package/__tests17__/FlexGrid/FlexGrid.test.jsx +136 -0
  20. package/__tests17__/FlexGrid/Row.test.jsx +273 -0
  21. package/__tests17__/HorizontalScroll/HorizontalScroll.test.jsx +165 -0
  22. package/__tests17__/Icon/Icon.test.jsx +61 -0
  23. package/__tests17__/IconButton/IconButton.test.jsx +52 -0
  24. package/__tests17__/InputLabel/InputLabel.test.jsx +28 -0
  25. package/__tests17__/InputLabel/__snapshots__/InputLabel.test.jsx.snap +3 -0
  26. package/__tests17__/InputSupports/InputSupports.test.jsx +60 -0
  27. package/__tests17__/Link/Link.test.jsx +63 -0
  28. package/__tests17__/Link/TextButton.test.jsx +35 -0
  29. package/__tests17__/List/List.test.jsx +82 -0
  30. package/__tests17__/Modal/Modal.test.jsx +47 -0
  31. package/__tests17__/Notification/Notification.test.jsx +20 -0
  32. package/__tests17__/Pagination/Pagination.test.jsx +160 -0
  33. package/__tests17__/Progress/Progress.test.jsx +79 -0
  34. package/__tests17__/Radio/Radio.test.jsx +87 -0
  35. package/__tests17__/Radio/RadioGroup.test.jsx +220 -0
  36. package/__tests17__/RadioCard/RadioCard.test.jsx +87 -0
  37. package/__tests17__/RadioCard/RadioCardGroup.test.jsx +246 -0
  38. package/__tests17__/Search/Search.test.jsx +87 -0
  39. package/__tests17__/Select/Select.test.jsx +94 -0
  40. package/__tests17__/SideNav/SideNav.test.jsx +110 -0
  41. package/__tests17__/Skeleton/Skeleton.test.jsx +61 -0
  42. package/__tests17__/SkipLink/SkipLink.test.jsx +61 -0
  43. package/__tests17__/Spacer/Spacer.test.jsx +63 -0
  44. package/__tests17__/StackView/StackView.test.jsx +211 -0
  45. package/__tests17__/StackView/StackWrap.test.jsx +47 -0
  46. package/__tests17__/StackView/getStackedContent.test.jsx +295 -0
  47. package/__tests17__/StepTracker/StepTracker.test.jsx +108 -0
  48. package/__tests17__/Tabs/Tabs.test.jsx +49 -0
  49. package/__tests17__/Tags/Tags.test.jsx +327 -0
  50. package/__tests17__/TextInput/TextArea.test.jsx +35 -0
  51. package/__tests17__/TextInput/TextInputBase.test.jsx +125 -0
  52. package/__tests17__/ThemeProvider/ThemeProvider.test.jsx +80 -0
  53. package/__tests17__/ThemeProvider/useThemeTokens.test.jsx +514 -0
  54. package/__tests17__/ThemeProvider/utils/theme-tokens.test.js +41 -0
  55. package/__tests17__/ToggleSwitch/ToggleSwitch.test.jsx +82 -0
  56. package/__tests17__/ToggleSwitch/ToggleSwitchGroup.test.jsx +192 -0
  57. package/__tests17__/Tooltip/Tooltip.test.jsx +65 -0
  58. package/__tests17__/Tooltip/getTooltipPosition.test.js +79 -0
  59. package/__tests17__/Typography/typography.test.jsx +90 -0
  60. package/__tests17__/utils/children.test.jsx +128 -0
  61. package/__tests17__/utils/containUniqueFields.test.js +25 -0
  62. package/__tests17__/utils/input.test.js +375 -0
  63. package/__tests17__/utils/props.test.js +36 -0
  64. package/__tests17__/utils/semantics.test.jsx +34 -0
  65. package/__tests17__/utils/useCopy.test.js +42 -0
  66. package/__tests17__/utils/useResponsiveProp.test.jsx +202 -0
  67. package/__tests17__/utils/useSpacingScale.test.jsx +273 -0
  68. package/__tests17__/utils/useUniqueId.test.js +31 -0
  69. package/component-docs.json +85 -438
  70. package/lib/A11yInfoProvider/index.js +14 -5
  71. package/lib/Button/ButtonGroup.js +3 -2
  72. package/lib/Checkbox/Checkbox.js +9 -6
  73. package/lib/ExpandCollapse/Control.js +6 -5
  74. package/lib/ExpandCollapse/Panel.js +5 -4
  75. package/lib/List/ListItem.js +10 -236
  76. package/lib/List/ListItemBase.js +162 -0
  77. package/lib/List/ListItemContent.js +85 -0
  78. package/lib/List/ListItemMark.js +158 -0
  79. package/lib/List/PressableListItemBase.js +147 -0
  80. package/lib/Notification/Notification.js +2 -1
  81. package/lib/Pagination/Pagination.js +4 -3
  82. package/lib/Radio/Radio.js +9 -6
  83. package/lib/RadioCard/RadioCard.js +9 -6
  84. package/lib/Tabs/Tabs.js +12 -3
  85. package/lib/Tags/Tags.js +3 -3
  86. package/lib/TextInput/TextInput.js +5 -4
  87. package/lib/ViewportProvider/useViewportListener.js +11 -5
  88. package/lib/utils/hasOwnProperty.js +18 -0
  89. package/lib/utils/props/a11yProps.js +212 -45
  90. package/lib/utils/props/getPropSelector.js +47 -5
  91. package/lib/utils/useResponsiveProp.js +5 -3
  92. package/lib/utils/withLinkRouter.js +3 -5
  93. package/lib-module/A11yInfoProvider/index.js +14 -4
  94. package/lib-module/Button/ButtonGroup.js +3 -2
  95. package/lib-module/Checkbox/Checkbox.js +9 -6
  96. package/lib-module/ExpandCollapse/Control.js +6 -5
  97. package/lib-module/ExpandCollapse/Panel.js +5 -4
  98. package/lib-module/List/ListItem.js +13 -235
  99. package/lib-module/List/ListItemBase.js +139 -0
  100. package/lib-module/List/ListItemContent.js +66 -0
  101. package/lib-module/List/ListItemMark.js +143 -0
  102. package/lib-module/List/PressableListItemBase.js +117 -0
  103. package/lib-module/Notification/Notification.js +2 -1
  104. package/lib-module/Pagination/Pagination.js +5 -3
  105. package/lib-module/Radio/Radio.js +9 -6
  106. package/lib-module/RadioCard/RadioCard.js +9 -6
  107. package/lib-module/Tabs/Tabs.js +13 -4
  108. package/lib-module/Tags/Tags.js +3 -3
  109. package/lib-module/TextInput/TextInput.js +5 -4
  110. package/lib-module/ViewportProvider/useViewportListener.js +10 -4
  111. package/lib-module/utils/hasOwnProperty.js +11 -0
  112. package/lib-module/utils/props/a11yProps.js +210 -45
  113. package/lib-module/utils/props/getPropSelector.js +44 -5
  114. package/lib-module/utils/useResponsiveProp.js +3 -4
  115. package/lib-module/utils/withLinkRouter.js +3 -5
  116. package/package.json +11 -16
  117. package/src/A11yInfoProvider/index.jsx +20 -4
  118. package/src/Button/ButtonGroup.jsx +4 -2
  119. package/src/Checkbox/Checkbox.jsx +7 -3
  120. package/src/ExpandCollapse/Control.jsx +8 -5
  121. package/src/ExpandCollapse/Panel.jsx +7 -5
  122. package/src/List/ListItem.jsx +12 -191
  123. package/src/List/ListItemBase.jsx +118 -0
  124. package/src/List/ListItemContent.jsx +52 -0
  125. package/src/List/ListItemMark.jsx +99 -0
  126. package/src/List/PressableListItemBase.jsx +102 -0
  127. package/src/Notification/Notification.jsx +1 -1
  128. package/src/Pagination/Pagination.jsx +6 -1
  129. package/src/Radio/Radio.jsx +7 -3
  130. package/src/RadioCard/RadioCard.jsx +7 -3
  131. package/src/Tabs/Tabs.jsx +19 -2
  132. package/src/Tags/Tags.jsx +3 -3
  133. package/src/TextInput/TextInput.jsx +4 -4
  134. package/src/ViewportProvider/useViewportListener.js +10 -5
  135. package/src/utils/hasOwnProperty.js +11 -0
  136. package/src/utils/props/a11yProps.js +168 -55
  137. package/src/utils/props/getPropSelector.js +45 -4
  138. package/src/utils/useResponsiveProp.js +3 -3
  139. package/src/utils/withLinkRouter.jsx +1 -3
@@ -0,0 +1,117 @@
1
+ import React, { forwardRef } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import ABBPropTypes from 'airbnb-prop-types';
4
+ import Pressable from "react-native-web/dist/exports/Pressable";
5
+ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
6
+ import Platform from "react-native-web/dist/exports/Platform";
7
+ import { resolvePressableTokens, clickProps, linkProps, hrefAttrsProp, withLinkRouter } from '../utils';
8
+ import ListItemBase from './ListItemBase';
9
+ import ListItemContent, { tokenTypes as contentTokenTypes } from './ListItemContent';
10
+ import ListItemMark, { tokenTypes as markTokenTypes } from './ListItemMark';
11
+ import { jsx as _jsx } from "react/jsx-runtime";
12
+ import { Fragment as _Fragment } from "react/jsx-runtime";
13
+ import { jsxs as _jsxs } from "react/jsx-runtime";
14
+
15
+ const selectPressableStyles = _ref => {
16
+ let {
17
+ backgroundColor,
18
+ paddingLeft,
19
+ paddingRight,
20
+ paddingTop,
21
+ paddingBottom,
22
+ interItemMargin
23
+ } = _ref;
24
+ return {
25
+ backgroundColor,
26
+ paddingLeft,
27
+ paddingRight,
28
+ paddingTop,
29
+ paddingBottom,
30
+ marginBottom: interItemMargin,
31
+ ...Platform.select({
32
+ web: {
33
+ outline: 'none'
34
+ }
35
+ })
36
+ };
37
+ };
38
+
39
+ const PressableListItemBase = /*#__PURE__*/forwardRef((_ref2, ref) => {
40
+ let {
41
+ href,
42
+ tokens,
43
+ icon,
44
+ children,
45
+ listItemRef,
46
+ ...rest
47
+ } = _ref2;
48
+ const {
49
+ onPress,
50
+ ...props
51
+ } = clickProps.toPressProps(rest);
52
+ const {
53
+ hrefAttrs,
54
+ rest: listItemProps
55
+ } = hrefAttrsProp.bundle(props);
56
+ const handlePress = linkProps.handleHref({
57
+ href,
58
+ onPress
59
+ });
60
+ return /*#__PURE__*/_jsx(ListItemBase, {
61
+ ref: listItemRef,
62
+ tokens: tokens(),
63
+ ...listItemProps,
64
+ children: _ref3 => {
65
+ let {
66
+ isLastItem
67
+ } = _ref3;
68
+
69
+ const getTokens = pressableState => resolvePressableTokens(tokens, pressableState, {
70
+ last: isLastItem
71
+ });
72
+
73
+ const getPressableStyle = pressableState => [staticStyles.itemContainer, selectPressableStyles(getTokens(pressableState))];
74
+
75
+ return /*#__PURE__*/_jsx(Pressable, {
76
+ onPress: handlePress,
77
+ href: href,
78
+ hrefAttrs: hrefAttrs,
79
+ style: getPressableStyle,
80
+ ref: ref,
81
+ children: pressableState => {
82
+ const themeTokens = getTokens(pressableState);
83
+ return /*#__PURE__*/_jsxs(_Fragment, {
84
+ children: [/*#__PURE__*/_jsx(ListItemMark, {
85
+ icon: icon,
86
+ tokens: themeTokens
87
+ }), /*#__PURE__*/_jsx(ListItemContent, {
88
+ tokens: themeTokens,
89
+ children: typeof children === 'function' ? children(pressableState) : children
90
+ })]
91
+ });
92
+ }
93
+ });
94
+ }
95
+ });
96
+ });
97
+ PressableListItemBase.displayName = 'PressableListItemBase';
98
+ const staticStyles = StyleSheet.create({
99
+ itemContainer: {
100
+ flexDirection: 'row',
101
+ flex: 1
102
+ },
103
+ tokens: { ...contentTokenTypes,
104
+ ...markTokenTypes
105
+ }
106
+ });
107
+ PressableListItemBase.propTypes = {
108
+ href: PropTypes.string,
109
+ onPress: PropTypes.func,
110
+ // TODO - type this better, maybe import the subcomponent token types and run it through util
111
+ // eslint-disable-next-line react/forbid-prop-types
112
+ tokens: PropTypes.any,
113
+ icon: PropTypes.elementType,
114
+ children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
115
+ listItemRef: ABBPropTypes.ref()
116
+ };
117
+ export default withLinkRouter(PressableListItemBase);
@@ -143,7 +143,8 @@ const Notification = /*#__PURE__*/forwardRef((_ref5, ref) => {
143
143
 
144
144
  const textStyles = selectTextStyles(themeTokens, themeOptions);
145
145
  const content = wrapStringsInText(typeof children === 'function' ? children({
146
- textStyles
146
+ textStyles,
147
+ variant
147
148
  }) : children, {
148
149
  style: textStyles
149
150
  });
@@ -10,6 +10,7 @@ import usePagination from './usePagination';
10
10
  import PageButton from './PageButton';
11
11
  import SideButton from './SideButton';
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
+ import { createElement as _createElement } from "react";
13
14
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
14
15
 
15
16
  const selectTextStyles = (_ref, themeOptions) => {
@@ -93,12 +94,13 @@ const Pagination = /*#__PURE__*/forwardRef((_ref2, ref) => {
93
94
  };
94
95
 
95
96
  if (shouldRenderButton(itemIndex)) {
96
- return /*#__PURE__*/_jsx(PageButton, { ...itemProps,
97
+ return /*#__PURE__*/_createElement(PageButton, { ...itemProps,
97
98
  LinkRouter: ItemLinkRouter,
98
99
  linkRouterProps: itemLinkRouterProps,
99
100
  label: buttonLabel,
100
101
  copy: copy,
101
- isActive: isItemActive(itemIndex)
102
+ isActive: isItemActive(itemIndex),
103
+ key: buttonLabel
102
104
  });
103
105
  }
104
106
 
@@ -106,7 +108,7 @@ const Pagination = /*#__PURE__*/forwardRef((_ref2, ref) => {
106
108
  return /*#__PURE__*/_jsx(Text, {
107
109
  style: ellipsisTextStyles,
108
110
  children: "..."
109
- });
111
+ }, "...");
110
112
  }
111
113
 
112
114
  return null;
@@ -151,17 +151,20 @@ const Radio = /*#__PURE__*/forwardRef((_ref4, ref) => {
151
151
 
152
152
  const uniqueId = useUniqueId('radio');
153
153
  const inputId = id !== null && id !== void 0 ? id : uniqueId;
154
+ const selectedProps = selectProps({
155
+ accessibilityRole: 'radio',
156
+ accessibilityState: {
157
+ checked: isChecked,
158
+ disabled: inactive
159
+ },
160
+ ...rest
161
+ });
154
162
  return /*#__PURE__*/_jsx(Pressable, {
155
163
  ref: ref,
156
164
  disabled: inactive,
157
165
  onKeyDown: handleKeyDown,
158
166
  onPress: handleChange,
159
- accessibilityRole: "radio",
160
- accessibilityState: {
161
- checked: isChecked,
162
- disabled: inactive
163
- },
164
- ...selectProps(rest),
167
+ ...selectedProps,
165
168
  children: _ref5 => {
166
169
  let {
167
170
  focused: focus,
@@ -87,18 +87,21 @@ const RadioCard = /*#__PURE__*/forwardRef((_ref, ref) => {
87
87
  const {
88
88
  themeOptions
89
89
  } = useTheme();
90
+ const selectedProps = selectProps({
91
+ accessibilityRole: 'radio',
92
+ accessibilityState: {
93
+ checked: isChecked,
94
+ disabled: inactive
95
+ },
96
+ ...rest
97
+ });
90
98
  return /*#__PURE__*/_jsx(PressableCardBase, {
91
99
  ref: ref,
92
100
  inactive: inactive,
93
101
  checked: isChecked,
94
102
  tokens: getCardTokens,
95
103
  onPress: handleChange,
96
- accessibilityRole: "radio",
97
- accessibilityState: {
98
- checked: isChecked,
99
- disabled: inactive
100
- },
101
- ...selectProps(rest),
104
+ ...selectedProps,
102
105
  children: cardState => {
103
106
  const {
104
107
  radioSpace,
@@ -3,11 +3,12 @@ import PropTypes from 'prop-types';
3
3
  import ABBPropTypes from 'airbnb-prop-types';
4
4
  import { useThemeTokens } from '../ThemeProvider';
5
5
  import StackView from '../StackView';
6
- import { a11yProps, getTokensPropType, selectSystemProps, useHash, useInputValue, variantProp, viewProps, withLinkRouter } from '../utils';
6
+ import { a11yProps, getTokensPropType, focusHandlerProps, pressProps, selectSystemProps, useHash, useInputValue, variantProp, viewProps, withLinkRouter } from '../utils';
7
7
  import HorizontalScroll, { horizontalScrollUtils, HorizontalScrollButton } from '../HorizontalScroll';
8
8
  import TabsItem from './TabsItem';
9
9
  import { jsx as _jsx } from "react/jsx-runtime";
10
10
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
11
+ const [selectItemProps, selectedItemPropTypes] = selectSystemProps([a11yProps, focusHandlerProps, pressProps, viewProps]);
11
12
  const {
12
13
  selectHorizontalScrollTokens,
13
14
  useItemPositions
@@ -94,15 +95,21 @@ const Tabs = /*#__PURE__*/forwardRef((_ref, ref) => {
94
95
  label,
95
96
  id,
96
97
  accessibilityRole = defaultTabItemAccessibiltyRole,
98
+ onPress,
97
99
  ref: itemRef,
98
100
  LinkRouter: ItemLinkRouter = LinkRouter,
99
- linkRouterProps: itemLinkRouterProps
101
+ linkRouterProps: itemLinkRouterProps,
102
+ ...itemRest
100
103
  } = _ref3;
101
104
  const itemId = id !== null && id !== void 0 ? id : label;
102
105
  const isSelected = Boolean(currentValue && currentValue === itemId);
103
106
 
104
- const handlePress = event => setValue(itemId, event);
107
+ const handlePress = event => {
108
+ if (typeof onPress === 'function') onPress(event);
109
+ setValue(itemId, event);
110
+ };
105
111
 
112
+ const itemProps = selectItemProps(itemRest);
106
113
  return /*#__PURE__*/_jsx(TabsItem, {
107
114
  ref: itemRef,
108
115
  href: href,
@@ -117,6 +124,7 @@ const Tabs = /*#__PURE__*/forwardRef((_ref, ref) => {
117
124
  linkRouterProps: { ...linkRouterProps,
118
125
  ...itemLinkRouterProps
119
126
  },
127
+ ...itemProps,
120
128
  children: label
121
129
  }, itemId);
122
130
  })
@@ -126,7 +134,8 @@ const Tabs = /*#__PURE__*/forwardRef((_ref, ref) => {
126
134
  Tabs.displayName = 'Tabs';
127
135
  Tabs.propTypes = { ...selectedSystemPropTypes,
128
136
  ...withLinkRouter.PropTypes,
129
- items: PropTypes.arrayOf(PropTypes.shape({ ...withLinkRouter.PropTypes,
137
+ items: PropTypes.arrayOf(PropTypes.shape({ ...selectedItemPropTypes,
138
+ ...withLinkRouter.PropTypes,
130
139
  href: PropTypes.string,
131
140
  label: PropTypes.string,
132
141
  id: PropTypes.string,
@@ -131,14 +131,14 @@ const Tags = /*#__PURE__*/forwardRef((_ref2, ref) => {
131
131
  toggleOneValue(id, event);
132
132
  };
133
133
 
134
- const itemProps = {
134
+ const itemProps = selectItemProps({
135
135
  accessibilityState: {
136
136
  checked: isSelected
137
137
  },
138
138
  accessibilityRole: itemA11yRole,
139
139
  ...a11yProps.getPositionInSet(items.length, index),
140
- ...selectItemProps(itemRest)
141
- };
140
+ ...itemRest
141
+ });
142
142
  return /*#__PURE__*/_jsx(ButtonBase, {
143
143
  ref: itemRef,
144
144
  ...pressHandlers,
@@ -27,6 +27,7 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, foc
27
27
  const TextInput = /*#__PURE__*/forwardRef((_ref, ref) => {
28
28
  let {
29
29
  tokens,
30
+ nativeID,
30
31
  variant = {},
31
32
  ...rest
32
33
  } = _ref;
@@ -41,18 +42,18 @@ const TextInput = /*#__PURE__*/forwardRef((_ref, ref) => {
41
42
  }
42
43
  };
43
44
  return /*#__PURE__*/_jsx(InputSupports, {
44
- nativeID: selectedProps.nativeID,
45
+ nativeID: nativeID,
45
46
  ...supportsProps,
46
47
  children: _ref2 => {
47
48
  let {
48
49
  inputId,
49
- ...props
50
+ ...propsFromInputSupports
50
51
  } = _ref2;
51
52
  return /*#__PURE__*/_jsx(TextInputBase, {
52
53
  ref: ref,
53
- ...inputProps,
54
54
  nativeID: inputId,
55
- ...props
55
+ ...propsFromInputSupports,
56
+ ...inputProps
56
57
  });
57
58
  }
58
59
  });
@@ -33,10 +33,16 @@ const useViewportListenerCSR = setViewport => {
33
33
  return setViewport(viewports.select(window.width));
34
34
  };
35
35
 
36
- const listener = Dimensions.addEventListener('change', onChange); // From RN 0.65.0, Dimensions.removeEventListener is deprecated for `remove` on addEventListener return value;
37
- // however, that is not available in RN <=0.64.X, therefore not in any Expo release as of 2021 (Expo SDK 43).
38
-
39
- return (listener === null || listener === void 0 ? void 0 : listener.remove) || (() => Dimensions.removeEventListener('change', onChange)); // setViewport is a function from `useState` so it is stable and won't make the effect re-run
36
+ const listener = Dimensions.addEventListener('change', onChange);
37
+ return () => {
38
+ if (typeof (listener === null || listener === void 0 ? void 0 : listener.remove) === 'function') {
39
+ // Can't just return listener.remove because listener.emitter disappears, causing an internal error.
40
+ // See https://github.com/facebook/react-native/issues/34508
41
+ listener.remove(); // From RN 0.65.0, Dimensions.removeEventListener is deprecated for `remove` on addEventListener return value
42
+ } else if (typeof Dimensions.removeEventListener === 'function') {
43
+ Dimensions.removeEventListener('change', onChange);
44
+ }
45
+ };
40
46
  }, [setViewport]);
41
47
  }; // Window is a defined global object in both Web and Native client-side, and undefined in SSR
42
48
 
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Linter disallows object instance prototype methods like someObject.hasOwnProperty(key),
3
+ * but we can use this instead.
4
+ *
5
+ * @param {object} object
6
+ * @param {String} key
7
+ * @returns {Boolean}
8
+ */
9
+ export default function hasOwnProperty(object, key) {
10
+ return Object.prototype.hasOwnProperty.call(object, key);
11
+ }
@@ -36,53 +36,211 @@ const nativeA11yPropTypes = {
36
36
  onAccessibilityEscape: PropTypes.func,
37
37
  onAccessibilityTap: PropTypes.func
38
38
  };
39
- const a11yPropTypes = { ...nativeA11yPropTypes,
39
+ const a11yPropTypes = Platform.select({
40
40
  // React Native Web adds many a11y props that alias aria-* attributes
41
41
  // Types based on https://necolas.github.io/react-native-web/docs/accessibility/
42
- accessibilityActiveDescendant: PropTypes.string,
43
- accessibilityAtomic: PropTypes.bool,
44
- accessibilityAutoComplete: PropTypes.string,
45
- accessibilityBusy: PropTypes.bool,
46
- accessibilityChecked: PropTypes.oneOf([true, false, 'mixed']),
47
- accessibilityColumnCount: PropTypes.number,
48
- accessibilityColumnIndex: PropTypes.number,
49
- accessibilityColumnSpan: PropTypes.number,
50
- accessibilityControls: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
51
- accessibilityCurrent: PropTypes.oneOf([true, false, 'page', 'step', 'location', 'date', 'time']),
52
- accessibilityDescribedBy: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
53
- accessibilityDetails: PropTypes.string,
54
- accessibilityDisabled: PropTypes.bool,
55
- accessibilityErrorMessage: PropTypes.string,
56
- accessibilityExpanded: PropTypes.bool,
57
- accessibilityFlowTo: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
58
- accessibilityHasPopup: PropTypes.string,
59
- accessibilityHidden: PropTypes.bool,
60
- accessibilityInvalid: PropTypes.bool,
61
- accessibilityKeyShortcuts: PropTypes.string,
62
- accessibilityLabelledBy: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
63
- accessibilityLevel: PropTypes.number,
64
- accessibilityModal: PropTypes.bool,
65
- accessibilityMultiline: PropTypes.bool,
66
- accessibilityMultiSelectable: PropTypes.bool,
67
- accessibilityOrientation: PropTypes.oneOf(['horizontal', 'vertical']),
68
- accessibilityOwns: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
69
- accessibilityPlaceholder: PropTypes.string,
70
- accessibilityPosInSet: PropTypes.number,
71
- accessibilityPressed: PropTypes.bool,
72
- accessibilityReadOnly: PropTypes.bool,
73
- accessibilityRequired: PropTypes.bool,
74
- accessibilityRoleDescription: PropTypes.string,
75
- accessibilityRowCount: PropTypes.number,
76
- accessibilityRowIndex: PropTypes.number,
77
- accessibilityRowSpan: PropTypes.number,
78
- accessibilitySelected: PropTypes.bool,
79
- accessibilitySetSize: PropTypes.number,
80
- accessibilitySort: PropTypes.oneOf(['ascending', 'descending', 'none', 'other']),
81
- accessibilityValueMax: PropTypes.number,
82
- accessibilityValueMin: PropTypes.number,
83
- accessibilityValueNow: PropTypes.number,
84
- accessibilityValueText: PropTypes.string
42
+ web: { ...nativeA11yPropTypes,
43
+ accessibilityActiveDescendant: PropTypes.string,
44
+ accessibilityAtomic: PropTypes.bool,
45
+ accessibilityAutoComplete: PropTypes.string,
46
+ accessibilityBusy: PropTypes.bool,
47
+ accessibilityChecked: PropTypes.oneOf([true, false, 'mixed']),
48
+ accessibilityColumnCount: PropTypes.number,
49
+ accessibilityColumnIndex: PropTypes.number,
50
+ accessibilityColumnSpan: PropTypes.number,
51
+ accessibilityControls: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
52
+ accessibilityCurrent: PropTypes.oneOf([true, false, 'page', 'step', 'location', 'date', 'time']),
53
+ accessibilityDescribedBy: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
54
+ accessibilityDetails: PropTypes.string,
55
+ accessibilityDisabled: PropTypes.bool,
56
+ accessibilityErrorMessage: PropTypes.string,
57
+ accessibilityExpanded: PropTypes.bool,
58
+ accessibilityFlowTo: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
59
+ accessibilityHasPopup: PropTypes.string,
60
+ accessibilityHidden: PropTypes.bool,
61
+ accessibilityInvalid: PropTypes.bool,
62
+ accessibilityKeyShortcuts: PropTypes.string,
63
+ accessibilityLabelledBy: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
64
+ accessibilityLevel: PropTypes.number,
65
+ accessibilityModal: PropTypes.bool,
66
+ accessibilityMultiline: PropTypes.bool,
67
+ accessibilityMultiSelectable: PropTypes.bool,
68
+ accessibilityOrientation: PropTypes.oneOf(['horizontal', 'vertical']),
69
+ accessibilityOwns: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
70
+ accessibilityPlaceholder: PropTypes.string,
71
+ accessibilityPosInSet: PropTypes.number,
72
+ accessibilityPressed: PropTypes.bool,
73
+ accessibilityReadOnly: PropTypes.bool,
74
+ accessibilityRequired: PropTypes.bool,
75
+ accessibilityRoleDescription: PropTypes.string,
76
+ accessibilityRowCount: PropTypes.number,
77
+ accessibilityRowIndex: PropTypes.number,
78
+ accessibilityRowSpan: PropTypes.number,
79
+ accessibilitySelected: PropTypes.bool,
80
+ accessibilitySetSize: PropTypes.number,
81
+ accessibilitySort: PropTypes.oneOf(['ascending', 'descending', 'none', 'other']),
82
+ accessibilityValueMax: PropTypes.number,
83
+ accessibilityValueMin: PropTypes.number,
84
+ accessibilityValueNow: PropTypes.number,
85
+ accessibilityValueText: PropTypes.string
86
+ },
87
+ // Ignore web-only props in native builds
88
+ default: nativeA11yPropTypes
89
+ }); // These RNW-only props only exist in RNW >=0.18. Catch them and map them according to platform
90
+ // so all props work on RN, RNW >=0.18 and RNW <=0.18, regardless of which they were written for:
91
+ // - On native, bundle them into objects, like `accessibilityValue: { max: 100 }`
92
+ // - On web, split them into both of:
93
+ // - The appropriate aria-* attr, like `aria-valuenow`, which will work regardless of RNW version
94
+ // - The corresponding RNW >=0.18 prop, like `accessibilityValueNow`, which in some cases does more
95
+ // than just add the aria-* (e.g. `accessibilityDisabled` adds `disabled` if element supports it,
96
+ // and future releases might add more features here).
97
+
98
+ const rwnPropMappings = {
99
+ // Former accessibilityValue props.
100
+ accessibilityValueMax: value => Platform.select({
101
+ web: {
102
+ 'aria-valuemax': value,
103
+ accessibilityValueMax: value
104
+ },
105
+ default: {
106
+ accessibilityValue: {
107
+ max: value
108
+ }
109
+ }
110
+ }),
111
+ accessibilityValueMin: value => Platform.select({
112
+ web: {
113
+ 'aria-valuemin': value,
114
+ accessibilityValueMin: value
115
+ },
116
+ default: {
117
+ accessibilityValue: {
118
+ min: value
119
+ }
120
+ }
121
+ }),
122
+ accessibilityValueNow: value => Platform.select({
123
+ web: {
124
+ 'aria-valuenow': value,
125
+ accessibilityValueNow: value
126
+ },
127
+ default: {
128
+ accessibilityValue: {
129
+ now: value
130
+ }
131
+ }
132
+ }),
133
+ accessibilityValueText: value => Platform.select({
134
+ web: {
135
+ 'aria-valuetext': value,
136
+ accessibilityValueText: value
137
+ },
138
+ default: {
139
+ accessibilityValue: {
140
+ text: value
141
+ }
142
+ }
143
+ }),
144
+ // Former accessibilityState props
145
+ accessibilityBusy: value => Platform.select({
146
+ web: {
147
+ 'aria-busy': value,
148
+ accessibilityBusy: value
149
+ },
150
+ default: {
151
+ accessibilityState: {
152
+ busy: value
153
+ }
154
+ }
155
+ }),
156
+ accessibilityChecked: value => Platform.select({
157
+ web: {
158
+ 'aria-checked': value,
159
+ accessibilityChecked: value
160
+ },
161
+ default: {
162
+ accessibilityState: {
163
+ checked: value
164
+ }
165
+ }
166
+ }),
167
+ accessibilityDisabled: value => Platform.select({
168
+ web: {
169
+ 'aria-disabled': value,
170
+ // RNW >= 0.18 maps `accessibilityDisabled` to `disabled` attr if element supports it
171
+ accessibilityDisabled: value,
172
+ // As of RNW 0.18.9, Pressable doesn't support `accessibilityDisabled`, only `disabled`,
173
+ // but everything else supports `accessibilityDisabled` but not `disabled`.
174
+ disabled: value
175
+ },
176
+ default: {
177
+ accessibilityState: {
178
+ disabled: value
179
+ }
180
+ }
181
+ }),
182
+ accessibilityExpanded: value => Platform.select({
183
+ web: {
184
+ 'aria-expanded': value,
185
+ accessibilityExpanded: value
186
+ },
187
+ default: {
188
+ accessibilityState: {
189
+ expanded: value
190
+ }
191
+ }
192
+ }),
193
+ accessibilitySelected: value => Platform.select({
194
+ web: {
195
+ 'aria-selected': value,
196
+ accessibilitySelected: value
197
+ },
198
+ default: {
199
+ accessibilityState: {
200
+ selected: value
201
+ }
202
+ }
203
+ })
85
204
  };
205
+
206
+ if (Platform.OS === 'web') {
207
+ const mapIfDefined = (value, fn) => value === undefined ? undefined : fn(value); // On Web only, these React Native object props need manual mapping in RNW >=0.18
208
+ // which dropped support for the React Native shape of these props.
209
+ // Re-use our RNW 0.18 prop mappings to support both RNW <0.18 (aria-*) and
210
+ // new features added in >=0.18 (e.g. for accessibilityDisabled).
211
+
212
+
213
+ rwnPropMappings.accessibilityValue = function () {
214
+ let {
215
+ max,
216
+ min,
217
+ now,
218
+ text
219
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
220
+ return { ...mapIfDefined(max, rwnPropMappings.accessibilityValueMax),
221
+ ...mapIfDefined(min, rwnPropMappings.accessibilityValueMin),
222
+ ...mapIfDefined(now, rwnPropMappings.accessibilityValueNow),
223
+ ...mapIfDefined(text, rwnPropMappings.accessibilityValueText)
224
+ };
225
+ };
226
+
227
+ rwnPropMappings.accessibilityState = function () {
228
+ let {
229
+ busy,
230
+ checked,
231
+ disabled,
232
+ expanded,
233
+ selected
234
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
235
+ return { ...mapIfDefined(busy, rwnPropMappings.accessibilityBusy),
236
+ ...mapIfDefined(checked, rwnPropMappings.accessibilityChecked),
237
+ ...mapIfDefined(disabled, rwnPropMappings.accessibilityDisabled),
238
+ ...mapIfDefined(expanded, rwnPropMappings.accessibilityExpanded),
239
+ ...mapIfDefined(selected, rwnPropMappings.accessibilitySelected)
240
+ };
241
+ };
242
+ }
243
+
86
244
  export default {
87
245
  /**
88
246
  * Proptypes for recognised React Native accessiblity (a11y) props.
@@ -96,7 +254,14 @@ export default {
96
254
  * Where components accept React Native a11y props, pass { ...rest } from its props to this,
97
255
  * then spread the returned object into the component's props (usually its outer container).
98
256
  */
99
- select: getPropSelector(a11yPropTypes, /^aria-/),
257
+ select: getPropSelector( // Allow all React Native accessibility props
258
+ a11yPropTypes, // Allow any `aria-*` attribute on web; ignore them on native
259
+ Platform.OS === 'web' && /^aria-/, // For the props added and deprecated in React Native Web 0.18, convert them to
260
+ // a form that is platform-appropriate and RNW-version safe
261
+ (key, value) => {
262
+ const rnwPropMapper = rwnPropMappings[key];
263
+ return rnwPropMapper ? rnwPropMapper(value) : undefined;
264
+ }),
100
265
 
101
266
  /**
102
267
  * Use this to disable focus for elements which are visually hidden but still rendered.