@telus-uds/components-base 1.92.0 → 1.94.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 (68) hide show
  1. package/CHANGELOG.md +21 -2
  2. package/lib/A11yText/index.js +7 -2
  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/Fieldset/FieldsetContainer.js +7 -2
  9. package/lib/Fieldset/FieldsetContainer.native.js +4 -1
  10. package/lib/FileUpload/FileUpload.js +336 -0
  11. package/lib/FileUpload/NotificationContent.js +60 -0
  12. package/lib/FileUpload/dictionary.js +47 -0
  13. package/lib/FileUpload/index.js +10 -0
  14. package/lib/Link/TextButton.js +7 -17
  15. package/lib/Modal/ModalContent.js +12 -6
  16. package/lib/MultiSelectFilter/ModalOverlay.js +49 -30
  17. package/lib/MultiSelectFilter/MultiSelectFilter.js +170 -131
  18. package/lib/Notification/Notification.js +11 -2
  19. package/lib/Status/Status.js +9 -4
  20. package/lib/index.js +8 -0
  21. package/lib/utils/convertFromMegaByteToByte.js +16 -0
  22. package/lib/utils/formatImageSource.js +34 -0
  23. package/lib/utils/index.js +17 -1
  24. package/lib-module/A11yText/index.js +7 -2
  25. package/lib-module/Button/ButtonGroup.js +17 -1
  26. package/lib-module/Card/Card.js +13 -1
  27. package/lib-module/Card/CardBase.js +38 -3
  28. package/lib-module/Carousel/Carousel.js +55 -13
  29. package/lib-module/Carousel/CarouselItem/CarouselItem.js +86 -12
  30. package/lib-module/Fieldset/FieldsetContainer.js +7 -2
  31. package/lib-module/Fieldset/FieldsetContainer.native.js +4 -1
  32. package/lib-module/FileUpload/FileUpload.js +329 -0
  33. package/lib-module/FileUpload/NotificationContent.js +55 -0
  34. package/lib-module/FileUpload/dictionary.js +40 -0
  35. package/lib-module/FileUpload/index.js +2 -0
  36. package/lib-module/Link/TextButton.js +7 -17
  37. package/lib-module/Modal/ModalContent.js +12 -6
  38. package/lib-module/MultiSelectFilter/ModalOverlay.js +49 -30
  39. package/lib-module/MultiSelectFilter/MultiSelectFilter.js +171 -132
  40. package/lib-module/Notification/Notification.js +11 -2
  41. package/lib-module/Status/Status.js +9 -4
  42. package/lib-module/index.js +1 -0
  43. package/lib-module/utils/convertFromMegaByteToByte.js +10 -0
  44. package/lib-module/utils/formatImageSource.js +27 -0
  45. package/lib-module/utils/index.js +3 -1
  46. package/package.json +4 -3
  47. package/src/A11yText/index.jsx +7 -3
  48. package/src/Button/ButtonGroup.jsx +9 -1
  49. package/src/Card/Card.jsx +18 -2
  50. package/src/Card/CardBase.jsx +47 -12
  51. package/src/Carousel/Carousel.jsx +59 -13
  52. package/src/Carousel/CarouselItem/CarouselItem.jsx +94 -9
  53. package/src/Fieldset/FieldsetContainer.jsx +4 -3
  54. package/src/Fieldset/FieldsetContainer.native.jsx +9 -6
  55. package/src/FileUpload/FileUpload.jsx +396 -0
  56. package/src/FileUpload/NotificationContent.jsx +44 -0
  57. package/src/FileUpload/dictionary.js +40 -0
  58. package/src/FileUpload/index.js +3 -0
  59. package/src/Link/TextButton.jsx +10 -17
  60. package/src/Modal/ModalContent.jsx +8 -3
  61. package/src/MultiSelectFilter/ModalOverlay.jsx +44 -18
  62. package/src/MultiSelectFilter/MultiSelectFilter.jsx +188 -126
  63. package/src/Notification/Notification.jsx +12 -4
  64. package/src/Status/Status.jsx +15 -4
  65. package/src/index.js +1 -0
  66. package/src/utils/convertFromMegaByteToByte.js +11 -0
  67. package/src/utils/formatImageSource.js +29 -0
  68. package/src/utils/index.js +2 -0
