@pinuts/bsr-uikit-relaunch
Version:
BSR UI-KIT Relaunch
290 lines (284 loc) • 12.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _propTypes = _interopRequireDefault(require("prop-types"));
var _react = _interopRequireWildcard(require("react"));
var _formBuilder = require("@pinuts/form-builder");
var _reactI18next = require("react-i18next");
var _react2 = require("@ariakit/react");
var _withFieldGroup = _interopRequireDefault(require("../../hooks/withFieldGroup.jsx"));
var _FormFieldWrapper = _interopRequireDefault(require("../FormFieldWrapper/FormFieldWrapper.jsx"));
var _index = require("../../utils/index.js");
var _BSRAddressSelectorModule = _interopRequireDefault(require("./BSRAddressSelector.module.scss"));
var _BSRAddressContext = require("./BSRAddressContext.js");
var _useGetPlaceHolderText = _interopRequireDefault(require("./useGetPlaceHolderText.js"));
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); }
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; }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } //FIXME this component is too complicated and probably over-engineered.
// simplify it :)
const {
useFormikContext,
useField
} = _formBuilder.formik;
let debounceTimeout = null;
/**
* Fetches options from the given URL
*
* @param url
* @return {({label: string, value: string}|{label: string, value: string}|{label: string, value: string}|{label: string, value: string}|{label: string, value: string})[]}
*/
const fetchOptions = async url => {
try {
const response = await fetch(url);
const data = await response.json();
return data;
} catch (error) {
console.error(error);
}
};
const BSRAutocompleteField = _ref => {
let {
config
} = _ref;
const [t] = (0, _reactI18next.useTranslation)();
const {
scope,
additionalQuery,
labelTemplate,
inputProps = {},
key,
viewMode,
labelText,
disabled,
readOnly,
suggestionsAmount = undefined
} = config;
const {
prevSelection,
setPrevSelection,
selectedOptionId,
setSelectedOptionId,
triggerCancelCombox,
setTriggerCancelCombox,
getControllerPath,
dontShowSelector,
fieldKeys
} = (0, _react.useContext)(_BSRAddressContext.BSRAddressContext);
const {
setFieldValue
} = useFormikContext();
const [field,, {
setValue
}] = useField(key);
const groupKey = fieldKeys?.groupKey;
const labelFieldKey = `${key}Label`;
const [labelField] = useField(labelFieldKey);
const usedValueLabel = labelField?.value;
const [fetchedOptions, setFetchedOptions] = (0, _react.useState)([]);
const [searchInput, setSearchInput] = (0, _react.useState)('');
const [selectedOption, setSelectedOption] = (0, _react.useState)({});
const [isFocused, setIsFocused] = (0, _react.useState)(false);
const preselectedItemRef = (0, _react.useRef)(null);
const inputRef = (0, _react.useRef)(null);
const mountedRef = (0, _react.useRef)(true);
const cancelButtonRef = (0, _react.useRef)(null);
const isInvalid = false;
const controllerPath = getControllerPath();
const placeHolderI18nKey = 'bsrAddressSelector.labels.streetPlaceholder';
const placeHolderI18n = (0, _useGetPlaceHolderText.default)(placeHolderI18nKey);
const placeHolderConfig = config.placeholder || placeHolderI18nKey;
const placeholder = placeHolderConfig && placeHolderI18nKey !== placeHolderConfig ? placeHolderConfig : placeHolderI18n;
// need this to reset the combobox from outside
(0, _react.useEffect)(() => {
if (triggerCancelCombox) {
cancelButtonRef.current?.click();
setSearchInput('');
setTriggerCancelCombox(false);
}
}, [cancelButtonRef, triggerCancelCombox, setTriggerCancelCombox]);
(0, _react.useEffect)(() => {
if (mountedRef) {
const loadData = async () => {
const searchQuery = selectedOptionId || searchInput;
if (searchQuery.length > 2) {
const url = `${controllerPath}streetNames/?searchQuery=${encodeURIComponent(searchQuery)}`;
try {
const dataArr = await fetchOptions(url);
// Nur State verändern, wenn Komponente gemounted ist
if (mountedRef && dataArr) {
if (suggestionsAmount && dataArr.length > suggestionsAmount) {
dataArr.length = suggestionsAmount;
}
setFetchedOptions(dataArr);
}
} catch (error) {
console.error(error);
}
}
};
if (debounceTimeout) {
clearTimeout(debounceTimeout);
}
// set time out for debouncing
debounceTimeout = setTimeout(() => {
loadData();
}, 300);
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[selectedOptionId, scope, additionalQuery, controllerPath, labelTemplate, searchInput]);
(0, _react.useEffect)(() => {
return () => {
mountedRef.current = false;
};
}, []);
const filteredOptions = fetchedOptions; // no filter for now
(0, _react.useEffect)(() => {
const newSelectedOption = fetchedOptions.find(option => option.value === field.value);
if (newSelectedOption) {
if (newSelectedOption.value === '') {
setSearchInput(searchInput);
setSelectedOption(newSelectedOption);
return;
}
setSearchInput(newSelectedOption.label);
setSelectedOption(newSelectedOption);
}
}, [field.value, searchInput, fetchedOptions]);
const handleOnSelectChange = (0, _react.useCallback)(userInput => {
setSearchInput(userInput);
const newSelectedOption = filteredOptions.find(option => option.value === userInput);
setValue(''); // reset value
// set few states to the new selected option, if it exists
const [value, label] = newSelectedOption ? [newSelectedOption.value, newSelectedOption.label] : ['', ''];
setFieldValue(key, value);
setFieldValue(labelFieldKey, label);
setSelectedOption(newSelectedOption || {});
setSelectedOptionId(newSelectedOption?.value || '');
// keep previous selection, if new selection is empty
if (newSelectedOption) {
setPrevSelection(newSelectedOption);
}
}, [setValue, filteredOptions, key, setSearchInput, setSelectedOptionId, setFieldValue, labelFieldKey, setPrevSelection]);
const combobox = (0, _react2.useComboboxStore)({
value: selectedOption?.value === '' && (searchInput === selectedOption.label || searchInput === '') ? '' : searchInput || usedValueLabel,
setValue: handleOnSelectChange,
setSelectedValue: handleOnSelectChange
});
const handleBlur = (0, _react.useCallback)(() => {
setSelectedOptionId('');
setIsFocused(false);
}, [setSelectedOptionId, setIsFocused]);
const resetValues = (0, _react.useCallback)(() => {
setSelectedOptionId(' ');
setPrevSelection({});
setFieldValue(key, '');
setFieldValue(groupKey, '');
setFieldValue(labelFieldKey, undefined);
setTimeout(() => {
try {
inputRef.current.select();
} catch (e) {
// ignore
}
}, 50);
}, [key, setFieldValue, labelFieldKey, groupKey, setSelectedOptionId, setPrevSelection]);
const className = (0, _react.useMemo)(() => [_BSRAddressSelectorModule.default.comboboxWrapper, _BSRAddressSelectorModule.default.formControl, _BSRAddressSelectorModule.default.ariakitCombobox, 'ariakit-combobox', 'form-control py-1 px-0', isFocused && 'focused', isInvalid && 'is-invalid'].filter(Boolean).join(' '), [isFocused, isInvalid]);
const formControlClassNames = (0, _index.getFormControlClassNames)(disabled, readOnly, disabled, ['input', field.className].filter(Boolean));
const getPreviousSelectedItem = (0, _react.useCallback)(() => {
return prevSelection?.value ? prevSelection.value : field.value;
}, [prevSelection, field.value]);
if (dontShowSelector) {
return null;
}
if (viewMode) {
return usedValueLabel?.label || '';
}
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_react2.ComboboxProvider, null, /*#__PURE__*/_react.default.createElement("div", {
className: className
}, /*#__PURE__*/_react.default.createElement(_react2.Combobox, _extends({
store: combobox,
autoSelect: true,
getAutoSelectId: getPreviousSelectedItem,
className: formControlClassNames,
focusable: true,
placeholder: placeholder,
onBlur: handleBlur,
onFocus: event => {
setIsFocused(true);
event.target.select();
},
ref: inputRef
}, inputProps)), selectedOption.value && /*#__PURE__*/_react.default.createElement(_react2.ComboboxCancel, {
className: `btn ${_BSRAddressSelectorModule.default.comboboxCancel || ''}`,
store: combobox,
render: /*#__PURE__*/_react.default.createElement("button", {
type: "button",
onClick: resetValues,
ref: cancelButtonRef,
className: `form-control btn ${_BSRAddressSelectorModule.default.comboboxCancel || ''}`,
"aria-label": `${t('aria.deleteField', {
label: t(labelText)
})}`
})
}), filteredOptions.length > 0 && /*#__PURE__*/_react.default.createElement(_react2.ComboboxDisclosure, {
className: `btn ${_BSRAddressSelectorModule.default.comboboxArrow}`,
store: combobox
})), filteredOptions.length > 0 && /*#__PURE__*/_react.default.createElement("div", {
className: `${_BSRAddressSelectorModule.default.comboboxPopoverWrapper} comboboxPopoverWrapper`
}, /*#__PURE__*/_react.default.createElement(_react2.ComboboxPopover, {
store: combobox,
gutter: 4,
focusable: true,
className: `${_BSRAddressSelectorModule.default.popover}`,
sameWidth: true,
autoFocusOnShow: false,
initialFocus: preselectedItemRef
}, filteredOptions.map((_ref2, index) => {
let {
value,
label
} = _ref2;
return /*#__PURE__*/_react.default.createElement(_react2.ComboboxItem, {
key: `k${value}-${index}`,
id: value,
value: value,
className: `${_BSRAddressSelectorModule.default.comboboxItem} dropdown-item ${value === prevSelection.value ? 'selected' : ''}`,
ref: value === prevSelection.value ? preselectedItemRef : undefined
}, label);
})))));
};
BSRAutocompleteField.propTypes = {
config: _propTypes.default.shape({
controllerPath: _propTypes.default.string,
key: _propTypes.default.string.isRequired,
groupKey: _propTypes.default.string,
labelTemplate: _propTypes.default.string,
inputProps: _propTypes.default.instanceOf(Object),
scope: _propTypes.default.string,
additionalQuery: _propTypes.default.string,
doSubmitOnChange: _propTypes.default.bool,
readOnly: _propTypes.default.bool,
labelText: _propTypes.default.string,
viewMode: _propTypes.default.bool,
disabled: _propTypes.default.bool,
suggestionsAmount: _propTypes.default.number,
placeholder: _propTypes.default.string
}).isRequired
};
const HigherOrderAutocompleteField = (0, _withFieldGroup.default)(BSRAutocompleteField);
const WrappedAutocompleteField = props => {
const {
dontShowSelector
} = (0, _react.useContext)(_BSRAddressContext.BSRAddressContext);
if (dontShowSelector) {
return null;
}
return /*#__PURE__*/_react.default.createElement(_FormFieldWrapper.default, props, /*#__PURE__*/_react.default.createElement(HigherOrderAutocompleteField, props));
};
(0, _formBuilder.registerComponent)('BSRAutocompleteField', WrappedAutocompleteField);
(0, _formBuilder.registerComponent)('BSRAutocompleteFieldBasic', HigherOrderAutocompleteField);
var _default = exports.default = BSRAutocompleteField;