@koumoul/vjsf 3.0.0-beta.25 → 3.0.0-beta.27
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/package.json +2 -2
- package/src/compat/v2.js +23 -13
- package/src/components/nodes/list.vue +9 -3
- package/src/components/nodes/one-of-select.vue +11 -9
- package/src/components/options.js +1 -1
- package/src/composables/use-vjsf.js +20 -19
- package/types/compat/v2.d.ts.map +1 -1
- package/types/components/fragments/select-item.vue.d.ts +2 -2
- package/types/components/vjsf.vue.d.ts +2 -2
- package/types/composables/use-vjsf.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koumoul/vjsf",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.27",
|
|
4
4
|
"description": "Generate forms for the vuetify UI library (vuejs) based on annotated JSON schemas.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "vitest",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"vuetify": "^3.6.8"
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
|
-
"@json-layout/core": "0.
|
|
79
|
+
"@json-layout/core": "0.23.0",
|
|
80
80
|
"@vueuse/core": "^10.5.0",
|
|
81
81
|
"debug": "^4.3.4",
|
|
82
82
|
"ejs": "^3.1.9"
|
package/src/compat/v2.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ajvModule from 'ajv'
|
|
2
2
|
import addFormats from 'ajv-formats'
|
|
3
|
-
import {
|
|
3
|
+
import { resolveLocaleRefs, clone } from '@json-layout/core'
|
|
4
4
|
import { isPartialGetItemsObj } from '@json-layout/vocabulary'
|
|
5
5
|
|
|
6
6
|
// @ts-ignore
|
|
@@ -59,7 +59,17 @@ const fixExpression = (expression, type = 'js-eval') => {
|
|
|
59
59
|
return { type, expr, pure }
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
/**
|
|
63
|
+
*
|
|
64
|
+
* @param {import("ajv").SchemaObject} schema
|
|
65
|
+
* @param {(schemaId: string, ref: string) => [any, string, string]} getJSONRef
|
|
66
|
+
* @param {string} schemaId
|
|
67
|
+
*/
|
|
68
|
+
const processFragment = (schema, getJSONRef, schemaId) => {
|
|
69
|
+
if (schema.$ref) {
|
|
70
|
+
const [refFragment, refSchemaId] = getJSONRef(schemaId, schema.$ref)
|
|
71
|
+
processFragment(refFragment, getJSONRef, refSchemaId)
|
|
72
|
+
}
|
|
63
73
|
if (!schema.layout) {
|
|
64
74
|
/** @type import('@json-layout/vocabulary').PartialCompObject */
|
|
65
75
|
const layout = {}
|
|
@@ -137,12 +147,12 @@ const processFragment = (/** @type {import("ajv").SchemaObject} */schema) => {
|
|
|
137
147
|
|
|
138
148
|
if (schema.properties) {
|
|
139
149
|
for (const propertyKey of Object.keys(schema.properties)) {
|
|
140
|
-
processFragment(schema.properties[propertyKey])
|
|
150
|
+
processFragment(schema.properties[propertyKey], getJSONRef, schemaId)
|
|
141
151
|
}
|
|
142
152
|
}
|
|
143
153
|
|
|
144
154
|
if (schema.allOf) {
|
|
145
|
-
for (const item of schema.allOf) processFragment(item)
|
|
155
|
+
for (const item of schema.allOf) processFragment(item, getJSONRef, schemaId)
|
|
146
156
|
}
|
|
147
157
|
|
|
148
158
|
if (schema.oneOf) {
|
|
@@ -157,28 +167,28 @@ const processFragment = (/** @type {import("ajv").SchemaObject} */schema) => {
|
|
|
157
167
|
}
|
|
158
168
|
}
|
|
159
169
|
}
|
|
160
|
-
for (const item of schema.oneOf) processFragment(item)
|
|
170
|
+
for (const item of schema.oneOf) processFragment(item, getJSONRef, schemaId)
|
|
161
171
|
}
|
|
162
172
|
|
|
163
173
|
if (schema.anyOf) {
|
|
164
|
-
for (const item of schema.anyOf) processFragment(item)
|
|
174
|
+
for (const item of schema.anyOf) processFragment(item, getJSONRef, schemaId)
|
|
165
175
|
}
|
|
166
176
|
|
|
167
177
|
if (schema.type === 'array' && schema.items) {
|
|
168
178
|
if (Array.isArray(schema.items)) {
|
|
169
|
-
for (const item of schema.items) processFragment(item)
|
|
179
|
+
for (const item of schema.items) processFragment(item, getJSONRef, schemaId)
|
|
170
180
|
} else {
|
|
171
|
-
processFragment(schema.items)
|
|
181
|
+
processFragment(schema.items, getJSONRef, schemaId)
|
|
172
182
|
}
|
|
173
183
|
}
|
|
174
184
|
if (schema.dependencies) {
|
|
175
185
|
for (const key of Object.keys(schema.dependencies)) {
|
|
176
|
-
processFragment(schema.dependencies[key])
|
|
186
|
+
processFragment(schema.dependencies[key], getJSONRef, schemaId)
|
|
177
187
|
}
|
|
178
188
|
}
|
|
179
189
|
if (schema.if) {
|
|
180
|
-
if (schema.then) processFragment(schema.then)
|
|
181
|
-
if (schema.else) processFragment(schema.else)
|
|
190
|
+
if (schema.then) processFragment(schema.then, getJSONRef, schemaId)
|
|
191
|
+
if (schema.else) processFragment(schema.else, getJSONRef, schemaId)
|
|
182
192
|
}
|
|
183
193
|
}
|
|
184
194
|
|
|
@@ -201,7 +211,7 @@ export function v2compat (_schema, _ajv, lang = 'en') {
|
|
|
201
211
|
|
|
202
212
|
const schema = /** @type {import("ajv").SchemaObject} */ (clone(_schema))
|
|
203
213
|
schema.$id = schema.$id ?? '_jl'
|
|
204
|
-
|
|
205
|
-
processFragment(schema)
|
|
214
|
+
const getJSONRef = resolveLocaleRefs(schema, ajv, lang)
|
|
215
|
+
processFragment(schema, getJSONRef, schema.$id)
|
|
206
216
|
return schema
|
|
207
217
|
}
|
|
@@ -30,7 +30,7 @@ watch(() => props.modelValue.children, (array) => { sortableArray.value = array
|
|
|
30
30
|
|
|
31
31
|
/* manage hovered and edited items */
|
|
32
32
|
const editedItem = computed(() => {
|
|
33
|
-
return props.statefulLayout.
|
|
33
|
+
return props.statefulLayout.activatedItems[props.modelValue.fullKey]
|
|
34
34
|
})
|
|
35
35
|
const menuOpened = ref(-1)
|
|
36
36
|
const activeItem = computed(() => {
|
|
@@ -54,7 +54,9 @@ const buttonDensity = computed(() => {
|
|
|
54
54
|
const pushEmptyItem = () => {
|
|
55
55
|
const newData = (props.modelValue.data ?? []).concat([undefined])
|
|
56
56
|
props.statefulLayout.input(props.modelValue, newData)
|
|
57
|
-
|
|
57
|
+
if (props.modelValue.layout.listEditMode === 'inline-single') {
|
|
58
|
+
props.statefulLayout.activateItem(props.modelValue, newData.length - 1)
|
|
59
|
+
}
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
/**
|
|
@@ -73,13 +75,17 @@ const deleteItem = (childIndex) => {
|
|
|
73
75
|
const duplicateItem = (child, childIndex) => {
|
|
74
76
|
const newData = [...props.modelValue.data.slice(0, childIndex), clone(child.data), ...props.modelValue.data.slice(childIndex)]
|
|
75
77
|
props.statefulLayout.input(props.modelValue, newData)
|
|
76
|
-
props.
|
|
78
|
+
if (props.modelValue.layout.listEditMode === 'inline-single') {
|
|
79
|
+
props.statefulLayout.activateItem(props.modelValue, childIndex + 1)
|
|
80
|
+
}
|
|
77
81
|
menuOpened.value = -1
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
const itemBorderColor = computed(() => (/** @type {import('@json-layout/core').StateNode} */child, /** @type {number} */childIndex) => {
|
|
81
85
|
if (editedItem.value === childIndex) return theme.current.value.colors.primary
|
|
82
86
|
if (child.validated && (child.error || child.childError)) return theme.current.value.colors.error
|
|
87
|
+
if (props.modelValue.options.readOnly) return 'transparent'
|
|
88
|
+
if (activeItem.value === childIndex) return theme.current.value.colors.primary
|
|
83
89
|
return 'transparent'
|
|
84
90
|
})
|
|
85
91
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { VSelect, VRow, VCol } from 'vuetify/components'
|
|
3
|
-
import {
|
|
3
|
+
import { ref, watch, computed, h } from 'vue'
|
|
4
4
|
import { isSection } from '@json-layout/core'
|
|
5
5
|
import { isCompObject } from '@json-layout/vocabulary'
|
|
6
6
|
import { getInputProps } from '../../utils/index.js'
|
|
@@ -19,18 +19,19 @@ const props = defineProps({
|
|
|
19
19
|
}
|
|
20
20
|
})
|
|
21
21
|
|
|
22
|
-
/** @type import('vue').
|
|
23
|
-
const activeChildTree =
|
|
22
|
+
/** @type import('vue').Ref<string | undefined> */
|
|
23
|
+
const activeChildTree = ref(undefined)
|
|
24
24
|
watch(() => props.modelValue, () => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
if (props.modelValue.children?.length === 1) {
|
|
26
|
+
if (typeof props.modelValue.children[0].key === 'number') {
|
|
27
|
+
activeChildTree.value = props.modelValue.skeleton.childrenTrees?.[props.modelValue.children[0].key]
|
|
28
|
+
}
|
|
28
29
|
} else {
|
|
29
30
|
activeChildTree.value = undefined
|
|
30
31
|
}
|
|
31
32
|
}, { immediate: true })
|
|
32
33
|
|
|
33
|
-
const onChange = (/** @type
|
|
34
|
+
const onChange = (/** @type {string} */childTree) => {
|
|
34
35
|
if (!props.modelValue.skeleton.childrenTrees) return
|
|
35
36
|
props.statefulLayout.activateItem(props.modelValue, props.modelValue.skeleton.childrenTrees.indexOf(childTree))
|
|
36
37
|
}
|
|
@@ -39,9 +40,9 @@ const fieldProps = computed(() => {
|
|
|
39
40
|
const fieldProps = getInputProps(props.modelValue, props.statefulLayout)
|
|
40
41
|
fieldProps.modelValue = activeChildTree.value
|
|
41
42
|
fieldProps['onUpdate:modelValue'] = onChange
|
|
42
|
-
fieldProps.returnObject = true
|
|
43
43
|
const items = []
|
|
44
|
-
for (const
|
|
44
|
+
for (const childTreePointer of props.modelValue.skeleton.childrenTrees || []) {
|
|
45
|
+
const childTree = props.statefulLayout.compiledLayout.skeletonTrees[childTreePointer]
|
|
45
46
|
const childLayout = props.statefulLayout.compiledLayout.normalizedLayouts[childTree.root.pointer]
|
|
46
47
|
if (!isCompObject(childLayout) || !childLayout.if || !!props.statefulLayout.evalNodeExpression(props.modelValue, childLayout.if, props.modelValue.data)) {
|
|
47
48
|
items.push(childTree)
|
|
@@ -49,6 +50,7 @@ const fieldProps = computed(() => {
|
|
|
49
50
|
}
|
|
50
51
|
fieldProps.items = items
|
|
51
52
|
fieldProps.itemTitle = 'title'
|
|
53
|
+
fieldProps.itemValue = (/** @type {import('@json-layout/core').SkeletonTree} */childTree) => childTree.root.pointer
|
|
52
54
|
return fieldProps
|
|
53
55
|
})
|
|
54
56
|
</script>
|
|
@@ -15,7 +15,7 @@ export const defaultOptions = {
|
|
|
15
15
|
* @returns
|
|
16
16
|
*/
|
|
17
17
|
export const getFullOptions = (options, form, width, slots, defaultNodeComponents) => {
|
|
18
|
-
const components = options?.components
|
|
18
|
+
const components = { ...options?.components }
|
|
19
19
|
const nodeComponents = { ...defaultNodeComponents, ...options?.nodeComponents }
|
|
20
20
|
if (options?.plugins) {
|
|
21
21
|
for (const plugin of options.plugins) {
|
|
@@ -90,35 +90,36 @@ export const useVjsf = (schema, modelValue, options, nodeComponents, emit, compi
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
const onAutofocus = () => {
|
|
94
|
+
if (!el.value) return
|
|
95
|
+
// @ts-ignore
|
|
96
|
+
const autofocusNodeElement = el.value.querySelector('.vjsf-input--autofocus')
|
|
97
|
+
if (autofocusNodeElement) {
|
|
98
|
+
const autofocusInputElement = autofocusNodeElement.querySelector('input') ?? autofocusNodeElement.querySelector('textarea:not([style*="display: none"]')
|
|
99
|
+
if (autofocusInputElement) autofocusInputElement.focus()
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
93
103
|
const initStatefulLayout = () => {
|
|
94
104
|
if (!width.value) return
|
|
105
|
+
if (statefulLayout.value) {
|
|
106
|
+
statefulLayout.value.events.off('update', onStatefulLayoutUpdate)
|
|
107
|
+
statefulLayout.value.events.off('data', onDataUpdate)
|
|
108
|
+
statefulLayout.value.events.off('autofocus', onAutofocus)
|
|
109
|
+
}
|
|
95
110
|
|
|
96
111
|
// @ts-ignore
|
|
97
|
-
|
|
112
|
+
statefulLayout.value = /** @type {import('../types.js').VjsfStatefulLayout} */(new StatefulLayout(
|
|
98
113
|
toRaw(compiledLayout.value),
|
|
99
|
-
toRaw(compiledLayout.value.
|
|
114
|
+
toRaw(compiledLayout.value.skeletonTrees[compiledLayout.value.mainTree]),
|
|
100
115
|
toRaw(fullOptions.value),
|
|
101
116
|
toRaw(modelValue.value)
|
|
102
117
|
))
|
|
103
|
-
statefulLayout.value = _statefulLayout
|
|
104
118
|
onStatefulLayoutUpdate()
|
|
105
119
|
onDataUpdate()
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
_statefulLayout.events.on('data', () => {
|
|
110
|
-
onDataUpdate()
|
|
111
|
-
})
|
|
112
|
-
emit('update:state', _statefulLayout)
|
|
113
|
-
_statefulLayout.events.on('autofocus', () => {
|
|
114
|
-
if (!el.value) return
|
|
115
|
-
// @ts-ignore
|
|
116
|
-
const autofocusNodeElement = el.value.querySelector('.vjsf-input--autofocus')
|
|
117
|
-
if (autofocusNodeElement) {
|
|
118
|
-
const autofocusInputElement = autofocusNodeElement.querySelector('input') ?? autofocusNodeElement.querySelector('textarea:not([style*="display: none"]')
|
|
119
|
-
if (autofocusInputElement) autofocusInputElement.focus()
|
|
120
|
-
}
|
|
121
|
-
})
|
|
120
|
+
statefulLayout.value.events.on('update', onStatefulLayoutUpdate)
|
|
121
|
+
statefulLayout.value.events.on('data', onDataUpdate)
|
|
122
|
+
statefulLayout.value.events.on('autofocus', onAutofocus)
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
// case where options are updated from outside
|
package/types/compat/v2.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"v2.d.ts","sourceRoot":"","sources":["../../src/compat/v2.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"v2.d.ts","sourceRoot":"","sources":["../../src/compat/v2.js"],"names":[],"mappings":"AAkMA;;;;;;GAMG;AACH,kCALW,MAAM,+CAEN,MAAM,0BAkBhB;sBAxNqB,KAAK"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
declare const _default: import("vue").DefineComponent<{}, {
|
|
2
2
|
multiple: boolean;
|
|
3
|
-
itemProps: Record<string, any>;
|
|
4
3
|
item: import("../../../../node_modules/@json-layout/vocabulary/types/normalized-layout/types.js").SelectItem;
|
|
4
|
+
itemProps: Record<string, any>;
|
|
5
5
|
$props: {
|
|
6
6
|
readonly multiple?: boolean | undefined;
|
|
7
|
-
readonly itemProps?: Record<string, any> | undefined;
|
|
8
7
|
readonly item?: import("../../../../node_modules/@json-layout/vocabulary/types/normalized-layout/types.js").SelectItem | undefined;
|
|
8
|
+
readonly itemProps?: Record<string, any> | undefined;
|
|
9
9
|
};
|
|
10
10
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
|
|
11
11
|
export default _default;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
declare const _default: import("vue").DefineComponent<{}, {
|
|
2
2
|
$emit: ((event: "update:modelValue", data: any) => void) & ((event: "update:state", state: import("../types.js").VjsfStatefulLayout) => void);
|
|
3
|
+
schema: Record<string, any>;
|
|
3
4
|
modelValue: any;
|
|
4
5
|
options: Partial<Omit<import("../types.js").VjsfOptions, "width" | "vjsfSlots">> | null;
|
|
5
|
-
schema: Record<string, any>;
|
|
6
6
|
precompiledLayout: import("../../../node_modules/@json-layout/core/types/compile/types.js").CompiledLayout;
|
|
7
7
|
$props: {
|
|
8
|
+
readonly schema?: Record<string, any> | undefined;
|
|
8
9
|
readonly modelValue?: any;
|
|
9
10
|
readonly options?: Partial<Omit<import("../types.js").VjsfOptions, "width" | "vjsfSlots">> | null | undefined;
|
|
10
|
-
readonly schema?: Record<string, any> | undefined;
|
|
11
11
|
readonly precompiledLayout?: import("../../../node_modules/@json-layout/core/types/compile/types.js").CompiledLayout | undefined;
|
|
12
12
|
};
|
|
13
13
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-vjsf.d.ts","sourceRoot":"","sources":["../../src/composables/use-vjsf.js"],"names":[],"mappings":"AASA;IACE;;MAEE;gCADO,GAAG;IAGZ;;MAEE;4BADO,OAAO,aAAa,EAAE,kBAAkB;EAGlD;AAWM,gCARI,OAAO,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,cACzB,OAAO,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,WACtB,OAAO,KAAK,EAAE,GAAG,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC,kBAClE,OAAO,MAAM,EAAE,OAAO,KAAK,EAAE,SAAS,CAAC,QACvC,GAAG;;;;
|
|
1
|
+
{"version":3,"file":"use-vjsf.d.ts","sourceRoot":"","sources":["../../src/composables/use-vjsf.js"],"names":[],"mappings":"AASA;IACE;;MAEE;gCADO,GAAG;IAGZ;;MAEE;4BADO,OAAO,aAAa,EAAE,kBAAkB;EAGlD;AAWM,gCARI,OAAO,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,cACzB,OAAO,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,WACtB,OAAO,KAAK,EAAE,GAAG,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC,kBAClE,OAAO,MAAM,EAAE,OAAO,KAAK,EAAE,SAAS,CAAC,QACvC,GAAG;;;;EAuHb"}
|