UNPKG

@sparklink-pro/apant

Version:

Apollo & Antd tools

274 lines 15.6 kB
import { __awaiter, __rest } from "tslib"; import { createElement as _createElement } from "react"; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import React, { forwardRef, useContext, useImperativeHandle, useMemo, useState } from 'react'; import { Form as FormAnt } from 'antd'; import { filter, find, isArray, isEqual, isFunction, some } from 'lodash-es'; import { isFormContentType, } from '../definitions'; import { normalizeFieldName, mergeNamePath, getFormHelpers } from '../helpers'; import { resolveWidget, useFields } from '../hooks/Form/useFields'; import { useFilterValues } from '../hooks/Form/useFilterValues'; import { useInitialValues } from '../hooks/Form/useInitialValues'; import { ContextWrapperQueries, ContextWrapperDefault } from './AsyncWrappers'; import { FormError } from './FormError'; export const FieldsContext = React.createContext({}); export const FormDisabledContext = React.createContext(false); const useFieldFromContext = (name) => { const { fields, isList } = useContext(FieldsContext); if (!name) { return undefined; } const fieldName = normalizeFieldName(isArray(name) && isList ? name.slice(1) : name); return find(fields, (f) => isEqual(f.item.name, fieldName)); }; const useFieldListPathFromContext = () => { const { isList, listPath } = useContext(FieldsContext); return isList ? listPath : undefined; }; const useFieldsFromContext = (names, group) => { const { fields } = useContext(FieldsContext); if (names) { const fieldNames = names.map(normalizeFieldName); return filter(fields, (field) => { if (!field.item.name) { return false; } return some(fieldNames, (name) => isEqual(name, field.item.name)); }); } return filter(fields, (field) => field.group === group); }; function FormContentItemDynamic({ content }) { const { context } = useContext(FieldsContext); return (_jsx(FormAnt.Item, { noStyle: true, shouldUpdate: () => true, children: () => content(context) })); } function FormContentItem({ content }) { if (isFunction(content)) { return _jsx(FormContentItemDynamic, { content: content }); } return content; } export function FormItem(_a) { var { name, widgetProps = {} } = _a, props = __rest(_a, ["name", "widgetProps"]); const normalizedName = name ? normalizeFieldName(name) : undefined; const { context } = useContext(FieldsContext); const field = useFieldFromContext(normalizedName); const parentListPath = useFieldListPathFromContext(); const isDisabledForm = useContext(FormDisabledContext); const path = mergeNamePath(parentListPath, normalizedName); const callbackArgs = useMemo(() => (field ? { context, field, path } : undefined), [field, context, path]); const shouldUpdate = useMemo(() => { if (!field || !field.shouldUpdate) { return true; } if (typeof field.shouldUpdate !== 'function') { return field.shouldUpdate || true; } return (prev, next) => { if (typeof field.shouldUpdate !== 'function') { return field.shouldUpdate === undefined ? true : field.shouldUpdate; } return field.shouldUpdate(normalizedName, prev, next); }; }, [field === null || field === void 0 ? void 0 : field.shouldUpdate, normalizedName]); if (field && field.list) { return (_jsxs(FormError, { children: ["Form list ", _jsx("strong", { children: JSON.stringify(normalizedName) }), " is a list but has been called with ", '<FormItem />'] })); } if (!field) { if (normalizedName) { return (_jsxs(FormError, { children: ["Field ", _jsx("strong", { children: JSON.stringify(normalizedName) }), " not found in form."] })); } return _jsx(FormAnt.Item, Object.assign({}, props)); } if (field.item.children || props.children || !field.widget) { return _jsx(FormAnt.Item, Object.assign({}, field.item, { name: normalizedName }, props)); } // Boolean version of show if (field.show === false) { return null; } const isDynamic = isFunction(field.show) || isFunction(field.item.rules) || isFunction(field.disabled) || isFunction(field.widget); /** * A field is dynamic when we need to dynamically render it again if it has a show callback or dynamics rules */ if (!isDynamic || !callbackArgs) { const _b = field.widget, { widget: Widget } = _b, wProps = __rest(_b, ["widget"]); if (field.disabled === true) { wProps.disabled = true; } return (_jsx(FormAnt.Item, Object.assign({}, field.item, { name: normalizedName }, props, { children: _jsx(Widget, Object.assign({}, wProps, widgetProps)) }))); } return (_jsx(FormAnt.Item, { noStyle: true, shouldUpdate: shouldUpdate, children: (form) => { if (isFunction(field.show) && !field.show(callbackArgs)) { return null; } if (!field.widget) { return null; } const rules = isFunction(field.item.rules) ? field.item.rules(callbackArgs) : field.item.rules; const isDisabled = field.disabled === true || isDisabledForm || (isFunction(field.disabled) && field.disabled(callbackArgs)); let _a = isFunction(field.widget) ? field.widget(callbackArgs) : field.widget, { widget: Widget } = _a, wProps = __rest(_a, ["widget"]); if (typeof Widget === 'string') { const _b = resolveWidget(Widget), { widget: W, defaultValue } = _b, wfProps = __rest(_b, ["widget", "defaultValue"]); Widget = W; wProps = Object.assign(Object.assign({}, wProps), wfProps); if (defaultValue && props.initialValue === undefined) { props.initialValue = defaultValue; } } return (_jsx(FormAnt.Item, Object.assign({}, field.item, { name: normalizedName, rules: rules }, props, { children: _jsx(Widget, Object.assign({}, wProps, { disabled: isDisabled }, widgetProps)) }))); } })); } export function FormList(_a) { var _b, _c; var { name, children } = _a, props = __rest(_a, ["name", "children"]); const normalizedName = normalizeFieldName(name); const { context } = useContext(FieldsContext); const field = useFieldFromContext(name); const parentListPath = useFieldListPathFromContext(); const shouldUpdate = useMemo(() => { if (!field || !field.shouldUpdate) { return true; } if (typeof field.shouldUpdate !== 'function') { return field.shouldUpdate || true; } return (prev, next) => { if (typeof field.shouldUpdate !== 'function') { return field.shouldUpdate === undefined ? true : field.shouldUpdate; } return field.shouldUpdate(normalizedName, prev, next); }; }, [field === null || field === void 0 ? void 0 : field.shouldUpdate, normalizedName]); if (field && !field.list) { return (_jsxs(FormError, { children: ["Form item ", _jsx("strong", { children: JSON.stringify(name) }), " is not a list but has been called with ", '<FormList />'] })); } const childrenProp = children || ((_b = field === null || field === void 0 ? void 0 : field.item) === null || _b === void 0 ? void 0 : _b.children); if (!childrenProp) { return (_jsxs(FormError, { children: ["Form list ", _jsx("strong", { children: JSON.stringify(name) }), " doesn't have any children"] })); } const fields = (field === null || field === void 0 ? void 0 : field.fields) || []; const hasFields = fields.length > 0; const listPath = mergeNamePath(parentListPath, normalizedName); const listProps = Object.assign(Object.assign(Object.assign({}, (field ? field.item : {})), props), { name: normalizedName }); const fieldsContext = useMemo(() => ({ context, fields, isList: true, listPath }), [fields, context]); /** Initial values used by default when adding new element in the list, don't bind to global context object */ const initialValuesDefault = useInitialValues({ fields, context: Object.assign(Object.assign({}, context), { object: undefined }) }); const callbackArgs = field ? { context, field, path: listPath } : undefined; const isDynamic = isFunction(field === null || field === void 0 ? void 0 : field.show) || isFunction((_c = field === null || field === void 0 ? void 0 : field.item) === null || _c === void 0 ? void 0 : _c.rules); /** Rewrite the add operation so it uses computed initialValues if no value are provided */ const newChildrenProps = (listFields, _a, meta) => { var { add } = _a, operations = __rest(_a, ["add"]); return childrenProp(listFields, Object.assign(Object.assign({}, operations), { add: (values, idx) => (values !== undefined ? add(values, idx) : add(hasFields ? initialValuesDefault : null, idx)) }), meta); }; if (!field || !isDynamic || !callbackArgs) { if ((field === null || field === void 0 ? void 0 : field.show) === false) { return null; } return (_jsx(FieldsContext.Provider, { value: fieldsContext, children: _jsx(FormAnt.List, Object.assign({}, listProps, { children: newChildrenProps })) })); } return (_jsx(FormAnt.Item, { noStyle: true, shouldUpdate: shouldUpdate, children: () => { if (field.show === false || (isFunction(field.show) && !field.show(callbackArgs))) { return null; } const rules = (isFunction(field === null || field === void 0 ? void 0 : field.item.rules) ? field.item.rules(callbackArgs) : field.item.rules || []).filter((rule) => { if (!rule.validator) { console.warn(`Rules on Form List at ${listPath} only accept customs rules. Skipping rule: `, rule); return false; } return true; }); return (_jsx(FieldsContext.Provider, { value: fieldsContext, children: _jsx(FormAnt.List, Object.assign({}, listProps, { rules: rules, children: newChildrenProps })) })); } })); } export function FormItems({ names, group }) { const fields = useFieldsFromContext(names, group); return (_jsx(_Fragment, { children: fields.map((field, idx) => { const key = `field_${idx}`; if (field.list) { return _jsx(FormList, { name: field.item.name }, key); } const props = field.item.name ? {} : field.item; return _jsx(FormItem, Object.assign({ name: field.item.name }, props), key); }) })); } const FormInner = forwardRef((_a, ref) => { var { debug, config, context: formContext, children, header, footer, onFinish, onValues, contextExtraProps, formRef, onSubmitState } = _a, formProps = __rest(_a, ["debug", "config", "context", "children", "header", "footer", "onFinish", "onValues", "contextExtraProps", "formRef", "onSubmitState"]); const [defaultForm] = FormAnt.useForm(); const form = formProps.form || defaultForm; const [isSubmitting, setIsSubmitting] = useState(false); const context = Object.assign(Object.assign(Object.assign({ form }, formContext), getFormHelpers(form)), { extra: contextExtraProps }); const fields = useFields({ fields: (isFunction(config.fields) ? config.fields(context) : config.fields) || [], mappers: (isFunction(config.mappers) ? config.mappers(context) : config.mappers) || [], context, }); const realFields = fields.filter((f) => !isFormContentType(f)); const additionalProps = (isFunction(config.props) ? config.props(context) : config.props) || {}; const fieldsContext = useMemo(() => ({ fields: realFields, context }), [fields]); const initialValues = useInitialValues({ fields: realFields, context }); if (debug) { console.log('[APANT] Form debug'); console.log('[APANT] Fields', fields); console.log('[APANT] Fields context', fieldsContext); console.log('[APANT] Initial values', initialValues); } const filterValues = useFilterValues({ fields: realFields, context }); useImperativeHandle(ref, () => ({ filterValues, }), [form]); const onFinishFiltered = onFinish ? (values) => __awaiter(void 0, void 0, void 0, function* () { setIsSubmitting(true); onSubmitState === null || onSubmitState === void 0 ? void 0 : onSubmitState(true); if (debug) { console.log('[APANT] Submitted values', values); } let res; try { let filteredValues = yield filterValues(values); if (debug) { console.log('[APANT] Submitted filtered values', values); } if (onValues) { filteredValues = yield onValues(values, context); } res = yield onFinish(filteredValues); } catch (e) { console.error('[APANT] Error while submitting form', e); throw e; } finally { setIsSubmitting(false); onSubmitState === null || onSubmitState === void 0 ? void 0 : onSubmitState(false); return res; } }) : undefined; return (_jsx(FormAnt, Object.assign({ initialValues: initialValues }, additionalProps, formProps, { onFinish: onFinishFiltered, form: form, ref: formRef, children: _jsx(FormDisabledContext.Provider, { value: !!formProps.disabled, children: _jsxs(FieldsContext.Provider, { value: fieldsContext, children: [header, isFunction(children) ? children({ fields: realFields, form, isSubmitting }) : children, !children && fields .filter((f) => isFormContentType(f) || f.auto) .map((field, idx) => { if (isFormContentType(field)) { const key = `content_${idx}`; return _createElement(FormContentItem, Object.assign({}, field, { key: key })); } const key = `field_${idx}`; if (field.list) { return _jsx(FormList, { name: field.item.name }, key); } const props = field.item.name ? {} : field.item; return _jsx(FormItem, Object.assign({ name: field.item.name }, props), key); }), footer] }) }) }))); }); /** * Render a antd form wrapper with the list of fields. */ export const Form = forwardRef((props, ref) => { const { config: { context }, } = props; const ContextWrapperCustom = (context === null || context === void 0 ? void 0 : context.wrapper) || ContextWrapperDefault; return (_jsx(ContextWrapperCustom, { children: (customExtraProps) => (_jsx(ContextWrapperQueries, { queries: (context === null || context === void 0 ? void 0 : context.queries) || {}, children: (queryExtraProps) => (_jsx(FormInner, Object.assign({}, props, { contextExtraProps: Object.assign(Object.assign({}, customExtraProps), queryExtraProps), ref: ref }))) })) })); }); export default Form; //# sourceMappingURL=Form.js.map