@ram_28/kf-ai-sdk 2.0.16 → 2.0.17

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 (84) 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.cjs +1 -1
  10. package/dist/bdo.mjs +1 -1
  11. package/dist/components/hooks/useActivityForm/types.d.ts +4 -5
  12. package/dist/components/hooks/useActivityForm/types.d.ts.map +1 -1
  13. package/dist/components/hooks/useActivityForm/useActivityForm.d.ts.map +1 -1
  14. package/dist/components/hooks/useActivityTable/types.d.ts +5 -4
  15. package/dist/components/hooks/useActivityTable/types.d.ts.map +1 -1
  16. package/dist/components/hooks/useActivityTable/useActivityTable.d.ts.map +1 -1
  17. package/dist/components/hooks/useBDOTable/types.d.ts +20 -12
  18. package/dist/components/hooks/useBDOTable/types.d.ts.map +1 -1
  19. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts +2 -2
  20. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts.map +1 -1
  21. package/dist/{constants-ConHc1oS.js → constants-Cyi942Yr.js} +5 -5
  22. package/dist/constants-DEmYwKfC.cjs +1 -0
  23. package/dist/filter.cjs +1 -1
  24. package/dist/filter.mjs +1 -1
  25. package/dist/form.cjs +1 -1
  26. package/dist/form.mjs +1 -1
  27. package/dist/table.cjs +1 -1
  28. package/dist/table.mjs +15 -16
  29. package/dist/table.types.d.ts +1 -1
  30. package/dist/table.types.d.ts.map +1 -1
  31. package/dist/types/constants.d.ts +1 -1
  32. package/dist/workflow/Activity.d.ts +8 -5
  33. package/dist/workflow/Activity.d.ts.map +1 -1
  34. package/dist/workflow.cjs +1 -1
  35. package/dist/workflow.mjs +461 -476
  36. package/docs/README.md +51 -0
  37. package/docs/bdo/README.md +161 -0
  38. package/docs/bdo/api_reference.md +281 -0
  39. package/docs/examples/bdo/create-product.md +69 -0
  40. package/docs/examples/bdo/edit-product-dialog.md +95 -0
  41. package/docs/examples/bdo/filtered-product-table.md +100 -0
  42. package/docs/examples/bdo/product-listing.md +73 -0
  43. package/docs/examples/bdo/supplier-dropdown.md +60 -0
  44. package/docs/examples/workflow/approve-leave-request.md +76 -0
  45. package/docs/examples/workflow/filtered-activity-table.md +101 -0
  46. package/docs/examples/workflow/my-pending-requests.md +90 -0
  47. package/docs/examples/workflow/start-new-workflow.md +47 -0
  48. package/docs/examples/workflow/submit-leave-request.md +72 -0
  49. package/docs/examples/workflow/workflow-progress.md +49 -0
  50. package/docs/useActivityForm/README.md +241 -0
  51. package/docs/useActivityForm/api_reference.md +279 -0
  52. package/docs/useActivityTable/README.md +263 -0
  53. package/docs/useActivityTable/api_reference.md +294 -0
  54. package/docs/useBDOForm/README.md +172 -0
  55. package/docs/useBDOForm/api_reference.md +244 -0
  56. package/docs/useBDOTable/README.md +242 -0
  57. package/docs/useBDOTable/api_reference.md +253 -0
  58. package/docs/useFilter/README.md +323 -0
  59. package/docs/useFilter/api_reference.md +228 -0
  60. package/docs/workflow/README.md +158 -0
  61. package/docs/workflow/api_reference.md +161 -0
  62. package/package.json +1 -1
  63. package/sdk/auth/authConfig.ts +1 -1
  64. package/sdk/auth/types.ts +1 -1
  65. package/sdk/components/hooks/useActivityForm/types.ts +4 -6
  66. package/sdk/components/hooks/useActivityForm/useActivityForm.ts +10 -73
  67. package/sdk/components/hooks/useActivityTable/types.ts +4 -5
  68. package/sdk/components/hooks/useActivityTable/useActivityTable.ts +10 -8
  69. package/sdk/components/hooks/useBDOTable/types.ts +20 -10
  70. package/sdk/components/hooks/useBDOTable/useBDOTable.ts +12 -8
  71. package/sdk/table.types.ts +2 -0
  72. package/sdk/types/constants.ts +1 -1
  73. package/sdk/workflow/Activity.ts +39 -7
  74. package/dist/constants-QX2RX-wu.cjs +0 -1
  75. package/docs/api.md +0 -95
  76. package/docs/bdo.md +0 -224
  77. package/docs/gaps.md +0 -360
  78. package/docs/useActivityForm.md +0 -393
  79. package/docs/useActivityTable.md +0 -418
  80. package/docs/useBDOForm.md +0 -376
  81. package/docs/useBDOTable.md +0 -284
  82. package/docs/useFilter.md +0 -188
  83. package/docs/workflow.md +0 -560
  84. /package/docs/{useAuth.md → useAuth/README.md} +0 -0
