@koumoul/vjsf 2.23.2 → 3.0.0-alpha.1
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 +56 -87
- package/src/compat/v2.js +120 -0
- package/src/compile/index.js +51 -0
- package/src/compile/v-jsf-compiled.vue.ejs +83 -0
- package/src/components/fragments/help-message.vue +48 -0
- package/src/components/fragments/node-slot.vue +49 -0
- package/src/components/fragments/section-header.vue +55 -0
- package/src/components/fragments/select-item-icon.vue +28 -0
- package/src/components/fragments/select-item.vue +43 -0
- package/src/components/fragments/select-selection.vue +35 -0
- package/src/components/fragments/text-field-menu.vue +68 -0
- package/src/components/node.vue +69 -0
- package/src/components/nodes/autocomplete.vue +95 -0
- package/src/components/nodes/checkbox.vue +27 -0
- package/src/components/nodes/color-picker.vue +43 -0
- package/src/components/nodes/combobox.vue +73 -0
- package/src/components/nodes/date-picker.vue +45 -0
- package/src/components/nodes/date-time-picker.vue +20 -0
- package/src/components/nodes/expansion-panels.vue +52 -0
- package/src/components/nodes/list.vue +112 -0
- package/src/components/nodes/markdown.vue +29 -0
- package/src/components/nodes/number-combobox.vue +73 -0
- package/src/components/nodes/number-field.vue +34 -0
- package/src/components/nodes/one-of-select.vue +56 -0
- package/src/components/nodes/section.vue +30 -0
- package/src/components/nodes/select.vue +79 -0
- package/src/components/nodes/slider.vue +34 -0
- package/src/components/nodes/switch.vue +29 -0
- package/src/components/nodes/tabs.vue +63 -0
- package/src/components/nodes/text-field.vue +29 -0
- package/src/components/nodes/textarea.vue +29 -0
- package/src/components/nodes/time-picker.vue +7 -0
- package/src/components/nodes/vertical-tabs.vue +70 -0
- package/src/components/options.js +25 -0
- package/src/components/tree.vue +26 -0
- package/src/components/types.ts +63 -0
- package/src/components/vjsf.vue +195 -0
- package/src/index.js +3 -0
- package/src/utils/clone.js +3 -0
- package/src/utils/dates.js +52 -0
- package/src/utils/props.js +87 -0
- package/src/utils/slots.js +19 -0
- package/types/compat/v2.d.ts +10 -0
- package/types/compat/v2.d.ts.map +1 -0
- package/types/compile/index.d.ts +7 -0
- package/types/compile/index.d.ts.map +1 -0
- package/types/components/fragments/help-message.vue.d.ts +8 -0
- package/types/components/fragments/help-message.vue.d.ts.map +1 -0
- package/types/components/fragments/node-slot.vue.d.ts +47 -0
- package/types/components/fragments/node-slot.vue.d.ts.map +1 -0
- package/types/components/fragments/section-header.vue.d.ts +8 -0
- package/types/components/fragments/section-header.vue.d.ts.map +1 -0
- package/types/components/fragments/select-item-icon.vue.d.ts +15 -0
- package/types/components/fragments/select-item-icon.vue.d.ts.map +1 -0
- package/types/components/fragments/select-item.vue.d.ts +12 -0
- package/types/components/fragments/select-item.vue.d.ts.map +1 -0
- package/types/components/fragments/select-selection.vue.d.ts +12 -0
- package/types/components/fragments/select-selection.vue.d.ts.map +1 -0
- package/types/components/fragments/text-field-menu.vue.d.ts +20 -0
- package/types/components/fragments/text-field-menu.vue.d.ts.map +1 -0
- package/types/components/node.vue.d.ts +10 -0
- package/types/components/node.vue.d.ts.map +1 -0
- package/types/components/nodes/autocomplete.vue.d.ts +27 -0
- package/types/components/nodes/autocomplete.vue.d.ts.map +1 -0
- package/types/components/nodes/checkbox.vue.d.ts +10 -0
- package/types/components/nodes/checkbox.vue.d.ts.map +1 -0
- package/types/components/nodes/color-picker.vue.d.ts +10 -0
- package/types/components/nodes/color-picker.vue.d.ts.map +1 -0
- package/types/components/nodes/combobox.vue.d.ts +27 -0
- package/types/components/nodes/combobox.vue.d.ts.map +1 -0
- package/types/components/nodes/date-picker.vue.d.ts +10 -0
- package/types/components/nodes/date-picker.vue.d.ts.map +1 -0
- package/types/components/nodes/date-time-picker.vue.d.ts +10 -0
- package/types/components/nodes/date-time-picker.vue.d.ts.map +1 -0
- package/types/components/nodes/expansion-panels.vue.d.ts +10 -0
- package/types/components/nodes/expansion-panels.vue.d.ts.map +1 -0
- package/types/components/nodes/list.vue.d.ts +10 -0
- package/types/components/nodes/list.vue.d.ts.map +1 -0
- package/types/components/nodes/markdown.vue.d.ts +27 -0
- package/types/components/nodes/markdown.vue.d.ts.map +1 -0
- package/types/components/nodes/number-combobox.vue.d.ts +27 -0
- package/types/components/nodes/number-combobox.vue.d.ts.map +1 -0
- package/types/components/nodes/number-field.vue.d.ts +27 -0
- package/types/components/nodes/number-field.vue.d.ts.map +1 -0
- package/types/components/nodes/one-of-select.vue.d.ts +10 -0
- package/types/components/nodes/one-of-select.vue.d.ts.map +1 -0
- package/types/components/nodes/section.vue.d.ts +10 -0
- package/types/components/nodes/section.vue.d.ts.map +1 -0
- package/types/components/nodes/select.vue.d.ts +27 -0
- package/types/components/nodes/select.vue.d.ts.map +1 -0
- package/types/components/nodes/slider.vue.d.ts +10 -0
- package/types/components/nodes/slider.vue.d.ts.map +1 -0
- package/types/components/nodes/switch.vue.d.ts +10 -0
- package/types/components/nodes/switch.vue.d.ts.map +1 -0
- package/types/components/nodes/tabs.vue.d.ts +10 -0
- package/types/components/nodes/tabs.vue.d.ts.map +1 -0
- package/types/components/nodes/text-field copy.vue.d.ts +10 -0
- package/types/components/nodes/text-field copy.vue.d.ts.map +1 -0
- package/types/components/nodes/text-field.vue.d.ts +27 -0
- package/types/components/nodes/text-field.vue.d.ts.map +1 -0
- package/types/components/nodes/textarea.vue.d.ts +27 -0
- package/types/components/nodes/textarea.vue.d.ts.map +1 -0
- package/types/components/nodes/time-picker.vue.d.ts +3 -0
- package/types/components/nodes/time-picker.vue.d.ts.map +1 -0
- package/types/components/nodes/vertical-tabs.vue.d.ts +10 -0
- package/types/components/nodes/vertical-tabs.vue.d.ts.map +1 -0
- package/types/components/options.d.ts +3 -0
- package/types/components/options.d.ts.map +1 -0
- package/types/components/tree.vue.d.ts +10 -0
- package/types/components/tree.vue.d.ts.map +1 -0
- package/types/components/types.d.ts +75 -0
- package/types/components/types.d.ts.map +1 -0
- package/types/components/v-jsf.vue.d.ts +13 -0
- package/types/components/v-jsf.vue.d.ts.map +1 -0
- package/types/components/vjsf.vue.d.ts +16 -0
- package/types/components/vjsf.vue.d.ts.map +1 -0
- package/types/index.d.ts +4 -0
- package/types/index.d.ts.map +1 -0
- package/types/utils/clone.d.ts +3 -0
- package/types/utils/clone.d.ts.map +1 -0
- package/types/utils/dates.d.ts +7 -0
- package/types/utils/dates.d.ts.map +1 -0
- package/types/utils/props.d.ts +21 -0
- package/types/utils/props.d.ts.map +1 -0
- package/types/utils/slots.d.ts +7 -0
- package/types/utils/slots.d.ts.map +1 -0
- package/.eslintignore +0 -9
- package/.eslintrc.js +0 -38
- package/.github/workflows/scrape-doc.yml +0 -14
- package/.nvmrc +0 -1
- package/CONTRIBUTE.md +0 -61
- package/FUNDING.yml +0 -1
- package/README.md +0 -19
- package/babel.config.js +0 -4
- package/dist/main.css +0 -67
- package/dist/main.js +0 -2
- package/dist/main.js.LICENSE.txt +0 -10
- package/dist/third-party.js +0 -8
- package/dist/third-party.js.LICENSE.txt +0 -8
- package/lib/VJsf.css +0 -67
- package/lib/VJsf.js +0 -117
- package/lib/VJsfNoDeps.js +0 -528
- package/lib/deps/third-party.js +0 -16
- package/lib/mixins/ColorProperty.js +0 -45
- package/lib/mixins/DateProperty.js +0 -170
- package/lib/mixins/Dependent.js +0 -69
- package/lib/mixins/EditableArray.js +0 -418
- package/lib/mixins/FileProperty.js +0 -81
- package/lib/mixins/MarkdownEditor.js +0 -183
- package/lib/mixins/ObjectContainer.js +0 -351
- package/lib/mixins/SelectProperty.js +0 -400
- package/lib/mixins/SimpleProperty.js +0 -165
- package/lib/mixins/Tooltip.js +0 -42
- package/lib/mixins/Validatable.js +0 -119
- package/lib/utils/expr-eval-parser.js +0 -47
- package/lib/utils/is-cyclic.js +0 -34
- package/lib/utils/json-refs.js +0 -209
- package/lib/utils/options.js +0 -328
- package/lib/utils/rules.js +0 -81
- package/lib/utils/schema.js +0 -100
- package/lib/utils/select.js +0 -141
- package/webpack.config.js +0 -46
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { defineComponent, h, computed, shallowRef, ref } from 'vue'
|
|
3
|
+
import { VCombobox } from 'vuetify/components'
|
|
4
|
+
import { getInputProps } from '../../utils/props.js'
|
|
5
|
+
import { getCompSlots } from '../../utils/slots.js'
|
|
6
|
+
|
|
7
|
+
export default defineComponent({
|
|
8
|
+
props: {
|
|
9
|
+
modelValue: {
|
|
10
|
+
/** @type import('vue').PropType<import('../types.js').VjsfComboboxNode> */
|
|
11
|
+
type: Object,
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
statefulLayout: {
|
|
15
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
16
|
+
type: Object,
|
|
17
|
+
required: true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
setup (props) {
|
|
21
|
+
/** @type import('vue').Ref<import('@json-layout/vocabulary').SelectItems> */
|
|
22
|
+
const items = shallowRef(props.modelValue.layout.items ?? [])
|
|
23
|
+
/** @type import('vue').Ref<boolean> */
|
|
24
|
+
const loading = ref(false)
|
|
25
|
+
|
|
26
|
+
/** @type import('@json-layout/core').StateTree | null */
|
|
27
|
+
let lastStateTree = null
|
|
28
|
+
/** @type Record<string, any> | null */
|
|
29
|
+
let lastContext = null
|
|
30
|
+
|
|
31
|
+
const hasItems = computed(() => {
|
|
32
|
+
return !!(props.modelValue.layout.items || props.modelValue.layout.getItems)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const refresh = async () => {
|
|
36
|
+
if (props.modelValue.layout.items) return
|
|
37
|
+
if (props.statefulLayout.stateTree === lastStateTree && props.statefulLayout.options.context === lastContext) return
|
|
38
|
+
lastStateTree = props.statefulLayout.stateTree
|
|
39
|
+
lastContext = props.statefulLayout.options.context ?? null
|
|
40
|
+
if (hasItems.value) {
|
|
41
|
+
loading.value = true
|
|
42
|
+
items.value = await props.statefulLayout.getItems(props.modelValue)
|
|
43
|
+
loading.value = false
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!props.modelValue.layout.items) {
|
|
48
|
+
refresh()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const fieldProps = computed(() => {
|
|
52
|
+
const fieldProps = getInputProps(props.modelValue, props.statefulLayout, ['step', 'min', 'max'])
|
|
53
|
+
fieldProps.type = 'number'
|
|
54
|
+
fieldProps.loading = loading.value
|
|
55
|
+
if (hasItems.value) fieldProps.items = items.value
|
|
56
|
+
if (props.modelValue.options.readOnly) fieldProps.menuProps = { modelValue: false }
|
|
57
|
+
if (props.modelValue.layout.multiple) {
|
|
58
|
+
fieldProps.multiple = true
|
|
59
|
+
fieldProps.chips = true
|
|
60
|
+
fieldProps.closableChips = true
|
|
61
|
+
}
|
|
62
|
+
fieldProps['onUpdate:menu'] = () => refresh()
|
|
63
|
+
fieldProps['onUpdate:modelValue'] = (/** @type string[] */value) => props.statefulLayout.input(props.modelValue, value && value.map(Number))
|
|
64
|
+
return fieldProps
|
|
65
|
+
})
|
|
66
|
+
const fieldSlots = computed(() => getCompSlots(props.modelValue, props.statefulLayout))
|
|
67
|
+
|
|
68
|
+
// @ts-ignore
|
|
69
|
+
return () => h(VCombobox, fieldProps.value, fieldSlots.value)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
</script>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { defineComponent, h, computed } from 'vue'
|
|
3
|
+
import { VTextField } from 'vuetify/components'
|
|
4
|
+
import { getInputProps } from '../../utils/props.js'
|
|
5
|
+
import { getCompSlots } from '../../utils/slots.js'
|
|
6
|
+
|
|
7
|
+
export default defineComponent({
|
|
8
|
+
props: {
|
|
9
|
+
modelValue: {
|
|
10
|
+
/** @type import('vue').PropType<import('../types.js').VjsfNumberFieldNode> */
|
|
11
|
+
type: Object,
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
statefulLayout: {
|
|
15
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
16
|
+
type: Object,
|
|
17
|
+
required: true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
setup (props) {
|
|
21
|
+
const fieldProps = computed(() => {
|
|
22
|
+
const fieldProps = getInputProps(props.modelValue, props.statefulLayout, ['step', 'min', 'max'])
|
|
23
|
+
fieldProps.type = 'number'
|
|
24
|
+
fieldProps['onUpdate:modelValue'] = (/** @type string */value) => props.statefulLayout.input(props.modelValue, value && Number(value))
|
|
25
|
+
return fieldProps
|
|
26
|
+
})
|
|
27
|
+
const fieldSlots = computed(() => getCompSlots(props.modelValue, props.statefulLayout))
|
|
28
|
+
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
return () => h(VTextField, fieldProps.value, fieldSlots.value)
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
</script>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { VSelect } from 'vuetify/components'
|
|
3
|
+
import { shallowRef, watch } from 'vue'
|
|
4
|
+
import { isSection } from '@json-layout/core'
|
|
5
|
+
import Node from '../node.vue'
|
|
6
|
+
|
|
7
|
+
const props = defineProps({
|
|
8
|
+
modelValue: {
|
|
9
|
+
/** @type import('vue').PropType<import('../types.js').VjsfOneOfSelectNode> */
|
|
10
|
+
type: Object,
|
|
11
|
+
required: true
|
|
12
|
+
},
|
|
13
|
+
statefulLayout: {
|
|
14
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
15
|
+
type: Object,
|
|
16
|
+
required: true
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
/** @type import('vue').ShallowRef<import('@json-layout/core').SkeletonTree | undefined> */
|
|
21
|
+
const activeChildTree = shallowRef(undefined)
|
|
22
|
+
watch(() => props.modelValue, () => {
|
|
23
|
+
// we set the active oneOf child as the one whose schema validates on the current data
|
|
24
|
+
if (props.modelValue.fullKey in props.statefulLayout.activeItems) {
|
|
25
|
+
activeChildTree.value = props.modelValue.skeleton.childrenTrees?.[props.statefulLayout.activeItems[props.modelValue.fullKey]]
|
|
26
|
+
} else {
|
|
27
|
+
activeChildTree.value = undefined
|
|
28
|
+
}
|
|
29
|
+
}, { immediate: true })
|
|
30
|
+
|
|
31
|
+
const onChange = (/** @type import('@json-layout/core').SkeletonTree */childTree) => {
|
|
32
|
+
if (!props.modelValue.skeleton.childrenTrees) return
|
|
33
|
+
props.statefulLayout.activateItem(props.modelValue, props.modelValue.skeleton.childrenTrees.indexOf(childTree))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<v-select
|
|
40
|
+
v-if="modelValue.skeleton.childrenTrees"
|
|
41
|
+
v-model="activeChildTree"
|
|
42
|
+
:items="modelValue.skeleton.childrenTrees"
|
|
43
|
+
item-title="title"
|
|
44
|
+
return-object
|
|
45
|
+
:error-messages="modelValue.validated ? modelValue.error : null"
|
|
46
|
+
@update:model-value="onChange"
|
|
47
|
+
/>
|
|
48
|
+
<v-row v-if="modelValue.children?.[0]">
|
|
49
|
+
<node
|
|
50
|
+
v-for="grandChild of isSection(modelValue.children?.[0]) ? modelValue.children?.[0].children : modelValue.children"
|
|
51
|
+
:key="grandChild.fullKey"
|
|
52
|
+
:model-value="/** @type import('../types.js').VjsfNode */(grandChild)"
|
|
53
|
+
:stateful-layout="statefulLayout"
|
|
54
|
+
/>
|
|
55
|
+
</v-row>
|
|
56
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import Node from '../node.vue'
|
|
3
|
+
import SectionHeader from '../fragments/section-header.vue'
|
|
4
|
+
|
|
5
|
+
defineProps({
|
|
6
|
+
modelValue: {
|
|
7
|
+
/** @type import('vue').PropType<import('../types.js').VjsfSectionNode> */
|
|
8
|
+
type: Object,
|
|
9
|
+
required: true
|
|
10
|
+
},
|
|
11
|
+
statefulLayout: {
|
|
12
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
13
|
+
type: Object,
|
|
14
|
+
required: true
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<section-header :node="modelValue" />
|
|
22
|
+
<v-row :dense="modelValue.options?.density === 'compact' || modelValue.options?.density === 'comfortable'">
|
|
23
|
+
<node
|
|
24
|
+
v-for="child of modelValue.children"
|
|
25
|
+
:key="child.fullKey"
|
|
26
|
+
:model-value="/** @type import('../types.js').VjsfNode */(child)"
|
|
27
|
+
:stateful-layout="statefulLayout"
|
|
28
|
+
/>
|
|
29
|
+
</v-row>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { VSelect } from 'vuetify/components'
|
|
3
|
+
import { defineComponent, h, computed, ref, shallowRef } from 'vue'
|
|
4
|
+
import { getInputProps } from '../../utils/props.js'
|
|
5
|
+
import { getCompSlots } from '../../utils/slots.js'
|
|
6
|
+
import SelectItem from '../fragments/select-item.vue'
|
|
7
|
+
import SelectSelection from '../fragments/select-selection.vue'
|
|
8
|
+
|
|
9
|
+
export default defineComponent({
|
|
10
|
+
props: {
|
|
11
|
+
modelValue: {
|
|
12
|
+
/** @type import('vue').PropType<import('../types.js').VjsfSelectNode> */
|
|
13
|
+
type: Object,
|
|
14
|
+
required: true
|
|
15
|
+
},
|
|
16
|
+
statefulLayout: {
|
|
17
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
18
|
+
type: Object,
|
|
19
|
+
required: true
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
setup (props) {
|
|
23
|
+
/** @type import('vue').Ref<import('@json-layout/vocabulary').SelectItems> */
|
|
24
|
+
const items = shallowRef([])
|
|
25
|
+
/** @type import('vue').Ref<boolean> */
|
|
26
|
+
const loading = ref(false)
|
|
27
|
+
|
|
28
|
+
const fieldProps = computed(() => {
|
|
29
|
+
const fieldProps = getInputProps(props.modelValue, props.statefulLayout, ['multiple'])
|
|
30
|
+
if (props.modelValue.options.readOnly) fieldProps.menuProps = { modelValue: false }
|
|
31
|
+
fieldProps.loading = loading.value
|
|
32
|
+
fieldProps.items = items.value
|
|
33
|
+
fieldProps['onUpdate:menu'] = refresh
|
|
34
|
+
return fieldProps
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
/** @type import('@json-layout/core').StateTree | null */
|
|
38
|
+
let lastStateTree = null
|
|
39
|
+
/** @type Record<string, any> | null */
|
|
40
|
+
let lastContext = null
|
|
41
|
+
|
|
42
|
+
const refresh = async () => {
|
|
43
|
+
if (props.statefulLayout.stateTree === lastStateTree && props.statefulLayout.options.context === lastContext) return
|
|
44
|
+
lastStateTree = props.statefulLayout.stateTree
|
|
45
|
+
lastContext = props.statefulLayout.options.context ?? null
|
|
46
|
+
loading.value = true
|
|
47
|
+
items.value = await props.statefulLayout.getItems(props.modelValue)
|
|
48
|
+
loading.value = false
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!props.modelValue.layout.items) {
|
|
52
|
+
refresh()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const fieldSlots = computed(() => {
|
|
56
|
+
const slots = getCompSlots(props.modelValue, props.statefulLayout)
|
|
57
|
+
if (!slots.item) {
|
|
58
|
+
slots.item = (/** @type {any} */ context) => h(SelectItem, {
|
|
59
|
+
multiple: props.modelValue.layout.multiple,
|
|
60
|
+
itemProps: context.props,
|
|
61
|
+
item: context.item.raw
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
if (!slots.selection) {
|
|
65
|
+
slots.selection = (/** @type {any} */ context) => h(SelectSelection, {
|
|
66
|
+
multiple: props.modelValue.layout.multiple,
|
|
67
|
+
last: props.modelValue.layout.multiple && context.index === props.modelValue.data.length - 1,
|
|
68
|
+
item: context.item.raw
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
return slots
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
return () => h(VSelect, fieldProps.value, fieldSlots.value)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
</script>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { VSlider } from 'vuetify/components'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { getInputProps } from '../../utils/props.js'
|
|
5
|
+
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
modelValue: {
|
|
8
|
+
/** @type import('vue').PropType<import('../types.js').VjsfSliderNode> */
|
|
9
|
+
type: Object,
|
|
10
|
+
required: true
|
|
11
|
+
},
|
|
12
|
+
statefulLayout: {
|
|
13
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
14
|
+
type: Object,
|
|
15
|
+
required: true
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const fieldProps = computed(() => {
|
|
20
|
+
const fieldProps = getInputProps(props.modelValue, props.statefulLayout)
|
|
21
|
+
if ('step' in props.modelValue.layout) fieldProps.step = props.modelValue.layout.step
|
|
22
|
+
fieldProps.min = props.modelValue.layout.min
|
|
23
|
+
fieldProps.max = props.modelValue.layout.max
|
|
24
|
+
return fieldProps
|
|
25
|
+
})
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<v-slider
|
|
30
|
+
type="number"
|
|
31
|
+
v-bind="fieldProps"
|
|
32
|
+
@update:model-value="value => statefulLayout.input(modelValue, value && Number(value))"
|
|
33
|
+
/>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { VSwitch } from 'vuetify/components'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { getInputProps } from '../../utils/props.js'
|
|
5
|
+
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
modelValue: {
|
|
8
|
+
/** @type import('vue').PropType<import('../types.js').VjsfSwitchNode> */
|
|
9
|
+
type: Object,
|
|
10
|
+
required: true
|
|
11
|
+
},
|
|
12
|
+
statefulLayout: {
|
|
13
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
14
|
+
type: Object,
|
|
15
|
+
required: true
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const fieldProps = computed(() =>
|
|
20
|
+
getInputProps(props.modelValue, props.statefulLayout)
|
|
21
|
+
)
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<v-switch
|
|
26
|
+
v-bind="fieldProps"
|
|
27
|
+
@update:model-value="value => statefulLayout.input(modelValue, value)"
|
|
28
|
+
/>
|
|
29
|
+
</template>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { VTabs, VTab, VContainer } from 'vuetify/components'
|
|
3
|
+
import { ref } from 'vue'
|
|
4
|
+
import { isSection } from '@json-layout/core'
|
|
5
|
+
import Node from '../node.vue'
|
|
6
|
+
import SectionHeader from '../fragments/section-header.vue'
|
|
7
|
+
|
|
8
|
+
defineProps({
|
|
9
|
+
modelValue: {
|
|
10
|
+
/** @type import('vue').PropType<import('../types.js').VjsfTabsNode> */
|
|
11
|
+
type: Object,
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
statefulLayout: {
|
|
15
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
16
|
+
type: Object,
|
|
17
|
+
required: true
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const tab = ref(0)
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<section-header :node="modelValue" />
|
|
26
|
+
<v-sheet border>
|
|
27
|
+
<v-tabs v-model="tab">
|
|
28
|
+
<v-tab
|
|
29
|
+
v-for="(child, i) of modelValue.children"
|
|
30
|
+
:key="child.key"
|
|
31
|
+
:value="i"
|
|
32
|
+
:density="modelValue.options.density"
|
|
33
|
+
:color="child.validated && (child.error || child.childError) ? 'error' : undefined"
|
|
34
|
+
>
|
|
35
|
+
<v-icon
|
|
36
|
+
v-if="child.validated && (child.error || child.childError)"
|
|
37
|
+
color="error"
|
|
38
|
+
>
|
|
39
|
+
mdi-alert
|
|
40
|
+
</v-icon>
|
|
41
|
+
{{ child.layout.title ?? child.layout.label }}
|
|
42
|
+
</v-tab>
|
|
43
|
+
</v-tabs>
|
|
44
|
+
<v-window v-model="tab">
|
|
45
|
+
<v-window-item
|
|
46
|
+
v-for="(child, i) of modelValue.children"
|
|
47
|
+
:key="child.key"
|
|
48
|
+
:value="i"
|
|
49
|
+
>
|
|
50
|
+
<v-container fluid>
|
|
51
|
+
<v-row>
|
|
52
|
+
<node
|
|
53
|
+
v-for="grandChild of isSection(child) ? child.children : [child]"
|
|
54
|
+
:key="grandChild.fullKey"
|
|
55
|
+
:model-value="/** @type import('../types.js').VjsfNode */(grandChild)"
|
|
56
|
+
:stateful-layout="statefulLayout"
|
|
57
|
+
/>
|
|
58
|
+
</v-row>
|
|
59
|
+
</v-container>
|
|
60
|
+
</v-window-item>
|
|
61
|
+
</v-window>
|
|
62
|
+
</v-sheet>
|
|
63
|
+
</template>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { defineComponent, h, computed } from 'vue'
|
|
3
|
+
import { VTextField } from 'vuetify/components'
|
|
4
|
+
import { getInputProps } from '../../utils/props.js'
|
|
5
|
+
import { getCompSlots } from '../../utils/slots.js'
|
|
6
|
+
|
|
7
|
+
export default defineComponent({
|
|
8
|
+
props: {
|
|
9
|
+
modelValue: {
|
|
10
|
+
/** @type import('vue').PropType<import('../types.js').VjsfTextFieldNode> */
|
|
11
|
+
type: Object,
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
statefulLayout: {
|
|
15
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
16
|
+
type: Object,
|
|
17
|
+
required: true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
setup (props) {
|
|
21
|
+
const fieldProps = computed(() => getInputProps(props.modelValue, props.statefulLayout))
|
|
22
|
+
const fieldSlots = computed(() => getCompSlots(props.modelValue, props.statefulLayout))
|
|
23
|
+
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
return () => h(VTextField, fieldProps.value, fieldSlots.value)
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
</script>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { defineComponent, h, computed } from 'vue'
|
|
3
|
+
import { VTextarea } from 'vuetify/components'
|
|
4
|
+
import { getInputProps } from '../../utils/props.js'
|
|
5
|
+
import { getCompSlots } from '../../utils/slots.js'
|
|
6
|
+
|
|
7
|
+
export default defineComponent({
|
|
8
|
+
props: {
|
|
9
|
+
modelValue: {
|
|
10
|
+
/** @type import('vue').PropType<import('../types.js').VjsfTextareaNode> */
|
|
11
|
+
type: Object,
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
statefulLayout: {
|
|
15
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
16
|
+
type: Object,
|
|
17
|
+
required: true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
setup (props) {
|
|
21
|
+
const fieldProps = computed(() => getInputProps(props.modelValue, props.statefulLayout))
|
|
22
|
+
const fieldSlots = computed(() => getCompSlots(props.modelValue, props.statefulLayout))
|
|
23
|
+
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
return () => h(VTextarea, fieldProps.value, fieldSlots.value)
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
</script>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { isSection } from '@json-layout/core'
|
|
3
|
+
import { VTabs, VTab, VContainer } from 'vuetify/components'
|
|
4
|
+
import { ref } from 'vue'
|
|
5
|
+
import Node from '../node.vue'
|
|
6
|
+
import SectionHeader from '../fragments/section-header.vue'
|
|
7
|
+
|
|
8
|
+
defineProps({
|
|
9
|
+
modelValue: {
|
|
10
|
+
/** @type import('vue').PropType<import('../types.js').VjsfVerticalTabsNode> */
|
|
11
|
+
type: Object,
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
statefulLayout: {
|
|
15
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
16
|
+
type: Object,
|
|
17
|
+
required: true
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const tab = ref(0)
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<section-header :node="modelValue" />
|
|
26
|
+
<v-sheet border>
|
|
27
|
+
<div class="d-flex flex-row">
|
|
28
|
+
<v-tabs
|
|
29
|
+
v-model="tab"
|
|
30
|
+
direction="vertical"
|
|
31
|
+
>
|
|
32
|
+
<v-tab
|
|
33
|
+
v-for="(child, i) of modelValue.children"
|
|
34
|
+
:key="child.key"
|
|
35
|
+
:value="i"
|
|
36
|
+
:color="child.validated && (child.error || child.childError) ? 'error' : undefined"
|
|
37
|
+
>
|
|
38
|
+
<v-icon
|
|
39
|
+
v-if="child.validated && (child.error || child.childError)"
|
|
40
|
+
color="error"
|
|
41
|
+
>
|
|
42
|
+
mdi-alert
|
|
43
|
+
</v-icon>
|
|
44
|
+
{{ child.layout.title ?? child.layout.label }}
|
|
45
|
+
</v-tab>
|
|
46
|
+
</v-tabs>
|
|
47
|
+
<v-window
|
|
48
|
+
v-model="tab"
|
|
49
|
+
class="flex-fill"
|
|
50
|
+
>
|
|
51
|
+
<v-window-item
|
|
52
|
+
v-for="(child, i) of modelValue.children"
|
|
53
|
+
:key="child.key"
|
|
54
|
+
:value="i"
|
|
55
|
+
>
|
|
56
|
+
<v-container fluid>
|
|
57
|
+
<v-row>
|
|
58
|
+
<node
|
|
59
|
+
v-for="grandChild of isSection(child) ? child.children : [child]"
|
|
60
|
+
:key="grandChild.fullKey"
|
|
61
|
+
:model-value="/** @type import('../types.js').VjsfNode */(grandChild)"
|
|
62
|
+
:stateful-layout="statefulLayout"
|
|
63
|
+
/>
|
|
64
|
+
</v-row>
|
|
65
|
+
</v-container>
|
|
66
|
+
</v-window-item>
|
|
67
|
+
</v-window>
|
|
68
|
+
</div>
|
|
69
|
+
</v-sheet>
|
|
70
|
+
</template>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** @type import("./types.js").PartialVjsfOptions */
|
|
2
|
+
export const defaultOptions = {
|
|
3
|
+
// matches the density prop found in many vuetify components
|
|
4
|
+
density: 'default',
|
|
5
|
+
titleDepth: 2,
|
|
6
|
+
fieldProps: {},
|
|
7
|
+
fieldPropsCompact: {
|
|
8
|
+
density: 'compact',
|
|
9
|
+
hideDetails: 'auto'
|
|
10
|
+
},
|
|
11
|
+
fieldPropsComfortable: {
|
|
12
|
+
density: 'comfortable'
|
|
13
|
+
},
|
|
14
|
+
fieldPropsReadOnly: { hideDetails: 'auto', variant: 'plain' },
|
|
15
|
+
textfieldProps: {},
|
|
16
|
+
textfieldPropsReadOnly: {},
|
|
17
|
+
textareaProps: {},
|
|
18
|
+
textareaPropsReadOnly: {},
|
|
19
|
+
// it is not very common to show an error below checkboxes and switches and without hide-details=auto they take a lot of space
|
|
20
|
+
checkboxProps: { hideDetails: 'auto' },
|
|
21
|
+
checkboxPropsReadOnly: {},
|
|
22
|
+
switchProps: { hideDetails: 'auto' },
|
|
23
|
+
switchPropsReadOnly: {},
|
|
24
|
+
errorAlertProps: { type: 'error', variant: 'tonal' }
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { VRow } from 'vuetify/components'
|
|
3
|
+
import Node from './node.vue'
|
|
4
|
+
|
|
5
|
+
defineProps({
|
|
6
|
+
modelValue: {
|
|
7
|
+
/** @type import('vue').PropType<import('@json-layout/core').StateTree> */
|
|
8
|
+
type: Object,
|
|
9
|
+
required: true
|
|
10
|
+
},
|
|
11
|
+
statefulLayout: {
|
|
12
|
+
/** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
|
|
13
|
+
type: Object,
|
|
14
|
+
required: true
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<v-row class="vjsf-tree">
|
|
21
|
+
<node
|
|
22
|
+
:stateful-layout="statefulLayout"
|
|
23
|
+
:model-value="/** @type import('./types.js').VjsfNode */(modelValue.root)"
|
|
24
|
+
/>
|
|
25
|
+
</v-row>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StatefulLayoutOptions,
|
|
3
|
+
StateNode,
|
|
4
|
+
CheckboxNode,
|
|
5
|
+
ColorPickerNode,
|
|
6
|
+
DatePickerNode,
|
|
7
|
+
DateTimePickerNode,
|
|
8
|
+
TabsNode,
|
|
9
|
+
ExpansionPanelsNode,
|
|
10
|
+
ListNode,
|
|
11
|
+
NumberFieldNode,
|
|
12
|
+
OneOfSelectNode,
|
|
13
|
+
SectionNode,
|
|
14
|
+
SelectNode,
|
|
15
|
+
SliderNode,
|
|
16
|
+
SwitchNode,
|
|
17
|
+
TextFieldNode,
|
|
18
|
+
TextareaNode,
|
|
19
|
+
VerticalTabsNode,
|
|
20
|
+
ComboboxNode,
|
|
21
|
+
CompileOptions
|
|
22
|
+
} from '@json-layout/core'
|
|
23
|
+
|
|
24
|
+
export type Density = 'default' | 'comfortable' | 'compact'
|
|
25
|
+
|
|
26
|
+
export type VjsfOptions = StatefulLayoutOptions & CompileOptions & {
|
|
27
|
+
density: Density,
|
|
28
|
+
fieldProps: Record<string, unknown>,
|
|
29
|
+
fieldPropsCompact: Record<string, unknown>,
|
|
30
|
+
fieldPropsComfortable: Record<string, unknown>,
|
|
31
|
+
fieldPropsReadOnly: Record<string, unknown>,
|
|
32
|
+
textfieldProps: Record<string, unknown>,
|
|
33
|
+
textfieldPropsReadOnly: Record<string, unknown>,
|
|
34
|
+
textareaProps: Record<string, unknown>,
|
|
35
|
+
textareaPropsReadOnly: Record<string, unknown>,
|
|
36
|
+
checkboxProps: Record<string, unknown>,
|
|
37
|
+
checkboxPropsReadOnly: Record<string, unknown>,
|
|
38
|
+
switchProps: Record<string, unknown>,
|
|
39
|
+
switchPropsReadOnly: Record<string, unknown>,
|
|
40
|
+
errorAlertProps: Record<string, unknown>,
|
|
41
|
+
vjsfSlots: Record<string, () => unknown>,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type PartialVjsfOptions = Partial<Omit<VjsfOptions, 'width'>>
|
|
45
|
+
|
|
46
|
+
export type VjsfNode = Omit<StateNode, 'options'> & {options: VjsfOptions}
|
|
47
|
+
export type VjsfTabsNode = Omit<TabsNode, 'options'> & {options: VjsfOptions}
|
|
48
|
+
export type VjsfCheckboxNode = Omit<CheckboxNode, 'options'> & {options: VjsfOptions}
|
|
49
|
+
export type VjsfColorPickerNode = Omit<ColorPickerNode, 'options'> & {options: VjsfOptions}
|
|
50
|
+
export type VjsfDatePickerNode = Omit<DatePickerNode, 'options'> & {options: VjsfOptions}
|
|
51
|
+
export type VjsfDateTimePickerNode = Omit<DateTimePickerNode, 'options'> & {options: VjsfOptions}
|
|
52
|
+
export type VjsfExpansionPanelsNode = Omit<ExpansionPanelsNode, 'options'> & {options: VjsfOptions}
|
|
53
|
+
export type VjsfListNode = Omit<ListNode, 'options'> & {options: VjsfOptions}
|
|
54
|
+
export type VjsfNumberFieldNode = Omit<NumberFieldNode, 'options'> & {options: VjsfOptions}
|
|
55
|
+
export type VjsfOneOfSelectNode = Omit<OneOfSelectNode, 'options'> & {options: VjsfOptions}
|
|
56
|
+
export type VjsfSectionNode = Omit<SectionNode, 'options'> & {options: VjsfOptions}
|
|
57
|
+
export type VjsfSelectNode = Omit<SelectNode, 'options'> & {options: VjsfOptions}
|
|
58
|
+
export type VjsfSliderNode = Omit<SliderNode, 'options'> & {options: VjsfOptions}
|
|
59
|
+
export type VjsfSwitchNode = Omit<SwitchNode, 'options'> & {options: VjsfOptions}
|
|
60
|
+
export type VjsfTextFieldNode = Omit<TextFieldNode, 'options'> & {options: VjsfOptions}
|
|
61
|
+
export type VjsfTextareaNode = Omit<TextareaNode, 'options'> & {options: VjsfOptions}
|
|
62
|
+
export type VjsfVerticalTabsNode = Omit<VerticalTabsNode, 'options'> & {options: VjsfOptions}
|
|
63
|
+
export type VjsfComboboxNode = Omit<ComboboxNode, 'options'> & {options: VjsfOptions}
|