@@ -2,8 +2,12 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import View from "react-native-web/dist/exports/View";
4
4
  import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
+ import Dimensions from "react-native-web/dist/exports/Dimensions";
6
+ import SafeAreaView from "react-native-web/dist/exports/SafeAreaView";
7
+ import Platform from "react-native-web/dist/exports/Platform";
8
+ import ScrollView from "react-native-web/dist/exports/ScrollView";
5
9
  import { useThemeTokens, useThemeTokensCallback, applyTextStyles } from '../ThemeProvider';
6
- import { containUniqueFields, getTokensPropType, getPressHandlersWithArgs, selectTokens, useOverlaidPosition, useCopy, useMultipleInputValues, useResponsiveProp, variantProp } from '../utils';
10
+ import { containUniqueFields, getTokensPropType, getPressHandlersWithArgs, selectTokens, useOverlaidPosition, useCopy, useMultipleInputValues, useResponsiveProp, variantProp, useScrollBlocking } from '../utils';
7
11
  import defaultDictionary from './dictionary';
8
12
  import { useViewport } from '../ViewportProvider';
9
13
  import Box from '../Box';
@@ -16,7 +20,6 @@ import StackView from '../StackView';
16
20
  import Typography from '../Typography';
17
21
  import { TextButton } from '../Link';
18
22
  import ModalOverlay from './ModalOverlay';
19
- import Modal from '../Modal';
20
23
  import { jsx as _jsx } from "react/jsx-runtime";
21
24
  import { Fragment as _Fragment } from "react/jsx-runtime";
22
25
  import { jsxs as _jsxs } from "react/jsx-runtime";
@@ -32,21 +35,54 @@ const selectSubTitleTokens = _ref => {
32
35
  color: subtitleColor
33
36
  };
34
37
  };
35
- const selectDividerToknes = _ref2 => {
38
+ const selectDividerTokens = _ref2 => {
36
39
  let {
37
- dividerColor,
38
- width,
39
- decorative = true,
40
- weight = 'thin'
40
+ dividerColor
41
41
  } = _ref2;
42
42
  return {
43
- color: dividerColor,
44
- width,
45
- decorative,
46
- weight
43
+ color: dividerColor
47
44
  };
48
45
  };
49
- const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
46
+ const selectHeaderTokens = _ref3 => {
47
+ let {
48
+ contentMarginLeft,
49
+ contentMarginRight,
50
+ contentMarginTop,
51
+ contentPaddingLeft,
52
+ contentPaddingRight
53
+ } = _ref3;
54
+ return {
55
+ marginLeft: contentMarginLeft,
56
+ marginRight: contentMarginRight,
57
+ marginTop: contentMarginTop,
58
+ paddingLeft: contentPaddingLeft,
59
+ paddingRight: contentPaddingRight,
60
+ flexGrow: 1
61
+ };
62
+ };
63
+ const selectControlsTokens = _ref4 => {
64
+ let {
65
+ contentMarginBottom,
66
+ contentMarginLeft,
67
+ contentMarginRight,
68
+ contentPaddingLeft,
69
+ contentPaddingRight
70
+ } = _ref4;
71
+ return {
72
+ marginBottom: contentMarginBottom,
73
+ marginLeft: contentMarginLeft,
74
+ marginRight: contentMarginRight,
75
+ paddingLeft: contentPaddingLeft,
76
+ paddingRight: contentPaddingRight
77
+ };
78
+ };
79
+ const selectContainerStyle = (windowHeight, windowWidth) => ({
80
+ height: windowHeight,
81
+ width: windowWidth
82
+ });
83
+ const TOTAL_COLUMNS = 12;
84
+ const MAX_ITEMS_THRESHOLD = 12;
85
+ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
50
86
  let {
51
87
  label,
52
88
  subtitle,
@@ -68,7 +104,7 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
68
104
  rowLimit = 12,
69
105
  dictionary = defaultDictionary,
70
106
  ...rest
71
- } = _ref3;
107
+ } = _ref5;
72
108
  const viewport = useViewport();
