foorm 0.2.0 → 0.2.2
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 +12 -1
- package/dist/index.cjs +16 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.mjs +16 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,7 +73,9 @@ const passwordField: TFoormField = {
|
|
|
73
73
|
type: 'password',
|
|
74
74
|
label: 'Password',
|
|
75
75
|
optional: false,
|
|
76
|
+
disabled: false,
|
|
76
77
|
hidden: false,
|
|
78
|
+
readonly: false,
|
|
77
79
|
|
|
78
80
|
// Static placeholder
|
|
79
81
|
placeholder: 'Enter a strong password',
|
|
@@ -85,6 +87,12 @@ const passwordField: TFoormField = {
|
|
|
85
87
|
hint: scope =>
|
|
86
88
|
scope.v ? `${8 - String(scope.v).length} more characters needed` : 'At least 8 characters',
|
|
87
89
|
|
|
90
|
+
// Custom attributes for testing or accessibility
|
|
91
|
+
attrs: {
|
|
92
|
+
'data-testid': 'password-input',
|
|
93
|
+
'aria-describedby': scope => scope.data.name ? 'password-requirements' : undefined,
|
|
94
|
+
},
|
|
95
|
+
|
|
88
96
|
validators: [
|
|
89
97
|
s => !!s.v || 'Password is required',
|
|
90
98
|
s => String(s.v).length >= 8 || 'At least 8 characters',
|
|
@@ -228,15 +236,18 @@ A single field definition. All description and constraint properties support `TC
|
|
|
228
236
|
| `optional` | `TComputed<boolean>` | Whether the field is optional |
|
|
229
237
|
| `disabled` | `TComputed<boolean>` | Whether the field is disabled |
|
|
230
238
|
| `hidden` | `TComputed<boolean>` | Whether the field is hidden |
|
|
239
|
+
| `readonly` | `TComputed<boolean>` | Whether the field is read-only (visible but not editable) |
|
|
231
240
|
| `classes` | `TComputed<string \| Record<string, boolean>>` | CSS classes |
|
|
232
241
|
| `styles` | `TComputed<string \| Record<string, string>>` | Inline styles |
|
|
233
242
|
| `options` | `TComputed<TFoormEntryOptions[]>` | Options for select/radio fields |
|
|
243
|
+
| `value` | `TComputed<unknown>` | Default or computed value |
|
|
244
|
+
| `attrs` | `Record<string, TComputed<unknown>>` | Custom attributes passed to field components |
|
|
234
245
|
| `validators` | `Array<(scope) => boolean \| string>` | Validation functions |
|
|
235
246
|
| `component` | `string` | Named component override |
|
|
236
247
|
| `autocomplete` | `string` | HTML autocomplete attribute |
|
|
237
248
|
| `altAction` | `string` | Alternate submit action name |
|
|
238
249
|
| `order` | `number` | Rendering order |
|
|
239
|
-
| `
|
|
250
|
+
| `name` | `string` | Field name (defaults to field identifier) |
|
|
240
251
|
| `maxLength` | `number` | HTML maxlength constraint |
|
|
241
252
|
| `minLength` | `number` | HTML minlength constraint |
|
|
242
253
|
| `min` | `number` | HTML min constraint |
|
package/dist/index.cjs
CHANGED
|
@@ -27,13 +27,26 @@ const NON_DATA_TYPES = new Set(['action', 'paragraph']);
|
|
|
27
27
|
/**
|
|
28
28
|
* Creates initial form data from field default values.
|
|
29
29
|
* Skips non-data field types (action, paragraph).
|
|
30
|
+
* Evaluates computed default values with empty scope.
|
|
30
31
|
*/
|
|
31
32
|
function createFormData(fields) {
|
|
32
33
|
var _a;
|
|
33
34
|
const data = {};
|
|
34
35
|
for (const f of fields) {
|
|
35
36
|
if (!NON_DATA_TYPES.has(f.type)) {
|
|
36
|
-
|
|
37
|
+
// Evaluate default value with minimal scope (data will be populated as we go)
|
|
38
|
+
const scope = {
|
|
39
|
+
v: undefined,
|
|
40
|
+
data,
|
|
41
|
+
context: {},
|
|
42
|
+
entry: {
|
|
43
|
+
field: f.field,
|
|
44
|
+
type: f.type,
|
|
45
|
+
component: f.component,
|
|
46
|
+
name: f.name || f.field,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
data[f.field] = (_a = evalComputed(f.value, scope)) !== null && _a !== void 0 ? _a : undefined;
|
|
37
50
|
}
|
|
38
51
|
}
|
|
39
52
|
return data;
|
|
@@ -67,6 +80,8 @@ function getFormValidator(model, context) {
|
|
|
67
80
|
entry.disabled = evalComputed(f.disabled, scope);
|
|
68
81
|
entry.optional = evalComputed(f.optional, scope);
|
|
69
82
|
entry.hidden = evalComputed(f.hidden, scope);
|
|
83
|
+
entry.readonly = evalComputed(f.readonly, scope);
|
|
84
|
+
entry.options = evalComputed(f.options, scope);
|
|
70
85
|
// Skip disabled and hidden fields
|
|
71
86
|
if (entry.disabled || entry.hidden) {
|
|
72
87
|
continue;
|
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ interface TFoormFieldEvaluated {
|
|
|
26
26
|
disabled?: boolean;
|
|
27
27
|
optional?: boolean;
|
|
28
28
|
hidden?: boolean;
|
|
29
|
+
readonly?: boolean;
|
|
30
|
+
options?: TFoormEntryOptions[];
|
|
29
31
|
}
|
|
30
32
|
type TFoormEntryOptions = {
|
|
31
33
|
key: string;
|
|
@@ -49,11 +51,12 @@ interface TFoormField {
|
|
|
49
51
|
optional: TComputed<boolean>;
|
|
50
52
|
disabled: TComputed<boolean>;
|
|
51
53
|
hidden: TComputed<boolean>;
|
|
54
|
+
readonly: TComputed<boolean>;
|
|
52
55
|
classes?: TComputed<string | Record<string, boolean>>;
|
|
53
56
|
styles?: TComputed<string | Record<string, string>>;
|
|
54
57
|
options?: TComputed<TFoormEntryOptions[]>;
|
|
55
58
|
attrs?: Record<string, TComputed<unknown>>;
|
|
56
|
-
value?: unknown
|
|
59
|
+
value?: TComputed<unknown>;
|
|
57
60
|
validators: Array<(scope: TFoormFnScope) => boolean | string>;
|
|
58
61
|
maxLength?: number;
|
|
59
62
|
minLength?: number;
|
|
@@ -88,6 +91,7 @@ declare function validate(validators: TFoormField['validators'], scope: TFoormFn
|
|
|
88
91
|
/**
|
|
89
92
|
* Creates initial form data from field default values.
|
|
90
93
|
* Skips non-data field types (action, paragraph).
|
|
94
|
+
* Evaluates computed default values with empty scope.
|
|
91
95
|
*/
|
|
92
96
|
declare function createFormData<T = Record<string, unknown>>(fields: TFoormField[]): T;
|
|
93
97
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -25,13 +25,26 @@ const NON_DATA_TYPES = new Set(['action', 'paragraph']);
|
|
|
25
25
|
/**
|
|
26
26
|
* Creates initial form data from field default values.
|
|
27
27
|
* Skips non-data field types (action, paragraph).
|
|
28
|
+
* Evaluates computed default values with empty scope.
|
|
28
29
|
*/
|
|
29
30
|
function createFormData(fields) {
|
|
30
31
|
var _a;
|
|
31
32
|
const data = {};
|
|
32
33
|
for (const f of fields) {
|
|
33
34
|
if (!NON_DATA_TYPES.has(f.type)) {
|
|
34
|
-
|
|
35
|
+
// Evaluate default value with minimal scope (data will be populated as we go)
|
|
36
|
+
const scope = {
|
|
37
|
+
v: undefined,
|
|
38
|
+
data,
|
|
39
|
+
context: {},
|
|
40
|
+
entry: {
|
|
41
|
+
field: f.field,
|
|
42
|
+
type: f.type,
|
|
43
|
+
component: f.component,
|
|
44
|
+
name: f.name || f.field,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
data[f.field] = (_a = evalComputed(f.value, scope)) !== null && _a !== void 0 ? _a : undefined;
|
|
35
48
|
}
|
|
36
49
|
}
|
|
37
50
|
return data;
|
|
@@ -65,6 +78,8 @@ function getFormValidator(model, context) {
|
|
|
65
78
|
entry.disabled = evalComputed(f.disabled, scope);
|
|
66
79
|
entry.optional = evalComputed(f.optional, scope);
|
|
67
80
|
entry.hidden = evalComputed(f.hidden, scope);
|
|
81
|
+
entry.readonly = evalComputed(f.readonly, scope);
|
|
82
|
+
entry.options = evalComputed(f.options, scope);
|
|
68
83
|
// Skip disabled and hidden fields
|
|
69
84
|
if (entry.disabled || entry.hidden) {
|
|
70
85
|
continue;
|