@telus-uds/components-base 1.93.0 → 1.95.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 (101) hide show
  1. package/CHANGELOG.md +32 -3
  2. package/lib/Autocomplete/Autocomplete.js +2 -1
  3. package/lib/Button/ButtonGroup.js +17 -1
  4. package/lib/Card/Card.js +12 -0
  5. package/lib/Card/CardBase.js +37 -2
  6. package/lib/Carousel/Carousel.js +55 -13
  7. package/lib/Carousel/CarouselItem/CarouselItem.js +86 -12
  8. package/lib/DownloadApp/DownloadApp.js +168 -0
  9. package/lib/DownloadApp/dictionary.js +17 -0
  10. package/lib/DownloadApp/index.js +10 -0
  11. package/lib/Fieldset/FieldsetContainer.js +7 -2
  12. package/lib/Fieldset/FieldsetContainer.native.js +4 -1
  13. package/lib/FileUpload/FileUpload.js +336 -0
  14. package/lib/FileUpload/NotificationContent.js +60 -0
  15. package/lib/FileUpload/dictionary.js +47 -0
  16. package/lib/FileUpload/index.js +10 -0
  17. package/lib/Icon/IconText.js +19 -2
  18. package/lib/Link/LinkBase.js +2 -2
  19. package/lib/Link/TextButton.js +7 -17
  20. package/lib/Modal/Modal.js +1 -1
  21. package/lib/Modal/ModalContent.js +12 -6
  22. package/lib/MultiSelectFilter/ModalOverlay.js +49 -30
  23. package/lib/MultiSelectFilter/MultiSelectFilter.js +170 -131
  24. package/lib/Notification/Notification.js +11 -2
  25. package/lib/Status/Status.js +9 -4
  26. package/lib/TabBar/TabBar.js +133 -0
  27. package/lib/TabBar/TabBarItem.js +184 -0
  28. package/lib/TabBar/index.js +10 -0
  29. package/lib/TextInput/TextInputBase.js +2 -1
  30. package/lib/Tooltip/getTooltipPosition.js +8 -9
  31. package/lib/index.js +24 -0
  32. package/lib/utils/convertFromMegaByteToByte.js +16 -0
  33. package/lib/utils/formatImageSource.js +34 -0
  34. package/lib/utils/index.js +17 -1
  35. package/lib-module/Autocomplete/Autocomplete.js +2 -1
  36. package/lib-module/Button/ButtonGroup.js +17 -1
  37. package/lib-module/Card/Card.js +13 -1
  38. package/lib-module/Card/CardBase.js +38 -3
  39. package/lib-module/Carousel/Carousel.js +55 -13
  40. package/lib-module/Carousel/CarouselItem/CarouselItem.js +86 -12
  41. package/lib-module/DownloadApp/DownloadApp.js +160 -0
  42. package/lib-module/DownloadApp/dictionary.js +10 -0
  43. package/lib-module/DownloadApp/index.js +2 -0
  44. package/lib-module/Fieldset/FieldsetContainer.js +7 -2
  45. package/lib-module/Fieldset/FieldsetContainer.native.js +4 -1
  46. package/lib-module/FileUpload/FileUpload.js +329 -0
  47. package/lib-module/FileUpload/NotificationContent.js +55 -0
  48. package/lib-module/FileUpload/dictionary.js +40 -0
  49. package/lib-module/FileUpload/index.js +2 -0
  50. package/lib-module/Icon/IconText.js +19 -2
  51. package/lib-module/Link/LinkBase.js +2 -2
  52. package/lib-module/Link/TextButton.js +7 -17
  53. package/lib-module/Modal/Modal.js +1 -1
  54. package/lib-module/Modal/ModalContent.js +12 -6
  55. package/lib-module/MultiSelectFilter/ModalOverlay.js +49 -30
  56. package/lib-module/MultiSelectFilter/MultiSelectFilter.js +171 -132
  57. package/lib-module/Notification/Notification.js +11 -2
  58. package/lib-module/Status/Status.js +9 -4
  59. package/lib-module/TabBar/TabBar.js +125 -0
  60. package/lib-module/TabBar/TabBarItem.js +177 -0
  61. package/lib-module/TabBar/index.js +2 -0
  62. package/lib-module/TextInput/TextInputBase.js +2 -1
  63. package/lib-module/Tooltip/getTooltipPosition.js +8 -9
  64. package/lib-module/index.js +3 -0
  65. package/lib-module/utils/convertFromMegaByteToByte.js +10 -0
  66. package/lib-module/utils/formatImageSource.js +27 -0
  67. package/lib-module/utils/index.js +3 -1
  68. package/package.json +4 -3
  69. package/src/Autocomplete/Autocomplete.jsx +2 -1
  70. package/src/Button/ButtonGroup.jsx +9 -1
  71. package/src/Card/Card.jsx +18 -2
  72. package/src/Card/CardBase.jsx +47 -12
  73. package/src/Carousel/Carousel.jsx +59 -13
  74. package/src/Carousel/CarouselItem/CarouselItem.jsx +94 -9
  75. package/src/DownloadApp/DownloadApp.jsx +165 -0
  76. package/src/DownloadApp/dictionary.js +10 -0
  77. package/src/DownloadApp/index.js +3 -0
  78. package/src/Fieldset/FieldsetContainer.jsx +4 -3
  79. package/src/Fieldset/FieldsetContainer.native.jsx +9 -6
  80. package/src/FileUpload/FileUpload.jsx +396 -0
  81. package/src/FileUpload/NotificationContent.jsx +44 -0
  82. package/src/FileUpload/dictionary.js +40 -0
  83. package/src/FileUpload/index.js +3 -0
  84. package/src/Icon/IconText.jsx +21 -4
  85. package/src/Link/LinkBase.jsx +2 -2
  86. package/src/Link/TextButton.jsx +10 -17
  87. package/src/Modal/Modal.jsx +1 -1
  88. package/src/Modal/ModalContent.jsx +8 -3
  89. package/src/MultiSelectFilter/ModalOverlay.jsx +44 -18
  90. package/src/MultiSelectFilter/MultiSelectFilter.jsx +188 -126
  91. package/src/Notification/Notification.jsx +12 -4
  92. package/src/Status/Status.jsx +15 -4
  93. package/src/TabBar/TabBar.jsx +123 -0
  94. package/src/TabBar/TabBarItem.jsx +149 -0
  95. package/src/TabBar/index.js +3 -0
  96. package/src/TextInput/TextInputBase.jsx +1 -1
  97. package/src/Tooltip/getTooltipPosition.js +11 -12
  98. package/src/index.js +3 -0
  99. package/src/utils/convertFromMegaByteToByte.js +11 -0
  100. package/src/utils/formatImageSource.js +29 -0
  101. package/src/utils/index.js +2 -0
