@ram_28/kf-ai-sdk 2.0.20-beta.2 → 2.0.21

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.
Files changed (94) hide show
  1. package/README.md +16 -8
  2. package/dist/api.cjs +1 -1
  3. package/dist/api.mjs +1 -1
  4. package/dist/auth/authConfig.d.ts +1 -1
  5. package/dist/auth/types.d.ts +1 -1
  6. package/dist/auth/types.d.ts.map +1 -1
  7. package/dist/auth.cjs +1 -1
  8. package/dist/auth.mjs +1 -1
  9. package/dist/bdo/core/Item.d.ts.map +1 -1
  10. package/dist/bdo.cjs +1 -1
  11. package/dist/bdo.mjs +1 -1
  12. package/dist/components/hooks/useActivityForm/types.d.ts +4 -5
  13. package/dist/components/hooks/useActivityForm/types.d.ts.map +1 -1
  14. package/dist/components/hooks/useActivityForm/useActivityForm.d.ts.map +1 -1
  15. package/dist/components/hooks/useActivityTable/types.d.ts +5 -4
  16. package/dist/components/hooks/useActivityTable/types.d.ts.map +1 -1
  17. package/dist/components/hooks/useActivityTable/useActivityTable.d.ts.map +1 -1
  18. package/dist/components/hooks/useBDOForm/createItemProxy.d.ts +2 -2
  19. package/dist/components/hooks/useBDOForm/createItemProxy.d.ts.map +1 -1
  20. package/dist/components/hooks/useBDOTable/types.d.ts +20 -12
  21. package/dist/components/hooks/useBDOTable/types.d.ts.map +1 -1
  22. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts +2 -2
  23. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts.map +1 -1
  24. package/dist/{constants-ConHc1oS.js → constants-Cyi942Yr.js} +5 -5
  25. package/dist/constants-DEmYwKfC.cjs +1 -0
  26. package/dist/filter.cjs +1 -1
  27. package/dist/filter.mjs +1 -1
  28. package/dist/form.cjs +1 -1
  29. package/dist/form.mjs +1 -1
  30. package/dist/table.cjs +1 -1
  31. package/dist/table.mjs +15 -16
  32. package/dist/table.types.d.ts +1 -1
  33. package/dist/table.types.d.ts.map +1 -1
  34. package/dist/types/constants.d.ts +1 -1
  35. package/dist/workflow/Activity.d.ts +8 -5
  36. package/dist/workflow/Activity.d.ts.map +1 -1
  37. package/dist/workflow.cjs +1 -1
  38. package/dist/workflow.mjs +461 -476
  39. package/docs/README.md +57 -0
  40. package/docs/bdo/README.md +161 -0
  41. package/docs/bdo/api_reference.md +281 -0
  42. package/docs/examples/bdo/create-product.md +69 -0
  43. package/docs/examples/bdo/edit-product-dialog.md +95 -0
  44. package/docs/examples/bdo/filtered-product-table.md +100 -0
  45. package/docs/examples/bdo/product-listing.md +73 -0
  46. package/docs/examples/bdo/supplier-dropdown.md +60 -0
  47. package/docs/examples/fields/complex-fields.md +248 -0
  48. package/docs/examples/fields/primitive-fields.md +217 -0
  49. package/docs/examples/workflow/approve-leave-request.md +76 -0
  50. package/docs/examples/workflow/filtered-activity-table.md +101 -0
  51. package/docs/examples/workflow/my-pending-requests.md +90 -0
  52. package/docs/examples/workflow/start-new-workflow.md +47 -0
  53. package/docs/examples/workflow/submit-leave-request.md +72 -0
  54. package/docs/examples/workflow/workflow-progress.md +49 -0
  55. package/docs/fields/README.md +141 -0
  56. package/docs/fields/api_reference.md +134 -0
  57. package/docs/useActivityForm/README.md +244 -0
  58. package/docs/useActivityForm/api_reference.md +279 -0
  59. package/docs/useActivityTable/README.md +263 -0
  60. package/docs/useActivityTable/api_reference.md +294 -0
  61. package/docs/useBDOForm/README.md +175 -0
  62. package/docs/useBDOForm/api_reference.md +244 -0
  63. package/docs/useBDOTable/README.md +242 -0
  64. package/docs/useBDOTable/api_reference.md +253 -0
  65. package/docs/useFilter/README.md +323 -0
  66. package/docs/useFilter/api_reference.md +228 -0
  67. package/docs/workflow/README.md +158 -0
  68. package/docs/workflow/api_reference.md +161 -0
  69. package/package.json +15 -14
  70. package/sdk/auth/authConfig.ts +1 -1
  71. package/sdk/auth/types.ts +1 -1
  72. package/sdk/bdo/core/Item.ts +2 -1
  73. package/sdk/bdo/expressions/evaluator.ts +8 -4
  74. package/sdk/components/hooks/useActivityForm/types.ts +4 -6
  75. package/sdk/components/hooks/useActivityForm/useActivityForm.ts +10 -73
  76. package/sdk/components/hooks/useActivityTable/types.ts +4 -5
  77. package/sdk/components/hooks/useActivityTable/useActivityTable.ts +10 -8
  78. package/sdk/components/hooks/useBDOForm/createItemProxy.ts +9 -5
  79. package/sdk/components/hooks/useBDOTable/types.ts +20 -10
  80. package/sdk/components/hooks/useBDOTable/useBDOTable.ts +12 -8
  81. package/sdk/table.types.ts +2 -0
  82. package/sdk/types/constants.ts +1 -1
  83. package/sdk/workflow/Activity.ts +39 -7
  84. package/dist/constants-QX2RX-wu.cjs +0 -1
  85. package/docs/api.md +0 -95
  86. package/docs/bdo.md +0 -224
  87. package/docs/gaps.md +0 -360
  88. package/docs/useActivityForm.md +0 -393
  89. package/docs/useActivityTable.md +0 -418
  90. package/docs/useBDOForm.md +0 -498
  91. package/docs/useBDOTable.md +0 -284
  92. package/docs/useFilter.md +0 -188
  93. package/docs/workflow.md +0 -560
  94. /package/docs/{useAuth.md → useAuth/README.md} +0 -0
