@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 12.1 kB
Source Map (JSON)
{"version":3,"file":"Field.mjs","names":["formMessages"],"sources":["../../../src/base-ui/FormKit/Field.tsx"],"sourcesContent":["'use client';\n\nimport { cx, useResponsive } from 'antd-style';\nimport {\n cloneElement,\n isValidElement,\n memo,\n type ReactElement,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport formMessages from '@/i18n/resources/en/form';\nimport { useTranslation } from '@/i18n/useTranslation';\n\nimport FormDivider from '../Form/components/FormDivider';\nimport FormTitle from '../Form/components/FormTitle';\nimport { fieldStyles, fieldVariants } from '../Form/style';\nimport { resolveBinding } from './binding';\nimport { useFormKitContext } from './context';\nimport type { FieldValidator } from './engine/types';\nimport { getInternals } from './instance';\nimport { toFieldValidator } from './schema';\nimport { fieldKitStyles } from './style';\nimport type { FieldRenderProps, FormFieldProps, FormValues } from './type';\nimport { useStoreSelector } from './useStoreSelector';\n\nconst isEmpty = (value: unknown) =>\n value === undefined ||\n value === null ||\n value === '' ||\n (Array.isArray(value) && value.length === 0);\n\ntype ControlProps = Pick<\n FormFieldProps,\n | 'bare'\n | 'children'\n | 'deps'\n | 'emptyValue'\n | 'getValue'\n | 'name'\n | 'render'\n | 'required'\n | 'trigger'\n | 'validate'\n | 'validateDebounce'\n | 'validateOn'\n | 'valueProp'\n> & { id: string; name: string };\n\nconst FieldControl = memo<ControlProps>(\n ({\n bare,\n children,\n deps,\n emptyValue,\n getValue,\n id,\n name,\n render,\n required,\n trigger,\n validate,\n validateDebounce,\n validateOn,\n valueProp,\n }) => {\n const { form } = useFormKitContext();\n const { engine, validateOn: formValidateOn } = getInternals(form);\n const { t } = useTranslation(formMessages);\n const errorId = `${id}-error`;\n\n const requiredMessage = typeof required === 'string' ? required : t('form.required');\n const fieldValidator = validate ? toFieldValidator(validate) : undefined;\n const validatorRef = useRef<FieldValidator | undefined>(undefined);\n validatorRef.current = async (value, values) => {\n if (required && isEmpty(value)) return requiredMessage;\n return fieldValidator?.(value, values);\n };\n const hasValidator = Boolean(required || validate);\n const depsKey = deps?.join('\\u0000');\n\n useEffect(\n () =>\n engine.registerField(name, {\n debounceMs: validateDebounce,\n deps: depsKey ? depsKey.split('\\u0000') : undefined,\n validate: hasValidator\n ? (value, values) => validatorRef.current!(value, values)\n : undefined,\n validateOn: validateOn ?? formValidateOn,\n }),\n [engine, name, hasValidator, depsKey, validateDebounce, validateOn, formValidateOn],\n );\n\n const field = useStoreSelector(engine, (e) => e.getField(name));\n\n const child = isValidElement(children) ? (children as ReactElement<any>) : undefined;\n const binding = child\n ? resolveBinding(child, { emptyValue, getValue, trigger, valueProp })\n : undefined;\n const handlerRef = useRef({ binding, childProps: child?.props as Record<string, any> });\n handlerRef.current = { binding, childProps: child?.props as Record<string, any> };\n\n const onChange = useCallback(\n (...args: unknown[]) => {\n const { binding: current, childProps } = handlerRef.current;\n if (current) childProps?.[current.trigger]?.(...args);\n const next = current ? current.getValue(...args) : args[0];\n engine.setValue(name, next, 'user');\n },\n [engine, name],\n );\n const onBlur = useCallback(\n (...args: unknown[]) => {\n handlerRef.current.childProps?.onBlur?.(...args);\n engine.blurField(name);\n },\n [engine, name],\n );\n\n const warnedRef = useRef(false);\n useEffect(() => {\n if (render || child || warnedRef.current || process.env.NODE_ENV === 'production') return;\n warnedRef.current = true;\n console.warn(\n `[@lobehub/ui/base-ui/form] Form.Field \"${name}\" needs a single element child or a render prop; nothing was bound.`,\n );\n }, [render, child, name]);\n\n const errorNode =\n field.error && !bare ? (\n <div className={fieldStyles.error} id={errorId}>\n {field.error}\n </div>\n ) : null;\n\n if (render) {\n const renderProps: FieldRenderProps = {\n error: field.error,\n name,\n onBlur,\n onChange,\n touched: field.touched,\n validating: field.validating,\n value: field.value,\n };\n return (\n <>\n {render(renderProps)}\n {errorNode}\n </>\n );\n }\n\n if (!child || !binding) return <>{children}</>;\n\n const control = cloneElement(child, {\n 'aria-describedby': field.error ? errorId : undefined,\n 'aria-invalid': field.error ? true : undefined,\n 'id': child.props.id ?? id,\n [binding.trigger]: onChange,\n [binding.valueProp]: field.value === undefined ? binding.emptyValue : field.value,\n 'onBlur': onBlur,\n });\n\n return (\n <>\n {control}\n {errorNode}\n </>\n );\n },\n);\n\nFieldControl.displayName = 'FormFieldControl';\n\nconst FormField = memo<FormFieldProps>(\n ({\n avatar,\n bare,\n children,\n className,\n deps,\n desc,\n divider,\n emptyValue,\n extra,\n getValue,\n hidden,\n label,\n layout,\n minWidth,\n name,\n render,\n required,\n style,\n tag,\n trigger,\n validate,\n validateDebounce,\n validateOn,\n valueProp,\n variant,\n }) => {\n const id = useId();\n const { mobile } = useResponsive();\n const config = useFormKitContext();\n\n if (hidden) return null;\n\n const control = !name ? (\n children\n ) : (\n <FieldControl\n bare={bare}\n deps={deps}\n emptyValue={emptyValue}\n getValue={getValue}\n id={id}\n name={name}\n render={render}\n required={required}\n trigger={trigger}\n validate={validate}\n validateDebounce={validateDebounce}\n validateOn={validateOn}\n valueProp={valueProp}\n >\n {children}\n </FieldControl>\n );\n\n if (bare) return <>{control}</>;\n\n const labelFor = render\n ? undefined\n : name\n ? id\n : isValidElement<{ id?: string }>(children)\n ? children.props.id\n : undefined;\n const mergedLayout = layout || (mobile ? 'vertical' : config.layout);\n const mergedVariant = variant || config.variant;\n const controlWidth =\n mergedLayout === 'vertical' || minWidth === undefined || minWidth === ''\n ? undefined\n : typeof minWidth === 'number'\n ? `${minWidth}px`\n : minWidth;\n\n return (\n <>\n {divider && <FormDivider visible={mergedVariant !== 'borderless'} />}\n <div className={cx(fieldVariants({ layout: mergedLayout }), className)} style={style}>\n <label className={fieldStyles.label} htmlFor={labelFor}>\n <FormTitle\n avatar={avatar}\n desc={desc}\n tag={tag}\n title={\n required ? (\n <>\n {label}\n <span aria-hidden className={fieldKitStyles.required}>\n *\n </span>\n </>\n ) : (\n label\n )\n }\n />\n </label>\n <div\n style={controlWidth ? { width: controlWidth } : undefined}\n className={cx(\n fieldStyles.control,\n mergedLayout === 'vertical' && fieldStyles.controlVertical,\n controlWidth && fieldKitStyles.controlFixed,\n )}\n >\n {control}\n {extra && <div className={fieldKitStyles.extra}>{extra}</div>}\n </div>\n </div>\n </>\n );\n },\n);\n\nFormField.displayName = 'FormField';\n\nexport default FormField as unknown as (<T extends FormValues = FormValues>(\n props: FormFieldProps<T>,\n) => ReactNode) & { displayName?: string };\n"],"mappings":"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"}