@page-speed/forms 0.4.4 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import * as React3 from 'react';
2
- import { createContext, useRef, useCallback, useContext } from 'react';
1
+ import * as React4 from 'react';
2
+ import { useRef, useCallback, useContext } from 'react';
3
3
  import { useObservable, useSelector } from '@legendapp/state/react';
4
4
  import { useMap } from '@opensite/hooks/useMap';
5
5
  import { clsx } from 'clsx';
@@ -249,7 +249,7 @@ function useForm(options) {
249
249
  getFieldMeta
250
250
  };
251
251
  }
252
- var FormContext = createContext(null);
252
+ var FormContext = React4.createContext(null);
253
253
  FormContext.displayName = "FormContext";
254
254
 
255
255
  // src/core/useField.ts
@@ -319,7 +319,7 @@ function Form({
319
319
  noValidate = true,
320
320
  ...props
321
321
  }) {
322
- const handleFormSubmit = React3.useCallback(
322
+ const handleFormSubmit = React4.useCallback(
323
323
  async (e) => {
324
324
  try {
325
325
  await form.handleSubmit(e);
@@ -328,7 +328,7 @@ function Form({
328
328
  },
329
329
  [form]
330
330
  );
331
- return /* @__PURE__ */ React3.createElement(FormContext.Provider, { value: form }, /* @__PURE__ */ React3.createElement(
331
+ return /* @__PURE__ */ React4.createElement(FormContext.Provider, { value: form }, /* @__PURE__ */ React4.createElement(
332
332
  "form",
333
333
  {
334
334
  onSubmit: handleFormSubmit,
@@ -355,7 +355,7 @@ var FieldFeedback = ({
355
355
  }) => {
356
356
  const errorText = Array.isArray(error) ? error.join(", ") : error;
357
357
  if (!errorText || !shouldRenderError) return null;
358
- return /* @__PURE__ */ React.createElement(
358
+ return /* @__PURE__ */ React4.createElement(
359
359
  "div",
360
360
  {
361
361
  id: errorId,
@@ -387,11 +387,11 @@ var LabelGroup = ({
387
387
  variant === "legend" ? "mb-1.5" : "mb-1 block",
388
388
  primaryClassName
389
389
  );
390
- const requiredIndicator = required ? /* @__PURE__ */ React3.createElement("span", { className: "text-destructive pl-0.5", "aria-label": "required" }, "*") : null;
390
+ const requiredIndicator = required ? /* @__PURE__ */ React4.createElement("span", { className: "text-destructive pl-0.5", "aria-label": "required" }, "*") : null;
391
391
  let primaryElement = null;
392
392
  if (primary) {
393
393
  if (variant === "label") {
394
- primaryElement = /* @__PURE__ */ React3.createElement(
394
+ primaryElement = /* @__PURE__ */ React4.createElement(
395
395
  "label",
396
396
  {
397
397
  htmlFor: labelHtmlFor,
@@ -402,12 +402,12 @@ var LabelGroup = ({
402
402
  requiredIndicator
403
403
  );
404
404
  } else if (variant === "legend") {
405
- primaryElement = /* @__PURE__ */ React3.createElement("legend", { "data-slot": "field-legend", className: primaryClasses }, primary, requiredIndicator);
405
+ primaryElement = /* @__PURE__ */ React4.createElement("legend", { "data-slot": "field-legend", className: primaryClasses }, primary, requiredIndicator);
406
406
  } else {
407
- primaryElement = /* @__PURE__ */ React3.createElement("div", { "data-slot": "field-label", className: primaryClasses }, primary, requiredIndicator);
407
+ primaryElement = /* @__PURE__ */ React4.createElement("div", { "data-slot": "field-label", className: primaryClasses }, primary, requiredIndicator);
408
408
  }
409
409
  }
410
- const secondaryElement = secondary ? /* @__PURE__ */ React3.createElement(
410
+ const secondaryElement = secondary ? /* @__PURE__ */ React4.createElement(
411
411
  "p",
412
412
  {
413
413
  "data-slot": "field-description",
@@ -417,7 +417,7 @@ var LabelGroup = ({
417
417
  secondary
418
418
  ) : null;
419
419
  if (!primaryElement && !secondaryElement) return null;
420
- return /* @__PURE__ */ React3.createElement(React3.Fragment, null, primaryElement, secondaryElement);
420
+ return /* @__PURE__ */ React4.createElement(React4.Fragment, null, primaryElement, secondaryElement);
421
421
  };
422
422
 
423
423
  // src/core/Field.tsx
@@ -434,12 +434,12 @@ function Field({
434
434
  }) {
435
435
  const fieldState = useField({ name, validate });
436
436
  const { meta } = fieldState;
437
- const hasError = React3.useMemo(() => {
437
+ const hasError = React4.useMemo(() => {
438
438
  return showError && meta.touched && meta.error ? true : false;
439
439
  }, [meta?.touched, meta?.error, showError]);
440
440
  const errorId = `${name}-error`;
441
441
  const descriptionId = `${name}-description`;
442
- return /* @__PURE__ */ React3.createElement("div", { className, "data-field": name }, /* @__PURE__ */ React3.createElement(
442
+ return /* @__PURE__ */ React4.createElement("div", { className, "data-field": name }, /* @__PURE__ */ React4.createElement(
443
443
  LabelGroup,
444
444
  {
445
445
  labelHtmlFor: name,
@@ -449,7 +449,7 @@ function Field({
449
449
  secondary: description,
450
450
  primary: label
451
451
  }
452
- ), /* @__PURE__ */ React3.createElement("div", null, typeof children === "function" ? children(fieldState) : children), /* @__PURE__ */ React3.createElement(
452
+ ), /* @__PURE__ */ React4.createElement("div", null, typeof children === "function" ? children(fieldState) : children), /* @__PURE__ */ React4.createElement(
453
453
  FieldFeedback,
454
454
  {
455
455
  errorId,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/useForm.ts","../src/core/FormContext.tsx","../src/core/useField.ts","../src/core/Form.tsx","../src/utils.ts","../src/core/field-feedback.tsx","../src/core/label-group.tsx","../src/core/Field.tsx"],"names":["errors","touched","values","initialValues","useCallback","React2","React4"],"mappings":"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","file":"index.js","sourcesContent":["\"use client\";\n\nimport { useCallback, useRef } from \"react\";\nimport { useObservable, useSelector } from \"@legendapp/state/react\";\n// Tree-shakable imports from @opensite/hooks following ECOSYSTEM_GUIDELINES\nimport { useMap } from \"@opensite/hooks/useMap\";\nimport type {\n FormValues,\n FormErrors,\n TouchedFields,\n UseFormOptions,\n UseFormReturn,\n SubmissionStatus,\n FieldInputProps,\n FieldMeta,\n FormHelpers,\n} from \"./types\";\n\n/**\n * useForm - High-performance form state management with field-level reactivity\n *\n * Built on @legendapp/state for optimal performance:\n * - Field-level reactivity: Only re-render the specific field that changed\n * - Observable-based state: ~1 re-render per change vs ~10 for traditional hooks\n * - Tree-shakable: Only bundle what you use\n *\n * @example\n * ```tsx\n * const form = useForm({\n * initialValues: { email: '', password: '' },\n * onSubmit: async (values) => {\n * await login(values);\n * },\n * validationSchema: {\n * email: (value) => !value ? 'Required' : undefined,\n * password: (value) => value.length < 8 ? 'Too short' : undefined,\n * },\n * });\n *\n * return (\n * <form onSubmit={form.handleSubmit}>\n * <input {...form.getFieldProps('email')} />\n * {form.errors.email && <span>{form.errors.email}</span>}\n * </form>\n * );\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/use-form\n */\nexport function useForm<T extends FormValues = FormValues>(\n options: UseFormOptions<T>\n): UseFormReturn<T> {\n const {\n initialValues,\n validationSchema,\n validateOn = \"onBlur\",\n revalidateOn = \"onChange\",\n onSubmit,\n onError,\n debug = false,\n } = options;\n\n // Create observable form state for field-level reactivity\n // Note: Type assertion needed for @legendapp/state beta compatibility\n // The beta version's TypeScript types don't properly expose nested Observable properties\n // This will be removed once stable v3.0.0 is released with proper type definitions\n const state$ = useObservable({\n values: initialValues,\n errors: {} as FormErrors<T>,\n touched: {} as TouchedFields<T>,\n isSubmitting: false,\n status: \"idle\" as SubmissionStatus,\n initialValues: { ...initialValues }, // Create a copy to prevent reference sharing\n hasValidated: {} as Record<string, boolean>,\n }) as any;\n\n // Track validation in progress to prevent race conditions\n const validationInProgress = useRef<Set<string>>(new Set());\n\n // Enhanced state management with @opensite/hooks\n // useMap: Manage complex nested field metadata immutably\n const [, fieldMetadataActions] = useMap<\n string,\n { lastValidated?: number; validationCount: number }\n >();\n\n /**\n * Validate a single field\n * Enhanced with @opensite/hooks useMap for metadata tracking\n */\n const validateField = useCallback(\n async <K extends keyof T>(field: K): Promise<string | undefined> => {\n const validators = validationSchema?.[field];\n if (!validators) return undefined;\n\n const fieldKey = String(field);\n validationInProgress.current.add(fieldKey);\n\n // Track validation metadata using useMap\n const currentMeta = fieldMetadataActions.get(fieldKey) || {\n validationCount: 0,\n };\n fieldMetadataActions.set(fieldKey, {\n lastValidated: Date.now(),\n validationCount: currentMeta.validationCount + 1,\n });\n\n try {\n const value = state$.values[field].get();\n const allValues = state$.values.get();\n\n const validatorArray = Array.isArray(validators)\n ? validators\n : [validators];\n\n for (const validator of validatorArray) {\n const error = await validator(value, allValues);\n if (error) {\n state$.errors[field].set(error);\n validationInProgress.current.delete(fieldKey);\n return error;\n }\n }\n\n // Clear error if validation passed\n state$.errors[field].set(undefined);\n validationInProgress.current.delete(fieldKey);\n return undefined;\n } catch (error) {\n validationInProgress.current.delete(fieldKey);\n const errorMessage =\n error instanceof Error ? error.message : \"Validation error\";\n state$.errors[field].set(errorMessage);\n return errorMessage;\n }\n },\n [validationSchema, state$, fieldMetadataActions]\n );\n\n /**\n * Validate entire form\n */\n const validateForm = useCallback(async (): Promise<FormErrors<T>> => {\n if (!validationSchema) return {};\n\n const fields = Object.keys(validationSchema) as Array<keyof T>;\n const errors: FormErrors<T> = {};\n\n await Promise.all(\n fields.map(async (field) => {\n const error = await validateField(field);\n if (error) {\n errors[field] = error;\n }\n })\n );\n\n state$.errors.set(errors);\n return errors;\n }, [validationSchema, validateField, state$]);\n\n /**\n * Set field value with optional validation\n */\n const setFieldValue = useCallback(\n <K extends keyof T>(field: K, value: T[K]) => {\n state$.values[field].set(value);\n\n // Revalidate if field has been validated before\n const shouldRevalidate =\n revalidateOn === \"onChange\" &&\n state$.hasValidated[String(field)].get();\n\n if (shouldRevalidate && validationSchema?.[field]) {\n validateField(field);\n }\n\n if (debug) {\n console.log(\"[useForm] setFieldValue:\", { field, value });\n }\n },\n [state$, revalidateOn, validationSchema, validateField, debug]\n );\n\n /**\n * Set field as touched with optional validation\n */\n const setFieldTouched = useCallback(\n <K extends keyof T>(field: K, touched: boolean) => {\n state$.touched[field].set(touched);\n\n // Validate on blur if configured\n if (touched && validateOn === \"onBlur\" && validationSchema?.[field]) {\n state$.hasValidated[String(field)].set(true);\n validateField(field);\n }\n\n if (debug) {\n console.log(\"[useForm] setFieldTouched:\", { field, touched });\n }\n },\n [state$, validateOn, validationSchema, validateField, debug]\n );\n\n /**\n * Reset form to initial values\n * Enhanced with @opensite/hooks useMap to clear field metadata\n */\n const resetForm = useCallback(() => {\n state$.values.set(state$.initialValues.get());\n state$.errors.set({});\n state$.touched.set({});\n state$.isSubmitting.set(false);\n state$.status.set(\"idle\");\n state$.hasValidated.set({});\n\n // Clear field metadata tracked by useMap\n fieldMetadataActions.clear();\n\n if (debug) {\n console.log(\"[useForm] Form reset\");\n }\n }, [state$, fieldMetadataActions, debug]);\n\n /**\n * Handle form submission\n */\n const handleSubmit = useCallback(\n async (e?: React.FormEvent) => {\n e?.preventDefault();\n\n if (debug) {\n console.log(\"[useForm] handleSubmit started\");\n }\n\n state$.isSubmitting.set(true);\n state$.status.set(\"submitting\");\n\n try {\n // Validate form\n const errors = await validateForm();\n const hasErrors = Object.keys(errors).length > 0;\n\n if (hasErrors) {\n state$.status.set(\"error\");\n onError?.(errors);\n\n if (debug) {\n console.log(\"[useForm] Validation errors:\", errors);\n }\n\n return;\n }\n\n // Create form helpers\n const helpers: FormHelpers<T> = {\n setValues: (values) => {\n if (typeof values === \"function\") {\n state$.values.set(values(state$.values.get()));\n } else {\n state$.values.set(values);\n }\n },\n setFieldValue,\n setErrors: (errors) => state$.errors.set(errors),\n setFieldError: (field, error) => state$.errors[field].set(error),\n setTouched: (touched) => state$.touched.set(touched),\n setFieldTouched,\n setSubmitting: (submitting) => state$.isSubmitting.set(submitting),\n resetForm,\n };\n\n // Call submission handler\n await onSubmit(state$.values.get(), helpers);\n\n state$.status.set(\"success\");\n\n if (debug) {\n console.log(\"[useForm] Submit successful\");\n }\n } catch (error) {\n state$.status.set(\"error\");\n\n if (debug) {\n console.error(\"[useForm] Submit error:\", error);\n }\n\n throw error;\n } finally {\n state$.isSubmitting.set(false);\n }\n },\n [\n state$,\n validateForm,\n onSubmit,\n onError,\n setFieldValue,\n setFieldTouched,\n resetForm,\n debug,\n ]\n );\n\n /**\n * Get field props for binding to inputs\n */\n const getFieldProps = useCallback(\n <K extends keyof T>(field: K): FieldInputProps<T[K]> => {\n return {\n name: String(field),\n value: state$.values[field].get(),\n onChange: (value: T[K]) => setFieldValue(field, value),\n onBlur: () => setFieldTouched(field, true),\n };\n },\n [state$, setFieldValue, setFieldTouched]\n );\n\n /**\n * Get field meta information\n * Enhanced with @opensite/hooks useMap for validation metadata\n * and usePrevious for change detection\n */\n const getFieldMeta = useCallback(\n <K extends keyof T>(field: K): FieldMeta => {\n const fieldKey = String(field);\n const metadata = fieldMetadataActions.get(fieldKey);\n\n return {\n error: state$.errors[field].get(),\n touched: state$.touched[field].get() ?? false,\n isDirty:\n state$.values[field].get() !== state$.initialValues[field].get(),\n isValidating: validationInProgress.current.has(fieldKey),\n // Additional metadata from @opensite/hooks\n validationCount: metadata?.validationCount,\n lastValidated: metadata?.lastValidated,\n };\n },\n [state$, fieldMetadataActions]\n );\n\n // Use selectors for reactive properties\n const values = useSelector(() => state$.values.get());\n const errors = useSelector(() => state$.errors.get());\n const touched = useSelector(() => state$.touched.get());\n const isSubmitting = useSelector(() => state$.isSubmitting.get());\n const status = useSelector(() => state$.status.get());\n\n // Use selectors for derived state to ensure reactivity\n const isValid = useSelector(() => Object.keys(state$.errors.get()).length === 0);\n const isDirty = useSelector(() => {\n const currentValues = state$.values.get();\n const initialValues = state$.initialValues.get();\n return Object.keys(currentValues).some(\n (key) => currentValues[key] !== initialValues[key]\n );\n });\n\n return {\n // State\n values,\n errors,\n touched,\n isSubmitting,\n isValid,\n isDirty,\n status,\n\n // Actions\n handleSubmit,\n setValues: (values) => {\n if (typeof values === \"function\") {\n state$.values.set(values(state$.values.get()));\n } else {\n state$.values.set(values);\n }\n },\n setFieldValue,\n setErrors: (errors) => state$.errors.set(errors),\n setFieldError: (field, error) => state$.errors[field].set(error),\n setTouched: (touched) => state$.touched.set(touched),\n setFieldTouched,\n validateForm,\n validateField,\n resetForm,\n getFieldProps,\n getFieldMeta,\n };\n}\n","\"use client\";\n\nimport { createContext } from \"react\";\nimport type { UseFormReturn } from \"./types\";\n\n/**\n * FormContext - React context for providing form state to child components\n *\n * Allows useField hook to access form state without prop drilling.\n * Automatically provided by the <Form> component.\n *\n * @internal\n */\nexport const FormContext = createContext<UseFormReturn<any> | null>(null);\n\nFormContext.displayName = \"FormContext\";\n","\"use client\";\n\nimport { useCallback, useContext } from \"react\";\nimport { FormContext } from \"./FormContext\";\nimport type { UseFieldOptions, UseFieldReturn, FieldInputProps, FieldMeta } from \"./types\";\n\n/**\n * useField - Field-level reactive hook for form inputs\n *\n * Provides isolated reactivity for individual form fields.\n * Only re-renders when the specific field changes, not when other fields update.\n *\n * Must be used within a FormContext (inside <Form> component).\n *\n * @example\n * ```tsx\n * function EmailInput() {\n * const { field, meta, helpers } = useField({ name: 'email' });\n *\n * return (\n * <div>\n * <input {...field} type=\"email\" />\n * {meta.touched && meta.error && <span>{meta.error}</span>}\n * </div>\n * );\n * }\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/use-field\n */\nexport function useField<T = any>(\n options: UseFieldOptions<T>\n): UseFieldReturn<T> {\n const { name, validate, transform } = options;\n\n const form = useContext(FormContext);\n\n if (!form) {\n throw new Error(\n \"useField must be used within a FormContext. \" +\n \"Wrap your component with <Form> or use useForm's getFieldProps instead.\"\n );\n }\n\n // Get field props with automatic change/blur handling\n const baseFieldProps = form.getFieldProps(name);\n\n // Apply transform if provided\n const field: FieldInputProps<T> = {\n ...baseFieldProps,\n value: baseFieldProps.value as T,\n onChange: (value: T) => {\n const transformedValue = transform ? transform(value) : value;\n baseFieldProps.onChange(transformedValue);\n\n // Run field-level validation if provided\n if (validate) {\n const result = validate(transformedValue, form.values);\n if (result instanceof Promise) {\n result.then((error) => {\n if (error !== undefined) {\n form.setFieldError(name, error);\n }\n });\n } else if (result !== undefined) {\n form.setFieldError(name, result);\n }\n }\n },\n };\n\n // Get field meta information\n const meta: FieldMeta = form.getFieldMeta(name);\n\n // Field helpers\n const helpers = {\n setValue: useCallback(\n (value: T) => {\n const transformedValue = transform ? transform(value) : value;\n form.setFieldValue(name, transformedValue);\n },\n [name, transform, form]\n ),\n setTouched: useCallback(\n (touched: boolean) => {\n form.setFieldTouched(name, touched);\n },\n [name, form]\n ),\n setError: useCallback(\n (error: string | undefined) => {\n form.setFieldError(name, error);\n },\n [name, form]\n ),\n };\n\n return {\n field,\n meta,\n helpers,\n };\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { FormContext } from \"./FormContext\";\nimport type { FormProps, FormValues } from \"./types\";\n\n/**\n * Form - Progressive enhancement form component\n *\n * Provides form context to child components and handles form submission.\n * Supports progressive enhancement with server-side fallback.\n *\n * Features:\n * - Provides FormContext for useField hook\n * - Handles form submission with validation\n * - Progressive enhancement support (works without JavaScript)\n * - Accessible form semantics\n *\n * @example\n * ```tsx\n * const form = useForm({\n * initialValues: { email: '' },\n * onSubmit: async (values) => {\n * await submitForm(values);\n * },\n * });\n *\n * return (\n * <Form form={form} action=\"/api/submit\" method=\"post\">\n * <input {...form.getFieldProps('email')} />\n * <button type=\"submit\">Submit</button>\n * </Form>\n * );\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/form\n */\nexport function Form<T extends FormValues = FormValues>({\n form,\n children,\n className,\n action,\n method = \"post\",\n noValidate = true,\n ...props\n}: FormProps<T> & React.FormHTMLAttributes<HTMLFormElement>) {\n // Wrap handleSubmit to catch any unhandled rejections\n const handleFormSubmit = React.useCallback(\n async (e: React.FormEvent) => {\n try {\n await form.handleSubmit(e);\n } catch (error) {\n // Error is already handled by useForm, just prevent unhandled rejection\n // The form status and errors are already set by useForm's error handling\n }\n },\n [form]\n );\n\n return (\n <FormContext.Provider value={form}>\n <form\n onSubmit={handleFormSubmit}\n action={action}\n method={method}\n noValidate={noValidate}\n className={className}\n {...props}\n >\n {children}\n </form>\n </FormContext.Provider>\n );\n}\n\nForm.displayName = \"Form\";\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Normalizes browser autofill colors so inputs keep theme colors.\n */\nexport const INPUT_AUTOFILL_RESET_CLASSES =\n \"autofill:bg-transparent autofill:text-foreground \" +\n \"[&:-webkit-autofill]:[-webkit-text-fill-color:hsl(var(--foreground))] \" +\n \"[&:-webkit-autofill]:[caret-color:hsl(var(--foreground))] \" +\n \"[&:-webkit-autofill]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] \" +\n \"[&:-webkit-autofill:hover]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] \" +\n \"[&:-webkit-autofill:focus]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] \" +\n \"[&:-webkit-autofill]:[transition:background-color_9999s_ease-out,color_9999s_ease-out]\";\n","\"use client\";\n\nimport { FieldMeta } from \"./types\";\nimport { cn } from \"../utils\";\n\ntype Props = {\n errorId?: string;\n errorClassName?: string;\n shouldRenderError?: boolean;\n error?: FieldMeta[\"error\"];\n};\nconst FieldFeedback = ({\n errorId,\n errorClassName,\n error,\n shouldRenderError,\n}: Props) => {\n const errorText = Array.isArray(error) ? error.join(\", \") : error;\n if (!errorText || !shouldRenderError) return null;\n\n return (\n <div\n id={errorId}\n className={cn(\n \"text-xs px-3 py-2 font-medium\",\n \"rounded-md shadow-md mt-2\",\n \"text-destructive-foreground bg-destructive\",\n \"border border-destructive\",\n errorClassName,\n )}\n role=\"alert\"\n aria-live=\"polite\"\n >\n {errorText}\n </div>\n );\n};\n\nexport { FieldFeedback };\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../utils\";\n\nexport type LabelGroupProps = {\n variant?: \"legend\" | \"label\" | \"text\";\n secondary?: ReactNode;\n secondaryId?: string;\n primary?: ReactNode;\n labelHtmlFor?: string;\n required?: boolean;\n primaryClassName?: string;\n secondaryClassName?: string;\n};\n\nconst LabelGroup = ({\n labelHtmlFor,\n required = false,\n variant = \"label\",\n secondaryId,\n secondary,\n primary,\n primaryClassName,\n secondaryClassName,\n}: LabelGroupProps) => {\n const primaryClasses = cn(\n \"text-sm font-medium leading-snug\",\n variant === \"legend\" ? \"mb-1.5\" : \"mb-1 block\",\n primaryClassName,\n );\n\n const requiredIndicator = required ? (\n <span className=\"text-destructive pl-0.5\" aria-label=\"required\">\n *\n </span>\n ) : null;\n\n let primaryElement: ReactNode = null;\n if (primary) {\n if (variant === \"label\") {\n primaryElement = (\n <label\n htmlFor={labelHtmlFor}\n data-slot=\"field-label\"\n className={primaryClasses}\n >\n {primary}\n {requiredIndicator}\n </label>\n );\n } else if (variant === \"legend\") {\n primaryElement = (\n <legend data-slot=\"field-legend\" className={primaryClasses}>\n {primary}\n {requiredIndicator}\n </legend>\n );\n } else {\n primaryElement = (\n <div data-slot=\"field-label\" className={primaryClasses}>\n {primary}\n {requiredIndicator}\n </div>\n );\n }\n }\n\n const secondaryElement = secondary ? (\n <p\n data-slot=\"field-description\"\n id={secondaryId}\n className={cn(\"text-sm leading-normal font-normal\", secondaryClassName)}\n >\n {secondary}\n </p>\n ) : null;\n\n if (!primaryElement && !secondaryElement) return null;\n\n return (\n <>\n {primaryElement}\n {secondaryElement}\n </>\n );\n};\n\nexport { LabelGroup };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { useField } from \"./useField\";\nimport type { FieldProps } from \"./types\";\nimport { FieldFeedback } from \"./field-feedback\";\nimport { LabelGroup } from \"./label-group\";\n\n/**\n * Field - Field wrapper component with label, description, and error display\n *\n * Provides a complete field UI with automatic error handling and accessibility.\n * Uses useField hook internally for field-level reactivity.\n *\n * Features:\n * - Automatic label association\n * - Error display with accessibility\n * - Optional description text\n * - Render prop pattern for flexibility\n * - Full accessibility support\n *\n * @example\n * ```tsx\n * <Field name=\"email\" label=\"Email Address\" description=\"We'll never share your email\">\n * {({ field, meta }) => (\n * <input\n * {...field}\n * type=\"email\"\n * className={meta.error && meta.touched ? 'error' : ''}\n * />\n * )}\n * </Field>\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/field\n */\nexport function Field({\n name,\n label,\n description,\n children,\n showError = true,\n className,\n errorClassName,\n required = false,\n validate,\n}: FieldProps) {\n const fieldState = useField({ name, validate });\n const { meta } = fieldState;\n\n const hasError = React.useMemo(() => {\n return showError && meta.touched && meta.error ? true : false;\n }, [meta?.touched, meta?.error, showError]);\n\n const errorId = `${name}-error`;\n const descriptionId = `${name}-description`;\n\n return (\n <div className={className} data-field={name}>\n <LabelGroup\n labelHtmlFor={name}\n required={required}\n variant=\"label\"\n secondaryId={descriptionId}\n secondary={description}\n primary={label}\n />\n\n {/* Field content (render prop or direct children) */}\n <div>\n {typeof children === \"function\" ? children(fieldState) : children}\n </div>\n\n {/* Error message */}\n <FieldFeedback\n errorId={errorId}\n errorClassName={errorClassName}\n shouldRenderError={hasError}\n error={meta.error}\n />\n </div>\n );\n}\n\nField.displayName = \"Field\";\n"]}
1
+ {"version":3,"sources":["../src/core/useForm.ts","../src/core/FormContext.tsx","../src/core/useField.ts","../src/core/Form.tsx","../src/utils.ts","../src/core/field-feedback.tsx","../src/core/label-group.tsx","../src/core/Field.tsx"],"names":["errors","touched","values","initialValues","React","useCallback","React2","React3","React5"],"mappings":"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","file":"index.js","sourcesContent":["\"use client\";\n\nimport { useCallback, useRef } from \"react\";\nimport { useObservable, useSelector } from \"@legendapp/state/react\";\n// Tree-shakable imports from @opensite/hooks following ECOSYSTEM_GUIDELINES\nimport { useMap } from \"@opensite/hooks/useMap\";\nimport type {\n FormValues,\n FormErrors,\n TouchedFields,\n UseFormOptions,\n UseFormReturn,\n SubmissionStatus,\n FieldInputProps,\n FieldMeta,\n FormHelpers,\n} from \"./types\";\n\n/**\n * useForm - High-performance form state management with field-level reactivity\n *\n * Built on @legendapp/state for optimal performance:\n * - Field-level reactivity: Only re-render the specific field that changed\n * - Observable-based state: ~1 re-render per change vs ~10 for traditional hooks\n * - Tree-shakable: Only bundle what you use\n *\n * @example\n * ```tsx\n * const form = useForm({\n * initialValues: { email: '', password: '' },\n * onSubmit: async (values) => {\n * await login(values);\n * },\n * validationSchema: {\n * email: (value) => !value ? 'Required' : undefined,\n * password: (value) => value.length < 8 ? 'Too short' : undefined,\n * },\n * });\n *\n * return (\n * <form onSubmit={form.handleSubmit}>\n * <input {...form.getFieldProps('email')} />\n * {form.errors.email && <span>{form.errors.email}</span>}\n * </form>\n * );\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/use-form\n */\nexport function useForm<T extends FormValues = FormValues>(\n options: UseFormOptions<T>\n): UseFormReturn<T> {\n const {\n initialValues,\n validationSchema,\n validateOn = \"onBlur\",\n revalidateOn = \"onChange\",\n onSubmit,\n onError,\n debug = false,\n } = options;\n\n // Create observable form state for field-level reactivity\n // Note: Type assertion needed for @legendapp/state beta compatibility\n // The beta version's TypeScript types don't properly expose nested Observable properties\n // This will be removed once stable v3.0.0 is released with proper type definitions\n const state$ = useObservable({\n values: initialValues,\n errors: {} as FormErrors<T>,\n touched: {} as TouchedFields<T>,\n isSubmitting: false,\n status: \"idle\" as SubmissionStatus,\n initialValues: { ...initialValues }, // Create a copy to prevent reference sharing\n hasValidated: {} as Record<string, boolean>,\n }) as any;\n\n // Track validation in progress to prevent race conditions\n const validationInProgress = useRef<Set<string>>(new Set());\n\n // Enhanced state management with @opensite/hooks\n // useMap: Manage complex nested field metadata immutably\n const [, fieldMetadataActions] = useMap<\n string,\n { lastValidated?: number; validationCount: number }\n >();\n\n /**\n * Validate a single field\n * Enhanced with @opensite/hooks useMap for metadata tracking\n */\n const validateField = useCallback(\n async <K extends keyof T>(field: K): Promise<string | undefined> => {\n const validators = validationSchema?.[field];\n if (!validators) return undefined;\n\n const fieldKey = String(field);\n validationInProgress.current.add(fieldKey);\n\n // Track validation metadata using useMap\n const currentMeta = fieldMetadataActions.get(fieldKey) || {\n validationCount: 0,\n };\n fieldMetadataActions.set(fieldKey, {\n lastValidated: Date.now(),\n validationCount: currentMeta.validationCount + 1,\n });\n\n try {\n const value = state$.values[field].get();\n const allValues = state$.values.get();\n\n const validatorArray = Array.isArray(validators)\n ? validators\n : [validators];\n\n for (const validator of validatorArray) {\n const error = await validator(value, allValues);\n if (error) {\n state$.errors[field].set(error);\n validationInProgress.current.delete(fieldKey);\n return error;\n }\n }\n\n // Clear error if validation passed\n state$.errors[field].set(undefined);\n validationInProgress.current.delete(fieldKey);\n return undefined;\n } catch (error) {\n validationInProgress.current.delete(fieldKey);\n const errorMessage =\n error instanceof Error ? error.message : \"Validation error\";\n state$.errors[field].set(errorMessage);\n return errorMessage;\n }\n },\n [validationSchema, state$, fieldMetadataActions]\n );\n\n /**\n * Validate entire form\n */\n const validateForm = useCallback(async (): Promise<FormErrors<T>> => {\n if (!validationSchema) return {};\n\n const fields = Object.keys(validationSchema) as Array<keyof T>;\n const errors: FormErrors<T> = {};\n\n await Promise.all(\n fields.map(async (field) => {\n const error = await validateField(field);\n if (error) {\n errors[field] = error;\n }\n })\n );\n\n state$.errors.set(errors);\n return errors;\n }, [validationSchema, validateField, state$]);\n\n /**\n * Set field value with optional validation\n */\n const setFieldValue = useCallback(\n <K extends keyof T>(field: K, value: T[K]) => {\n state$.values[field].set(value);\n\n // Revalidate if field has been validated before\n const shouldRevalidate =\n revalidateOn === \"onChange\" &&\n state$.hasValidated[String(field)].get();\n\n if (shouldRevalidate && validationSchema?.[field]) {\n validateField(field);\n }\n\n if (debug) {\n console.log(\"[useForm] setFieldValue:\", { field, value });\n }\n },\n [state$, revalidateOn, validationSchema, validateField, debug]\n );\n\n /**\n * Set field as touched with optional validation\n */\n const setFieldTouched = useCallback(\n <K extends keyof T>(field: K, touched: boolean) => {\n state$.touched[field].set(touched);\n\n // Validate on blur if configured\n if (touched && validateOn === \"onBlur\" && validationSchema?.[field]) {\n state$.hasValidated[String(field)].set(true);\n validateField(field);\n }\n\n if (debug) {\n console.log(\"[useForm] setFieldTouched:\", { field, touched });\n }\n },\n [state$, validateOn, validationSchema, validateField, debug]\n );\n\n /**\n * Reset form to initial values\n * Enhanced with @opensite/hooks useMap to clear field metadata\n */\n const resetForm = useCallback(() => {\n state$.values.set(state$.initialValues.get());\n state$.errors.set({});\n state$.touched.set({});\n state$.isSubmitting.set(false);\n state$.status.set(\"idle\");\n state$.hasValidated.set({});\n\n // Clear field metadata tracked by useMap\n fieldMetadataActions.clear();\n\n if (debug) {\n console.log(\"[useForm] Form reset\");\n }\n }, [state$, fieldMetadataActions, debug]);\n\n /**\n * Handle form submission\n */\n const handleSubmit = useCallback(\n async (e?: React.FormEvent) => {\n e?.preventDefault();\n\n if (debug) {\n console.log(\"[useForm] handleSubmit started\");\n }\n\n state$.isSubmitting.set(true);\n state$.status.set(\"submitting\");\n\n try {\n // Validate form\n const errors = await validateForm();\n const hasErrors = Object.keys(errors).length > 0;\n\n if (hasErrors) {\n state$.status.set(\"error\");\n onError?.(errors);\n\n if (debug) {\n console.log(\"[useForm] Validation errors:\", errors);\n }\n\n return;\n }\n\n // Create form helpers\n const helpers: FormHelpers<T> = {\n setValues: (values) => {\n if (typeof values === \"function\") {\n state$.values.set(values(state$.values.get()));\n } else {\n state$.values.set(values);\n }\n },\n setFieldValue,\n setErrors: (errors) => state$.errors.set(errors),\n setFieldError: (field, error) => state$.errors[field].set(error),\n setTouched: (touched) => state$.touched.set(touched),\n setFieldTouched,\n setSubmitting: (submitting) => state$.isSubmitting.set(submitting),\n resetForm,\n };\n\n // Call submission handler\n await onSubmit(state$.values.get(), helpers);\n\n state$.status.set(\"success\");\n\n if (debug) {\n console.log(\"[useForm] Submit successful\");\n }\n } catch (error) {\n state$.status.set(\"error\");\n\n if (debug) {\n console.error(\"[useForm] Submit error:\", error);\n }\n\n throw error;\n } finally {\n state$.isSubmitting.set(false);\n }\n },\n [\n state$,\n validateForm,\n onSubmit,\n onError,\n setFieldValue,\n setFieldTouched,\n resetForm,\n debug,\n ]\n );\n\n /**\n * Get field props for binding to inputs\n */\n const getFieldProps = useCallback(\n <K extends keyof T>(field: K): FieldInputProps<T[K]> => {\n return {\n name: String(field),\n value: state$.values[field].get(),\n onChange: (value: T[K]) => setFieldValue(field, value),\n onBlur: () => setFieldTouched(field, true),\n };\n },\n [state$, setFieldValue, setFieldTouched]\n );\n\n /**\n * Get field meta information\n * Enhanced with @opensite/hooks useMap for validation metadata\n * and usePrevious for change detection\n */\n const getFieldMeta = useCallback(\n <K extends keyof T>(field: K): FieldMeta => {\n const fieldKey = String(field);\n const metadata = fieldMetadataActions.get(fieldKey);\n\n return {\n error: state$.errors[field].get(),\n touched: state$.touched[field].get() ?? false,\n isDirty:\n state$.values[field].get() !== state$.initialValues[field].get(),\n isValidating: validationInProgress.current.has(fieldKey),\n // Additional metadata from @opensite/hooks\n validationCount: metadata?.validationCount,\n lastValidated: metadata?.lastValidated,\n };\n },\n [state$, fieldMetadataActions]\n );\n\n // Use selectors for reactive properties\n const values = useSelector(() => state$.values.get());\n const errors = useSelector(() => state$.errors.get());\n const touched = useSelector(() => state$.touched.get());\n const isSubmitting = useSelector(() => state$.isSubmitting.get());\n const status = useSelector(() => state$.status.get());\n\n // Use selectors for derived state to ensure reactivity\n const isValid = useSelector(() => Object.keys(state$.errors.get()).length === 0);\n const isDirty = useSelector(() => {\n const currentValues = state$.values.get();\n const initialValues = state$.initialValues.get();\n return Object.keys(currentValues).some(\n (key) => currentValues[key] !== initialValues[key]\n );\n });\n\n return {\n // State\n values,\n errors,\n touched,\n isSubmitting,\n isValid,\n isDirty,\n status,\n\n // Actions\n handleSubmit,\n setValues: (values) => {\n if (typeof values === \"function\") {\n state$.values.set(values(state$.values.get()));\n } else {\n state$.values.set(values);\n }\n },\n setFieldValue,\n setErrors: (errors) => state$.errors.set(errors),\n setFieldError: (field, error) => state$.errors[field].set(error),\n setTouched: (touched) => state$.touched.set(touched),\n setFieldTouched,\n validateForm,\n validateField,\n resetForm,\n getFieldProps,\n getFieldMeta,\n };\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { UseFormReturn } from \"./types\";\n\n/**\n * FormContext - React context for providing form state to child components\n *\n * Allows useField hook to access form state without prop drilling.\n * Automatically provided by the <Form> component.\n *\n * @internal\n */\nexport const FormContext = React.createContext<UseFormReturn<any> | null>(null);\n\nFormContext.displayName = \"FormContext\";\n","\"use client\";\n\nimport { useCallback, useContext } from \"react\";\nimport { FormContext } from \"./FormContext\";\nimport type { UseFieldOptions, UseFieldReturn, FieldInputProps, FieldMeta } from \"./types\";\n\n/**\n * useField - Field-level reactive hook for form inputs\n *\n * Provides isolated reactivity for individual form fields.\n * Only re-renders when the specific field changes, not when other fields update.\n *\n * Must be used within a FormContext (inside <Form> component).\n *\n * @example\n * ```tsx\n * function EmailInput() {\n * const { field, meta, helpers } = useField({ name: 'email' });\n *\n * return (\n * <div>\n * <input {...field} type=\"email\" />\n * {meta.touched && meta.error && <span>{meta.error}</span>}\n * </div>\n * );\n * }\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/use-field\n */\nexport function useField<T = any>(\n options: UseFieldOptions<T>\n): UseFieldReturn<T> {\n const { name, validate, transform } = options;\n\n const form = useContext(FormContext);\n\n if (!form) {\n throw new Error(\n \"useField must be used within a FormContext. \" +\n \"Wrap your component with <Form> or use useForm's getFieldProps instead.\"\n );\n }\n\n // Get field props with automatic change/blur handling\n const baseFieldProps = form.getFieldProps(name);\n\n // Apply transform if provided\n const field: FieldInputProps<T> = {\n ...baseFieldProps,\n value: baseFieldProps.value as T,\n onChange: (value: T) => {\n const transformedValue = transform ? transform(value) : value;\n baseFieldProps.onChange(transformedValue);\n\n // Run field-level validation if provided\n if (validate) {\n const result = validate(transformedValue, form.values);\n if (result instanceof Promise) {\n result.then((error) => {\n if (error !== undefined) {\n form.setFieldError(name, error);\n }\n });\n } else if (result !== undefined) {\n form.setFieldError(name, result);\n }\n }\n },\n };\n\n // Get field meta information\n const meta: FieldMeta = form.getFieldMeta(name);\n\n // Field helpers\n const helpers = {\n setValue: useCallback(\n (value: T) => {\n const transformedValue = transform ? transform(value) : value;\n form.setFieldValue(name, transformedValue);\n },\n [name, transform, form]\n ),\n setTouched: useCallback(\n (touched: boolean) => {\n form.setFieldTouched(name, touched);\n },\n [name, form]\n ),\n setError: useCallback(\n (error: string | undefined) => {\n form.setFieldError(name, error);\n },\n [name, form]\n ),\n };\n\n return {\n field,\n meta,\n helpers,\n };\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { FormContext } from \"./FormContext\";\nimport type { FormProps, FormValues } from \"./types\";\n\n/**\n * Form - Progressive enhancement form component\n *\n * Provides form context to child components and handles form submission.\n * Supports progressive enhancement with server-side fallback.\n *\n * Features:\n * - Provides FormContext for useField hook\n * - Handles form submission with validation\n * - Progressive enhancement support (works without JavaScript)\n * - Accessible form semantics\n *\n * @example\n * ```tsx\n * const form = useForm({\n * initialValues: { email: '' },\n * onSubmit: async (values) => {\n * await submitForm(values);\n * },\n * });\n *\n * return (\n * <Form form={form} action=\"/api/submit\" method=\"post\">\n * <input {...form.getFieldProps('email')} />\n * <button type=\"submit\">Submit</button>\n * </Form>\n * );\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/form\n */\nexport function Form<T extends FormValues = FormValues>({\n form,\n children,\n className,\n action,\n method = \"post\",\n noValidate = true,\n ...props\n}: FormProps<T> & React.FormHTMLAttributes<HTMLFormElement>) {\n // Wrap handleSubmit to catch any unhandled rejections\n const handleFormSubmit = React.useCallback(\n async (e: React.FormEvent) => {\n try {\n await form.handleSubmit(e);\n } catch (error) {\n // Error is already handled by useForm, just prevent unhandled rejection\n // The form status and errors are already set by useForm's error handling\n }\n },\n [form]\n );\n\n return (\n <FormContext.Provider value={form}>\n <form\n onSubmit={handleFormSubmit}\n action={action}\n method={method}\n noValidate={noValidate}\n className={className}\n {...props}\n >\n {children}\n </form>\n </FormContext.Provider>\n );\n}\n\nForm.displayName = \"Form\";\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Normalizes browser autofill colors so inputs keep theme colors.\n */\nexport const INPUT_AUTOFILL_RESET_CLASSES =\n \"autofill:bg-transparent autofill:text-foreground \" +\n \"[&:-webkit-autofill]:[-webkit-text-fill-color:hsl(var(--foreground))] \" +\n \"[&:-webkit-autofill]:[caret-color:hsl(var(--foreground))] \" +\n \"[&:-webkit-autofill]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] \" +\n \"[&:-webkit-autofill:hover]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] \" +\n \"[&:-webkit-autofill:focus]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] \" +\n \"[&:-webkit-autofill]:[transition:background-color_9999s_ease-out,color_9999s_ease-out]\";\n","\"use client\";\n\nimport * as React from \"react\";\nimport { FieldMeta } from \"./types\";\nimport { cn } from \"../utils\";\n\ntype Props = {\n errorId?: string;\n errorClassName?: string;\n shouldRenderError?: boolean;\n error?: FieldMeta[\"error\"];\n};\nconst FieldFeedback = ({\n errorId,\n errorClassName,\n error,\n shouldRenderError,\n}: Props) => {\n const errorText = Array.isArray(error) ? error.join(\", \") : error;\n if (!errorText || !shouldRenderError) return null;\n\n return (\n <div\n id={errorId}\n className={cn(\n \"text-xs px-3 py-2 font-medium\",\n \"rounded-md shadow-md mt-2\",\n \"text-destructive-foreground bg-destructive\",\n \"border border-destructive\",\n errorClassName,\n )}\n role=\"alert\"\n aria-live=\"polite\"\n >\n {errorText}\n </div>\n );\n};\n\nexport { FieldFeedback };\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../utils\";\n\nexport type LabelGroupProps = {\n variant?: \"legend\" | \"label\" | \"text\";\n secondary?: ReactNode;\n secondaryId?: string;\n primary?: ReactNode;\n labelHtmlFor?: string;\n required?: boolean;\n primaryClassName?: string;\n secondaryClassName?: string;\n};\n\nconst LabelGroup = ({\n labelHtmlFor,\n required = false,\n variant = \"label\",\n secondaryId,\n secondary,\n primary,\n primaryClassName,\n secondaryClassName,\n}: LabelGroupProps) => {\n const primaryClasses = cn(\n \"text-sm font-medium leading-snug\",\n variant === \"legend\" ? \"mb-1.5\" : \"mb-1 block\",\n primaryClassName,\n );\n\n const requiredIndicator = required ? (\n <span className=\"text-destructive pl-0.5\" aria-label=\"required\">\n *\n </span>\n ) : null;\n\n let primaryElement: ReactNode = null;\n if (primary) {\n if (variant === \"label\") {\n primaryElement = (\n <label\n htmlFor={labelHtmlFor}\n data-slot=\"field-label\"\n className={primaryClasses}\n >\n {primary}\n {requiredIndicator}\n </label>\n );\n } else if (variant === \"legend\") {\n primaryElement = (\n <legend data-slot=\"field-legend\" className={primaryClasses}>\n {primary}\n {requiredIndicator}\n </legend>\n );\n } else {\n primaryElement = (\n <div data-slot=\"field-label\" className={primaryClasses}>\n {primary}\n {requiredIndicator}\n </div>\n );\n }\n }\n\n const secondaryElement = secondary ? (\n <p\n data-slot=\"field-description\"\n id={secondaryId}\n className={cn(\"text-sm leading-normal font-normal\", secondaryClassName)}\n >\n {secondary}\n </p>\n ) : null;\n\n if (!primaryElement && !secondaryElement) return null;\n\n return (\n <>\n {primaryElement}\n {secondaryElement}\n </>\n );\n};\n\nexport { LabelGroup };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { useField } from \"./useField\";\nimport type { FieldProps } from \"./types\";\nimport { FieldFeedback } from \"./field-feedback\";\nimport { LabelGroup } from \"./label-group\";\n\n/**\n * Field - Field wrapper component with label, description, and error display\n *\n * Provides a complete field UI with automatic error handling and accessibility.\n * Uses useField hook internally for field-level reactivity.\n *\n * Features:\n * - Automatic label association\n * - Error display with accessibility\n * - Optional description text\n * - Render prop pattern for flexibility\n * - Full accessibility support\n *\n * @example\n * ```tsx\n * <Field name=\"email\" label=\"Email Address\" description=\"We'll never share your email\">\n * {({ field, meta }) => (\n * <input\n * {...field}\n * type=\"email\"\n * className={meta.error && meta.touched ? 'error' : ''}\n * />\n * )}\n * </Field>\n * ```\n *\n * @see https://opensite.ai/developers/page-speed/forms/field\n */\nexport function Field({\n name,\n label,\n description,\n children,\n showError = true,\n className,\n errorClassName,\n required = false,\n validate,\n}: FieldProps) {\n const fieldState = useField({ name, validate });\n const { meta } = fieldState;\n\n const hasError = React.useMemo(() => {\n return showError && meta.touched && meta.error ? true : false;\n }, [meta?.touched, meta?.error, showError]);\n\n const errorId = `${name}-error`;\n const descriptionId = `${name}-description`;\n\n return (\n <div className={className} data-field={name}>\n <LabelGroup\n labelHtmlFor={name}\n required={required}\n variant=\"label\"\n secondaryId={descriptionId}\n secondary={description}\n primary={label}\n />\n\n {/* Field content (render prop or direct children) */}\n <div>\n {typeof children === \"function\" ? children(fieldState) : children}\n </div>\n\n {/* Error message */}\n <FieldFeedback\n errorId={errorId}\n errorClassName={errorClassName}\n shouldRenderError={hasError}\n error={meta.error}\n />\n </div>\n );\n}\n\nField.displayName = \"Field\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@page-speed/forms",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "Ultra-high-performance React form library with field-level reactivity and tree-shakable architecture",
5
5
  "keywords": [
6
6
  "react",