@formality-ui/core 0.0.0 → 0.1.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 +103 -93
- package/dist/index.cjs +245 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +111 -16
- package/dist/index.d.ts +111 -16
- package/dist/index.js +245 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FieldMatcher - Matchers for a single field in multi-field conditions
|
|
3
|
+
*
|
|
4
|
+
* Used when `when` is an object mapping field names to their matchers.
|
|
5
|
+
* All specified matchers must pass (AND logic).
|
|
6
|
+
*/
|
|
7
|
+
interface FieldMatcher {
|
|
8
|
+
/** Exact value match */
|
|
9
|
+
is?: unknown;
|
|
10
|
+
/** Truthy/falsy check (alias: isTruthy) */
|
|
11
|
+
truthy?: boolean;
|
|
12
|
+
/** Truthy/falsy check (alias for truthy) */
|
|
13
|
+
isTruthy?: boolean;
|
|
14
|
+
/** Field validity check - true if field has no errors */
|
|
15
|
+
isValid?: boolean;
|
|
16
|
+
/** Field disabled state check */
|
|
17
|
+
isDisabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Multi-field when trigger - maps field names to their matchers
|
|
21
|
+
*
|
|
22
|
+
* All field conditions must match (AND logic).
|
|
23
|
+
* Example: { email: { isValid: true }, name: { isTruthy: true } }
|
|
24
|
+
*/
|
|
25
|
+
type WhenMultiField = Record<string, FieldMatcher>;
|
|
1
26
|
/**
|
|
2
27
|
* ConditionDescriptor - Defines a single condition rule
|
|
3
28
|
*
|
|
@@ -7,10 +32,11 @@
|
|
|
7
32
|
*/
|
|
8
33
|
interface ConditionDescriptor {
|
|
9
34
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
35
|
+
* Field reference trigger - can be:
|
|
36
|
+
* - string: Single field reference (e.g., "client")
|
|
37
|
+
* - object: Multi-field with per-field matchers (e.g., { email: { isValid: true }, name: { isTruthy: true } })
|
|
12
38
|
*/
|
|
13
|
-
when?: string;
|
|
39
|
+
when?: string | WhenMultiField;
|
|
14
40
|
/**
|
|
15
41
|
* Expression or function trigger
|
|
16
42
|
* Example: "client.id > 5" or ({ fields }) => fields.client?.value?.id > 5
|
|
@@ -27,6 +53,18 @@ interface ConditionDescriptor {
|
|
|
27
53
|
* false: matches if trigger is falsy
|
|
28
54
|
*/
|
|
29
55
|
truthy?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Field validity check (requires 'when' trigger)
|
|
58
|
+
* true: matches if the 'when' field is valid (no errors)
|
|
59
|
+
* false: matches if the 'when' field is invalid (has errors)
|
|
60
|
+
*/
|
|
61
|
+
isValid?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Field disabled state check (requires 'when' trigger)
|
|
64
|
+
* true: matches if the 'when' field is disabled
|
|
65
|
+
* false: matches if the 'when' field is enabled
|
|
66
|
+
*/
|
|
67
|
+
isDisabled?: boolean;
|
|
30
68
|
/**
|
|
31
69
|
* Set disabled state
|
|
32
70
|
* Multiple conditions use OR logic (any true = disabled)
|
|
@@ -117,16 +155,33 @@ type ValidatorSpec = string | ValidatorFunction | Array<string | ValidatorFuncti
|
|
|
117
155
|
/**
|
|
118
156
|
* ValidatorFactory - Factory function for parameterized validators
|
|
119
157
|
*
|
|
120
|
-
*
|
|
158
|
+
* Accepts any number of factory arguments and returns a {@link ValidatorFunction}.
|
|
159
|
+
* The `...args: any[]` rest signature is intentional: it lets concrete factories
|
|
160
|
+
* with specific parameter types (e.g. `(min: number) => ValidatorFunction`,
|
|
161
|
+
* `(regex: RegExp, message: string) => ValidatorFunction`) be assignable to this
|
|
162
|
+
* type without parameter-invariance errors, while still producing a fully typed
|
|
163
|
+
* `ValidatorFunction` return.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* const min: ValidatorFactory = (minVal: number) => (value) =>
|
|
167
|
+
* Number(value) < minVal ? { type: 'min' } : true;
|
|
168
|
+
*/
|
|
169
|
+
type ValidatorFactory = (...args: any[]) => ValidatorFunction;
|
|
170
|
+
/**
|
|
171
|
+
* ValidatorEntry - A named validator or a validator factory.
|
|
172
|
+
*
|
|
173
|
+
* Either a direct {@link ValidatorFunction} (called with `value` + `formValues`)
|
|
174
|
+
* or a {@link ValidatorFactory} (called with factory args to produce a
|
|
175
|
+
* `ValidatorFunction`).
|
|
121
176
|
*/
|
|
122
|
-
type
|
|
177
|
+
type ValidatorEntry = ValidatorFunction | ValidatorFactory;
|
|
123
178
|
/**
|
|
124
179
|
* ValidatorsConfig - Named validators configuration
|
|
125
180
|
*
|
|
126
|
-
* Values can be direct
|
|
181
|
+
* Values can be direct {@link ValidatorFunction}s or {@link ValidatorFactory}s.
|
|
127
182
|
*/
|
|
128
183
|
interface ValidatorsConfig {
|
|
129
|
-
[name: string]:
|
|
184
|
+
[name: string]: ValidatorEntry;
|
|
130
185
|
}
|
|
131
186
|
/**
|
|
132
187
|
* ErrorMessagesConfig - Error message templates by type key
|
|
@@ -164,6 +219,8 @@ interface FieldState {
|
|
|
164
219
|
error?: FieldError;
|
|
165
220
|
/** Inverse of valid state for convenience */
|
|
166
221
|
invalid: boolean;
|
|
222
|
+
/** Whether the field is disabled */
|
|
223
|
+
disabled?: boolean;
|
|
167
224
|
/** Map of subscriber field names watching this field */
|
|
168
225
|
watchers?: Record<string, boolean>;
|
|
169
226
|
}
|
|
@@ -230,9 +287,24 @@ type SelectFunction<TReturn = unknown> = (formState: FormState, methods: unknown
|
|
|
230
287
|
*
|
|
231
288
|
* This defines how a particular input type (e.g., textField, switch, autocomplete)
|
|
232
289
|
* behaves across all forms.
|
|
290
|
+
*
|
|
291
|
+
* Framework agnosticism: `component` and `template` are intentionally `unknown`
|
|
292
|
+
* here (core cannot import a UI framework). React consumers should use the
|
|
293
|
+
* `ReactInputConfig<TValue>` overlay exported from `@formality-ui/react`, which
|
|
294
|
+
* narrows both to `ComponentType<...>`.
|
|
295
|
+
*
|
|
296
|
+
* `TValue` (default `unknown`) links `defaultValue`, `parser`, and `formatter`
|
|
297
|
+
* to a single value type. It defaults to `unknown` because the framework-agnostic
|
|
298
|
+
* core cannot know the value type of every UI component; React consumers can
|
|
299
|
+
* parameterize it via `ReactInputConfig<TValue>` (e.g.
|
|
300
|
+
* `ReactInputConfig<string>` for a text field). Today only the overlay exposes
|
|
301
|
+
* this parameterization; end-to-end per-input value inference is a future
|
|
302
|
+
* enhancement.
|
|
303
|
+
*
|
|
304
|
+
* @template TValue - The form value type this input produces/consumes.
|
|
233
305
|
*/
|
|
234
306
|
interface InputConfig<TValue = unknown> {
|
|
235
|
-
/** The
|
|
307
|
+
/** The component to render (typed `unknown` for framework agnosticism; React consumers see `ComponentType<any>` via `ReactInputConfig`) */
|
|
236
308
|
component: unknown;
|
|
237
309
|
/** Default value for this input type (e.g., '' for text, false for switch) */
|
|
238
310
|
defaultValue: TValue;
|
|
@@ -250,7 +322,7 @@ interface InputConfig<TValue = unknown> {
|
|
|
250
322
|
formatter?: string | ((value: TValue) => unknown);
|
|
251
323
|
/** Type-level validation (runs after field-level validator) */
|
|
252
324
|
validator?: ValidatorSpec;
|
|
253
|
-
/** Template component wrapper for consistent styling */
|
|
325
|
+
/** Template component wrapper for consistent styling (typed `unknown` for framework agnosticism; React consumers see `ComponentType<InputTemplateProps>` via `ReactInputConfig`) */
|
|
254
326
|
template?: unknown;
|
|
255
327
|
/** Default props for this input type */
|
|
256
328
|
props?: Record<string, unknown>;
|
|
@@ -260,6 +332,12 @@ interface InputConfig<TValue = unknown> {
|
|
|
260
332
|
*
|
|
261
333
|
* This defines field-level behavior including conditions, validation,
|
|
262
334
|
* and dynamic props.
|
|
335
|
+
*
|
|
336
|
+
* Framework agnosticism: `rules` is intentionally `Record<string, unknown>` here
|
|
337
|
+
* (core cannot import react-hook-form). React consumers should use the
|
|
338
|
+
* `ReactFieldConfig` overlay exported from `@formality-ui/react`, which narrows
|
|
339
|
+
* `rules` to react-hook-form's `RegisterOptions` for full autocomplete and
|
|
340
|
+
* checking (required, min, max, pattern, validate, valueAsNumber, …).
|
|
263
341
|
*/
|
|
264
342
|
interface FieldConfig {
|
|
265
343
|
/** Input type key (resolves to InputConfig) */
|
|
@@ -276,7 +354,7 @@ interface FieldConfig {
|
|
|
276
354
|
order?: number;
|
|
277
355
|
/** Key to use when reading initial value from record (defaults to field name) */
|
|
278
356
|
recordKey?: string;
|
|
279
|
-
/**
|
|
357
|
+
/** Register options forwarded to the framework's field register call (typed loose for framework agnosticism; React consumers see react-hook-form's `RegisterOptions` via `ReactFieldConfig`) */
|
|
280
358
|
rules?: Record<string, unknown>;
|
|
281
359
|
/** Field-level validation (runs before type-level validator) */
|
|
282
360
|
validator?: ValidatorSpec;
|
|
@@ -297,8 +375,12 @@ interface FieldConfig {
|
|
|
297
375
|
}
|
|
298
376
|
/**
|
|
299
377
|
* FormFieldsConfig - Map of field names to their configurations
|
|
378
|
+
*
|
|
379
|
+
* Generic over the field-name union so a typed `<Form<TFieldValues>>` can reject
|
|
380
|
+
* unknown config keys. Defaults to `string`, which is identical to the previous
|
|
381
|
+
* non-generic `Record<string, FieldConfig>` (backwards compatible).
|
|
300
382
|
*/
|
|
301
|
-
type FormFieldsConfig = Record<
|
|
383
|
+
type FormFieldsConfig<TName extends string = string> = Record<TName, FieldConfig>;
|
|
302
384
|
/**
|
|
303
385
|
* GroupConfig - Configuration for a FieldGroup
|
|
304
386
|
*/
|
|
@@ -334,6 +416,11 @@ interface FormConfig {
|
|
|
334
416
|
* FormalityProviderConfig - Global provider configuration
|
|
335
417
|
*
|
|
336
418
|
* Sets up input types, transformers, validators, and global defaults.
|
|
419
|
+
*
|
|
420
|
+
* Framework agnosticism: `defaultInputTemplate` and `inputTemplates` are
|
|
421
|
+
* intentionally `unknown` here (core cannot import a UI framework). React's
|
|
422
|
+
* `FormalityProviderProps` and `ConfigContextValue` overlay
|
|
423
|
+
* `ComponentType<InputTemplateProps>` on top of these loose fields.
|
|
337
424
|
*/
|
|
338
425
|
interface FormalityProviderConfig {
|
|
339
426
|
/** Input type definitions */
|
|
@@ -359,6 +446,10 @@ interface FormalityProviderConfig {
|
|
|
359
446
|
}
|
|
360
447
|
/**
|
|
361
448
|
* InputTemplateProps - Props passed to input template components
|
|
449
|
+
*
|
|
450
|
+
* Framework agnosticism: `Field` is intentionally `unknown` here. React overlays
|
|
451
|
+
* this same-named type in `@formality-ui/react` with `Field: ComponentType<any>`
|
|
452
|
+
* and RHF-typed `fieldState`/`formState`; React consumers import that overlay.
|
|
362
453
|
*/
|
|
363
454
|
interface InputTemplateProps {
|
|
364
455
|
/** The input component to render */
|
|
@@ -481,6 +572,7 @@ interface FieldStateForContext {
|
|
|
481
572
|
isValidating?: boolean;
|
|
482
573
|
error?: unknown;
|
|
483
574
|
invalid?: boolean;
|
|
575
|
+
disabled?: boolean;
|
|
484
576
|
}
|
|
485
577
|
/**
|
|
486
578
|
* Build a minimal evaluation context from field values
|
|
@@ -500,8 +592,8 @@ declare function buildEvaluationContext(fieldValues: Record<string, unknown>, re
|
|
|
500
592
|
* Extract field names from an expression string
|
|
501
593
|
*
|
|
502
594
|
* Scans the expression for unqualified identifiers that represent field names.
|
|
503
|
-
* Skips JavaScript keywords
|
|
504
|
-
* are only skipped when followed by a dot.
|
|
595
|
+
* Skips JavaScript keywords and identifiers inside string literals.
|
|
596
|
+
* Qualified prefixes (fields, record, props, etc.) are only skipped when followed by a dot.
|
|
505
597
|
*
|
|
506
598
|
* @param expr - Expression string to analyze
|
|
507
599
|
* @returns Array of unique field names referenced
|
|
@@ -512,6 +604,7 @@ declare function buildEvaluationContext(fieldValues: Record<string, unknown>, re
|
|
|
512
604
|
* inferFieldsFromExpression("record.name") // → [] (qualified path)
|
|
513
605
|
* inferFieldsFromExpression("true && false") // → [] (keywords)
|
|
514
606
|
* inferFieldsFromExpression("fields === null") // → ["fields"] (not followed by dot)
|
|
607
|
+
* inferFieldsFromExpression('signed ? "target-on" : "target-off"') // → ["signed"] (string contents skipped)
|
|
515
608
|
*/
|
|
516
609
|
declare function inferFieldsFromExpression(expr: string): string[];
|
|
517
610
|
/**
|
|
@@ -541,6 +634,7 @@ interface FieldStateInput {
|
|
|
541
634
|
isValidating?: boolean;
|
|
542
635
|
error?: unknown;
|
|
543
636
|
invalid?: boolean;
|
|
637
|
+
disabled?: boolean;
|
|
544
638
|
}
|
|
545
639
|
/**
|
|
546
640
|
* Input for condition evaluation
|
|
@@ -589,9 +683,10 @@ declare function evaluateConditions(input: EvaluateConditionsInput): ConditionRe
|
|
|
589
683
|
* @param fieldValues - Map of field names to their current values
|
|
590
684
|
* @param record - Optional record for expression context
|
|
591
685
|
* @param props - Optional props for expression context
|
|
686
|
+
* @param fieldStates - Optional field states for state-based matchers
|
|
592
687
|
* @returns true if the condition matches
|
|
593
688
|
*/
|
|
594
|
-
declare function conditionMatches(condition: ConditionDescriptor, fieldValues: Record<string, unknown>, record?: Record<string, unknown>, props?: Record<string, unknown>): boolean;
|
|
689
|
+
declare function conditionMatches(condition: ConditionDescriptor, fieldValues: Record<string, unknown>, record?: Record<string, unknown>, props?: Record<string, unknown>, fieldStates?: Record<string, FieldStateInput>): boolean;
|
|
595
690
|
/**
|
|
596
691
|
* Merge condition results from multiple sources (e.g., group + field)
|
|
597
692
|
*
|
|
@@ -917,7 +1012,7 @@ declare function deepMerge<T extends object>(base: T, override: Partial<T> | und
|
|
|
917
1012
|
* @param formInputs - Form input configs (or function to transform)
|
|
918
1013
|
* @returns Merged input configs
|
|
919
1014
|
*/
|
|
920
|
-
declare function mergeInputConfigs(providerInputs: Record<string, InputConfig>, formInputs?: FormConfig[
|
|
1015
|
+
declare function mergeInputConfigs(providerInputs: Record<string, InputConfig>, formInputs?: FormConfig["inputs"]): Record<string, InputConfig>;
|
|
921
1016
|
/**
|
|
922
1017
|
* Resolve input config for a specific type
|
|
923
1018
|
*
|
|
@@ -1179,4 +1274,4 @@ declare function getUnusedFields(allFields: string[], declaredFields: Set<string
|
|
|
1179
1274
|
*/
|
|
1180
1275
|
declare function getOrderedUnusedFields(allFields: string[], declaredFields: Set<string>, fieldConfigs: Record<string, FieldConfig>): string[];
|
|
1181
1276
|
|
|
1182
|
-
export { type ConditionDescriptor, type ConditionResult, type ErrorMessagesConfig, type EvaluateConditionsInput, type EvaluationContext, FIELD_PROXY_MARKER, FIELD_PROXY_VALUE, type FieldConfig, type FieldError, type FieldState, type FieldStateInput, type FormConfig, type FormFieldsConfig, type FormState, type FormalityProviderConfig, type FormatterFunction, type FormatterSpec, type FormattersConfig, type GroupConfig, type InputConfig, type InputTemplateProps, KEYWORDS, type ParserFunction, type ParserSpec, type ParsersConfig, QUALIFIED_PREFIXES, type SelectFunction, type SelectValue, type ValidationResult, type ValidatorFactory, type ValidatorFunction, type ValidatorSpec, type ValidatorsConfig, buildEvaluationContext, buildFieldContext, buildFormContext, clearExpressionCache, composeValidators, conditionMatches, createConfigContext, createDefaultFormatters, createDefaultParsers, createErrorMessages, createFieldStateProxy, createFloatFormatter, createFloatParser, createIntParser, createLabelWithUnit, createTrimParser, createValidationError, deepMerge, evaluate, evaluateConditions, evaluateDescriptor, extractValueField, format, formatTypeAsMessage, getErrorType, getInputDefaultValue, getOrderedUnusedFields, getUnusedFields, humanizeLabel, inferFieldsFromConditions, inferFieldsFromDescriptor, inferFieldsFromExpression, isAutoGeneratedLabel, isEmptyValue, isFieldProxy, isValid, maxLength, mergeConditionResults, mergeFieldProps, mergeInputConfigs, mergeRecordWithDefaults, mergeStaticProps, minLength, parse, parseLabelWithUnit, pattern, required, resolveAllInitialValues, resolveErrorMessage, resolveFieldType, resolveFormTitle, resolveInitialValue, resolveInputConfig, resolveLabel, runValidator, runValidatorSync, sortFieldsByOrder, transformFieldName, unwrapFieldProxy };
|
|
1277
|
+
export { type ConditionDescriptor, type ConditionResult, type ErrorMessagesConfig, type EvaluateConditionsInput, type EvaluationContext, FIELD_PROXY_MARKER, FIELD_PROXY_VALUE, type FieldConfig, type FieldError, type FieldState, type FieldStateInput, type FormConfig, type FormFieldsConfig, type FormState, type FormalityProviderConfig, type FormatterFunction, type FormatterSpec, type FormattersConfig, type GroupConfig, type InputConfig, type InputTemplateProps, KEYWORDS, type ParserFunction, type ParserSpec, type ParsersConfig, QUALIFIED_PREFIXES, type SelectFunction, type SelectValue, type ValidationResult, type ValidatorEntry, type ValidatorFactory, type ValidatorFunction, type ValidatorSpec, type ValidatorsConfig, buildEvaluationContext, buildFieldContext, buildFormContext, clearExpressionCache, composeValidators, conditionMatches, createConfigContext, createDefaultFormatters, createDefaultParsers, createErrorMessages, createFieldStateProxy, createFloatFormatter, createFloatParser, createIntParser, createLabelWithUnit, createTrimParser, createValidationError, deepMerge, evaluate, evaluateConditions, evaluateDescriptor, extractValueField, format, formatTypeAsMessage, getErrorType, getInputDefaultValue, getOrderedUnusedFields, getUnusedFields, humanizeLabel, inferFieldsFromConditions, inferFieldsFromDescriptor, inferFieldsFromExpression, isAutoGeneratedLabel, isEmptyValue, isFieldProxy, isValid, maxLength, mergeConditionResults, mergeFieldProps, mergeInputConfigs, mergeRecordWithDefaults, mergeStaticProps, minLength, parse, parseLabelWithUnit, pattern, required, resolveAllInitialValues, resolveErrorMessage, resolveFieldType, resolveFormTitle, resolveInitialValue, resolveInputConfig, resolveLabel, runValidator, runValidatorSync, sortFieldsByOrder, transformFieldName, unwrapFieldProxy };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FieldMatcher - Matchers for a single field in multi-field conditions
|
|
3
|
+
*
|
|
4
|
+
* Used when `when` is an object mapping field names to their matchers.
|
|
5
|
+
* All specified matchers must pass (AND logic).
|
|
6
|
+
*/
|
|
7
|
+
interface FieldMatcher {
|
|
8
|
+
/** Exact value match */
|
|
9
|
+
is?: unknown;
|
|
10
|
+
/** Truthy/falsy check (alias: isTruthy) */
|
|
11
|
+
truthy?: boolean;
|
|
12
|
+
/** Truthy/falsy check (alias for truthy) */
|
|
13
|
+
isTruthy?: boolean;
|
|
14
|
+
/** Field validity check - true if field has no errors */
|
|
15
|
+
isValid?: boolean;
|
|
16
|
+
/** Field disabled state check */
|
|
17
|
+
isDisabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Multi-field when trigger - maps field names to their matchers
|
|
21
|
+
*
|
|
22
|
+
* All field conditions must match (AND logic).
|
|
23
|
+
* Example: { email: { isValid: true }, name: { isTruthy: true } }
|
|
24
|
+
*/
|
|
25
|
+
type WhenMultiField = Record<string, FieldMatcher>;
|
|
1
26
|
/**
|
|
2
27
|
* ConditionDescriptor - Defines a single condition rule
|
|
3
28
|
*
|
|
@@ -7,10 +32,11 @@
|
|
|
7
32
|
*/
|
|
8
33
|
interface ConditionDescriptor {
|
|
9
34
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
35
|
+
* Field reference trigger - can be:
|
|
36
|
+
* - string: Single field reference (e.g., "client")
|
|
37
|
+
* - object: Multi-field with per-field matchers (e.g., { email: { isValid: true }, name: { isTruthy: true } })
|
|
12
38
|
*/
|
|
13
|
-
when?: string;
|
|
39
|
+
when?: string | WhenMultiField;
|
|
14
40
|
/**
|
|
15
41
|
* Expression or function trigger
|
|
16
42
|
* Example: "client.id > 5" or ({ fields }) => fields.client?.value?.id > 5
|
|
@@ -27,6 +53,18 @@ interface ConditionDescriptor {
|
|
|
27
53
|
* false: matches if trigger is falsy
|
|
28
54
|
*/
|
|
29
55
|
truthy?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Field validity check (requires 'when' trigger)
|
|
58
|
+
* true: matches if the 'when' field is valid (no errors)
|
|
59
|
+
* false: matches if the 'when' field is invalid (has errors)
|
|
60
|
+
*/
|
|
61
|
+
isValid?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Field disabled state check (requires 'when' trigger)
|
|
64
|
+
* true: matches if the 'when' field is disabled
|
|
65
|
+
* false: matches if the 'when' field is enabled
|
|
66
|
+
*/
|
|
67
|
+
isDisabled?: boolean;
|
|
30
68
|
/**
|
|
31
69
|
* Set disabled state
|
|
32
70
|
* Multiple conditions use OR logic (any true = disabled)
|
|
@@ -117,16 +155,33 @@ type ValidatorSpec = string | ValidatorFunction | Array<string | ValidatorFuncti
|
|
|
117
155
|
/**
|
|
118
156
|
* ValidatorFactory - Factory function for parameterized validators
|
|
119
157
|
*
|
|
120
|
-
*
|
|
158
|
+
* Accepts any number of factory arguments and returns a {@link ValidatorFunction}.
|
|
159
|
+
* The `...args: any[]` rest signature is intentional: it lets concrete factories
|
|
160
|
+
* with specific parameter types (e.g. `(min: number) => ValidatorFunction`,
|
|
161
|
+
* `(regex: RegExp, message: string) => ValidatorFunction`) be assignable to this
|
|
162
|
+
* type without parameter-invariance errors, while still producing a fully typed
|
|
163
|
+
* `ValidatorFunction` return.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* const min: ValidatorFactory = (minVal: number) => (value) =>
|
|
167
|
+
* Number(value) < minVal ? { type: 'min' } : true;
|
|
168
|
+
*/
|
|
169
|
+
type ValidatorFactory = (...args: any[]) => ValidatorFunction;
|
|
170
|
+
/**
|
|
171
|
+
* ValidatorEntry - A named validator or a validator factory.
|
|
172
|
+
*
|
|
173
|
+
* Either a direct {@link ValidatorFunction} (called with `value` + `formValues`)
|
|
174
|
+
* or a {@link ValidatorFactory} (called with factory args to produce a
|
|
175
|
+
* `ValidatorFunction`).
|
|
121
176
|
*/
|
|
122
|
-
type
|
|
177
|
+
type ValidatorEntry = ValidatorFunction | ValidatorFactory;
|
|
123
178
|
/**
|
|
124
179
|
* ValidatorsConfig - Named validators configuration
|
|
125
180
|
*
|
|
126
|
-
* Values can be direct
|
|
181
|
+
* Values can be direct {@link ValidatorFunction}s or {@link ValidatorFactory}s.
|
|
127
182
|
*/
|
|
128
183
|
interface ValidatorsConfig {
|
|
129
|
-
[name: string]:
|
|
184
|
+
[name: string]: ValidatorEntry;
|
|
130
185
|
}
|
|
131
186
|
/**
|
|
132
187
|
* ErrorMessagesConfig - Error message templates by type key
|
|
@@ -164,6 +219,8 @@ interface FieldState {
|
|
|
164
219
|
error?: FieldError;
|
|
165
220
|
/** Inverse of valid state for convenience */
|
|
166
221
|
invalid: boolean;
|
|
222
|
+
/** Whether the field is disabled */
|
|
223
|
+
disabled?: boolean;
|
|
167
224
|
/** Map of subscriber field names watching this field */
|
|
168
225
|
watchers?: Record<string, boolean>;
|
|
169
226
|
}
|
|
@@ -230,9 +287,24 @@ type SelectFunction<TReturn = unknown> = (formState: FormState, methods: unknown
|
|
|
230
287
|
*
|
|
231
288
|
* This defines how a particular input type (e.g., textField, switch, autocomplete)
|
|
232
289
|
* behaves across all forms.
|
|
290
|
+
*
|
|
291
|
+
* Framework agnosticism: `component` and `template` are intentionally `unknown`
|
|
292
|
+
* here (core cannot import a UI framework). React consumers should use the
|
|
293
|
+
* `ReactInputConfig<TValue>` overlay exported from `@formality-ui/react`, which
|
|
294
|
+
* narrows both to `ComponentType<...>`.
|
|
295
|
+
*
|
|
296
|
+
* `TValue` (default `unknown`) links `defaultValue`, `parser`, and `formatter`
|
|
297
|
+
* to a single value type. It defaults to `unknown` because the framework-agnostic
|
|
298
|
+
* core cannot know the value type of every UI component; React consumers can
|
|
299
|
+
* parameterize it via `ReactInputConfig<TValue>` (e.g.
|
|
300
|
+
* `ReactInputConfig<string>` for a text field). Today only the overlay exposes
|
|
301
|
+
* this parameterization; end-to-end per-input value inference is a future
|
|
302
|
+
* enhancement.
|
|
303
|
+
*
|
|
304
|
+
* @template TValue - The form value type this input produces/consumes.
|
|
233
305
|
*/
|
|
234
306
|
interface InputConfig<TValue = unknown> {
|
|
235
|
-
/** The
|
|
307
|
+
/** The component to render (typed `unknown` for framework agnosticism; React consumers see `ComponentType<any>` via `ReactInputConfig`) */
|
|
236
308
|
component: unknown;
|
|
237
309
|
/** Default value for this input type (e.g., '' for text, false for switch) */
|
|
238
310
|
defaultValue: TValue;
|
|
@@ -250,7 +322,7 @@ interface InputConfig<TValue = unknown> {
|
|
|
250
322
|
formatter?: string | ((value: TValue) => unknown);
|
|
251
323
|
/** Type-level validation (runs after field-level validator) */
|
|
252
324
|
validator?: ValidatorSpec;
|
|
253
|
-
/** Template component wrapper for consistent styling */
|
|
325
|
+
/** Template component wrapper for consistent styling (typed `unknown` for framework agnosticism; React consumers see `ComponentType<InputTemplateProps>` via `ReactInputConfig`) */
|
|
254
326
|
template?: unknown;
|
|
255
327
|
/** Default props for this input type */
|
|
256
328
|
props?: Record<string, unknown>;
|
|
@@ -260,6 +332,12 @@ interface InputConfig<TValue = unknown> {
|
|
|
260
332
|
*
|
|
261
333
|
* This defines field-level behavior including conditions, validation,
|
|
262
334
|
* and dynamic props.
|
|
335
|
+
*
|
|
336
|
+
* Framework agnosticism: `rules` is intentionally `Record<string, unknown>` here
|
|
337
|
+
* (core cannot import react-hook-form). React consumers should use the
|
|
338
|
+
* `ReactFieldConfig` overlay exported from `@formality-ui/react`, which narrows
|
|
339
|
+
* `rules` to react-hook-form's `RegisterOptions` for full autocomplete and
|
|
340
|
+
* checking (required, min, max, pattern, validate, valueAsNumber, …).
|
|
263
341
|
*/
|
|
264
342
|
interface FieldConfig {
|
|
265
343
|
/** Input type key (resolves to InputConfig) */
|
|
@@ -276,7 +354,7 @@ interface FieldConfig {
|
|
|
276
354
|
order?: number;
|
|
277
355
|
/** Key to use when reading initial value from record (defaults to field name) */
|
|
278
356
|
recordKey?: string;
|
|
279
|
-
/**
|
|
357
|
+
/** Register options forwarded to the framework's field register call (typed loose for framework agnosticism; React consumers see react-hook-form's `RegisterOptions` via `ReactFieldConfig`) */
|
|
280
358
|
rules?: Record<string, unknown>;
|
|
281
359
|
/** Field-level validation (runs before type-level validator) */
|
|
282
360
|
validator?: ValidatorSpec;
|
|
@@ -297,8 +375,12 @@ interface FieldConfig {
|
|
|
297
375
|
}
|
|
298
376
|
/**
|
|
299
377
|
* FormFieldsConfig - Map of field names to their configurations
|
|
378
|
+
*
|
|
379
|
+
* Generic over the field-name union so a typed `<Form<TFieldValues>>` can reject
|
|
380
|
+
* unknown config keys. Defaults to `string`, which is identical to the previous
|
|
381
|
+
* non-generic `Record<string, FieldConfig>` (backwards compatible).
|
|
300
382
|
*/
|
|
301
|
-
type FormFieldsConfig = Record<
|
|
383
|
+
type FormFieldsConfig<TName extends string = string> = Record<TName, FieldConfig>;
|
|
302
384
|
/**
|
|
303
385
|
* GroupConfig - Configuration for a FieldGroup
|
|
304
386
|
*/
|
|
@@ -334,6 +416,11 @@ interface FormConfig {
|
|
|
334
416
|
* FormalityProviderConfig - Global provider configuration
|
|
335
417
|
*
|
|
336
418
|
* Sets up input types, transformers, validators, and global defaults.
|
|
419
|
+
*
|
|
420
|
+
* Framework agnosticism: `defaultInputTemplate` and `inputTemplates` are
|
|
421
|
+
* intentionally `unknown` here (core cannot import a UI framework). React's
|
|
422
|
+
* `FormalityProviderProps` and `ConfigContextValue` overlay
|
|
423
|
+
* `ComponentType<InputTemplateProps>` on top of these loose fields.
|
|
337
424
|
*/
|
|
338
425
|
interface FormalityProviderConfig {
|
|
339
426
|
/** Input type definitions */
|
|
@@ -359,6 +446,10 @@ interface FormalityProviderConfig {
|
|
|
359
446
|
}
|
|
360
447
|
/**
|
|
361
448
|
* InputTemplateProps - Props passed to input template components
|
|
449
|
+
*
|
|
450
|
+
* Framework agnosticism: `Field` is intentionally `unknown` here. React overlays
|
|
451
|
+
* this same-named type in `@formality-ui/react` with `Field: ComponentType<any>`
|
|
452
|
+
* and RHF-typed `fieldState`/`formState`; React consumers import that overlay.
|
|
362
453
|
*/
|
|
363
454
|
interface InputTemplateProps {
|
|
364
455
|
/** The input component to render */
|
|
@@ -481,6 +572,7 @@ interface FieldStateForContext {
|
|
|
481
572
|
isValidating?: boolean;
|
|
482
573
|
error?: unknown;
|
|
483
574
|
invalid?: boolean;
|
|
575
|
+
disabled?: boolean;
|
|
484
576
|
}
|
|
485
577
|
/**
|
|
486
578
|
* Build a minimal evaluation context from field values
|
|
@@ -500,8 +592,8 @@ declare function buildEvaluationContext(fieldValues: Record<string, unknown>, re
|
|
|
500
592
|
* Extract field names from an expression string
|
|
501
593
|
*
|
|
502
594
|
* Scans the expression for unqualified identifiers that represent field names.
|
|
503
|
-
* Skips JavaScript keywords
|
|
504
|
-
* are only skipped when followed by a dot.
|
|
595
|
+
* Skips JavaScript keywords and identifiers inside string literals.
|
|
596
|
+
* Qualified prefixes (fields, record, props, etc.) are only skipped when followed by a dot.
|
|
505
597
|
*
|
|
506
598
|
* @param expr - Expression string to analyze
|
|
507
599
|
* @returns Array of unique field names referenced
|
|
@@ -512,6 +604,7 @@ declare function buildEvaluationContext(fieldValues: Record<string, unknown>, re
|
|
|
512
604
|
* inferFieldsFromExpression("record.name") // → [] (qualified path)
|
|
513
605
|
* inferFieldsFromExpression("true && false") // → [] (keywords)
|
|
514
606
|
* inferFieldsFromExpression("fields === null") // → ["fields"] (not followed by dot)
|
|
607
|
+
* inferFieldsFromExpression('signed ? "target-on" : "target-off"') // → ["signed"] (string contents skipped)
|
|
515
608
|
*/
|
|
516
609
|
declare function inferFieldsFromExpression(expr: string): string[];
|
|
517
610
|
/**
|
|
@@ -541,6 +634,7 @@ interface FieldStateInput {
|
|
|
541
634
|
isValidating?: boolean;
|
|
542
635
|
error?: unknown;
|
|
543
636
|
invalid?: boolean;
|
|
637
|
+
disabled?: boolean;
|
|
544
638
|
}
|
|
545
639
|
/**
|
|
546
640
|
* Input for condition evaluation
|
|
@@ -589,9 +683,10 @@ declare function evaluateConditions(input: EvaluateConditionsInput): ConditionRe
|
|
|
589
683
|
* @param fieldValues - Map of field names to their current values
|
|
590
684
|
* @param record - Optional record for expression context
|
|
591
685
|
* @param props - Optional props for expression context
|
|
686
|
+
* @param fieldStates - Optional field states for state-based matchers
|
|
592
687
|
* @returns true if the condition matches
|
|
593
688
|
*/
|
|
594
|
-
declare function conditionMatches(condition: ConditionDescriptor, fieldValues: Record<string, unknown>, record?: Record<string, unknown>, props?: Record<string, unknown>): boolean;
|
|
689
|
+
declare function conditionMatches(condition: ConditionDescriptor, fieldValues: Record<string, unknown>, record?: Record<string, unknown>, props?: Record<string, unknown>, fieldStates?: Record<string, FieldStateInput>): boolean;
|
|
595
690
|
/**
|
|
596
691
|
* Merge condition results from multiple sources (e.g., group + field)
|
|
597
692
|
*
|
|
@@ -917,7 +1012,7 @@ declare function deepMerge<T extends object>(base: T, override: Partial<T> | und
|
|
|
917
1012
|
* @param formInputs - Form input configs (or function to transform)
|
|
918
1013
|
* @returns Merged input configs
|
|
919
1014
|
*/
|
|
920
|
-
declare function mergeInputConfigs(providerInputs: Record<string, InputConfig>, formInputs?: FormConfig[
|
|
1015
|
+
declare function mergeInputConfigs(providerInputs: Record<string, InputConfig>, formInputs?: FormConfig["inputs"]): Record<string, InputConfig>;
|
|
921
1016
|
/**
|
|
922
1017
|
* Resolve input config for a specific type
|
|
923
1018
|
*
|
|
@@ -1179,4 +1274,4 @@ declare function getUnusedFields(allFields: string[], declaredFields: Set<string
|
|
|
1179
1274
|
*/
|
|
1180
1275
|
declare function getOrderedUnusedFields(allFields: string[], declaredFields: Set<string>, fieldConfigs: Record<string, FieldConfig>): string[];
|
|
1181
1276
|
|
|
1182
|
-
export { type ConditionDescriptor, type ConditionResult, type ErrorMessagesConfig, type EvaluateConditionsInput, type EvaluationContext, FIELD_PROXY_MARKER, FIELD_PROXY_VALUE, type FieldConfig, type FieldError, type FieldState, type FieldStateInput, type FormConfig, type FormFieldsConfig, type FormState, type FormalityProviderConfig, type FormatterFunction, type FormatterSpec, type FormattersConfig, type GroupConfig, type InputConfig, type InputTemplateProps, KEYWORDS, type ParserFunction, type ParserSpec, type ParsersConfig, QUALIFIED_PREFIXES, type SelectFunction, type SelectValue, type ValidationResult, type ValidatorFactory, type ValidatorFunction, type ValidatorSpec, type ValidatorsConfig, buildEvaluationContext, buildFieldContext, buildFormContext, clearExpressionCache, composeValidators, conditionMatches, createConfigContext, createDefaultFormatters, createDefaultParsers, createErrorMessages, createFieldStateProxy, createFloatFormatter, createFloatParser, createIntParser, createLabelWithUnit, createTrimParser, createValidationError, deepMerge, evaluate, evaluateConditions, evaluateDescriptor, extractValueField, format, formatTypeAsMessage, getErrorType, getInputDefaultValue, getOrderedUnusedFields, getUnusedFields, humanizeLabel, inferFieldsFromConditions, inferFieldsFromDescriptor, inferFieldsFromExpression, isAutoGeneratedLabel, isEmptyValue, isFieldProxy, isValid, maxLength, mergeConditionResults, mergeFieldProps, mergeInputConfigs, mergeRecordWithDefaults, mergeStaticProps, minLength, parse, parseLabelWithUnit, pattern, required, resolveAllInitialValues, resolveErrorMessage, resolveFieldType, resolveFormTitle, resolveInitialValue, resolveInputConfig, resolveLabel, runValidator, runValidatorSync, sortFieldsByOrder, transformFieldName, unwrapFieldProxy };
|
|
1277
|
+
export { type ConditionDescriptor, type ConditionResult, type ErrorMessagesConfig, type EvaluateConditionsInput, type EvaluationContext, FIELD_PROXY_MARKER, FIELD_PROXY_VALUE, type FieldConfig, type FieldError, type FieldState, type FieldStateInput, type FormConfig, type FormFieldsConfig, type FormState, type FormalityProviderConfig, type FormatterFunction, type FormatterSpec, type FormattersConfig, type GroupConfig, type InputConfig, type InputTemplateProps, KEYWORDS, type ParserFunction, type ParserSpec, type ParsersConfig, QUALIFIED_PREFIXES, type SelectFunction, type SelectValue, type ValidationResult, type ValidatorEntry, type ValidatorFactory, type ValidatorFunction, type ValidatorSpec, type ValidatorsConfig, buildEvaluationContext, buildFieldContext, buildFormContext, clearExpressionCache, composeValidators, conditionMatches, createConfigContext, createDefaultFormatters, createDefaultParsers, createErrorMessages, createFieldStateProxy, createFloatFormatter, createFloatParser, createIntParser, createLabelWithUnit, createTrimParser, createValidationError, deepMerge, evaluate, evaluateConditions, evaluateDescriptor, extractValueField, format, formatTypeAsMessage, getErrorType, getInputDefaultValue, getOrderedUnusedFields, getUnusedFields, humanizeLabel, inferFieldsFromConditions, inferFieldsFromDescriptor, inferFieldsFromExpression, isAutoGeneratedLabel, isEmptyValue, isFieldProxy, isValid, maxLength, mergeConditionResults, mergeFieldProps, mergeInputConfigs, mergeRecordWithDefaults, mergeStaticProps, minLength, parse, parseLabelWithUnit, pattern, required, resolveAllInitialValues, resolveErrorMessage, resolveFieldType, resolveFormTitle, resolveInitialValue, resolveInputConfig, resolveLabel, runValidator, runValidatorSync, sortFieldsByOrder, transformFieldName, unwrapFieldProxy };
|