UNPKG

styled-hook-form

Version:

React form library for styled-components based on grommet and react-hook-form

251 lines (250 loc) 13.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DropDown = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = __importStar(require("react")); const react_2 = require("react"); const react_hook_form_1 = require("react-hook-form"); const grommet_1 = require("grommet"); const grommet_2 = require("grommet"); const paged_data_source_1 = require("../../../utils/paged-data-source"); const context_1 = require("../../../../context"); const styled_components_1 = __importDefault(require("styled-components")); // @ts-ignore const styles_1 = require("grommet/utils/styles"); const use_debounce_1 = require("use-debounce"); const grommet_icons_1 = require("grommet-icons"); const remeda_1 = require("remeda"); const MultipleOption = react_2.memo((props) => { let { label, selected } = props; return (jsx_runtime_1.jsxs(grommet_1.Box, Object.assign({ direction: "row", gap: "small", align: "center", pad: "xsmall" }, { children: [jsx_runtime_1.jsx(grommet_1.CheckBox, { tabIndex: -1, checked: selected, onChange: () => { } }, void 0), label] }), void 0)); }); const SingleOption = react_2.memo((props) => { let { label, selected } = props; return (jsx_runtime_1.jsx(grommet_1.Box, Object.assign({ direction: "row", gap: "small", align: "center", pad: "xsmall", background: selected ? "brand" : "light-1" }, { children: label }), void 0)); }); const LabelBox = styled_components_1.default(grommet_1.Box).attrs({ direction: "row", }) ` ${({ plainLabel }) => !plainLabel && styles_1.inputStyle} border:none; display: flex; flex-direction: row; flex-wrap: wrap; `; const DefaultOptionLabel = ({ content }) => (jsx_runtime_1.jsxs("span", { children: [" ", content, " "] }, void 0)); const DropDown = react_1.default.memo(react_2.forwardRef((props, ref) => { let vrules = props.validationRules || {}; const { translate: T } = context_1.useFormBuilderContext(); let { name, label, options, methods, required, multiple, onSearch, itemLabelKey, itemValueKey, placeholder, labelWrap, renderItem, renderItemLabel, plainLabel, selectProps, shouldUnregister, defaultValue: initialValue, searchDebounce = 500, } = props; let [localValue, setLocalValue] = react_2.useState(null); let [localOptions, setLocalOptions] = react_2.useState([]); let [remoteOptions, setRemoteOptions] = react_2.useState([]); let [remoteSearchKey, setRemoteSearchKey] = react_2.useState(""); let dataSourceOptions = react_1.useMemo(() => { return options.hasOwnProperty("request") ? options : null; }, [options]); const params = react_1.useMemo(() => { var _a; return Object.assign(Object.assign({}, (typeof (dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.request) !== "string" ? (_a = dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.request) === null || _a === void 0 ? void 0 : _a.params : {})), dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.extraParams); }, [dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.extraParams, dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.request]); let { loading = false, nextPage = null, hasMore = null } = paged_data_source_1.usePagedData({ request: dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.request, pageParamName: dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.pageKey, pageSizeParamName: dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.pageSizeKey, pageSize: dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.pageSize, searchParamName: dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.searchKey, searchParam: remoteSearchKey, listPropName: dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.listKey, totalPropName: dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.totalKey, params: params, mockResponse: dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.mockResponse, onRequest: (data, headers) => { if (dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.onRequest) { data = dataSourceOptions.onRequest(data, headers); } return data; }, onResponse: (data, page, headers) => { var _a; if (dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.onResponse) { data = dataSourceOptions.onResponse(data, headers); } if (!Array.isArray(data)) { data = data[(_a = dataSourceOptions === null || dataSourceOptions === void 0 ? void 0 : dataSourceOptions.listKey) !== null && _a !== void 0 ? _a : "list"]; } setRemoteOptions((oldOptions) => { let newOptions = [...(page > 1 ? oldOptions : []), ...data]; return newOptions; }); return data; }, }); let control = methods === null || methods === void 0 ? void 0 : methods.control; if (required) { vrules.required = { value: required, message: T("required-msg", { name: label }), }; } react_2.useEffect(() => { setLocalOptions(options instanceof Array ? options : []); }, [options]); let liveValue = react_hook_form_1.useWatch({ name: name, control: methods.control, defaultValue: initialValue, }); let actualOptions = react_1.useMemo(() => (dataSourceOptions ? remoteOptions !== null && remoteOptions !== void 0 ? remoteOptions : [] : localOptions), [dataSourceOptions, remoteOptions, localOptions]); const getOptionsByValue = react_2.useCallback((options, value) => { return options.filter((o) => Array.isArray(value) ? value.some((v) => v === o[itemValueKey] || v[itemValueKey] === o[itemValueKey]) : value === o[itemValueKey] || value === o); }, [itemValueKey]); const liveValueRef = react_1.useRef(null); const updateLocalValue = react_2.useCallback(() => { setLocalValue(getOptionsByValue(actualOptions, liveValue)); liveValueRef.current = liveValue; }, [actualOptions, getOptionsByValue, liveValue]); react_2.useEffect(() => { if (actualOptions && (!liveValueRef.current || JSON.stringify(liveValueRef.current) !== JSON.stringify(liveValue))) { updateLocalValue(); } }, [actualOptions, liveValue, updateLocalValue]); react_2.useEffect(() => { if (actualOptions) { updateLocalValue(); } }, [actualOptions, updateLocalValue]); react_2.useEffect(() => { if (actualOptions && initialValue) { setLocalValue(getOptionsByValue(actualOptions, initialValue)); } }, [actualOptions, getOptionsByValue, initialValue]); const handleSearch = use_debounce_1.useDebouncedCallback((text) => { if (!dataSourceOptions && text.length === 0) { setLocalOptions(options instanceof Array ? options : []); return; } if (dataSourceOptions) { setRemoteSearchKey(text); } else { let filteredOptions; if (onSearch) { filteredOptions = onSearch(text, localOptions); } const escapedText = text.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); filteredOptions = localOptions.filter((o) => o[itemLabelKey].match(new RegExp(escapedText, "gi"))); setLocalOptions(filteredOptions); } }, searchDebounce); const handleMore = () => { if (hasMore) { nextPage(); } }; const selectDynamicProps = {}; if (dataSourceOptions && loading) { selectDynamicProps.icon = jsx_runtime_1.jsx(grommet_2.Spinner, {}, void 0); } const handleChange = react_2.useCallback((field) => (e) => { setLocalValue(e.value); field.onChange(multiple ? e.value.map((v) => v[itemValueKey]) : e.value[itemValueKey]); }, [itemValueKey, multiple]); let selectContent = (option) => { let selectedValues = localValue; let opt_value = option[itemValueKey], opt_label = option[itemLabelKey]; const selected = selectedValues ? Array.isArray(selectedValues) ? selectedValues.findIndex((v) => v[itemValueKey] === opt_value) !== -1 : selectedValues[itemValueKey] === opt_value : false; return multiple ? (jsx_runtime_1.jsx(MultipleOption, { label: renderItem ? (renderItem(option, selected)) : (jsx_runtime_1.jsx(DefaultOptionLabel, { content: opt_label }, void 0)), selected: selected }, void 0)) : renderItem ? (renderItem(option, selected)) : (jsx_runtime_1.jsx(SingleOption, { selected: selected, label: opt_label }, void 0)); }; const valueLabel = () => { const handleClear = (e) => { e.stopPropagation(); setLocalValue(null); if (methods) { methods.setValue(name, null); } }; const isEmpty = (value) => Array.isArray(value) ? !value.length : !value; let _value = localValue ? Array.isArray(localValue) ? localValue : [localValue] : []; let labels = (jsx_runtime_1.jsxs(grommet_1.Box, Object.assign({ direction: "row", justify: "between", align: "center", fill: "horizontal" }, { children: [jsx_runtime_1.jsx(LabelBox, Object.assign({ plainLabel: plainLabel, fill: "horizontal" }, { children: _value && _value.length ? (_value.map((val, idx) => (jsx_runtime_1.jsx(react_1.Fragment, { children: renderItemLabel ? (renderItemLabel(val, { setValue: (setter) => { let transformedValue = setter(_value); methods.setValue(name, transformedValue); setLocalValue(transformedValue); }, }, idx)) : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [jsx_runtime_1.jsx(grommet_1.Text, { children: val[itemLabelKey] }, void 0), localValue.length - 1 > idx && jsx_runtime_1.jsx("span", { children: "," }, void 0)] }, void 0)) }, val[itemValueKey])))) : (jsx_runtime_1.jsx(grommet_1.Text, { children: placeholder !== null && placeholder !== void 0 ? placeholder : T("drop-down-plcaholder") }, void 0)) }), void 0), (selectProps === null || selectProps === void 0 ? void 0 : selectProps.clear) && !isEmpty(localValue) && (jsx_runtime_1.jsx(grommet_1.Button, { focusIndicator: false, icon: jsx_runtime_1.jsx(grommet_icons_1.Close, { size: "small", onClick: handleClear }, void 0) }, void 0))] }), void 0)); let wrapElement = labelWrap ? react_1.default.cloneElement(labelWrap, {}, labels) : react_1.default.createElement(grommet_1.Box, { direction: "row", overflow: "hidden", fill: "horizontal", wrap: true, }, labels); return wrapElement; }; return (jsx_runtime_1.jsx(react_hook_form_1.Controller, { name: name, defaultValue: initialValue, shouldUnregister: shouldUnregister, rules: vrules, control: control, render: ({ field }) => (jsx_runtime_1.jsx(grommet_1.Select, Object.assign({}, selectProps, { closeOnChange: !multiple, ref: ref, multiple: multiple, valueLabel: valueLabel(), options: actualOptions, option: true, labelKey: itemLabelKey, valueKey: itemValueKey, onSearch: handleSearch, onMore: handleMore, onChange: handleChange(field), value: localValue !== null && localValue !== void 0 ? localValue : [], emptySearchMessage: T("drop-down-search-empty-msg"), clear: false }, selectDynamicProps, { children: selectContent }), void 0)) }, void 0)); }), (prev, next) => { const eq = remeda_1.equals(remeda_1.omit(prev, [ "methods", "children", "onChange", "onSearch", "renderItem", "renderItemLabel", "render", ]), remeda_1.omit(next, [ "methods", "children", "onChange", "onSearch", "renderItem", "renderItemLabel", "render", ])); return eq; }); exports.DropDown = DropDown;