UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

307 lines (306 loc) 13 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _reactDom = require("react-dom"); var _clsx = _interopRequireDefault(require("clsx")); var _withComponentMarkers = _interopRequireDefault(require("../../../shared/helpers/withComponentMarkers.js")); var _useId = _interopRequireDefault(require("../../../shared/helpers/useId.js")); var _Input = _interopRequireDefault(require("../../Input.js")); var _FormLabel = _interopRequireDefault(require("../../FormLabel.js")); var _SpacingUtils = require("../../space/SpacingUtils.js"); var _useSegmentedFieldValues = require("../hooks/useSegmentedFieldValues.js"); var _SegmentedFieldSection = _interopRequireDefault(require("./SegmentedFieldSection.js")); 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 SegmentedField(props) { const fallbackId = (0, _useId.default)(props === null || props === void 0 ? void 0 : props.id); const fallbackFieldsetRef = (0, _react.useRef)(null); const { id = fallbackId, label, labelDirection = 'vertical', inputs, delimiter, onChange: onChangeExternal, disabled, status, statusState, values: defaultValues, className, stretch, _omitInputShellClass, scopeRef = fallbackFieldsetRef, size, suffix, onBlur, onFocus, overwriteMode = 'shift', optionsEnhancer, ...rest } = props; const hasExternalScopeRef = Boolean(props.scopeRef); const [values, onChangeBase] = (0, _useSegmentedFieldValues.useSegmentedFieldValues)({ inputs, defaultValues }); const valuesRef = (0, _react.useRef)(values); const sectionRefs = (0, _react.useRef)({}); const caretPositionsRef = (0, _react.useRef)({}); const sectionSelectionModeRef = (0, _react.useRef)({}); const areInputsInFocus = (0, _react.useRef)(false); const [wholeGroupSelectionUi, setWholeGroupSelectionUi] = (0, _react.useState)(false); const wholeGroupSelectionUiRef = (0, _react.useRef)(false); wholeGroupSelectionUiRef.current = wholeGroupSelectionUi; valuesRef.current = values; (0, _react.useEffect)(() => { optionsEnhancer === null || optionsEnhancer === void 0 || optionsEnhancer({ overwriteMode }); }, [optionsEnhancer, overwriteMode]); const onChange = (0, _react.useCallback)((inputId, value) => { const updatedValues = { ...valuesRef.current, [inputId]: value }; valuesRef.current = updatedValues; onChangeBase(updatedValues); if (typeof onChangeExternal === 'function') { onChangeExternal(updatedValues); } }, [onChangeBase, onChangeExternal]); const clearGroupSelection = (0, _react.useCallback)(() => { if (wholeGroupSelectionUiRef.current) { (0, _reactDom.flushSync)(() => { setWholeGroupSelectionUi(false); }); } }, []); const clearSectionSelection = (0, _react.useCallback)(() => { const selection = window.getSelection(); selection === null || selection === void 0 || selection.removeAllRanges(); inputs.forEach(({ id }) => { var _section$textContent$, _section$textContent; const inputId = String(id); const section = sectionRefs.current[inputId]; const length = (_section$textContent$ = section === null || section === void 0 || (_section$textContent = section.textContent) === null || _section$textContent === void 0 ? void 0 : _section$textContent.length) !== null && _section$textContent$ !== void 0 ? _section$textContent$ : 0; sectionSelectionModeRef.current[inputId] = 'caret'; caretPositionsRef.current[inputId] = length; }); }, [inputs]); const selectSection = (0, _react.useCallback)(inputId => { const section = sectionRefs.current[inputId]; if (!section) { return; } const selection = window.getSelection(); const range = document.createRange(); range.selectNodeContents(section); selection === null || selection === void 0 || selection.removeAllRanges(); selection === null || selection === void 0 || selection.addRange(range); sectionSelectionModeRef.current[inputId] = 'all'; caretPositionsRef.current[inputId] = 0; }, []); const setSectionCaret = (0, _react.useCallback)((inputId, position) => { var _section$textContent$2, _section$textContent2; const section = sectionRefs.current[inputId]; if (!section) { return; } const safePosition = Math.max(0, Math.min(position, (_section$textContent$2 = (_section$textContent2 = section.textContent) === null || _section$textContent2 === void 0 ? void 0 : _section$textContent2.length) !== null && _section$textContent$2 !== void 0 ? _section$textContent$2 : 0)); const textNode = (0, _dom.ensureTextNode)(section); if (!textNode) { return; } const selection = window.getSelection(); const range = document.createRange(); range.setStart(textNode, safePosition); range.collapse(true); selection === null || selection === void 0 || selection.removeAllRanges(); selection === null || selection === void 0 || selection.addRange(range); sectionSelectionModeRef.current[inputId] = 'caret'; caretPositionsRef.current[inputId] = safePosition; }, []); const selectWholeGroup = (0, _react.useCallback)(targetInputId => { var _lastTextNode$textCon, _lastTextNode$textCon2; const currentSection = sectionRefs.current[targetInputId]; const currentGroup = currentSection === null || currentSection === void 0 ? void 0 : currentSection.closest('.dnb-segmented-field__group'); const sections = (0, _dom.listAllSections)(currentGroup || undefined); if (sections.length === 0) { return; } const firstSection = sections[0]; const lastSection = sections[sections.length - 1]; if (!firstSection || !lastSection) { return; } (0, _reactDom.flushSync)(() => { setWholeGroupSelectionUi(true); }); const firstTextNode = (0, _dom.ensureTextNode)(firstSection); const lastTextNode = (0, _dom.ensureTextNode)(lastSection); if (!firstTextNode || !lastTextNode) { clearGroupSelection(); return; } const selection = window.getSelection(); const range = document.createRange(); range.setStart(firstTextNode, 0); range.setEnd(lastTextNode, (_lastTextNode$textCon = (_lastTextNode$textCon2 = lastTextNode.textContent) === null || _lastTextNode$textCon2 === void 0 ? void 0 : _lastTextNode$textCon2.length) !== null && _lastTextNode$textCon !== void 0 ? _lastTextNode$textCon : 0); selection === null || selection === void 0 || selection.removeAllRanges(); selection === null || selection === void 0 || selection.addRange(range); sections.forEach(section => { const sectionId = section.dataset.segmentedInputId; if (!sectionId) { return; } sectionSelectionModeRef.current[sectionId] = 'all'; caretPositionsRef.current[sectionId] = 0; }); }, [clearGroupSelection, caretPositionsRef, sectionRefs, sectionSelectionModeRef]); const focusSection = (0, _react.useCallback)((inputId, mode) => { var _section$textContent3; const section = sectionRefs.current[inputId]; if (!section) { return; } section.focus(); if (mode === 'all') { selectSection(inputId); return; } const displayValue = (_section$textContent3 = section.textContent) !== null && _section$textContent3 !== void 0 ? _section$textContent3 : ''; setSectionCaret(inputId, mode === 'end' ? displayValue.length : 0); }, [selectSection, setSectionCaret]); const focusFirstSection = (0, _react.useCallback)(event => { var _inputs$; const firstId = (_inputs$ = inputs[0]) === null || _inputs$ === void 0 ? void 0 : _inputs$.id; if (disabled || !firstId) { return; } focusSection(String(firstId), 'all'); }, [disabled, focusSection, inputs]); const onLegendClick = (0, _react.useCallback)(() => { focusFirstSection(); }, [focusFirstSection]); const WrapperElement = label ? 'fieldset' : 'div'; const hiddenInputValue = (0, _utils.joinValues)(values, delimiter); const inputElement = (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [(0, _jsxRuntime.jsx)("div", { className: "dnb-segmented-field__group", role: "group", "data-segmented-selection": wholeGroupSelectionUi ? 'all' : undefined, children: inputs.map(({ id: inputId, onFocus: _a, onBlur: _b, ...itemProps }, index) => { var _values$inputId; return (0, _jsxRuntime.jsx)(_SegmentedFieldSection.default, { groupId: id, inputId: String(inputId), itemProps: itemProps, value: String((_values$inputId = values[inputId]) !== null && _values$inputId !== void 0 ? _values$inputId : ''), overwriteMode: overwriteMode, delimiter: index !== inputs.length - 1 ? delimiter : undefined, groupDelimiter: delimiter, disabled: Boolean(disabled), valuesRef: valuesRef, inputs: inputs.map(({ id, mask }) => ({ id: String(id), mask })), scopeRef: scopeRef, sectionRefs: sectionRefs, caretPositionsRef: caretPositionsRef, sectionSelectionModeRef: sectionSelectionModeRef, wholeGroupSelectionUi: wholeGroupSelectionUi, clearGroupSelection: clearGroupSelection, clearSectionSelection: clearSectionSelection, selectWholeGroup: selectWholeGroup, selectSection: selectSection, setSectionCaret: setSectionCaret, focusSection: focusSection, onChange: onChange, onGroupFocus: () => { if (!areInputsInFocus.current) { onFocus === null || onFocus === void 0 || onFocus(valuesRef.current); } areInputsInFocus.current = true; }, onGroupBlur: event => { var _event$relatedTarget; if (!((_event$relatedTarget = event.relatedTarget) !== null && _event$relatedTarget !== void 0 && (_event$relatedTarget = _event$relatedTarget.id) !== null && _event$relatedTarget !== void 0 && _event$relatedTarget.startsWith(`${id}-`))) { const run = () => onBlur === null || onBlur === void 0 ? void 0 : onBlur(valuesRef.current); window.requestAnimationFrame(run); areInputsInFocus.current = false; clearGroupSelection(); clearSectionSelection(); } }, ...rest }, String(inputId)); }) }), (0, _jsxRuntime.jsx)("input", { id: id, className: "dnb-segmented-field__hidden-input dnb-sr-only", value: hiddenInputValue, onFocus: focusFirstSection, readOnly: true, tabIndex: -1, "aria-hidden": true })] }); const labelElement = label && (0, _jsxRuntime.jsx)(_FormLabel.default, { element: "legend", forId: id, disabled: disabled, labelDirection: labelDirection, onClick: onLegendClick, children: label }); const wrapperProps = (0, _SpacingUtils.applySpacing)(rest, { ref: element => { if (!hasExternalScopeRef && !scopeRef.current) { scopeRef.current = element; } }, className: 'dnb-segmented-field__fieldset' + (labelDirection === 'horizontal' ? " dnb-segmented-field__fieldset--horizontal" : "") }); return (0, _jsxRuntime.jsx)(WrapperElement, { ...wrapperProps, children: (0, _jsxRuntime.jsx)(_Input.default, { ...rest, id: id, label: labelElement, className: (0, _clsx.default)('dnb-segmented-field', className), size: size, labelDirection: labelDirection, disabled: disabled, status: status, statusState: statusState, suffix: suffix, stretch: stretch, inputElement: inputElement, _omitInputShellClass: _omitInputShellClass }) }); } var _default = exports.default = SegmentedField; (0, _withComponentMarkers.default)(SegmentedField, { _formElement: true, _supportsSpacingProps: true }); //# sourceMappingURL=SegmentedField.js.map