@rokkit/forms 1.8.0 → 1.8.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 +7 -2
- package/dist/lib/fields.js +14 -1
- package/dist/lib/schema.d.ts +12 -0
- package/dist/lib/schema.js +19 -0
- package/dist/lib/validation.js +14 -4
- package/package.json +1 -1
- package/dist/lib/conditions.spec.d.ts +0 -1
- package/dist/lib/conditions.spec.js +0 -58
- package/dist/lib/fields.spec.d.ts +0 -1
- package/dist/lib/fields.spec.js +0 -250
- package/dist/lib/fixtures/combined-schema-layout.json +0 -64
- package/dist/lib/fixtures/input-layout.json +0 -68
- package/dist/lib/fixtures/input-schema.json +0 -16
- package/dist/lib/fixtures/result-with-generated-layout.json +0 -64
- package/dist/lib/fixtures/result-with-generated-schema.json +0 -60
- package/dist/lib/fixtures/result-with-only-data.json +0 -60
package/README.md
CHANGED
|
@@ -86,10 +86,15 @@ form.isDirty // any field changed
|
|
|
86
86
|
```js
|
|
87
87
|
import { validateField, validateAll, patterns } from '@rokkit/forms'
|
|
88
88
|
|
|
89
|
-
const result = validateField(
|
|
90
|
-
// result → { state: 'error', text: '
|
|
89
|
+
const result = validateField('bad', { type: 'string', required: true, pattern: patterns.email }, 'Email')
|
|
90
|
+
// result → { state: 'error', text: 'Email format is invalid' } — null when valid
|
|
91
|
+
// Rules are checked per `type`: without one, only `required` applies.
|
|
91
92
|
```
|
|
92
93
|
|
|
94
|
+
A field is required when it says `required: true`, or when its parent object lists it, the
|
|
95
|
+
JSON Schema way (`{ type: 'object', required: ['email'], properties: { email } }`), at any depth.
|
|
96
|
+
`validateAll` / `form.validate()` and the rendered input's `required` attribute honour both.
|
|
97
|
+
|
|
93
98
|
### Dependent lookups with createLookup
|
|
94
99
|
|
|
95
100
|
`createLookup` creates a reactive dropdown data source that can depend on other field values:
|
package/dist/lib/fields.js
CHANGED
|
@@ -75,9 +75,11 @@ export function findAttributeByPath(scope, schema) {
|
|
|
75
75
|
|
|
76
76
|
const pathArray = scope.split('/').slice(1)
|
|
77
77
|
let schemaPointer = schema
|
|
78
|
+
let parent = null
|
|
78
79
|
let currentKey = ''
|
|
79
80
|
|
|
80
81
|
pathArray.forEach((key) => {
|
|
82
|
+
parent = schemaPointer
|
|
81
83
|
schemaPointer = schemaPointer.properties[key]
|
|
82
84
|
currentKey = key
|
|
83
85
|
})
|
|
@@ -86,10 +88,21 @@ export function findAttributeByPath(scope, schema) {
|
|
|
86
88
|
|
|
87
89
|
return {
|
|
88
90
|
key: currentKey,
|
|
89
|
-
props:
|
|
91
|
+
props: requiredProps(schemaPointer, parent, currentKey)
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
|
|
95
|
+
/**
|
|
96
|
+
* A field's props with `required` as the input reads it: true when the field says so or its
|
|
97
|
+
* parent's JSON Schema `required` list names it. An object's own list is its children's rule —
|
|
98
|
+
* dropped here so it never reaches an input as a truthy `required`.
|
|
99
|
+
*/
|
|
100
|
+
function requiredProps(fieldSchema, parent, key) {
|
|
101
|
+
const { required, ...props } = fieldSchema
|
|
102
|
+
const listed = Array.isArray(parent?.required) && parent.required.includes(key)
|
|
103
|
+
return required === true || listed ? { ...props, required: true } : props
|
|
104
|
+
}
|
|
105
|
+
|
|
93
106
|
/**
|
|
94
107
|
* Combines an element from layout with schema
|
|
95
108
|
*
|
package/dist/lib/schema.d.ts
CHANGED
|
@@ -18,3 +18,15 @@ export function deriveSchemaFromValue(data: any): import("../types").DataSchema;
|
|
|
18
18
|
* @returns {Object | null}
|
|
19
19
|
*/
|
|
20
20
|
export function schemaAt(schema: Object | null | undefined, path: string): Object | null;
|
|
21
|
+
/**
|
|
22
|
+
* Whether the field at a slash path must have a value.
|
|
23
|
+
*
|
|
24
|
+
* JSON Schema states it on the PARENT object — `{ type: 'object', required: ['city'], … }` — at
|
|
25
|
+
* any depth. The field-level `required: true` form is also honoured. An object's own `required`
|
|
26
|
+
* array is its children's rule, never a claim that the object itself is required.
|
|
27
|
+
*
|
|
28
|
+
* @param {Object | null | undefined} schema
|
|
29
|
+
* @param {string} path
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
export function requiredAt(schema: Object | null | undefined, path: string): boolean;
|
package/dist/lib/schema.js
CHANGED
|
@@ -56,3 +56,22 @@ export function schemaAt(schema, path) {
|
|
|
56
56
|
for (const key of path.split('/').slice(1)) current = childSchema(current, key)
|
|
57
57
|
return isSchemaObject(current) ? current : null
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether the field at a slash path must have a value.
|
|
62
|
+
*
|
|
63
|
+
* JSON Schema states it on the PARENT object — `{ type: 'object', required: ['city'], … }` — at
|
|
64
|
+
* any depth. The field-level `required: true` form is also honoured. An object's own `required`
|
|
65
|
+
* array is its children's rule, never a claim that the object itself is required.
|
|
66
|
+
*
|
|
67
|
+
* @param {Object | null | undefined} schema
|
|
68
|
+
* @param {string} path
|
|
69
|
+
* @returns {boolean}
|
|
70
|
+
*/
|
|
71
|
+
export function requiredAt(schema, path) {
|
|
72
|
+
if (schemaAt(schema, path)?.required === true) return true
|
|
73
|
+
const keys = path.split('/')
|
|
74
|
+
const key = keys.pop()
|
|
75
|
+
const parent = keys.length > 0 ? schemaAt(schema, keys.join('/')) : schema
|
|
76
|
+
return Array.isArray(parent?.required) && parent.required.includes(key)
|
|
77
|
+
}
|
package/dist/lib/validation.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { schemaAt } from './schema.js'
|
|
1
|
+
import { schemaAt, requiredAt } from './schema.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Validation utility for FormBuilder
|
|
@@ -223,7 +223,8 @@ function validateByType(value, fieldSchema, fieldLabel) {
|
|
|
223
223
|
* @returns {ValidationMessage|null|'skip'}
|
|
224
224
|
*/
|
|
225
225
|
function checkPresence(value, fieldSchema, fieldLabel) {
|
|
226
|
-
|
|
226
|
+
// `=== true`: an object schema's `required` is an ARRAY naming its children, not a flag.
|
|
227
|
+
if (fieldSchema.required === true && isEmpty(value)) return errorMsg(`${fieldLabel} is required`)
|
|
227
228
|
if (isEmpty(value)) return 'skip'
|
|
228
229
|
return null
|
|
229
230
|
}
|
|
@@ -243,6 +244,16 @@ export function validateField(value, fieldSchema, fieldLabel = 'Field') {
|
|
|
243
244
|
return validateByType(value, fieldSchema, fieldLabel)
|
|
244
245
|
}
|
|
245
246
|
|
|
247
|
+
/**
|
|
248
|
+
* The field's schema with `required` decided by its path — the parent's JSON Schema `required`
|
|
249
|
+
* list counts, not only the field's own flag. Null for a path the schema does not know.
|
|
250
|
+
* @private
|
|
251
|
+
*/
|
|
252
|
+
function effectiveSchema(schema, path) {
|
|
253
|
+
const fieldSchema = schemaAt(schema, path)
|
|
254
|
+
return fieldSchema && { ...fieldSchema, required: requiredAt(schema, path) }
|
|
255
|
+
}
|
|
256
|
+
|
|
246
257
|
/**
|
|
247
258
|
* Validate one element from the layout
|
|
248
259
|
* @private
|
|
@@ -253,11 +264,10 @@ function validateElement(element, data, schema, results) {
|
|
|
253
264
|
if (!element.scope) return
|
|
254
265
|
|
|
255
266
|
const fieldPath = element.scope.replace(/^#\//, '')
|
|
256
|
-
const fieldSchema = schemaAt(schema, fieldPath)
|
|
257
267
|
const fieldLabel = element.label || element.title || fieldPath
|
|
258
268
|
const value = getValueByPath(data, fieldPath)
|
|
259
269
|
|
|
260
|
-
const result = validateField(value,
|
|
270
|
+
const result = validateField(value, effectiveSchema(schema, fieldPath), fieldLabel)
|
|
261
271
|
if (result) {
|
|
262
272
|
results[fieldPath] = result
|
|
263
273
|
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { evaluateCondition } from './conditions.js'
|
|
3
|
-
|
|
4
|
-
describe('evaluateCondition', () => {
|
|
5
|
-
it('returns true when condition is null', () => {
|
|
6
|
-
expect(evaluateCondition(null, { accountType: 'personal' })).toBe(true)
|
|
7
|
-
})
|
|
8
|
-
|
|
9
|
-
it('returns true when condition is undefined', () => {
|
|
10
|
-
expect(evaluateCondition(undefined, { accountType: 'personal' })).toBe(true)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('returns true when neither operator is set', () => {
|
|
14
|
-
expect(evaluateCondition({ field: 'accountType' }, { accountType: 'business' })).toBe(true)
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
describe('equals operator', () => {
|
|
18
|
-
it('returns true when value matches', () => {
|
|
19
|
-
expect(
|
|
20
|
-
evaluateCondition({ field: 'accountType', equals: 'business' }, { accountType: 'business' })
|
|
21
|
-
).toBe(true)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('returns false when value does not match', () => {
|
|
25
|
-
expect(
|
|
26
|
-
evaluateCondition({ field: 'accountType', equals: 'business' }, { accountType: 'personal' })
|
|
27
|
-
).toBe(false)
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
it('returns false when field is absent (undefined)', () => {
|
|
31
|
-
expect(evaluateCondition({ field: 'accountType', equals: 'business' }, {})).toBe(false)
|
|
32
|
-
})
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
describe('notEquals operator', () => {
|
|
36
|
-
it('returns true when value does not match', () => {
|
|
37
|
-
expect(
|
|
38
|
-
evaluateCondition(
|
|
39
|
-
{ field: 'accountType', notEquals: 'business' },
|
|
40
|
-
{ accountType: 'personal' }
|
|
41
|
-
)
|
|
42
|
-
).toBe(true)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('returns false when value matches', () => {
|
|
46
|
-
expect(
|
|
47
|
-
evaluateCondition(
|
|
48
|
-
{ field: 'accountType', notEquals: 'business' },
|
|
49
|
-
{ accountType: 'business' }
|
|
50
|
-
)
|
|
51
|
-
).toBe(false)
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('returns true when field is absent (undefined !== value)', () => {
|
|
55
|
-
expect(evaluateCondition({ field: 'accountType', notEquals: 'business' }, {})).toBe(true)
|
|
56
|
-
})
|
|
57
|
-
})
|
|
58
|
-
})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/lib/fields.spec.js
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { deriveSchemaFromValue } from './schema.js'
|
|
3
|
-
import { deriveLayoutFromValue } from './layout.js'
|
|
4
|
-
import { findAttributeByPath, getSchemaWithLayout } from './fields.js'
|
|
5
|
-
|
|
6
|
-
import inputLayout from './fixtures/input-layout.json'
|
|
7
|
-
import inputSchema from './fixtures/input-schema.json'
|
|
8
|
-
import resultWithGeneratedSchema from './fixtures/result-with-generated-schema.json'
|
|
9
|
-
import resultWithGeneratedLayout from './fixtures/result-with-generated-layout.json'
|
|
10
|
-
import combinedSchemaLayout from './fixtures/combined-schema-layout.json'
|
|
11
|
-
import resultWithOnlyData from './fixtures/result-with-only-data.json'
|
|
12
|
-
|
|
13
|
-
describe('fields', () => {
|
|
14
|
-
describe('findAttributeByPath', () => {
|
|
15
|
-
it('should find attribute from path', () => {
|
|
16
|
-
const schema = {
|
|
17
|
-
type: 'object',
|
|
18
|
-
properties: {
|
|
19
|
-
name: { type: 'string' },
|
|
20
|
-
age: { type: 'integer', min: 0, max: 100 }
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
let attribute = findAttributeByPath('#/name', schema)
|
|
24
|
-
expect(attribute).toEqual({
|
|
25
|
-
key: 'name',
|
|
26
|
-
props: {
|
|
27
|
-
type: 'string'
|
|
28
|
-
}
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
attribute = findAttributeByPath('#/age', schema)
|
|
32
|
-
expect(attribute).toEqual({
|
|
33
|
-
key: 'age',
|
|
34
|
-
props: {
|
|
35
|
-
type: 'integer',
|
|
36
|
-
min: 0,
|
|
37
|
-
max: 100
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('should find attribute from nested path', () => {
|
|
43
|
-
const schema = {
|
|
44
|
-
type: 'object',
|
|
45
|
-
properties: {
|
|
46
|
-
address: {
|
|
47
|
-
type: 'object',
|
|
48
|
-
properties: {
|
|
49
|
-
street: { type: 'string' },
|
|
50
|
-
city: { type: 'string' },
|
|
51
|
-
state: { type: 'string' },
|
|
52
|
-
zip: { type: 'integer' }
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
let attribute = findAttributeByPath('#/address/street', schema)
|
|
58
|
-
expect(attribute).toEqual({
|
|
59
|
-
key: 'street',
|
|
60
|
-
props: {
|
|
61
|
-
type: 'string'
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
attribute = findAttributeByPath('#/address/city', schema)
|
|
66
|
-
expect(attribute).toEqual({
|
|
67
|
-
key: 'city',
|
|
68
|
-
props: {
|
|
69
|
-
type: 'string'
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
attribute = findAttributeByPath('#/address/state', schema)
|
|
74
|
-
expect(attribute).toEqual({
|
|
75
|
-
key: 'state',
|
|
76
|
-
props: {
|
|
77
|
-
type: 'string'
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
attribute = findAttributeByPath('#/address/zip', schema)
|
|
82
|
-
expect(attribute).toEqual({
|
|
83
|
-
key: 'zip',
|
|
84
|
-
props: {
|
|
85
|
-
type: 'integer'
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('should throw error if path is invalid', () => {
|
|
91
|
-
const schema = {
|
|
92
|
-
type: 'object',
|
|
93
|
-
properties: {
|
|
94
|
-
name: { type: 'string' },
|
|
95
|
-
age: { type: 'integer', min: 0, max: 100 }
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
expect(() => {
|
|
99
|
-
findAttributeByPath('#/invalid', schema)
|
|
100
|
-
}).toThrowError('Invalid scope: #/invalid')
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('should return props if scope is missing', () => {
|
|
104
|
-
const schema = {
|
|
105
|
-
type: 'object',
|
|
106
|
-
properties: {
|
|
107
|
-
name: { type: 'string' },
|
|
108
|
-
age: { type: 'integer', min: 0, max: 100 }
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
const attribute = findAttributeByPath(null, schema)
|
|
112
|
-
expect(attribute).toEqual({
|
|
113
|
-
props: schema
|
|
114
|
-
})
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
describe('getSchemaWithLayout', () => {
|
|
119
|
-
const value = {
|
|
120
|
-
name: 'John',
|
|
121
|
-
age: 30,
|
|
122
|
-
address: {
|
|
123
|
-
street: '123 Main St',
|
|
124
|
-
city: 'New York',
|
|
125
|
-
state: 'NY',
|
|
126
|
-
zip: 10001
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
const schema = inputSchema
|
|
130
|
-
const layout = inputLayout
|
|
131
|
-
|
|
132
|
-
it('should combine generated schema and layout', () => {
|
|
133
|
-
const value = {
|
|
134
|
-
name: 'John',
|
|
135
|
-
age: 30
|
|
136
|
-
}
|
|
137
|
-
const schema = getSchemaWithLayout(deriveSchemaFromValue(value), deriveLayoutFromValue(value))
|
|
138
|
-
expect(schema).toEqual({
|
|
139
|
-
type: 'vertical',
|
|
140
|
-
elements: [
|
|
141
|
-
{
|
|
142
|
-
key: 'name',
|
|
143
|
-
|
|
144
|
-
props: {
|
|
145
|
-
label: 'name',
|
|
146
|
-
type: 'string'
|
|
147
|
-
}
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
key: 'age',
|
|
151
|
-
|
|
152
|
-
props: {
|
|
153
|
-
label: 'age',
|
|
154
|
-
type: 'integer'
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
]
|
|
158
|
-
})
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
it('should combine generated schema & layout for nested data', () => {
|
|
162
|
-
const schema = getSchemaWithLayout(deriveSchemaFromValue(value), deriveLayoutFromValue(value))
|
|
163
|
-
expect(schema).toEqual(resultWithOnlyData)
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
it('should combine schema with generated layout', () => {
|
|
167
|
-
const combined = getSchemaWithLayout(schema, deriveLayoutFromValue(value))
|
|
168
|
-
expect(combined).toEqual(resultWithGeneratedLayout)
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
it('should combine layout with generated schema', () => {
|
|
172
|
-
const combined = getSchemaWithLayout(deriveSchemaFromValue(value), layout)
|
|
173
|
-
expect(combined).toEqual(resultWithGeneratedSchema)
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('should combine the schema and layout', () => {
|
|
177
|
-
const combined = getSchemaWithLayout(schema, layout)
|
|
178
|
-
expect(combined).toEqual(combinedSchemaLayout)
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
it('should combine the schema and layout for nested array', () => {
|
|
182
|
-
const schema = {
|
|
183
|
-
type: 'object',
|
|
184
|
-
properties: {
|
|
185
|
-
users: {
|
|
186
|
-
type: 'array',
|
|
187
|
-
items: {
|
|
188
|
-
type: 'object',
|
|
189
|
-
properties: {
|
|
190
|
-
name: { type: 'string' },
|
|
191
|
-
age: { type: 'integer' }
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
const layout = {
|
|
198
|
-
type: 'vertical',
|
|
199
|
-
elements: [
|
|
200
|
-
{
|
|
201
|
-
scope: '#/users',
|
|
202
|
-
schema: {
|
|
203
|
-
type: 'vertical',
|
|
204
|
-
|
|
205
|
-
elements: [
|
|
206
|
-
{
|
|
207
|
-
scope: '#/name',
|
|
208
|
-
label: 'name'
|
|
209
|
-
},
|
|
210
|
-
{
|
|
211
|
-
scope: '#/age',
|
|
212
|
-
label: 'age'
|
|
213
|
-
}
|
|
214
|
-
]
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
]
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const combined = getSchemaWithLayout(schema, layout)
|
|
221
|
-
expect(combined).toEqual({
|
|
222
|
-
type: 'vertical',
|
|
223
|
-
elements: [
|
|
224
|
-
{
|
|
225
|
-
key: 'users',
|
|
226
|
-
props: {
|
|
227
|
-
type: 'array',
|
|
228
|
-
schema: {
|
|
229
|
-
type: 'vertical',
|
|
230
|
-
elements: [
|
|
231
|
-
{
|
|
232
|
-
key: 'name',
|
|
233
|
-
props: {
|
|
234
|
-
label: 'name',
|
|
235
|
-
type: 'string'
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
{
|
|
239
|
-
key: 'age',
|
|
240
|
-
props: { label: 'age', type: 'integer' }
|
|
241
|
-
}
|
|
242
|
-
]
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
]
|
|
247
|
-
})
|
|
248
|
-
})
|
|
249
|
-
})
|
|
250
|
-
})
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"type": "vertical",
|
|
3
|
-
"elements": [
|
|
4
|
-
{
|
|
5
|
-
"key": "name",
|
|
6
|
-
"component": "custom",
|
|
7
|
-
"props": {
|
|
8
|
-
"type": "string",
|
|
9
|
-
"label": "Name"
|
|
10
|
-
}
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"key": "age",
|
|
14
|
-
|
|
15
|
-
"props": {
|
|
16
|
-
"label": "age",
|
|
17
|
-
"type": "number",
|
|
18
|
-
"min": 0,
|
|
19
|
-
"max": 100
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"type": "vertical",
|
|
24
|
-
"key": "address",
|
|
25
|
-
"title": "Address",
|
|
26
|
-
"elements": [
|
|
27
|
-
{
|
|
28
|
-
"key": "street",
|
|
29
|
-
|
|
30
|
-
"props": {
|
|
31
|
-
"label": "street",
|
|
32
|
-
"type": "string"
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
"key": "city",
|
|
37
|
-
|
|
38
|
-
"props": {
|
|
39
|
-
"label": "city",
|
|
40
|
-
"type": "string"
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"key": "state",
|
|
45
|
-
|
|
46
|
-
"props": {
|
|
47
|
-
"label": "state",
|
|
48
|
-
"type": "string"
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"key": "zip",
|
|
53
|
-
|
|
54
|
-
"props": {
|
|
55
|
-
"label": "zip",
|
|
56
|
-
"type": "number",
|
|
57
|
-
"min": 0,
|
|
58
|
-
"max": 99999
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
}
|
|
63
|
-
]
|
|
64
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"type": "vertical",
|
|
3
|
-
"elements": [
|
|
4
|
-
{
|
|
5
|
-
"scope": "#/name",
|
|
6
|
-
"key": "name",
|
|
7
|
-
"label": "name",
|
|
8
|
-
"component": "custom",
|
|
9
|
-
"props": {
|
|
10
|
-
"type": "string",
|
|
11
|
-
"label": "Name"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"scope": "#/age",
|
|
16
|
-
"key": "age",
|
|
17
|
-
"label": "age",
|
|
18
|
-
|
|
19
|
-
"props": {
|
|
20
|
-
"type": "number"
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"type": "vertical",
|
|
25
|
-
"scope": "#/address",
|
|
26
|
-
"key": "address",
|
|
27
|
-
"title": "Address",
|
|
28
|
-
"elements": [
|
|
29
|
-
{
|
|
30
|
-
"scope": "#/address/street",
|
|
31
|
-
"key": "street",
|
|
32
|
-
"label": "street",
|
|
33
|
-
|
|
34
|
-
"props": {
|
|
35
|
-
"type": "string"
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"scope": "#/address/city",
|
|
40
|
-
"key": "city",
|
|
41
|
-
"label": "city",
|
|
42
|
-
|
|
43
|
-
"props": {
|
|
44
|
-
"type": "string"
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
"scope": "#/address/state",
|
|
49
|
-
"key": "state",
|
|
50
|
-
"label": "state",
|
|
51
|
-
|
|
52
|
-
"props": {
|
|
53
|
-
"type": "string"
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
"scope": "#/address/zip",
|
|
58
|
-
"key": "zip",
|
|
59
|
-
"label": "zip",
|
|
60
|
-
|
|
61
|
-
"props": {
|
|
62
|
-
"type": "number"
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"type": "object",
|
|
3
|
-
"properties": {
|
|
4
|
-
"name": { "type": "string" },
|
|
5
|
-
"age": { "type": "number", "min": 0, "max": 100 },
|
|
6
|
-
"address": {
|
|
7
|
-
"type": "object",
|
|
8
|
-
"properties": {
|
|
9
|
-
"street": { "type": "string" },
|
|
10
|
-
"city": { "type": "string" },
|
|
11
|
-
"state": { "type": "string" },
|
|
12
|
-
"zip": { "type": "number", "min": 0, "max": 99999 }
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"type": "vertical",
|
|
3
|
-
"elements": [
|
|
4
|
-
{
|
|
5
|
-
"key": "name",
|
|
6
|
-
|
|
7
|
-
"props": {
|
|
8
|
-
"label": "name",
|
|
9
|
-
"type": "string"
|
|
10
|
-
}
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"key": "age",
|
|
14
|
-
|
|
15
|
-
"props": {
|
|
16
|
-
"label": "age",
|
|
17
|
-
"type": "number",
|
|
18
|
-
"min": 0,
|
|
19
|
-
"max": 100
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"type": "vertical",
|
|
24
|
-
"key": "address",
|
|
25
|
-
"title": "address",
|
|
26
|
-
"elements": [
|
|
27
|
-
{
|
|
28
|
-
"key": "street",
|
|
29
|
-
|
|
30
|
-
"props": {
|
|
31
|
-
"label": "street",
|
|
32
|
-
"type": "string"
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
"key": "city",
|
|
37
|
-
|
|
38
|
-
"props": {
|
|
39
|
-
"label": "city",
|
|
40
|
-
"type": "string"
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"key": "state",
|
|
45
|
-
|
|
46
|
-
"props": {
|
|
47
|
-
"label": "state",
|
|
48
|
-
"type": "string"
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"key": "zip",
|
|
53
|
-
|
|
54
|
-
"props": {
|
|
55
|
-
"label": "zip",
|
|
56
|
-
"type": "number",
|
|
57
|
-
"min": 0,
|
|
58
|
-
"max": 99999
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
}
|
|
63
|
-
]
|
|
64
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"type": "vertical",
|
|
3
|
-
"elements": [
|
|
4
|
-
{
|
|
5
|
-
"key": "name",
|
|
6
|
-
"component": "custom",
|
|
7
|
-
"props": {
|
|
8
|
-
"type": "string",
|
|
9
|
-
"label": "Name"
|
|
10
|
-
}
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"key": "age",
|
|
14
|
-
|
|
15
|
-
"props": {
|
|
16
|
-
"label": "age",
|
|
17
|
-
"type": "number"
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"type": "vertical",
|
|
22
|
-
"key": "address",
|
|
23
|
-
"title": "Address",
|
|
24
|
-
"elements": [
|
|
25
|
-
{
|
|
26
|
-
"key": "street",
|
|
27
|
-
|
|
28
|
-
"props": {
|
|
29
|
-
"label": "street",
|
|
30
|
-
"type": "string"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"key": "city",
|
|
35
|
-
|
|
36
|
-
"props": {
|
|
37
|
-
"label": "city",
|
|
38
|
-
"type": "string"
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"key": "state",
|
|
43
|
-
|
|
44
|
-
"props": {
|
|
45
|
-
"label": "state",
|
|
46
|
-
"type": "string"
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"key": "zip",
|
|
51
|
-
|
|
52
|
-
"props": {
|
|
53
|
-
"label": "zip",
|
|
54
|
-
"type": "number"
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
}
|
|
59
|
-
]
|
|
60
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"type": "vertical",
|
|
3
|
-
"elements": [
|
|
4
|
-
{
|
|
5
|
-
"key": "name",
|
|
6
|
-
|
|
7
|
-
"props": {
|
|
8
|
-
"type": "string",
|
|
9
|
-
"label": "name"
|
|
10
|
-
}
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"key": "age",
|
|
14
|
-
|
|
15
|
-
"props": {
|
|
16
|
-
"label": "age",
|
|
17
|
-
"type": "integer"
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"type": "vertical",
|
|
22
|
-
"key": "address",
|
|
23
|
-
"title": "address",
|
|
24
|
-
"elements": [
|
|
25
|
-
{
|
|
26
|
-
"key": "street",
|
|
27
|
-
|
|
28
|
-
"props": {
|
|
29
|
-
"label": "street",
|
|
30
|
-
"type": "string"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"key": "city",
|
|
35
|
-
|
|
36
|
-
"props": {
|
|
37
|
-
"label": "city",
|
|
38
|
-
"type": "string"
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"key": "state",
|
|
43
|
-
|
|
44
|
-
"props": {
|
|
45
|
-
"label": "state",
|
|
46
|
-
"type": "string"
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"key": "zip",
|
|
51
|
-
|
|
52
|
-
"props": {
|
|
53
|
-
"label": "zip",
|
|
54
|
-
"type": "integer"
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
}
|
|
59
|
-
]
|
|
60
|
-
}
|