@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
@@ -0,0 +1,329 @@
1
+ import React from 'react';
2
+ import View from "react-native-web/dist/exports/View";
3
+ import Platform from "react-native-web/dist/exports/Platform";
4
+ import PropTypes from 'prop-types';
5
+ import { useThemeTokens } from '../ThemeProvider';
6
+ import { a11yProps, copyPropTypes, getTokensPropType, selectSystemProps, useCopy, variantProp, viewProps, convertFromMegaByteToByte } from '../utils';
7
+ import InputLabel from '../InputLabel';
8
+ import { Button } from '../Button';
9
+ import Notification from '../Notification';
10
+ import Spacer from '../Spacer';
11
+ import StackView from '../StackView';
12
+ import NotificationContent from './NotificationContent';
13
+ import dictionary from './dictionary';
14
+ import { jsx as _jsx } from "react/jsx-runtime";
15
+ import { jsxs as _jsxs } from "react/jsx-runtime";
16
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
17
+ const getHintFromFileTypes = fileTypes => {
18
+ const acceptedFileTypes = fileTypes.map(type => type.toUpperCase());
19
+ return acceptedFileTypes.reduce((acc, curr, index) => {
20
+ if (index === 0) {
21
+ return `${curr}`;
22
+ }
23
+ return `${acc}, ${curr}`;
24
+ }, '');
25
+ };
26
+ const stringifyFileTypesList = (fileTypes, getCopy) => {
27
+ const acceptedFileTypes = fileTypes.map(type => `.${type.toUpperCase()}`);
28
+ return acceptedFileTypes.reduce((acc, curr, index) => {
29
+ if (index === 0) {
30
+ return curr;
31
+ }
32
+ if (index === acceptedFileTypes.length - 1) {
33
+ return `${acc} ${getCopy('or')} ${curr}`;
34
+ }
35
+ return `${acc}, ${curr}`;
36
+ }, '');
37
+ };
38
+ const selectComponentTokens = (tokens, componentIdentifier) => {
39
+ return Object.entries(tokens).reduce((acc, _ref) => {
40
+ let [key, value] = _ref;
41
+ if (key.startsWith(componentIdentifier) && value !== null) {
42
+ const newKey = key.replace(componentIdentifier, '').replace('Text', '').charAt(0).toLowerCase() + key.replace(componentIdentifier, '').replace('Text', '').slice(1);
43
+ acc[newKey] = value;
44
+ }
45
+ return acc;
46
+ }, {});
47
+ };
48
+
49
+ /**
50
+ * FileUpload component for uploading files.
51
+ *
52
+ * @component
53
+ * @example
54
+ * // Usage:
55
+ * <FileUpload
56
+ * tokens={tokens}
57
+ * variant={variant}
58
+ * copy={copy}
59
+ * fileTypes={fileTypes}
60
+ * allowMultipleFiles={allowMultipleFiles}
61
+ * maxFileSize={maxFileSize}
62
+ * maxFilesCount={maxFilesCount}
63
+ * onUpload={onUpload}
64
+ * onDelete={onDelete}
65
+ * documentPicker={documentPicker}
66
+ * {...rest}
67
+ * />
68
+ *
69
+ * @param {Object} props - The component props.
70
+ * @param {Object} props.tokens - The tokens for styling the component.
71
+ * @param {string} props.variant - The variant of the component.
72
+ * @param {string} props.copy - The copy for the component.
73
+ * @param {string[]} props.fileTypes - The allowed file types for upload.
74
+ * @param {boolean} props.allowMultipleFiles - Whether multiple files can be uploaded.
75
+ * @param {number} props.maxFileSize - The maximum file size in megabytes.
76
+ * @param {number} props.maxFilesCount - The maximum number of files that can be uploaded.
77
+ * @param {Function} props.onUpload - The callback function for file upload.
78
+ * @param {Function} props.onDelete - The callback function for file deletion.
79
+ * @param {Object} props.documentPicker - The document picker object.
80
+ * @param {any} props.rest - Additional props to be spread to the component.
81
+ * @returns {JSX.Element} The rendered FileUpload component.
82
+ */
83
+ const FileUpload = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
84
+ let {
85
+ tokens,
86
+ variant,
87
+ copy = 'en',
88
+ fileTypes,
89
+ allowMultipleFiles = false,
90
+ maxFileSize,
91
+ maxFilesCount = 1,
92
+ onUpload,
93
+ onDelete,
94
+ documentPicker,
95
+ ...rest
96
+ } = _ref2;
97
+ const themeTokens = useThemeTokens('FileUpload', tokens, variant);
98
+ const getCopy = useCopy({
99
+ dictionary,
100
+ copy
101
+ });
102
+ const inputFileRef = React.useRef(null);
103
+ const [filesStatus, setFilesStatus] = React.useState([]);
104
+ const [renderTrigger, setRenderTrigger] = React.useState(0);
105
+ React.useEffect(() => {
106
+ setRenderTrigger(prev => prev + 1);
107
+ }, [filesStatus]);
108
+ const areFileTypesExtensionsValid = files => files.some(file => {
109
+ const fileExtension = file.name.split('.').pop().toLowerCase();
110
+ if (!fileTypes.includes(fileExtension)) {
111
+ setFilesStatus([{
112
+ description: getCopy('wrongFileType').replace('%{fileType}', stringifyFileTypesList(fileTypes, getCopy)),
113
+ style: 'error'
114
+ }]);
115
+ return false;
116
+ }
117
+ return true;
118
+ });
119
+ const areFileSizesWithinLimit = files => files.some(file => {
120
+ if (file.size > convertFromMegaByteToByte(maxFileSize)) {
121
+ setFilesStatus([{
122
+ description: getCopy('fileTooBig').replace('%{size}', maxFileSize),
123
+ style: 'error'
124
+ }]);
125
+ return false;
126
+ }
127
+ return true;
128
+ });
129
+ const areMoreFilesUploadedThanAllowed = files => {
130
+ if (files.length > maxFilesCount) {
131
+ setFilesStatus([{
132
+ description: getCopy('tooManyFiles').replace('%{maxFilesCount}', maxFilesCount),
133
+ style: 'error'
134
+ }]);
135
+ return true;
136
+ }
137
+ return false;
138
+ };
139
+ const handleFilesUpload = async files => {
140
+ try {
141
+ const results = await onUpload(files);
142
+ const currentFilesStatus = files.map((file, index) => {
143
+ if (results[index].error) {
144
+ return {
145
+ description: /*#__PURE__*/_jsx(NotificationContent, {
146
+ file: file,
147
+ color: selectComponentTokens(themeTokens, 'notification').color,
148
+ children: ` ${getCopy('uploadError')} ${results[index].error}.`
149
+ }),
150
+ style: 'error'
151
+ };
152
+ }
153
+ return {
154
+ description: /*#__PURE__*/_jsx(NotificationContent, {
155
+ file: file,
156
+ color: selectComponentTokens(themeTokens, 'notification').color,
157
+ children: ` ${getCopy('uploadSuccess')}`
158
+ }),
159
+ style: 'success',
160
+ file,
161
+ onDismiss: () => handleFileDeletion(file)
162
+ };
163
+ });
164
+ setFilesStatus(currentFilesStatus);
165
+ } catch (error) {
166
+ setFilesStatus([{
167
+ description: allowMultipleFiles ? getCopy('problemUploadingMultipleFiles') : getCopy('problemUploading'),
168
+ style: 'error'
169
+ }]);
170
+ }
171
+ };
172
+ const handleFileDeletion = async file => {
173
+ const copyFile = {
174
+ ...file
175
+ };
176
+ try {
177
+ const result = await onDelete(copyFile);
178
+ setFilesStatus(prevStatus => {
179
+ const filteredFilesStatus = prevStatus.filter(f => f.file && f.file.name !== file.name);
180
+ return result.error ? [...filteredFilesStatus, {
181
+ description: /*#__PURE__*/_jsx(NotificationContent, {
182
+ file: file,
183
+ color: selectComponentTokens(themeTokens, 'notification').color,
184
+ children: ` ${getCopy('uploadSuccess')}`
185
+ }),
186
+ style: 'success',
187
+ file,
188
+ onDismiss: () => handleFileDeletion(file)
189
+ }, {
190
+ description: /*#__PURE__*/_jsx(NotificationContent, {
191
+ file: file,
192
+ color: selectComponentTokens(themeTokens, 'notification').color,
193
+ children: ` ${getCopy('deleteProblem')} ${result.error}.`
194
+ }),
195
+ style: 'error',
196
+ file
197
+ }] : filteredFilesStatus;
198
+ });
199
+ } catch (error) {
200
+ setFilesStatus([{
201
+ description: /*#__PURE__*/_jsx(NotificationContent, {
202
+ file: file,
203
+ color: selectComponentTokens(themeTokens, 'notification').color,
204
+ children: ` ${getCopy('problemDeleting')}`
205
+ }),
206
+ style: 'error'
207
+ }]);
208
+ }
209
+ };
210
+ const handleOnChange = async event => {
211
+ const targetFiles = event.target.files;
212
+ const files = Array.from(targetFiles);
213
+ if (files.length === 0) return;
214
+ if (fileTypes && !areFileTypesExtensionsValid(files)) return;
215
+ if (maxFileSize && !areFileSizesWithinLimit(files)) return;
216
+ if (maxFilesCount && areMoreFilesUploadedThanAllowed(files)) return;
217
+ await handleFilesUpload(files);
218
+ if (inputFileRef.current) inputFileRef.current.value = '';
219
+ };
220
+ const onFileUploadButtonClick = async () => {
221
+ if (Platform.OS === 'web') {
222
+ inputFileRef.current.click();
223
+ } else {
224
+ try {
225
+ const result = await documentPicker.getDocumentAsync({
226
+ multiple: allowMultipleFiles
227
+ });
228
+ if (result) {
229
+ const files = Array.isArray(result) ? result : [result];
230
+ if (files.find(file => file.type === 'cancel')) return;
231
+ const event = {
232
+ target: {
233
+ files
234
+ }
235
+ };
236
+ await handleOnChange(event);
237
+ }
238
+ } catch (_) {
239
+ setFilesStatus([{
240
+ description: allowMultipleFiles ? getCopy('problemUploadingFiles') : getCopy('problemUploading'),
241
+ style: 'error'
242
+ }]);
243
+ }
244
+ }
245
+ };
246
+ return /*#__PURE__*/_jsxs(View, {
247
+ ref: ref,
248
+ ...selectProps(rest),
249
+ children: [/*#__PURE__*/_jsx(InputLabel, {
250
+ label: getCopy('label'),
251
+ hint: fileTypes && getCopy('allowedFileTypes').replace('%{fileTypes}', getHintFromFileTypes(fileTypes)),
252
+ hintPosition: "below"
253
+ }), /*#__PURE__*/_jsx(Spacer, {
254
+ space: 4
255
+ }), Platform.OS === 'web' && /*#__PURE__*/_jsx("input", {
256
+ type: "file",
257
+ multiple: allowMultipleFiles,
258
+ ref: inputFileRef,
259
+ hidden: true,
260
+ accept: fileTypes && fileTypes.map(type => `.${type}`).join(', '),
261
+ onChange: handleOnChange
262
+ }), /*#__PURE__*/_jsx(Button, {
263
+ onClick: onFileUploadButtonClick,
264
+ tokens: selectComponentTokens(themeTokens, 'button'),
265
+ children: getCopy('buttonLabel')
266
+ }), filesStatus.length > 0 && /*#__PURE__*/_jsxs(View, {
267
+ children: [/*#__PURE__*/_jsx(Spacer, {
268
+ space: 4
269
+ }), /*#__PURE__*/_jsx(StackView, {
270
+ space: 4,
271
+ children: filesStatus.map((_ref3, index) => {
272
+ let {
273
+ description,
274
+ style,
275
+ onDismiss
276
+ } = _ref3;
277
+ return /*#__PURE__*/_jsx(Notification, {
278
+ variant: {
279
+ style
280
+ },
281
+ dismissible: !!onDismiss,
282
+ onDismiss: onDismiss,
283
+ tokens: selectComponentTokens(themeTokens, 'notification'),
284
+ children: description
285
+ }, `${index.toString()}-${renderTrigger}`);
286
+ })
287
+ })]
288
+ })]
289
+ });
290
+ });
291
+ FileUpload.displayName = 'FileUpload';
292
+ FileUpload.propTypes = {
293
+ ...selectedSystemPropTypes,
294
+ tokens: getTokensPropType('FileUpload'),
295
+ variant: variantProp.propType,
296
+ /**
297
+ * To define the locale of the copy
298
+ */
299
+ copy: copyPropTypes,
300
+ /**
301
+ * The file types allowed for upload. Example: fileTypes={['pdf', 'docx']}.
302
+ */
303
+ fileTypes: PropTypes.arrayOf(PropTypes.string),
304
+ /**
305
+ * Whether to allow multiple files to be uploaded.
306
+ */
307
+ allowMultipleFiles: PropTypes.bool,
308
+ /**
309
+ * The maximum file size allowed for upload in MB.
310
+ */
311
+ maxFileSize: PropTypes.number,
312
+ /**
313
+ * The maximum number of files allowed for upload.
314
+ */
315
+ maxFilesCount: PropTypes.number,
316
+ /**
317
+ * Callback function called when a file is uploaded.
318
+ */
319
+ onUpload: PropTypes.func,
320
+ /**
321
+ * Callback function called when a file is deleted
322
+ */
323
+ onDelete: PropTypes.func,
324
+ /**
325
+ * The document picker to use for mobile
326
+ */
327
+ documentPicker: PropTypes.object
328
+ };
329
+ export default FileUpload;
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import Typography from '../Typography';
4
+
5
+ /**
6
+ * Renders the content of a notification for a file upload.
7
+ *
8
+ * @component
9
+ * @param {Object} props - The component props.
10
+ * @param {Object} props.file - The file object.
11
+ * @param {string} props.children - The content to be displayed.
12
+ * @param {string} props.color - The color of the typography.
13
+ * @param {React.Ref} ref - The ref to be forwarded to the Typography component.
14
+ * @returns {JSX.Element} The rendered NotificationContent component.
15
+ */
16
+ import { jsx as _jsx } from "react/jsx-runtime";
17
+ import { jsxs as _jsxs } from "react/jsx-runtime";
18
+ const NotificationContent = /*#__PURE__*/React.forwardRef((_ref, ref) => {
19
+ let {
20
+ file,
21
+ color,
22
+ children
23
+ } = _ref;
24
+ return /*#__PURE__*/_jsxs(Typography, {
25
+ tokens: {
26
+ color
27
+ },
28
+ ref: ref,
29
+ children: [/*#__PURE__*/_jsx(Typography, {
30
+ variant: {
31
+ bold: true
32
+ },
33
+ tokens: {
34
+ color
35
+ },
36
+ children: file.name
37
+ }), children]
38
+ });
39
+ });
40
+ NotificationContent.displayName = 'NotificationContent';
41
+ NotificationContent.propTypes = {
42
+ /**
43
+ * The file object.
44
+ */
45
+ file: PropTypes.object,
46
+ /**
47
+ * The content to be displayed.
48
+ */
49
+ children: PropTypes.string,
50
+ /**
51
+ * The color of the typography.
52
+ */
53
+ color: PropTypes.string
54
+ };
55
+ export default NotificationContent;
@@ -0,0 +1,40 @@
1
+ export default {
2
+ en: {
3
+ label: 'Upload files',
4
+ buttonLabel: 'Choose files',
5
+ dismissButtonLabel: 'Remove file',
6
+ wrongFileType: 'The selected file must be a %{fileType}.',
7
+ allowedFileTypes: 'Allowed file types: %{fileTypes}.',
8
+ fileTooBig: 'The selected file must be smaller than %{size}MB.',
9
+ fileIsEmpty: 'The selected file is empty.',
10
+ problemUploading: 'The selected file could not be uploaded. Try again.',
11
+ problemDeleting: 'The selected file could not be deleted. Try again.',
12
+ problemUploadingMultipleFiles: 'The selected files could not be uploaded. Try again.',
13
+ only: 'only',
14
+ and: 'and',
15
+ or: 'or',
16
+ uploadSuccess: 'uploaded successfully.',
17
+ uploadError: 'was not uploaded due to',
18
+ deleteProblem: 'was not deleted due to',
19
+ tooManyFiles: 'You can only select up to %{maxFilesCount} files at the same time.'
20
+ },
21
+ fr: {
22
+ label: 'Téléverser les fichiers"',
23
+ buttonLabel: 'Choisir les fichiers',
24
+ dismissButtonLabel: 'Supprimer le fichier',
25
+ wrongFileType: 'Le fichier sélectionné doit être au format %{fileType}.',
26
+ allowedFileTypes: 'Formats de fichiers autorisés : %{fileTypes}.',
27
+ fileTooBig: 'Le fichier sélectionné doit être inférieur à %{size}Mo.',
28
+ fileIsEmpty: 'Le fichier sélectionné est vide.',
29
+ problemUploading: 'Impossible de téléverser le fichier sélectionné. Veuillez réessayer.',
30
+ problemDeleting: `Le fichier sélectionné n'a pas pu être supprimé. Réessayez.`,
31
+ problemUploadingMultipleFiles: `Les fichiers sélectionnés n'ont pas pu être téléchargés. Veuillez réessayer.`,
32
+ only: 'uniquement',
33
+ and: 'et',
34
+ or: 'ou',
35
+ uploadSuccess: 'téléchargé avec succès.',
36
+ uploadError: `n'a pas été téléchargé en raison de`,
37
+ deleteProblem: `n'a pas été supprimé en raison de`,
38
+ tooManyFiles: `Vous ne pouvez sélectionner que jusqu'à %{maxFilesCount} fichiers en même temps.`
39
+ }
40
+ };
@@ -0,0 +1,2 @@
1
+ import FileUpload from './FileUpload';
2
+ export default FileUpload;
@@ -2,6 +2,8 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import Platform from "react-native-web/dist/exports/Platform";
4
4
  import View from "react-native-web/dist/exports/View";