@@ -0,0 +1,294 @@
1
+ # useActivityTable API Reference
2
+
3
+ ```tsx
4
+ import { useActivityTable, ActivityTableStatus } from "@ram_28/kf-ai-sdk/workflow";
5
+ import type {
6
+ UseActivityTableOptionsType,
7
+ UseActivityTableReturnType,
8
+ ActivityRowType,
9
+ ActivityTableStatusType,
10
+ } from "@ram_28/kf-ai-sdk/workflow";
11
+ import type { ActivityInstanceFieldsType } from "@ram_28/kf-ai-sdk/workflow";
12
+ ```
13
+
14
+ ## Signature
15
+
16
+ ```tsx
17
+ const table: UseActivityTableReturnType<A> = useActivityTable<A>(options: UseActivityTableOptionsType<A>);
18
+ ```
19
+
20
+ ## Options
21
+
22
+ `UseActivityTableOptionsType<A>`
23
+
24
+ - `activity: A`
25
+ - **Required**
26
+ - Activity instance with `getInProgressList()`, `getCompletedList()`, `inProgressCount()`, and `completedCount()` methods. Must be memoized with `useMemo()`.
27
+ - `status: ActivityTableStatusType`
28
+ - **Required**
29
+ - `ActivityTableStatus.InProgress` or `ActivityTableStatus.Completed`. Determines whether in-progress or completed items are fetched.
30
+ - `initialState`
31
+ - **Optional**
32
+ - Object with:
33
+ - `sort?: SortType` — Initial sort configuration. Format: `[{ "fieldName": "ASC" }]`
34
+ - `pagination?: PaginationStateType` — Initial page and page size. Defaults to `{ pageNo: 1, pageSize: 10 }`.
35
+ - `filter?: UseFilterOptionsType<ActivityRowType<A>>` — Initial filter conditions and operator.
36
+ - `onError?: (error: Error) => void`
37
+ - **Optional**
38
+ - Called when fetching items or count fails.
39
+ - `onSuccess?: (data: ActivityRowType<A>[]) => void`
40
+ - **Optional**
41
+ - Called with the current page rows after a successful list fetch.
42
+
43
+ ## Return Value
44
+
45
+ `UseActivityTableReturnType<A>`
46
+
47
+ Alias for `UseTableReturnType<ActivityRowType<A>>`. `ActivityRowType<A>` resolves to `ActivityInstanceType<TEntity & ActivityInstanceFieldsType, TEditable, TReadonly & ActivitySystemReadonlyType>` — inferred from the Activity's `getInProgressList()` return type. Rows are proxy objects with `.get()` accessors, persistence methods, and activity system fields.
48
+
49
+ ### Data
50
+
51
+ - `rows: ActivityInstanceType<...>[]`
52
+ - Array of `ActivityInstanceType` proxy instances for the current page. Access field values via `.get()` (e.g. `row.LeaveType.get()`), not direct property access. Each row also has persistence methods (`update()`, `save()`, `complete()`, `progress()`) and activity system fields (`BPInstanceId`, `Status`, `AssignedTo`, `CompletedAt`). Empty array during initial loading.
53
+ - `totalItems: number`
54
+ - Total number of records matching the current filters and search. `0` while count is loading.
55
+
56
+ ### Loading & Error
57
+
58
+ - `isLoading: boolean`
59
+ - `true` during the initial load of both items and count.
60
+ - `isFetching: boolean`
61
+ - `true` during any fetch including background refetches for items or count.
62
+ - `error: Error | null`
63
+ - Most recent fetch error from either items or count. `null` when no error.
64
+
65
+ ### Search
66
+
67
+ - `search.query: string`
68
+ - Current search input value (updated immediately on `set()`).
69
+ - `search.field: keyof T | null`
70
+ - The field currently being searched. `null` when no search is active.
71
+ - `search.set(field: keyof T, query: string): void`
72
+ - Set the search field and query. The input value updates immediately; the data fetch is debounced by 300 ms. Pagination resets to page 1 after the debounce. Query is capped at 255 characters.
73
+ - `search.clear(): void`
74
+ - Clear the search field and query. Pagination resets to page 1.
75
+
76
+ ### Sort
77
+
78
+ - `sort.field: keyof T | null`
79
+ - Currently sorted field. `null` when no sort is active.
80
+ - `sort.direction: "ASC" | "DESC" | null`
81
+ - Current sort direction. `null` when no sort is active.
82
+ - `sort.toggle(field: keyof T): void`
83
+ - Cycle the sort for a field: ASC -> DESC -> cleared. If a different field was sorted, starts at ASC.
84
+ - `sort.clear(): void`
85
+ - Remove all sorting.
86
+ - `sort.set(field: keyof T | null, direction: "ASC" | "DESC" | null): void`
87
+ - Explicitly set the sort field and direction.
88
+
89
+ ### Filter
90
+
91
+ - `filter: UseFilterReturnType<T>`
92
+ - Full filter state and operations. See [useFilter reference](../useFilter/api_reference.md) for the complete API.
93
+
94
+ ### Pagination
95
+
96
+ - `pagination.pageNo: number`
97
+ - Current page number (1-indexed).
98
+ - `pagination.pageSize: number`
99
+ - Current number of items per page.
100
+ - `pagination.totalPages: number`
101
+ - Total number of pages based on `totalItems` and `pageSize`.
102
+ - `pagination.totalItems: number`
103
+ - Same as the top-level `totalItems`.
104
+ - `pagination.canGoNext: boolean`
105
+ - `true` when a next page exists.
106
+ - `pagination.canGoPrevious: boolean`
107
+ - `true` when a previous page exists (i.e. `pageNo > 1`).
108
+ - `pagination.goToNext(): void`
109
+ - Navigate to the next page. No-op if already on the last page.
110
+ - `pagination.goToPrevious(): void`
111
+ - Navigate to the previous page. No-op if already on page 1.
112
+ - `pagination.goToPage(page: number): void`
113
+ - Navigate to a specific page. Clamped to `[1, totalPages]`.
114
+ - `pagination.setPageSize(size: number): void`
115
+ - Change the page size. Resets to page 1.
116
+
117
+ ### Operations
118
+
119
+ - `refetch(): Promise<ListResponseType<T>>`
120
+ - Manually refetch both the items and the count. Returns the list response.
121
+
122
+ ## Exported Constants
123
+
124
+ Available from `@ram_28/kf-ai-sdk/workflow`:
125
+
126
+ ```typescript
127
+ import { ActivityTableStatus } from "@ram_28/kf-ai-sdk/workflow";
128
+ ```
129
+
130
+ **ActivityTableStatus**
131
+
132
+ | Key | Value | Description |
133
+ |-----|-------|-------------|
134
+ | `InProgress` | `"inprogress"` | Fetches the in-progress items of the current activity |
135
+ | `Completed` | `"completed"` | Fetches the completed items of the current activity |
136
+
137
+ **SortDirection** (from `@ram_28/kf-ai-sdk/table`)
138
+
139
+ | Key | Value |
140
+ |-----|-------|
141
+ | `ASC` | `"ASC"` |
142
+ | `DESC` | `"DESC"` |
143
+
144
+ **TableDefaults** (from `@ram_28/kf-ai-sdk/table`)
145
+
146
+ | Key | Value | Description |
147
+ |-----|-------|-------------|
148
+ | `SEARCH_DEBOUNCE_MS` | `300` | Debounce delay for search (ms) |
149
+ | `PAGE_SIZE` | `10` | Default items per page |
150
+ | `PAGE` | `1` | Default page number (1-indexed) |
151
+ | `SEARCH_MAX_LENGTH` | `255` | Maximum search query length |
152
+
153
+ For filter constants (`ConditionOperator`, `GroupOperator`, `RHSType`), see [useFilter reference](../useFilter/api_reference.md).
154
+
155
+ ## Types
156
+
157
+ ```typescript
158
+ import type { ActivityInstanceType } from "@ram_28/kf-ai-sdk/workflow";
159
+
160
+ // ============================================================
161
+ // Options
162
+ // ============================================================
163
+
164
+ interface UseActivityTableOptionsType<A extends Activity<any, any, any>> {
165
+ activity: A;
166
+ status: ActivityTableStatusType;
167
+ initialState?: {
168
+ sort?: SortType;
169
+ pagination?: PaginationStateType;
170
+ filter?: UseFilterOptionsType<ActivityRowType<A>>;
171
+ };
172
+ onError?: (error: Error) => void;
173
+ onSuccess?: (data: ActivityRowType<A>[]) => void;
174
+ }
175
+
176
+ // ============================================================
177
+ // Return type
178
+ // ============================================================
179
+
180
+ type UseActivityTableReturnType<A extends Activity<any, any, any>> =
181
+ UseTableReturnType<ActivityRowType<A>>;
182
+
183
+ // ActivityRowType resolves to ActivityInstanceType<...>
184
+ // ActivityInstanceType<TEntity, TEditable, TReadonly> provides:
185
+ // row._id: string (direct access, no .get())
186
+ // row.Field.get(): value (read field value)
187
+ // row.Field.set(value): void (editable fields only)
188
+ // row.Field.validate(): ValidationResultType (single field)
189
+ // row.Field.label / .required / .readOnly / .defaultValue / .meta
190
+ // row.toJSON(): plain object
191
+ // row.validate(): ValidationResultType (all fields)
192
+ // row.update(data): Promise (persist changes)
193
+ // row.save(data): Promise (commit draft)
194
+ // row.complete(): Promise (complete activity)
195
+ // row.progress(): Promise (get workflow progress)
196
+
197
+ interface UseTableReturnType<T> {
198
+ // Data
199
+ rows: T[];
200
+ totalItems: number;
201
+
202
+ // Loading States
203
+ isLoading: boolean;
204
+ isFetching: boolean;
205
+
206
+ // Error Handling
207
+ error: Error | null;
208
+
209
+ // Search
210
+ search: {
211
+ query: string;
212
+ field: keyof T | null;
213
+ set: (field: keyof T, query: string) => void;
214
+ clear: () => void;
215
+ };
216
+
217
+ // Sorting
218
+ sort: {
219
+ field: keyof T | null;
220
+ direction: "ASC" | "DESC" | null;
221
+ toggle: (field: keyof T) => void;
222
+ clear: () => void;
223
+ set: (field: keyof T | null, direction: "ASC" | "DESC" | null) => void;
224
+ };
225
+
226
+ // Filter
227
+ filter: UseFilterReturnType<T>;
228
+
229
+ // Pagination
230
+ pagination: {
231
+ pageNo: number;
232
+ pageSize: number;
233
+ totalPages: number;
234
+ totalItems: number;
235
+ canGoNext: boolean;
236
+ canGoPrevious: boolean;
237
+ goToNext: () => void;
238
+ goToPrevious: () => void;
239
+ goToPage: (page: number) => void;
240
+ setPageSize: (size: number) => void;
241
+ };
242
+
243
+ // Operations
244
+ refetch: () => Promise<ListResponseType<T>>;
245
+ }
246
+
247
+ // ============================================================
248
+ // Status
249
+ // ============================================================
250
+
251
+ const ActivityTableStatus = {
252
+ InProgress: "inprogress",
253
+ Completed: "completed",
254
+ } as const;
255
+
256
+ type ActivityTableStatusType =
257
+ (typeof ActivityTableStatus)[keyof typeof ActivityTableStatus];
258
+ // resolves to: "inprogress" | "completed"
259
+
260
+ // ============================================================
261
+ // Row type inference
262
+ // ============================================================
263
+
264
+ type ActivityRowType<A extends Activity<any, any, any>> =
265
+ A extends { getInProgressList(opts?: any): Promise<(infer R)[]> }
266
+ ? R
267
+ : never;
268
+
269
+ // ============================================================
270
+ // Activity system fields
271
+ // ============================================================
272
+
273
+ type ActivityInstanceFieldsType = {
274
+ _id: string;
275
+ BPInstanceId: string;
276
+ Status: "InProgress" | "Completed";
277
+ AssignedTo: Array<{ _id: string; _name: string }>;
278
+ CompletedAt: string; // ISO 8601 datetime
279
+ };
280
+
281
+ // ============================================================
282
+ // State types
283
+ // ============================================================
284
+
285
+ interface PaginationStateType {
286
+ pageNo: number;
287
+ pageSize: number;
288
+ }
289
+
290
+ type SortOptionType = Record<string, "ASC" | "DESC">;
291
+ type SortType = SortOptionType[];
292
+
293
+ // Filter types — see useFilter reference (../useFilter/api_reference.md)
294
+ ```
@@ -0,0 +1,175 @@
1
+ # useBDOForm
2
+
3
+ BDO-integrated form hook that wraps React Hook Form with automatic schema fetching, validation, per-field sync, and API submission.
4
+
5
+ ## When to Use
6
+
7
+ **Use `useBDOForm` when:**
8
+
9
+ - Building create or edit forms backed by a BDO (Business Data Object)
10
+ - You want automatic validation without manual rules
11
+ - You want `handleSubmit` to call the API automatically (no manual `bdo.create()` / `bdo.update()`)
12
+
13
+ **Use something else when:**
14
+
15
+ - Building a workflow/activity form — use [`useActivityForm`](../useActivityForm/README.md) instead
16
+ - Building a filter or search form — use [`useFilter`](../useFilter/README.md) instead
17
+
18
+ ## Imports
19
+
20
+ ```tsx
21
+ import { useBDOForm } from "@ram_28/kf-ai-sdk/form";
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```tsx
27
+ import { useMemo } from "react";
28
+ import { useBDOForm } from "@ram_28/kf-ai-sdk/form";
29
+ import { SellerProduct } from "@/bdo/seller/Product";
30
+
31
+ function CreateProductForm({ id }: { id?: string }) {
32
+ const product = useMemo(() => new SellerProduct(), []);
33
+
34
+ const { register, handleSubmit, errors, isLoading, isSubmitting } =
35
+ useBDOForm({ bdo: product, recordId: id });
36
+
37
+ if (isLoading) return <p>Loading...</p>;
38
+
39
+ return (
40
+ <form onSubmit={handleSubmit((data) => console.log("Saved", data._id))}>
41
+ <label>{product.Title.label}</label>
42
+ <input {...register(product.Title.id)} />
43
+ {errors.Title && <p>{errors.Title.message}</p>}
44
+
45
+ <label>{product.Price.label}</label>
46
+ <input type="number" step="0.01" {...register(product.Price.id)} />
47
+ {errors.Price && <p>{errors.Price.message}</p>}
48
+
49
+ <button type="submit" disabled={isSubmitting}>
50
+ {isSubmitting ? "Saving..." : "Save"}
51
+ </button>
52
+ </form>
53
+ );
54
+ }
55
+ ```
56
+
57
+ ## Usage Guide
58
+
59
+ ### Create Mode
60
+
61
+ When no `recordId` is passed (or it's `undefined`), the hook enters create mode. A draft is allocated on mount to get an `_id`.
62
+
63
+ ```tsx
64
+ useBDOForm({ bdo: product });
65
+ ```
66
+
67
+ ### Update Mode
68
+
69
+ When `recordId` is a string, the hook enters update mode. The record is fetched and the form is populated.
70
+
71
+ ```tsx
72
+ useBDOForm({ bdo: product, recordId: id });
73
+ ```
74
+
75
+ ### Registering Fields
76
+
77
+ Use the BDO instance's field to get the field ID, label, and metadata — never hardcode field names as strings.
78
+
79
+ ```tsx
80
+ <label>{product.Title.label} {product.Title.required && <span>*</span>}</label>
81
+ <input {...register(product.Title.id)} />
82
+ {errors.Title && <p>{errors.Title.message}</p>}
83
+ ```
84
+
85
+ For **select, reference, boolean, and other custom components** that don't fire native change events, use `watch()` + `setValue()` instead of `register()` (see [Fields — Selection & Reference](../fields/README.md#selection--reference-fields) for full patterns):
86
+
87
+ ```tsx
88
+ <Select
89
+ value={watch(product.Category.id) ?? ""}
90
+ onValueChange={(v) => setValue(product.Category.id, v)}
91
+ >
92
+ ...
93
+ </Select>
94
+ ```
95
+
96
+ Readonly fields are auto-disabled by `register()` — no manual disable needed.
97
+
98
+ ### Validation
99
+
100
+ Validation happens automatically. The hook validates field types, constraints (required, length, integerPart/fractionPart), and backend expression rules — all without any manual configuration.
101
+
102
+ Errors appear in `errors.FieldName.message`:
103
+
104
+ ```tsx
105
+ {errors.Title && <p>{errors.Title.message}</p>}
106
+ ```
107
+
108
+ ### Handling Submit
109
+
110
+ Pass `handleSubmit` to your form's `onSubmit`. It validates, filters the payload, calls the API, and invokes your callbacks:
111
+
112
+ ```tsx
113
+ <form onSubmit={handleSubmit(onSuccess, onError)}>
114
+ ```
115
+
116
+ - **`onSuccess(data)`** — Called with `{ _id: string }` after a successful create or update.
117
+ - **`onError(error)`** — Called with `FieldErrors` (validation failure) or `Error` (API failure).
118
+
119
+ > **Don't** call `bdo.create()` or `bdo.update()` manually — `handleSubmit` does it for you.
120
+
121
+ ### Working with `item`
122
+
123
+ `item` represents the current record instance. Each field on `item` is an accessor with methods to read, write, and validate that field's value.
124
+
125
+ **Instance-level members:**
126
+
127
+ ```tsx
128
+ const { item } = useBDOForm({ bdo: product });
129
+
130
+ item._id; // current record ID
131
+ item.toJSON(); // all form values as plain object
132
+ await item.validate(); // trigger validation for all fields
133
+ ```
134
+
135
+ **Field-level accessors** (`item.FieldName`):
136
+
137
+ ```tsx
138
+ // Read/write
139
+ item.Title.get(); // current value
140
+ item.Price.getOrDefault(0); // value or fallback
141
+ item.Title.set("New Title"); // update value
142
+
143
+ // Validate
144
+ item.Title.validate(); // { valid: boolean, errors: string[] }
145
+
146
+ // Metadata
147
+ item.Title.label; // display label
148
+ item.Title.required; // is required?
149
+ item.Title.readOnly; // is readonly?
150
+ ```
151
+
152
+ **When to use `item` vs `register`/`watch`/`setValue`:**
153
+
154
+ - Use `register()` for standard HTML inputs (text, number, date)
155
+ - Use `watch()` + `setValue()` for custom components (select, checkbox, reference)
156
+ - Use `item.Field.get()` / `item.Field.set()` for programmatic read/write (event handlers, computed logic)
157
+
158
+ ## Further Reading
159
+
160
+ - [API Reference](./api_reference.md) — All options, return values, and type definitions
161
+ - [Fields](../fields/README.md) — All 13 field classes, constraint getters, and attachment methods
162
+ - [Create Product](../examples/bdo/create-product.md) — Create form with validation and select fields
163
+ - [Edit Product Dialog](../examples/bdo/edit-product-dialog.md) — Table + edit dialog + refetch
164
+ - [Supplier Dropdown](../examples/bdo/supplier-dropdown.md) — Lazy-loaded reference field options
165
+ - [Primitive Fields](../examples/fields/primitive-fields.md) — Form with String, Number, Boolean, Date, DateTime, Text
166
+ - [Complex Fields](../examples/fields/complex-fields.md) — Form with Select, Reference, User, File, Image
167
+
168
+ ## Common Mistakes
169
+
170
+ - **Don't forget `useMemo` on the BDO.** `new BdoClass()` must be wrapped in `useMemo(() => ..., [])`. Re-creating the instance on every render breaks the hook.
171
+ - **Don't set date `defaultValues` to empty string.** Use `undefined` instead. Empty strings cause type validation errors for Date and DateTime fields.
172
+ - **Don't mix `register()` and `watch()`+`setValue()` for the same field.** Pick one approach per field. `register()` for native inputs, `watch()`+`setValue()` for custom components.
173
+ - **Don't use `register()` for select, checkbox, or reference components.** They don't fire native change events. Use `watch()` + `setValue()`.
174
+ - **Don't call `bdo.create()` or `bdo.update()` manually.** `handleSubmit` handles the API call. Calling them yourself will double-submit.
175
+ - **Don't render the form before `isLoading` is false.** In create mode, the draft is being allocated. In update mode, the record is being fetched. Guard with `if (isLoading) return <Loading />`.