@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
480 lines (479 loc) • 19.5 kB
JavaScript
"use strict";
"use client";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = SegmentedFieldSection;
var _react = _interopRequireWildcard(require("react"));
var _clsx = _interopRequireDefault(require("clsx"));
var _dom = require("./dom.js");
var _utils = require("./utils.js");
var _jsxRuntime = require("react/jsx-runtime");
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); }
function SegmentedFieldSection({
groupId,
inputId,
itemProps,
value,
overwriteMode,
delimiter,
groupDelimiter,
disabled,
valuesRef,
inputs,
scopeRef,
sectionRefs,
caretPositionsRef,
sectionSelectionModeRef,
wholeGroupSelectionUi,
clearGroupSelection,
clearSectionSelection,
selectWholeGroup,
selectSection,
setSectionCaret,
focusSection,
onChange,
onGroupFocus,
onGroupBlur,
...sharedProps
}) {
var _spinButton$parseValu, _spinButton$parseValu2;
const {
label,
mask,
spinButton,
className,
placeholder,
onCopy: onCopyExternal,
onPaste: onPasteExternal,
...htmlProps
} = itemProps;
const displayValue = (0, _utils.getDisplayValue)({
value,
placeholder: String(placeholder || ''),
length: mask.length
});
const hasTypedValue = value.length > 0;
const handledPasteTimestampRef = (0, _react.useRef)(undefined);
const setRef = (0, _react.useCallback)(element => {
sectionRefs.current[inputId] = element;
}, [inputId, sectionRefs]);
(0, _react.useLayoutEffect)(() => {
const element = sectionRefs.current[inputId];
if (!element) {
return;
}
(0, _dom.setSectionDomApi)({
element,
inputId,
displayValue,
caretPositionsRef,
sectionSelectionModeRef,
selectSection,
setSectionCaret
});
}, [caretPositionsRef, displayValue, inputId, selectSection, sectionRefs, sectionSelectionModeRef, setSectionCaret, value]);
(0, _react.useLayoutEffect)(() => {
var _caretPositionsRef$cu;
const element = sectionRefs.current[inputId];
if (!element || document.activeElement !== element) {
return;
}
if (wholeGroupSelectionUi) {
return;
}
if (sectionSelectionModeRef.current[inputId] === 'all') {
selectSection(inputId);
return;
}
setSectionCaret(inputId, (_caretPositionsRef$cu = caretPositionsRef.current[inputId]) !== null && _caretPositionsRef$cu !== void 0 ? _caretPositionsRef$cu : displayValue.length);
}, [caretPositionsRef, displayValue.length, inputId, sectionRefs, sectionSelectionModeRef, selectSection, setSectionCaret, value, wholeGroupSelectionUi]);
const updateValue = (0, _react.useCallback)(nextValue => {
var _caretPositionsRef$cu2;
caretPositionsRef.current[inputId] = Math.min((_caretPositionsRef$cu2 = caretPositionsRef.current[inputId]) !== null && _caretPositionsRef$cu2 !== void 0 ? _caretPositionsRef$cu2 : 0, nextValue.length);
onChange(inputId, nextValue);
}, [caretPositionsRef, inputId, onChange]);
const stepSpinButton = (0, _react.useCallback)(direction => {
var _valuesRef$current$in, _parseValue, _formatValue;
if (!spinButton) {
return false;
}
const {
min,
max,
step = 1,
wrap = true,
getInitialValue,
parseValue,
formatValue
} = spinButton;
const currentValue = (_valuesRef$current$in = valuesRef.current[inputId]) !== null && _valuesRef$current$in !== void 0 ? _valuesRef$current$in : '';
const parsedValue = (_parseValue = parseValue === null || parseValue === void 0 ? void 0 : parseValue(currentValue)) !== null && _parseValue !== void 0 ? _parseValue : currentValue ? Number(currentValue) : undefined;
let nextValue = parsedValue;
if (typeof parsedValue !== 'number' || Number.isNaN(parsedValue)) {
const initialValue = getInitialValue === null || getInitialValue === void 0 ? void 0 : getInitialValue();
nextValue = typeof initialValue === 'number' && !Number.isNaN(initialValue) ? initialValue : direction === 'up' ? min : max;
} else {
nextValue = parsedValue + (direction === 'up' ? step : step * -1);
if (nextValue > max) {
nextValue = wrap ? min : max;
} else if (nextValue < min) {
nextValue = wrap ? max : min;
}
}
const formattedValue = ((_formatValue = formatValue === null || formatValue === void 0 ? void 0 : formatValue(nextValue)) !== null && _formatValue !== void 0 ? _formatValue : String(nextValue).padStart(mask.length, '0')).slice(0, mask.length);
updateValue(formattedValue);
selectSection(inputId);
return true;
}, [inputId, mask.length, selectSection, spinButton, updateValue, valuesRef]);
const getNextSectionId = (0, _react.useCallback)((direction, {
withinGroup = false
} = {}) => {
var _sections2;
const current = sectionRefs.current[inputId];
if (!current) {
return undefined;
}
const root = withinGroup ? current.closest('.dnb-segmented-field__group') || undefined : scopeRef.current || undefined;
const sections = (0, _dom.listAllSections)(root);
const index = sections.findIndex(section => section === current);
if (index < 0) {
return undefined;
}
if (direction === 'prev') {
var _sections;
return (_sections = sections[index - 1]) === null || _sections === void 0 ? void 0 : _sections.dataset.segmentedInputId;
}
return (_sections2 = sections[index + 1]) === null || _sections2 === void 0 ? void 0 : _sections2.dataset.segmentedInputId;
}, [inputId, scopeRef, sectionRefs]);
const focusAdjacentSection = (0, _react.useCallback)(direction => {
const current = sectionRefs.current[inputId];
if (!current) {
return false;
}
const sections = (0, _dom.listAllSections)(scopeRef.current || undefined);
const index = sections.findIndex(section => section === current);
if (index < 0) {
return false;
}
const target = direction === 'prev' ? sections[index - 1] : sections[index + 1];
if (!target) {
return false;
}
target.focus();
return true;
}, [inputId, scopeRef, sectionRefs]);
const replaceWithChar = (0, _react.useCallback)(char => {
var _valuesRef$current$in2, _caretPositionsRef$cu3, _mask$Math$min;
const currentValue = (_valuesRef$current$in2 = valuesRef.current[inputId]) !== null && _valuesRef$current$in2 !== void 0 ? _valuesRef$current$in2 : '';
const currentPosition = (_caretPositionsRef$cu3 = caretPositionsRef.current[inputId]) !== null && _caretPositionsRef$cu3 !== void 0 ? _caretPositionsRef$cu3 : 0;
const isAllSelected = sectionSelectionModeRef.current[inputId] === 'all';
if (!((_mask$Math$min = mask[Math.min(currentPosition, mask.length - 1)]) !== null && _mask$Math$min !== void 0 && _mask$Math$min.test(char))) {
return false;
}
if (!isAllSelected && currentPosition >= mask.length && currentValue.length >= mask.length) {
const nextSectionId = getNextSectionId('next', {
withinGroup: true
});
if (nextSectionId) {
var _inputs$find, _nextMask$;
const nextMask = (_inputs$find = inputs.find(({
id
}) => id === nextSectionId)) === null || _inputs$find === void 0 ? void 0 : _inputs$find.mask;
if (!(nextMask !== null && nextMask !== void 0 && (_nextMask$ = nextMask[0]) !== null && _nextMask$ !== void 0 && _nextMask$.test(char))) {
return false;
}
focusSection(nextSectionId, 'all');
caretPositionsRef.current[nextSectionId] = 0;
return (0, _utils.insertCharIntoSection)({
char,
inputId: nextSectionId,
overwriteMode,
valuesRef,
inputs,
caretPositionsRef,
sectionSelectionModeRef,
onChange,
focusSection,
setSectionCaret
});
}
if (focusAdjacentSection('next')) {
var _document$activeEleme;
;
(_document$activeEleme = document.activeElement) === null || _document$activeEleme === void 0 || _document$activeEleme.dispatchEvent(new KeyboardEvent('keydown', {
key: char,
bubbles: true,
cancelable: true
}));
return true;
}
return false;
}
const sourceValue = isAllSelected ? '' : currentValue;
const sourcePosition = isAllSelected ? 0 : currentPosition;
const nextValue = (0, _utils.insertChar)(sourceValue, char, sourcePosition, {
overwriteMode,
maxLength: mask.length
});
updateValue(nextValue);
const nextPosition = Math.min(sourcePosition + 1, mask.length);
if (nextValue.length >= mask.length && nextPosition >= mask.length) {
const nextSectionId = getNextSectionId('next', {
withinGroup: true
});
if (nextSectionId) {
focusSection(nextSectionId, 'all');
} else if (!focusAdjacentSection('next')) {
setSectionCaret(inputId, mask.length);
}
} else {
setSectionCaret(inputId, nextPosition);
}
return true;
}, [caretPositionsRef, focusAdjacentSection, focusSection, getNextSectionId, inputId, inputs, mask, onChange, overwriteMode, sectionSelectionModeRef, setSectionCaret, updateValue, valuesRef]);
const sectionProps = (0, _react.useMemo)(() => ({
...(0, _dom.pickSectionDomProps)(htmlProps),
...(0, _dom.pickSectionDomProps)(sharedProps)
}), [htmlProps, sharedProps]);
const handlePaste = (0, _react.useCallback)(event => {
if (handledPasteTimestampRef.current === event.timeStamp) {
return;
}
handledPasteTimestampRef.current = event.timeStamp;
onPasteExternal === null || onPasteExternal === void 0 || onPasteExternal(event);
if (event.defaultPrevented) {
return;
}
const pastedValue = event.clipboardData.getData('text/plain');
if (!pastedValue) {
return;
}
event.preventDefault();
const nextValues = pastedValue.length > mask.length || /[./\-\s]/.test(pastedValue) ? (0, _utils.distributeValueFromStart)({
value: pastedValue,
inputs,
existingValues: valuesRef.current
}) : {
...valuesRef.current,
[inputId]: (0, _utils.extractValidChars)(pastedValue, mask)
};
Object.entries(nextValues).forEach(([key, nextValue]) => {
onChange(key, nextValue);
});
if (pastedValue.length > mask.length || /[./\-\s]/.test(pastedValue)) {
const lastFilledSection = inputs.map(({
id
}) => id).reverse().find(key => nextValues[key]);
if (lastFilledSection) {
focusSection(lastFilledSection, 'end');
}
} else {
setSectionCaret(inputId, Math.min(nextValues[inputId].length, mask.length));
}
}, [focusSection, inputId, inputs, mask, onChange, onPasteExternal, setSectionCaret, valuesRef]);
const clearWholeGroup = (0, _react.useCallback)(() => {
var _inputs$;
if (!groupDelimiter) {
return false;
}
inputs.forEach(({
id
}) => {
onChange(id, '');
sectionSelectionModeRef.current[id] = 'caret';
caretPositionsRef.current[id] = 0;
});
clearGroupSelection();
const firstSectionId = (_inputs$ = inputs[0]) === null || _inputs$ === void 0 ? void 0 : _inputs$.id;
if (firstSectionId) {
focusSection(firstSectionId, 'start');
} else {
setSectionCaret(inputId, 0);
}
return true;
}, [caretPositionsRef, clearGroupSelection, focusSection, groupDelimiter, inputId, inputs, onChange, sectionSelectionModeRef, setSectionCaret]);
return (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [(0, _jsxRuntime.jsx)("span", {
id: `${groupId}-${inputId}`,
ref: setRef,
className: (0, _clsx.default)("dnb-input__input dnb-segmented-field__section", className, hasTypedValue && 'dnb-segmented-field__section--highlight'),
"data-segmented-input-id": inputId,
contentEditable: !disabled && !wholeGroupSelectionUi,
suppressContentEditableWarning: true,
role: spinButton ? 'spinbutton' : 'textbox',
tabIndex: disabled ? -1 : 0,
spellCheck: false,
"aria-label": String(label),
"aria-readonly": disabled,
"aria-disabled": disabled,
"aria-valuemin": spinButton ? spinButton.min : undefined,
"aria-valuemax": spinButton ? spinButton.max : undefined,
"aria-valuenow": spinButton && hasTypedValue ? (_spinButton$parseValu = spinButton === null || spinButton === void 0 || (_spinButton$parseValu2 = spinButton.parseValue) === null || _spinButton$parseValu2 === void 0 ? void 0 : _spinButton$parseValu2.call(spinButton, value)) !== null && _spinButton$parseValu !== void 0 ? _spinButton$parseValu : Number(value) : undefined,
"aria-valuetext": spinButton ? hasTypedValue ? value : 'Empty' : undefined,
onFocus: () => {
clearGroupSelection();
onGroupFocus();
selectSection(inputId);
},
onBlur: onGroupBlur,
onMouseDown: event => {
clearGroupSelection();
event.preventDefault();
if (document.activeElement !== sectionRefs.current[inputId]) {
var _sectionRefs$current$;
(_sectionRefs$current$ = sectionRefs.current[inputId]) === null || _sectionRefs$current$ === void 0 || _sectionRefs$current$.focus();
selectSection(inputId);
return;
}
selectSection(inputId);
},
onBeforeInput: event => {
if (event.nativeEvent.inputType === 'insertParagraph' || event.nativeEvent.inputType === 'insertLineBreak') {
event.preventDefault();
}
},
onInput: event => {
event.preventDefault();
},
onKeyDown: event => {
if (disabled) {
return;
}
const key = event.key;
if ((event.metaKey || event.ctrlKey) && key.toLowerCase() === 'a') {
event.preventDefault();
selectWholeGroup(inputId);
return;
}
if ((event.metaKey || event.ctrlKey) && key.toLowerCase() === 'c') {
return;
}
if (event.metaKey || event.ctrlKey) {
return;
}
const hadWholeGroupSelected = wholeGroupSelectionUi;
clearGroupSelection();
if (key === 'Enter') {
event.preventDefault();
return;
}
if (key === 'Tab') {
clearSectionSelection();
return;
}
if (key === 'ArrowRight') {
event.preventDefault();
focusAdjacentSection('next');
return;
}
if (key === 'ArrowLeft') {
event.preventDefault();
focusAdjacentSection('prev');
return;
}
if (key === 'ArrowUp' || key === 'ArrowDown') {
event.preventDefault();
stepSpinButton(key === 'ArrowUp' ? 'up' : 'down');
return;
}
if (key === 'Backspace') {
var _valuesRef$current$in3, _caretPositionsRef$cu4;
event.preventDefault();
if (hadWholeGroupSelected) {
clearWholeGroup();
return;
}
const isAllSelected = sectionSelectionModeRef.current[inputId] === 'all';
const currentValue = (_valuesRef$current$in3 = valuesRef.current[inputId]) !== null && _valuesRef$current$in3 !== void 0 ? _valuesRef$current$in3 : '';
const currentPosition = (_caretPositionsRef$cu4 = caretPositionsRef.current[inputId]) !== null && _caretPositionsRef$cu4 !== void 0 ? _caretPositionsRef$cu4 : 0;
if (isAllSelected && currentValue.length > 0) {
updateValue('');
selectSection(inputId);
return;
}
if (currentValue.length === 0 || currentPosition <= 0) {
const previousSectionId = getNextSectionId('prev', {
withinGroup: true
});
if (previousSectionId) {
focusSection(previousSectionId, 'all');
} else {
if (currentValue.length === 0) {
focusAdjacentSection('prev');
}
return;
}
return;
}
const nextValue = (0, _utils.removeChar)(currentValue, currentPosition - 1);
updateValue(nextValue);
setSectionCaret(inputId, currentPosition - 1);
return;
}
if (key === 'Delete') {
var _valuesRef$current$in4, _caretPositionsRef$cu5;
event.preventDefault();
if (hadWholeGroupSelected) {
clearWholeGroup();
return;
}
const isAllSelected = sectionSelectionModeRef.current[inputId] === 'all';
const currentValue = (_valuesRef$current$in4 = valuesRef.current[inputId]) !== null && _valuesRef$current$in4 !== void 0 ? _valuesRef$current$in4 : '';
const currentPosition = (_caretPositionsRef$cu5 = caretPositionsRef.current[inputId]) !== null && _caretPositionsRef$cu5 !== void 0 ? _caretPositionsRef$cu5 : 0;
if (isAllSelected) {
updateValue('');
selectSection(inputId);
return;
}
const nextValue = (0, _utils.removeChar)(currentValue, currentPosition);
updateValue(nextValue);
setSectionCaret(inputId, currentPosition);
return;
}
if (key.length === 1) {
event.preventDefault();
if (hadWholeGroupSelected) {
var _inputs$2;
const firstSectionId = (_inputs$2 = inputs[0]) === null || _inputs$2 === void 0 ? void 0 : _inputs$2.id;
if (firstSectionId && clearWholeGroup()) {
(0, _utils.insertCharIntoSection)({
char: key,
inputId: firstSectionId,
overwriteMode,
valuesRef,
inputs,
caretPositionsRef,
sectionSelectionModeRef,
onChange,
focusSection,
setSectionCaret
});
return;
}
}
replaceWithChar(key);
return;
}
},
onCopy: event => {
onCopyExternal === null || onCopyExternal === void 0 || onCopyExternal(event);
if (event.defaultPrevented) {
return;
}
event.preventDefault();
event.clipboardData.setData('text/plain', (0, _utils.joinValues)(valuesRef.current, groupDelimiter));
},
onPasteCapture: handlePaste,
onPaste: handlePaste,
...sectionProps,
children: displayValue
}), delimiter && (0, _jsxRuntime.jsx)("span", {
"aria-hidden": true,
className: 'dnb-segmented-field__delimiter' + (hasTypedValue ? " dnb-segmented-field__delimiter--highlight" : ""),
children: delimiter
})]
});
}
//# sourceMappingURL=SegmentedFieldSection.js.map