{"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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"}