@ic-reactor/candid 3.0.13-beta.0 → 3.0.14-beta.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/README.md +28 -0
- package/dist/visitor/arguments/helpers.d.ts +5 -5
- package/dist/visitor/arguments/helpers.d.ts.map +1 -1
- package/dist/visitor/arguments/helpers.js.map +1 -1
- package/dist/visitor/arguments/index.d.ts +12 -2
- package/dist/visitor/arguments/index.d.ts.map +1 -1
- package/dist/visitor/arguments/index.js +136 -12
- package/dist/visitor/arguments/index.js.map +1 -1
- package/dist/visitor/arguments/types.d.ts +112 -359
- package/dist/visitor/arguments/types.d.ts.map +1 -1
- package/dist/visitor/returns/types.d.ts +3 -4
- package/dist/visitor/returns/types.d.ts.map +1 -1
- package/dist/visitor/types.d.ts +14 -0
- package/dist/visitor/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/visitor/arguments/helpers.ts +5 -5
- package/src/visitor/arguments/index.test.ts +43 -22
- package/src/visitor/arguments/index.ts +167 -32
- package/src/visitor/arguments/schema.test.ts +114 -4
- package/src/visitor/arguments/types.ts +178 -444
- package/src/visitor/returns/types.ts +4 -27
- package/src/visitor/types.ts +45 -0
|
@@ -1,24 +1,14 @@
|
|
|
1
1
|
import type { BaseActor, FunctionName, FunctionType } from "@ic-reactor/core"
|
|
2
2
|
import * as z from "zod"
|
|
3
|
+
import type { VisitorDataType, TextFormat, NumberFormat } from "../types"
|
|
4
|
+
|
|
5
|
+
export type { TextFormat, NumberFormat }
|
|
3
6
|
|
|
4
7
|
// ════════════════════════════════════════════════════════════════════════════
|
|
5
8
|
// Field Type Union
|
|
6
9
|
// ════════════════════════════════════════════════════════════════════════════
|
|
7
10
|
|
|
8
|
-
export type ArgumentFieldType =
|
|
9
|
-
| "record"
|
|
10
|
-
| "variant"
|
|
11
|
-
| "tuple"
|
|
12
|
-
| "optional"
|
|
13
|
-
| "vector"
|
|
14
|
-
| "blob"
|
|
15
|
-
| "recursive"
|
|
16
|
-
| "principal"
|
|
17
|
-
| "number"
|
|
18
|
-
| "text"
|
|
19
|
-
| "boolean"
|
|
20
|
-
| "null"
|
|
21
|
-
| "unknown"
|
|
11
|
+
export type ArgumentFieldType = VisitorDataType
|
|
22
12
|
|
|
23
13
|
// ════════════════════════════════════════════════════════════════════════════
|
|
24
14
|
// Component Type Hints
|
|
@@ -27,18 +17,6 @@ export type ArgumentFieldType =
|
|
|
27
17
|
/**
|
|
28
18
|
* Suggested component type for rendering the field.
|
|
29
19
|
* This eliminates the need for switch statements in the frontend.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```tsx
|
|
33
|
-
* const componentMap = {
|
|
34
|
-
* 'text-input': TextField,
|
|
35
|
-
* 'number-input': NumberField,
|
|
36
|
-
* 'boolean-checkbox': BooleanField,
|
|
37
|
-
* // ...
|
|
38
|
-
* }
|
|
39
|
-
* const Component = componentMap[field.component]
|
|
40
|
-
* return <Component field={field} />
|
|
41
|
-
* ```
|
|
42
20
|
*/
|
|
43
21
|
export type FieldComponentType =
|
|
44
22
|
| "record-container"
|
|
@@ -74,18 +52,6 @@ export type InputType =
|
|
|
74
52
|
/**
|
|
75
53
|
* Rendering hints for the UI.
|
|
76
54
|
* Eliminates the need for frontend to maintain COMPLEX_TYPES arrays.
|
|
77
|
-
*
|
|
78
|
-
* @example
|
|
79
|
-
* ```tsx
|
|
80
|
-
* // Frontend no longer needs:
|
|
81
|
-
* // const COMPLEX_TYPES = ["record", "tuple", "variant", "vector", "optional"]
|
|
82
|
-
*
|
|
83
|
-
* // Instead use:
|
|
84
|
-
* if (field.renderHint.isCompound) {
|
|
85
|
-
* return <CompoundFieldRenderer field={field} />
|
|
86
|
-
* }
|
|
87
|
-
* return <PrimitiveInput field={field} />
|
|
88
|
-
* ```
|
|
89
55
|
*/
|
|
90
56
|
export interface RenderHint {
|
|
91
57
|
/** Whether this field has its own container/card styling (compound types) */
|
|
@@ -105,15 +71,10 @@ export interface RenderHint {
|
|
|
105
71
|
/**
|
|
106
72
|
* Pre-computed HTML input props for primitive fields.
|
|
107
73
|
* Can be spread directly onto an input element.
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* ```tsx
|
|
111
|
-
* <input {...field.inputProps} value={value} onChange={handleChange} />
|
|
112
|
-
* ```
|
|
113
74
|
*/
|
|
114
75
|
export interface PrimitiveInputProps {
|
|
115
|
-
/** HTML input type */
|
|
116
|
-
type?: "text" | "number" | "checkbox"
|
|
76
|
+
/** HTML input type - includes format-specific types */
|
|
77
|
+
type?: "text" | "number" | "checkbox" | "email" | "url" | "tel"
|
|
117
78
|
/** Placeholder text */
|
|
118
79
|
placeholder?: string
|
|
119
80
|
/** Minimum value for number inputs */
|
|
@@ -122,10 +83,10 @@ export interface PrimitiveInputProps {
|
|
|
122
83
|
max?: string | number
|
|
123
84
|
/** Step value for number inputs */
|
|
124
85
|
step?: string | number
|
|
125
|
-
/** Pattern for text inputs */
|
|
86
|
+
/** Pattern for text inputs (e.g., phone numbers) */
|
|
126
87
|
pattern?: string
|
|
127
88
|
/** Input mode for virtual keyboards */
|
|
128
|
-
inputMode?: "text" | "numeric" | "decimal"
|
|
89
|
+
inputMode?: "text" | "numeric" | "decimal" | "email" | "tel" | "url"
|
|
129
90
|
/** Autocomplete hint */
|
|
130
91
|
autoComplete?: string
|
|
131
92
|
/** Whether to check spelling */
|
|
@@ -140,205 +101,29 @@ export interface PrimitiveInputProps {
|
|
|
140
101
|
// Base Field Interface
|
|
141
102
|
// ════════════════════════════════════════════════════════════════════════════
|
|
142
103
|
|
|
143
|
-
|
|
104
|
+
interface FieldBase<T extends VisitorDataType = VisitorDataType> {
|
|
144
105
|
/** The field type */
|
|
145
|
-
type:
|
|
106
|
+
type: T
|
|
146
107
|
/** Raw label from Candid: "__arg0", "_0_" */
|
|
147
108
|
label: string
|
|
148
|
-
/**
|
|
149
|
-
* Pre-formatted display label for UI rendering.
|
|
150
|
-
* Transforms raw labels into human-readable format.
|
|
151
|
-
*
|
|
152
|
-
* @example
|
|
153
|
-
* "__arg0" => "Arg 0"
|
|
154
|
-
* "_0_" => "Item 0"
|
|
155
|
-
* "created_at_time" => "Created At Time"
|
|
156
|
-
*/
|
|
109
|
+
/** Pre-formatted display label for UI rendering */
|
|
157
110
|
displayLabel: string
|
|
158
|
-
/**
|
|
159
|
-
* Form field name path for binding.
|
|
160
|
-
* Uses bracket notation for array indices: `[0]`, `args[0].owner`, `tags[1]`
|
|
161
|
-
* Compatible with TanStack Form's `form.Field` name prop.
|
|
162
|
-
*
|
|
163
|
-
* @example
|
|
164
|
-
* ```tsx
|
|
165
|
-
* <form.Field name={field.name}>
|
|
166
|
-
* {(fieldApi) => <input {...} />}
|
|
167
|
-
* </form.Field>
|
|
168
|
-
* ```
|
|
169
|
-
*/
|
|
111
|
+
/** Form field name path for binding */
|
|
170
112
|
name: string
|
|
171
|
-
/**
|
|
172
|
-
* Suggested component type for rendering this field.
|
|
173
|
-
* Eliminates the need for switch statements in the frontend.
|
|
174
|
-
*/
|
|
113
|
+
/** Suggested component type for rendering this field */
|
|
175
114
|
component: FieldComponentType
|
|
176
|
-
/**
|
|
177
|
-
* Rendering hints for UI strategy.
|
|
178
|
-
* Use this to determine if the field needs a container or is a simple input.
|
|
179
|
-
*/
|
|
115
|
+
/** Rendering hints for UI strategy */
|
|
180
116
|
renderHint: RenderHint
|
|
181
117
|
/** Zod schema for field validation */
|
|
182
118
|
schema: z.ZodTypeAny
|
|
183
|
-
/** Default value for the field */
|
|
184
|
-
defaultValue: TValue
|
|
185
119
|
/** Original Candid type name for reference */
|
|
186
|
-
candidType
|
|
120
|
+
candidType: string
|
|
187
121
|
}
|
|
188
122
|
|
|
189
123
|
// ════════════════════════════════════════════════════════════════════════════
|
|
190
|
-
//
|
|
124
|
+
// Type-Specific Extras
|
|
191
125
|
// ════════════════════════════════════════════════════════════════════════════
|
|
192
126
|
|
|
193
|
-
export interface RecordField extends FieldBase<Record<string, unknown>> {
|
|
194
|
-
type: "record"
|
|
195
|
-
/** Child fields in the record */
|
|
196
|
-
fields: Field[]
|
|
197
|
-
/** Map of field label to its metadata for quick lookup */
|
|
198
|
-
fieldMap: Map<string, Field>
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export interface VariantField extends FieldBase<Record<string, unknown>> {
|
|
202
|
-
type: "variant"
|
|
203
|
-
/** All variant option fields */
|
|
204
|
-
fields: Field[]
|
|
205
|
-
/** List of variant option names */
|
|
206
|
-
options: string[]
|
|
207
|
-
/** Default selected option */
|
|
208
|
-
defaultOption: string
|
|
209
|
-
/** Map of option name to its field metadata */
|
|
210
|
-
optionMap: Map<string, Field>
|
|
211
|
-
/**
|
|
212
|
-
* Get default value for a specific option.
|
|
213
|
-
* Useful when switching between variant options.
|
|
214
|
-
*
|
|
215
|
-
* @example
|
|
216
|
-
* ```tsx
|
|
217
|
-
* const handleOptionChange = (newOption: string) => {
|
|
218
|
-
* const newDefault = field.getOptionDefault(newOption)
|
|
219
|
-
* fieldApi.handleChange(newDefault)
|
|
220
|
-
* }
|
|
221
|
-
* ```
|
|
222
|
-
*/
|
|
223
|
-
getOptionDefault: (option: string) => Record<string, unknown>
|
|
224
|
-
/**
|
|
225
|
-
* Get the field for a specific option.
|
|
226
|
-
*
|
|
227
|
-
* @example
|
|
228
|
-
* ```tsx
|
|
229
|
-
* const transferField = field.getField("Transfer")
|
|
230
|
-
* ```
|
|
231
|
-
*/
|
|
232
|
-
getField: (option: string) => Field
|
|
233
|
-
/**
|
|
234
|
-
* Get the currently selected option from a value.
|
|
235
|
-
* Returns the first valid key found, or the default option.
|
|
236
|
-
*
|
|
237
|
-
* @example
|
|
238
|
-
* ```tsx
|
|
239
|
-
* const selectedOption = field.getSelectedOption(currentValue)
|
|
240
|
-
* // { Transfer: {...} } => "Transfer"
|
|
241
|
-
* ```
|
|
242
|
-
*/
|
|
243
|
-
getSelectedOption: (value: Record<string, unknown>) => string
|
|
244
|
-
/**
|
|
245
|
-
* Get the selected field from a value.
|
|
246
|
-
* Combines getSelectedOption and getField for convenience.
|
|
247
|
-
*
|
|
248
|
-
* @example
|
|
249
|
-
* ```tsx
|
|
250
|
-
* // Current (verbose):
|
|
251
|
-
* const validKeys = Object.keys(currentValue).filter(k => field.options.includes(k))
|
|
252
|
-
* const selected = validKeys[0] ?? field.options[0]
|
|
253
|
-
* const selectedIndex = Math.max(0, field.options.indexOf(selected))
|
|
254
|
-
* const selectedField = field.fields[selectedIndex]
|
|
255
|
-
*
|
|
256
|
-
* // Proposed (simple):
|
|
257
|
-
* const selectedField = field.getSelectedField(currentValue)
|
|
258
|
-
* ```
|
|
259
|
-
*/
|
|
260
|
-
getSelectedField: (value: Record<string, unknown>) => Field
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
export interface TupleField extends FieldBase<unknown[]> {
|
|
264
|
-
type: "tuple"
|
|
265
|
-
/** Tuple element fields in order */
|
|
266
|
-
fields: Field[]
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
export interface OptionalField extends FieldBase<null> {
|
|
270
|
-
type: "optional"
|
|
271
|
-
/** The inner field when value is present */
|
|
272
|
-
innerField: Field
|
|
273
|
-
/**
|
|
274
|
-
* Get default value when enabling the optional.
|
|
275
|
-
* Returns the inner field's default value.
|
|
276
|
-
*
|
|
277
|
-
* @example
|
|
278
|
-
* ```tsx
|
|
279
|
-
* const handleToggle = (enabled: boolean) => {
|
|
280
|
-
* if (enabled) {
|
|
281
|
-
* fieldApi.handleChange(field.getInnerDefault())
|
|
282
|
-
* } else {
|
|
283
|
-
* fieldApi.handleChange(null)
|
|
284
|
-
* }
|
|
285
|
-
* }
|
|
286
|
-
* ```
|
|
287
|
-
*/
|
|
288
|
-
getInnerDefault: () => unknown
|
|
289
|
-
/**
|
|
290
|
-
* Check if a value represents an enabled optional.
|
|
291
|
-
* Returns true if the value is not null or undefined.
|
|
292
|
-
*
|
|
293
|
-
* @example
|
|
294
|
-
* ```tsx
|
|
295
|
-
* // Current:
|
|
296
|
-
* const enabled = fieldApi.state.value !== null && typeof fieldApi.state.value !== "undefined"
|
|
297
|
-
*
|
|
298
|
-
* // Proposed:
|
|
299
|
-
* const enabled = field.isEnabled(fieldApi.state.value)
|
|
300
|
-
* ```
|
|
301
|
-
*/
|
|
302
|
-
isEnabled: (value: unknown) => boolean
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
export interface VectorField extends FieldBase<unknown[]> {
|
|
306
|
-
type: "vector"
|
|
307
|
-
/** Template field for vector items */
|
|
308
|
-
itemField: Field
|
|
309
|
-
/**
|
|
310
|
-
* Get a new item with default values.
|
|
311
|
-
* Used when adding items to the vector.
|
|
312
|
-
*
|
|
313
|
-
* @example
|
|
314
|
-
* ```tsx
|
|
315
|
-
* <button onClick={() => fieldApi.pushValue(field.getItemDefault())}>
|
|
316
|
-
* Add Item
|
|
317
|
-
* </button>
|
|
318
|
-
* ```
|
|
319
|
-
*/
|
|
320
|
-
getItemDefault: () => unknown
|
|
321
|
-
/**
|
|
322
|
-
* Create a properly configured item field for a specific index.
|
|
323
|
-
* Handles name path and label generation.
|
|
324
|
-
*
|
|
325
|
-
* @example
|
|
326
|
-
* ```tsx
|
|
327
|
-
* // Current:
|
|
328
|
-
* renderField({
|
|
329
|
-
* ...field.itemField,
|
|
330
|
-
* label: itemLabel,
|
|
331
|
-
* name: itemFieldName
|
|
332
|
-
* })
|
|
333
|
-
*
|
|
334
|
-
* // Proposed:
|
|
335
|
-
* const itemField = field.createItemField(index, { label: itemLabel })
|
|
336
|
-
* renderField(itemField)
|
|
337
|
-
* ```
|
|
338
|
-
*/
|
|
339
|
-
createItemField: (index: number, overrides?: { label?: string }) => Field
|
|
340
|
-
}
|
|
341
|
-
|
|
342
127
|
/**
|
|
343
128
|
* Blob field size limits.
|
|
344
129
|
*/
|
|
@@ -361,151 +146,166 @@ export interface BlobValidationResult {
|
|
|
361
146
|
error?: string
|
|
362
147
|
}
|
|
363
148
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
149
|
+
type FieldExtras<T extends VisitorDataType> = T extends "record"
|
|
150
|
+
? {
|
|
151
|
+
/** Child fields in the record */
|
|
152
|
+
fields: FieldNode[]
|
|
153
|
+
/** Map of field label to its metadata for quick lookup */
|
|
154
|
+
fieldMap: Map<string, FieldNode>
|
|
155
|
+
defaultValue: Record<string, unknown>
|
|
156
|
+
}
|
|
157
|
+
: T extends "variant"
|
|
158
|
+
? {
|
|
159
|
+
/** All variant option fields */
|
|
160
|
+
fields: FieldNode[]
|
|
161
|
+
/** List of variant option names */
|
|
162
|
+
options: string[]
|
|
163
|
+
/** Default selected option */
|
|
164
|
+
defaultOption: string
|
|
165
|
+
/** Map of option name to its field metadata */
|
|
166
|
+
optionMap: Map<string, FieldNode>
|
|
167
|
+
defaultValue: Record<string, unknown>
|
|
168
|
+
/** Get default value for a specific option */
|
|
169
|
+
getOptionDefault: (option: string) => Record<string, unknown>
|
|
170
|
+
/** Get the field for a specific option */
|
|
171
|
+
getField: (option: string) => FieldNode
|
|
172
|
+
/** Get the currently selected option from a value */
|
|
173
|
+
getSelectedOption: (value: Record<string, unknown>) => string
|
|
174
|
+
/** Get the selected field from a value */
|
|
175
|
+
getSelectedField: (value: Record<string, unknown>) => FieldNode
|
|
176
|
+
}
|
|
177
|
+
: T extends "tuple"
|
|
178
|
+
? {
|
|
179
|
+
/** Tuple element fields in order */
|
|
180
|
+
fields: FieldNode[]
|
|
181
|
+
defaultValue: unknown[]
|
|
182
|
+
}
|
|
183
|
+
: T extends "optional"
|
|
184
|
+
? {
|
|
185
|
+
/** The inner field when value is present */
|
|
186
|
+
innerField: FieldNode
|
|
187
|
+
defaultValue: null
|
|
188
|
+
/** Get default value when enabling the optional */
|
|
189
|
+
getInnerDefault: () => unknown
|
|
190
|
+
/** Check if a value represents an enabled optional */
|
|
191
|
+
isEnabled: (value: unknown) => boolean
|
|
192
|
+
}
|
|
193
|
+
: T extends "vector"
|
|
194
|
+
? {
|
|
195
|
+
/** Template field for vector items */
|
|
196
|
+
itemField: FieldNode
|
|
197
|
+
defaultValue: unknown[]
|
|
198
|
+
/** Get a new item with default values */
|
|
199
|
+
getItemDefault: () => unknown
|
|
200
|
+
/** Create a properly configured item field for a specific index */
|
|
201
|
+
createItemField: (
|
|
202
|
+
index: number,
|
|
203
|
+
overrides?: { label?: string }
|
|
204
|
+
) => FieldNode
|
|
205
|
+
}
|
|
206
|
+
: T extends "blob"
|
|
207
|
+
? {
|
|
208
|
+
/** Item field for individual bytes (nat8) */
|
|
209
|
+
itemField: FieldNode
|
|
210
|
+
/** Accepted input formats */
|
|
211
|
+
acceptedFormats: ("hex" | "base64" | "file")[]
|
|
212
|
+
/** Size limits for blob input */
|
|
213
|
+
limits: BlobLimits
|
|
214
|
+
/** Normalize hex input */
|
|
215
|
+
normalizeHex: (input: string) => string
|
|
216
|
+
/** Validate blob input value */
|
|
217
|
+
validateInput: (
|
|
218
|
+
value: string | Uint8Array
|
|
219
|
+
) => BlobValidationResult
|
|
220
|
+
defaultValue: string
|
|
221
|
+
}
|
|
222
|
+
: T extends "recursive"
|
|
223
|
+
? {
|
|
224
|
+
/** Type name for the recursive type */
|
|
225
|
+
typeName: string
|
|
226
|
+
/** Lazily extract the inner field to prevent infinite loops */
|
|
227
|
+
extract: () => FieldNode
|
|
228
|
+
/** Get default value for the recursive type (evaluates lazily) */
|
|
229
|
+
getInnerDefault: () => unknown
|
|
230
|
+
defaultValue: undefined
|
|
231
|
+
}
|
|
232
|
+
: T extends "principal"
|
|
233
|
+
? {
|
|
234
|
+
maxLength: number
|
|
235
|
+
minLength: number
|
|
236
|
+
/** Detected format based on label heuristics */
|
|
237
|
+
format: TextFormat
|
|
238
|
+
/** Pre-computed HTML input props */
|
|
239
|
+
inputProps: PrimitiveInputProps
|
|
240
|
+
defaultValue: string
|
|
241
|
+
}
|
|
242
|
+
: T extends "number"
|
|
243
|
+
? {
|
|
244
|
+
/** Whether this is an unsigned type */
|
|
245
|
+
unsigned: boolean
|
|
246
|
+
/** Whether this is a floating point type */
|
|
247
|
+
isFloat: boolean
|
|
248
|
+
/** Bit width if applicable (8, 16, 32, 64, or undefined for unbounded) */
|
|
249
|
+
bits?: number
|
|
250
|
+
/** Minimum value constraint (for bounded types) */
|
|
251
|
+
min?: string
|
|
252
|
+
/** Maximum value constraint (for bounded types) */
|
|
253
|
+
max?: string
|
|
254
|
+
/** Detected format based on label heuristics */
|
|
255
|
+
format: NumberFormat
|
|
256
|
+
/** Pre-computed HTML input props */
|
|
257
|
+
inputProps: PrimitiveInputProps
|
|
258
|
+
defaultValue: string
|
|
259
|
+
}
|
|
260
|
+
: T extends "text"
|
|
261
|
+
? {
|
|
262
|
+
/** Minimum length constraint */
|
|
263
|
+
minLength?: number
|
|
264
|
+
/** Maximum length constraint */
|
|
265
|
+
maxLength?: number
|
|
266
|
+
/** Whether to render as multiline textarea */
|
|
267
|
+
multiline?: boolean
|
|
268
|
+
/** Detected format based on label heuristics */
|
|
269
|
+
format: TextFormat
|
|
270
|
+
/** Pre-computed HTML input props */
|
|
271
|
+
inputProps: PrimitiveInputProps
|
|
272
|
+
defaultValue: string
|
|
273
|
+
}
|
|
274
|
+
: T extends "boolean"
|
|
275
|
+
? {
|
|
276
|
+
/** Pre-computed HTML input props */
|
|
277
|
+
inputProps: PrimitiveInputProps
|
|
278
|
+
defaultValue: boolean
|
|
279
|
+
}
|
|
280
|
+
: T extends "null"
|
|
281
|
+
? {
|
|
282
|
+
defaultValue: null
|
|
283
|
+
}
|
|
284
|
+
: T extends "unknown"
|
|
285
|
+
? {
|
|
286
|
+
defaultValue: undefined
|
|
287
|
+
}
|
|
288
|
+
: {}
|
|
490
289
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
290
|
+
/**
|
|
291
|
+
* A unified field node that contains all metadata needed for rendering.
|
|
292
|
+
*/
|
|
293
|
+
export type FieldNode<T extends VisitorDataType = VisitorDataType> =
|
|
294
|
+
FieldBase<T> & FieldExtras<T>
|
|
295
|
+
|
|
296
|
+
export type RecordField = FieldNode<"record">
|
|
297
|
+
export type VariantField = FieldNode<"variant">
|
|
298
|
+
export type TupleField = FieldNode<"tuple">
|
|
299
|
+
export type OptionalField = FieldNode<"optional">
|
|
300
|
+
export type VectorField = FieldNode<"vector">
|
|
301
|
+
export type BlobField = FieldNode<"blob">
|
|
302
|
+
export type RecursiveField = FieldNode<"recursive">
|
|
303
|
+
export type PrincipalField = FieldNode<"principal">
|
|
304
|
+
export type NumberField = FieldNode<"number">
|
|
305
|
+
export type TextField = FieldNode<"text">
|
|
306
|
+
export type BooleanField = FieldNode<"boolean">
|
|
307
|
+
export type NullField = FieldNode<"null">
|
|
308
|
+
export type UnknownField = FieldNode<"unknown">
|
|
509
309
|
|
|
510
310
|
// ════════════════════════════════════════════════════════════════════════════
|
|
511
311
|
// Form Metadata - TanStack Form Integration
|
|
@@ -514,31 +314,6 @@ export type Field =
|
|
|
514
314
|
/**
|
|
515
315
|
* Form metadata for a Candid method.
|
|
516
316
|
* Contains all information needed to create a TanStack Form instance.
|
|
517
|
-
*
|
|
518
|
-
* @example
|
|
519
|
-
* ```tsx
|
|
520
|
-
* import { useForm } from '@tanstack/react-form'
|
|
521
|
-
*
|
|
522
|
-
* function MethodForm({ meta }: { meta: FormMeta }) {
|
|
523
|
-
* const form = useForm({
|
|
524
|
-
* ...meta.formOptions,
|
|
525
|
-
* onSubmit: async ({ value }) => {
|
|
526
|
-
* await actor[meta.functionName](...value)
|
|
527
|
-
* }
|
|
528
|
-
* })
|
|
529
|
-
*
|
|
530
|
-
* return (
|
|
531
|
-
* <form onSubmit={(e) => { e.preventDefault(); form.handleSubmit() }}>
|
|
532
|
-
* {meta.fields.map(field => (
|
|
533
|
-
* <form.Field key={field.name} name={field.name}>
|
|
534
|
-
* {(fieldApi) => <DynamicInput field={field} fieldApi={fieldApi} />}
|
|
535
|
-
* </form.Field>
|
|
536
|
-
* ))}
|
|
537
|
-
* <button type="submit">Submit</button>
|
|
538
|
-
* </form>
|
|
539
|
-
* )
|
|
540
|
-
* }
|
|
541
|
-
* ```
|
|
542
317
|
*/
|
|
543
318
|
export interface ArgumentsMeta<
|
|
544
319
|
A = BaseActor,
|
|
@@ -549,7 +324,7 @@ export interface ArgumentsMeta<
|
|
|
549
324
|
/** The function name */
|
|
550
325
|
functionName: Name
|
|
551
326
|
/** Argument field definitions for rendering */
|
|
552
|
-
fields:
|
|
327
|
+
fields: FieldNode[]
|
|
553
328
|
/** Default values for all arguments (as a tuple) */
|
|
554
329
|
defaultValues: unknown[]
|
|
555
330
|
/** Combined Zod schema for all arguments */
|
|
@@ -588,30 +363,17 @@ export type ArgumentsServiceMeta<A = BaseActor> = {
|
|
|
588
363
|
|
|
589
364
|
/** Extract a specific field type */
|
|
590
365
|
export type FieldByType<T extends ArgumentFieldType> = Extract<
|
|
591
|
-
|
|
366
|
+
FieldNode,
|
|
592
367
|
{ type: T }
|
|
593
368
|
>
|
|
594
369
|
|
|
595
370
|
/**
|
|
596
371
|
* Props type helper for field components.
|
|
597
372
|
* Use this to type your field components for better DX.
|
|
598
|
-
*
|
|
599
|
-
* @example
|
|
600
|
-
* ```tsx
|
|
601
|
-
* const VariantField: React.FC<FieldProps<'variant'>> = ({ field, renderField }) => {
|
|
602
|
-
* // field is properly typed as VariantField
|
|
603
|
-
* return (
|
|
604
|
-
* <div>
|
|
605
|
-
* <select>{field.options.map(opt => ...)}</select>
|
|
606
|
-
* {renderField?.(field.getSelectedField(currentValue))}
|
|
607
|
-
* </div>
|
|
608
|
-
* )
|
|
609
|
-
* }
|
|
610
|
-
* ```
|
|
611
373
|
*/
|
|
612
374
|
export type FieldProps<T extends ArgumentFieldType> = {
|
|
613
375
|
field: FieldByType<T>
|
|
614
|
-
renderField?: (child:
|
|
376
|
+
renderField?: (child: FieldNode) => React.ReactNode
|
|
615
377
|
}
|
|
616
378
|
|
|
617
379
|
/** Compound field types that contain other fields */
|
|
@@ -630,31 +392,3 @@ export type PrimitiveField =
|
|
|
630
392
|
| TextField
|
|
631
393
|
| BooleanField
|
|
632
394
|
| NullField
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* A complete mapping of component types to React components.
|
|
636
|
-
* Use this type when defining your component map.
|
|
637
|
-
*
|
|
638
|
-
* @example
|
|
639
|
-
* ```tsx
|
|
640
|
-
* const componentMap: ComponentMap<typeof MyTextInput, typeof MyNumberInput, ...> = {
|
|
641
|
-
* 'text-input': MyTextInput,
|
|
642
|
-
* 'number-input': MyNumberInput,
|
|
643
|
-
* // ...
|
|
644
|
-
* }
|
|
645
|
-
* ```
|
|
646
|
-
*/
|
|
647
|
-
export type ComponentMap<
|
|
648
|
-
TComponents extends Record<FieldComponentType, unknown>,
|
|
649
|
-
> = {
|
|
650
|
-
[K in FieldComponentType]: TComponents[K]
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
/**
|
|
654
|
-
* Get the component type for a given field component type.
|
|
655
|
-
* Useful for typing dynamic component lookups.
|
|
656
|
-
*/
|
|
657
|
-
export type GetComponentType<
|
|
658
|
-
TMap extends Partial<Record<FieldComponentType, unknown>>,
|
|
659
|
-
TKey extends FieldComponentType,
|
|
660
|
-
> = TKey extends keyof TMap ? TMap[TKey] : never
|