@@ -0,0 +1,241 @@
1
+ # useActivityForm
2
+
3
+ Form hook for workflow activities with automatic per-field sync and a single `handleSubmit` to complete the activity and advance the workflow.
4
+
5
+ ## When to Use
6
+
7
+ **Use `useActivityForm` when:**
8
+
9
+ - Building a form for a workflow activity (employee leave request, manager approval, etc.)
10
+ - You need `handleSubmit` to complete the activity and advance the workflow
11
+ - Fields from prior activities should appear as readonly context
12
+
13
+ **Use something else when:**
14
+
15
+ - Building a BDO record form — use [`useBDOForm`](../useBDOForm/README.md) instead
16
+ - Listing activity instances in a table — use [`useActivityTable`](../useActivityTable/README.md) instead
17
+
18
+ ## Imports
19
+
20
+ ```tsx
21
+ import { useActivityForm } from "@ram_28/kf-ai-sdk/workflow";
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```tsx
27
+ import { useMemo } from "react";
28
+ import { useActivityForm } from "@ram_28/kf-ai-sdk/workflow";
29
+ import { EmployeeInputActivity } from "@/workflow/leave";
30
+
31
+ function LeaveRequestForm({ instanceId }: { instanceId: string }) {
32
+ const activity = useMemo(() => new EmployeeInputActivity(), []);
33
+
34
+ const { register, handleSubmit, errors, isLoading, isSubmitting } =
35
+ useActivityForm(activity, { activity_instance_id: instanceId });
36
+
37
+ if (isLoading) return <p>Loading...</p>;
38
+
39
+ return (
40
+ <form>
41
+ <label>{activity.StartDate.label}</label>
42
+ <input type="date" {...register(activity.StartDate.id)} />
43
+ {errors.StartDate && <p>{errors.StartDate.message}</p>}
44
+
45
+ <label>{activity.EndDate.label}</label>
46
+ <input type="date" {...register(activity.EndDate.id)} />
47
+ {errors.EndDate && <p>{errors.EndDate.message}</p>}
48
+
49
+ <button type="button" disabled={isSubmitting}
50
+ onClick={handleSubmit(() => {}, console.error)}>
51
+ Submit Request
52
+ </button>
53
+ </form>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ## Usage Guide
59
+
60
+ ### Registering Fields
61
+
62
+ Use the Activity instance's field to get the field ID, label, and metadata — never hardcode field names as strings.
63
+
64
+ ```tsx
65
+ <label>{activity.StartDate.label} {activity.StartDate.required && <span>*</span>}</label>
66
+ <input type="date" {...register(activity.StartDate.id)} />
67
+ {errors.StartDate && <p>{errors.StartDate.message}</p>}
68
+ ```
69
+
70
+ For **select, reference, boolean, and other custom components** that don't fire native change events, use `watch()` + `setValue()` instead of `register()`:
71
+
72
+ ```tsx
73
+ <Select
74
+ value={watch(activity.LeaveType.id) ?? ""}
75
+ onValueChange={(v) => setValue(activity.LeaveType.id, v)}
76
+ >
77
+ <SelectTrigger>
78
+ <SelectValue placeholder="Select leave type" />
79
+ </SelectTrigger>
80
+ <SelectContent>
81
+ {activity.LeaveType.options.map((opt) => (
82
+ <SelectItem key={opt.value} value={opt.value}>
83
+ {opt.label}
84
+ </SelectItem>
85
+ ))}
86
+ </SelectContent>
87
+ </Select>
88
+ ```
89
+
90
+ Readonly fields are auto-disabled by `register()` — no manual disable needed.
91
+
92
+ ### Context-Derived Readonly Fields
93
+
94
+ When a workflow has multiple activities, fields from prior activities appear as readonly context. The hook discovers them automatically from BP metadata, and `register()` returns `{ disabled: true }` for them.
95
+
96
+ In a manager approval form, the employee's StartDate, EndDate, LeaveType, and LeaveDays are readonly context, while ManagerApproved and ManagerReason are editable:
97
+
98
+ ```tsx
99
+ import { useMemo } from "react";
100
+ import { useActivityForm } from "@ram_28/kf-ai-sdk/workflow";
101
+ import { ManagerApprovalActivity } from "@/workflow/leave";
102
+
103
+ function ManagerApprovalForm({ instanceId }: { instanceId: string }) {
104
+ const activity = useMemo(() => new ManagerApprovalActivity(), []);
105
+
106
+ const { register, handleSubmit, errors, isLoading, isSubmitting, watch, setValue } =
107
+ useActivityForm(activity, { activity_instance_id: instanceId });
108
+
109
+ if (isLoading) return <p>Loading...</p>;
110
+
111
+ return (
112
+ <div>
113
+ {/* Readonly context from employee's activity — auto-disabled */}
114
+ <label>{activity.StartDate.label}</label>
115
+ <input type="date" {...register(activity.StartDate.id)} className="bg-gray-100" />
116
+
117
+ <label>{activity.EndDate.label}</label>
118
+ <input type="date" {...register(activity.EndDate.id)} className="bg-gray-100" />
119
+
120
+ <label>{activity.LeaveDays.label}</label>
121
+ <input type="number" {...register(activity.LeaveDays.id)} className="bg-gray-100" />
122
+
123
+ {/* Editable manager decision fields */}
124
+ <div>
125
+ <input
126
+ type="checkbox"
127
+ checked={watch(activity.ManagerApproved.id) ?? false}
128
+ onChange={(e) => setValue(activity.ManagerApproved.id, e.target.checked)}
129
+ />
130
+ <label>
131
+ {activity.ManagerApproved.label}
132
+ {activity.ManagerApproved.required && <span> *</span>}
133
+ </label>
134
+ {errors.ManagerApproved && <p>{errors.ManagerApproved.message}</p>}
135
+ </div>
136
+
137
+ <label>{activity.ManagerReason.label}</label>
138
+ <textarea {...register(activity.ManagerReason.id)} rows={3} />
139
+ {errors.ManagerReason && <p>{errors.ManagerReason.message}</p>}
140
+
141
+ <button type="button" disabled={isSubmitting}
142
+ onClick={handleSubmit(() => {}, console.error)}>
143
+ Complete Review
144
+ </button>
145
+ </div>
146
+ );
147
+ }
148
+ ```
149
+
150
+ ### Validation
151
+
152
+ Validation happens automatically. The hook validates field types, constraints (required, length, integerPart/fractionPart), and backend expression rules — all without any manual configuration.
153
+
154
+ Errors appear in `errors.FieldName.message`:
155
+
156
+ ```tsx
157
+ {errors.StartDate && <p>{errors.StartDate.message}</p>}
158
+ ```
159
+
160
+ ### Handling Submit
161
+
162
+ Per-field sync automatically saves changes on blur/change via `activity.update()`, so there's no need for a manual save button. When the user is ready, `handleSubmit` validates the form, sends any remaining dirty fields, then completes the activity to advance the workflow.
163
+
164
+ `handleSubmit` is curried: `(onSuccess?, onError?) => (event?) => Promise<void>`.
165
+
166
+ - **`onSuccess(result)`** — Called with `CreateUpdateResponseType` (`{ _id: string }`) after the activity is completed.
167
+ - **`onError(error)`** — Called with `FieldErrors` (validation failure) or `Error` (API failure).
168
+
169
+ ```tsx
170
+ <button type="button" disabled={isSubmitting}
171
+ onClick={handleSubmit(() => { toast.success("Submitted"); onClose(); }, console.error)}>
172
+ Submit Request
173
+ </button>
174
+ ```
175
+
176
+ To validate before showing a confirmation dialog, use `trigger()`:
177
+
178
+ ```tsx
179
+ const handleSubmitWithConfirm = async () => {
180
+ const valid = await trigger();
181
+ if (!valid) return;
182
+ // Show confirmation UI, then invoke:
183
+ handleSubmit(onSuccess, onError)(); // note the double invocation — curried
184
+ };
185
+ ```
186
+
187
+ > **Don't** call `activity.update()` or `activity.complete()` manually — `handleSubmit` does it for you.
188
+
189
+ ### Working with `item`
190
+
191
+ `item` represents the current activity instance. Each field on `item` is an accessor with methods to read, write, and validate that field's value.
192
+
193
+ **Instance-level members:**
194
+
195
+ ```tsx
196
+ const { item } = useActivityForm(activity, { activity_instance_id: instanceId });
197
+
198
+ item._id; // current activity instance ID
199
+ item.toJSON(); // all form values as plain object
200
+ await item.validate(); // trigger validation for all fields
201
+ ```
202
+
203
+ **Field-level accessors** (`item.FieldName`):
204
+
205
+ ```tsx
206
+ // Read/write
207
+ item.StartDate.get(); // current value
208
+ item.LeaveDays.getOrDefault(0); // value or fallback
209
+ item.StartDate.set("2026-03-01"); // update value
210
+
211
+ // Validate
212
+ item.StartDate.validate(); // { valid: boolean, errors: string[] }
213
+
214
+ // Metadata
215
+ item.StartDate.label; // display label
216
+ item.StartDate.required; // is required?
217
+ item.StartDate.readOnly; // is readonly?
218
+ ```
219
+
220
+ **When to use `item` vs `register`/`watch`/`setValue`:**
221
+
222
+ - Use `register()` for standard HTML inputs (text, number, date)
223
+ - Use `watch()` + `setValue()` for custom components (select, checkbox, reference)
224
+ - Use `item.Field.get()` / `item.Field.set()` for programmatic read/write (event handlers, computed logic)
225
+
226
+ ## Further Reading
227
+
228
+ - [API Reference](./api_reference.md) — All options, return values, and type definitions
229
+ - [Submit Leave Request](../examples/workflow/submit-leave-request.md) — Employee form submission
230
+ - [Approve Leave Request](../examples/workflow/approve-leave-request.md) — Manager approval with readonly context
231
+ - [Start New Workflow](../examples/workflow/start-new-workflow.md) — `workflow.start()` flow
232
+
233
+ ## Common Mistakes
234
+
235
+ - **Don't forget `useMemo` on the Activity.** `new ActivityClass()` must be wrapped in `useMemo(() => ..., [])`. Re-creating the instance on every render breaks the hook.
236
+ - **Don't create a manual save button.** Per-field sync handles auto-saving on blur/change. `handleSubmit` is for completing the activity, not saving drafts.
237
+ - **Don't set date `defaultValues` to empty string.** Use `undefined` instead. Empty strings cause type validation errors for Date and DateTime fields.
238
+ - **Don't use `register()` for select, checkbox, or reference components.** They don't fire native change events. Use `watch()` + `setValue()`.
239
+ - **Don't call `activity.update()` or `activity.complete()` manually.** `handleSubmit` handles the API calls. Calling them yourself will double-submit.
240
+ - **Don't render the form before `isLoading` is false.** The activity data and metadata are being fetched. Guard with `if (isLoading) return <Loading />`.
241
+ - **Don't forget `activity_instance_id` is required.** This is the activity instance ID (from `workflow.start()` or `getInProgressList()`), not a BDO record ID.
@@ -0,0 +1,279 @@
1
+ # useActivityForm API Reference
2
+
3
+ ```tsx
4
+ import { useActivityForm } from "@ram_28/kf-ai-sdk/workflow";
5
+ import type {
6
+ UseActivityFormOptions,
7
+ UseActivityFormReturn,
8
+ } from "@ram_28/kf-ai-sdk/workflow";
9
+ ```
10
+
11
+ ## Signature
12
+
13
+ ```tsx
14
+ const form: UseActivityFormReturn<EmployeeInputActivity> = useActivityForm(
15
+ activity: EmployeeInputActivity,
16
+ options: UseActivityFormOptions<EmployeeInputActivity>,
17
+ );
18
+ ```
19
+
20
+ First argument is the Activity instance (positional). Second argument is the options object.
21
+
22
+ ## Options
23
+
24
+ `UseActivityFormOptions<A>`
25
+
26
+ - `activity_instance_id: string`
27
+ - **Required**
28
+ - Activity instance ID. From `workflow.start()` response or `getInProgressList()` rows.
29
+ - `defaultValues?: Partial<ExtractActivityEditable<A>>`
30
+ - **Optional** · Defaults to `{}`
31
+ - Initial form values before server data loads. Server data wins on merge.
32
+ - `mode?: "onBlur" | "onChange" | "onSubmit" | "onTouched" | "all"`
33
+ - **Optional** · Defaults to `"onBlur"`
34
+ - RHF validation mode. Also controls when per-field server sync fires.
35
+ - `enabled?: boolean`
36
+ - **Optional** · Defaults to `true`
37
+ - Set `false` to defer `activity.read()` until the instance ID is available.
38
+
39
+ ## Return Value
40
+
41
+ `UseActivityFormReturn<A>`
42
+
43
+ ### Instance
44
+
45
+ - `item: FormItemType<TEditable, TReadonly>`
46
+ - The current activity instance. Each field is an accessor with methods to read, write, and validate. See [Instance and Field Accessors](#instance-and-field-accessors).
47
+ - `activity: A`
48
+ - The Activity instance passed to the hook.
49
+
50
+ ### Form Methods
51
+
52
+ - `register: FormRegisterType<TEditable, TReadonly>`
53
+ - Registers an input field. Auto-disables readonly fields (`{ disabled: true }`).
54
+ - `handleSubmit: HandleSubmitType<CreateUpdateResponseType>`
55
+ - Validates, updates any remaining dirty fields, then completes the activity. See [handleSubmit](#handlesubmit).
56
+ - `watch: UseFormWatch<AllActivityFields<A>>`
57
+ - Standard RHF `watch`. Typed to all fields (editable + readonly).
58
+ - `setValue: UseFormSetValue<ExtractActivityEditable<A>>`
59
+ - Standard RHF `setValue`. Typed to editable fields only.
60
+ - `getValues: UseFormGetValues<AllActivityFields<A>>`
61
+ - Returns all field values.
62
+ - `reset: UseFormReset<AllActivityFields<A>>`
63
+ - Resets form to given values or defaults.
64
+ - `trigger: UseFormTrigger<AllActivityFields<A>>`
65
+ - Manually triggers validation for specific or all fields.
66
+ - `control: Control<AllActivityFields<A>>`
67
+ - RHF control for `Controller` components.
68
+
69
+ ### Form State
70
+
71
+ - `errors: FieldErrors<AllActivityFields<A>>`
72
+ - Validation errors by field name. Each entry has `type` and `message`.
73
+ - `isValid: boolean`
74
+ - `true` if all fields pass validation.
75
+ - `isDirty: boolean`
76
+ - `true` if any field has been modified.
77
+ - `isSubmitting: boolean`
78
+ - `true` during `handleSubmit` (from button click to API response).
79
+ - `isSubmitSuccessful: boolean`
80
+ - `true` after the last submission succeeded.
81
+
82
+ ### Loading & Error
83
+
84
+ - `isLoading: boolean`
85
+ - `true` during initial data + metadata loading. Guard form render on this.
86
+ - `isMetadataLoading: boolean`
87
+ - `true` while BP metadata is being fetched.
88
+ - `loadError: Error | null`
89
+ - Error from `activity.read()`.
90
+ - `hasError: boolean`
91
+ - `true` when `loadError` is non-null.
92
+
93
+ ### Other
94
+
95
+ - `bpMetadata: Record<string, unknown> | null`
96
+ - Raw BP metadata blob. `null` while loading.
97
+ - `clearErrors: () => void`
98
+ - Clear all form validation errors.
99
+
100
+ ## handleSubmit
101
+
102
+ ```typescript
103
+ type HandleSubmitType<TRead> = (
104
+ onSuccess?: (data: TRead, e?: React.BaseSyntheticEvent) => void | Promise<void>,
105
+ onError?: (error: FieldErrors | Error, e?: React.BaseSyntheticEvent) => void | Promise<void>,
106
+ ) => (e?: React.BaseSyntheticEvent) => Promise<void>;
107
+ ```
108
+
109
+ Curried function. Pass to an `onClick` handler: `onClick={handleSubmit(onSuccess, onError)}`.
110
+
111
+ **Behavior:**
112
+ 1. Validates all fields via the resolver (type + constraint).
113
+ 2. Collects dirty, non-readonly fields and sends them via `activity.update()`.
114
+ 3. Calls `activity.complete()` to advance the workflow.
115
+ 4. Invokes `onSuccess` with the complete response.
116
+
117
+ - `onSuccess(result, e?)`
118
+ - Called with `CreateUpdateResponseType` (`{ _id: string }`) after the activity is completed and the workflow advances.
119
+ - `onError(error, e?)`
120
+ - Called with `FieldErrors` if validation fails, or `Error` if the API call fails.
121
+
122
+ If no dirty fields exist, the update call is skipped but `complete()` is still called.
123
+
124
+ > Per-field sync handles auto-saving on blur/change. `handleSubmit` is for completing the activity, not saving drafts.
125
+
126
+ ## Instance and Field Accessors
127
+
128
+ `item` represents the current activity instance. Each field on `item` is an accessor object.
129
+
130
+ ### Instance Members (`item`)
131
+
132
+ - `_id: string | undefined`
133
+ - Current activity instance ID.
134
+ - `toJSON(): Partial<TEditable & TReadonly>`
135
+ - All form values as a plain object.
136
+ - `validate(): Promise<boolean>`
137
+ - Triggers validation for all fields. Returns `true` if valid.
138
+
139
+ ### Editable Field (`item.FieldName`)
140
+
141
+ - `get(): T | undefined`
142
+ - Current value from form state.
143
+ - `getOrDefault(fallback: T): T`
144
+ - Value or fallback if null/undefined.
145
+ - `set(value: T): void`
146
+ - Sets the field value.
147
+ - `validate(): ValidationResultType`
148
+ - Validates the current value. Returns `{ valid: boolean, errors: string[] }`.
149
+ - `label: string`
150
+ - Display label from field metadata.
151
+ - `required: boolean`
152
+ - Whether the field is required.
153
+ - `readOnly: boolean`
154
+ - Always `false` for editable fields.
155
+ - `defaultValue: unknown`
156
+ - Default value from metadata.
157
+ - `meta: BaseFieldMetaType`
158
+ - Raw field metadata.
159
+
160
+ ### Readonly Field (`item.FieldName`)
161
+
162
+ Same as editable except: no `set()` method, `readOnly` is always `true`.
163
+
164
+ ## Types
165
+
166
+ ```typescript
167
+ // ---- Generic extraction helpers ----
168
+
169
+ type ExtractActivityEntity<A> =
170
+ A extends Activity<infer E, any, any> ? E : never;
171
+
172
+ type ExtractActivityEditable<A> =
173
+ A extends Activity<any, infer E, any> ? E : never;
174
+
175
+ type ExtractActivityReadonly<A> =
176
+ A extends Activity<any, any, infer R> ? R : never;
177
+
178
+ type AllActivityFields<A> =
179
+ ExtractActivityEditable<A> & ExtractActivityReadonly<A>;
180
+
181
+ // ---- Hook options ----
182
+
183
+ interface UseActivityFormOptions<A extends Activity<any, any, any>> {
184
+ activity_instance_id: string;
185
+ defaultValues?: Partial<ExtractActivityEditable<A>>;
186
+ mode?: "onBlur" | "onChange" | "onSubmit" | "onTouched" | "all";
187
+ enabled?: boolean;
188
+ }
189
+
190
+ // ---- Hook return type ----
191
+
192
+ interface UseActivityFormReturn<A extends Activity<any, any, any>> {
193
+ item: FormItemType<ExtractActivityEditable<A>, ExtractActivityReadonly<A>>;
194
+ activity: A;
195
+
196
+ register: FormRegisterType<ExtractActivityEditable<A>, ExtractActivityReadonly<A>>;
197
+ handleSubmit: HandleSubmitType<CreateUpdateResponseType>;
198
+ watch: UseFormWatch<AllActivityFields<A>>;
199
+ setValue: UseFormSetValue<ExtractActivityEditable<A>>;
200
+ getValues: UseFormGetValues<AllActivityFields<A>>;
201
+ reset: UseFormReset<AllActivityFields<A>>;
202
+ trigger: UseFormTrigger<AllActivityFields<A>>;
203
+ control: Control<AllActivityFields<A>>;
204
+
205
+ errors: FieldErrors<AllActivityFields<A>>;
206
+ isValid: boolean;
207
+ isDirty: boolean;
208
+ isSubmitting: boolean;
209
+ isSubmitSuccessful: boolean;
210
+
211
+ isLoading: boolean;
212
+ isMetadataLoading: boolean;
213
+ loadError: Error | null;
214
+ hasError: boolean;
215
+
216
+ bpMetadata: Record<string, unknown> | null;
217
+ clearErrors: () => void;
218
+ }
219
+
220
+ // ---- Shared types ----
221
+
222
+ type HandleSubmitType<TRead = unknown> = (
223
+ onSuccess?: (
224
+ data: TRead,
225
+ e?: React.BaseSyntheticEvent,
226
+ ) => void | Promise<void>,
227
+ onError?: (
228
+ error: FieldErrors | Error,
229
+ e?: React.BaseSyntheticEvent,
230
+ ) => void | Promise<void>,
231
+ ) => (e?: React.BaseSyntheticEvent) => Promise<void>;
232
+
233
+ type FormRegisterType<TEditable, TReadonly> = <
234
+ K extends keyof TEditable | keyof TReadonly | string
235
+ >(
236
+ name: K & string,
237
+ options?: RegisterOptions,
238
+ ) => K extends keyof TReadonly
239
+ ? UseFormRegisterReturn & { disabled: true }
240
+ : UseFormRegisterReturn;
241
+
242
+ type FormItemType<TEditable, TReadonly> = {
243
+ [K in keyof TEditable]: EditableFormFieldAccessorType<TEditable[K]>;
244
+ } & {
245
+ [K in keyof TReadonly]: ReadonlyFormFieldAccessorType<TReadonly[K]>;
246
+ } & {
247
+ readonly _id: string | undefined;
248
+ toJSON(): Partial<TEditable & TReadonly>;
249
+ validate(): Promise<boolean>;
250
+ };
251
+
252
+ interface EditableFormFieldAccessorType<T> {
253
+ readonly label: string;
254
+ readonly required: boolean;
255
+ readonly readOnly: false;
256
+ readonly defaultValue: unknown;
257
+ readonly meta: BaseFieldMetaType;
258
+ get(): T | undefined;
259
+ getOrDefault(fallback: T): T;
260
+ set(value: T): void;
261
+ validate(): ValidationResultType;
262
+ }
263
+
264
+ interface ReadonlyFormFieldAccessorType<T> {
265
+ readonly label: string;
266
+ readonly required: boolean;
267
+ readonly readOnly: true;
268
+ readonly defaultValue: unknown;
269
+ readonly meta: BaseFieldMetaType;
270
+ get(): T | undefined;
271
+ getOrDefault(fallback: T): T;
272
+ validate(): ValidationResultType;
273
+ }
274
+
275
+ interface ValidationResultType {
276
+ valid: boolean;
277
+ errors: string[];
278
+ }
279
+ ```