5
+ import Text from "react-native-web/dist/exports/Text";
6
+ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
7
  import Icon, { iconComponentPropTypes } from './Icon';
6
8
  import { getStackedContent } from '../StackView';
7
9
  import { spacingProps } from '../utils';
@@ -15,6 +17,7 @@ import { spacingProps } from '../utils';
15
17
  * - within a container with `flexDirection: 'row'`
16
18
  */
17
19
  import { jsx as _jsx } from "react/jsx-runtime";
20
+ import { jsxs as _jsxs } from "react/jsx-runtime";
18
21
  const IconText = /*#__PURE__*/React.forwardRef((_ref, ref) => {
19
22
  var _iconProps$tokens, _iconProps$tokens2;
20
23
  let {
@@ -59,6 +62,15 @@ const IconText = /*#__PURE__*/React.forwardRef((_ref, ref) => {
59
62
  });
60
63
  const mobile = Platform.OS === 'android' ? iconAdjustedAndroid : iconAdjustedIOS;
61
64
  const adjustedContainer = Platform.OS === 'web' ? iconContent : mobile;
65
+ const adjustedContainerWithPosition = /*#__PURE__*/_jsx(View, {
66
+ style: staticStyles.adjustedContainer,
67
+ children: adjustedContainer
68
+ });
69
+ if (iconPosition === 'inline') {
70
+ return /*#__PURE__*/_jsxs(Text, {
71
+ children: [children, " ", adjustedContainerWithPosition]
72
+ });
73
+ }
62
74
  return getStackedContent(iconPosition === 'left' ? [adjustedContainer, children] : [children, adjustedContainer], {
63
75
  space,
64
76
  direction: 'row'
@@ -73,9 +85,9 @@ IconText.propTypes = {
73
85
  */
74
86
  space: spacingProps.types.spacingValue,
75
87
  /**
76
- * Whether the icon should be to the left of the content or the right of the content.
88
+ * Whether the icon should be to the left of the content, the right of the content or inline with the content.
77
89
  */
78
- iconPosition: PropTypes.oneOf(['left', 'right']),
90
+ iconPosition: PropTypes.oneOf(['left', 'right', 'inline']),
79
91
  /**
80
92
  * A valid UDS icon component imported from a UDS palette.
81
93
  */
@@ -94,4 +106,9 @@ IconText.propTypes = {
94
106
  /* eslint-enable react/no-unused-prop-types */
95
107
  };
96
108
 
109
+ const staticStyles = StyleSheet.create({
110
+ adjustedContainer: {
111
+ position: 'absolute'
112
+ }
113
+ });
97
114
  export default IconText;
@@ -238,9 +238,9 @@ LinkBase.propTypes = {
238
238
  */
239
239
  icon: PropTypes.elementType,
240
240
  /**
241
- * When `icon` is provided, use `iconPosition` to place the Icon to the left or right side of Link.
241
+ * When `icon` is provided, use `iconPosition` to place the Icon to the left, right or inline with Link.
242
242
  */
243
- iconPosition: PropTypes.oneOf(['left', 'right']),
243
+ iconPosition: PropTypes.oneOf(['left', 'right', 'inline']),
244
244
  /**
245
245
  * On Web if href is passed, React Native Web maps this object's props to
246
246
  * `rel`, `target` and `download` attrs.
@@ -1,7 +1,5 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import View from "react-native-web/dist/exports/View";
4
- import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
3
  import { useThemeTokensCallback } from '../ThemeProvider';
6
4
  import LinkBase from './LinkBase';
7
5
  import { variantProp } from '../utils';
@@ -22,23 +20,15 @@ const TextButton = /*#__PURE__*/React.forwardRef((_ref, ref) => {
22
20
  ...linkProps
23
21
  } = _ref;
24
22
  const getTokens = useThemeTokensCallback('Link', tokens, variant);
25
- return /*#__PURE__*/_jsx(View, {
26
- style: styles.textButton,
27
- children: /*#__PURE__*/_jsx(LinkBase, {
28
- onPress: onPress,
29
- accessibilityRole: accessibilityRole,
30
- tokens: getTokens,
31
- ref: ref,
32
- ...linkProps,
33
- children: children
34
- })
23
+ return /*#__PURE__*/_jsx(LinkBase, {
24
+ onPress: onPress,
25
+ accessibilityRole: accessibilityRole,
26
+ tokens: getTokens,
27
+ ref: ref,
28
+ ...linkProps,
29
+ children: children
35
30
  });
36
31
  });
37
- const styles = StyleSheet.create({
38
- textButton: {
39
- flex: 1
40
- }
41
- });
42
32
  TextButton.displayName = 'TextButton';
43
33
  TextButton.propTypes = {
44
34
  ...LinkBase.propTypes,
@@ -153,7 +153,7 @@ const Modal = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
153
153
  if (Platform.OS === 'web') {
154
154
  const handleFocus = () => {
155
155
  // If the focus is on the last item of the web modal container, move it to the close button
156
- if (document.activeElement === focusTrapRef.current) {
156
+ if (document.activeElement === focusTrapRef.current && closeButtonRef.current) {
157
157
  closeButtonRef.current.focus();
158
158
  }
159
159
  return undefined;
@@ -135,12 +135,15 @@ const ModalContent = /*#__PURE__*/React.forwardRef((_ref, ref) => {
135
135
  },
136
136
  onPress: onConfirm,
137
137
  children: confirmButtonText
138
- }), hasCancelButton ? /*#__PURE__*/_jsx(CancelButton, {
139
- tokens: {
140
- color: cancelButtonColor
141
- },
142
- onPress: onCancel,
143
- children: cancelButtonText
138
+ }), hasCancelButton ? /*#__PURE__*/_jsx(View, {
139
+ style: styles.cancelButton,
140
+ children: /*#__PURE__*/_jsx(CancelButton, {
141
+ tokens: {
142
+ color: cancelButtonColor
143
+ },
144
+ onPress: onCancel,
145
+ children: cancelButtonText
146
+ })
144
147
  }) : null]
145
148
  })]
146
149
  });
@@ -151,6 +154,9 @@ const styles = StyleSheet.create({
151
154
  flex: 1,
152
155
  flexDirection: 'column',
153
156
  minHeight: Platform.OS === 'web' ? '100%' : 'auto'
157
+ },
158
+ cancelButton: {
159
+ flex: 1
154
160
  }
155
161
  });
156
162
  ModalContent.propTypes = {