@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
400 lines (399 loc) • 16.2 kB
JavaScript
"use strict";
"use client";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var z = _interopRequireWildcard(require("zod"));
var _index = require("../../../../components/index.js");
var _classnames = _interopRequireDefault(require("classnames"));
var _useCountries = _interopRequireDefault(require("../SelectCountry/useCountries.js"));
var _index2 = _interopRequireDefault(require("../String/index.js"));
var _index3 = _interopRequireDefault(require("../Composition/index.js"));
var _index4 = require("../../hooks/index.js");
var _utils = require("../../../../components/flex/utils.js");
var _Context = _interopRequireDefault(require("../../../../shared/Context.js"));
var _index5 = require("../SelectCountry/index.js");
var _useTranslation = _interopRequireDefault(require("../../hooks/useTranslation.js"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const defaultCountryCode = '+47';
const defaultPlaceholder = '00 00 00 00';
const defaultMask = [/\d/, /\d/, ' ', /\d/, /\d/, ' ', /\d/, /\d/, ' ', /\d/, /\d/];
function PhoneNumber(props = {}) {
var _sharedContext$locale, _props$inputRef, _countryCodeRef$curre2;
const sharedContext = (0, _react.useContext)(_Context.default);
const {
label: defaultLabel,
countryCodeLabel: defaultCountryCodeLabel,
errorRequired
} = (0, _useTranslation.default)().PhoneNumber;
const lang = (_sharedContext$locale = sharedContext.locale) === null || _sharedContext$locale === void 0 ? void 0 : _sharedContext$locale.split('-')[0];
const countryCodeRef = (0, _react.useRef)(props.emptyValue);
const prevCountryCodeRef = (0, _react.useRef)(countryCodeRef.current);
const numberRef = (0, _react.useRef)(props.emptyValue);
const dataRef = (0, _react.useRef)(null);
const langRef = (0, _react.useRef)(lang);
const wasFilled = (0, _react.useRef)(false);
const currentCountryRef = (0, _react.useRef)();
const errorMessages = (0, _react.useMemo)(() => ({
'Field.errorRequired': errorRequired,
'Field.errorPattern': errorRequired,
...props.errorMessages
}), [errorRequired, props.errorMessages]);
const validateRequired = (0, _react.useCallback)((value, {
required,
isChanged,
error
}) => {
if (required) {
const [countryCode, phoneNumber] = splitValue(value);
if (countryCode !== prevCountryCodeRef.current) {
if (countryCode) {
prevCountryCodeRef.current = countryCode;
}
return undefined;
}
if (isChanged && !phoneNumber) {
return error;
}
}
return undefined;
}, []);
const fromExternal = (0, _react.useCallback)(external => {
if (typeof external === 'string') {
const [countryCode, phoneNumber] = splitValue(external);
if (!countryCode && !phoneNumber && !props.omitCountryCodeField) {
return countryCodeRef.current;
}
}
return external;
}, [props.omitCountryCodeField]);
const toEvent = (0, _react.useCallback)(value => {
const [, phoneNumber] = splitValue(value);
if (!phoneNumber) {
return props.emptyValue;
}
return value;
}, [props.emptyValue]);
const customTransformIn = props.transformIn;
const transformIn = (0, _react.useCallback)(value => {
if (customTransformIn) {
const external = customTransformIn(value);
if (typeof external === 'string') {
return external;
}
if (external !== null && external !== void 0 && external.phoneNumber) {
return joinValue([external.countryCode, external.phoneNumber]);
}
}
return value;
}, [customTransformIn]);
const provideAdditionalArgs = (0, _react.useCallback)(value => {
var _currentCountryRef$cu;
const [countryCode, phoneNumber] = splitValue(value);
return {
...(!props.omitCountryCodeField ? {
countryCode: countryCode || countryCodeRef.current || undefined
} : {}),
phoneNumber: phoneNumber || numberRef.current || undefined,
iso: (_currentCountryRef$cu = currentCountryRef.current) === null || _currentCountryRef$cu === void 0 ? void 0 : _currentCountryRef$cu.iso
};
}, [props.omitCountryCodeField]);
const schema = (0, _react.useMemo)(() => {
if (props.schema) {
return props.schema;
}
if (!props.pattern) return undefined;
return p => {
let s = z.string();
if (p !== null && p !== void 0 && p.pattern) {
try {
s = s.regex(new RegExp(p.pattern, 'u'), 'Field.errorPattern');
} catch (_e) {}
}
return s;
};
}, [props.schema, props.pattern]);
const defaultProps = {
...(schema ? {
schema
} : {}),
errorMessages
};
const ref = (0, _react.useRef)();
const preparedProps = {
...props,
...defaultProps,
validateRequired,
fromExternal,
toEvent,
provideAdditionalArgs,
transformIn,
inputRef: (_props$inputRef = props.inputRef) !== null && _props$inputRef !== void 0 ? _props$inputRef : ref
};
const {
id,
path,
itemPath,
value,
className,
inputRef,
countryCodeFieldClassName,
numberFieldClassName,
countryCodePlaceholder,
placeholder,
countryCodeLabel,
label,
labelDescription,
numberLabel,
labelSrOnly,
numberMask,
countries: ccFilter = 'Prioritized',
emptyValue,
info,
warning,
size,
error,
hasError,
disabled,
width,
help,
required,
validateInitially,
continuousValidation,
validateContinuously,
validateUnchanged,
omitCountryCodeField,
setHasFocus,
handleChange,
setDisplayValue,
onCountryCodeChange,
onNumberChange,
filterCountries
} = (0, _index4.useFieldProps)(preparedProps, {
executeOnChangeRegardlessOfUnchangedValue: true
});
(0, _react.useEffect)(() => {
if (path || itemPath) {
var _inputRef$current;
const number = (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.value;
setDisplayValue((number === null || number === void 0 ? void 0 : number.length) > 0 ? joinValue([countryCodeRef.current, number]) : undefined);
}
}, [inputRef, itemPath, path, setDisplayValue, value]);
const filter = (0, _react.useCallback)(country => {
return (0, _index5.countryFilter)(country, filterCountries, ccFilter);
}, [ccFilter, filterCountries]);
const {
countries
} = (0, _useCountries.default)();
const updateCurrentDataSet = (0, _react.useCallback)(() => {
dataRef.current = (0, _index5.getCountryData)({
countries,
lang,
filter: ccFilter === 'Prioritized' && !wasFilled.current ? country => `${formatCountryCode(country.cdc)}` === countryCodeRef.current : filter,
sort: ccFilter,
makeObject
});
}, [countries, lang, ccFilter, filter]);
const prepareEventValues = (0, _react.useCallback)(({
countryCode = countryCodeRef.current || emptyValue,
phoneNumber = numberRef.current || emptyValue
} = {}) => {
var _currentCountryRef$cu2;
if (!currentCountryRef.current) {
const cdcVal = countryCode === null || countryCode === void 0 ? void 0 : countryCode.replace(/^\+/, '');
const item = dataRef.current.find(item => {
var _item$country;
const cdc = item === null || item === void 0 || (_item$country = item.country) === null || _item$country === void 0 ? void 0 : _item$country.cdc;
return cdc === cdcVal;
});
currentCountryRef.current = item === null || item === void 0 ? void 0 : item.country;
}
return {
...(!omitCountryCodeField ? {
countryCode
} : {}),
phoneNumber,
iso: (_currentCountryRef$cu2 = currentCountryRef.current) === null || _currentCountryRef$cu2 === void 0 ? void 0 : _currentCountryRef$cu2.iso
};
}, [emptyValue, omitCountryCodeField]);
const callOnChange = (0, _react.useCallback)(data => {
const eventValues = prepareEventValues(data);
handleChange(toEvent(joinValue([eventValues.countryCode, eventValues.phoneNumber])), eventValues);
}, [prepareEventValues, handleChange]);
const callOnBlurOrFocus = (0, _react.useCallback)(hasFocus => {
const eventValues = prepareEventValues();
setHasFocus(hasFocus, undefined, eventValues);
}, [prepareEventValues, setHasFocus]);
(0, _react.useMemo)(() => {
const [countryCode, phoneNumber] = splitValue(props.value || value);
numberRef.current = phoneNumber;
if (lang !== langRef.current || !wasFilled.current) {
if (!countryCodeRef.current || countryCode) {
countryCodeRef.current = countryCode || defaultCountryCode;
}
langRef.current = lang;
updateCurrentDataSet();
}
}, [value, props.value, lang, updateCurrentDataSet]);
const handleCountryCodeChange = (0, _react.useCallback)(({
data
}) => {
var _data$selectedKey, _countryCodeRef$curre, _numberRef$current;
const countryCode = countryCodeRef.current = (data === null || data === void 0 || (_data$selectedKey = data.selectedKey) === null || _data$selectedKey === void 0 ? void 0 : _data$selectedKey.trim()) || emptyValue;
currentCountryRef.current = data === null || data === void 0 ? void 0 : data.country;
if (!numberMask && (_countryCodeRef$curre = countryCodeRef.current) !== null && _countryCodeRef$curre !== void 0 && _countryCodeRef$curre.includes(defaultCountryCode) && ((_numberRef$current = numberRef.current) === null || _numberRef$current === void 0 ? void 0 : _numberRef$current.length) > 8) {
const truncatedNumber = numberRef.current.substring(0, 8);
callOnChange({
countryCode,
phoneNumber: truncatedNumber
});
onNumberChange === null || onNumberChange === void 0 || onNumberChange(truncatedNumber);
} else {
callOnChange({
countryCode
});
}
onCountryCodeChange === null || onCountryCodeChange === void 0 || onCountryCodeChange(countryCode);
}, [emptyValue, numberMask, onCountryCodeChange, callOnChange, onNumberChange]);
const handleNumberChange = (0, _react.useCallback)(value => {
const phoneNumber = numberRef.current = value || emptyValue;
callOnChange({
phoneNumber
});
onNumberChange === null || onNumberChange === void 0 || onNumberChange(phoneNumber);
}, [emptyValue, callOnChange, onNumberChange]);
const handleOnBlur = (0, _react.useCallback)(() => {
callOnBlurOrFocus(false);
}, [callOnBlurOrFocus]);
const handleOnFocus = (0, _react.useCallback)(() => {
callOnBlurOrFocus(true);
}, [callOnBlurOrFocus]);
const handleCountryCodeFocus = (0, _react.useCallback)(({
updateData
}) => {
if (!wasFilled.current) {
wasFilled.current = true;
updateCurrentDataSet();
updateData(dataRef.current);
}
handleOnFocus();
}, [handleOnFocus, updateCurrentDataSet]);
const onTypeHandler = (0, _react.useCallback)(({
value,
updateData,
revalidateInputValue,
event
}) => {
var _event$nativeEvent;
if (typeof (event === null || event === void 0 || (_event$nativeEvent = event.nativeEvent) === null || _event$nativeEvent === void 0 ? void 0 : _event$nativeEvent.data) === 'undefined') {
const cdcVal = /\+\d{1,3}\s{1}\d+/.test(value) ? splitValue(value)[0] : value;
const country = countries.find(({
cdc
}) => cdc === cdcVal);
if (country !== null && country !== void 0 && country.cdc) {
const countryCode = countryCodeRef.current = formatCountryCode(country.cdc);
updateCurrentDataSet();
updateData(dataRef.current);
callOnChange({
countryCode
});
window.requestAnimationFrame(() => {
revalidateInputValue();
});
}
}
}, [callOnChange, countries, updateCurrentDataSet]);
const isDefault = (_countryCodeRef$curre2 = countryCodeRef.current) === null || _countryCodeRef$curre2 === void 0 ? void 0 : _countryCodeRef$curre2.includes(defaultCountryCode);
const compositionFieldProps = {
id,
className: (0, _classnames.default)('dnb-forms-field-phone-number', className),
width: 'stretch',
label,
labelDescription,
labelSrOnly,
help: undefined,
...(0, _utils.pickSpacingProps)(props)
};
return _react.default.createElement(_index3.default, compositionFieldProps, !omitCountryCodeField && _react.default.createElement(_index.Autocomplete, {
className: (0, _classnames.default)('dnb-forms-field-phone-number__country-code', countryCodeFieldClassName),
mode: "async",
placeholder: countryCodePlaceholder,
label_direction: "vertical",
label: countryCodeLabel === false ? defaultCountryCodeLabel : countryCodeLabel !== null && countryCodeLabel !== void 0 ? countryCodeLabel : defaultCountryCodeLabel,
label_sr_only: countryCodeLabel === false ? true : undefined,
data: dataRef.current,
value: countryCodeRef.current,
status: hasError ? 'error' : undefined,
disabled: disabled,
on_focus: handleCountryCodeFocus,
on_blur: handleOnBlur,
on_change: handleCountryCodeChange,
on_type: onTypeHandler,
independent_width: true,
search_numbers: true,
keep_selection: true,
selectall: true,
autoComplete: "tel-country-code",
no_animation: props.noAnimation,
size: size
}), _react.default.createElement(_index2.default, {
className: (0, _classnames.default)('dnb-forms-field-phone-number__number', numberFieldClassName),
type: "tel",
autoComplete: "tel-national",
emptyValue: emptyValue,
layout: "vertical",
label: numberLabel === false ? defaultLabel : numberLabel !== null && numberLabel !== void 0 ? numberLabel : defaultLabel,
labelSrOnly: numberLabel === false ? true : undefined,
placeholder: placeholder !== null && placeholder !== void 0 ? placeholder : isDefault ? defaultPlaceholder : undefined,
mask: numberMask !== null && numberMask !== void 0 ? numberMask : isDefault ? defaultMask : Array(12).fill(/\d/),
onFocus: handleOnFocus,
onBlur: handleOnBlur,
onChange: handleNumberChange,
value: numberRef.current,
innerRef: inputRef,
info: info,
warning: warning,
error: error,
disabled: disabled,
width: width === 'stretch' ? 'stretch' : props.omitCountryCodeField && width === 'large' ? 'large' : 'medium',
help: {
...help,
breakout: false,
outset: false
},
required: required,
errorMessages: errorMessages,
validateInitially: validateInitially,
validateContinuously: continuousValidation || validateContinuously,
validateUnchanged: validateUnchanged,
inputMode: "tel",
size: size
}));
}
function makeObject(country, lang) {
var _country$i18n$lang;
const name = (_country$i18n$lang = country.i18n[lang]) !== null && _country$i18n$lang !== void 0 ? _country$i18n$lang : country.i18n.en;
const code = formatCountryCode(country.cdc);
return {
selectedKey: code,
selected_value: `${country.iso} (${code})`,
search_content: [code, name],
content: [name, code],
country
};
}
function formatCountryCode(value) {
return `+${value}`;
}
function splitValue(value) {
return (typeof value === 'string' ? value.match(/^(\+[^ ]+)? ?(.*)$/) : [undefined, '', '']).slice(1);
}
function joinValue(array) {
return array.filter(Boolean).join(' ');
}
PhoneNumber._supportsSpacingProps = undefined;
var _default = exports.default = PhoneNumber;
//# sourceMappingURL=PhoneNumber.js.map