@telus-uds/components-base 3.22.0 → 3.23.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 +18 -1
- package/lib/cjs/Button/Button.js +2 -0
- package/lib/cjs/Button/ButtonBase.js +10 -5
- package/lib/cjs/Button/ButtonDropdown.js +2 -0
- package/lib/cjs/Button/ButtonGroup.js +45 -38
- package/lib/cjs/Button/propTypes.js +6 -0
- package/lib/cjs/Carousel/Carousel.js +52 -19
- package/lib/cjs/Carousel/CarouselItem/CarouselItem.js +23 -3
- package/lib/cjs/Icon/Icon.js +8 -11
- package/lib/cjs/Icon/IconText.js +0 -1
- package/lib/cjs/Listbox/GroupControl.js +33 -39
- package/lib/cjs/Listbox/Listbox.js +22 -13
- package/lib/cjs/Listbox/ListboxGroup.js +2 -1
- package/lib/cjs/Listbox/ListboxOverlay.js +5 -2
- package/lib/cjs/Listbox/PressableItem.js +8 -4
- package/lib/cjs/TextInput/TextInputBase.js +5 -1
- package/lib/cjs/Validator/Validator.js +171 -135
- package/lib/esm/Button/Button.js +2 -0
- package/lib/esm/Button/ButtonBase.js +10 -5
- package/lib/esm/Button/ButtonDropdown.js +2 -0
- package/lib/esm/Button/ButtonGroup.js +44 -39
- package/lib/esm/Button/propTypes.js +6 -0
- package/lib/esm/Carousel/Carousel.js +52 -19
- package/lib/esm/Carousel/CarouselItem/CarouselItem.js +23 -3
- package/lib/esm/Icon/Icon.js +8 -11
- package/lib/esm/Icon/IconText.js +0 -1
- package/lib/esm/Listbox/GroupControl.js +33 -39
- package/lib/esm/Listbox/Listbox.js +23 -14
- package/lib/esm/Listbox/ListboxGroup.js +2 -1
- package/lib/esm/Listbox/ListboxOverlay.js +5 -2
- package/lib/esm/Listbox/PressableItem.js +8 -4
- package/lib/esm/TextInput/TextInputBase.js +5 -1
- package/lib/esm/Validator/Validator.js +171 -135
- package/lib/package.json +2 -2
- package/package.json +2 -2
- package/src/Button/Button.jsx +2 -1
- package/src/Button/ButtonBase.jsx +18 -12
- package/src/Button/ButtonDropdown.jsx +2 -0
- package/src/Button/ButtonGroup.jsx +62 -45
- package/src/Button/propTypes.js +6 -0
- package/src/Carousel/Carousel.jsx +58 -5
- package/src/Carousel/CarouselItem/CarouselItem.jsx +31 -3
- package/src/Icon/Icon.jsx +11 -14
- package/src/Icon/IconText.jsx +0 -1
- package/src/Listbox/GroupControl.jsx +41 -47
- package/src/Listbox/Listbox.jsx +26 -9
- package/src/Listbox/ListboxGroup.jsx +2 -1
- package/src/Listbox/ListboxOverlay.jsx +7 -2
- package/src/Listbox/PressableItem.jsx +8 -4
- package/src/TextInput/TextInputBase.jsx +5 -1
- package/src/Validator/Validator.jsx +180 -159
|
@@ -7,8 +7,8 @@ exports.default = void 0;
|
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
9
9
|
var _View = _interopRequireDefault(require("react-native-web/dist/cjs/exports/View"));
|
|
10
|
-
var _StyleSheet = _interopRequireDefault(require("react-native-web/dist/cjs/exports/StyleSheet"));
|
|
11
10
|
var _Platform = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Platform"));
|
|
11
|
+
var _StyleSheet = _interopRequireDefault(require("react-native-web/dist/cjs/exports/StyleSheet"));
|
|
12
12
|
var _ThemeProvider = require("../ThemeProvider");
|
|
13
13
|
var _utils = require("../utils");
|
|
14
14
|
var _ExpandCollapse = _interopRequireDefault(require("../ExpandCollapse"));
|
|
@@ -21,11 +21,16 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
21
21
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
22
22
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
23
23
|
const styles = _StyleSheet.default.create({
|
|
24
|
-
|
|
24
|
+
container: {
|
|
25
25
|
padding: 0,
|
|
26
26
|
margin: 0
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
|
+
const selectContainerStyles = tokens => ({
|
|
30
|
+
minHeight: tokens.minHeight,
|
|
31
|
+
minWidth: tokens.minWidth,
|
|
32
|
+
backgroundColor: tokens.containerBackgroundColor
|
|
33
|
+
});
|
|
29
34
|
const getInitialOpen = (items, selectedId) => items.filter(item => item.items && item.items.some(nestedItem => (nestedItem.id ?? nestedItem.label) === selectedId)).map(item => item.id ?? item.label);
|
|
30
35
|
const Listbox = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
31
36
|
let {
|
|
@@ -39,14 +44,12 @@ const Listbox = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
|
39
44
|
itemRouterProps,
|
|
40
45
|
onClose,
|
|
41
46
|
variant,
|
|
42
|
-
tokens
|
|
47
|
+
tokens,
|
|
48
|
+
testID
|
|
43
49
|
} = _ref;
|
|
44
50
|
const initialOpen = getInitialOpen(items, defaultSelectedId);
|
|
45
51
|
const [selectedId, setSelectedId] = _react.default.useState(defaultSelectedId);
|
|
46
|
-
const
|
|
47
|
-
minHeight,
|
|
48
|
-
minWidth
|
|
49
|
-
} = (0, _ThemeProvider.useThemeTokens)('Listbox', variant, tokens);
|
|
52
|
+
const listboxTokens = (0, _ThemeProvider.useThemeTokens)('Listbox', tokens, variant);
|
|
50
53
|
|
|
51
54
|
// We need to keep track of each item's ref in order to be able to
|
|
52
55
|
// focus on a specific item via keyboard navigation
|
|
@@ -105,11 +108,9 @@ const Listbox = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
|
105
108
|
maxOpen: 1,
|
|
106
109
|
ref: ref,
|
|
107
110
|
children: expandProps => /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
|
|
108
|
-
style: [styles.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}],
|
|
112
|
-
role: "listbox",
|
|
111
|
+
style: [styles.container, selectContainerStyles(listboxTokens)],
|
|
112
|
+
accessibilityRole: "combobox",
|
|
113
|
+
testID: testID,
|
|
113
114
|
children: items.map((item, index) => {
|
|
114
115
|
const {
|
|
115
116
|
id,
|
|
@@ -171,7 +172,15 @@ Listbox.propTypes = {
|
|
|
171
172
|
/**
|
|
172
173
|
* onClose event
|
|
173
174
|
*/
|
|
174
|
-
onClose: _propTypes.default.func
|
|
175
|
+
onClose: _propTypes.default.func,
|
|
176
|
+
/**
|
|
177
|
+
* Test ID for testing
|
|
178
|
+
*/
|
|
179
|
+
testID: _propTypes.default.string,
|
|
180
|
+
/**
|
|
181
|
+
* Listbox variant
|
|
182
|
+
*/
|
|
183
|
+
variant: _utils.variantProp.propType
|
|
175
184
|
};
|
|
176
185
|
Listbox.Overlay = _ListboxOverlay.default;
|
|
177
186
|
var _default = exports.default = Listbox;
|
|
@@ -85,7 +85,8 @@ const ListboxGroup = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
|
85
85
|
borderColor: 'transparent',
|
|
86
86
|
borderRadius: 0,
|
|
87
87
|
borderWidth: 0,
|
|
88
|
-
marginBottom: 0
|
|
88
|
+
marginBottom: 0,
|
|
89
|
+
contentPanelBackgroundColor: 'transparent'
|
|
89
90
|
},
|
|
90
91
|
controlRef: ref,
|
|
91
92
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
|
|
@@ -37,12 +37,14 @@ const DropdownOverlay = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
|
37
37
|
maxWidth,
|
|
38
38
|
minWidth,
|
|
39
39
|
onLayout,
|
|
40
|
-
tokens
|
|
40
|
+
tokens,
|
|
41
|
+
testID
|
|
41
42
|
} = _ref;
|
|
42
43
|
const systemTokens = (0, _ThemeProvider.useThemeTokens)('Listbox', {}, {});
|
|
43
44
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
|
|
44
45
|
ref: ref,
|
|
45
46
|
onLayout: onLayout,
|
|
47
|
+
testID: testID,
|
|
46
48
|
style: [overlaidPosition, {
|
|
47
49
|
maxWidth,
|
|
48
50
|
minWidth
|
|
@@ -81,6 +83,7 @@ DropdownOverlay.propTypes = {
|
|
|
81
83
|
maxWidth: _propTypes.default.number,
|
|
82
84
|
minWidth: _propTypes.default.number,
|
|
83
85
|
onLayout: _propTypes.default.func,
|
|
84
|
-
tokens: _propTypes.default.object
|
|
86
|
+
tokens: _propTypes.default.object,
|
|
87
|
+
testID: _propTypes.default.string
|
|
85
88
|
};
|
|
86
89
|
var _default = exports.default = _Platform.default.OS === 'web' ? withPortal(DropdownOverlay) : DropdownOverlay;
|
|
@@ -48,10 +48,14 @@ const getItemStyles = _ref => {
|
|
|
48
48
|
color: itemColor,
|
|
49
49
|
outline: itemOutline,
|
|
50
50
|
textDecoration: itemTextDecoration,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
borderLeftWidth: itemBorderLeftWidth,
|
|
52
|
+
borderLeftColor: itemBorderLeftColor,
|
|
53
|
+
borderRightWidth: itemBorderRightWidth,
|
|
54
|
+
borderRightColor: itemBorderRightColor,
|
|
55
|
+
borderTopWidth: itemBorderTopWidth,
|
|
56
|
+
borderTopColor: itemBorderTopColor,
|
|
57
|
+
borderBottomWidth: itemBorderBottomWidth,
|
|
58
|
+
borderBottomColor: itemBorderBottomColor,
|
|
55
59
|
borderRadius: itemBorderRadius,
|
|
56
60
|
justifyContent: 'center'
|
|
57
61
|
};
|
|
@@ -286,6 +286,10 @@ const TextInputBase = /*#__PURE__*/_react.default.forwardRef((_ref8, ref) => {
|
|
|
286
286
|
// Add a space every 4 digits starting from the 5th position
|
|
287
287
|
filteredText = formattedValue.replace(regex, '$1 ').trim();
|
|
288
288
|
}
|
|
289
|
+
// Apply maxLength if provided
|
|
290
|
+
if (rest.maxLength && filteredText && filteredText.length > rest.maxLength) {
|
|
291
|
+
filteredText = filteredText.substring(0, rest.maxLength);
|
|
292
|
+
}
|
|
289
293
|
setValue(filteredText, event);
|
|
290
294
|
if (typeof onChangeText === 'function') onChangeText(filteredText, event);
|
|
291
295
|
};
|
|
@@ -358,7 +362,7 @@ const TextInputBase = /*#__PURE__*/_react.default.forwardRef((_ref8, ref) => {
|
|
|
358
362
|
onMouseOut: handleMouseOut,
|
|
359
363
|
onChange: handleChangeText,
|
|
360
364
|
defaultValue: initialValue,
|
|
361
|
-
maxLength: type === 'card' ? 19 :
|
|
365
|
+
maxLength: type === 'card' ? 19 : rest.maxLength,
|
|
362
366
|
value: isControlled ? currentValue : undefined,
|
|
363
367
|
onKeyPress
|
|
364
368
|
};
|
|
@@ -44,11 +44,10 @@ const Validator = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
44
44
|
supportsProps
|
|
45
45
|
} = selectProps(rest);
|
|
46
46
|
const strValidation = supportsProps.validation;
|
|
47
|
-
const [, setIndividualCodes] = _react.default.useState({});
|
|
48
|
-
const [text, setText] = _react.default.useState(value);
|
|
49
47
|
const validatorsLength = 6;
|
|
50
48
|
const prefix = 'code';
|
|
51
49
|
const sufixValidation = 'Validation';
|
|
50
|
+
const [codes, setCodes] = _react.default.useState(() => Array(validatorsLength).fill(''));
|
|
52
51
|
const [isHover, setIsHover] = _react.default.useState(false);
|
|
53
52
|
const handleMouseOver = () => {
|
|
54
53
|
setIsHover(true);
|
|
@@ -59,84 +58,87 @@ const Validator = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
59
58
|
const themeTokens = (0, _ThemeProvider.useThemeTokens)('TextInput', tokens, variant, {
|
|
60
59
|
hover: isHover
|
|
61
60
|
});
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
Array.from({
|
|
61
|
+
|
|
62
|
+
// Create refs for input elements
|
|
63
|
+
const codeReferences = _react.default.useMemo(() => {
|
|
64
|
+
return Array.from({
|
|
66
65
|
length: validatorsLength
|
|
67
|
-
}, (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
}, () => /*#__PURE__*/_react.default.createRef());
|
|
67
|
+
}, [validatorsLength]);
|
|
68
|
+
|
|
69
|
+
// Keep onChange and mask in refs to avoid re-creating event listeners
|
|
70
|
+
const onChangeRef = _react.default.useRef(onChange);
|
|
71
|
+
const maskRef = _react.default.useRef(mask);
|
|
72
|
+
_react.default.useEffect(() => {
|
|
73
|
+
onChangeRef.current = onChange;
|
|
74
|
+
maskRef.current = mask;
|
|
75
|
+
}, [onChange, mask]);
|
|
76
|
+
|
|
77
|
+
// Update a single code digit
|
|
78
|
+
const updateCode = _react.default.useCallback((index, digit) => {
|
|
79
|
+
setCodes(prevCodes => {
|
|
80
|
+
const newCodes = [...prevCodes];
|
|
81
|
+
newCodes[index] = digit;
|
|
82
|
+
if (onChangeRef.current) {
|
|
83
|
+
const codeString = newCodes.join('');
|
|
84
|
+
const singleCodesObj = {};
|
|
85
|
+
newCodes.forEach((code, i) => {
|
|
86
|
+
singleCodesObj[prefix + i] = code;
|
|
87
|
+
singleCodesObj[prefix + i + sufixValidation] = code ? 'success' : '';
|
|
88
|
+
});
|
|
89
|
+
onChangeRef.current(codeString, singleCodesObj);
|
|
90
|
+
}
|
|
91
|
+
return newCodes;
|
|
72
92
|
});
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
singleCodes[codeId + sufixValidation] = validation;
|
|
78
|
-
setIndividualCodes(prev => ({
|
|
79
|
-
...prev,
|
|
80
|
-
[codeId]: val
|
|
81
|
-
}));
|
|
82
|
-
}, [singleCodes, sufixValidation]);
|
|
83
|
-
const changeDataMasking = _react.default.useCallback(boxElement => {
|
|
84
|
-
let charMasking = '';
|
|
85
|
-
const element = boxElement;
|
|
86
|
-
if (mask && mask.length === 1) {
|
|
87
|
-
charMasking = mask;
|
|
88
|
-
} else if (mask && mask.length > 1) {
|
|
89
|
-
charMasking = mask.substring(0, 1);
|
|
90
|
-
}
|
|
91
|
-
if (charMasking && element) {
|
|
92
|
-
element.value = charMasking;
|
|
93
|
-
}
|
|
94
|
-
}, [mask]);
|
|
95
|
-
const handleChangeCode = _react.default.useCallback(() => {
|
|
96
|
-
const code = Array.from({
|
|
97
|
-
length: validatorsLength
|
|
98
|
-
}, (_, i) => singleCodes[prefix + i] || '').join('');
|
|
99
|
-
if (typeof onChange === 'function') {
|
|
100
|
-
onChange(code, singleCodes);
|
|
101
|
-
}
|
|
102
|
-
}, [validatorsLength, singleCodes, prefix, onChange]);
|
|
103
|
-
const handleChangeCodeValues = _react.default.useCallback((event, codeId, nextIndex) => {
|
|
104
|
-
const codeElement = codeReferences[codeId]?.current;
|
|
93
|
+
}, [prefix, sufixValidation]);
|
|
94
|
+
|
|
95
|
+
// Handle input change
|
|
96
|
+
const handleInputChange = _react.default.useCallback((index, event) => {
|
|
105
97
|
const val = event.nativeEvent?.value || event.target?.value;
|
|
106
98
|
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
if (codeElement && codeElement.value) {
|
|
110
|
-
codeElement.value = numericOnly;
|
|
111
|
-
}
|
|
112
|
-
handleSingleCodes(codeId, numericOnly, numericOnly ? 'success' : '');
|
|
113
|
-
handleChangeCode();
|
|
114
|
-
if (nextIndex === validatorsLength) {
|
|
115
|
-
codeElement?.blur();
|
|
116
|
-
changeDataMasking(codeElement);
|
|
99
|
+
// This prevents the infinite loop where setting element.value triggers another input event
|
|
100
|
+
if (maskRef.current && val === maskRef.current.substring(0, 1)) {
|
|
117
101
|
return;
|
|
118
102
|
}
|
|
119
|
-
|
|
120
|
-
|
|
103
|
+
const numericOnly = val.replace(/\D/g, '').substring(0, 1);
|
|
104
|
+
|
|
105
|
+
// Update state
|
|
106
|
+
updateCode(index, numericOnly);
|
|
107
|
+
|
|
108
|
+
// Update DOM element
|
|
109
|
+
const element = codeReferences[index]?.current;
|
|
110
|
+
if (element) {
|
|
111
|
+
if (maskRef.current && numericOnly) {
|
|
112
|
+
element.value = maskRef.current.substring(0, 1);
|
|
113
|
+
} else {
|
|
114
|
+
element.value = numericOnly;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Move to next field if digit entered
|
|
119
|
+
if (numericOnly && index < validatorsLength - 1) {
|
|
120
|
+
const nextElement = codeReferences[index + 1]?.current;
|
|
121
121
|
nextElement?.focus();
|
|
122
|
-
|
|
122
|
+
} else if (index === validatorsLength - 1) {
|
|
123
|
+
element?.blur();
|
|
123
124
|
}
|
|
124
|
-
}, [codeReferences,
|
|
125
|
-
|
|
125
|
+
}, [codeReferences, updateCode, validatorsLength]);
|
|
126
|
+
|
|
127
|
+
// Handle backspace
|
|
128
|
+
const handleKeyPress = _react.default.useCallback((index, event) => {
|
|
126
129
|
if (!(event.keyCode === 8 || event.code === 'Backspace')) {
|
|
127
130
|
return;
|
|
128
131
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
const currentElement = codeReferences[index]?.current;
|
|
133
|
+
if (currentElement) {
|
|
134
|
+
currentElement.value = '';
|
|
135
|
+
}
|
|
136
|
+
updateCode(index, '');
|
|
137
|
+
if (index > 0) {
|
|
138
|
+
const previousElement = codeReferences[index - 1]?.current;
|
|
135
139
|
previousElement?.focus();
|
|
136
140
|
}
|
|
137
|
-
|
|
138
|
-
handleChangeCode();
|
|
139
|
-
};
|
|
141
|
+
}, [codeReferences, updateCode]);
|
|
140
142
|
const getCodeComponents = () => {
|
|
141
143
|
return Array.from({
|
|
142
144
|
length: validatorsLength
|
|
@@ -145,11 +147,14 @@ const Validator = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
145
147
|
const codeInputProps = {
|
|
146
148
|
nativeID: codeId,
|
|
147
149
|
keyboardType: 'numeric',
|
|
148
|
-
ref: codeReferences[
|
|
149
|
-
validation: strValidation ||
|
|
150
|
+
ref: codeReferences[i] ?? null,
|
|
151
|
+
validation: strValidation || (codes[i] ? 'success' : ''),
|
|
150
152
|
tokens: selectCodeTextInputTokens(themeTokens),
|
|
153
|
+
// Only use secureTextEntry in React Native, web handles mask differently
|
|
154
|
+
secureTextEntry: !!(_Platform.default.OS !== 'web' && mask),
|
|
155
|
+
selectTextOnFocus: _Platform.default.OS !== 'web',
|
|
151
156
|
onFocus: () => {
|
|
152
|
-
const element = codeReferences[
|
|
157
|
+
const element = codeReferences[i]?.current;
|
|
153
158
|
if (_Platform.default.OS === 'web' && element?.select) {
|
|
154
159
|
return element.select() ?? null;
|
|
155
160
|
}
|
|
@@ -158,11 +163,35 @@ const Validator = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
158
163
|
}
|
|
159
164
|
return null;
|
|
160
165
|
},
|
|
161
|
-
onKeyPress: event => handleKeyPress(
|
|
166
|
+
onKeyPress: event => handleKeyPress(i, event),
|
|
162
167
|
onMouseOver: handleMouseOver,
|
|
163
168
|
onMouseOut: handleMouseOut,
|
|
164
169
|
inactive
|
|
165
170
|
};
|
|
171
|
+
|
|
172
|
+
// For React Native, use onChangeText and maxLength
|
|
173
|
+
if (_Platform.default.OS !== 'web') {
|
|
174
|
+
codeInputProps.maxLength = 1;
|
|
175
|
+
codeInputProps.value = codes[i];
|
|
176
|
+
codeInputProps.onChange = () => {};
|
|
177
|
+
codeInputProps.onChangeText = text => {
|
|
178
|
+
if (text) {
|
|
179
|
+
updateCode(i, text);
|
|
180
|
+
if (i < validatorsLength - 1) {
|
|
181
|
+
setTimeout(() => {
|
|
182
|
+
codeReferences[i + 1]?.current?.focus();
|
|
183
|
+
}, 50);
|
|
184
|
+
}
|
|
185
|
+
} else {
|
|
186
|
+
updateCode(i, '');
|
|
187
|
+
if (i > 0) {
|
|
188
|
+
setTimeout(() => {
|
|
189
|
+
codeReferences[i - 1]?.current?.focus();
|
|
190
|
+
}, 50);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
166
195
|
if (!codeInputProps.validation) {
|
|
167
196
|
delete codeInputProps.validation;
|
|
168
197
|
}
|
|
@@ -174,89 +203,96 @@ const Validator = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
174
203
|
}, codeId);
|
|
175
204
|
});
|
|
176
205
|
};
|
|
206
|
+
|
|
207
|
+
// Sync external value prop to internal state
|
|
177
208
|
_react.default.useEffect(() => {
|
|
178
|
-
if (Number(value).toString() !== 'NaN') {
|
|
179
|
-
|
|
209
|
+
if (value && Number(value).toString() !== 'NaN') {
|
|
210
|
+
const digits = value.split('').slice(0, validatorsLength);
|
|
211
|
+
const newCodes = Array(validatorsLength).fill('');
|
|
212
|
+
digits.forEach((digit, i) => {
|
|
213
|
+
if (/\d/.test(digit)) {
|
|
214
|
+
newCodes[i] = digit;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
setCodes(newCodes);
|
|
180
218
|
}
|
|
181
|
-
}, [value]);
|
|
219
|
+
}, [value, validatorsLength]);
|
|
220
|
+
|
|
221
|
+
// Sync codes state to DOM elements
|
|
182
222
|
_react.default.useEffect(() => {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}, (_, i) => {
|
|
186
|
-
const element = codeReferences[prefix + i]?.current;
|
|
223
|
+
codes.forEach((code, i) => {
|
|
224
|
+
const element = codeReferences[i]?.current;
|
|
187
225
|
if (element && element.value !== undefined) {
|
|
188
|
-
if (mask &&
|
|
189
|
-
element.value = mask;
|
|
226
|
+
if (mask && code) {
|
|
227
|
+
element.value = mask.substring(0, 1);
|
|
190
228
|
} else {
|
|
191
|
-
element.value =
|
|
229
|
+
element.value = code;
|
|
192
230
|
}
|
|
193
231
|
}
|
|
194
|
-
handleSingleCodes(prefix + i, text[i] ?? '', text[i] ? 'success' : '');
|
|
195
|
-
return null;
|
|
196
232
|
});
|
|
197
|
-
}, [
|
|
233
|
+
}, [codes, codeReferences, mask]);
|
|
234
|
+
|
|
235
|
+
// Setup event listeners - only runs once on mount
|
|
198
236
|
_react.default.useEffect(() => {
|
|
199
|
-
|
|
237
|
+
if (_Platform.default.OS !== 'web') {
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
const handlePaste = event => {
|
|
200
241
|
event.preventDefault();
|
|
201
|
-
|
|
202
|
-
// Clear current state first
|
|
203
|
-
setText('');
|
|
204
|
-
|
|
205
|
-
// Clear all individual input fields and their state
|
|
206
|
-
Array.from({
|
|
207
|
-
length: validatorsLength
|
|
208
|
-
}, (_, i) => {
|
|
209
|
-
const element = codeReferences[prefix + i]?.current;
|
|
210
|
-
if (element && element.value !== undefined) {
|
|
211
|
-
element.value = '';
|
|
212
|
-
}
|
|
213
|
-
handleSingleCodes(prefix + i, '', '');
|
|
214
|
-
return null;
|
|
215
|
-
});
|
|
216
242
|
const clipBoardText = event.clipboardData.getData('text');
|
|
217
|
-
|
|
218
|
-
// Validate that input contains only digits and truncate to 6 characters
|
|
219
243
|
const numericOnly = clipBoardText.replace(/\D/g, '').substring(0, validatorsLength);
|
|
220
|
-
|
|
221
|
-
|
|
244
|
+
const newCodes = Array(validatorsLength).fill('');
|
|
245
|
+
numericOnly.split('').forEach((digit, i) => {
|
|
246
|
+
newCodes[i] = digit;
|
|
247
|
+
});
|
|
248
|
+
setCodes(newCodes);
|
|
249
|
+
if (onChangeRef.current) {
|
|
250
|
+
const singleCodesObj = {};
|
|
251
|
+
newCodes.forEach((code, i) => {
|
|
252
|
+
singleCodesObj[prefix + i] = code;
|
|
253
|
+
singleCodesObj[prefix + i + sufixValidation] = code ? 'success' : '';
|
|
254
|
+
});
|
|
255
|
+
onChangeRef.current(numericOnly, singleCodesObj);
|
|
222
256
|
}
|
|
223
257
|
};
|
|
224
258
|
const handleCopy = event => {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
259
|
+
setCodes(currentCodes => {
|
|
260
|
+
const clipBoardText = currentCodes.join('');
|
|
261
|
+
event.clipboardData.setData('text/plain', clipBoardText);
|
|
262
|
+
event.preventDefault();
|
|
263
|
+
return currentCodes;
|
|
264
|
+
});
|
|
230
265
|
};
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
266
|
+
|
|
267
|
+
// Add event listeners to each input
|
|
268
|
+
codeReferences.forEach((inputRef, i) => {
|
|
269
|
+
const element = inputRef?.current;
|
|
270
|
+
if (element && typeof element.addEventListener === 'function') {
|
|
271
|
+
element.addEventListener('paste', handlePaste);
|
|
272
|
+
element.addEventListener('copy', handleCopy);
|
|
273
|
+
element.addEventListener('input', event => handleInputChange(i, event));
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Cleanup
|
|
278
|
+
return () => {
|
|
279
|
+
codeReferences.forEach(inputRef => {
|
|
280
|
+
const element = inputRef?.current;
|
|
281
|
+
if (element && typeof element.removeEventListener === 'function') {
|
|
282
|
+
element.removeEventListener('paste', handlePaste);
|
|
283
|
+
element.removeEventListener('copy', handleCopy);
|
|
284
|
+
element.removeEventListener('input', event => handleInputChange(event.target.dataset.index, event));
|
|
240
285
|
}
|
|
241
|
-
return null;
|
|
242
286
|
});
|
|
243
|
-
}
|
|
244
|
-
return () => {
|
|
245
|
-
if (_Platform.default.OS === 'web') {
|
|
246
|
-
Array.from({
|
|
247
|
-
length: validatorsLength
|
|
248
|
-
}, (_, i) => {
|
|
249
|
-
const element = codeReferences[prefix + i]?.current;
|
|
250
|
-
if (element && typeof element.removeEventListener === 'function') {
|
|
251
|
-
element.removeEventListener('paste', handlePasteCode);
|
|
252
|
-
element.removeEventListener('copy', handleCopy);
|
|
253
|
-
element.removeEventListener('input', event => handleChangeCodeValues(event, prefix + i, i + 1));
|
|
254
|
-
}
|
|
255
|
-
return null;
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
287
|
};
|
|
259
|
-
|
|
288
|
+
/*
|
|
289
|
+
* codeReferences and handleInputChange are intentionally omitted from dependencies
|
|
290
|
+
* because we want event listeners to be registered ONLY ONCE when the component mounts.
|
|
291
|
+
* codeReferences is stable (created with useMemo) and handleInputChange is stable (useCallback).
|
|
292
|
+
* Including them would cause unnecessary re-registration of listeners on each render.
|
|
293
|
+
*/
|
|
294
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
295
|
+
}, []);
|
|
260
296
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_InputSupports.default, {
|
|
261
297
|
...supportsProps,
|
|
262
298
|
feedbackProps: {
|
package/lib/esm/Button/Button.js
CHANGED
|
@@ -10,6 +10,7 @@ const Button = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
10
10
|
accessibilityRole = 'button',
|
|
11
11
|
tokens,
|
|
12
12
|
variant,
|
|
13
|
+
heightFull = true,
|
|
13
14
|
...props
|
|
14
15
|
} = _ref;
|
|
15
16
|
const viewport = useViewport();
|
|
@@ -27,6 +28,7 @@ const Button = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
27
28
|
return /*#__PURE__*/_jsx(ButtonBase, {
|
|
28
29
|
...props,
|
|
29
30
|
tokens: getTokens,
|
|
31
|
+
heightFull: heightFull,
|
|
30
32
|
accessibilityRole: accessibilityRole,
|
|
31
33
|
ref: ref,
|
|
32
34
|
viewport: viewport
|
|
@@ -33,23 +33,27 @@ const selectFlexAndWidthStyles = _ref2 => {
|
|
|
33
33
|
}
|
|
34
34
|
return styles;
|
|
35
35
|
};
|
|
36
|
-
const selectOuterContainerStyles = _ref3 => {
|
|
36
|
+
const selectOuterContainerStyles = (_ref3, heightFull) => {
|
|
37
37
|
let {
|
|
38
38
|
opacity,
|
|
39
39
|
outerBorderColor,
|
|
40
40
|
outerBorderWidth,
|
|
41
41
|
outerBorderGap,
|
|
42
42
|
borderRadius,
|
|
43
|
-
outerBackgroundColor
|
|
43
|
+
outerBackgroundColor,
|
|
44
|
+
alignSelf
|
|
44
45
|
} = _ref3;
|
|
45
46
|
return {
|
|
47
|
+
backgroundColor: outerBackgroundColor,
|
|
48
|
+
opacity,
|
|
46
49
|
...Platform.select({
|
|
47
50
|
native: {
|
|
51
|
+
alignSelf: alignSelf !== undefined ? alignSelf : 'flex-start'
|
|
52
|
+
},
|
|
53
|
+
web: heightFull ? {} : {
|
|
48
54
|
alignSelf: 'flex-start'
|
|
49
55
|
}
|
|
50
56
|
}),
|
|
51
|
-
backgroundColor: outerBackgroundColor,
|
|
52
|
-
opacity,
|
|
53
57
|
...applyOuterBorder({
|
|
54
58
|
outerBorderGap,
|
|
55
59
|
outerBorderWidth,
|
|
@@ -248,6 +252,7 @@ const ButtonBase = /*#__PURE__*/React.forwardRef((_ref12, ref) => {
|
|
|
248
252
|
icon,
|
|
249
253
|
iconPosition = icon ? 'left' : undefined,
|
|
250
254
|
iconProps,
|
|
255
|
+
heightFull = true,
|
|
251
256
|
...rawRest
|
|
252
257
|
} = _ref12;
|
|
253
258
|
const {
|
|
@@ -307,7 +312,7 @@ const ButtonBase = /*#__PURE__*/React.forwardRef((_ref12, ref) => {
|
|
|
307
312
|
}
|
|
308
313
|
const themeTokens = resolveButtonTokens(pressableState);
|
|
309
314
|
const flexAndWidthStyles = themeTokens.width === '100%' && themeTokens.flex === 1 ? selectFlexAndWidthStyles(themeTokens) : {};
|
|
310
|
-
return [staticStyles.row, selectWebOnlyStyles(inactive, themeTokens, systemProps), selectOuterContainerStyles(themeTokens), ...(Object.keys(flexAndWidthStyles).length > 0 ? [flexAndWidthStyles] : []), selectOuterSizeStyles(themeTokens)];
|
|
315
|
+
return [staticStyles.row, selectWebOnlyStyles(inactive, themeTokens, systemProps), selectOuterContainerStyles(themeTokens, heightFull), ...(Object.keys(flexAndWidthStyles).length > 0 ? [flexAndWidthStyles] : []), selectOuterSizeStyles(themeTokens)];
|
|
311
316
|
};
|
|
312
317
|
const dataSetProp = flexAndWidthStylesIds || rawRest.dataSet ? {
|
|
313
318
|
dataSet: {
|
|
@@ -103,6 +103,7 @@ const ButtonDropdown = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
103
103
|
accessibilityRole = 'radio',
|
|
104
104
|
description,
|
|
105
105
|
singleOption,
|
|
106
|
+
heightFull = true,
|
|
106
107
|
...props
|
|
107
108
|
} = _ref2;
|
|
108
109
|
const isFullWidth = variant?.width === FULL_WIDTH_STYLE;
|
|
@@ -145,6 +146,7 @@ const ButtonDropdown = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
145
146
|
...pressHandlers,
|
|
146
147
|
onPress: handlePress,
|
|
147
148
|
tokens: getButtonTokens,
|
|
149
|
+
heightFull: heightFull,
|
|
148
150
|
inactive: singleOption || inactive,
|
|
149
151
|
icon: () => null,
|
|
150
152
|
accessibilityRole: accessibilityRole,
|