@telus-uds/components-base 1.14.2 → 1.16.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 (161) hide show
  1. package/CHANGELOG.md +40 -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 +120 -85
  70. package/lib/A11yInfoProvider/index.js +14 -5
  71. package/lib/Button/ButtonGroup.js +3 -2
  72. package/lib/Carousel/Carousel.js +18 -2
  73. package/lib/Carousel/CarouselTabs/CarouselTabs.js +6 -7
  74. package/lib/Checkbox/Checkbox.js +9 -6
  75. package/lib/ExpandCollapse/Control.js +6 -5
  76. package/lib/ExpandCollapse/Panel.js +5 -4
  77. package/lib/List/ListItem.js +10 -236
  78. package/lib/List/ListItemBase.js +162 -0
  79. package/lib/List/ListItemContent.js +85 -0
  80. package/lib/List/ListItemMark.js +158 -0
  81. package/lib/List/PressableListItemBase.js +147 -0
  82. package/lib/Notification/Notification.js +2 -1
  83. package/lib/Pagination/Pagination.js +4 -3
  84. package/lib/Radio/Radio.js +9 -6
  85. package/lib/RadioCard/RadioCard.js +9 -6
  86. package/lib/Select/Select.js +1 -0
  87. package/lib/Skeleton/Skeleton.js +18 -13
  88. package/lib/Skeleton/useSkeletonNativeAnimation.js +4 -2
  89. package/lib/Tabs/Tabs.js +12 -3
  90. package/lib/Tags/Tags.js +3 -3
  91. package/lib/TextInput/TextInput.js +5 -4
  92. package/lib/ToggleSwitch/ToggleSwitch.js +24 -19
  93. package/lib/ViewportProvider/useViewportListener.js +11 -5
  94. package/lib/utils/hasOwnProperty.js +18 -0
  95. package/lib/utils/props/a11yProps.js +171 -1
  96. package/lib/utils/props/getPropSelector.js +47 -5
  97. package/lib/utils/ssr.js +116 -1
  98. package/lib/utils/useResponsiveProp.js +5 -3
  99. package/lib/utils/withLinkRouter.js +3 -5
  100. package/lib-module/A11yInfoProvider/index.js +14 -4
  101. package/lib-module/Button/ButtonGroup.js +3 -2
  102. package/lib-module/Carousel/Carousel.js +16 -2
  103. package/lib-module/Carousel/CarouselTabs/CarouselTabs.js +7 -6
  104. package/lib-module/Checkbox/Checkbox.js +9 -6
  105. package/lib-module/ExpandCollapse/Control.js +6 -5
  106. package/lib-module/ExpandCollapse/Panel.js +5 -4
  107. package/lib-module/List/ListItem.js +13 -235
  108. package/lib-module/List/ListItemBase.js +139 -0
  109. package/lib-module/List/ListItemContent.js +66 -0
  110. package/lib-module/List/ListItemMark.js +143 -0
  111. package/lib-module/List/PressableListItemBase.js +117 -0
  112. package/lib-module/Notification/Notification.js +2 -1
  113. package/lib-module/Pagination/Pagination.js +5 -3
  114. package/lib-module/Radio/Radio.js +9 -6
  115. package/lib-module/RadioCard/RadioCard.js +9 -6
  116. package/lib-module/Select/Select.js +1 -0
  117. package/lib-module/Skeleton/Skeleton.js +15 -13
  118. package/lib-module/Skeleton/useSkeletonNativeAnimation.js +3 -2
  119. package/lib-module/Tabs/Tabs.js +13 -4
  120. package/lib-module/Tags/Tags.js +3 -3
  121. package/lib-module/TextInput/TextInput.js +5 -4
  122. package/lib-module/ToggleSwitch/ToggleSwitch.js +24 -19
  123. package/lib-module/ViewportProvider/useViewportListener.js +10 -4
  124. package/lib-module/utils/hasOwnProperty.js +11 -0
  125. package/lib-module/utils/props/a11yProps.js +169 -1
  126. package/lib-module/utils/props/getPropSelector.js +44 -5
  127. package/lib-module/utils/ssr.js +106 -0
  128. package/lib-module/utils/useResponsiveProp.js +3 -4
  129. package/lib-module/utils/withLinkRouter.js +3 -5
  130. package/package.json +12 -17
  131. package/src/A11yInfoProvider/index.jsx +20 -4
  132. package/src/Button/ButtonGroup.jsx +4 -2
  133. package/src/Carousel/Carousel.jsx +15 -2
  134. package/src/Carousel/CarouselTabs/CarouselTabs.jsx +5 -3
  135. package/src/Checkbox/Checkbox.jsx +7 -3
  136. package/src/ExpandCollapse/Control.jsx +8 -5
  137. package/src/ExpandCollapse/Panel.jsx +7 -5
  138. package/src/List/ListItem.jsx +12 -191
  139. package/src/List/ListItemBase.jsx +118 -0
  140. package/src/List/ListItemContent.jsx +52 -0
  141. package/src/List/ListItemMark.jsx +99 -0
  142. package/src/List/PressableListItemBase.jsx +102 -0
  143. package/src/Notification/Notification.jsx +1 -1
  144. package/src/Pagination/Pagination.jsx +6 -1
  145. package/src/Radio/Radio.jsx +7 -3
  146. package/src/RadioCard/RadioCard.jsx +7 -3
  147. package/src/Select/Select.jsx +1 -1
  148. package/src/Skeleton/Skeleton.jsx +25 -19
  149. package/src/Skeleton/useSkeletonNativeAnimation.js +3 -3
  150. package/src/Tabs/Tabs.jsx +19 -2
  151. package/src/Tags/Tags.jsx +3 -3
  152. package/src/TextInput/TextInput.jsx +4 -4
  153. package/src/ToggleSwitch/ToggleSwitch.jsx +3 -3
  154. package/src/ViewportProvider/useViewportListener.js +10 -5
  155. package/src/utils/hasOwnProperty.js +11 -0
  156. package/src/utils/props/a11yProps.js +107 -1
  157. package/src/utils/props/getPropSelector.js +45 -4
  158. package/src/utils/ssr.jsx +124 -0
  159. package/src/utils/useResponsiveProp.js +3 -3
  160. package/src/utils/withLinkRouter.jsx +1 -3
  161. package/src/utils/ssr.js +0 -35
