All files / frontend/src/components/SukohForm useField.ts

34.28% Statements 12/35
25% Branches 1/4
21.05% Functions 4/19
32.35% Lines 11/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108                          4x 4x   4x       4x   4x 4x   4x 4x           4x 4x           4x                                                                                                                                        
import { useMemo } from 'react';
import { useFormContext, FieldConfig, FileReference } from './FormContext';
 
export interface UseFieldResult<T = unknown> {
  field: FieldConfig;
  value: T | undefined;
  setValue: (value: T, debounce?: number) => void;
  clearValue: () => void;
  cache: Record<string, unknown>;
  meta: typeof useFormContext extends () => infer R ? R extends { meta: infer M } ? M : never : never;
}
 
export function useField<T = unknown>(compositeKey: string): UseFieldResult<T> {
  const form = useFormContext();
  const field = form.getFieldConfig(compositeKey);
 
  Iif (!field) {
    throw new Error(`Field config not found: ${compositeKey}`);
  }
 
  const valuePath = useMemo(() => compositeKey.replace(/^root\./, ''), [compositeKey]);
 
  const value = form.getValueAtPath<T>(valuePath);
  const cache = form.getCache(compositeKey);
 
  const setValue = useMemo(
    () => (newValue: T, debounce?: number) => {
      form.setValueAtPath(valuePath, newValue, debounce);
    },
    [form, valuePath]
  );
 
  const clearValue = useMemo(
    () => () => {
      form.clearValueAtPath(valuePath);
    },
    [form, valuePath]
  );
 
  return { field, value, setValue, clearValue, cache, meta: form.meta };
}
 
export interface UseResourcesResult {
  resources: FileReference[];
  setResources: (files: FileReference[]) => void;
  addResource: (file: FileReference) => void;
  removeResource: (src: string) => void;
  updateResource: (src: string, updates: Partial<FileReference>) => void;
}
 
export function useResources(compositeKey: string): UseResourcesResult {
  const form = useFormContext();
  const resources = form.getResources(compositeKey);
 
  const setResources = useMemo(
    () => (files: FileReference[]) => {
      form.setResources(compositeKey, files);
    },
    [form, compositeKey]
  );
 
  const addResource = useMemo(
    () => (file: FileReference) => {
      form.setResources(compositeKey, [...resources, file]);
    },
    [form, compositeKey, resources]
  );
 
  const removeResource = useMemo(
    () => (src: string) => {
      form.setResources(
        compositeKey,
        resources.filter((r) => r.src !== src)
      );
    },
    [form, compositeKey, resources]
  );
 
  const updateResource = useMemo(
    () => (src: string, updates: Partial<FileReference>) => {
      form.setResources(
        compositeKey,
        resources.map((r) => (r.src === src ? { ...r, ...updates } : r))
      );
    },
    [form, compositeKey, resources]
  );
 
  return { resources, setResources, addResource, removeResource, updateResource };
}
 
export function useRenderFields() {
  return useFormContext().renderFields;
}
 
export function useFormState() {
  const form = useFormContext();
  return {
    isDirty: form.isDirty,
    isSubmitting: form.isSubmitting,
    saveForm: form.saveForm,
    document: form.document,
    meta: form.meta,
  };
}
 
export default useField;