@jobber/components 7.13.2 → 7.14.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/dist/Autocomplete/index.cjs +3 -2
- package/dist/Autocomplete/index.mjs +2 -1
- package/dist/DataList/components/DataListSearch/index.cjs +2 -1
- package/dist/DataList/components/DataListSearch/index.mjs +2 -1
- package/dist/DataList/index.cjs +2 -1
- package/dist/DataList/index.mjs +2 -1
- package/dist/DataTable/index.cjs +2 -1
- package/dist/DataTable/index.mjs +2 -1
- package/dist/FormField/index.cjs +11 -10
- package/dist/FormField/index.mjs +2 -1
- package/dist/FormField-cjs.js +7 -6
- package/dist/FormField-es.js +2 -1
- package/dist/FormFieldPostFix-cjs.js +250 -0
- package/dist/FormFieldPostFix-es.js +238 -0
- package/dist/InputDate/index.cjs +2 -1
- package/dist/InputDate/index.mjs +2 -1
- package/dist/InputEmail/index.cjs +1 -0
- package/dist/InputEmail/index.mjs +1 -0
- package/dist/InputEmail-cjs.js +4 -3
- package/dist/InputEmail-es.js +2 -1
- package/dist/InputNumber/index.cjs +2 -1
- package/dist/InputNumber/index.mjs +2 -1
- package/dist/InputPassword/index.cjs +2 -1
- package/dist/InputPassword/index.mjs +2 -1
- package/dist/InputPhoneNumber/InputPhoneNumber.d.ts +2 -2
- package/dist/InputPhoneNumber/InputPhoneNumber.types.d.ts +2 -20
- package/dist/InputPhoneNumber/hooks/useInputPhoneActions.d.ts +2 -2
- package/dist/InputPhoneNumber/index.cjs +13 -250
- package/dist/InputPhoneNumber/index.d.ts +2 -5
- package/dist/InputPhoneNumber/index.mjs +12 -253
- package/dist/InputPhoneNumber-cjs.js +190 -0
- package/dist/InputPhoneNumber-es.js +188 -0
- package/dist/InputText/index.cjs +5 -4
- package/dist/InputText/index.mjs +2 -1
- package/dist/InputTime/index.cjs +4 -3
- package/dist/InputTime/index.mjs +2 -1
- package/dist/RecurringSelect/index.cjs +2 -1
- package/dist/RecurringSelect/index.mjs +2 -1
- package/dist/Select/index.cjs +2 -1
- package/dist/Select/index.mjs +2 -1
- package/dist/Select-cjs.js +5 -4
- package/dist/Select-es.js +2 -1
- package/dist/docs/InputPhoneNumber/InputPhoneNumber.md +40 -21
- package/dist/docs/usage-guidelines/usage-guidelines.md +7 -8
- package/dist/index.cjs +13 -12
- package/dist/index.mjs +3 -2
- package/dist/mergeRefs-cjs.js +0 -248
- package/dist/mergeRefs-es.js +1 -238
- package/package.json +2 -2
- package/dist/InputPhoneNumber/InputPhoneNumber.rebuilt.d.ts +0 -3
|
@@ -1,262 +1,25 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
var reactHookForm = require('react-hook-form');
|
|
9
|
-
require('../Button-cjs.js');
|
|
10
|
-
require('@jobber/design');
|
|
11
|
-
var filterDataAttributes = require('../filterDataAttributes-cjs.js');
|
|
12
|
-
var FormField = require('../FormField-cjs.js');
|
|
3
|
+
var InputPhoneNumber = require('../InputPhoneNumber-cjs.js');
|
|
4
|
+
require('../tslib.es6-cjs.js');
|
|
5
|
+
require('react');
|
|
6
|
+
require('classnames');
|
|
7
|
+
require('../FormFieldPostFix-cjs.js');
|
|
13
8
|
require('@jobber/hooks');
|
|
14
9
|
require('framer-motion');
|
|
10
|
+
require('@jobber/design');
|
|
11
|
+
require('../Button-cjs.js');
|
|
12
|
+
require('react-router-dom');
|
|
15
13
|
require('../Icon-cjs.js');
|
|
16
|
-
require('../Text-cjs.js');
|
|
17
14
|
require('../Typography-cjs.js');
|
|
15
|
+
require('../Text-cjs.js');
|
|
18
16
|
require('../useFormFieldFocus-cjs.js');
|
|
19
17
|
require('../InputValidation-cjs.js');
|
|
20
18
|
require('../Spinner-cjs.js');
|
|
21
|
-
require('
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
function useInputMask({ value = "", pattern, delimiter = "*", strict = true, onChange, }) {
|
|
26
|
-
const [isMasking, setIsMasking] = React.useState(!value);
|
|
27
|
-
const patternInfo = React.useMemo(() => {
|
|
28
|
-
const patternChars = pattern.split("");
|
|
29
|
-
const specialChars = patternChars.filter(char => char !== delimiter);
|
|
30
|
-
const maxCleanChars = patternChars.filter(char => char === delimiter).length;
|
|
31
|
-
return {
|
|
32
|
-
patternChars,
|
|
33
|
-
specialChars,
|
|
34
|
-
maxCleanChars,
|
|
35
|
-
};
|
|
36
|
-
}, [pattern, delimiter]);
|
|
37
|
-
const inputValue = React.useMemo(() => {
|
|
38
|
-
return value
|
|
39
|
-
.split("")
|
|
40
|
-
.filter(char => !patternInfo.specialChars.includes(char))
|
|
41
|
-
.join("");
|
|
42
|
-
}, [value, patternInfo.specialChars]);
|
|
43
|
-
const formatValue = React.useCallback((unformattedValue) => {
|
|
44
|
-
const { patternChars, specialChars, maxCleanChars } = patternInfo;
|
|
45
|
-
const cleanValueChars = unformattedValue
|
|
46
|
-
.split("")
|
|
47
|
-
.filter(char => !specialChars.includes(char) && !Number.isNaN(Number(char)));
|
|
48
|
-
const isOverCharLimit = cleanValueChars.length > maxCleanChars;
|
|
49
|
-
if (!strict && isOverCharLimit) {
|
|
50
|
-
return cleanValueChars.join("");
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
const formattedValue = patternChars.reduce(getMaskedValue([...cleanValueChars], specialChars), "");
|
|
54
|
-
return formattedValue;
|
|
55
|
-
}
|
|
56
|
-
}, [patternInfo, strict]);
|
|
57
|
-
const maskedOnChange = React.useCallback((newValue, event) => {
|
|
58
|
-
const formatted = formatValue(newValue);
|
|
59
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(formatted, event);
|
|
60
|
-
}, [formatValue, onChange]);
|
|
61
|
-
const formattedValue = React.useMemo(() => formatValue(value), [formatValue, value]);
|
|
62
|
-
React.useEffect(() => {
|
|
63
|
-
const shouldMask = strict || inputValue.length < patternInfo.maxCleanChars;
|
|
64
|
-
setIsMasking(shouldMask);
|
|
65
|
-
}, [inputValue, patternInfo.maxCleanChars, strict]);
|
|
66
|
-
const placeholderMask = React.useMemo(() => pattern
|
|
67
|
-
.replace(new RegExp(`\\${delimiter}`, "g"), "_")
|
|
68
|
-
.slice(value.length), [pattern, delimiter, value]);
|
|
69
|
-
return {
|
|
70
|
-
formattedValue,
|
|
71
|
-
placeholderMask,
|
|
72
|
-
isMasking,
|
|
73
|
-
maskedOnChange,
|
|
74
|
-
inputValue,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
function getMaskedValue(cleanVal, specialChars) {
|
|
78
|
-
return (result, nextCharacter) => {
|
|
79
|
-
if (!cleanVal.length)
|
|
80
|
-
return result;
|
|
81
|
-
if (specialChars.includes(nextCharacter))
|
|
82
|
-
return result + nextCharacter;
|
|
83
|
-
const nextValue = cleanVal.shift();
|
|
84
|
-
return result + (nextValue !== undefined ? nextValue : "");
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function MaskElement({ isMasking, formattedValue, placeholderMask, }) {
|
|
89
|
-
if (!isMasking) {
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
return (React.createElement("div", { className: styles.mask, "aria-hidden": "true" },
|
|
93
|
-
React.createElement("span", { className: styles.hiddenValue }, formattedValue),
|
|
94
|
-
React.createElement("span", null, placeholderMask)));
|
|
95
|
-
}
|
|
96
|
-
function InputMask({ children, delimiter = "*", pattern, strict = true, }) {
|
|
97
|
-
const { value: inputValue, onChange } = children.props;
|
|
98
|
-
const { placeholderMask, isMasking, formattedValue, maskedOnChange } = useInputMask({
|
|
99
|
-
value: String(inputValue || ""),
|
|
100
|
-
pattern,
|
|
101
|
-
delimiter,
|
|
102
|
-
strict,
|
|
103
|
-
onChange: onChange,
|
|
104
|
-
});
|
|
105
|
-
const inputMask = (React.createElement(MaskElement, { isMasking: isMasking, formattedValue: formattedValue, placeholderMask: placeholderMask }));
|
|
106
|
-
return React.cloneElement(children, {
|
|
107
|
-
onChange: maskedOnChange,
|
|
108
|
-
children: isMasking && inputMask,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const DEFAULT_PATTERN = "(***) ***-****";
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Combines the actions on the InputPhoneNumber such as onChange, onEnter, onFocus, onBlur, and onClear to forward information to the consumers of the InputPhoneNumber.
|
|
116
|
-
* Do not repeat this pattern. We are doing this as a proof of concept relating to the refactoring of Form inputs to see what can be removed.
|
|
117
|
-
*/
|
|
118
|
-
function useInputPhoneActions({ onChange, inputRef, onFocus, onBlur, onKeyDown, onEnter, onClick, onMouseDown, onMouseUp, onPointerDown, onPointerUp, }) {
|
|
119
|
-
function handleClear() {
|
|
120
|
-
var _a;
|
|
121
|
-
onChange && onChange("");
|
|
122
|
-
(_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
123
|
-
}
|
|
124
|
-
function handleChange(event) {
|
|
125
|
-
const newValue = event.currentTarget.value;
|
|
126
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(newValue, event);
|
|
127
|
-
}
|
|
128
|
-
function handleFocus(event) {
|
|
129
|
-
onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
|
|
130
|
-
}
|
|
131
|
-
function handleKeyDown(event) {
|
|
132
|
-
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
|
|
133
|
-
if (!onEnter)
|
|
134
|
-
return;
|
|
135
|
-
if (event.key !== "Enter")
|
|
136
|
-
return;
|
|
137
|
-
if (event.shiftKey || event.ctrlKey)
|
|
138
|
-
return;
|
|
139
|
-
event.preventDefault();
|
|
140
|
-
onEnter === null || onEnter === void 0 ? void 0 : onEnter(event);
|
|
141
|
-
}
|
|
142
|
-
function handleBlur(event) {
|
|
143
|
-
onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
|
|
144
|
-
}
|
|
145
|
-
function handleClick(event) {
|
|
146
|
-
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
147
|
-
}
|
|
148
|
-
function handleMouseDown(event) {
|
|
149
|
-
onMouseDown === null || onMouseDown === void 0 ? void 0 : onMouseDown(event);
|
|
150
|
-
}
|
|
151
|
-
function handleMouseUp(event) {
|
|
152
|
-
onMouseUp === null || onMouseUp === void 0 ? void 0 : onMouseUp(event);
|
|
153
|
-
}
|
|
154
|
-
function handlePointerDown(event) {
|
|
155
|
-
onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
|
|
156
|
-
}
|
|
157
|
-
function handlePointerUp(event) {
|
|
158
|
-
onPointerUp === null || onPointerUp === void 0 ? void 0 : onPointerUp(event);
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
handleClear,
|
|
162
|
-
handleChange,
|
|
163
|
-
handleFocus,
|
|
164
|
-
handleBlur,
|
|
165
|
-
handleKeyDown,
|
|
166
|
-
handleClick,
|
|
167
|
-
handleMouseDown,
|
|
168
|
-
handleMouseUp,
|
|
169
|
-
handlePointerDown,
|
|
170
|
-
handlePointerUp,
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const InputPhoneNumberRebuilt = React.forwardRef(function InputPhoneNumberInternal(_a, ref) {
|
|
175
|
-
var _b, _c, _d, _e;
|
|
176
|
-
var { pattern = DEFAULT_PATTERN } = _a, props = tslib_es6.__rest(_a, ["pattern"]);
|
|
177
|
-
const inputPhoneNumberRef = (_b = ref) !== null && _b !== void 0 ? _b : React.useRef(null);
|
|
178
|
-
const wrapperRef = React.useRef(null);
|
|
179
|
-
const generatedId = React.useId();
|
|
180
|
-
const id = props.id || generatedId;
|
|
181
|
-
const { name } = useAtlantisFormFieldName.useAtlantisFormFieldName({
|
|
182
|
-
nameProp: props.name,
|
|
183
|
-
id: id,
|
|
184
|
-
});
|
|
185
|
-
const { formattedValue, isMasking, placeholderMask, inputValue, maskedOnChange, } = useInputMask({
|
|
186
|
-
value: props.value,
|
|
187
|
-
pattern,
|
|
188
|
-
strict: false,
|
|
189
|
-
onChange: props.onChange,
|
|
190
|
-
});
|
|
191
|
-
const { handleChange, handleBlur, handleFocus, handleClear, handleKeyDown, handleClick, handleMouseDown, handleMouseUp, handlePointerDown, handlePointerUp, } = useInputPhoneActions({
|
|
192
|
-
onChange: maskedOnChange,
|
|
193
|
-
onBlur: props.onBlur,
|
|
194
|
-
onFocus: props.onFocus,
|
|
195
|
-
onEnter: props.onEnter,
|
|
196
|
-
onKeyDown: props.onKeyDown,
|
|
197
|
-
onClick: props.onClick,
|
|
198
|
-
onMouseDown: props.onMouseDown,
|
|
199
|
-
onMouseUp: props.onMouseUp,
|
|
200
|
-
onPointerDown: props.onPointerDown,
|
|
201
|
-
onPointerUp: props.onPointerUp,
|
|
202
|
-
inputRef: inputPhoneNumberRef,
|
|
203
|
-
});
|
|
204
|
-
const descriptionIdentifier = `descriptionUUID--${id}`, descriptionVisible = props.description && !props.inline;
|
|
205
|
-
const isInvalid = Boolean(props.error || props.invalid);
|
|
206
|
-
const dataAttrs = filterDataAttributes.filterDataAttributes(props);
|
|
207
|
-
return (React.createElement(mergeRefs.FormFieldWrapper, { disabled: props.disabled, size: props.size, inline: props.inline, wrapperRef: wrapperRef, error: (_c = props.error) !== null && _c !== void 0 ? _c : "", invalid: Boolean(props.error || props.invalid), identifier: id, descriptionIdentifier: descriptionIdentifier, description: props.description, clearable: (_d = props.clearable) !== null && _d !== void 0 ? _d : "never", onClear: handleClear, type: "tel", placeholder: props.placeholder, value: formattedValue, prefix: props.prefix, suffix: props.suffix, readonly: props.readOnly, loading: props.loading },
|
|
208
|
-
React.createElement("input", Object.assign({ id: id, name: name, type: "tel", ref: inputPhoneNumberRef, className: classnames(mergeRefs.formFieldStyles.input, {
|
|
209
|
-
[styles.emptyValue]: inputValue.length === 0 && pattern[0] === "(",
|
|
210
|
-
}), value: formattedValue, disabled: props.disabled, readOnly: props.readOnly, autoFocus: props.autoFocus, autoComplete: props.autoComplete, inputMode: props.inputMode, tabIndex: props.tabIndex, required: props.required, role: props.role, "aria-label": props["aria-label"], "aria-describedby": descriptionVisible
|
|
211
|
-
? descriptionIdentifier
|
|
212
|
-
: props["aria-describedby"], "aria-invalid": isInvalid ? true : undefined, "aria-controls": props["aria-controls"], "aria-expanded": props["aria-expanded"], "aria-activedescendant": props["aria-activedescendant"], "aria-autocomplete": props["aria-autocomplete"], "aria-required": props["aria-required"], onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, onKeyDown: handleKeyDown, onClick: handleClick, onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, onPointerDown: handlePointerDown, onPointerUp: handlePointerUp }, dataAttrs)),
|
|
213
|
-
React.createElement(MaskElement, { isMasking: isMasking, formattedValue: formattedValue, placeholderMask: placeholderMask }),
|
|
214
|
-
React.createElement(mergeRefs.FormFieldPostFix, { variation: "spinner", visible: (_e = props.loading) !== null && _e !== void 0 ? _e : false })));
|
|
215
|
-
});
|
|
19
|
+
require('../useAtlantisFormFieldName-cjs.js');
|
|
20
|
+
require('react-hook-form');
|
|
21
|
+
require('../filterDataAttributes-cjs.js');
|
|
216
22
|
|
|
217
|
-
function InputPhoneNumber$1(_a) {
|
|
218
|
-
var { required } = _a, props = tslib_es6.__rest(_a, ["required"]);
|
|
219
|
-
const { placeholder, validations, pattern = DEFAULT_PATTERN } = props;
|
|
220
|
-
const errorSubject = placeholder || "Phone number";
|
|
221
|
-
const { getValues } = reactHookForm.useFormContext() != undefined
|
|
222
|
-
? reactHookForm.useFormContext()
|
|
223
|
-
: // If there isn't a Form Context being provided, get a form for this field.
|
|
224
|
-
reactHookForm.useForm({ mode: "onTouched" });
|
|
225
|
-
return (React.createElement(InputMask, { pattern: pattern, strict: false },
|
|
226
|
-
React.createElement(FormField.FormField, Object.assign({}, props, { type: "tel", pattern: pattern, validations: Object.assign(Object.assign({ required: {
|
|
227
|
-
value: Boolean(required),
|
|
228
|
-
message: `${errorSubject} is required`,
|
|
229
|
-
} }, validations), { validate: getPhoneNumberValidation }) }))));
|
|
230
|
-
function getPhoneNumberValidation(value) {
|
|
231
|
-
// Get unique characters that aren't * in the pattern
|
|
232
|
-
const patternNonDelimterCharacters = pattern
|
|
233
|
-
.split("")
|
|
234
|
-
.filter(char => char !== "*")
|
|
235
|
-
.filter((char, index, arr) => arr.indexOf(char) === index);
|
|
236
|
-
const specialCharacters = patternNonDelimterCharacters.join(" ");
|
|
237
|
-
// Remove special characters from pattern
|
|
238
|
-
const cleanValue = value.replace(new RegExp(`[${specialCharacters}]`, "g"), "");
|
|
239
|
-
const cleanValueRequiredLength = (pattern.match(/\*/g) || []).length;
|
|
240
|
-
if (cleanValue.length > 0 && cleanValue.length < cleanValueRequiredLength) {
|
|
241
|
-
return `${errorSubject} must contain ${cleanValueRequiredLength} or more digits`;
|
|
242
|
-
}
|
|
243
|
-
if (typeof (validations === null || validations === void 0 ? void 0 : validations.validate) === "function") {
|
|
244
|
-
return validations.validate(value, getValues);
|
|
245
|
-
}
|
|
246
|
-
return true;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
23
|
|
|
250
|
-
function isNewInputPhoneNumberProps(props) {
|
|
251
|
-
return props.version === 2;
|
|
252
|
-
}
|
|
253
|
-
const InputPhoneNumber = React.forwardRef(function InputPhoneNumberShim(props, ref) {
|
|
254
|
-
if (isNewInputPhoneNumberProps(props)) {
|
|
255
|
-
return React.createElement(InputPhoneNumberRebuilt, Object.assign({}, props, { ref: ref }));
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
return React.createElement(InputPhoneNumber$1, Object.assign({}, props));
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
24
|
|
|
262
|
-
exports.InputPhoneNumber = InputPhoneNumber;
|
|
25
|
+
exports.InputPhoneNumber = InputPhoneNumber.InputPhoneNumber;
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export type InputPhoneNumberShimProps = InputPhoneNumberLegacyProps | InputPhoneNumberRebuiltProps;
|
|
4
|
-
export declare const InputPhoneNumber: React.ForwardRefExoticComponent<InputPhoneNumberShimProps & React.RefAttributes<HTMLInputElement>>;
|
|
5
|
-
export type { InputPhoneNumberLegacyProps, InputPhoneNumberRebuiltProps };
|
|
1
|
+
export type { InputPhoneNumberProps } from "./InputPhoneNumber.types";
|
|
2
|
+
export { InputPhoneNumber } from "./InputPhoneNumber";
|
|
@@ -1,260 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { useFormContext, useForm } from 'react-hook-form';
|
|
7
|
-
import '../Button-es.js';
|
|
8
|
-
import '@jobber/design';
|
|
9
|
-
import { f as filterDataAttributes } from '../filterDataAttributes-es.js';
|
|
10
|
-
import { F as FormField } from '../FormField-es.js';
|
|
1
|
+
export { I as InputPhoneNumber } from '../InputPhoneNumber-es.js';
|
|
2
|
+
import '../tslib.es6-es.js';
|
|
3
|
+
import 'react';
|
|
4
|
+
import 'classnames';
|
|
5
|
+
import '../FormFieldPostFix-es.js';
|
|
11
6
|
import '@jobber/hooks';
|
|
12
7
|
import 'framer-motion';
|
|
8
|
+
import '@jobber/design';
|
|
9
|
+
import '../Button-es.js';
|
|
10
|
+
import 'react-router-dom';
|
|
13
11
|
import '../Icon-es.js';
|
|
14
|
-
import '../Text-es.js';
|
|
15
12
|
import '../Typography-es.js';
|
|
13
|
+
import '../Text-es.js';
|
|
16
14
|
import '../useFormFieldFocus-es.js';
|
|
17
15
|
import '../InputValidation-es.js';
|
|
18
16
|
import '../Spinner-es.js';
|
|
19
|
-
import '
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
function useInputMask({ value = "", pattern, delimiter = "*", strict = true, onChange, }) {
|
|
24
|
-
const [isMasking, setIsMasking] = useState(!value);
|
|
25
|
-
const patternInfo = useMemo(() => {
|
|
26
|
-
const patternChars = pattern.split("");
|
|
27
|
-
const specialChars = patternChars.filter(char => char !== delimiter);
|
|
28
|
-
const maxCleanChars = patternChars.filter(char => char === delimiter).length;
|
|
29
|
-
return {
|
|
30
|
-
patternChars,
|
|
31
|
-
specialChars,
|
|
32
|
-
maxCleanChars,
|
|
33
|
-
};
|
|
34
|
-
}, [pattern, delimiter]);
|
|
35
|
-
const inputValue = useMemo(() => {
|
|
36
|
-
return value
|
|
37
|
-
.split("")
|
|
38
|
-
.filter(char => !patternInfo.specialChars.includes(char))
|
|
39
|
-
.join("");
|
|
40
|
-
}, [value, patternInfo.specialChars]);
|
|
41
|
-
const formatValue = useCallback((unformattedValue) => {
|
|
42
|
-
const { patternChars, specialChars, maxCleanChars } = patternInfo;
|
|
43
|
-
const cleanValueChars = unformattedValue
|
|
44
|
-
.split("")
|
|
45
|
-
.filter(char => !specialChars.includes(char) && !Number.isNaN(Number(char)));
|
|
46
|
-
const isOverCharLimit = cleanValueChars.length > maxCleanChars;
|
|
47
|
-
if (!strict && isOverCharLimit) {
|
|
48
|
-
return cleanValueChars.join("");
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
const formattedValue = patternChars.reduce(getMaskedValue([...cleanValueChars], specialChars), "");
|
|
52
|
-
return formattedValue;
|
|
53
|
-
}
|
|
54
|
-
}, [patternInfo, strict]);
|
|
55
|
-
const maskedOnChange = useCallback((newValue, event) => {
|
|
56
|
-
const formatted = formatValue(newValue);
|
|
57
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(formatted, event);
|
|
58
|
-
}, [formatValue, onChange]);
|
|
59
|
-
const formattedValue = useMemo(() => formatValue(value), [formatValue, value]);
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
const shouldMask = strict || inputValue.length < patternInfo.maxCleanChars;
|
|
62
|
-
setIsMasking(shouldMask);
|
|
63
|
-
}, [inputValue, patternInfo.maxCleanChars, strict]);
|
|
64
|
-
const placeholderMask = useMemo(() => pattern
|
|
65
|
-
.replace(new RegExp(`\\${delimiter}`, "g"), "_")
|
|
66
|
-
.slice(value.length), [pattern, delimiter, value]);
|
|
67
|
-
return {
|
|
68
|
-
formattedValue,
|
|
69
|
-
placeholderMask,
|
|
70
|
-
isMasking,
|
|
71
|
-
maskedOnChange,
|
|
72
|
-
inputValue,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
function getMaskedValue(cleanVal, specialChars) {
|
|
76
|
-
return (result, nextCharacter) => {
|
|
77
|
-
if (!cleanVal.length)
|
|
78
|
-
return result;
|
|
79
|
-
if (specialChars.includes(nextCharacter))
|
|
80
|
-
return result + nextCharacter;
|
|
81
|
-
const nextValue = cleanVal.shift();
|
|
82
|
-
return result + (nextValue !== undefined ? nextValue : "");
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function MaskElement({ isMasking, formattedValue, placeholderMask, }) {
|
|
87
|
-
if (!isMasking) {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
return (React__default.createElement("div", { className: styles.mask, "aria-hidden": "true" },
|
|
91
|
-
React__default.createElement("span", { className: styles.hiddenValue }, formattedValue),
|
|
92
|
-
React__default.createElement("span", null, placeholderMask)));
|
|
93
|
-
}
|
|
94
|
-
function InputMask({ children, delimiter = "*", pattern, strict = true, }) {
|
|
95
|
-
const { value: inputValue, onChange } = children.props;
|
|
96
|
-
const { placeholderMask, isMasking, formattedValue, maskedOnChange } = useInputMask({
|
|
97
|
-
value: String(inputValue || ""),
|
|
98
|
-
pattern,
|
|
99
|
-
delimiter,
|
|
100
|
-
strict,
|
|
101
|
-
onChange: onChange,
|
|
102
|
-
});
|
|
103
|
-
const inputMask = (React__default.createElement(MaskElement, { isMasking: isMasking, formattedValue: formattedValue, placeholderMask: placeholderMask }));
|
|
104
|
-
return cloneElement(children, {
|
|
105
|
-
onChange: maskedOnChange,
|
|
106
|
-
children: isMasking && inputMask,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const DEFAULT_PATTERN = "(***) ***-****";
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Combines the actions on the InputPhoneNumber such as onChange, onEnter, onFocus, onBlur, and onClear to forward information to the consumers of the InputPhoneNumber.
|
|
114
|
-
* Do not repeat this pattern. We are doing this as a proof of concept relating to the refactoring of Form inputs to see what can be removed.
|
|
115
|
-
*/
|
|
116
|
-
function useInputPhoneActions({ onChange, inputRef, onFocus, onBlur, onKeyDown, onEnter, onClick, onMouseDown, onMouseUp, onPointerDown, onPointerUp, }) {
|
|
117
|
-
function handleClear() {
|
|
118
|
-
var _a;
|
|
119
|
-
onChange && onChange("");
|
|
120
|
-
(_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
121
|
-
}
|
|
122
|
-
function handleChange(event) {
|
|
123
|
-
const newValue = event.currentTarget.value;
|
|
124
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(newValue, event);
|
|
125
|
-
}
|
|
126
|
-
function handleFocus(event) {
|
|
127
|
-
onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
|
|
128
|
-
}
|
|
129
|
-
function handleKeyDown(event) {
|
|
130
|
-
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
|
|
131
|
-
if (!onEnter)
|
|
132
|
-
return;
|
|
133
|
-
if (event.key !== "Enter")
|
|
134
|
-
return;
|
|
135
|
-
if (event.shiftKey || event.ctrlKey)
|
|
136
|
-
return;
|
|
137
|
-
event.preventDefault();
|
|
138
|
-
onEnter === null || onEnter === void 0 ? void 0 : onEnter(event);
|
|
139
|
-
}
|
|
140
|
-
function handleBlur(event) {
|
|
141
|
-
onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
|
|
142
|
-
}
|
|
143
|
-
function handleClick(event) {
|
|
144
|
-
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
145
|
-
}
|
|
146
|
-
function handleMouseDown(event) {
|
|
147
|
-
onMouseDown === null || onMouseDown === void 0 ? void 0 : onMouseDown(event);
|
|
148
|
-
}
|
|
149
|
-
function handleMouseUp(event) {
|
|
150
|
-
onMouseUp === null || onMouseUp === void 0 ? void 0 : onMouseUp(event);
|
|
151
|
-
}
|
|
152
|
-
function handlePointerDown(event) {
|
|
153
|
-
onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
|
|
154
|
-
}
|
|
155
|
-
function handlePointerUp(event) {
|
|
156
|
-
onPointerUp === null || onPointerUp === void 0 ? void 0 : onPointerUp(event);
|
|
157
|
-
}
|
|
158
|
-
return {
|
|
159
|
-
handleClear,
|
|
160
|
-
handleChange,
|
|
161
|
-
handleFocus,
|
|
162
|
-
handleBlur,
|
|
163
|
-
handleKeyDown,
|
|
164
|
-
handleClick,
|
|
165
|
-
handleMouseDown,
|
|
166
|
-
handleMouseUp,
|
|
167
|
-
handlePointerDown,
|
|
168
|
-
handlePointerUp,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const InputPhoneNumberRebuilt = forwardRef(function InputPhoneNumberInternal(_a, ref) {
|
|
173
|
-
var _b, _c, _d, _e;
|
|
174
|
-
var { pattern = DEFAULT_PATTERN } = _a, props = __rest(_a, ["pattern"]);
|
|
175
|
-
const inputPhoneNumberRef = (_b = ref) !== null && _b !== void 0 ? _b : React__default.useRef(null);
|
|
176
|
-
const wrapperRef = React__default.useRef(null);
|
|
177
|
-
const generatedId = useId();
|
|
178
|
-
const id = props.id || generatedId;
|
|
179
|
-
const { name } = useAtlantisFormFieldName({
|
|
180
|
-
nameProp: props.name,
|
|
181
|
-
id: id,
|
|
182
|
-
});
|
|
183
|
-
const { formattedValue, isMasking, placeholderMask, inputValue, maskedOnChange, } = useInputMask({
|
|
184
|
-
value: props.value,
|
|
185
|
-
pattern,
|
|
186
|
-
strict: false,
|
|
187
|
-
onChange: props.onChange,
|
|
188
|
-
});
|
|
189
|
-
const { handleChange, handleBlur, handleFocus, handleClear, handleKeyDown, handleClick, handleMouseDown, handleMouseUp, handlePointerDown, handlePointerUp, } = useInputPhoneActions({
|
|
190
|
-
onChange: maskedOnChange,
|
|
191
|
-
onBlur: props.onBlur,
|
|
192
|
-
onFocus: props.onFocus,
|
|
193
|
-
onEnter: props.onEnter,
|
|
194
|
-
onKeyDown: props.onKeyDown,
|
|
195
|
-
onClick: props.onClick,
|
|
196
|
-
onMouseDown: props.onMouseDown,
|
|
197
|
-
onMouseUp: props.onMouseUp,
|
|
198
|
-
onPointerDown: props.onPointerDown,
|
|
199
|
-
onPointerUp: props.onPointerUp,
|
|
200
|
-
inputRef: inputPhoneNumberRef,
|
|
201
|
-
});
|
|
202
|
-
const descriptionIdentifier = `descriptionUUID--${id}`, descriptionVisible = props.description && !props.inline;
|
|
203
|
-
const isInvalid = Boolean(props.error || props.invalid);
|
|
204
|
-
const dataAttrs = filterDataAttributes(props);
|
|
205
|
-
return (React__default.createElement(FormFieldWrapper, { disabled: props.disabled, size: props.size, inline: props.inline, wrapperRef: wrapperRef, error: (_c = props.error) !== null && _c !== void 0 ? _c : "", invalid: Boolean(props.error || props.invalid), identifier: id, descriptionIdentifier: descriptionIdentifier, description: props.description, clearable: (_d = props.clearable) !== null && _d !== void 0 ? _d : "never", onClear: handleClear, type: "tel", placeholder: props.placeholder, value: formattedValue, prefix: props.prefix, suffix: props.suffix, readonly: props.readOnly, loading: props.loading },
|
|
206
|
-
React__default.createElement("input", Object.assign({ id: id, name: name, type: "tel", ref: inputPhoneNumberRef, className: classnames(formFieldStyles.input, {
|
|
207
|
-
[styles.emptyValue]: inputValue.length === 0 && pattern[0] === "(",
|
|
208
|
-
}), value: formattedValue, disabled: props.disabled, readOnly: props.readOnly, autoFocus: props.autoFocus, autoComplete: props.autoComplete, inputMode: props.inputMode, tabIndex: props.tabIndex, required: props.required, role: props.role, "aria-label": props["aria-label"], "aria-describedby": descriptionVisible
|
|
209
|
-
? descriptionIdentifier
|
|
210
|
-
: props["aria-describedby"], "aria-invalid": isInvalid ? true : undefined, "aria-controls": props["aria-controls"], "aria-expanded": props["aria-expanded"], "aria-activedescendant": props["aria-activedescendant"], "aria-autocomplete": props["aria-autocomplete"], "aria-required": props["aria-required"], onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, onKeyDown: handleKeyDown, onClick: handleClick, onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, onPointerDown: handlePointerDown, onPointerUp: handlePointerUp }, dataAttrs)),
|
|
211
|
-
React__default.createElement(MaskElement, { isMasking: isMasking, formattedValue: formattedValue, placeholderMask: placeholderMask }),
|
|
212
|
-
React__default.createElement(FormFieldPostFix, { variation: "spinner", visible: (_e = props.loading) !== null && _e !== void 0 ? _e : false })));
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
function InputPhoneNumber$1(_a) {
|
|
216
|
-
var { required } = _a, props = __rest(_a, ["required"]);
|
|
217
|
-
const { placeholder, validations, pattern = DEFAULT_PATTERN } = props;
|
|
218
|
-
const errorSubject = placeholder || "Phone number";
|
|
219
|
-
const { getValues } = useFormContext() != undefined
|
|
220
|
-
? useFormContext()
|
|
221
|
-
: // If there isn't a Form Context being provided, get a form for this field.
|
|
222
|
-
useForm({ mode: "onTouched" });
|
|
223
|
-
return (React__default.createElement(InputMask, { pattern: pattern, strict: false },
|
|
224
|
-
React__default.createElement(FormField, Object.assign({}, props, { type: "tel", pattern: pattern, validations: Object.assign(Object.assign({ required: {
|
|
225
|
-
value: Boolean(required),
|
|
226
|
-
message: `${errorSubject} is required`,
|
|
227
|
-
} }, validations), { validate: getPhoneNumberValidation }) }))));
|
|
228
|
-
function getPhoneNumberValidation(value) {
|
|
229
|
-
// Get unique characters that aren't * in the pattern
|
|
230
|
-
const patternNonDelimterCharacters = pattern
|
|
231
|
-
.split("")
|
|
232
|
-
.filter(char => char !== "*")
|
|
233
|
-
.filter((char, index, arr) => arr.indexOf(char) === index);
|
|
234
|
-
const specialCharacters = patternNonDelimterCharacters.join(" ");
|
|
235
|
-
// Remove special characters from pattern
|
|
236
|
-
const cleanValue = value.replace(new RegExp(`[${specialCharacters}]`, "g"), "");
|
|
237
|
-
const cleanValueRequiredLength = (pattern.match(/\*/g) || []).length;
|
|
238
|
-
if (cleanValue.length > 0 && cleanValue.length < cleanValueRequiredLength) {
|
|
239
|
-
return `${errorSubject} must contain ${cleanValueRequiredLength} or more digits`;
|
|
240
|
-
}
|
|
241
|
-
if (typeof (validations === null || validations === void 0 ? void 0 : validations.validate) === "function") {
|
|
242
|
-
return validations.validate(value, getValues);
|
|
243
|
-
}
|
|
244
|
-
return true;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
function isNewInputPhoneNumberProps(props) {
|
|
249
|
-
return props.version === 2;
|
|
250
|
-
}
|
|
251
|
-
const InputPhoneNumber = forwardRef(function InputPhoneNumberShim(props, ref) {
|
|
252
|
-
if (isNewInputPhoneNumberProps(props)) {
|
|
253
|
-
return React__default.createElement(InputPhoneNumberRebuilt, Object.assign({}, props, { ref: ref }));
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
return React__default.createElement(InputPhoneNumber$1, Object.assign({}, props));
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
export { InputPhoneNumber };
|
|
17
|
+
import '../useAtlantisFormFieldName-es.js';
|
|
18
|
+
import 'react-hook-form';
|
|
19
|
+
import '../filterDataAttributes-es.js';
|