@telus-uds/components-base 4.0.0-alpha.2 → 4.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -1
- package/lib/cjs/Autocomplete/Autocomplete.js +13 -1
- package/lib/cjs/Autocomplete/constants.js +1 -1
- package/lib/cjs/Button/ButtonGroup.js +91 -23
- package/lib/cjs/Card/CardBase.js +75 -47
- package/lib/cjs/ColourToggle/ColourBubble.js +66 -13
- package/lib/cjs/ColourToggle/ColourToggle.js +41 -11
- package/lib/cjs/ColourToggle/constants.js +15 -0
- package/lib/cjs/ColourToggle/dictionary.js +14 -0
- package/lib/cjs/Listbox/ListboxOverlay.js +7 -1
- package/lib/cjs/MultiSelectFilter/ModalOverlay.js +7 -1
- package/lib/cjs/MultiSelectFilter/MultiSelectFilter.js +2 -28
- package/lib/cjs/TextInput/TextInputBase.js +2 -1
- package/lib/cjs/Validator/Validator.js +5 -1
- package/lib/cjs/utils/useOverlaidPosition.js +83 -42
- package/lib/esm/Autocomplete/Autocomplete.js +13 -1
- package/lib/esm/Autocomplete/constants.js +1 -1
- package/lib/esm/Button/ButtonGroup.js +91 -23
- package/lib/esm/Card/CardBase.js +75 -47
- package/lib/esm/ColourToggle/ColourBubble.js +67 -14
- package/lib/esm/ColourToggle/ColourToggle.js +41 -11
- package/lib/esm/ColourToggle/constants.js +8 -0
- package/lib/esm/ColourToggle/dictionary.js +8 -0
- package/lib/esm/Listbox/ListboxOverlay.js +7 -1
- package/lib/esm/MultiSelectFilter/ModalOverlay.js +8 -2
- package/lib/esm/MultiSelectFilter/MultiSelectFilter.js +2 -28
- package/lib/esm/TextInput/TextInputBase.js +2 -1
- package/lib/esm/Validator/Validator.js +5 -1
- package/lib/esm/utils/useOverlaidPosition.js +83 -42
- package/lib/package.json +3 -3
- package/package.json +3 -3
- package/src/Autocomplete/Autocomplete.jsx +11 -2
- package/src/Autocomplete/constants.js +1 -1
- package/src/Button/ButtonGroup.jsx +93 -24
- package/src/Card/CardBase.jsx +94 -75
- package/src/ColourToggle/ColourBubble.jsx +62 -7
- package/src/ColourToggle/ColourToggle.jsx +43 -9
- package/src/ColourToggle/constants.js +10 -0
- package/src/ColourToggle/dictionary.js +4 -0
- package/src/Listbox/ListboxOverlay.jsx +6 -2
- package/src/MultiSelectFilter/ModalOverlay.jsx +9 -3
- package/src/MultiSelectFilter/MultiSelectFilter.jsx +1 -31
- package/src/TextInput/TextInputBase.jsx +2 -1
- package/src/Validator/Validator.jsx +5 -1
- package/src/utils/useOverlaidPosition.js +84 -34
- package/types/A11yInfoProvider.d.ts +9 -0
- package/types/A11yText.d.ts +13 -0
- package/types/ActionCard.d.ts +19 -0
- package/types/ActivityIndicator.d.ts +13 -0
- package/types/Autocomplete.d.ts +27 -0
- package/types/Badge.d.ts +15 -4
- package/types/BaseProvider.d.ts +26 -0
- package/types/Box.d.ts +13 -3
- package/types/Button.d.ts +35 -0
- package/types/Card.d.ts +19 -0
- package/types/CardGroup.d.ts +23 -0
- package/types/Carousel.d.ts +25 -0
- package/types/Checkbox.d.ts +15 -2
- package/types/CheckboxCard.d.ts +20 -0
- package/types/CheckboxCardGroup.d.ts +10 -4
- package/types/ChevronLink.d.ts +9 -2
- package/types/ColourToggle.d.ts +16 -0
- package/types/Common.d.ts +7 -3
- package/types/Divider.d.ts +13 -1
- package/types/DownloadApp.d.ts +19 -0
- package/types/ExpandCollapse.d.ts +16 -9
- package/types/ExpandCollapseMini.d.ts +16 -0
- package/types/Feedback.d.ts +16 -0
- package/types/Fieldset.d.ts +17 -0
- package/types/FileUpload.d.ts +6 -0
- package/types/FlexGrid.d.ts +57 -0
- package/types/Footnote.d.ts +18 -0
- package/types/HorizontalScroll.d.ts +15 -0
- package/types/HorizontalScrollButton.d.ts +17 -1
- package/types/Icon.d.ts +13 -2
- package/types/IconButton.d.ts +19 -0
- package/types/InputLabel.d.ts +12 -0
- package/types/InputSupports.d.ts +19 -0
- package/types/Link.d.ts +20 -4
- package/types/List.d.ts +11 -4
- package/types/Listbox.d.ts +13 -3
- package/types/Modal.d.ts +25 -0
- package/types/MultiSelectFilter.d.ts +24 -0
- package/types/Notification.d.ts +19 -0
- package/types/OrderedList.d.ts +17 -0
- package/types/Pagination.d.ts +25 -0
- package/types/Portal.d.ts +5 -1
- package/types/PriceLockup.d.ts +28 -0
- package/types/ProductCard.d.ts +20 -0
- package/types/ProductCardGroup.d.ts +21 -0
- package/types/Progress.d.ts +22 -0
- package/types/QuickLinks.d.ts +27 -0
- package/types/QuickLinksFeature.d.ts +27 -0
- package/types/Radio.d.ts +22 -0
- package/types/RadioCard.d.ts +21 -0
- package/types/Responsive.d.ts +14 -0
- package/types/Scroll.d.ts +2 -2
- package/types/Search.d.ts +15 -2
- package/types/Select.d.ts +12 -4
- package/types/SideNav.d.ts +38 -0
- package/types/Skeleton.d.ts +17 -0
- package/types/SkipLink.d.ts +14 -0
- package/types/Spacer.d.ts +8 -1
- package/types/StackView.d.ts +8 -2
- package/types/Status.d.ts +2 -3
- package/types/StepTracker.d.ts +16 -0
- package/types/TabBar.d.ts +25 -0
- package/types/Tabs.d.ts +12 -3
- package/types/Tags.d.ts +24 -0
- package/types/TextButton.d.ts +11 -4
- package/types/TextInput.d.ts +38 -0
- package/types/ThemeProvider.d.ts +29 -0
- package/types/Timeline.d.ts +16 -0
- package/types/ToggleSwitch.d.ts +11 -2
- package/types/ToolTip.d.ts +7 -3
- package/types/TooltipButton.d.ts +20 -0
- package/types/Typography.d.ts +8 -2
- package/types/Validator.d.ts +16 -0
- package/types/ViewportProvider.d.ts +12 -0
- package/types/index.d.ts +197 -50
package/src/Card/CardBase.jsx
CHANGED
|
@@ -19,9 +19,7 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
|
|
|
19
19
|
|
|
20
20
|
const GRID_COLUMNS = 12
|
|
21
21
|
|
|
22
|
-
const isOverlayColor = (color) =>
|
|
23
|
-
return color && typeof color === 'string' && color.startsWith('rgba(')
|
|
24
|
-
}
|
|
22
|
+
const isOverlayColor = (color) => color && typeof color === 'string' && color.startsWith('rgba(')
|
|
25
23
|
|
|
26
24
|
const setBackgroundImage = ({
|
|
27
25
|
src,
|
|
@@ -30,7 +28,8 @@ const setBackgroundImage = ({
|
|
|
30
28
|
backgroundImagePosition,
|
|
31
29
|
backgroundImageAlign,
|
|
32
30
|
content,
|
|
33
|
-
cardStyle
|
|
31
|
+
cardStyle,
|
|
32
|
+
testID
|
|
34
33
|
}) => {
|
|
35
34
|
const borderRadius = cardStyle?.borderRadius || 0
|
|
36
35
|
const borderWidth = cardStyle?.borderWidth || 0
|
|
@@ -96,6 +95,7 @@ const setBackgroundImage = ({
|
|
|
96
95
|
style={[staticStyles.imageBackground, backgroundImageStyle]}
|
|
97
96
|
role="img"
|
|
98
97
|
aria-label={alt}
|
|
98
|
+
testID={testID}
|
|
99
99
|
>
|
|
100
100
|
{content}
|
|
101
101
|
</View>
|
|
@@ -113,6 +113,7 @@ const setBackgroundImage = ({
|
|
|
113
113
|
accessible={true}
|
|
114
114
|
accessibilityLabel={alt}
|
|
115
115
|
accessibilityIgnoresInvertColors={true}
|
|
116
|
+
testID={testID}
|
|
116
117
|
/>
|
|
117
118
|
<View style={staticStyles.contentOverlay}>{content}</View>
|
|
118
119
|
</View>
|
|
@@ -127,33 +128,18 @@ const setBackgroundImage = ({
|
|
|
127
128
|
style={staticStyles.imageBackground}
|
|
128
129
|
accessible={true}
|
|
129
130
|
accessibilityLabel={alt}
|
|
131
|
+
testID={testID}
|
|
130
132
|
>
|
|
131
133
|
{content}
|
|
132
134
|
</ImageBackground>
|
|
133
135
|
)
|
|
134
136
|
}
|
|
135
137
|
|
|
136
|
-
const selectPaddedContentStyles = ({
|
|
138
|
+
const selectPaddedContentStyles = ({ paddingTop, paddingBottom, paddingLeft, paddingRight }) => ({
|
|
137
139
|
paddingTop,
|
|
138
140
|
paddingBottom,
|
|
139
141
|
paddingLeft,
|
|
140
|
-
paddingRight
|
|
141
|
-
borderWidth,
|
|
142
|
-
borderColor,
|
|
143
|
-
borderRadius,
|
|
144
|
-
hasInteractiveBorder
|
|
145
|
-
}) => ({
|
|
146
|
-
paddingTop,
|
|
147
|
-
paddingBottom,
|
|
148
|
-
paddingLeft,
|
|
149
|
-
paddingRight,
|
|
150
|
-
...(hasInteractiveBorder
|
|
151
|
-
? {
|
|
152
|
-
borderWidth,
|
|
153
|
-
borderColor,
|
|
154
|
-
borderRadius
|
|
155
|
-
}
|
|
156
|
-
: {})
|
|
142
|
+
paddingRight
|
|
157
143
|
})
|
|
158
144
|
|
|
159
145
|
const selectInteractiveOverlayStyles = ({ backgroundColor, borderRadius, borderWidth }) => {
|
|
@@ -167,32 +153,49 @@ const selectInteractiveOverlayStyles = ({ backgroundColor, borderRadius, borderW
|
|
|
167
153
|
backgroundColor,
|
|
168
154
|
borderRadius: adjustedBorderRadius,
|
|
169
155
|
pointerEvents: 'none',
|
|
170
|
-
zIndex:
|
|
156
|
+
zIndex: 3
|
|
171
157
|
}
|
|
172
158
|
}
|
|
173
159
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
flex,
|
|
160
|
+
const selectOuterContainerStyles = ({
|
|
161
|
+
containerStyle,
|
|
177
162
|
backgroundColor,
|
|
178
|
-
borderColor,
|
|
179
163
|
borderRadius,
|
|
164
|
+
borderColor,
|
|
180
165
|
borderWidth,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
166
|
+
hasGradientToken
|
|
167
|
+
}) => ({
|
|
168
|
+
...containerStyle,
|
|
169
|
+
backgroundColor,
|
|
170
|
+
borderRadius,
|
|
171
|
+
...(hasGradientToken ? {} : { borderColor, borderWidth })
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
// Ensure explicit selection of tokens
|
|
175
|
+
export const selectStyles = (
|
|
176
|
+
{
|
|
177
|
+
flex,
|
|
178
|
+
backgroundColor,
|
|
179
|
+
borderColor,
|
|
180
|
+
borderRadius,
|
|
181
|
+
borderWidth,
|
|
182
|
+
paddingBottom,
|
|
183
|
+
paddingLeft,
|
|
184
|
+
paddingRight,
|
|
185
|
+
paddingTop,
|
|
186
|
+
marginTop,
|
|
187
|
+
marginBottom,
|
|
188
|
+
marginLeft,
|
|
189
|
+
marginRight,
|
|
190
|
+
minWidth,
|
|
191
|
+
shadow,
|
|
192
|
+
backgroundGradient,
|
|
193
|
+
gradient,
|
|
194
|
+
maxHeight,
|
|
195
|
+
overflowY
|
|
196
|
+
},
|
|
197
|
+
{ hasBgImage = false } = {}
|
|
198
|
+
) => {
|
|
196
199
|
const hasGradient = (gradient || backgroundGradient) && Platform.OS === 'web'
|
|
197
200
|
|
|
198
201
|
let backgroundImageValue = null
|
|
@@ -231,7 +234,9 @@ export const selectStyles = ({
|
|
|
231
234
|
? {
|
|
232
235
|
backgroundImage: backgroundImageValue,
|
|
233
236
|
backgroundOrigin: `border-box`,
|
|
234
|
-
|
|
237
|
+
// bgImage child fills the content-box and replaces what the inset shadow
|
|
238
|
+
// used to cover, so we omit it to avoid hiding the image.
|
|
239
|
+
...(hasBgImage ? {} : { boxShadow: `inset 0 1000px ${boxShadowColor}` }),
|
|
235
240
|
border: `${borderWidth}px solid transparent`
|
|
236
241
|
}
|
|
237
242
|
: {}),
|
|
@@ -249,14 +254,13 @@ export const selectStyles = ({
|
|
|
249
254
|
* intended to be used in apps or sites directly: build themed components on top of this.
|
|
250
255
|
*/
|
|
251
256
|
export const CardBase = React.forwardRef(
|
|
252
|
-
(
|
|
257
|
+
(
|
|
258
|
+
{ children, tokens, dataSet, backgroundImage, fullBleedContent, cardState, testID, ...rest },
|
|
259
|
+
ref
|
|
260
|
+
) => {
|
|
253
261
|
const resolvedTokens = typeof tokens === 'function' ? tokens(cardState) : tokens
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
? { ...resolvedTokens, gradient: undefined, backgroundGradient: undefined }
|
|
257
|
-
: resolvedTokens
|
|
258
|
-
|
|
259
|
-
const cardStyle = selectStyles(tokensToUse)
|
|
262
|
+
const hasBgImage = Boolean(backgroundImage && backgroundImage.src)
|
|
263
|
+
const cardStyle = selectStyles(resolvedTokens, { hasBgImage })
|
|
260
264
|
const props = selectProps(rest)
|
|
261
265
|
|
|
262
266
|
let content = children
|
|
@@ -288,31 +292,28 @@ export const CardBase = React.forwardRef(
|
|
|
288
292
|
} = cardStyle
|
|
289
293
|
|
|
290
294
|
const hasPadding = paddingTop || paddingBottom || paddingLeft || paddingRight
|
|
291
|
-
const hasInteractiveBorder = borderWidth && borderWidth > 0
|
|
292
295
|
const hasInteractiveOverlay = isOverlayColor(backgroundColor)
|
|
296
|
+
const outerBackgroundColor = hasInteractiveOverlay ? undefined : backgroundColor
|
|
297
|
+
const hasGradientToken = Boolean(resolvedTokens.gradient) && Platform.OS === 'web'
|
|
293
298
|
|
|
294
|
-
const paddedContent =
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
{children}
|
|
309
|
-
</View>
|
|
310
|
-
) : (
|
|
311
|
-
children
|
|
312
|
-
)
|
|
299
|
+
const paddedContent = hasPadding ? (
|
|
300
|
+
<View
|
|
301
|
+
style={selectPaddedContentStyles({
|
|
302
|
+
paddingTop,
|
|
303
|
+
paddingBottom,
|
|
304
|
+
paddingLeft,
|
|
305
|
+
paddingRight
|
|
306
|
+
})}
|
|
307
|
+
>
|
|
308
|
+
{children}
|
|
309
|
+
</View>
|
|
310
|
+
) : (
|
|
311
|
+
children
|
|
312
|
+
)
|
|
313
313
|
|
|
314
314
|
const contentWithOverlay = (
|
|
315
315
|
<>
|
|
316
|
+
<View style={staticStyles.contentOverlay}>{paddedContent}</View>
|
|
316
317
|
{hasInteractiveOverlay && Platform.OS === 'web' && (
|
|
317
318
|
<View
|
|
318
319
|
style={selectInteractiveOverlayStyles({
|
|
@@ -320,9 +321,9 @@ export const CardBase = React.forwardRef(
|
|
|
320
321
|
borderRadius,
|
|
321
322
|
borderWidth
|
|
322
323
|
})}
|
|
324
|
+
testID={testID && `${testID}-card-base-bg-overlay`}
|
|
323
325
|
/>
|
|
324
326
|
)}
|
|
325
|
-
<View style={staticStyles.contentOverlay}>{paddedContent}</View>
|
|
326
327
|
</>
|
|
327
328
|
)
|
|
328
329
|
|
|
@@ -333,11 +334,25 @@ export const CardBase = React.forwardRef(
|
|
|
333
334
|
backgroundImagePosition,
|
|
334
335
|
backgroundImageAlign,
|
|
335
336
|
content: contentWithOverlay,
|
|
336
|
-
cardStyle: {
|
|
337
|
+
cardStyle: { borderRadius, borderWidth },
|
|
338
|
+
testID: testID && `${testID}-card-base-bg-image`
|
|
337
339
|
})
|
|
338
340
|
|
|
339
341
|
return (
|
|
340
|
-
<View
|
|
342
|
+
<View
|
|
343
|
+
style={selectOuterContainerStyles({
|
|
344
|
+
containerStyle,
|
|
345
|
+
backgroundColor: outerBackgroundColor,
|
|
346
|
+
borderRadius,
|
|
347
|
+
borderColor,
|
|
348
|
+
borderWidth,
|
|
349
|
+
hasGradientToken
|
|
350
|
+
})}
|
|
351
|
+
dataSet={dataSet}
|
|
352
|
+
ref={ref}
|
|
353
|
+
testID={testID}
|
|
354
|
+
{...props}
|
|
355
|
+
>
|
|
341
356
|
{content}
|
|
342
357
|
</View>
|
|
343
358
|
)
|
|
@@ -370,7 +385,7 @@ export const CardBase = React.forwardRef(
|
|
|
370
385
|
)
|
|
371
386
|
|
|
372
387
|
return (
|
|
373
|
-
<View style={containerStyle} dataSet={dataSet} ref={ref} {...props}>
|
|
388
|
+
<View style={containerStyle} dataSet={dataSet} ref={ref} testID={testID} {...props}>
|
|
374
389
|
<FlexGrid>
|
|
375
390
|
<FlexGridRow>
|
|
376
391
|
{imageFirst ? (
|
|
@@ -391,7 +406,7 @@ export const CardBase = React.forwardRef(
|
|
|
391
406
|
}
|
|
392
407
|
|
|
393
408
|
return (
|
|
394
|
-
<View style={cardStyle} dataSet={dataSet} ref={ref} {...props}>
|
|
409
|
+
<View style={cardStyle} dataSet={dataSet} ref={ref} testID={testID} {...props}>
|
|
395
410
|
{content}
|
|
396
411
|
</View>
|
|
397
412
|
)
|
|
@@ -439,6 +454,10 @@ CardBase.propTypes = {
|
|
|
439
454
|
...selectedSystemPropTypes,
|
|
440
455
|
children: PropTypes.node,
|
|
441
456
|
tokens: getTokensPropType('Card'),
|
|
457
|
+
/**
|
|
458
|
+
* Identifier for testing purposes.
|
|
459
|
+
*/
|
|
460
|
+
testID: PropTypes.string,
|
|
442
461
|
/**
|
|
443
462
|
* Apply background image to the card.
|
|
444
463
|
*/
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
|
|
4
|
-
import { View, Pressable, Platform } from 'react-native'
|
|
4
|
+
import { View, Pressable, Platform, StyleSheet } from 'react-native'
|
|
5
5
|
import { resolvePressableTokens } from '../utils/pressability'
|
|
6
6
|
import { applyShadowToken } from '../ThemeProvider/utils/styles'
|
|
7
7
|
import { getTokensPropType } from '../utils/props/tokens'
|
|
8
8
|
import { Tooltip } from '../Tooltip/Tooltip.native'
|
|
9
|
+
import { UNAVAILABLE_VARIANT } from './constants'
|
|
9
10
|
|
|
10
11
|
const selectGeneralBubbleTokens = ({
|
|
11
12
|
outerBubbleHeight,
|
|
@@ -52,13 +53,41 @@ const selectBorderBubbleTokens = ({
|
|
|
52
53
|
borderRadius: bubbleBorderRadius
|
|
53
54
|
})
|
|
54
55
|
|
|
56
|
+
const selectOverlayStyles = ({ overlayColor, innerBubbleBorderRadius }) => ({
|
|
57
|
+
borderRadius: innerBubbleBorderRadius,
|
|
58
|
+
backgroundColor: overlayColor
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const selectSlashStyles = (
|
|
62
|
+
{ slashLightColor, slashDarkColor, slashWidth, slashOffset },
|
|
63
|
+
unavailable
|
|
64
|
+
) => ({
|
|
65
|
+
width: slashWidth,
|
|
66
|
+
backgroundColor: unavailable === UNAVAILABLE_VARIANT.DARK ? slashDarkColor : slashLightColor,
|
|
67
|
+
marginLeft: slashOffset
|
|
68
|
+
})
|
|
69
|
+
|
|
55
70
|
export const ColourBubble = React.forwardRef(
|
|
56
|
-
(
|
|
71
|
+
(
|
|
72
|
+
{
|
|
73
|
+
tokens = () => ({}),
|
|
74
|
+
id,
|
|
75
|
+
colourHexCode,
|
|
76
|
+
colourName,
|
|
77
|
+
isSelected,
|
|
78
|
+
onPress,
|
|
79
|
+
showTooltip,
|
|
80
|
+
unavailable,
|
|
81
|
+
isDisabled
|
|
82
|
+
},
|
|
83
|
+
ref
|
|
84
|
+
) => {
|
|
57
85
|
const defaultTokens = tokens({ selected: isSelected })
|
|
58
86
|
|
|
59
|
-
const resolveColourBubbleTokens = (pressState) =>
|
|
87
|
+
const resolveColourBubbleTokens = (pressState) =>
|
|
88
|
+
resolvePressableTokens(tokens, isDisabled ? {} : pressState, {})
|
|
60
89
|
|
|
61
|
-
const themeTokens =
|
|
90
|
+
const themeTokens = tokens()
|
|
62
91
|
|
|
63
92
|
const pressable = (
|
|
64
93
|
<Pressable
|
|
@@ -67,14 +96,23 @@ export const ColourBubble = React.forwardRef(
|
|
|
67
96
|
isSelected && selectBorderBubbleTokens(defaultTokens)
|
|
68
97
|
]}
|
|
69
98
|
onPress={onPress}
|
|
99
|
+
disabled={isDisabled}
|
|
100
|
+
focusable={!isDisabled}
|
|
70
101
|
accessible
|
|
71
102
|
accessibilityRole="radio"
|
|
72
103
|
accessibilityLabel={colourName}
|
|
73
|
-
accessibilityState={{ checked: isSelected }}
|
|
104
|
+
accessibilityState={{ checked: isSelected, disabled: isDisabled }}
|
|
74
105
|
ref={ref}
|
|
75
106
|
testID={id}
|
|
76
107
|
>
|
|
77
|
-
<View style={[selectInnerBubbleTokens(themeTokens), { backgroundColor: colourHexCode }]}
|
|
108
|
+
<View style={[selectInnerBubbleTokens(themeTokens), { backgroundColor: colourHexCode }]}>
|
|
109
|
+
{unavailable && (
|
|
110
|
+
<View style={[StyleSheet.absoluteFillObject, selectOverlayStyles(themeTokens)]} />
|
|
111
|
+
)}
|
|
112
|
+
</View>
|
|
113
|
+
{unavailable && (
|
|
114
|
+
<View style={[staticStyles.indicator, selectSlashStyles(themeTokens, unavailable)]} />
|
|
115
|
+
)}
|
|
78
116
|
</Pressable>
|
|
79
117
|
)
|
|
80
118
|
|
|
@@ -121,5 +159,22 @@ ColourBubble.propTypes = {
|
|
|
121
159
|
/**
|
|
122
160
|
* When true, wraps the bubble in a Tooltip that displays the colourName on hover (web only).
|
|
123
161
|
*/
|
|
124
|
-
showTooltip: PropTypes.bool
|
|
162
|
+
showTooltip: PropTypes.bool,
|
|
163
|
+
/**
|
|
164
|
+
* When set, renders a diagonal indicator over the bubble. Accepts either 'dark' or 'light' to determine the colour of the indicator.
|
|
165
|
+
*/
|
|
166
|
+
unavailable: PropTypes.oneOf(Object.values(UNAVAILABLE_VARIANT)),
|
|
167
|
+
/**
|
|
168
|
+
* When true, disables interaction on the bubble.
|
|
169
|
+
*/
|
|
170
|
+
isDisabled: PropTypes.bool
|
|
125
171
|
}
|
|
172
|
+
|
|
173
|
+
const staticStyles = StyleSheet.create({
|
|
174
|
+
indicator: {
|
|
175
|
+
position: 'absolute',
|
|
176
|
+
top: '50%',
|
|
177
|
+
height: 2,
|
|
178
|
+
transform: [{ rotate: '-45deg' }]
|
|
179
|
+
}
|
|
180
|
+
})
|
|
@@ -8,31 +8,50 @@ import { getTokensPropType } from '../utils/props/tokens'
|
|
|
8
8
|
import { selectSystemProps } from '../utils/props/selectSystemProps'
|
|
9
9
|
import { variantProp } from '../utils/props/variantProp'
|
|
10
10
|
import { viewProps } from '../utils/props/viewProps'
|
|
11
|
+
import { useCopy } from '../utils/useCopy'
|
|
11
12
|
import { StackWrap } from '../StackView/StackWrap'
|
|
12
13
|
import { Typography } from '../Typography/Typography'
|
|
13
14
|
import { ColourBubble } from './ColourBubble'
|
|
15
|
+
import { UNAVAILABLE_VARIANT, DICTIONARY_CONTENT_SHAPE } from './constants'
|
|
16
|
+
import { DEFAULT_COLOUR_TOGGLE_DICTIONARY } from './dictionary'
|
|
14
17
|
|
|
15
18
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
|
|
16
19
|
|
|
17
20
|
export const ColourToggle = React.forwardRef(
|
|
18
|
-
(
|
|
21
|
+
(
|
|
22
|
+
{
|
|
23
|
+
tokens,
|
|
24
|
+
variant,
|
|
25
|
+
defaultColourId,
|
|
26
|
+
items,
|
|
27
|
+
onChange,
|
|
28
|
+
showTooltips,
|
|
29
|
+
copy = 'en',
|
|
30
|
+
dictionary = DEFAULT_COLOUR_TOGGLE_DICTIONARY,
|
|
31
|
+
...rest
|
|
32
|
+
},
|
|
33
|
+
ref
|
|
34
|
+
) => {
|
|
19
35
|
const [currentColourId, setCurrentColourId] = React.useState(defaultColourId)
|
|
20
36
|
const getTokens = useThemeTokensCallback('ColourToggle', tokens, variant)
|
|
21
|
-
|
|
37
|
+
const getCopy = useCopy({ dictionary, copy })
|
|
22
38
|
const { space } = getTokens()
|
|
23
|
-
const {
|
|
24
|
-
items.find((item) => item.id === currentColourId) || ''
|
|
39
|
+
const currentItem = items.find(({ id }) => id === currentColourId)
|
|
25
40
|
|
|
26
41
|
return (
|
|
27
42
|
<View ref={ref} {...selectProps(rest)}>
|
|
28
|
-
<Typography>
|
|
43
|
+
<Typography>
|
|
44
|
+
{currentItem?.unavailable
|
|
45
|
+
? `${currentItem.colourName} ${getCopy('unavailable')}`
|
|
46
|
+
: currentItem?.colourName ?? ''}
|
|
47
|
+
</Typography>
|
|
29
48
|
<StackWrap space={space} accessibilityRole="radiogroup">
|
|
30
|
-
{items.map(({ id, colourHexCode, colourName }, index) => {
|
|
49
|
+
{items.map(({ id, colourHexCode, colourName, unavailable, disabled }, index) => {
|
|
31
50
|
const colourBubbleId = id || `ColourBubble[${index}]`
|
|
32
51
|
|
|
33
52
|
const handleChangeColour = (event) => {
|
|
34
53
|
setCurrentColourId(id)
|
|
35
|
-
onChange?.(event, { id, colourHexCode, colourName })
|
|
54
|
+
onChange?.(event, { id, colourHexCode, colourName, unavailable })
|
|
36
55
|
}
|
|
37
56
|
|
|
38
57
|
return (
|
|
@@ -45,6 +64,8 @@ export const ColourToggle = React.forwardRef(
|
|
|
45
64
|
colourName={colourName}
|
|
46
65
|
onPress={handleChangeColour}
|
|
47
66
|
showTooltip={showTooltips}
|
|
67
|
+
unavailable={unavailable}
|
|
68
|
+
isDisabled={!!disabled}
|
|
48
69
|
/>
|
|
49
70
|
)
|
|
50
71
|
})}
|
|
@@ -76,7 +97,9 @@ ColourToggle.propTypes = {
|
|
|
76
97
|
PropTypes.exact({
|
|
77
98
|
colourHexCode: PropTypes.string,
|
|
78
99
|
colourName: PropTypes.string,
|
|
79
|
-
id: PropTypes.string
|
|
100
|
+
id: PropTypes.string,
|
|
101
|
+
unavailable: PropTypes.oneOf(Object.values(UNAVAILABLE_VARIANT)),
|
|
102
|
+
disabled: PropTypes.bool
|
|
80
103
|
})
|
|
81
104
|
),
|
|
82
105
|
/**
|
|
@@ -86,5 +109,16 @@ ColourToggle.propTypes = {
|
|
|
86
109
|
/**
|
|
87
110
|
* When true, displays each colour's name as a tooltip on hover (web only).
|
|
88
111
|
*/
|
|
89
|
-
showTooltips: PropTypes.bool
|
|
112
|
+
showTooltips: PropTypes.bool,
|
|
113
|
+
/**
|
|
114
|
+
* Select English or French copy.
|
|
115
|
+
*/
|
|
116
|
+
copy: PropTypes.oneOf(['en', 'fr']),
|
|
117
|
+
/**
|
|
118
|
+
* Override default labels.
|
|
119
|
+
*/
|
|
120
|
+
dictionary: PropTypes.shape({
|
|
121
|
+
en: DICTIONARY_CONTENT_SHAPE,
|
|
122
|
+
fr: DICTIONARY_CONTENT_SHAPE
|
|
123
|
+
})
|
|
90
124
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
|
-
import { View, StyleSheet, Platform } from 'react-native'
|
|
3
|
+
import { View, StyleSheet, Platform, ScrollView } from 'react-native'
|
|
4
4
|
import { Portal } from '../Portal/Portal'
|
|
5
5
|
import { useThemeTokens } from '../ThemeProvider/useThemeTokens'
|
|
6
6
|
import { Card } from '../Card/Card'
|
|
@@ -69,7 +69,11 @@ const DropdownOverlay = React.forwardRef(
|
|
|
69
69
|
paddingRight: paddingHorizontal
|
|
70
70
|
}}
|
|
71
71
|
>
|
|
72
|
-
{
|
|
72
|
+
{Platform.OS !== 'web' ? (
|
|
73
|
+
<ScrollView style={{ maxHeight }}>{children}</ScrollView>
|
|
74
|
+
) : (
|
|
75
|
+
children
|
|
76
|
+
)}
|
|
73
77
|
</Card>
|
|
74
78
|
</View>
|
|
75
79
|
)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
import { View, StyleSheet, Platform } from 'react-native'
|
|
4
|
-
import { Portal } from '@gorhom/portal'
|
|
4
|
+
import { Portal as GorhomPortal } from '@gorhom/portal'
|
|
5
|
+
import { Portal as LocalPortal } from '../Portal/Portal'
|
|
5
6
|
import { useCopy } from '../utils/useCopy'
|
|
6
7
|
import { copyPropTypes } from '../utils/props/copyPropTypes'
|
|
7
8
|
import { getTokensPropType } from '../utils/props/tokens'
|
|
@@ -107,8 +108,13 @@ export const ModalOverlay = React.forwardRef(
|
|
|
107
108
|
const getCopy = useCopy({ dictionary, copy })
|
|
108
109
|
const closeLabel = getCopy('closeButton')
|
|
109
110
|
|
|
111
|
+
// On web, use the local Portal (always appends to document.body) to ensure correct
|
|
112
|
+
// absolute positioning in MFE/iframe contexts. @gorhom/portal may render its host
|
|
113
|
+
// outside the iframe's document, causing coordinate mismatches when scrolled.
|
|
114
|
+
const PortalComponent = Platform.OS === 'web' ? LocalPortal : GorhomPortal
|
|
115
|
+
|
|
110
116
|
return (
|
|
111
|
-
<
|
|
117
|
+
<PortalComponent>
|
|
112
118
|
<View
|
|
113
119
|
ref={containerRef}
|
|
114
120
|
onLayout={onLayout}
|
|
@@ -137,7 +143,7 @@ export const ModalOverlay = React.forwardRef(
|
|
|
137
143
|
{children}
|
|
138
144
|
</Card>
|
|
139
145
|
</View>
|
|
140
|
-
</
|
|
146
|
+
</PortalComponent>
|
|
141
147
|
)
|
|
142
148
|
}
|
|
143
149
|
)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
|
-
import { Portal } from '@gorhom/portal'
|
|
4
3
|
import { View, StyleSheet, Dimensions, SafeAreaView, Platform, ScrollView } from 'react-native'
|
|
5
4
|
import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider/useThemeTokens'
|
|
6
5
|
import { applyTextStyles } from '../ThemeProvider/utils/styles'
|
|
@@ -218,27 +217,11 @@ export const MultiSelectFilter = React.forwardRef(
|
|
|
218
217
|
onCancel()
|
|
219
218
|
}
|
|
220
219
|
|
|
221
|
-
const appRootRef = React.useRef(null)
|
|
222
|
-
const [rootOffsets, setRootOffsets] = React.useState(null)
|
|
223
|
-
|
|
224
|
-
React.useEffect(() => {
|
|
225
|
-
if (rootOffsets) return
|
|
226
|
-
appRootRef.current?.measureInWindow((x, y) => {
|
|
227
|
-
// Only set offsets if they are positive
|
|
228
|
-
// this is because we want to avoid negative offsets that could cause
|
|
229
|
-
// the dropdown to be positioned incorrectly in some situations
|
|
230
|
-
if (y > 0) setRootOffsets({ horizontal: x, vertical: y })
|
|
231
|
-
})
|
|
232
|
-
}, [isOpen, rootOffsets])
|
|
233
|
-
|
|
234
220
|
const { align, offsets } = useResponsiveProp({
|
|
235
221
|
xs: { align: { top: 'top', left: 'left' } },
|
|
236
222
|
sm: {
|
|
237
223
|
align: { top: 'bottom', left: 'left' },
|
|
238
|
-
offsets: {
|
|
239
|
-
vertical: 4 - (rootOffsets?.vertical || 0),
|
|
240
|
-
horizontal: -rootOffsets?.horizontal || 0
|
|
241
|
-
}
|
|
224
|
+
offsets: { vertical: 4 }
|
|
242
225
|
}
|
|
243
226
|
})
|
|
244
227
|
|
|
@@ -364,14 +347,6 @@ export const MultiSelectFilter = React.forwardRef(
|
|
|
364
347
|
|
|
365
348
|
return (
|
|
366
349
|
<>
|
|
367
|
-
{/*
|
|
368
|
-
This View is rendered inside a Portal to determine the application's root position.
|
|
369
|
-
Capturing it is crucial to determine offsets to position the Modal correctly, preventing
|
|
370
|
-
misalignment that can occur when the Portal does not render the Modal at the body level.
|
|
371
|
-
*/}
|
|
372
|
-
<Portal>
|
|
373
|
-
<View ref={appRootRef} style={styles.appRootRef} />
|
|
374
|
-
</Portal>
|
|
375
350
|
<ButtonDropdown
|
|
376
351
|
ref={sourceRef}
|
|
377
352
|
key={id}
|
|
@@ -460,11 +435,6 @@ const styles = StyleSheet.create({
|
|
|
460
435
|
},
|
|
461
436
|
scrollContainer: {
|
|
462
437
|
padding: 1
|
|
463
|
-
},
|
|
464
|
-
appRootRef: {
|
|
465
|
-
position: 'absolute',
|
|
466
|
-
top: 0,
|
|
467
|
-
left: 0
|
|
468
438
|
}
|
|
469
439
|
})
|
|
470
440
|
|
|
@@ -256,7 +256,8 @@ export const TextInputBase = React.forwardRef(
|
|
|
256
256
|
|
|
257
257
|
const handleChangeText = (event) => {
|
|
258
258
|
const text = event.nativeEvent?.text ?? event.target?.value
|
|
259
|
-
|
|
259
|
+
// Do NOT use `|| undefined`: empty string is falsy and would break the controlled contract
|
|
260
|
+
let filteredText = isNumeric ? text?.replace(/[^\d]/g, '') ?? '' : text
|
|
260
261
|
if (type === 'card' && filteredText) {
|
|
261
262
|
const formattedValue = filteredText.replace(/[^a-zA-Z0-9]/g, '')
|
|
262
263
|
const regex = new RegExp(`([a-zA-Z0-9]{4})(?=[a-zA-Z0-9])`, 'g')
|
|
@@ -205,7 +205,11 @@ export const Validator = React.forwardRef(
|
|
|
205
205
|
|
|
206
206
|
// Sync external value prop to internal state
|
|
207
207
|
React.useEffect(() => {
|
|
208
|
-
if (value
|
|
208
|
+
if (value === '') {
|
|
209
|
+
setCodes(Array(validatorsLength).fill(''))
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
if (Number(value).toString() !== 'NaN') {
|
|
209
213
|
const digits = value.split('').slice(0, validatorsLength)
|
|
210
214
|
const newCodes = Array(validatorsLength).fill('')
|
|
211
215
|
digits.forEach((digit, i) => {
|