@@ -0,0 +1,273 @@
1
+ import React from 'react'
2
+ import { renderHook } from '@testing-library/react-hooks'
3
+ import { useSpacingScale } from '../../src/utils'
4
+ import Theme from '../../__fixtures__/Theme'
5
+ import Viewport from '../../__fixtures__/Viewport'
6
+
7
+ describe('useSpacingScale', () => {
8
+ // values from testTheme.js
9
+ const expectedDefaultScale = [0, 4, 8, 16, 24, 32, 36]
10
+ const expectedCompactScale = [0, 2, 4, 6, 8, 10, 12]
11
+ const expectedResponsiveScale = {
12
+ xs: [0, 1, 2, 3, 4, 5, 6],
13
+ sm: [0, 3, 4, 5, 6, 7, 8],
14
+ md: [0, 3, 4, 5, 6, 7, 8],
15
+ lg: [0, 7, 8, 9, 10, 11, 12],
16
+ xl: [0, 7, 8, 9, 10, 11, 12]
17
+ }
18
+
19
+ const wrapper = ({ children, viewport }) => (
20
+ <Viewport viewport={viewport}>
21
+ <Theme>{children}</Theme>
22
+ </Viewport>
23
+ )
24
+
25
+ it.each(expectedDefaultScale.map((item, index) => [item, index]))(
26
+ 'returns the expected size index %# from the theme spacing scale',
27
+ (expectedSize, index) => {
28
+ const { result } = renderHook(() => useSpacingScale(index), {
29
+ wrapper
30
+ })
31
+ expect(result.current).toBe(expectedSize)
32
+ }
33
+ )
34
+ it.each(expectedCompactScale.map((item, index) => [item, index]))(
35
+ 'returns the expected size index %# from the theme spacing scale in a variant',
36
+ (expectedSize, index) => {
37
+ const { result } = renderHook(
38
+ () => useSpacingScale({ space: index, options: { variant: { compact: true } } }),
39
+ {
40
+ wrapper
41
+ }
42
+ )
43
+ expect(result.current).toBe(expectedSize)
44
+ }
45
+ )
46
+ it.each(Object.entries(expectedResponsiveScale))(
47
+ 'returns appropriate sizes from a responsive theme variant at %p viewport',
48
+ (viewport, expectedValues) => {
49
+ const { result, rerender } = renderHook(({ spacingValue }) => useSpacingScale(spacingValue), {
50
+ wrapper
51
+ })
52
+ expectedValues.forEach((expectedSize, index) => {
53
+ rerender({
54
+ viewport,
55
+ spacingValue: { space: index, options: { variant: { responsive: true } } }
56
+ })
57
+ expect(result.current).toBe(expectedSize)
58
+ })
59
+ }
60
+ )
61
+
62
+ it('returns the 0 index when passed a nullish spacing value', () => {
63
+ const { result, rerender } = renderHook((spacingValue) => useSpacingScale(spacingValue), {
64
+ wrapper
65
+ })
66
+ // implicit undefined
67
+ expect(result.current).toBe(expectedDefaultScale[0])
68
+ // explicit undefined
69
+ rerender(undefined)
70
+ expect(result.current).toBe(expectedDefaultScale[0])
71
+ rerender(null)
72
+ expect(result.current).toBe(expectedDefaultScale[0])
73
+
74
+ // confim this test isn't a false positive misuing rerender etc
75
+ rerender(1)
76
+ expect(result.current).toBe(expectedDefaultScale[1])
77
+ })
78
+ it('returns the 0 index when passed a nullish spacing value in a variant', () => {
79
+ const { result, rerender } = renderHook((spacingValue) => useSpacingScale(spacingValue), {
80
+ wrapper,
81
+ initialProps: { options: { variant: { compact: true } } }
82
+ })
83
+ // implicit undefined
84
+ expect(result.current).toBe(expectedCompactScale[0])
85
+ // explicit undefined
86
+ rerender({ space: undefined, options: { variant: { compact: true } } })
87
+ expect(result.current).toBe(expectedCompactScale[0])
88
+ rerender({ space: null, options: { variant: { compact: true } } })
89
+ expect(result.current).toBe(expectedCompactScale[0])
90
+
91
+ // confim this test isn't a false positive misuing rerender etc
92
+ rerender({ space: 1, options: { variant: { compact: true } } })
93
+ expect(result.current).toBe(expectedCompactScale[1])
94
+ })
95
+
96
+ it('returns the highest index when passed an out-of-bounds spacing index', () => {
97
+ const { result } = renderHook(() => useSpacingScale(99), {
98
+ wrapper
99
+ })
100
+ expect(result.current).toBe(expectedDefaultScale[expectedDefaultScale.length - 1])
101
+ })
102
+ it('returns the highest index when passed an out-of-bounds spacing index in a variant', () => {
103
+ const { result } = renderHook(
104
+ () => useSpacingScale({ space: 99, options: { variant: { compact: true } } }),
105
+ {
106
+ wrapper
107
+ }
108
+ )
109
+ expect(result.current).toBe(expectedCompactScale[expectedDefaultScale.length - 1])
110
+ })
111
+
112
+ it('returns viewport indexes that explicitly match current viewport', () => {
113
+ const spacingValue = { xs: 1, sm: 2, md: 3, lg: 4, xl: 5 }
114
+ const { rerender, result } = renderHook((args) => useSpacingScale(args.spacingValue), {
115
+ wrapper,
116
+ initialProps: { viewport: 'xs', spacingValue }
117
+ })
118
+ expect(result.current).toBe(expectedDefaultScale[1])
119
+ rerender({ viewport: 'sm', spacingValue })
120
+ expect(result.current).toBe(expectedDefaultScale[2])
121
+ rerender({ viewport: 'md', spacingValue })
122
+ expect(result.current).toBe(expectedDefaultScale[3])
123
+ rerender({ viewport: 'lg', spacingValue })
124
+ expect(result.current).toBe(expectedDefaultScale[4])
125
+ rerender({ viewport: 'xl', spacingValue })
126
+ expect(result.current).toBe(expectedDefaultScale[5])
127
+ })
128
+ it('returns viewport indexes that explicitly match current viewport in a variant', () => {
129
+ const spacingValue = {
130
+ xs: 1,
131
+ sm: 2,
132
+ md: 3,
133
+ lg: 4,
134
+ xl: 5,
135
+ options: { variant: { compact: true } }
136
+ }
137
+ const { rerender, result } = renderHook((args) => useSpacingScale(args.spacingValue), {
138
+ wrapper,
139
+ initialProps: { viewport: 'xs', spacingValue }
140
+ })
141
+ expect(result.current).toBe(expectedCompactScale[1])
142
+ rerender({ viewport: 'sm', spacingValue })
143
+ expect(result.current).toBe(expectedCompactScale[2])
144
+ rerender({ viewport: 'md', spacingValue })
145
+ expect(result.current).toBe(expectedCompactScale[3])
146
+ rerender({ viewport: 'lg', spacingValue })
147
+ expect(result.current).toBe(expectedCompactScale[4])
148
+ rerender({ viewport: 'xl', spacingValue })
149
+ expect(result.current).toBe(expectedCompactScale[5])
150
+ })
151
+
152
+ it('returns viewport indexes that implicitly match current viewport', () => {
153
+ const spacingValue = { xs: 1, md: 3 }
154
+ const { rerender, result } = renderHook((args) => useSpacingScale(args.spacingValue), {
155
+ wrapper,
156
+ initialProps: { viewport: 'xs', spacingValue }
157
+ })
158
+ expect(result.current).toBe(expectedDefaultScale[1])
159
+ rerender({ viewport: 'sm', spacingValue })
160
+ expect(result.current).toBe(expectedDefaultScale[1])
161
+ rerender({ viewport: 'md', spacingValue })
162
+ expect(result.current).toBe(expectedDefaultScale[3])
163
+ rerender({ viewport: 'lg', spacingValue })
164
+ expect(result.current).toBe(expectedDefaultScale[3])
165
+ rerender({ viewport: 'xl', spacingValue })
166
+ expect(result.current).toBe(expectedDefaultScale[3])
167
+ })
168
+ it('returns viewport indexes that implicitly match current viewport in a variant', () => {
169
+ const spacingValue = { xs: 1, md: 3, options: { variant: { compact: true } } }
170
+ const { rerender, result } = renderHook((args) => useSpacingScale(args.spacingValue), {
171
+ wrapper,
172
+ initialProps: { viewport: 'xs', spacingValue }
173
+ })
174
+ expect(result.current).toBe(expectedCompactScale[1])
175
+ rerender({ viewport: 'sm', spacingValue })
176
+ expect(result.current).toBe(expectedCompactScale[1])
177
+ rerender({ viewport: 'md', spacingValue })
178
+ expect(result.current).toBe(expectedCompactScale[3])
179
+ rerender({ viewport: 'lg', spacingValue })
180
+ expect(result.current).toBe(expectedCompactScale[3])
181
+ rerender({ viewport: 'xl', spacingValue })
182
+ expect(result.current).toBe(expectedCompactScale[3])
183
+ })
184
+
185
+ it('chooses smallest provided viewport index if viewport is unavailable', () => {
186
+ const spacingValue = { xs: 1, sm: 2, md: 3, lg: 4, xl: 5 }
187
+ const { result } = renderHook((args) => useSpacingScale(args.spacingValue), {
188
+ wrapper,
189
+ initialProps: { viewport: null, spacingValue }
190
+ })
191
+ expect(result.current).toBe(expectedDefaultScale[1])
192
+ })
193
+ it('chooses 0 index if current viewport matches no provided index', () => {
194
+ const spacingValue = { lg: 4 }
195
+ const { result, rerender } = renderHook((args) => useSpacingScale(args.spacingValue), {
196
+ wrapper,
197
+ initialProps: { viewport: 'xs', spacingValue }
198
+ })
199
+ expect(result.current).toBe(expectedDefaultScale[0])
200
+ rerender({ viewport: 'sm', spacingValue })
201
+ expect(result.current).toBe(expectedDefaultScale[0])
202
+ rerender({ viewport: 'md', spacingValue })
203
+ expect(result.current).toBe(expectedDefaultScale[0])
204
+ rerender({ viewport: 'lg', spacingValue })
205
+ expect(result.current).toBe(expectedDefaultScale[4])
206
+ rerender({ viewport: 'xl', spacingValue })
207
+ expect(result.current).toBe(expectedDefaultScale[4])
208
+ })
209
+
210
+ it('subtracts a provided value from a spacing scale value', () => {
211
+ const spacingValue = { viewport: 'xs', space: 2, options: { subtract: 3 } }
212
+ const { result } = renderHook(() => useSpacingScale(spacingValue), {
213
+ wrapper
214
+ })
215
+ expect(result.current).toBe(expectedDefaultScale[2] - 3)
216
+ })
217
+ it('subtracts a provided value from a spacing scale value in a variant', () => {
218
+ const spacingValue = {
219
+ space: 4,
220
+ options: { subtract: 3, variant: { compact: true } }
221
+ }
222
+ const { result } = renderHook(() => useSpacingScale(spacingValue), {
223
+ wrapper
224
+ })
225
+ expect(result.current).toBe(expectedCompactScale[4] - 3)
226
+ })
227
+ it('returns 0 if a subtraction would result in a negative number', () => {
228
+ const spacingValue = { space: 2, options: { subtract: 999 } }
229
+ const { result } = renderHook((args) => useSpacingScale(args.spacingValue), {
230
+ wrapper,
231
+ initialProps: { spacingValue }
232
+ })
233
+ expect(result.current).toBe(0)
234
+ })
235
+
236
+ it('gives an exact amount if `size` option is passed', () => {
237
+ const size = 123456
238
+ const spacingValue = { xs: 1, sm: 2, md: 3, lg: 4, xl: 5, options: { size } }
239
+ const compactSpacingValue = { ...spacingValue, options: { size, variant: { compact: true } } }
240
+ const { result, rerender } = renderHook((args) => useSpacingScale(args.spacingValue), {
241
+ wrapper,
242
+ initialProps: { viewport: 'xs', spacingValue }
243
+ })
244
+ expect(result.current).toBe(size)
245
+ rerender({ viewport: 'sm', spacingValue })
246
+ expect(result.current).toBe(size)
247
+ rerender({ viewport: 'md', spacingValue })
248
+ expect(result.current).toBe(size)
249
+ rerender({ viewport: 'lg', spacingValue })
250
+ expect(result.current).toBe(size)
251
+ rerender({ viewport: 'xl', spacingValue })
252
+ expect(result.current).toBe(size)
253
+ rerender({ viewport: 'xs', spacingValue: compactSpacingValue })
254
+ expect(result.current).toBe(size)
255
+ rerender({ viewport: 'sm', spacingValue: compactSpacingValue })
256
+ expect(result.current).toBe(size)
257
+ rerender({ viewport: 'md', spacingValue: compactSpacingValue })
258
+ expect(result.current).toBe(size)
259
+ rerender({ viewport: 'lg', spacingValue: compactSpacingValue })
260
+ expect(result.current).toBe(size)
261
+ rerender({ viewport: 'xl', spacingValue: compactSpacingValue })
262
+ expect(result.current).toBe(size)
263
+ })
264
+ it('subtracts from size if `subtract` and `size` options are provided', () => {
265
+ const size = 123456
266
+ const subtract = 12345
267
+ const spacingValue = { options: { size, subtract } }
268
+ const { result } = renderHook(() => useSpacingScale(spacingValue), {
269
+ wrapper
270
+ })
271
+ expect(result.current).toBe(size - subtract)
272
+ })
273
+ })
@@ -0,0 +1,31 @@
1
+ import { renderHook } from '@testing-library/react-hooks'
2
+ import useUniqueId from '../../lib/utils/useUniqueId'
3
+
4
+ describe('useUniqueId hook', () => {
5
+ it('returns the same id for each re-render, but a different id for a new instance', () => {
6
+ const { result, rerender } = renderHook(() => useUniqueId('prefix'))
7
+
8
+ expect(result.current).toBe('prefix-1')
9
+
10
+ rerender()
11
+
12
+ expect(result.current).toBe('prefix-1')
13
+
14
+ // has to be done within the same test case, as we can't ensure order in which tests are being run in parallel
15
+ const { result: result2, rerender: rerender2 } = renderHook(() => useUniqueId('prefix'))
16
+
17
+ expect(result.current).toBe('prefix-1')
18
+ expect(result2.current).toBe('prefix-2')
19
+
20
+ // ensure that instances' rerendering doesn't affect one another
21
+ rerender2()
22
+
23
+ expect(result.current).toBe('prefix-1')
24
+ expect(result2.current).toBe('prefix-2')
25
+
26
+ rerender()
27
+
28
+ expect(result.current).toBe('prefix-1')
29
+ expect(result2.current).toBe('prefix-2')
30
+ })
31
+ })
@@ -89,6 +89,7 @@
89
89
  "previousIcon": "icon",