73
109
  const {
74
110
  currentValues,
@@ -112,7 +148,8 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
112
148
  maxWidthSize,
113
149
  subHeaderLineHeight,
114
150
  minHeight,
115
- minWidth
151
+ minWidth,
152
+ ...restTokens
116
153
  } = useThemeTokens('MultiSelectFilter', tokens, {
117
154
  ...variant,
118
155
  maxHeight,
@@ -190,21 +227,35 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
190
227
  offsets,
191
228
  align
192
229
  });
193
- return /*#__PURE__*/_jsxs(_Fragment, {
194
- children: [/*#__PURE__*/_jsx(ButtonDropdown, {
195
- ref: sourceRef,
196
- ...pressHandlers,
197
- value: isOpen,
198
- selected: isSelected,
199
- label: label,
200
- onChange: handleChange,
201
- tokens: getButtonTokens,
202
- inactive: inactive
203
- }, id), isOpen && viewport === 'xs' && /*#__PURE__*/_jsxs(Modal, {
204
- isOpen: isOpen,
205
- onClose: onClose,
206
- ref: ref,
207
- children: [/*#__PURE__*/_jsx(Row, {
230
+ const [isScrolling, setIsScrolling] = React.useState(false);
231
+ const [scrollViewHeight, setScrollViewHeight] = React.useState(0);
232
+ const [rowHeight, setRowHeight] = React.useState(0);
233
+ const modalRef = useScrollBlocking(isOpen);
234
+ const windowWidth = Dimensions.get('window').width;
235
+ const windowHeight = Dimensions.get('window').height;
236
+ React.useEffect(() => {
237
+ if (rowHeight > scrollViewHeight) {
238
+ setIsScrolling(true);
239
+ } else {
240
+ setIsScrolling(false);
241
+ }
242
+ }, [scrollViewHeight, rowHeight]);
243
+ const handleScrollViewLayout = event => {
244
+ const {
245
+ height
246
+ } = event.nativeEvent.layout;
247
+ setScrollViewHeight(height);
248
+ };
249
+ const handleRowLayout = event => {
250
+ const {
251
+ height
252
+ } = event.nativeEvent.layout;
253
+ setRowHeight(height);
254
+ };
255
+ const headerContent = /*#__PURE__*/_jsxs(View, {
256
+ style: [selectHeaderTokens(restTokens), styles.container],
257
+ children: [/*#__PURE__*/_jsx(Row, {
258
+ children: /*#__PURE__*/_jsx(View, {
208
259
  children: /*#__PURE__*/_jsx(Typography, {
209
260
  tokens: {
210
261
  ...headerStyles,
@@ -212,26 +263,30 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
212
263
  },
213
264
  children: getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())
214
265
  })
215
- }), subtitle && /*#__PURE__*/_jsxs(_Fragment, {
216
- children: [/*#__PURE__*/_jsx(Spacer, {
217
- space: 5
218
- }), /*#__PURE__*/_jsx(Row, {
219
- children: /*#__PURE__*/_jsx(Typography, {
220
- tokens: {
221
- ...subeHeaderStyles,
222
- lineHeight: subHeaderLineHeight
223
- },
224
- children: subtitle
225
- })
226
- })]
266
+ })
267
+ }), subtitle && /*#__PURE__*/_jsxs(_Fragment, {
268
+ children: [/*#__PURE__*/_jsx(Spacer, {
269
+ space: 4
270
+ }), /*#__PURE__*/_jsx(Row, {
271
+ children: /*#__PURE__*/_jsx(Typography, {
272
+ tokens: {
273
+ ...subeHeaderStyles,
274
+ lineHeight: subHeaderLineHeight
275
+ },
276
+ children: subtitle
277
+ })
227
278
  }), /*#__PURE__*/_jsx(Spacer, {
228
279
  space: 4
229
- }), /*#__PURE__*/_jsx(Box, {
230
- scroll: true,
280
+ })]
281
+ }), /*#__PURE__*/_jsx(View, {
282
+ style: styles.options,
283
+ children: /*#__PURE__*/_jsx(ScrollView, {
284
+ onLayout: handleScrollViewLayout,
231
285
  children: /*#__PURE__*/_jsx(Row, {
232
286
  distribute: "between",
287
+ onLayout: handleRowLayout,
233
288
  children: [...Array(colSize).keys()].map(i => /*#__PURE__*/_jsxs(Col, {
234
- xs: 12 / colSize,
289
+ xs: TOTAL_COLUMNS / colSize,
235
290
  children: [/*#__PURE__*/_jsx(CheckboxGroup, {
236
291
  items: items.slice(i * rowLength, (i + 1) * rowLength),
237
292
  checkedIds: checkedIds,
@@ -241,13 +296,18 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
241
296
  })]
242
297
  }, i))
243
298
  })
244
- }), /*#__PURE__*/_jsx(Divider, {
245
- variant: selectDividerToknes({
246
- ...themeTokens,
247
- width: 'full'
248
- }),
249
- space: 4
250
- }), /*#__PURE__*/_jsx(Row, {
299
+ })
300
+ })]
301
+ });
302
+ const controlsContent = /*#__PURE__*/_jsxs(_Fragment, {
303
+ children: [isScrolling ? /*#__PURE__*/_jsx(Divider, {
304
+ tokens: selectDividerTokens(themeTokens),
305
+ space: 4
306
+ }) : /*#__PURE__*/_jsx(Spacer, {
307
+ space: 4
308
+ }), /*#__PURE__*/_jsx(View, {
309
+ style: selectControlsTokens(restTokens),
310
+ children: /*#__PURE__*/_jsx(Row, {
251
311
  horizontalAlign: buttonDirection === 'column' ? 'center' : 'start',
252
312
  children: /*#__PURE__*/_jsxs(StackView, {
253
313
  direction: buttonDirection,
@@ -261,7 +321,6 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
261
321
  children: [/*#__PURE__*/_jsx(Button, {
262
322
  onPress: () => onApply(checkedIds),
263
323
  variant: {
264
- size: 'small',
265
324
  priority: 'high',
266
325
  ...(viewport === 'xs' && {
267
326
  width: 'full'
@@ -275,105 +334,85 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
275
334
  })
276
335
  })]
277
336
  })
278
- })]
337
+ })
338
+ })]
339
+ });
340
+ return /*#__PURE__*/_jsxs(_Fragment, {
341
+ children: [/*#__PURE__*/_jsx(ButtonDropdown, {
342
+ ref: sourceRef,
343
+ ...pressHandlers,
344
+ value: isOpen,
345
+ selected: isSelected,
346
+ label: label,
347
+ onChange: handleChange,
348
+ tokens: getButtonTokens,
349
+ inactive: inactive
350
+ }, id), isOpen && viewport === 'xs' && /*#__PURE__*/_jsx(ModalOverlay, {
351
+ overlaidPosition: {
352
+ top: 0,
353
+ left: 0
354
+ },
355
+ onClose: onClose,
356
+ maxHeight: true,
357
+ maxHeightSize: windowHeight,
358
+ maxWidthSize: windowWidth,
359
+ minHeight: windowHeight,
360
+ minWidth: windowWidth,
361
+ tokens: {
362
+ ...tokens,
363
+ maxWidth: true
364
+ },
365
+ copy: copy,
366
+ isReady: isReady,
367
+ onLayout: onTargetLayout,
368
+ ref: modalRef,
369
+ enableFullscreen: true,
370
+ children: /*#__PURE__*/_jsxs(SafeAreaView, {
371
+ style: [selectContainerStyle(windowHeight, windowWidth), styles.content],
372
+ ref: ref,
373
+ children: [headerContent, /*#__PURE__*/_jsx(View, {
374
+ style: styles.controls,
375
+ children: controlsContent
376
+ })]
377
+ })
279
378
  }), isOpen && viewport !== 'xs' && /*#__PURE__*/_jsxs(ModalOverlay, {
280
379
  overlaidPosition: overlaidPosition,
281
380
  onClose: onClose,
282
- maxHeight: maxHeight,
381
+ maxHeight: items.length > MAX_ITEMS_THRESHOLD ? true : maxHeight,
283
382
  maxHeightSize: maxHeightSize,
284
383
  maxWidthSize: maxWidthSize,
285
384
  minHeight: minHeight,
286
385
  minWidth: minWidth,
287
386
  tokens: {
288
387
  ...tokens,
289
- maxWidth
388
+ maxWidth: items.length > MAX_ITEMS_THRESHOLD ? true : maxWidth
290
389
  },
291
390
  copy: copy,
292
391
  isReady: isReady,
293
392
  onLayout: onTargetLayout,
294
393
  ref: ref,
295
- children: [/*#__PURE__*/_jsx(Row, {
296
- children: /*#__PURE__*/_jsx(View, {
297
- style: styles.textContainerStyle,
298
- children: /*#__PURE__*/_jsx(Typography, {
299
- tokens: {
300
- ...headerStyles,
301
- lineHeight: headerLineHeight
302
- },
303
- children: getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())
304
- })
305
- })
306
- }), subtitle && /*#__PURE__*/_jsxs(_Fragment, {
307
- children: [/*#__PURE__*/_jsx(Spacer, {
308
- space: 5
309
- }), /*#__PURE__*/_jsx(Row, {
310
- children: /*#__PURE__*/_jsx(Typography, {
311
- tokens: {
312
- ...subeHeaderStyles,
313
- lineHeight: subHeaderLineHeight
314
- },
315
- children: subtitle
316
- })
317
- })]
318
- }), /*#__PURE__*/_jsx(Spacer, {
319
- space: 4
320
- }), /*#__PURE__*/_jsx(Box, {
321
- scroll: true,
322
- children: /*#__PURE__*/_jsx(Row, {
323
- distribute: "between",
324
- children: [...Array(colSize).keys()].map(i => /*#__PURE__*/_jsxs(Col, {
325
- xs: 12 / colSize,
326
- children: [/*#__PURE__*/_jsx(CheckboxGroup, {
327
- items: items.slice(i * rowLength, (i + 1) * rowLength),
328
- checkedIds: checkedIds,
329
- onChange: e => setCheckedIds(e, i)
330
- }), /*#__PURE__*/_jsx(Spacer, {
331
- size: 4
332
- })]
333
- }, i))
334
- })
335
- }), /*#__PURE__*/_jsx(Divider, {
336
- variant: selectDividerToknes({
337
- ...themeTokens,
338
- width: 'full'
339
- }),
340
- space: 4
341
- }), /*#__PURE__*/_jsx(Row, {
342
- horizontalAlign: buttonDirection === 'column' ? 'center' : 'start',
343
- children: /*#__PURE__*/_jsxs(StackView, {
344
- direction: buttonDirection,
345
- space: 3,
346
- tokens: {
347
- alignItems: 'center',
348
- ...(viewport === 'xs' && {
349
- flexGrow: 1
350
- })
351
- },
352
- children: [/*#__PURE__*/_jsx(Button, {
353
- onPress: () => onApply(checkedIds),
354
- variant: {
355
- size: 'small',
356
- priority: 'high',
357
- ...(viewport === 'xs' && {
358
- width: 'full'
359
- })
360
- },
361
- children: getCopy('applyButtonLabel')
362
- }), /*#__PURE__*/_jsx(Box, {
363
- children: /*#__PURE__*/_jsx(TextButton, {
364
- onPress: onClear,
365
- children: getCopy('clearButtonLabel')
366
- })
367
- })]
368
- })
369
- })]
394
+ children: [headerContent, controlsContent]
370
395
  })]
371
396
  });
372
397
  });
373
398
  MultiSelectFilter.displayName = 'MultiSelectFilter';
374
399
  const styles = StyleSheet.create({
375
- textContainerStyle: {
376
- marginRight: 52
400
+ container: {
401
+ flex: 1
402
+ },
403
+ controls: Platform.select({
404
+ web: {},
405
+ default: {
406
+ flex: 0.35
407
+ }
408
+ }),
409
+ content: {
410
+ flex: 1,
411
+ justifyContent: 'space-between',
412
+ backgroundColor: 'transparent'
413
+ },
414
+ options: {
415
+ flex: 1
377
416
  }
378
417
  });
379
418
 
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import View from "react-native-web/dist/exports/View";
3
+ import Platform from "react-native-web/dist/exports/Platform";
3
4
  import PropTypes from 'prop-types';
4
5
  import { applyTextStyles, useTheme, useThemeTokens, useResponsiveThemeTokens } from '../ThemeProvider';
5
6
  import { a11yProps, getTokensPropType, selectSystemProps, selectTokens, variantProp, viewProps, wrapStringsInText, useResponsiveProp, createMediaQueryStyles, StyleSheet } from '../utils';
@@ -176,7 +177,7 @@ const getMediaQueryStyles = (themeTokens, themeOptions, mediaIdsRef, dismissible
176
177
  const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible, viewport, system) => ({
177
178
  containerStyles: {
178
179
  container: {
179
- flexDirection: system === true && viewport === 'xl' ? 'row' : 'inherit',
180
+ flexDirection: system === true && viewport === 'xl' || Platform.OS === 'android' ? 'row' : 'inherit',
180
181
  ...selectContainerStyles(themeTokens)
181
182
  }
182
183
  },
@@ -281,6 +282,7 @@ const Notification = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
281
282
  copy = 'en',
282
283
  tokens,
283
284
  variant,
285
+ onDismiss,
284
286
  ...rest
285
287
  } = _ref6;
286
288
  const [isDismissed, setIsDismissed] = React.useState(false);
@@ -340,7 +342,10 @@ const Notification = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
340
342
  dismissIcon: DismissIconComponent,
341
343
  dismissIconColor
342
344
  } = enableMediaQueryStyleSheet === false ? themeTokens : themeTokens[viewport];
343
- const onDismissPress = () => setIsDismissed(true);
345
+ const onDismissPress = () => {
346
+ setIsDismissed(true);
347
+ onDismiss === null || onDismiss === void 0 ? void 0 : onDismiss();
348
+ };
344
349
  return /*#__PURE__*/_jsx(View, {
345
350
  ref: ref,
346
351
  style: notificationComponentRef.current.containerStyles.container,
@@ -414,6 +419,10 @@ Notification.propTypes = {
414
419
  copy: PropTypes.oneOfType([PropTypes.oneOf(['en', 'fr']), PropTypes.shape({
415
420
  dismiss: PropTypes.string
416
421
  })]),
422
+ /**
423
+ * Callback function called when the dismiss button is clicked
424
+ */
425
+ onDismiss: PropTypes.func,
417
426
  tokens: getTokensPropType('Notification'),
418
427
  variant: variantProp.propType
419
428
  };
@@ -75,7 +75,8 @@ const selectTextStyles = _ref3 => {
75
75
  textLineHeight,
76
76
  fontName,
77
77
  fontSize,
78
- fontWeight
78
+ fontWeight,
79
+ marginLeft
79
80
  } = _ref3;
80
81
  return applyTextStyles({
81
82
  fontColor: textColor,
@@ -83,7 +84,7 @@ const selectTextStyles = _ref3 => {
83
84
  fontSize,
84
85
  fontWeight,
85
86
  lineHeight: Platform.OS === 'web' ? textLineHeight : textLineHeight * 1.2,
86
- marginLeft: 8
87
+ marginLeft
87
88
  });
88
89
  };
89
90
 
@@ -95,6 +96,7 @@ const selectTextStyles = _ref3 => {
95
96
  * @param {string} variant - The variant of the status component.
96
97
  * @param {ReactNode} children - The content to be displayed inside the status component.
97
98
  * @param {function} customGradient - The custom gradient function for the status component.
99
+ * @param {elementType} customGradient - Defines an icon to be rendered.
98
100
  * @param {object} rest - The rest of the props to be applied to the status component.
99
101
  * @param {React.Ref} ref - The ref to be applied to the status component.
100
102
  * @returns {ReactNode} The rendered status component.
@@ -108,14 +110,17 @@ const Status = /*#__PURE__*/React.forwardRef((_ref4, ref) => {
108
110
  ...rest
109
111
  } = _ref4;
110
112
  const themeTokens = useThemeTokens('Status', tokens, variant);
113
+ const {
114
+ icon
115
+ } = themeTokens;
111
116
  const containerStyles = {
112
117
  ...selectContainerStyles(themeTokens),
113
118
  ...staticStyles.container
114
119
  };
115
120
  let content = /*#__PURE__*/_jsxs(_Fragment, {
116
- children: [/*#__PURE__*/_jsx(Icon, {
121
+ children: [icon ? /*#__PURE__*/_jsx(Icon, {
117
122
  ...selectIconProps(themeTokens)
118
- }), wrapStringsInText(children, {
123
+ }) : null, wrapStringsInText(children, {
119
124
  style: selectTextStyles(themeTokens)
120
125
  })]
121
126
  });
@@ -8,6 +8,7 @@ export * from './Button';
8
8
  export { default as Card, PressableCardBase } from './Card';
9
9
  export { default as CardGroup } from './CardGroup';
10
10
  export * from './Carousel';
11
+ export { default as FileUpload } from './FileUpload';
11
12
  export { default as Listbox } from './Listbox';
12
13
  export { default as Checkbox } from './Checkbox';
13
14
  export * from './Checkbox';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Converts a value from megabytes to bytes.
3
+ *
4
+ * @param {number} megaByte - The value in megabytes to be converted.
5
+ * @returns {number} The converted value in bytes.
6
+ */
7
+ const BYTES_IN_A_MEGABYTE = 1024 * 1024;
8
+ export default function convertFromMegaByteToByte(megaByte) {
9
+ return megaByte * BYTES_IN_A_MEGABYTE;
10
+ }
@@ -0,0 +1,27 @@
1
+ // react native source for Image and ImageBackground needs proper formatting to work
2
+ // remote sources that start with 'http' and base64 encoded sources that start with 'data:' need be wrapped in uri when passing source prop for Image and ImageBackground ie. source={ uri: image }
3
+ // local source for image can be passed normally without wrapping in uri ie. source={ image }
4
+
5
+ /**
6
+ * example code from react native docs: https://reactnative.dev/docs/imagebackground
7
+ *
8
+ * const image = {uri: 'https://legacy.reactjs.org/logo-og.png'}
9
+ *
10
+ * const App = () => (
11
+ * <View style={styles.container}>
12
+ * <ImageBackground source={image} resizeMode="cover" style={styles.image}>
13
+ * <Text style={styles.text}>Inside</Text>
14
+ * </ImageBackground>
15
+ * </View>
16
+ * )
17
+ */
18
+
19
+ /**
20
+ * Formats the image source for React Native Image and ImageBackground components.
21
+ * @param {string|number} source - The image source, either a URI string or a number (when a local image source is bundled in IOS or Android app).
22
+ * @returns {object|string} - The formatted image source.
23
+ */
24
+ const formatImageSource = source => typeof source === 'string' && (source.startsWith('http') || source.startsWith('data:')) ? {
25
+ uri: source
26
+ } : source;
27
+ export default formatImageSource;
@@ -20,4 +20,6 @@ export * from './ssr';
20
20
  export { default as containUniqueFields } from './containUniqueFields';
21
21
  export { default as BaseView } from './BaseView';
22
22
  export { default as htmlAttrs } from './htmlAttrs';
23
- export { transformGradient } from './transformGradient';
23
+ export { transformGradient } from './transformGradient';
24
+ export { default as convertFromMegaByteToByte } from './convertFromMegaByteToByte';
25
+ export { default as formatImageSource } from './formatImageSource';
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "@floating-ui/react-native": "^0.8.1",
12
12
  "@gorhom/portal": "^1.0.14",
13
13
  "@telus-uds/system-constants": "^1.3.0",
14
- "@telus-uds/system-theme-tokens": "^2.62.0",
14
+ "@telus-uds/system-theme-tokens": "^2.63.0",
15
15
  "airbnb-prop-types": "^2.16.0",
16
16
  "css-mediaquery": "^0.1.2",
17
17
  "expo-linear-gradient": "^12.5.0",
@@ -21,7 +21,8 @@
21
21
  "prop-types": "^15.7.2",
22
22
  "react-native-picker-select": "^8.0.4",
23
23
  "semver": "7.5.2",
24
- "string.prototype.matchall": "^4.0.9"
24
+ "string.prototype.matchall": "^4.0.9",
25
+ "expo-document-picker": "~10.3.0"
25
26
  },
26
27
  "description": "Base components",
27
28
  "devDependencies": {
@@ -85,6 +86,6 @@
85
86
  "standard-engine": {
86
87
  "skip": true
87
88
  },
88
- "version": "1.92.0",
89
+ "version": "1.94.0",
89
90
  "types": "types/index.d.ts"
90
91
  }
@@ -12,7 +12,7 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
12
12
  * It should be used to add selectable screen-reader-only text to the main document flow,
13
13
  * as a sibling to blocks of text like paragraphs and interactive elements like buttons.
14
14
  */
15
- const A11yText = React.forwardRef(({ text, heading, ...rest }, ref) => {
15
+ const A11yText = React.forwardRef(({ text, heading, role = 'text', ...rest }, ref) => {
16
16
  const selectedProps = selectProps({
17
17
  // On iOS, needs `accessible` to be true to be focusable without non-a11y content.
18
18
  // On Web, `accessible` causes RNW to set attributes that may make the element be treated as a group.
@@ -20,7 +20,7 @@ const A11yText = React.forwardRef(({ text, heading, ...rest }, ref) => {
20
20
  // see https://github.com/facebook/react-native/issues/30851#issuecomment-790165489
21
21
  accessible: Platform.OS === 'ios',
22
22
  accessibilityLabel: text,
23
- accessibilityRole: heading ? 'header' : 'text',
23
+ accessibilityRole: heading ? 'header' : role,
24
24
  ...rest
25
25
  })
26
26
 
@@ -38,7 +38,11 @@ A11yText.propTypes = {
38
38
  /**
39
39
  * Whether text should be rendered as a heading
40
40
  */
41
- heading: PropTypes.bool
41
+ heading: PropTypes.bool,
42
+ /**
43
+ * Role of the element
44
+ */
45
+ role: PropTypes.string
42
46
  }
43
47
 
44
48
  const styles = StyleSheet.create({
@@ -63,7 +63,8 @@ const ButtonGroup = React.forwardRef(
63
63
  const viewport = useViewport()
64
64
  const themeTokens = useThemeTokens('ButtonGroup', tokens, variant, { viewport })
65
65
  const stackTokens = selectTokens('StackView', themeTokens)
66
- const { direction, space, fieldSpace } = themeTokens
66
+ const { direction, space, fieldSpace, borderRadius, backgroundColor, padding, gap } =
67
+ themeTokens
67
68
 
68
69
  const getButtonTokens = useThemeTokensCallback('ButtonGroupItem', tokens, variant)
69
70
 
@@ -105,6 +106,12 @@ const ButtonGroup = React.forwardRef(
105
106
  inactive={inactive}
106
107
  validation={validation}
107
108
  accessibilityRole={accessibilityRole}
109
+ style={{
110
+ borderRadius,
111
+ backgroundColor,
112
+ padding,
113
+ ...(Platform.OS === 'web' ? { gap, width: 'fit-content' } : { alignSelf: 'flex-start' })
114
+ }}
108
115
  {...selectProps(rest)}
109
116
  >
110
117
  <StackWrap
@@ -112,6 +119,7 @@ const ButtonGroup = React.forwardRef(
112
119
  space={space}
113
120
  direction={direction}
114
121
  tokens={stackTokens}
122
+ gap={gap}
115
123
  ref={ref}
116
124
  >
117
125
  {items.map(