@telus-uds/components-base 3.7.1 → 3.9.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.
- package/CHANGELOG.md +34 -2
- package/lib/cjs/ActivityIndicator/FullScreenIndicator.js +89 -0
- package/lib/cjs/ActivityIndicator/InlineIndicator.js +64 -0
- package/lib/cjs/ActivityIndicator/OverlayIndicator.js +156 -0
- package/lib/cjs/ActivityIndicator/RenderActivityIndicator.js +88 -0
- package/lib/cjs/ActivityIndicator/index.js +91 -23
- package/lib/cjs/ActivityIndicator/shared.js +12 -1
- package/lib/cjs/ActivityIndicator/sharedProptypes.js +67 -0
- package/lib/cjs/Card/Card.js +38 -45
- package/lib/cjs/ExpandCollapseMini/ExpandCollapseMiniControl.js +1 -1
- package/lib/cjs/List/ListItemMark.js +13 -2
- package/lib/cjs/MultiSelectFilter/ModalOverlay.js +19 -5
- package/lib/cjs/MultiSelectFilter/MultiSelectFilter.js +22 -9
- package/lib/cjs/ToggleSwitch/ToggleSwitch.js +13 -2
- package/lib/cjs/Validator/Validator.js +135 -64
- package/lib/cjs/utils/index.js +9 -1
- package/lib/cjs/utils/useDetectOutsideClick.js +39 -0
- package/lib/cjs/utils/useVariants.js +46 -0
- package/lib/esm/ActivityIndicator/FullScreenIndicator.js +82 -0
- package/lib/esm/ActivityIndicator/InlineIndicator.js +57 -0
- package/lib/esm/ActivityIndicator/OverlayIndicator.js +149 -0
- package/lib/esm/ActivityIndicator/RenderActivityIndicator.js +83 -0
- package/lib/esm/ActivityIndicator/index.js +89 -23
- package/lib/esm/ActivityIndicator/shared.js +11 -0
- package/lib/esm/ActivityIndicator/sharedProptypes.js +61 -0
- package/lib/esm/Card/Card.js +38 -45
- package/lib/esm/ExpandCollapseMini/ExpandCollapseMiniControl.js +1 -1
- package/lib/esm/List/ListItemMark.js +13 -2
- package/lib/esm/MultiSelectFilter/ModalOverlay.js +19 -5
- package/lib/esm/MultiSelectFilter/MultiSelectFilter.js +22 -9
- package/lib/esm/ToggleSwitch/ToggleSwitch.js +13 -2
- package/lib/esm/Validator/Validator.js +135 -64
- package/lib/esm/utils/index.js +2 -1
- package/lib/esm/utils/useDetectOutsideClick.js +31 -0
- package/lib/esm/utils/useVariants.js +41 -0
- package/lib/package.json +2 -2
- package/package.json +2 -2
- package/src/ActivityIndicator/FullScreenIndicator.jsx +65 -0
- package/src/ActivityIndicator/InlineIndicator.jsx +47 -0
- package/src/ActivityIndicator/OverlayIndicator.jsx +140 -0
- package/src/ActivityIndicator/RenderActivityIndicator.jsx +82 -0
- package/src/ActivityIndicator/index.jsx +113 -32
- package/src/ActivityIndicator/shared.js +11 -0
- package/src/ActivityIndicator/sharedProptypes.js +62 -0
- package/src/Card/Card.jsx +51 -54
- package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +1 -1
- package/src/List/ListItemMark.jsx +18 -2
- package/src/MultiSelectFilter/ModalOverlay.jsx +18 -5
- package/src/MultiSelectFilter/MultiSelectFilter.jsx +21 -10
- package/src/ToggleSwitch/ToggleSwitch.jsx +17 -2
- package/src/Validator/Validator.jsx +172 -85
- package/src/utils/index.js +1 -0
- package/src/utils/useDetectOutsideClick.js +35 -0
- package/src/utils/useVariants.js +44 -0
|
@@ -37,7 +37,7 @@ const Validator = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
37
37
|
supportsProps
|
|
38
38
|
} = selectProps(rest);
|
|
39
39
|
const strValidation = supportsProps.validation;
|
|
40
|
-
const [
|
|
40
|
+
const [, setIndividualCodes] = React.useState({});
|
|
41
41
|
const [text, setText] = React.useState(value);
|
|
42
42
|
const validatorsLength = 6;
|
|
43
43
|
const prefix = 'code';
|
|
@@ -55,64 +55,85 @@ const Validator = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
55
55
|
const [codeReferences, singleCodes] = React.useMemo(() => {
|
|
56
56
|
const codes = [];
|
|
57
57
|
const valueCodes = {};
|
|
58
|
-
|
|
58
|
+
Array.from({
|
|
59
|
+
length: validatorsLength
|
|
60
|
+
}, (_, i) => {
|
|
59
61
|
codes[prefix + i] = /*#__PURE__*/React.createRef();
|
|
60
62
|
valueCodes[prefix + i] = '';
|
|
61
63
|
valueCodes[prefix + i + sufixValidation] = '';
|
|
62
|
-
|
|
64
|
+
return null;
|
|
65
|
+
});
|
|
63
66
|
return [codes, valueCodes];
|
|
64
|
-
}, []);
|
|
65
|
-
const handleSingleCodes = (codeId, val, validation) => {
|
|
67
|
+
}, [validatorsLength, prefix, sufixValidation]);
|
|
68
|
+
const handleSingleCodes = React.useCallback((codeId, val, validation) => {
|
|
66
69
|
singleCodes[codeId] = val;
|
|
67
70
|
singleCodes[codeId + sufixValidation] = validation;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
...individualCodes,
|
|
71
|
+
setIndividualCodes(prev => ({
|
|
72
|
+
...prev,
|
|
71
73
|
[codeId]: val
|
|
72
|
-
});
|
|
73
|
-
};
|
|
74
|
-
const changeDataMasking = boxElement => {
|
|
74
|
+
}));
|
|
75
|
+
}, [singleCodes, sufixValidation]);
|
|
76
|
+
const changeDataMasking = React.useCallback(boxElement => {
|
|
75
77
|
let charMasking = '';
|
|
76
78
|
const element = boxElement;
|
|
77
|
-
if (mask && mask.length === 1)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
if (mask && mask.length === 1) {
|
|
80
|
+
charMasking = mask;
|
|
81
|
+
} else if (mask && mask.length > 1) {
|
|
82
|
+
charMasking = mask.substring(0, 1);
|
|
83
|
+
}
|
|
84
|
+
if (charMasking && element) {
|
|
85
|
+
element.value = charMasking;
|
|
86
|
+
}
|
|
87
|
+
}, [mask]);
|
|
88
|
+
const handleChangeCode = React.useCallback(() => {
|
|
89
|
+
const code = Array.from({
|
|
90
|
+
length: validatorsLength
|
|
91
|
+
}, (_, i) => singleCodes[prefix + i] || '').join('');
|
|
92
|
+
if (typeof onChange === 'function') {
|
|
93
|
+
onChange(code, singleCodes);
|
|
94
|
+
}
|
|
95
|
+
}, [validatorsLength, singleCodes, prefix, onChange]);
|
|
96
|
+
const handleChangeCodeValues = React.useCallback((event, codeId, nextIndex) => {
|
|
86
97
|
const codeElement = codeReferences[codeId]?.current;
|
|
87
98
|
const val = event.nativeEvent?.value || event.target?.value;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
|
|
100
|
+
// Only allow numeric characters and limit to single digit
|
|
101
|
+
const numericOnly = val.replace(/\D/g, '').substring(0, 1);
|
|
102
|
+
if (codeElement && codeElement.value) {
|
|
103
|
+
codeElement.value = numericOnly;
|
|
91
104
|
}
|
|
92
|
-
handleSingleCodes(codeId,
|
|
105
|
+
handleSingleCodes(codeId, numericOnly, numericOnly ? 'success' : '');
|
|
93
106
|
handleChangeCode();
|
|
94
107
|
if (nextIndex === validatorsLength) {
|
|
95
|
-
codeElement
|
|
108
|
+
codeElement?.blur();
|
|
96
109
|
changeDataMasking(codeElement);
|
|
97
110
|
return;
|
|
98
111
|
}
|
|
99
|
-
if (
|
|
100
|
-
codeReferences[prefix + nextIndex]
|
|
112
|
+
if (numericOnly.length > 0) {
|
|
113
|
+
const nextElement = codeReferences[prefix + nextIndex]?.current;
|
|
114
|
+
nextElement?.focus();
|
|
101
115
|
changeDataMasking(codeElement);
|
|
102
116
|
}
|
|
103
|
-
};
|
|
117
|
+
}, [codeReferences, handleSingleCodes, handleChangeCode, validatorsLength, changeDataMasking, prefix]);
|
|
104
118
|
const handleKeyPress = (event, currentIndex, previousIndex) => {
|
|
105
|
-
if (!(event.keyCode === 8 || event.code === 'Backspace'))
|
|
119
|
+
if (!(event.keyCode === 8 || event.code === 'Backspace')) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
106
122
|
if (currentIndex > 0) {
|
|
107
|
-
codeReferences[prefix + currentIndex]
|
|
108
|
-
codeReferences[prefix + previousIndex]
|
|
123
|
+
const currentElement = codeReferences[prefix + currentIndex]?.current;
|
|
124
|
+
const previousElement = codeReferences[prefix + previousIndex]?.current;
|
|
125
|
+
if (currentElement && currentElement.value) {
|
|
126
|
+
currentElement.value = '';
|
|
127
|
+
}
|
|
128
|
+
previousElement?.focus();
|
|
109
129
|
}
|
|
110
130
|
handleSingleCodes(prefix + currentIndex, '', '');
|
|
111
131
|
handleChangeCode();
|
|
112
132
|
};
|
|
113
133
|
const getCodeComponents = () => {
|
|
114
|
-
|
|
115
|
-
|
|
134
|
+
return Array.from({
|
|
135
|
+
length: validatorsLength
|
|
136
|
+
}, (_, i) => {
|
|
116
137
|
const codeId = prefix + i;
|
|
117
138
|
const codeInputProps = {
|
|
118
139
|
nativeID: codeId,
|
|
@@ -120,65 +141,115 @@ const Validator = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
120
141
|
ref: codeReferences[codeId] ?? null,
|
|
121
142
|
validation: strValidation || singleCodes[codeId + sufixValidation],
|
|
122
143
|
tokens: selectCodeTextInputTokens(themeTokens),
|
|
123
|
-
onFocus: () =>
|
|
144
|
+
onFocus: () => {
|
|
145
|
+
const element = codeReferences[codeId]?.current;
|
|
146
|
+
if (Platform.OS === 'web' && element?.select) {
|
|
147
|
+
return element.select() ?? null;
|
|
148
|
+
}
|
|
149
|
+
if (element?.focus) {
|
|
150
|
+
return element.focus() ?? null;
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
},
|
|
124
154
|
onKeyPress: event => handleKeyPress(event, i, i - 1),
|
|
125
155
|
onMouseOver: handleMouseOver,
|
|
126
156
|
onMouseOut: handleMouseOut,
|
|
127
157
|
inactive
|
|
128
158
|
};
|
|
129
|
-
codeInputProps.validation
|
|
130
|
-
|
|
159
|
+
if (!codeInputProps.validation) {
|
|
160
|
+
delete codeInputProps.validation;
|
|
161
|
+
}
|
|
162
|
+
return /*#__PURE__*/_jsx(View, {
|
|
131
163
|
style: staticStyles.codeInputWidth,
|
|
132
164
|
children: /*#__PURE__*/_jsx(TextInput, {
|
|
133
165
|
...codeInputProps
|
|
134
166
|
})
|
|
135
|
-
}, codeId)
|
|
136
|
-
}
|
|
137
|
-
return components;
|
|
167
|
+
}, codeId);
|
|
168
|
+
});
|
|
138
169
|
};
|
|
139
170
|
React.useEffect(() => {
|
|
140
|
-
|
|
141
|
-
|
|
171
|
+
if (Number(value).toString() !== 'NaN') {
|
|
172
|
+
setText(value);
|
|
173
|
+
}
|
|
142
174
|
}, [value]);
|
|
143
|
-
|
|
144
|
-
/* eslint-disable react-hooks/exhaustive-deps */
|
|
145
175
|
React.useEffect(() => {
|
|
146
|
-
|
|
147
|
-
|
|
176
|
+
Array.from({
|
|
177
|
+
length: validatorsLength
|
|
178
|
+
}, (_, i) => {
|
|
179
|
+
const element = codeReferences[prefix + i]?.current;
|
|
180
|
+
if (element && element.value !== undefined) {
|
|
181
|
+
if (mask && text[i]) {
|
|
182
|
+
element.value = mask;
|
|
183
|
+
} else {
|
|
184
|
+
element.value = text[i] ?? '';
|
|
185
|
+
}
|
|
186
|
+
}
|
|
148
187
|
handleSingleCodes(prefix + i, text[i] ?? '', text[i] ? 'success' : '');
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
/* eslint-disable react-hooks/exhaustive-deps */
|
|
188
|
+
return null;
|
|
189
|
+
});
|
|
190
|
+
}, [text, mask, validatorsLength, prefix, codeReferences, handleSingleCodes]);
|
|
153
191
|
React.useEffect(() => {
|
|
154
192
|
const handlePasteCode = event => {
|
|
193
|
+
event.preventDefault();
|
|
194
|
+
|
|
195
|
+
// Clear current state first
|
|
155
196
|
setText('');
|
|
197
|
+
|
|
198
|
+
// Clear all individual input fields and their state
|
|
199
|
+
Array.from({
|
|
200
|
+
length: validatorsLength
|
|
201
|
+
}, (_, i) => {
|
|
202
|
+
const element = codeReferences[prefix + i]?.current;
|
|
203
|
+
if (element && element.value !== undefined) {
|
|
204
|
+
element.value = '';
|
|
205
|
+
}
|
|
206
|
+
handleSingleCodes(prefix + i, '', '');
|
|
207
|
+
return null;
|
|
208
|
+
});
|
|
156
209
|
const clipBoardText = event.clipboardData.getData('text');
|
|
157
|
-
|
|
210
|
+
|
|
211
|
+
// Validate that input contains only digits and truncate to 6 characters
|
|
212
|
+
const numericOnly = clipBoardText.replace(/\D/g, '').substring(0, validatorsLength);
|
|
213
|
+
if (numericOnly.length > 0) {
|
|
214
|
+
setText(numericOnly);
|
|
215
|
+
}
|
|
158
216
|
};
|
|
159
217
|
const handleCopy = event => {
|
|
160
|
-
|
|
161
|
-
|
|
218
|
+
const clipBoardText = Array.from({
|
|
219
|
+
length: validatorsLength
|
|
220
|
+
}, (_, i) => singleCodes[prefix + i] || '').join('');
|
|
162
221
|
event.clipboardData.setData('text/plain', clipBoardText);
|
|
163
222
|
event.preventDefault();
|
|
164
223
|
};
|
|
165
224
|
if (Platform.OS === 'web') {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
codeReferences[prefix + i]
|
|
170
|
-
|
|
225
|
+
Array.from({
|
|
226
|
+
length: validatorsLength
|
|
227
|
+
}, (_, i) => {
|
|
228
|
+
const element = codeReferences[prefix + i]?.current;
|
|
229
|
+
if (element && typeof element.addEventListener === 'function') {
|
|
230
|
+
element.addEventListener('paste', handlePasteCode);
|
|
231
|
+
element.addEventListener('copy', handleCopy);
|
|
232
|
+
element.addEventListener('input', event => handleChangeCodeValues(event, prefix + i, i + 1));
|
|
233
|
+
}
|
|
234
|
+
return null;
|
|
235
|
+
});
|
|
171
236
|
}
|
|
172
237
|
return () => {
|
|
173
|
-
if (Platform.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
codeReferences[prefix + i]?.current
|
|
178
|
-
|
|
238
|
+
if (Platform.OS === 'web') {
|
|
239
|
+
Array.from({
|
|
240
|
+
length: validatorsLength
|
|
241
|
+
}, (_, i) => {
|
|
242
|
+
const element = codeReferences[prefix + i]?.current;
|
|
243
|
+
if (element && typeof element.removeEventListener === 'function') {
|
|
244
|
+
element.removeEventListener('paste', handlePasteCode);
|
|
245
|
+
element.removeEventListener('copy', handleCopy);
|
|
246
|
+
element.removeEventListener('input', event => handleChangeCodeValues(event, prefix + i, i + 1));
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
});
|
|
179
250
|
}
|
|
180
251
|
};
|
|
181
|
-
}, []);
|
|
252
|
+
}, [validatorsLength, prefix, codeReferences, handleChangeCodeValues, handleSingleCodes, singleCodes]);
|
|
182
253
|
return /*#__PURE__*/_jsx(InputSupports, {
|
|
183
254
|
...supportsProps,
|
|
184
255
|
feedbackProps: {
|
package/lib/esm/utils/index.js
CHANGED
|
@@ -23,4 +23,5 @@ export { default as htmlAttrs } from './htmlAttrs';
|
|
|
23
23
|
export { transformGradient } from './transformGradient';
|
|
24
24
|
export { default as convertFromMegaByteToByte } from './convertFromMegaByteToByte';
|
|
25
25
|
export { default as formatImageSource } from './formatImageSource';
|
|
26
|
-
export { default as getSpacingScale } from './getSpacingScale';
|
|
26
|
+
export { default as getSpacingScale } from './getSpacingScale';
|
|
27
|
+
export { default as useVariants } from './useVariants';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Platform from "react-native-web/dist/exports/Platform";
|
|
3
|
+
/**
|
|
4
|
+
* Hook to detect clicks outside of a ref, only on web.
|
|
5
|
+
*
|
|
6
|
+
* @param {React.RefObject<HTMLElement>} ref
|
|
7
|
+
* Reference to the element you want to “protect.”
|
|
8
|
+
* @param {() => void} onOutside
|
|
9
|
+
* Callback invoked when a click occurs outside that ref.
|
|
10
|
+
* @param {boolean} [enabled=true]
|
|
11
|
+
* Flag to enable or disable the outside-click detection at runtime.
|
|
12
|
+
* @deprecated Will be removed in next major release; detection will always be enabled.
|
|
13
|
+
*/
|
|
14
|
+
function useDetectOutsideClick(ref, onOutside) {
|
|
15
|
+
let enabled = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
16
|
+
React.useEffect(() => {
|
|
17
|
+
if (!enabled || Platform.OS !== 'web') {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
const handleClickOutside = e => {
|
|
21
|
+
if (ref.current && !ref.current.contains(e.target)) {
|
|
22
|
+
onOutside();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
26
|
+
return () => {
|
|
27
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
28
|
+
};
|
|
29
|
+
}, [ref, onOutside, enabled]);
|
|
30
|
+
}
|
|
31
|
+
export default useDetectOutsideClick;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getComponentTheme, useTheme } from '../ThemeProvider';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generates a label string for a variant based on the provided key and value.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} key - The name of the variant.
|
|
7
|
+
* @param {*} value - The value of the variant. If it's a string, it will be appended to the key.
|
|
8
|
+
* @returns {string} The formatted variant label (e.g., "color: red" or "size").
|
|
9
|
+
*/
|
|
10
|
+
const getVariantLabel = (key, value) => `${key}${typeof value === 'string' ? `: ${value}` : ''}`;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Retrieves the variant options for a given component from the theme.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} componentName - The name of the component to get variants for.
|
|
16
|
+
* @returns {Array<Array>} An array of variant tuples. Each tuple contains:
|
|
17
|
+
* - {string|undefined} The variant key (e.g., 'size', 'color', or undefined for default).
|
|
18
|
+
* - {string|undefined} The variant value (e.g., 'small', 'primary', or undefined for default).
|
|
19
|
+
* - {string} The human-readable label for the variant.
|
|
20
|
+
* Returns [['default', {}]] if no componentName is provided.
|
|
21
|
+
* @throws {Error} If the theme does not define appearances for the given component.
|
|
22
|
+
*/
|
|
23
|
+
const useVariants = componentName => {
|
|
24
|
+
const theme = useTheme();
|
|
25
|
+
if (!componentName) return [['default', {}]];
|
|
26
|
+
const {
|
|
27
|
+
appearances
|
|
28
|
+
} = getComponentTheme(theme, componentName);
|
|
29
|
+
if (!appearances) {
|
|
30
|
+
throw new Error(`Theme ${theme.metadata?.name} does not have any appearances set for ${componentName}`);
|
|
31
|
+
}
|
|
32
|
+
const variants = Object.entries(appearances).reduce((pairs, _ref) => {
|
|
33
|
+
let [key, {
|
|
34
|
+
values,
|
|
35
|
+
type
|
|
36
|
+
} = {}] = _ref;
|
|
37
|
+
return type === 'variant' ? [...pairs, ...values.map(value => [key, value, getVariantLabel(key, value)])] : pairs;
|
|
38
|
+
}, [[undefined, undefined, 'default style']]);
|
|
39
|
+
return variants;
|
|
40
|
+
};
|
|
41
|
+
export default useVariants;
|
package/lib/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"@gorhom/portal": "^1.0.14",
|
|
13
13
|
"@react-native-picker/picker": "^2.9.0",
|
|
14
14
|
"@telus-uds/system-constants": "^3.0.0",
|
|
15
|
-
"@telus-uds/system-theme-tokens": "^4.
|
|
15
|
+
"@telus-uds/system-theme-tokens": "^4.7.0",
|
|
16
16
|
"airbnb-prop-types": "^2.16.0",
|
|
17
17
|
"css-mediaquery": "^0.1.2",
|
|
18
18
|
"expo-document-picker": "^13.0.1",
|
|
@@ -84,6 +84,6 @@
|
|
|
84
84
|
"standard-engine": {
|
|
85
85
|
"skip": true
|
|
86
86
|
},
|
|
87
|
-
"version": "3.
|
|
87
|
+
"version": "3.9.0",
|
|
88
88
|
"types": "types/index.d.ts"
|
|
89
89
|
}
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"@gorhom/portal": "^1.0.14",
|
|
13
13
|
"@react-native-picker/picker": "^2.9.0",
|
|
14
14
|
"@telus-uds/system-constants": "^3.0.0",
|
|
15
|
-
"@telus-uds/system-theme-tokens": "^4.
|
|
15
|
+
"@telus-uds/system-theme-tokens": "^4.7.0",
|
|
16
16
|
"airbnb-prop-types": "^2.16.0",
|
|
17
17
|
"css-mediaquery": "^0.1.2",
|
|
18
18
|
"expo-document-picker": "^13.0.1",
|
|
@@ -84,6 +84,6 @@
|
|
|
84
84
|
"standard-engine": {
|
|
85
85
|
"skip": true
|
|
86
86
|
},
|
|
87
|
-
"version": "3.
|
|
87
|
+
"version": "3.9.0",
|
|
88
88
|
"types": "types/index.d.ts"
|
|
89
89
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, StyleSheet, Platform } from 'react-native'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
import StackView from '../StackView'
|
|
5
|
+
import Typography from '../Typography'
|
|
6
|
+
import RenderActivityIndicator from './RenderActivityIndicator'
|
|
7
|
+
import { BACKDROP_Z_INDEX, SPACE_WITH_LABEL, SPACE_WITHOUT_LABEL } from './shared'
|
|
8
|
+
import { activityIndicatorCommonProps } from './sharedProptypes'
|
|
9
|
+
|
|
10
|
+
const FullScreenIndicator = React.forwardRef(
|
|
11
|
+
({ variantProps, label, labelPosition, labelMapping, backgroundColor, showLabel }, ref) => (
|
|
12
|
+
<View style={[staticStyles.fullScreenOverlay, { backgroundColor }]}>
|
|
13
|
+
<StackView
|
|
14
|
+
space={showLabel ? SPACE_WITH_LABEL : SPACE_WITHOUT_LABEL}
|
|
15
|
+
tokens={{ alignItems: 'center' }}
|
|
16
|
+
direction={labelMapping[labelPosition]}
|
|
17
|
+
>
|
|
18
|
+
<RenderActivityIndicator {...variantProps} ref={ref} label={label} />
|
|
19
|
+
{showLabel && <Typography>{label}</Typography>}
|
|
20
|
+
</StackView>
|
|
21
|
+
</View>
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
FullScreenIndicator.displayName = 'FullScreenIndicator'
|
|
26
|
+
|
|
27
|
+
const staticStyles = StyleSheet.create({
|
|
28
|
+
fullScreenOverlay: {
|
|
29
|
+
...Platform.select({
|
|
30
|
+
web: {
|
|
31
|
+
position: 'fixed',
|
|
32
|
+
top: 0,
|
|
33
|
+
left: 0,
|
|
34
|
+
width: '100vw',
|
|
35
|
+
height: '100vh',
|
|
36
|
+
zIndex: BACKDROP_Z_INDEX,
|
|
37
|
+
justifyContent: 'center',
|
|
38
|
+
alignItems: 'center'
|
|
39
|
+
},
|
|
40
|
+
default: {
|
|
41
|
+
position: 'absolute',
|
|
42
|
+
top: 0,
|
|
43
|
+
left: 0,
|
|
44
|
+
right: 0,
|
|
45
|
+
bottom: 0,
|
|
46
|
+
justifyContent: 'center',
|
|
47
|
+
alignItems: 'center',
|
|
48
|
+
...(Platform.OS === 'android' ? { elevation: 5 } : { zIndex: BACKDROP_Z_INDEX })
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
FullScreenIndicator.propTypes = {
|
|
55
|
+
/**
|
|
56
|
+
* Shared props
|
|
57
|
+
* */
|
|
58
|
+
...activityIndicatorCommonProps,
|
|
59
|
+
/**
|
|
60
|
+
* Background color for overlay
|
|
61
|
+
* */
|
|
62
|
+
backgroundColor: PropTypes.string.isRequired
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default FullScreenIndicator
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, StyleSheet, Platform } from 'react-native'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
import StackView from '../StackView'
|
|
5
|
+
import Typography from '../Typography'
|
|
6
|
+
import RenderActivityIndicator from './RenderActivityIndicator'
|
|
7
|
+
import { activityIndicatorCommonProps } from './sharedProptypes'
|
|
8
|
+
import { SPACE_WITH_LABEL, SPACE_WITHOUT_LABEL } from './shared'
|
|
9
|
+
|
|
10
|
+
const InlineIndicator = React.forwardRef(
|
|
11
|
+
({ variantProps, label, labelPosition, labelMapping, showLabel }, ref) => (
|
|
12
|
+
<View style={staticStyles.container}>
|
|
13
|
+
<StackView
|
|
14
|
+
space={showLabel ? SPACE_WITH_LABEL : SPACE_WITHOUT_LABEL}
|
|
15
|
+
direction={labelMapping[labelPosition]}
|
|
16
|
+
tokens={{ alignItems: 'center' }}
|
|
17
|
+
>
|
|
18
|
+
<RenderActivityIndicator {...variantProps} ref={ref} label={label} />
|
|
19
|
+
{showLabel && <Typography>{label}</Typography>}
|
|
20
|
+
</StackView>
|
|
21
|
+
</View>
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
InlineIndicator.displayName = 'InlineIndicator'
|
|
26
|
+
|
|
27
|
+
const staticStyles = StyleSheet.create({
|
|
28
|
+
container: {
|
|
29
|
+
flexDirection: 'column',
|
|
30
|
+
alignItems: 'center',
|
|
31
|
+
display: Platform.OS === 'web' ? 'inline-flex' : 'flex',
|
|
32
|
+
alignSelf: 'flex-start'
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
InlineIndicator.propTypes = {
|
|
37
|
+
/**
|
|
38
|
+
* Shared props
|
|
39
|
+
* */
|
|
40
|
+
...activityIndicatorCommonProps,
|
|
41
|
+
/**
|
|
42
|
+
* Whether the indicator sits inline with text/other elements
|
|
43
|
+
* */
|
|
44
|
+
inline: PropTypes.bool
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default InlineIndicator
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Platform, StyleSheet } from 'react-native'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
import StackView from '../StackView'
|
|
5
|
+
import Typography from '../Typography'
|
|
6
|
+
import RenderActivityIndicator from './RenderActivityIndicator'
|
|
7
|
+
import { BACKDROP_Z_INDEX, BACKDROP_OPACITY, SPACE_WITH_LABEL, SPACE_WITHOUT_LABEL } from './shared'
|
|
8
|
+
import { activityIndicatorCommonProps } from './sharedProptypes'
|
|
9
|
+
|
|
10
|
+
const recursiveMap = (nodeChildren, fn) =>
|
|
11
|
+
React.Children.map(nodeChildren, (child) => {
|
|
12
|
+
if (!React.isValidElement(child)) return child
|
|
13
|
+
if (child.props?.children) {
|
|
14
|
+
return fn(
|
|
15
|
+
React.cloneElement(child, {
|
|
16
|
+
children: recursiveMap(child.props.children, fn)
|
|
17
|
+
})
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
return fn(child)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const OverlayIndicator = React.forwardRef(
|
|
24
|
+
(
|
|
25
|
+
{
|
|
26
|
+
variantProps,
|
|
27
|
+
label,
|
|
28
|
+
labelPosition,
|
|
29
|
+
labelMapping,
|
|
30
|
+
children,
|
|
31
|
+
inline,
|
|
32
|
+
showLabel,
|
|
33
|
+
isActive = true
|
|
34
|
+
},
|
|
35
|
+
ref
|
|
36
|
+
) => {
|
|
37
|
+
const safeChildren =
|
|
38
|
+
Platform.OS === 'web' && isActive
|
|
39
|
+
? recursiveMap(children, (c) =>
|
|
40
|
+
React.isValidElement(c) ? React.cloneElement(c, { role: 'presentation' }) : c
|
|
41
|
+
)
|
|
42
|
+
: children
|
|
43
|
+
|
|
44
|
+
// inline + children
|
|
45
|
+
if (inline && children) {
|
|
46
|
+
return (
|
|
47
|
+
<View
|
|
48
|
+
style={[staticStyles.container, Platform.OS === 'web' && staticStyles.inlineContainer]}
|
|
49
|
+
>
|
|
50
|
+
<View style={staticStyles.backdropContainer}>{safeChildren}</View>
|
|
51
|
+
<View style={staticStyles.buttonOverlaySpinner}>
|
|
52
|
+
<RenderActivityIndicator {...variantProps} ref={ref} label={label} />
|
|
53
|
+
</View>
|
|
54
|
+
</View>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// overlay
|
|
59
|
+
return (
|
|
60
|
+
<View style={staticStyles.container}>
|
|
61
|
+
<View style={staticStyles.backdropContainer}>{safeChildren}</View>
|
|
62
|
+
|
|
63
|
+
<View
|
|
64
|
+
style={[
|
|
65
|
+
staticStyles.overlayContainer,
|
|
66
|
+
Platform.OS === 'web' && staticStyles.webOverlayContainer
|
|
67
|
+
]}
|
|
68
|
+
>
|
|
69
|
+
<StackView
|
|
70
|
+
space={showLabel ? SPACE_WITH_LABEL : SPACE_WITHOUT_LABEL}
|
|
71
|
+
tokens={{ alignItems: 'center' }}
|
|
72
|
+
direction={labelMapping[labelPosition]}
|
|
73
|
+
>
|
|
74
|
+
<RenderActivityIndicator {...variantProps} ref={ref} label={label} />
|
|
75
|
+
{showLabel && <Typography>{label}</Typography>}
|
|
76
|
+
</StackView>
|
|
77
|
+
</View>
|
|
78
|
+
</View>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
OverlayIndicator.displayName = 'OverlayIndicator'
|
|
84
|
+
|
|
85
|
+
const staticStyles = StyleSheet.create({
|
|
86
|
+
container: { position: 'relative' },
|
|
87
|
+
inlineContainer: { display: 'inline-flex' },
|
|
88
|
+
backdropContainer: { opacity: BACKDROP_OPACITY },
|
|
89
|
+
overlayContainer: {
|
|
90
|
+
position: 'absolute',
|
|
91
|
+
top: '50%',
|
|
92
|
+
left: '50%',
|
|
93
|
+
...Platform.select({
|
|
94
|
+
ios: { zIndex: BACKDROP_Z_INDEX },
|
|
95
|
+
android: { elevation: 5 }
|
|
96
|
+
})
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
webOverlayContainer: {
|
|
100
|
+
transform: [{ translateX: '-50%' }, { translateY: '-50%' }],
|
|
101
|
+
zIndex: BACKDROP_Z_INDEX
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
buttonOverlaySpinner: {
|
|
105
|
+
position: 'absolute',
|
|
106
|
+
top: '50%',
|
|
107
|
+
left: '50%',
|
|
108
|
+
...Platform.select({
|
|
109
|
+
web: {
|
|
110
|
+
transform: 'translate(-50%, -50%)',
|
|
111
|
+
zIndex: BACKDROP_Z_INDEX
|
|
112
|
+
},
|
|
113
|
+
default: {
|
|
114
|
+
transform: [{ translateX: -0.5 }, { translateY: -0.5 }],
|
|
115
|
+
zIndex: BACKDROP_Z_INDEX
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
OverlayIndicator.propTypes = {
|
|
122
|
+
/**
|
|
123
|
+
* Shared props
|
|
124
|
+
* */
|
|
125
|
+
...activityIndicatorCommonProps,
|
|
126
|
+
/**
|
|
127
|
+
* Background color for overlay
|
|
128
|
+
* */
|
|
129
|
+
inline: PropTypes.bool,
|
|
130
|
+
/**
|
|
131
|
+
* Children on which the overlay is drawn
|
|
132
|
+
* */
|
|
133
|
+
children: PropTypes.node,
|
|
134
|
+
/**
|
|
135
|
+
* Controls whether the overlay is active and should apply the presentation role
|
|
136
|
+
* */
|
|
137
|
+
isActive: PropTypes.bool
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export default OverlayIndicator
|