@telus-uds/components-base 1.0.0 → 1.2.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 (121) hide show
  1. package/.storybook/main.js +4 -0
  2. package/.storybook/preview.js +37 -0
  3. package/.ultra.cache.json +1 -1
  4. package/CHANGELOG.md +26 -0
  5. package/README.md +1 -1
  6. package/__fixtures__/Accessible.js +4 -2
  7. package/__fixtures__/Accessible.native.js +5 -2
  8. package/__fixtures__/testTheme.js +9 -0
  9. package/__tests__/HorizontalScroll/HorizontalScroll.test.jsx +1 -0
  10. package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +10 -0
  11. package/__tests__/ToggleSwitch/ToggleSwitchGroup.test.jsx +192 -0
  12. package/babel.config.js +9 -16
  13. package/component-docs.json +10131 -0
  14. package/generate-component-docs.js +56 -0
  15. package/lib/Box/Box.js +1 -0
  16. package/lib/Button/ButtonBase.js +20 -6
  17. package/lib/Card/CardBase.js +1 -0
  18. package/lib/Card/PressableCardBase.js +9 -3
  19. package/lib/Checkbox/Checkbox.js +0 -2
  20. package/lib/FlexGrid/FlexGrid.js +1 -1
  21. package/lib/IconButton/IconButton.js +8 -3
  22. package/lib/Link/LinkBase.js +10 -3
  23. package/lib/List/List.js +1 -2
  24. package/lib/List/ListItem.js +14 -27
  25. package/lib/List/index.js +15 -0
  26. package/lib/Pagination/PageButton.js +4 -8
  27. package/lib/Pagination/Pagination.js +16 -4
  28. package/lib/Pagination/SideButton.js +3 -1
  29. package/lib/Radio/Radio.js +0 -2
  30. package/lib/StackView/StackView.js +1 -0
  31. package/lib/StackView/StackWrap.js +9 -5
  32. package/lib/StackView/StackWrapBox.js +1 -0
  33. package/lib/Tabs/Tabs.js +12 -4
  34. package/lib/Tabs/TabsItem.js +12 -6
  35. package/lib/ToggleSwitch/ToggleSwitch.js +99 -37
  36. package/lib/ToggleSwitch/ToggleSwitchGroup.js +230 -0
  37. package/lib/ToggleSwitch/index.js +14 -4
  38. package/lib/index.js +28 -9
  39. package/lib/utils/a11y/propTypes.js +61 -0
  40. package/lib/utils/a11y/propTypes.native.js +47 -0
  41. package/lib/utils/index.js +10 -1
  42. package/lib/utils/propTypes.js +35 -91
  43. package/lib/utils/withLinkRouter.js +98 -0
  44. package/package.json +10 -6
  45. package/release-context.json +4 -4
  46. package/src/Box/Box.jsx +1 -0
  47. package/src/Button/ButtonBase.jsx +11 -4
  48. package/src/Card/CardBase.jsx +1 -0
  49. package/src/Card/PressableCardBase.jsx +6 -4
  50. package/src/Checkbox/Checkbox.jsx +0 -2
  51. package/src/FlexGrid/FlexGrid.jsx +1 -1
  52. package/src/IconButton/IconButton.jsx +6 -4
  53. package/src/Link/LinkBase.jsx +6 -4
  54. package/src/List/List.jsx +1 -3
  55. package/src/List/ListItem.jsx +11 -26
  56. package/src/List/index.js +5 -0
  57. package/src/Pagination/PageButton.jsx +5 -8
  58. package/src/Pagination/Pagination.jsx +29 -2
  59. package/src/Pagination/SideButton.jsx +2 -2
  60. package/src/Radio/Radio.jsx +0 -2
  61. package/src/StackView/StackView.jsx +1 -0
  62. package/src/StackView/StackWrap.jsx +7 -6
  63. package/src/StackView/StackWrapBox.jsx +1 -0
  64. package/src/Tabs/Tabs.jsx +49 -22
  65. package/src/Tabs/TabsItem.jsx +11 -7
  66. package/src/ToggleSwitch/ToggleSwitch.jsx +92 -34
  67. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +203 -0
  68. package/src/ToggleSwitch/index.js +2 -1
  69. package/src/index.js +2 -2
  70. package/src/utils/a11y/propTypes.js +61 -0
  71. package/src/utils/a11y/propTypes.native.js +39 -0
  72. package/src/utils/index.js +1 -0
  73. package/src/utils/propTypes.js +33 -111
  74. package/src/utils/withLinkRouter.jsx +68 -0
  75. package/stories/A11yText/A11yText.stories.jsx +1 -1
  76. package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +1 -1
  77. package/stories/Box/Box.stories.jsx +1 -1
  78. package/stories/Button/Button.stories.jsx +1 -1
  79. package/stories/Button/ButtonGroup.stories.jsx +1 -1
  80. package/stories/Button/ButtonLink.stories.jsx +1 -1
  81. package/stories/Card/Card.stories.jsx +1 -1
  82. package/stories/Checkbox/Checkbox.stories.jsx +1 -1
  83. package/stories/Divider/Divider.stories.jsx +1 -1
  84. package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +1 -1
  85. package/stories/Feedback/Feedback.stories.jsx +1 -1
  86. package/stories/FlexGrid/01 FlexGrid.stories.jsx +1 -1
  87. package/stories/FlexGrid/02 Row.stories.jsx +1 -1
  88. package/stories/FlexGrid/03 Col.stories.jsx +1 -1
  89. package/stories/Icon/Icon.stories.jsx +1 -1
  90. package/stories/IconButton/IconButton.stories.jsx +1 -1
  91. package/stories/InputLabel/InputLabel.stories.jsx +1 -1
  92. package/stories/Link/ChevronLink.stories.jsx +1 -1
  93. package/stories/Link/Link.stories.jsx +1 -1
  94. package/stories/Link/TextButton.stories.jsx +1 -1
  95. package/stories/List/List.stories.jsx +1 -1
  96. package/stories/Modal/Modal.stories.jsx +1 -1
  97. package/stories/Notification/Notification.stories.jsx +1 -1
  98. package/stories/Pagination/Pagination.stories.jsx +1 -1
  99. package/stories/Progress/Progress.stories.jsx +1 -1
  100. package/stories/Radio/Radio.stories.jsx +1 -1
  101. package/stories/RadioCard/RadioCard.stories.jsx +1 -1
  102. package/stories/Search/Search.stories.jsx +1 -1
  103. package/stories/Select/Select.stories.jsx +1 -1
  104. package/stories/SideNav/SideNav.stories.jsx +1 -1
  105. package/stories/SideNav/SideNavItem.stories.jsx +1 -1
  106. package/stories/SideNav/SideNavItemsGroup.stories.jsx +1 -1
  107. package/stories/Skeleton/Skeleton.stories.jsx +1 -1
  108. package/stories/Spacer/Spacer.stories.jsx +1 -1
  109. package/stories/StackView/StackView.stories.jsx +1 -1
  110. package/stories/StackView/StackWrap.stories.jsx +1 -1
  111. package/stories/StepTracker/StepTracker.stories.jsx +1 -1
  112. package/stories/Tabs/Tabs.stories.jsx +1 -1
  113. package/stories/Tags/Tags.stories.jsx +1 -1
  114. package/stories/TextInput/TextArea.stories.jsx +2 -1
  115. package/stories/TextInput/TextInput.stories.jsx +1 -1
  116. package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +6 -2
  117. package/stories/ToggleSwitch/ToggleSwitchGroup.stories.jsx +81 -0
  118. package/stories/Tooltip/Tooltip.stories.jsx +1 -1
  119. package/stories/TooltipButton/TooltipButton.stories.jsx +1 -1
  120. package/stories/Typography/Typography.stories.jsx +1 -1
  121. package/stories/supports.jsx +2 -3
