@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 9.6 kB
Source Map (JSON)
{"version":3,"file":"Form.mjs","names":["Form","BaseForm"],"sources":["../../../src/base-ui/Form/Form.tsx"],"sourcesContent":["'use client';\n\nimport { Form as BaseForm } from '@base-ui/react/form';\nimport { cx, useResponsive } from 'antd-style';\nimport { isUndefined } from 'es-toolkit/compat';\nimport { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport FormField from './components/FormField';\nimport FormFlatGroup from './components/FormFlatGroup';\nimport FormGroup from './components/FormGroup';\nimport { FormContext } from './context';\nimport { rootVariants } from './style';\nimport type { FormFieldProps, FormGroupItemType, FormProps } from './type';\n\nconst serializeForm = (form: HTMLFormElement | null) => {\n if (!form) return '';\n const entries = [...new FormData(form).entries()].filter(\n ([, value]) => typeof value === 'string',\n ) as [string, string][];\n return JSON.stringify(entries.sort((a, b) => a[0].localeCompare(b[0])));\n};\n\nconst Form = memo<FormProps>(\n ({\n className,\n itemMinWidth,\n footer,\n items = [],\n children,\n itemsType = 'group',\n variant = 'borderless',\n classNames,\n styles: customStyles,\n gap,\n style,\n collapsible,\n defaultActiveKey,\n initialValues,\n activeKey,\n onCollapse,\n onFinish,\n onFormSubmit,\n layout,\n ref,\n ...rest\n }) => {\n const { mobile } = useResponsive();\n const formRef = useRef<HTMLFormElement>(null);\n const [submitLoading, setSubmitLoading] = useState(false);\n const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);\n const snapshotRef = useRef('');\n\n const syncUnsaved = useCallback(() => {\n setHasUnsavedChanges(serializeForm(formRef.current) !== snapshotRef.current);\n }, []);\n\n useEffect(() => {\n const form = formRef.current;\n if (!form) return;\n snapshotRef.current = serializeForm(form);\n let resetTimer: ReturnType<typeof setTimeout>;\n const handleMutation = () => syncUnsaved();\n const handleReset = () => {\n resetTimer = setTimeout(() => {\n snapshotRef.current = serializeForm(formRef.current);\n syncUnsaved();\n }, 0);\n };\n form.addEventListener('input', handleMutation);\n form.addEventListener('change', handleMutation);\n form.addEventListener('reset', handleReset);\n return () => {\n clearTimeout(resetTimer);\n form.removeEventListener('input', handleMutation);\n form.removeEventListener('change', handleMutation);\n form.removeEventListener('reset', handleReset);\n };\n }, [syncUnsaved]);\n\n const requestReset = useCallback(() => {\n formRef.current?.reset();\n }, []);\n\n const mergedRef = useCallback(\n (node: HTMLFormElement | null) => {\n formRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [ref],\n );\n\n const context = useMemo(\n () => ({\n hasUnsavedChanges,\n initialValues,\n itemMinWidth,\n layout: layout || (mobile ? ('vertical' as const) : ('horizontal' as const)),\n requestReset,\n submitLoading,\n variant,\n }),\n [\n hasUnsavedChanges,\n initialValues,\n itemMinWidth,\n layout,\n mobile,\n requestReset,\n submitLoading,\n variant,\n ],\n );\n\n const mapFlat = useCallback(\n (item: FormFieldProps, itemIndex: number) => (\n <FormField\n className={classNames?.item}\n divider={itemIndex !== 0}\n key={itemIndex}\n style={customStyles?.item}\n variant={variant}\n {...item}\n />\n ),\n [variant, classNames, customStyles],\n );\n\n const mapTree = useCallback(\n (group: FormGroupItemType, groupIndex: number) => {\n const key = group?.key || groupIndex;\n return (\n <FormGroup\n active={activeKey && group?.key ? activeKey.includes(key) : undefined}\n className={classNames?.group}\n collapsible={isUndefined(group.collapsible) ? collapsible : group.collapsible}\n desc={group?.desc}\n extra={group?.extra}\n icon={group?.icon}\n key={key}\n style={customStyles?.group}\n title={group.title}\n variant={group?.variant || variant}\n defaultActive={\n defaultActiveKey && group?.key ? defaultActiveKey.includes(key) : group?.defaultActive\n }\n onCollapse={(active) => {\n let keys: (string | number)[] = activeKey || defaultActiveKey || [];\n keys = keys.filter((k) => k !== key);\n onCollapse?.(active ? [...keys, key] : keys);\n }}\n >\n {Array.isArray(group.children)\n ? group.children.filter((item) => !item.hidden).map((item, i) => mapFlat(item, i))\n : group.children}\n </FormGroup>\n );\n },\n [\n activeKey,\n collapsible,\n defaultActiveKey,\n onCollapse,\n variant,\n classNames,\n customStyles,\n mapFlat,\n ],\n );\n\n return (\n <FormContext value={context}>\n <BaseForm\n className={cx(rootVariants({ variant }), className)}\n ref={mergedRef}\n style={{ gap, ...style }}\n onFormSubmit={async (values, eventDetails) => {\n onFormSubmit?.(values, eventDetails);\n if (!onFinish) return;\n setSubmitLoading(true);\n try {\n await onFinish(values, eventDetails);\n snapshotRef.current = serializeForm(formRef.current);\n syncUnsaved();\n } finally {\n setSubmitLoading(false);\n }\n }}\n {...rest}\n >\n {items && items.length > 0 ? (\n itemsType === 'group' ? (\n (items as FormGroupItemType[]).map((item, i) => mapTree(item, i))\n ) : (\n <FormFlatGroup\n className={classNames?.group}\n style={customStyles?.group}\n variant={variant}\n >\n {(items as FormFieldProps[])\n .filter((item) => !item.hidden)\n .map((item, i) => mapFlat(item, i))}\n </FormFlatGroup>\n )\n ) : undefined}\n {children}\n {footer}\n </BaseForm>\n </FormContext>\n );\n },\n);\n\nForm.displayName = 'Form';\n\nexport default Form;\n"],"mappings":"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"}