@@ -1,6 +1,6 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { View, StyleSheet } from 'react-native'
3
+ import { View, StyleSheet, Platform } from 'react-native'
4
4
  import { Portal } from '@gorhom/portal'
5
5
  import { useCopy, copyPropTypes, getTokensPropType, variantProp } from '../utils'
6
6
  import { useViewport } from '../ViewportProvider'
@@ -13,8 +13,26 @@ import IconButton from '../IconButton'
13
13
  const staticStyles = StyleSheet.create({
14
14
  positioner: {
15
15
  flex: 1, // Grow to maxWidth when possible, shrink when not possible
16
- position: 'absolute',
17
- zIndex: 10000 // Position on top of all the other overlays, including backdrops and modals
16
+ zIndex: 10000, // Position on top of all the other overlays, including backdrops and modals,
17
+ elevation: 10000, // Position on top of all the other overlays, including backdrops and modals,
18
+ borderRadius: 4,
19
+ ...Platform.select({
20
+ web: {
21
+ boxShadow: 'rgba(0, 0, 0, 0.1) 0px 4px 8px 0px'
22
+ },
23
+ default: {
24
+ shadowColor: 'rgba(0, 0, 0, 0.1)',
25
+ shadowOffset: { width: 0, height: 4 },
26
+ shadowOpacity: 1,
27
+ shadowRadius: 8
28
+ }
29
+ })
30
+ },
31
+ card: {
32
+ paddingLeft: 0,
33
+ paddingRight: 0,
34
+ paddingTop: 0,
35
+ paddingBottom: 0
18
36
  },
19
37
  closeButtonContainer: {
20
38
  position: 'absolute',
@@ -29,18 +47,23 @@ const staticStyles = StyleSheet.create({
29
47
  }
30
48
  })
31
49
 
50
+ const selectContainerStyle = (enableFullscreen, themeTokens) => ({
51
+ borderColor: themeTokens.borderColor,
52
+ ...Platform.select({
53
+ web: {
54
+ position: enableFullscreen ? 'fixed' : 'absolute'
55
+ },
56
+ default: {
57
+ position: 'absolute'
58
+ }
59
+ })
60
+ })
61
+
32
62
  const selectCloseButtonContainerStyles = ({ paddingRight, paddingTop }) => ({
33
63
  paddingRight,
34
64
  paddingTop
35
65
  })
36
66
 
37
- const selectPaddingContainerStyles = ({ paddingTop, paddingLeft, paddingRight }) => ({
38
- paddingBottom: 35,
39
- paddingTop,
40
- paddingLeft,
41
- paddingRight
42
- })
43
-
44
67
  const ModalOverlay = React.forwardRef(
45
68
  (
46
69
  {
@@ -56,17 +79,18 @@ const ModalOverlay = React.forwardRef(
56
79
  variant,
57
80
  tokens,
58
81
  copy,
59
- onClose
82
+ onClose,
83
+ enableFullscreen = false
60
84
  },
61
85
  ref
62
86
  ) => {
63
87
  const viewport = useViewport()
64
88
  const themeTokens = useThemeTokens('Modal', tokens, variant, { viewport, maxWidth: false })
65
89
  const containerWidthHeight = {
66
- minWidth,
67
- minHeight,
68
- ...(tokens.maxWidth && maxWidthSize && { maxWidth: maxWidthSize }),
69
- ...(maxHeight && maxHeightSize && { maxHeight: maxHeightSize })
90
+ minWidth: tokens.maxWidth ? maxWidthSize : minWidth,
91
+ minHeight: maxHeight ? maxHeightSize : minHeight,
92
+ maxWidth: maxWidthSize,
93
+ maxHeight: maxHeightSize
70
94
  }
71
95
 
72
96
  const { closeIcon: CloseIconComponent } = themeTokens
@@ -83,10 +107,11 @@ const ModalOverlay = React.forwardRef(
83
107
  overlaidPosition,
84
108
  containerWidthHeight,
85
109
  staticStyles.positioner,
86
- !isReady && staticStyles.hidden
110
+ !isReady && staticStyles.hidden,
111
+ selectContainerStyle(enableFullscreen, themeTokens)
87
112
  ]}
88
113
  >
89
- <Card tokens={selectPaddingContainerStyles(themeTokens)}>
114
+ <Card tokens={staticStyles.card}>
90
115
  <View
91
116
  style={[
92
117
  staticStyles.closeButtonContainer,
@@ -127,7 +152,8 @@ ModalOverlay.propTypes = {
127
152
  variant: variantProp.propType,
128
153
  tokens: getTokensPropType('Modal'),
129
154
  copy: copyPropTypes,
130
- onClose: PropTypes.func
155
+ onClose: PropTypes.func,
156
+ enableFullscreen: PropTypes.bool
131
157
  }
132
158
 
133
159
  export default ModalOverlay
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
 
4
- import { View, StyleSheet } from 'react-native'
4
+ import { View, StyleSheet, Dimensions, SafeAreaView, Platform, ScrollView } from 'react-native'
5
5
  import { useThemeTokens, useThemeTokensCallback, applyTextStyles } from '../ThemeProvider'
6
6
  import {
7
7
  containUniqueFields,
@@ -12,7 +12,8 @@ import {
12
12
  useCopy,
13
13
  useMultipleInputValues,
14
14
  useResponsiveProp,
15
- variantProp
15
+ variantProp,
16
+ useScrollBlocking
16
17
  } from '../utils'
17
18
  import defaultDictionary from './dictionary'
18
19
  import { useViewport } from '../ViewportProvider'
@@ -26,7 +27,6 @@ import StackView from '../StackView'
26
27
  import Typography from '../Typography'
27
28
  import { TextButton } from '../Link'
28
29
  import ModalOverlay from './ModalOverlay'
29
- import Modal from '../Modal'
30
30
 
31
31
  const { Col, Row } = FlexGrid
32
32
 
@@ -34,13 +34,47 @@ const selectSubTitleTokens = ({ subtitleColor }) => ({
34
34
  color: subtitleColor
35
35
  })
36
36
 
37
- const selectDividerToknes = ({ dividerColor, width, decorative = true, weight = 'thin' }) => ({
38
- color: dividerColor,
39
- width,
40
- decorative,
41
- weight
37
+ const selectDividerTokens = ({ dividerColor }) => ({
38
+ color: dividerColor
42
39
  })
43
40
 
41
+ const selectHeaderTokens = ({
42
+ contentMarginLeft,
43
+ contentMarginRight,
44
+ contentMarginTop,
45
+ contentPaddingLeft,
46
+ contentPaddingRight
47
+ }) => ({
48
+ marginLeft: contentMarginLeft,
49
+ marginRight: contentMarginRight,
50
+ marginTop: contentMarginTop,
51
+ paddingLeft: contentPaddingLeft,
52
+ paddingRight: contentPaddingRight,
53
+ flexGrow: 1
54
+ })
55
+
56
+ const selectControlsTokens = ({
57
+ contentMarginBottom,
58
+ contentMarginLeft,
59
+ contentMarginRight,
60
+ contentPaddingLeft,
61
+ contentPaddingRight
62
+ }) => ({
63
+ marginBottom: contentMarginBottom,
64
+ marginLeft: contentMarginLeft,
65
+ marginRight: contentMarginRight,
66
+ paddingLeft: contentPaddingLeft,
67
+ paddingRight: contentPaddingRight
68
+ })
69
+
70
+ const selectContainerStyle = (windowHeight, windowWidth) => ({
71
+ height: windowHeight,
72
+ width: windowWidth
73
+ })
74
+
75
+ const TOTAL_COLUMNS = 12
76
+ const MAX_ITEMS_THRESHOLD = 12
77
+
44
78
  const MultiSelectFilter = React.forwardRef(
45
79
  (
46
80
  {
@@ -108,7 +142,8 @@ const MultiSelectFilter = React.forwardRef(
108
142
  maxWidthSize,
109
143
  subHeaderLineHeight,
110
144
  minHeight,
111
- minWidth
145
+ minWidth,
146
+ ...restTokens
112
147
  } = useThemeTokens(
113
148
  'MultiSelectFilter',
114
149
  tokens,
@@ -173,6 +208,105 @@ const MultiSelectFilter = React.forwardRef(
173
208
  align
174
209
  })
175
210
 
211
+ const [isScrolling, setIsScrolling] = React.useState(false)
212
+ const [scrollViewHeight, setScrollViewHeight] = React.useState(0)
213
+ const [rowHeight, setRowHeight] = React.useState(0)
214
+ const modalRef = useScrollBlocking(isOpen)
215
+ const windowWidth = Dimensions.get('window').width
216
+ const windowHeight = Dimensions.get('window').height
217
+
218
+ React.useEffect(() => {
219
+ if (rowHeight > scrollViewHeight) {
220
+ setIsScrolling(true)
221
+ } else {
222
+ setIsScrolling(false)
223
+ }
224
+ }, [scrollViewHeight, rowHeight])
225
+
226
+ const handleScrollViewLayout = (event) => {
227
+ const { height } = event.nativeEvent.layout
228
+ setScrollViewHeight(height)
229
+ }
230
+
231
+ const handleRowLayout = (event) => {
232
+ const { height } = event.nativeEvent.layout
233
+ setRowHeight(height)
234
+ }
235
+
236
+ const headerContent = (
237
+ <View style={[selectHeaderTokens(restTokens), styles.container]}>
238
+ <Row>
239
+ <View>
240
+ <Typography tokens={{ ...headerStyles, lineHeight: headerLineHeight }}>
241
+ {getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())}
242
+ </Typography>
243
+ </View>
244
+ </Row>
245
+ {subtitle && (
246
+ <>
247
+ <Spacer space={4} />
248
+ <Row>
249
+ <Typography tokens={{ ...subeHeaderStyles, lineHeight: subHeaderLineHeight }}>
250
+ {subtitle}
251
+ </Typography>
252
+ </Row>
253
+ <Spacer space={4} />
254
+ </>
255
+ )}
256
+ <View style={styles.options}>
257
+ <ScrollView onLayout={handleScrollViewLayout}>
258
+ <Row distribute="between" onLayout={handleRowLayout}>
259
+ {[...Array(colSize).keys()].map((i) => (
260
+ <Col xs={TOTAL_COLUMNS / colSize} key={i}>
261
+ <CheckboxGroup
262
+ items={items.slice(i * rowLength, (i + 1) * rowLength)}
263
+ checkedIds={checkedIds}
264
+ onChange={(e) => setCheckedIds(e, i)}
265
+ />
266
+ <Spacer size={4} />
267
+ </Col>
268
+ ))}
269
+ </Row>
270
+ </ScrollView>
271
+ </View>
272
+ </View>
273
+ )
274
+
275
+ const controlsContent = (
276
+ <>
277
+ {isScrolling ? (
278
+ <Divider tokens={selectDividerTokens(themeTokens)} space={4} />
279
+ ) : (
280
+ <Spacer space={4} />
281
+ )}
282
+ <View style={selectControlsTokens(restTokens)}>
283
+ <Row horizontalAlign={buttonDirection === 'column' ? 'center' : 'start'}>
284
+ <StackView
285
+ direction={buttonDirection}
286
+ space={3}
287
+ tokens={{
288
+ alignItems: 'center',
289
+ ...(viewport === 'xs' && { flexGrow: 1 })
290
+ }}
291
+ >
292
+ <Button
293
+ onPress={() => onApply(checkedIds)}
294
+ variant={{
295
+ priority: 'high',
296
+ ...(viewport === 'xs' && { width: 'full' })
297
+ }}
298
+ >
299
+ {getCopy('applyButtonLabel')}
300
+ </Button>
301
+ <Box>
302
+ <TextButton onPress={onClear}>{getCopy('clearButtonLabel')}</TextButton>
303
+ </Box>
304
+ </StackView>
305
+ </Row>
306
+ </View>
307
+ </>
308
+ )
309
+
176
310
  return (
177
311
  <>
178
312
  <ButtonDropdown
@@ -187,139 +321,53 @@ const MultiSelectFilter = React.forwardRef(
187
321
  inactive={inactive}
188
322
  />
189
323
  {isOpen && viewport === 'xs' && (
190
- <Modal isOpen={isOpen} onClose={onClose} ref={ref}>
191
- <Row>
192
- <Typography tokens={{ ...headerStyles, lineHeight: headerLineHeight }}>
193
- {getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())}
194
- </Typography>
195
- </Row>
196
- {subtitle && (
197
- <>
198
- <Spacer space={5} />
199
- <Row>
200
- <Typography tokens={{ ...subeHeaderStyles, lineHeight: subHeaderLineHeight }}>
201
- {subtitle}
202
- </Typography>
203
- </Row>
204
- </>
205
- )}
206
- <Spacer space={4} />
207
- <Box scroll={true}>
208
- <Row distribute="between">
209
- {[...Array(colSize).keys()].map((i) => (
210
- <Col xs={12 / colSize} key={i}>
211
- <CheckboxGroup
212
- items={items.slice(i * rowLength, (i + 1) * rowLength)}
213
- checkedIds={checkedIds}
214
- onChange={(e) => setCheckedIds(e, i)}
215
- />
216
- <Spacer size={4} />
217
- </Col>
218
- ))}
219
- </Row>
220
- </Box>
221
- <Divider variant={selectDividerToknes({ ...themeTokens, width: 'full' })} space={4} />
222
- <Row horizontalAlign={buttonDirection === 'column' ? 'center' : 'start'}>
223
- <StackView
224
- direction={buttonDirection}
225
- space={3}
226
- tokens={{
227
- alignItems: 'center',
228
- ...(viewport === 'xs' && { flexGrow: 1 })
229
- }}
230
- >
231
- <Button
232
- onPress={() => onApply(checkedIds)}
233
- variant={{
234
- size: 'small',
235
- priority: 'high',
236
- ...(viewport === 'xs' && { width: 'full' })
237
- }}
238
- >
239
- {getCopy('applyButtonLabel')}
240
- </Button>
241
- <Box>
242
- <TextButton onPress={onClear}>{getCopy('clearButtonLabel')}</TextButton>
243
- </Box>
244
- </StackView>
245
- </Row>
246
- </Modal>
324
+ <ModalOverlay
325
+ overlaidPosition={{ top: 0, left: 0 }}
326
+ onClose={onClose}
327
+ maxHeight={true}
328
+ maxHeightSize={windowHeight}
329
+ maxWidthSize={windowWidth}
330
+ minHeight={windowHeight}
331
+ minWidth={windowWidth}
332
+ tokens={{
333
+ ...tokens,
334
+ maxWidth: true
335
+ }}
336
+ copy={copy}
337
+ isReady={isReady}
338
+ onLayout={onTargetLayout}
339
+ ref={modalRef}
340
+ enableFullscreen
341
+ >
342
+ <SafeAreaView
343
+ style={[selectContainerStyle(windowHeight, windowWidth), styles.content]}
344
+ ref={ref}
345
+ >
346
+ {headerContent}
347
+ <View style={styles.controls}>{controlsContent}</View>
348
+ </SafeAreaView>
349
+ </ModalOverlay>
247
350
  )}
248
351
  {isOpen && viewport !== 'xs' && (
249
352
  <ModalOverlay
250
353
  overlaidPosition={overlaidPosition}
251
354
  onClose={onClose}
252
- maxHeight={maxHeight}
355
+ maxHeight={items.length > MAX_ITEMS_THRESHOLD ? true : maxHeight}
253
356
  maxHeightSize={maxHeightSize}
254
357
  maxWidthSize={maxWidthSize}
255
358
  minHeight={minHeight}
256
359
  minWidth={minWidth}
257
360
  tokens={{
258
361
  ...tokens,
259
- maxWidth
362
+ maxWidth: items.length > MAX_ITEMS_THRESHOLD ? true : maxWidth
260
363
  }}
261
364
  copy={copy}
262
365
  isReady={isReady}
263
366
  onLayout={onTargetLayout}
264
367
  ref={ref}
265
368
  >
266
- <Row>
267
- <View style={styles.textContainerStyle}>
268
- <Typography tokens={{ ...headerStyles, lineHeight: headerLineHeight }}>
269
- {getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())}
270
- </Typography>
271
- </View>
272
- </Row>
273
- {subtitle && (
274
- <>
275
- <Spacer space={5} />
276
- <Row>
277
- <Typography tokens={{ ...subeHeaderStyles, lineHeight: subHeaderLineHeight }}>
278
- {subtitle}
279
- </Typography>
280
- </Row>
281
- </>
282
- )}
283
- <Spacer space={4} />
284
- <Box scroll={true}>
285
- <Row distribute="between">
286
- {[...Array(colSize).keys()].map((i) => (
287
- <Col xs={12 / colSize} key={i}>
288
- <CheckboxGroup
289
- items={items.slice(i * rowLength, (i + 1) * rowLength)}
290
- checkedIds={checkedIds}
291
- onChange={(e) => setCheckedIds(e, i)}
292
- />
293
- <Spacer size={4} />
294
- </Col>
295
- ))}
296
- </Row>
297
- </Box>
298
- <Divider variant={selectDividerToknes({ ...themeTokens, width: 'full' })} space={4} />
299
- <Row horizontalAlign={buttonDirection === 'column' ? 'center' : 'start'}>
300
- <StackView
301
- direction={buttonDirection}
302
- space={3}
303
- tokens={{
304
- alignItems: 'center',
305
- ...(viewport === 'xs' && { flexGrow: 1 })
306
- }}
307
- >
308
- <Button
309
- onPress={() => onApply(checkedIds)}
310
- variant={{
311
- size: 'small',
312
- priority: 'high',
313
- ...(viewport === 'xs' && { width: 'full' })
314
- }}
315
- >
316
- {getCopy('applyButtonLabel')}
317
- </Button>
318
- <Box>
319
- <TextButton onPress={onClear}>{getCopy('clearButtonLabel')}</TextButton>
320
- </Box>
321
- </StackView>
322
- </Row>
369
+ {headerContent}
370
+ {controlsContent}
323
371
  </ModalOverlay>
324
372
  )}
325
373
  </>
@@ -330,7 +378,21 @@ const MultiSelectFilter = React.forwardRef(
330
378
  MultiSelectFilter.displayName = 'MultiSelectFilter'
331
379
 
332
380
  const styles = StyleSheet.create({
333
- textContainerStyle: { marginRight: 52 }
381
+ container: { flex: 1 },
382
+ controls: Platform.select({
383
+ web: {},
384
+ default: {
385
+ flex: 0.35
386
+ }
387
+ }),
388
+ content: {
389
+ flex: 1,
390
+ justifyContent: 'space-between',
391
+ backgroundColor: 'transparent'
392
+ },
393
+ options: {
394
+ flex: 1
395
+ }
334
396
  })
335
397
 
336
398
  // If a language dictionary entry is provided, it must contain every key
@@ -1,5 +1,5 @@
1
1
  import React from 'react'
2
- import { View } from 'react-native'
2
+ import { View, Platform } from 'react-native'
3
3
 
4
4
  import PropTypes from 'prop-types'
5
5
  import {
@@ -162,7 +162,8 @@ const getMediaQueryStyles = (
162
162
  const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible, viewport, system) => ({
163
163
  containerStyles: {
164
164
  container: {
165
- flexDirection: system === true && viewport === 'xl' ? 'row' : 'inherit',
165
+ flexDirection:
166
+ (system === true && viewport === 'xl') || Platform.OS === 'android' ? 'row' : 'inherit',
166
167
  ...selectContainerStyles(themeTokens)
167
168
  }
168
169
  },
@@ -241,7 +242,7 @@ const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible, view
241
242
  * Show system notifications at the top of the page, below the navigation, and expands the full-width of the viewport
242
243
  */
243
244
  const Notification = React.forwardRef(
244
- ({ children, system, dismissible, copy = 'en', tokens, variant, ...rest }, ref) => {
245
+ ({ children, system, dismissible, copy = 'en', tokens, variant, onDismiss, ...rest }, ref) => {
245
246
  const [isDismissed, setIsDismissed] = React.useState(false)
246
247
  const viewport = useViewport()
247
248
  const getCopy = useCopy({ dictionary, copy })
@@ -310,7 +311,10 @@ const Notification = React.forwardRef(
310
311
  dismissIconColor
311
312
  } = enableMediaQueryStyleSheet === false ? themeTokens : themeTokens[viewport]
312
313
 
313
- const onDismissPress = () => setIsDismissed(true)
314
+ const onDismissPress = () => {
315
+ setIsDismissed(true)
316
+ onDismiss?.()
317
+ }
314
318
 
315
319
  return (
316
320
  <View
@@ -407,6 +411,10 @@ Notification.propTypes = {
407
411
  PropTypes.oneOf(['en', 'fr']),
408
412
  PropTypes.shape({ dismiss: PropTypes.string })
409
413
  ]),
414
+ /**
415
+ * Callback function called when the dismiss button is clicked
416
+ */
417
+ onDismiss: PropTypes.func,
410
418
  tokens: getTokensPropType('Notification'),
411
419
  variant: variantProp.propType
412
420
  }
@@ -63,14 +63,21 @@ const selectIconProps = ({ icon, iconColor }) => ({
63
63
  variant: { size: 'small' }
64
64
  })
65
65
 
66
- const selectTextStyles = ({ textColor, textLineHeight, fontName, fontSize, fontWeight }) =>
66
+ const selectTextStyles = ({
67
+ textColor,
68
+ textLineHeight,
69
+ fontName,
70
+ fontSize,
71
+ fontWeight,
72
+ marginLeft
73
+ }) =>
67
74
  applyTextStyles({
68
75
  fontColor: textColor,
69
76
  fontName,
70
77
  fontSize,
71
78
  fontWeight,
72
79
  lineHeight: Platform.OS === 'web' ? textLineHeight : textLineHeight * 1.2,
73
- marginLeft: 8
80
+ marginLeft
74
81
  })
75
82
 
76
83
  /**
@@ -81,18 +88,22 @@ const selectTextStyles = ({ textColor, textLineHeight, fontName, fontSize, fontW
81
88
  * @param {string} variant - The variant of the status component.
82
89
  * @param {ReactNode} children - The content to be displayed inside the status component.
83
90
  * @param {function} customGradient - The custom gradient function for the status component.
91
+ * @param {elementType} customGradient - Defines an icon to be rendered.
84
92
  * @param {object} rest - The rest of the props to be applied to the status component.
85
93
  * @param {React.Ref} ref - The ref to be applied to the status component.
86
94
  * @returns {ReactNode} The rendered status component.
87
95
  */
88
96
  const Status = React.forwardRef(({ tokens, variant, children, customGradient, ...rest }, ref) => {
89
97
  const themeTokens = useThemeTokens('Status', tokens, variant)
98
+ const { icon } = themeTokens
90
99
  const containerStyles = { ...selectContainerStyles(themeTokens), ...staticStyles.container }
91
100
 
92
101
  let content = (
93
102
  <>
94
- <Icon {...selectIconProps(themeTokens)} />
95
- {wrapStringsInText(children, { style: selectTextStyles(themeTokens) })}
103
+ {icon ? <Icon {...selectIconProps(themeTokens)} /> : null}
104
+ {wrapStringsInText(children, {
105
+ style: selectTextStyles(themeTokens)
106
+ })}
96
107
  </>
97
108
  )
98
109
  if (typeof customGradient === 'function') {