@@ -0,0 +1,203 @@
1
+ import React, { forwardRef } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import ABBPropTypes from 'airbnb-prop-types'
4
+ import { Platform } from 'react-native'
5
+
6
+ import ToggleSwitch from './ToggleSwitch'
7
+ import Fieldset from '../Fieldset'
8
+ import { getStackedContent } from '../StackView'
9
+ import { useViewport } from '../ViewportProvider'
10
+ import { useThemeTokens } from '../ThemeProvider'
11
+ import { a11yProps, pressProps, variantProp, getTokensPropType } from '../utils/propTypes'
12
+ import { useMultipleInputValues } from '../utils/input'
13
+
14
+ const ToggleSwitchGroup = forwardRef(
15
+ (
16
+ {
17
+ variant,
18
+ tokens,
19
+ items = [],
20
+ values,
21
+ initialValues,
22
+ maxValues = 1,
23
+ onChange,
24
+ readOnly = false,
25
+ inactive = false,
26
+ feedback,
27
+ hint,
28
+ tooltip,
29
+ legend,
30
+ name: inputGroupName,
31
+ accessibilityRole = maxValues === 1
32
+ ? 'radiogroup' // radiogroup is cross-platform; only web aria has generic groups
33
+ : Platform.select({ web: 'group', default: 'none' }),
34
+ toggleSwitchTokens,
35
+ validation,
36
+ ...rest
37
+ },
38
+ ref
39
+ ) => {
40
+ const viewport = useViewport()
41
+
42
+ const { space, fieldSpace } = useThemeTokens('ToggleSwitchGroup', tokens, variant, {
43
+ viewport
44
+ })
45
+
46
+ const { currentValues, toggleOneValue } = useMultipleInputValues({
47
+ initialValues,
48
+ values,
49
+ maxValues,
50
+ onChange,
51
+ readOnly
52
+ })
53
+
54
+ const a11y = a11yProps.select({
55
+ accessibilityRole,
56
+ ...rest
57
+ })
58
+ const itemA11yRole = a11y.accessibilityRole === 'radiogroup' ? 'radio' : 'switch'
59
+
60
+ const toggleSwitches = items.map(
61
+ (
62
+ {
63
+ label,
64
+ id = label,
65
+ accessibilityLabel = label,
66
+ onChange: itemOnChange,
67
+ ref: itemRef,
68
+ tooltip: itemTooltip
69
+ },
70
+ index
71
+ ) => {
72
+ const isSelected = currentValues.includes(id)
73
+
74
+ const handleChange = (newCheckedState, event) => {
75
+ if (typeof itemOnChange === 'function') itemOnChange(newCheckedState, event)
76
+ toggleOneValue(id, event)
77
+ }
78
+
79
+ const itemA11y = {
80
+ accessibilityState: { checked: isSelected },
81
+ accessibilityRole: itemA11yRole,
82
+ accessibilityLabel,
83
+ ...a11yProps.getPositionInSet(items.length, index)
84
+ }
85
+
86
+ return (
87
+ <ToggleSwitch
88
+ id={id}
89
+ ref={itemRef}
90
+ key={id}
91
+ onChange={handleChange}
92
+ tokens={toggleSwitchTokens}
93
+ value={isSelected}
94
+ inactive={inactive}
95
+ label={label}
96
+ tooltip={itemTooltip}
97
+ {...itemA11y}
98
+ />
99
+ )
100
+ }
101
+ )
102
+
103
+ return (
104
+ <Fieldset
105
+ ref={ref}
106
+ name={inputGroupName}
107
+ legend={legend}
108
+ tooltip={tooltip}
109
+ hint={hint}
110
+ space={fieldSpace}
111
+ feedback={feedback}
112
+ inactive={inactive}
113
+ validation={validation}
114
+ {...a11y}
115
+ >
116
+ {getStackedContent(toggleSwitches, { space, direction: 'column' })}
117
+ </Fieldset>
118
+ )
119
+ }
120
+ )
121
+ ToggleSwitchGroup.displayName = 'ToggleSwitchGroup'
122
+
123
+ ToggleSwitchGroup.propTypes = {
124
+ ...a11yProps.propTypes,
125
+ ...pressProps.propTypes,
126
+ tokens: getTokensPropType('ToggleSwitchGroup'),
127
+ variant: variantProp.propType,
128
+ /**
129
+ * The maximum number of items a user may select at once. Defaults to 1 and behaves
130
+ * like radio buttons. To have no limit and allow any number of selections, pass `null`.
131
+ */
132
+ maxValues: PropTypes.number,
133
+ /**
134
+ * The options a user may select
135
+ */
136
+ items: PropTypes.arrayOf(
137
+ PropTypes.shape({
138
+ /**
139
+ * The text displayed to the user on the label.
140
+ */
141
+ label: PropTypes.string.isRequired,
142
+ /**
143
+ * An optional accessibility label may be passed to each ToggleSwitch
144
+ * and will be applied as normal for a React Native accessibilityLabel prop.
145
+ */
146
+ accessibilityLabel: PropTypes.string,
147
+ /**
148
+ * An optional unique string may be provided to identify this option,
149
+ * which will be used in code and passed to any onChange function.
150
+ * If not provided, the label is used.
151
+ */
152
+ id: PropTypes.string,
153
+ /**
154
+ * An optional ref for one individual ToggleSwitch in the ToggleSwitchGroup
155
+ */
156
+ ref: ABBPropTypes.ref()
157
+ })
158
+ ),
159
+ /**
160
+ * If provided, this function is called when the current selection is changed
161
+ * and is passed an array of the `id`s of all currently selected `items`.
162
+ */
163
+ onChange: PropTypes.func,
164
+ /**
165
+ * If the selected item(s) in the toggle switch group are to be controlled externally by
166
+ * a parent component, pass an array of strings as well as an `onChange` handler.
167
+ * Passing an array for "values" makes the ToggleSwitchGroup a "controlled" component that
168
+ * expects its state to be handled via `onChange` and so doesn't handle it itself.
169
+ */
170
+ values: PropTypes.arrayOf(PropTypes.string),
171
+ /**
172
+ * If `values` is not passed, making the ToggleSwitchGroup an "uncontrolled" component
173
+ * managing its own selected state, a default set of selections may be provided.
174
+ * Changing the `initialValues` does not change the user's selections.
175
+ */
176
+ initialValues: PropTypes.arrayOf(PropTypes.string),
177
+ /**
178
+ * Optional additional text giving more detail to help a user make a choice.
179
+ */
180
+ hint: PropTypes.string,
181
+ /**
182
+ * Optional tooltip text content to include alongside the legend and hint.
183
+ */
184
+ tooltip: PropTypes.string,
185
+ /**
186
+ * If provided, a Feedback element is rendered containing this text.
187
+ */
188
+ feedback: PropTypes.string,
189
+ /**
190
+ * Main text used to describe this group, used in Fieldset's Legend element.
191
+ */
192
+ legend: PropTypes.string,
193
+ /**
194
+ * Toggle switch token overrides.
195
+ */
196
+ toggleSwitchTokens: getTokensPropType('ToggleSwitch'),
197
+ /**
198
+ * Current validation status of the group, passed to the feedback element if there is one.
199
+ */
200
+ validation: PropTypes.oneOf(['error', 'success'])
201
+ }
202
+
203
+ export default ToggleSwitchGroup
@@ -1,3 +1,4 @@
1
1
  import ToggleSwitch from './ToggleSwitch'
