@ram_28/kf-ai-sdk 1.0.0
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/LICENSE +21 -0
- package/README.md +840 -0
- package/dist/api/client.d.ts +78 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/datetime.d.ts +21 -0
- package/dist/api/datetime.d.ts.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/metadata.d.ts +75 -0
- package/dist/api/metadata.d.ts.map +1 -0
- package/dist/components/hooks/index.d.ts +8 -0
- package/dist/components/hooks/index.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/index.d.ts +5 -0
- package/dist/components/hooks/useFilter/index.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/payloadBuilder.utils.d.ts +33 -0
- package/dist/components/hooks/useFilter/payloadBuilder.utils.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/types.d.ts +137 -0
- package/dist/components/hooks/useFilter/types.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts +3 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/validation.utils.d.ts +38 -0
- package/dist/components/hooks/useFilter/validation.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/apiClient.d.ts +71 -0
- package/dist/components/hooks/useForm/apiClient.d.ts.map +1 -0
- package/dist/components/hooks/useForm/expressionValidator.utils.d.ts +28 -0
- package/dist/components/hooks/useForm/expressionValidator.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/index.d.ts +6 -0
- package/dist/components/hooks/useForm/index.d.ts.map +1 -0
- package/dist/components/hooks/useForm/optimizedExpressionValidator.utils.d.ts +88 -0
- package/dist/components/hooks/useForm/optimizedExpressionValidator.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/ruleClassifier.utils.d.ts +28 -0
- package/dist/components/hooks/useForm/ruleClassifier.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/schemaParser.utils.d.ts +29 -0
- package/dist/components/hooks/useForm/schemaParser.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/types.d.ts +412 -0
- package/dist/components/hooks/useForm/types.d.ts.map +1 -0
- package/dist/components/hooks/useForm/useForm.d.ts +3 -0
- package/dist/components/hooks/useForm/useForm.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/apiClient.d.ts +99 -0
- package/dist/components/hooks/useKanban/apiClient.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/context.d.ts +4 -0
- package/dist/components/hooks/useKanban/context.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/dragDropManager.d.ts +27 -0
- package/dist/components/hooks/useKanban/dragDropManager.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/index.d.ts +6 -0
- package/dist/components/hooks/useKanban/index.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/types.d.ts +438 -0
- package/dist/components/hooks/useKanban/types.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/useKanban.d.ts +3 -0
- package/dist/components/hooks/useKanban/useKanban.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/useKanbanSimple.d.ts +62 -0
- package/dist/components/hooks/useKanban/useKanbanSimple.d.ts.map +1 -0
- package/dist/components/hooks/useTable/index.d.ts +3 -0
- package/dist/components/hooks/useTable/index.d.ts.map +1 -0
- package/dist/components/hooks/useTable/types.d.ts +107 -0
- package/dist/components/hooks/useTable/types.d.ts.map +1 -0
- package/dist/components/hooks/useTable/useTable.d.ts +8 -0
- package/dist/components/hooks/useTable/useTable.d.ts.map +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/ui/index.d.ts +2 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/kanban/Kanban.d.ts +12 -0
- package/dist/components/ui/kanban/Kanban.d.ts.map +1 -0
- package/dist/components/ui/kanban/index.d.ts +2 -0
- package/dist/components/ui/kanban/index.d.ts.map +1 -0
- package/dist/index.cjs +45 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +6522 -0
- package/dist/types/base-fields.d.ts +182 -0
- package/dist/types/base-fields.d.ts.map +1 -0
- package/dist/types/common.d.ts +238 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/cn.d.ts +7 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/formatting.d.ts +52 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +98 -0
- package/sdk/api/client.ts +447 -0
- package/sdk/api/datetime.ts +33 -0
- package/sdk/api/index.ts +61 -0
- package/sdk/api/metadata.ts +148 -0
- package/sdk/components/hooks/index.ts +34 -0
- package/sdk/components/hooks/useFilter/index.ts +37 -0
- package/sdk/components/hooks/useFilter/payloadBuilder.utils.ts +298 -0
- package/sdk/components/hooks/useFilter/types.ts +158 -0
- package/sdk/components/hooks/useFilter/useFilter.llm.txt +497 -0
- package/sdk/components/hooks/useFilter/useFilter.ts +494 -0
- package/sdk/components/hooks/useFilter/validation.utils.ts +401 -0
- package/sdk/components/hooks/useForm/apiClient.ts +441 -0
- package/sdk/components/hooks/useForm/expressionValidator.utils.ts +444 -0
- package/sdk/components/hooks/useForm/index.ts +64 -0
- package/sdk/components/hooks/useForm/optimizedExpressionValidator.utils.ts +482 -0
- package/sdk/components/hooks/useForm/ruleClassifier.utils.ts +424 -0
- package/sdk/components/hooks/useForm/schemaParser.utils.ts +519 -0
- package/sdk/components/hooks/useForm/types.ts +630 -0
- package/sdk/components/hooks/useForm/useForm.llm.txt +340 -0
- package/sdk/components/hooks/useForm/useForm.ts +821 -0
- package/sdk/components/hooks/useKanban/apiClient.ts +494 -0
- package/sdk/components/hooks/useKanban/context.ts +14 -0
- package/sdk/components/hooks/useKanban/dragDropManager.ts +529 -0
- package/sdk/components/hooks/useKanban/index.ts +63 -0
- package/sdk/components/hooks/useKanban/types.ts +606 -0
- package/sdk/components/hooks/useKanban/useKanban.llm.txt +482 -0
- package/sdk/components/hooks/useKanban/useKanban.ts +725 -0
- package/sdk/components/hooks/useKanban/useKanbanSimple.ts +389 -0
- package/sdk/components/hooks/useTable/index.ts +5 -0
- package/sdk/components/hooks/useTable/types.ts +154 -0
- package/sdk/components/hooks/useTable/useTable.llm.txt +344 -0
- package/sdk/components/hooks/useTable/useTable.ts +413 -0
- package/sdk/components/index.ts +15 -0
- package/sdk/components/ui/index.ts +2 -0
- package/sdk/components/ui/kanban/Kanban.tsx +134 -0
- package/sdk/components/ui/kanban/index.ts +11 -0
- package/sdk/index.ts +13 -0
- package/sdk/types/base-fields.ts +221 -0
- package/sdk/types/common.ts +306 -0
- package/sdk/types/index.ts +5 -0
- package/sdk/utils/cn.ts +10 -0
- package/sdk/utils/formatting.ts +212 -0
- package/sdk/utils/index.ts +5 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# useForm Hook - LLM Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `useForm` hook is a React hook that integrates react-hook-form with backend schemas for building dynamic forms. It provides:
|
|
6
|
+
- Automatic schema fetching from Business Data Objects (BDO)
|
|
7
|
+
- Validation rules from backend schema
|
|
8
|
+
- Computed field support via draft API
|
|
9
|
+
- Cross-field validation
|
|
10
|
+
- Record fetching for update operations
|
|
11
|
+
- Role-based field permissions
|
|
12
|
+
- Type-safe form handling
|
|
13
|
+
|
|
14
|
+
## Import
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { useForm } from "kf-ai-sdk";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Basic Usage
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
const form = useForm<ProductType>({
|
|
24
|
+
source: "BDO_ProductMaster",
|
|
25
|
+
operation: "create", // or "update"
|
|
26
|
+
recordId: selectedProduct?._id, // required for update
|
|
27
|
+
enabled: showForm,
|
|
28
|
+
mode: "onBlur",
|
|
29
|
+
onSuccess: () => {
|
|
30
|
+
setShowForm(false);
|
|
31
|
+
table.refetch();
|
|
32
|
+
},
|
|
33
|
+
onError: (error) => console.error(error),
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Configuration Options
|
|
38
|
+
|
|
39
|
+
### UseFormOptions<T>
|
|
40
|
+
|
|
41
|
+
| Property | Type | Required | Default | Description |
|
|
42
|
+
|----------|------|----------|---------|-------------|
|
|
43
|
+
| `source` | `string` | Yes | - | Data source identifier (BDO name) |
|
|
44
|
+
| `operation` | `"create" \| "update"` | Yes | - | Form operation type |
|
|
45
|
+
| `recordId` | `string` | For update | - | Record ID for update operations |
|
|
46
|
+
| `defaultValues` | `Partial<T>` | No | `{}` | Default form values |
|
|
47
|
+
| `mode` | `FormMode` | No | `"onBlur"` | Validation mode |
|
|
48
|
+
| `enabled` | `boolean` | No | `true` | Enable schema fetching |
|
|
49
|
+
| `userRole` | `string` | No | - | User role for permissions |
|
|
50
|
+
| `onSuccess` | `(data: T) => void` | No | - | Success callback |
|
|
51
|
+
| `onError` | `(error: Error) => void` | No | - | Error callback |
|
|
52
|
+
| `onSchemaError` | `(error: Error) => void` | No | - | Schema load error callback |
|
|
53
|
+
| `onSubmitError` | `(error: Error) => void` | No | - | Submit error callback |
|
|
54
|
+
| `skipSchemaFetch` | `boolean` | No | `false` | Skip schema fetching |
|
|
55
|
+
| `schema` | `BackendSchema \| BDOSchema` | No | - | Manual schema |
|
|
56
|
+
| `draftOnEveryChange` | `boolean` | No | `false` | Trigger draft API on every change |
|
|
57
|
+
|
|
58
|
+
### Validation Modes
|
|
59
|
+
|
|
60
|
+
| Mode | Description |
|
|
61
|
+
|------|-------------|
|
|
62
|
+
| `"onSubmit"` | Validate only when form is submitted |
|
|
63
|
+
| `"onBlur"` | Validate when field loses focus (default) |
|
|
64
|
+
| `"onChange"` | Validate on every keystroke/change |
|
|
65
|
+
| `"onTouched"` | Validate on first blur, then on every change |
|
|
66
|
+
| `"all"` | Validate on both blur and change |
|
|
67
|
+
|
|
68
|
+
**Important:** Computation (draft API calls) ALWAYS fires on blur regardless of mode, but only if the field value is valid.
|
|
69
|
+
|
|
70
|
+
## Return Value
|
|
71
|
+
|
|
72
|
+
### UseFormReturn<T>
|
|
73
|
+
|
|
74
|
+
#### Form Methods
|
|
75
|
+
| Property | Type | Description |
|
|
76
|
+
|----------|------|-------------|
|
|
77
|
+
| `register` | `<K extends Path<T>>(name: K, options?) => ...` | Register field for validation |
|
|
78
|
+
| `handleSubmit` | `() => (e?) => Promise<void>` | Handle form submission |
|
|
79
|
+
| `watch` | `<K extends Path<T>>(name?: K) => ...` | Watch field values |
|
|
80
|
+
| `setValue` | `<K extends Path<T>>(name: K, value, options?) => void` | Set field value programmatically |
|
|
81
|
+
| `reset` | `(values?: T) => void` | Reset form to default values |
|
|
82
|
+
|
|
83
|
+
#### Flattened Form State
|
|
84
|
+
| Property | Type | Description |
|
|
85
|
+
|----------|------|-------------|
|
|
86
|
+
| `errors` | `FieldErrors<T>` | Form validation errors |
|
|
87
|
+
| `isValid` | `boolean` | Form is valid |
|
|
88
|
+
| `isDirty` | `boolean` | Form has been modified |
|
|
89
|
+
| `isSubmitting` | `boolean` | Form is submitting |
|
|
90
|
+
| `isSubmitSuccessful` | `boolean` | Submission was successful |
|
|
91
|
+
| `formState` | `FormState<T>` | Full form state (backward compatibility) |
|
|
92
|
+
|
|
93
|
+
#### Loading States
|
|
94
|
+
| Property | Type | Description |
|
|
95
|
+
|----------|------|-------------|
|
|
96
|
+
| `isLoadingInitialData` | `boolean` | Loading schema/data |
|
|
97
|
+
| `isLoadingRecord` | `boolean` | Loading record for update |
|
|
98
|
+
| `isLoading` | `boolean` | Any loading state active |
|
|
99
|
+
|
|
100
|
+
#### Error Handling
|
|
101
|
+
| Property | Type | Description |
|
|
102
|
+
|----------|------|-------------|
|
|
103
|
+
| `loadError` | `Error \| null` | Schema fetch error |
|
|
104
|
+
| `submitError` | `Error \| null` | Form submission error |
|
|
105
|
+
| `hasError` | `boolean` | Any error active |
|
|
106
|
+
|
|
107
|
+
#### Schema Information
|
|
108
|
+
| Property | Type | Description |
|
|
109
|
+
|----------|------|-------------|
|
|
110
|
+
| `schema` | `BackendSchema \| null` | Raw backend schema |
|
|
111
|
+
| `processedSchema` | `ProcessedSchema \| null` | Processed schema for rendering |
|
|
112
|
+
| `computedFields` | `Array<keyof T>` | Computed field names |
|
|
113
|
+
| `requiredFields` | `Array<keyof T>` | Required field names |
|
|
114
|
+
|
|
115
|
+
#### Field Helpers
|
|
116
|
+
| Property | Type | Description |
|
|
117
|
+
|----------|------|-------------|
|
|
118
|
+
| `getField` | `<K extends keyof T>(fieldName: K) => ProcessedField \| null` | Get field metadata |
|
|
119
|
+
| `getFields` | `() => Record<keyof T, ProcessedField>` | Get all fields |
|
|
120
|
+
| `hasField` | `<K extends keyof T>(fieldName: K) => boolean` | Check if field exists |
|
|
121
|
+
| `isFieldRequired` | `<K extends keyof T>(fieldName: K) => boolean` | Check if required |
|
|
122
|
+
| `isFieldComputed` | `<K extends keyof T>(fieldName: K) => boolean` | Check if computed |
|
|
123
|
+
|
|
124
|
+
#### Operations
|
|
125
|
+
| Property | Type | Description |
|
|
126
|
+
|----------|------|-------------|
|
|
127
|
+
| `submit` | `() => Promise<void>` | Submit form manually |
|
|
128
|
+
| `refreshSchema` | `() => Promise<void>` | Refresh schema |
|
|
129
|
+
| `validateForm` | `() => Promise<boolean>` | Validate form manually |
|
|
130
|
+
| `clearErrors` | `() => void` | Clear all errors |
|
|
131
|
+
|
|
132
|
+
## E-Commerce App Usage Example
|
|
133
|
+
|
|
134
|
+
### Seller Products Page (SellerProductsPage.tsx)
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const [formMode, setFormMode] = useState<"create" | "update">("create");
|
|
138
|
+
const [selectedProduct, setSelectedProduct] = useState<Product | null>(null);
|
|
139
|
+
const [showForm, setShowForm] = useState(false);
|
|
140
|
+
|
|
141
|
+
const form = useForm<SellerProduct>({
|
|
142
|
+
source: "BDO_AmazonProductMaster",
|
|
143
|
+
operation: formMode,
|
|
144
|
+
recordId: selectedProduct?._id,
|
|
145
|
+
enabled: showForm,
|
|
146
|
+
mode: "onBlur",
|
|
147
|
+
draftOnEveryChange: false, // Only trigger draft for computed field dependencies
|
|
148
|
+
onSuccess: () => {
|
|
149
|
+
setShowForm(false);
|
|
150
|
+
setSelectedProduct(null);
|
|
151
|
+
table.refetch();
|
|
152
|
+
},
|
|
153
|
+
onError: (error) => setGeneralError(error.message),
|
|
154
|
+
onSchemaError: (error) => setGeneralError(`Configuration Error: ${error.message}`),
|
|
155
|
+
onSubmitError: (error) => setGeneralError(`Submission Failed: ${error.message}`),
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Form submission
|
|
159
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
160
|
+
e.preventDefault();
|
|
161
|
+
await form.handleSubmit()();
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Form fields
|
|
165
|
+
<form onSubmit={handleSubmit}>
|
|
166
|
+
{/* Text input with register */}
|
|
167
|
+
<Input
|
|
168
|
+
{...form.register("Title")}
|
|
169
|
+
placeholder="Enter product title"
|
|
170
|
+
defaultValue={selectedProduct?.Title || ""}
|
|
171
|
+
className={form.formState.errors.Title ? "border-red-500" : ""}
|
|
172
|
+
/>
|
|
173
|
+
{form.formState.errors.Title && (
|
|
174
|
+
<p className="text-red-600">{form.formState.errors.Title.message}</p>
|
|
175
|
+
)}
|
|
176
|
+
|
|
177
|
+
{/* Number input */}
|
|
178
|
+
<Input
|
|
179
|
+
type="number"
|
|
180
|
+
{...form.register("Price")}
|
|
181
|
+
placeholder="0.00"
|
|
182
|
+
defaultValue={selectedProduct?.Price || ""}
|
|
183
|
+
/>
|
|
184
|
+
|
|
185
|
+
{/* Select with setValue */}
|
|
186
|
+
<Select
|
|
187
|
+
value={form.watch("Category") || ""}
|
|
188
|
+
onValueChange={(value) => form.setValue("Category", value)}
|
|
189
|
+
>
|
|
190
|
+
<SelectTrigger>
|
|
191
|
+
<SelectValue placeholder="Select category" />
|
|
192
|
+
</SelectTrigger>
|
|
193
|
+
<SelectContent>
|
|
194
|
+
{categories.map((cat) => (
|
|
195
|
+
<SelectItem key={cat.Value} value={cat.Value}>
|
|
196
|
+
{cat.Label}
|
|
197
|
+
</SelectItem>
|
|
198
|
+
))}
|
|
199
|
+
</SelectContent>
|
|
200
|
+
</Select>
|
|
201
|
+
|
|
202
|
+
{/* Computed field (read-only) */}
|
|
203
|
+
<Input
|
|
204
|
+
value={(form.watch("Discount") || 0).toFixed(2)}
|
|
205
|
+
readOnly
|
|
206
|
+
disabled
|
|
207
|
+
className="bg-gray-50"
|
|
208
|
+
/>
|
|
209
|
+
<p className="text-xs text-gray-500">
|
|
210
|
+
Auto-calculated from (MRP - Price) / MRP * 100
|
|
211
|
+
</p>
|
|
212
|
+
|
|
213
|
+
{/* Computed boolean indicator */}
|
|
214
|
+
<span className={form.watch("LowStock") ? "text-red-800" : "text-green-800"}>
|
|
215
|
+
{form.watch("LowStock") ? "Low Stock" : "Good Stock"}
|
|
216
|
+
</span>
|
|
217
|
+
|
|
218
|
+
{/* Root/Cross-field errors */}
|
|
219
|
+
{form.formState.errors.root && (
|
|
220
|
+
<div className="bg-red-50 text-red-700">
|
|
221
|
+
{Object.values(form.formState.errors.root).map((err, idx) => (
|
|
222
|
+
<li key={idx}>{err.message}</li>
|
|
223
|
+
))}
|
|
224
|
+
</div>
|
|
225
|
+
)}
|
|
226
|
+
|
|
227
|
+
{/* Submit button */}
|
|
228
|
+
<Button type="submit" disabled={form.isSubmitting}>
|
|
229
|
+
{form.isSubmitting ? "Saving..." : "Save"}
|
|
230
|
+
</Button>
|
|
231
|
+
</form>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Field Types
|
|
235
|
+
|
|
236
|
+
The hook maps backend field types to HTML input types:
|
|
237
|
+
|
|
238
|
+
| Backend Type | HTML Type |
|
|
239
|
+
|--------------|-----------|
|
|
240
|
+
| `String` | `text` |
|
|
241
|
+
| `Number` | `number` |
|
|
242
|
+
| `Boolean` | `checkbox` |
|
|
243
|
+
| `Date` | `date` |
|
|
244
|
+
| `DateTime` | `datetime-local` |
|
|
245
|
+
| `Reference` | `reference` (select) |
|
|
246
|
+
|
|
247
|
+
## Computed Fields
|
|
248
|
+
|
|
249
|
+
Computed fields are automatically calculated by the backend. The hook:
|
|
250
|
+
|
|
251
|
+
1. Detects computed field dependencies from the schema
|
|
252
|
+
2. Watches for changes in dependency fields
|
|
253
|
+
3. Calls draft API on blur (after validation passes)
|
|
254
|
+
4. Updates computed field values from API response
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
// Example: Discount is computed from MRP and Price
|
|
258
|
+
// When Price or MRP changes and blurs, draft API is called
|
|
259
|
+
// Backend returns new Discount value which is auto-applied
|
|
260
|
+
|
|
261
|
+
// Computed fields are read-only
|
|
262
|
+
<Input
|
|
263
|
+
value={form.watch("Discount")}
|
|
264
|
+
readOnly
|
|
265
|
+
disabled
|
|
266
|
+
/>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### draftOnEveryChange Option
|
|
270
|
+
|
|
271
|
+
- `false` (default): Draft API only called when computed field dependencies change
|
|
272
|
+
- `true`: Draft API called for any field change (useful for complex server-side logic)
|
|
273
|
+
|
|
274
|
+
## Validation
|
|
275
|
+
|
|
276
|
+
### Client-side Validation
|
|
277
|
+
|
|
278
|
+
The hook automatically generates validation rules from the schema:
|
|
279
|
+
- Required field validation
|
|
280
|
+
- Type-specific validation (number, date, etc.)
|
|
281
|
+
- Expression-based validation rules
|
|
282
|
+
|
|
283
|
+
### Cross-field Validation
|
|
284
|
+
|
|
285
|
+
Cross-field validation rules are executed on form submission:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
// Cross-field errors appear in form.formState.errors.root
|
|
289
|
+
{form.formState.errors.root && (
|
|
290
|
+
<div className="error">
|
|
291
|
+
{Object.values(form.formState.errors.root).map((err) => (
|
|
292
|
+
<p>{err.message}</p>
|
|
293
|
+
))}
|
|
294
|
+
</div>
|
|
295
|
+
)}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Schema Structure
|
|
299
|
+
|
|
300
|
+
### ProcessedField
|
|
301
|
+
|
|
302
|
+
| Property | Type | Description |
|
|
303
|
+
|----------|------|-------------|
|
|
304
|
+
| `name` | `string` | Field name |
|
|
305
|
+
| `type` | `string` | HTML input type |
|
|
306
|
+
| `label` | `string` | Display label |
|
|
307
|
+
| `required` | `boolean` | Is required |
|
|
308
|
+
| `computed` | `boolean` | Is computed |
|
|
309
|
+
| `defaultValue` | `any` | Default value |
|
|
310
|
+
| `options` | `Array<{value, label}>` | Select options |
|
|
311
|
+
| `description` | `string` | Help text |
|
|
312
|
+
| `permission` | `FieldPermission` | User permissions |
|
|
313
|
+
| `rules` | `object` | Validation/computation rules |
|
|
314
|
+
|
|
315
|
+
### FieldPermission
|
|
316
|
+
|
|
317
|
+
| Property | Type | Description |
|
|
318
|
+
|----------|------|-------------|
|
|
319
|
+
| `editable` | `boolean` | Can user edit |
|
|
320
|
+
| `readable` | `boolean` | Can user see |
|
|
321
|
+
| `hidden` | `boolean` | Is completely hidden |
|
|
322
|
+
|
|
323
|
+
## Key Behaviors
|
|
324
|
+
|
|
325
|
+
1. **Schema caching**: Schemas are cached for 30 minutes
|
|
326
|
+
2. **Record caching**: Records are cached for 5 minutes
|
|
327
|
+
3. **Auto-reset on create**: Form resets after successful create
|
|
328
|
+
4. **Draft API debouncing**: Draft calls are debounced by 300ms
|
|
329
|
+
5. **Computed field exclusion**: Computed fields are excluded from submission
|
|
330
|
+
6. **Type-safe registration**: `register` is fully typed with Path<T>
|
|
331
|
+
7. **Enhanced onBlur**: Custom onBlur triggers validation + computation
|
|
332
|
+
|
|
333
|
+
## Architecture Notes
|
|
334
|
+
|
|
335
|
+
- Built on react-hook-form for form state management
|
|
336
|
+
- Uses TanStack Query for schema and record fetching
|
|
337
|
+
- Expression validator for backend rule evaluation
|
|
338
|
+
- Optimized dependency tracking for computed fields
|
|
339
|
+
- Stable callback refs to prevent infinite loops
|
|
340
|
+
- Full TypeScript generics support
|