90
90
  "showPreviousNextNavigation": "show",
91
91
  "showPanelNavigation": "show",
92
+ "showPanelTabs": "show",
92
93
  "spaceBetweenSlideAndPreviousNextNavigation": "size",
93
94
  "spaceBetweenSlideAndPanelNavigation": "size",
94
95
  "thumbnailBorderColor": "color",
@@ -4646,12 +4647,26 @@
4646
4647
  "docs": {
4647
4648
  "description": "ListItem is responsible for rendering icon or a bullet as side item",
4648
4649
  "props": {
4649
- "accessibilityRole": {
4650
- "defaultValue": {
4651
- "value": "Platform.select({ web: 'listitem', default: undefined })",
4652
- "computed": true
4650
+ "variant": {
4651
+ "type": {
4652
+ "name": "objectOf",
4653
+ "value": {
4654
+ "name": "union",
4655
+ "value": [
4656
+ {
4657
+ "name": "string"
4658
+ },
4659
+ {
4660
+ "name": "number"
4661
+ },
4662
+ {
4663
+ "name": "bool"
4664
+ }
4665
+ ]
4666
+ }
4653
4667
  },
4654
- "required": false
4668
+ "required": false,
4669
+ "description": ""
4655
4670
  },
4656
4671
  "tokens": {
4657
4672
  "type": {
@@ -4679,30 +4694,17 @@
4679
4694
  "required": false,
4680
4695
  "description": ""
4681
4696
  },
4682
- "variant": {
4683
- "type": {
4684
- "name": "objectOf",
4685
- "value": {
4686
- "name": "union",
4687
- "value": [
4688
- {
4689
- "name": "string"
4690
- },
4691
- {
4692
- "name": "number"
4693
- },
4694
- {
4695
- "name": "bool"
4696
- }
4697
- ]
4698
- }
4699
- },
4700
- "required": false,
4701
- "description": ""
4702
- },
4703
4697
  "children": {
4704
4698
  "type": {
4705
- "name": "node"
4699
+ "name": "union",
4700
+ "value": [
4701
+ {
4702
+ "name": "node"
4703
+ },
4704
+ {
4705
+ "name": "func"
4706
+ }
4707
+ ]
4706
4708
  },
4707
4709
  "required": true,
4708
4710
  "description": ""
@@ -4817,12 +4819,26 @@
4817
4819
  "docs": {
4818
4820
  "description": "ListItem is responsible for rendering icon or a bullet as side item",
4819
4821
  "props": {
4820
- "accessibilityRole": {
4821
- "defaultValue": {
4822
- "value": "Platform.select({ web: 'listitem', default: undefined })",
4823
- "computed": true
4822
+ "variant": {
4823
+ "type": {
4824
+ "name": "objectOf",
4825
+ "value": {
4826
+ "name": "union",
4827
+ "value": [
4828
+ {
4829
+ "name": "string"
4830
+ },
4831
+ {
4832
+ "name": "number"
4833
+ },
4834
+ {
4835
+ "name": "bool"
4836
+ }
4837
+ ]
4838
+ }
4824
4839
  },
4825
- "required": false
4840
+ "required": false,
4841
+ "description": ""
4826
4842
  },
4827
4843
  "tokens": {
4828
4844
  "type": {
@@ -4850,30 +4866,17 @@
4850
4866
  "required": false,
4851
4867
  "description": ""
4852
4868
  },
4853
- "variant": {
4854
- "type": {
4855
- "name": "objectOf",
4856
- "value": {
4857
- "name": "union",
4858
- "value": [
4859
- {
4860
- "name": "string"
4861
- },
4862
- {
4863
- "name": "number"
4864
- },
4865
- {
4866
- "name": "bool"
4867
- }
4868
- ]
4869
- }
4870
- },
4871
- "required": false,
4872
- "description": ""
4873
- },
4874
4869
  "children": {
4875
4870
  "type": {
4876
- "name": "node"
4871
+ "name": "union",
4872
+ "value": [
4873
+ {
4874
+ "name": "node"
4875
+ },
4876
+ {
4877
+ "name": "func"
4878
+ }
4879
+ ]
4877
4880
  },
4878
4881
  "required": true,
4879
4882
  "description": ""
@@ -4910,12 +4913,26 @@
4910
4913
  "docs": {
4911
4914
  "description": "ListItem is responsible for rendering icon or a bullet as side item",
4912
4915
  "props": {
4913
- "accessibilityRole": {
4914
- "defaultValue": {
4915
- "value": "Platform.select({ web: 'listitem', default: undefined })",
4916
- "computed": true
4916
+ "variant": {
4917
+ "type": {
4918
+ "name": "objectOf",
4919
+ "value": {
4920
+ "name": "union",
4921
+ "value": [
4922
+ {
4923
+ "name": "string"
4924
+ },
4925
+ {
4926
+ "name": "number"
4927
+ },
4928
+ {
4929
+ "name": "bool"
4930
+ }
4931
+ ]
4932
+ }
4917
4933
  },
4918
- "required": false
4934
+ "required": false,
4935
+ "description": ""
4919
4936
  },
4920
4937
  "tokens": {
4921
4938
  "type": {
@@ -4943,30 +4960,17 @@
4943
4960
  "required": false,
4944
4961
  "description": ""
4945
4962
  },
4946
- "variant": {
4947
- "type": {
4948
- "name": "objectOf",
4949
- "value": {
4950
- "name": "union",
4951
- "value": [
4952
- {
4953
- "name": "string"
4954
- },
4955
- {
4956
- "name": "number"
4957
- },
4958
- {
4959
- "name": "bool"
4960
- }
4961
- ]
4962
- }
4963
- },
4964
- "required": false,
4965
- "description": ""
4966
- },
4967
4963
  "children": {
4968
4964
  "type": {
4969
- "name": "node"
4965
+ "name": "union",
4966
+ "value": [
4967
+ {
4968
+ "name": "node"
4969
+ },
4970
+ {
4971
+ "name": "func"
4972
+ }
4973
+ ]
4970
4974
  },
4971
4975
  "required": true,
4972
4976
  "description": ""
@@ -8822,6 +8826,17 @@
8822
8826
  "required": false,
8823
8827
  "description": "Minimal part of slide width must be swiped for changing index.\nOtherwise animation restore current slide. Default value 0.2 means that 20% must be swiped for change index"
8824
8828
  },
8829
+ "refocus": {
8830
+ "defaultValue": {
8831
+ "value": "Boolean(tabs)",
8832
+ "computed": true
8833
+ },
8834
+ "type": {
8835
+ "name": "bool"
8836
+ },
8837
+ "required": false,
8838
+ "description": "If true, whenever a new slide comes into view, the focus of the Carousel switches to the start.\n\nPass this as true when using carousel items that contain interactive content, so a user can easily tab into that content.\n\nIf skipLinkHref is passed, the focus target will be the SkipLink; if not, it'll be an empty element before the slide content."
8839
+ },
8825
8840
  "title": {
8826
8841
  "defaultValue": {
8827
8842
  "value": "'carousel'",
@@ -8994,6 +9009,7 @@
8994
9009
  "previousIcon": "icon",
8995
9010
  "showPreviousNextNavigation": "show",
8996
9011
  "showPanelNavigation": "show",
9012
+ "showPanelTabs": "show",
8997
9013
  "spaceBetweenSlideAndPreviousNextNavigation": "size",
8998
9014
  "spaceBetweenSlideAndPanelNavigation": "size",
8999
9015
  "thumbnailBorderColor": "color",
@@ -9063,12 +9079,17 @@
9063
9079
  "required": false,
9064
9080
  "description": "If this is a complex carousel with a lot of focusable content, pass a href for a skip link. Typically, this will be an anchor link\nwith the ID of a focusable element immediately after the Carousel, e.g. `'#section-2-heading'`."
9065
9081
  },
9066
- "refocus": {
9082
+ "tabs": {
9067
9083
  "type": {
9068
- "name": "bool"
9084
+ "name": "arrayOf",
9085
+ "value": {
9086
+ "name": "shape",
9087
+ "value": "CarouselTabsPanelItem.propTypes || {}",
9088
+ "computed": true
9089
+ }
9069
9090
  },
9070
9091
  "required": false,
9071
- "description": "If true, whenever a new slide comes into view, the focus of the Carousel switches to the start.\n\nPass this as true when using carousel items that contain interactive content, so a user can easily tab into that content.\n\nIf skipLinkHref is passed, the focus target will be the SkipLink; if not, it'll be an empty element before the slide content."
9092
+ "description": "If provided, defaults the navigation panel to a CarouselTabsPanel element passing each item as props for one tab.\n\nBe careful to ensure that the order of each element in the items array matches the order of each child in the Carousel."
9072
9093
  },
9073
9094
  "onAnimationStart": {
9074
9095
  "type": {
@@ -9259,7 +9280,7 @@
9259
9280
  },
9260
9281
  "CarouselTabs": {
9261
9282
  "docs": {
9262
- "description": "",
9283
+ "description": "@deprecated Please use Carousel and pass the `tabs` prop.",
9263
9284
  "props": {
9264
9285
  "refocus": {
9265
9286
  "defaultValue": {
@@ -9300,6 +9321,7 @@
9300
9321
  "previousIcon": "icon",
9301
9322
  "showPreviousNextNavigation": "show",
9302
9323
  "showPanelNavigation": "show",
9324
+ "showPanelTabs": "show",
9303
9325
  "spaceBetweenSlideAndPreviousNextNavigation": "size",
9304
9326
  "spaceBetweenSlideAndPanelNavigation": "size",
9305
9327
  "thumbnailBorderColor": "color",
@@ -9463,6 +9485,18 @@
9463
9485
  "required": false,
9464
9486
  "description": "If this is a complex carousel with a lot of focusable content, pass a href for a skip link. Typically, this will be an anchor link\nwith the ID of a focusable element immediately after the Carousel, e.g. `'#section-2-heading'`."
9465
9487
  },
9488
+ "tabs": {
9489
+ "type": {
9490
+ "name": "arrayOf",
9491
+ "value": {
9492
+ "name": "shape",
9493
+ "value": "CarouselTabsPanelItem.propTypes || {}",
9494
+ "computed": true
9495
+ }
9496
+ },
9497
+ "required": false,
9498
+ "description": "If provided, defaults the navigation panel to a CarouselTabsPanel element passing each item as props for one tab.\n\nBe careful to ensure that the order of each element in the items array matches the order of each child in the Carousel."
9499
+ },
9466
9500
  "panelNavigation": {
9467
9501
  "type": {
9468
9502
  "name": "element"
@@ -9679,6 +9713,7 @@
9679
9713
  "previousIcon": "icon",
9680
9714
  "showPreviousNextNavigation": "show",
9681
9715
  "showPanelNavigation": "show",
9716
+ "showPanelTabs": "show",
9682
9717
  "spaceBetweenSlideAndPreviousNextNavigation": "size",
9683
9718
  "spaceBetweenSlideAndPanelNavigation": "size",
9684
9719
  "thumbnailBorderColor": "color",
@@ -37,9 +37,9 @@ const A11yInfoProvider = _ref => {
37
37
  return () => {};
38
38
  }
39
39
 
40
- _AccessibilityInfo.default.addEventListener('reduceMotionChanged', setReduceMotionEnabled);
40
+ const motionSubscription = _AccessibilityInfo.default.addEventListener('reduceMotionChanged', setReduceMotionEnabled);
41
41
 
42
- _AccessibilityInfo.default.addEventListener('screenReaderChanged', setScreenReaderEnabled);
42
+ const screenReaderSubscription = _AccessibilityInfo.default.addEventListener('screenReaderChanged', setScreenReaderEnabled);
43
43
 
44
44
  const setInitialA11yInfo = async () => {
45
45
  const [initialReduceMotionEnabled, initialScreenReaderEnabled] = await Promise.all([_AccessibilityInfo.default.isReduceMotionEnabled(), _AccessibilityInfo.default.isScreenReaderEnabled()]); // Browsers can't detect screen readers; in RNW isScreenReaderEnabled() is always `true`
@@ -55,9 +55,18 @@ const A11yInfoProvider = _ref => {
55
55
  }
56
56
 
57
57
  return () => {
58
- _AccessibilityInfo.default.removeEventListener('reduceMotionChanged', setReduceMotionEnabled);
59
-
60
- _AccessibilityInfo.default.removeEventListener('screenReaderChanged', setScreenReaderEnabled);
58
+ // From react-native 0.65, AccessibilityInfo.removeEventListener is deprecated for `remove` on addEventListener return value
59
+ if (typeof (motionSubscription === null || motionSubscription === void 0 ? void 0 : motionSubscription.remove) === 'function') {
60
+ motionSubscription === null || motionSubscription === void 0 ? void 0 : motionSubscription.remove();
61
+ } else if (typeof _AccessibilityInfo.default.removeEventListener === 'function') {
62
+ _AccessibilityInfo.default.removeEventListener('reduceMotionChanged', setReduceMotionEnabled);
63
+ }
64
+
65
+ if (typeof (screenReaderSubscription === null || screenReaderSubscription === void 0 ? void 0 : screenReaderSubscription.remove) === 'function') {
66
+ screenReaderSubscription === null || screenReaderSubscription === void 0 ? void 0 : screenReaderSubscription.remove();
67
+ } else if (typeof _AccessibilityInfo.default.removeEventListener === 'function') {
68
+ _AccessibilityInfo.default.removeEventListener('screenReaderChanged', setScreenReaderEnabled);
69
+ }
61
70
  };
62
71
  }, []);
63
72
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(ReducedMotionContext.Provider, {
@@ -155,8 +155,9 @@ const ButtonGroup = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
155
155
  tokens: getButtonTokens,
156
156
  selected: isSelected,
157
157
  inactive: inactive,
158
- ...itemA11y,
159
- ...selectItemProps(itemRest),
158
+ ...selectItemProps({ ...itemRest,
159
+ ...itemA11y
160
+ }),
160
161
  children: label
161
162
  }, id);
162
163
  })