2
+ import ToggleSwitchGroup from './ToggleSwitchGroup'
2
3
 
3
- export default ToggleSwitch
4
+ export { ToggleSwitch, ToggleSwitchGroup }
package/src/index.js CHANGED
@@ -17,7 +17,7 @@ export * from './Icon'
17
17
  export { default as IconButton } from './IconButton'
18
18
  export { default as InputLabel } from './InputLabel'
19
19
  export * from './Link'
20
- export { default as List } from './List'
20
+ export { default as List, ListItem, ListBase } from './List'
21
21
  export { default as Modal } from './Modal'
22
22
  export { default as Notification } from './Notification'
23
23
  export { default as Pagination } from './Pagination'
@@ -37,7 +37,7 @@ export { default as StepTracker } from './StepTracker'
37
37
  export { default as Tabs } from './Tabs'
38
38
  export { default as Tags } from './Tags'
39
39
  export * from './TextInput'
40
- export { default as ToggleSwitch } from './ToggleSwitch'
40
+ export * from './ToggleSwitch'
41
41
  export { default as Tooltip } from './Tooltip'
42
42
  export { default as TooltipButton } from './TooltipButton'
43
43
  export { default as Typography } from './Typography'
@@ -0,0 +1,61 @@
1
+ import PropTypes from 'prop-types'
2
+
3
+ import nativePropTypes from './propTypes.native'
4
+
5
+ export default {
6
+ ...nativePropTypes,
7
+ // React Native Web adds many a11y props that alias aria-* attributes
8
+ // Types based on https://necolas.github.io/react-native-web/docs/accessibility/
9
+ accessibilityActiveDescendant: PropTypes.string,
10
+ accessibilityAtomic: PropTypes.bool,
11
+ accessibilityAutoComplete: PropTypes.string,
12
+ accessibilityBusy: PropTypes.bool,
13
+ accessibilityChecked: PropTypes.oneOf([true, false, 'mixed']),
14
+ accessibilityColumnCount: PropTypes.number,
15
+ accessibilityColumnIndex: PropTypes.number,
16
+ accessibilityColumnSpan: PropTypes.number,
17
+ accessibilityControls: PropTypes.oneOfType([
18
+ PropTypes.string,
19
+ PropTypes.arrayOf(PropTypes.string)
20
+ ]),
21
+ accessibilityCurrent: PropTypes.oneOf([true, false, 'page', 'step', 'location', 'date', 'time']),
22
+ accessibilityDescribedBy: PropTypes.oneOfType([
23
+ PropTypes.string,
24
+ PropTypes.arrayOf(PropTypes.string)
25
+ ]),
26
+ accessibilityDetails: PropTypes.string,
27
+ accessibilityDisabled: PropTypes.bool,
28
+ accessibilityErrorMessage: PropTypes.string,
29
+ accessibilityExpanded: PropTypes.bool,
30
+ accessibilityFlowTo: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
31
+ accessibilityHasPopup: PropTypes.string,
32
+ accessibilityHidden: PropTypes.bool,
33
+ accessibilityInvalid: PropTypes.bool,
34
+ accessibilityKeyShortcuts: PropTypes.string,
35
+ accessibilityLabelledBy: PropTypes.oneOfType([
36
+ PropTypes.string,
37
+ PropTypes.arrayOf(PropTypes.string)
38
+ ]),
39
+ accessibilityLevel: PropTypes.number,
40
+ accessibilityModal: PropTypes.bool,
41
+ accessibilityMultiline: PropTypes.bool,
42
+ accessibilityMultiSelectable: PropTypes.bool,
43
+ accessibilityOrientation: PropTypes.oneOf(['horizontal', 'vertical']),
44
+ accessibilityOwns: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
45
+ accessibilityPlaceholder: PropTypes.string,
46
+ accessibilityPosInSet: PropTypes.number,
47
+ accessibilityPressed: PropTypes.bool,
48
+ accessibilityReadOnly: PropTypes.bool,
49
+ accessibilityRequired: PropTypes.bool,
50
+ accessibilityRoleDescription: PropTypes.string,
51
+ accessibilityRowCount: PropTypes.number,
52
+ accessibilityRowIndex: PropTypes.number,
53
+ accessibilityRowSpan: PropTypes.number,
54
+ accessibilitySelected: PropTypes.bool,
55
+ accessibilitySetSize: PropTypes.number,
56
+ accessibilitySort: PropTypes.oneOf(['ascending', 'descending', 'none', 'other']),
57
+ accessibilityValueMax: PropTypes.number,
58
+ accessibilityValueMin: PropTypes.number,
59
+ accessibilityValueNow: PropTypes.number,
60
+ accessibilityValueText: PropTypes.string
61
+ }
@@ -0,0 +1,39 @@
1
+ import PropTypes from 'prop-types'
2
+
3
+ // React Native exports a11y prop definitions as TypeScript Interfaces, but no longer exports PropTypes
4
+ // so we have to define them ourselves.
5
+ export default {
6
+ accessible: PropTypes.bool,
7
+ focusable: PropTypes.bool,
8
+
9
+ accessibilityElementsHidden: PropTypes.bool,
10
+ accessibilityHint: PropTypes.string, // react-native-web ignores `accessibilityHint`
11
+ accessibilityIgnoresInvertColors: PropTypes.bool,
12
+ accessibilityLabel: PropTypes.string,
13
+ accessibilityRole: PropTypes.string,
14
+ accessibilityActions: PropTypes.arrayOf(
15
+ PropTypes.shape({
16
+ name: PropTypes.string.isRequired,
17
+ label: PropTypes.string
18
+ })
19
+ ),
20
+ accessibilityLiveRegion: PropTypes.oneOf(['none', 'polite', 'assertive']),
21
+ accessibilityState: PropTypes.shape({
22
+ disabled: PropTypes.bool,
23
+ selected: PropTypes.bool,
24
+ checked: PropTypes.oneOf([true, false, 'mixed']),
25
+ busy: PropTypes.bool,
26
+ expanded: PropTypes.bool
27
+ }),
28
+ accessibilityValue: PropTypes.shape({
29
+ min: PropTypes.number,
30
+ max: PropTypes.number,
31
+ now: PropTypes.number,
32
+ text: PropTypes.string
33
+ }),
34
+ accessibilityViewIsModal: PropTypes.bool,
35
+ importantForAccessibility: PropTypes.oneOf(['auto', 'yes', 'no', 'no-hide-descendants']),
36
+ onAccessibilityAction: PropTypes.func,
37
+ onAccessibilityEscape: PropTypes.func,
38
+ onAccessibilityTap: PropTypes.func
39
+ }
@@ -12,3 +12,4 @@ export { default as useSpacingScale } from './useSpacingScale'
12
12
  export { default as useResponsiveProp } from './useResponsiveProp'
13
13
  export * from './useResponsiveProp'
14
14
  export { default as useUniqueId } from './useUniqueId'
15
+ export { default as withLinkRouter } from './withLinkRouter'
@@ -1,6 +1,7 @@
1
1
  import PropTypes from 'prop-types'
2
2
  import { Linking, Platform } from 'react-native'
3
3
  import { components as tokenKeys } from '@telus-uds/system-theme-tokens'
4
+ import a11yPropTypes from './a11y/propTypes'
4
5
 
5
6
  export const paddingProp = {
6
7
  propType: PropTypes.shape({
@@ -202,116 +203,6 @@ function getPropSelector(propTypes, regexp) {
202
203
  )
203
204
  }
204
205
 
205
- // React Native exports a11y prop definitions as TypeScript Interfaces, but no longer exports PropTypes
206
- // so we have to define them ourselves.
207
- const a11yPropTypes = {
208
- accessible: PropTypes.bool,
209
- focusable: PropTypes.bool,
210
-
211
- accessibilityElementsHidden: PropTypes.bool,
212
- accessibilityHint: PropTypes.string, // react-native-web ignores `accessibilityHint`
213
- accessibilityIgnoresInvertColors: PropTypes.bool,
214
- accessibilityLabel: PropTypes.string,
215
- accessibilityRole: PropTypes.string,
216
- accessibilityActions: PropTypes.arrayOf(
217
- PropTypes.shape({
218
- name: PropTypes.string.isRequired,
219
- label: PropTypes.string
220
- })
221
- ),
222
- accessibilityLiveRegion: PropTypes.oneOf(['none', 'polite', 'assertive']),
223
- accessibilityState: PropTypes.shape({
224
- disabled: PropTypes.bool,
225
- selected: PropTypes.bool,
226
- checked: PropTypes.oneOf([true, false, 'mixed']),
227
- busy: PropTypes.bool,
228
- expanded: PropTypes.bool
229
- }),
230
- accessibilityValue: PropTypes.shape({
231
- min: PropTypes.number,
232
- max: PropTypes.number,
233
- now: PropTypes.number,
234
- text: PropTypes.string
235
- }),
236
- accessibilityViewIsModal: PropTypes.bool,
237
- importantForAccessibility: PropTypes.oneOf(['auto', 'yes', 'no', 'no-hide-descendants']),
238
- onAccessibilityAction: PropTypes.func,
239
- onAccessibilityEscape: PropTypes.func,
240
- onAccessibilityTap: PropTypes.func,
241
- ...Platform.select({
242
- web: {
243
- // React Native Web adds many a11y props that alias aria-* attributes
244
- // Types based on https://necolas.github.io/react-native-web/docs/accessibility/
245
- accessibilityActiveDescendant: PropTypes.string,
246
- accessibilityAtomic: PropTypes.bool,
247
- accessibilityAutoComplete: PropTypes.string,
248
- accessibilityBusy: PropTypes.bool,
249
- accessibilityChecked: PropTypes.oneOf([true, false, 'mixed']),
250
- accessibilityColumnCount: PropTypes.number,
251
- accessibilityColumnIndex: PropTypes.number,
252
- accessibilityColumnSpan: PropTypes.number,
253
- accessibilityControls: PropTypes.oneOfType([
254
- PropTypes.string,
255
- PropTypes.arrayOf(PropTypes.string)
256
- ]),
257
- accessibilityCurrent: PropTypes.oneOf([
258
- true,
259
- false,
260
- 'page',
261
- 'step',
262
- 'location',
263
- 'date',
264
- 'time'
265
- ]),
266
- accessibilityDescribedBy: PropTypes.oneOfType([
267
- PropTypes.string,
268
- PropTypes.arrayOf(PropTypes.string)
269
- ]),
270
- accessibilityDetails: PropTypes.string,
271
- accessibilityDisabled: PropTypes.bool,
272
- accessibilityErrorMessage: PropTypes.string,
273
- accessibilityExpanded: PropTypes.bool,
274
- accessibilityFlowTo: PropTypes.oneOfType([
275
- PropTypes.string,
276
- PropTypes.arrayOf(PropTypes.string)
277
- ]),
278
- accessibilityHasPopup: PropTypes.string,
279
- accessibilityHidden: PropTypes.bool,
280
- accessibilityInvalid: PropTypes.bool,
281
- accessibilityKeyShortcuts: PropTypes.string,
282
- accessibilityLabelledBy: PropTypes.oneOfType([
283
- PropTypes.string,
284
- PropTypes.arrayOf(PropTypes.string)
285
- ]),
286
- accessibilityLevel: PropTypes.number,
287
- accessibilityModal: PropTypes.bool,
288
- accessibilityMultiline: PropTypes.bool,
289
- accessibilityMultiSelectable: PropTypes.bool,
290
- accessibilityOrientation: PropTypes.oneOf(['horizontal', 'vertical']),
291
- accessibilityOwns: PropTypes.oneOfType([
292
- PropTypes.string,
293
- PropTypes.arrayOf(PropTypes.string)
294
- ]),
295
- accessibilityPlaceholder: PropTypes.string,
296
- accessibilityPosInSet: PropTypes.number,
297
- accessibilityPressed: PropTypes.bool,
298
- accessibilityReadOnly: PropTypes.bool,
299
- accessibilityRequired: PropTypes.bool,
300
- accessibilityRoleDescription: PropTypes.string,
301
- accessibilityRowCount: PropTypes.number,
302
- accessibilityRowIndex: PropTypes.number,
303
- accessibilityRowSpan: PropTypes.number,
304
- accessibilitySelected: PropTypes.bool,
305
- accessibilitySetSize: PropTypes.number,
306
- accessibilitySort: PropTypes.oneOf(['ascending', 'descending', 'none', 'other']),
307
- accessibilityValueMax: PropTypes.number,
308
- accessibilityValueMin: PropTypes.number,
309
- accessibilityValueNow: PropTypes.number,
310
- accessibilityValueText: PropTypes.string
311
- }
312
- })
313
- }
314
-
315
206
  export const a11yProps = {
316
207
  /**
317
208
  * Proptypes for recognised React Native accessiblity (a11y) props.
@@ -429,6 +320,36 @@ export const pressProps = {
429
320
  selectHandlers: getPropSelector(pressHandlerPropTypes)
430
321
  }
431
322
 
323
+ const clickHandlerMapping = {
324
+ onClick: 'onPress',
325
+ mouseDown: 'onPressIn',
326
+ mouseUp: 'onPressOut'
327
+ }
328
+
329
+ export const clickProps = {
330
+ /**
331
+ * Web-oriented HTML click handlers that may be mapped to React Native press handlers
332
+ */
333
+ types: Object.fromEntries(
334
+ Object.keys(clickHandlerMapping).map((mouseName) => [mouseName, PropTypes.func])
335
+ ),
336
+ /**
337
+ * Takes a set of props and converts HTML mouse click oriented event handlers to closest
338
+ * equivalent React Native press event handler.
339
+ *
340
+ * Use this when a component that expects press-oriented props may need to support third-party
341
+ * web-oriented tooling that injects web-oriented event handlers directly. For example, for
342
+ * to support use with NextJS's 'next/link' component, which injects `onClick` prop into its child.
343
+ */
344
+ toPressProps: (props) =>
345
+ Object.fromEntries(
346
+ Object.entries(props).map(([originalName, value]) => {
347
+ const translatedName = clickHandlerMapping[originalName]
348
+ return translatedName ? [translatedName, value] : [originalName, value]
349
+ })
350
+ )
351
+ }
352
+
432
353
  const linkPropTypes = {
433
354
  ...pressPropTypes,
434
355
  href: PropTypes.string,
@@ -470,7 +391,8 @@ const viewPropTypes = {
470
391
  pointerEvents: PropTypes.oneOf(['all', 'none', 'box-only', 'box-none']),
471
392
  onLayout: PropTypes.func,
472
393
  nativeID: PropTypes.string,
473
- testID: PropTypes.string
394
+ testID: PropTypes.string,
395
+ dataSet: PropTypes.object
474
396
  }
475
397
 
476
398
  export const viewProps = {
@@ -0,0 +1,68 @@
1
+ import React, { forwardRef } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ // Prototype-safe alternative to (linter-forbidden) someObject.hasOwnProperty()
5
+ const hasOwnProperty = (object, prop) => Object.prototype.hasOwnProperty.call(object, prop)
6
+
7
+ /**
8
+ * Higher-order component that has no effect unless an additional prop `LinkRouter` is passed.
9
+ * This may be used to provide custom wrappers for integrations with third party libraries.
10
+ *
11
+ * If LinkRouter is passed, LinkRouter is rendered in place of the main component and is passed:
12
+ *
13
+ * - `linkRouterProps`: an optional object passed alongside LinkRouter, for props needed by the wrapper
14
+ * that are not valid props for the wrapped component.
15
+ * - `Component`: automatically provided, the original component to render inside the wrapper.
16
+ * - `ref`: forwarded `ref` passed down to `Component`
17
+ * - All other props passed to the outer component
18
+ *
19
+ * @example A LinkRouter component to be used with link-like components might look like:
20
+ *
21
+ * ```jsx
22
+ * const LinkLinkRouter = forwardRef(({ Component, linkRouterProps: { to, options }, href, ...rest }, ref) => {
23
+ * const { href: resolvedHref, onClick } = useSomeRouterHook({ to, href, options })
24
+ * return <Component href={resolvedHref} onPress={onClick} {...rest} />
25
+ * })
26
+ * ```
27
+ *
28
+ * Any component that takes href and onPress props may then use this wrapper:
29
+ *
30
+ * ```jsx
31
+ * <Link href={href} LinkRouter={LinkLinkRouter} linkRouterProps={{ to, options }}>Some link</Link>
32
+ * <IconButton icon={SomeIcon} LinkRouter={LinkLinkRouter} linkRouterProps={{ to, options }} ref={iconRef} />
33
+ * ```
34
+ */
35
+ const withLinkRouter = (Component) => {
36
+ const wrappedComponent = forwardRef(({ LinkRouter, linkRouterProps, ...props }, ref) => {
37
+ if (!LinkRouter) return <Component {...props} ref={ref} />
38
+ return (
39
+ <LinkRouter linkRouterProps={linkRouterProps} Component={Component} ref={ref} {...props} />
40
+ )
41
+ })
42
+
43
+ // Ensure the returned component has appropriate outer properties set:
44
+ /* eslint-disable-next-line react/forbid-foreign-prop-types */
45
+ const { displayName, name, propTypes, ...otherProperties } = Component
46
+
47
+ // Apply unique component name as a displayName
48
+ wrappedComponent.displayName = Component.displayName || Component.name
49
+
50
+ // Apply proptypes including wrapper props - is safely { ...undefined, ...undefined } in prod
51
+ wrappedComponent.propTypes = { ...Component.propTypes, ...withLinkRouter.propTypes }
52
+
53
+ // Forward any other properties explicitly set e.g. Component.SubComponent
54
+ Object.keys(otherProperties).forEach((key) => {
55
+ // Skip internal React properties from wrappedComponent's forwardRef (render, $$typeof, etc)
56
+ if (hasOwnProperty(Component, key) && !hasOwnProperty(wrappedComponent, key)) {
57
+ wrappedComponent[key] = Component[key]
58
+ }
59
+ })
60
+ return wrappedComponent
61
+ }
62
+
63
+ withLinkRouter.propTypes = {
64
+ LinkRouter: PropTypes.elementType,
65
+ linkRouterProps: PropTypes.object
66
+ }
67
+
68
+ export default withLinkRouter
@@ -12,7 +12,7 @@ const defaultArgs = {
12
12
  }
13
13
 
14
14
  export default {
15
- title: 'Base/A11yText',
15
+ title: 'A11yText',
16
16
  component: A11yText,
17
17
  parameters: defaultArgs
18
18
  }
@@ -4,7 +4,7 @@ import { ActivityIndicator } from '../../src'
4
4
  import { EachParentType, parentTypesParams } from '../supports'
5
5
 
6
6
  export default {
7
- title: 'Base/ActivityIndicator',
7
+ title: 'ActivityIndicator',
8
8
  component: ActivityIndicator,
9
9
  args: {
10
10
  label: 'loading...'
@@ -12,7 +12,7 @@ import {
12
12
  } from '../supports'
13
13
 
14
14
  export default {
15
- title: 'Base/Box',
15
+ title: 'Box',
16
16
  component: Box
17
17
  }
18
18
 
@@ -10,7 +10,7 @@ Default.storyName = 'Button'
10
10
  const defaultLabel = "I'm a button"
11
11
 
12
12
  export default {
13
- title: 'Base/Button',
13
+ title: 'Button',
14
14
  component: Button,
15
15
  args: {
16
16
  // eslint-disable-next-line no-console
@@ -22,7 +22,7 @@ const defaultControlledArgs = {
22
22
  }
23
23
 
24
24
  export default {
25
- title: 'Base/ButtonGroup',
25
+ title: 'ButtonGroup',
26
26
  component: ButtonGroup,
27
27
  args: {
28
28
  ...defaultArgs
@@ -3,7 +3,7 @@ import { ButtonLink } from '../../src'
3
3
  import { Container, useVariants } from '../supports'
4
4
 
5
5
  export default {
6
- title: 'Base/ButtonLink',
6
+ title: 'ButtonLink',
7
7
  component: ButtonLink,
8
8
  args: {
9
9
  children: "I'm a button link",
@@ -6,7 +6,7 @@ import { Card } from '../../src'
6
6
  import { Container, useVariants, EachParentType, parentTypesParams } from '../supports'
7
7
 
8
8
  export default {
9
- title: 'Base/Card',
9
+ title: 'Card',
10
10
  component: Card
11
11
  }
12
12
 
@@ -5,7 +5,7 @@ import { Checkbox, CheckboxGroup, Typography } from '../../src'
5
5
  import { Container, EachParentType, parentTypesParams } from '../supports'
6
6
 
7
7
  export default {
8
- title: 'Base/Checkbox',
8
+ title: 'Checkbox',
9
9
  component: Checkbox,
10
10
  argTypes: {
11
11
  checked: {
@@ -5,7 +5,7 @@ import { Divider, Typography } from '../../src'
5
5
  import { EachParentType, parentTypesParams } from '../supports'
6
6
 
7
7
  export default {
8
- title: 'Base/Divider',
8
+ title: 'Divider',
9
9
  component: Divider
10
10
  }
11
11
 
@@ -6,7 +6,7 @@ import { Container, EachParentType, parentTypesParams } from '../supports'
6
6
  import { useMultipleInputValues } from '../../src/utils'
7
7
 
8
8
  export default {
9
- title: 'Base/ExpandCollapse',
9
+ title: 'ExpandCollapse',
10
10
  component: ExpandCollapse,
11
11
  args: {
12
12
  children: () => {}