@koumoul/vjsf 3.0.0-alpha.3 → 3.0.0-alpha.5
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 +27 -6
- package/src/compile/index.js +18 -4
- package/src/compile/options.js +19 -0
- package/src/compile/v-jsf-compiled.vue.ejs +28 -10
- package/src/components/fragments/help-message.vue +3 -2
- package/src/components/fragments/node-slot.vue +3 -3
- package/src/components/fragments/section-header.vue +2 -1
- package/src/components/fragments/text-field-menu.vue +3 -3
- package/src/components/node.vue +27 -10
- package/src/components/nodes/autocomplete.vue +3 -10
- package/src/components/nodes/checkbox.vue +3 -3
- package/src/components/nodes/color-picker.vue +3 -3
- package/src/components/nodes/combobox.vue +3 -4
- package/src/components/nodes/date-picker.vue +3 -4
- package/src/components/nodes/date-time-picker.vue +2 -2
- package/src/components/nodes/expansion-panels.vue +4 -4
- package/src/components/nodes/file-input.vue +43 -0
- package/src/components/nodes/list.vue +14 -11
- package/src/components/nodes/number-combobox.vue +3 -4
- package/src/components/nodes/number-field.vue +3 -4
- package/src/components/nodes/one-of-select.vue +4 -4
- package/src/components/nodes/section.vue +4 -3
- package/src/components/nodes/select.vue +3 -4
- package/src/components/nodes/slider.vue +3 -3
- package/src/components/nodes/stepper.vue +4 -6
- package/src/components/nodes/switch.vue +3 -3
- package/src/components/nodes/tabs.vue +4 -4
- package/src/components/nodes/text-field.vue +9 -4
- package/src/components/nodes/textarea.vue +26 -6
- package/src/components/nodes/vertical-tabs.vue +4 -4
- package/src/components/options.js +9 -6
- package/src/components/tree.vue +2 -2
- package/src/components/vjsf.vue +9 -13
- package/src/composables/use-dnd.js +16 -1
- package/src/composables/use-vjsf.js +11 -9
- package/src/index.js +1 -0
- package/src/{components/types.ts → types.ts} +18 -2
- package/src/utils/global-register.js +10 -0
- package/src/utils/index.js +5 -0
- package/src/utils/props.js +4 -4
- package/src/utils/slots.js +2 -3
- package/types/compile/index.d.ts +3 -2
- package/types/compile/index.d.ts.map +1 -1
- package/types/compile/options.d.ts +4 -0
- package/types/compile/options.d.ts.map +1 -0
- package/types/components/fragments/help-message.vue.d.ts +2 -2
- package/types/components/fragments/node-slot.vue.d.ts +8 -8
- package/types/components/fragments/node-slot.vue.d.ts.map +1 -1
- package/types/components/fragments/section-header.vue.d.ts +2 -2
- package/types/components/fragments/select-item.vue.d.ts +2 -2
- package/types/components/fragments/text-field-menu.vue.d.ts +4 -4
- package/types/components/fragments/text-field-menu.vue.d.ts.map +1 -1
- package/types/components/global-register.d.ts +8 -0
- package/types/components/global-register.d.ts.map +1 -0
- package/types/components/node.vue.d.ts +4 -4
- package/types/components/nodes/autocomplete.vue.d.ts +8 -8
- package/types/components/nodes/autocomplete.vue.d.ts.map +1 -1
- package/types/components/nodes/checkbox.vue.d.ts +4 -4
- package/types/components/nodes/color-picker.vue.d.ts +4 -4
- package/types/components/nodes/combobox.vue.d.ts +8 -8
- package/types/components/nodes/combobox.vue.d.ts.map +1 -1
- package/types/components/nodes/date-picker.vue.d.ts +4 -4
- package/types/components/nodes/date-time-picker.vue.d.ts +4 -4
- package/types/components/nodes/expansion-panels.vue.d.ts +4 -4
- package/types/components/nodes/file-input.vue.d.ts +27 -0
- package/types/components/nodes/file-input.vue.d.ts.map +1 -0
- package/types/components/nodes/list.vue.d.ts +4 -4
- package/types/components/nodes/number-combobox.vue.d.ts +8 -8
- package/types/components/nodes/number-combobox.vue.d.ts.map +1 -1
- package/types/components/nodes/number-field.vue.d.ts +8 -8
- package/types/components/nodes/number-field.vue.d.ts.map +1 -1
- package/types/components/nodes/one-of-select.vue.d.ts +4 -4
- package/types/components/nodes/section.vue.d.ts +4 -4
- package/types/components/nodes/select.vue.d.ts +8 -8
- package/types/components/nodes/select.vue.d.ts.map +1 -1
- package/types/components/nodes/slider.vue.d.ts +4 -4
- package/types/components/nodes/stepper.vue.d.ts +4 -4
- package/types/components/nodes/switch.vue.d.ts +4 -4
- package/types/components/nodes/tabs.vue.d.ts +4 -4
- package/types/components/nodes/text-field.vue.d.ts +8 -8
- package/types/components/nodes/text-field.vue.d.ts.map +1 -1
- package/types/components/nodes/textarea.vue.d.ts +8 -8
- package/types/components/nodes/textarea.vue.d.ts.map +1 -1
- package/types/components/nodes/vertical-tabs.vue.d.ts +4 -4
- package/types/components/options.d.ts +3 -3
- package/types/components/options.d.ts.map +1 -1
- package/types/components/tree.vue.d.ts +2 -2
- package/types/components/types.d.ts +14 -2
- package/types/components/types.d.ts.map +1 -1
- package/types/components/vjsf.vue.d.ts +3 -3
- package/types/composables/use-dnd.d.ts +5 -1
- package/types/composables/use-dnd.d.ts.map +1 -1
- package/types/composables/use-vjsf.d.ts +4 -5
- package/types/composables/use-vjsf.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/types.d.ts +95 -0
- package/types/types.d.ts.map +1 -0
- package/types/utils/global-register.d.ts +8 -0
- package/types/utils/global-register.d.ts.map +1 -0
- package/types/utils/index.d.ts +6 -0
- package/types/utils/index.d.ts.map +1 -0
- package/types/utils/props.d.ts +3 -3
- package/types/utils/props.d.ts.map +1 -1
- package/types/utils/slots.d.ts +3 -3
- package/types/utils/slots.d.ts.map +1 -1
- package/src/components/nodes/markdown.vue +0 -242
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { defineComponent, h, computed, shallowRef, ref } from 'vue'
|
|
3
3
|
import { VCombobox } from 'vuetify/components'
|
|
4
|
-
import { getInputProps } from '../../utils/
|
|
5
|
-
import { getCompSlots } from '../../utils/slots.js'
|
|
4
|
+
import { getInputProps, getCompSlots } from '../../utils/index.js'
|
|
6
5
|
|
|
7
6
|
export default defineComponent({
|
|
8
7
|
props: {
|
|
9
8
|
modelValue: {
|
|
10
|
-
/** @type import('vue').PropType<import('
|
|
9
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfComboboxNode> */
|
|
11
10
|
type: Object,
|
|
12
11
|
required: true
|
|
13
12
|
},
|
|
14
13
|
statefulLayout: {
|
|
15
|
-
/** @type import('vue').PropType<import('
|
|
14
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
16
15
|
type: Object,
|
|
17
16
|
required: true
|
|
18
17
|
}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { defineComponent, h, computed } from 'vue'
|
|
3
3
|
import { VTextField } from 'vuetify/components'
|
|
4
|
-
import { getInputProps } from '../../utils/
|
|
5
|
-
import { getCompSlots } from '../../utils/slots.js'
|
|
4
|
+
import { getInputProps, getCompSlots } from '../../utils/index.js'
|
|
6
5
|
|
|
7
6
|
export default defineComponent({
|
|
8
7
|
props: {
|
|
9
8
|
modelValue: {
|
|
10
|
-
/** @type import('vue').PropType<import('
|
|
9
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfNumberFieldNode> */
|
|
11
10
|
type: Object,
|
|
12
11
|
required: true
|
|
13
12
|
},
|
|
14
13
|
statefulLayout: {
|
|
15
|
-
/** @type import('vue').PropType<import('
|
|
14
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
16
15
|
type: Object,
|
|
17
16
|
required: true
|
|
18
17
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { VSelect } from 'vuetify/components'
|
|
2
|
+
import { VSelect, VRow } from 'vuetify/components'
|
|
3
3
|
import { shallowRef, watch } from 'vue'
|
|
4
4
|
import { isSection } from '@json-layout/core'
|
|
5
5
|
import Node from '../node.vue'
|
|
6
6
|
|
|
7
7
|
const props = defineProps({
|
|
8
8
|
modelValue: {
|
|
9
|
-
/** @type import('vue').PropType<import('
|
|
9
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfOneOfSelectNode> */
|
|
10
10
|
type: Object,
|
|
11
11
|
required: true
|
|
12
12
|
},
|
|
13
13
|
statefulLayout: {
|
|
14
|
-
/** @type import('vue').PropType<import('
|
|
14
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
15
15
|
type: Object,
|
|
16
16
|
required: true
|
|
17
17
|
}
|
|
@@ -49,7 +49,7 @@ const onChange = (/** @type import('@json-layout/core').SkeletonTree */childTree
|
|
|
49
49
|
<node
|
|
50
50
|
v-for="grandChild of isSection(modelValue.children?.[0]) ? modelValue.children?.[0].children : modelValue.children"
|
|
51
51
|
:key="grandChild.fullKey"
|
|
52
|
-
:model-value="/** @type import('
|
|
52
|
+
:model-value="/** @type import('../../types.js').VjsfNode */(grandChild)"
|
|
53
53
|
:stateful-layout="statefulLayout"
|
|
54
54
|
/>
|
|
55
55
|
</v-row>
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { VRow } from 'vuetify/components'
|
|
2
3
|
import Node from '../node.vue'
|
|
3
4
|
import SectionHeader from '../fragments/section-header.vue'
|
|
4
5
|
|
|
5
6
|
defineProps({
|
|
6
7
|
modelValue: {
|
|
7
|
-
/** @type import('vue').PropType<import('
|
|
8
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfSectionNode> */
|
|
8
9
|
type: Object,
|
|
9
10
|
required: true
|
|
10
11
|
},
|
|
11
12
|
statefulLayout: {
|
|
12
|
-
/** @type import('vue').PropType<import('
|
|
13
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
13
14
|
type: Object,
|
|
14
15
|
required: true
|
|
15
16
|
}
|
|
@@ -23,7 +24,7 @@ defineProps({
|
|
|
23
24
|
<node
|
|
24
25
|
v-for="child of modelValue.children"
|
|
25
26
|
:key="child.fullKey"
|
|
26
|
-
:model-value="/** @type import('
|
|
27
|
+
:model-value="/** @type import('../../types.js').VjsfNode */(child)"
|
|
27
28
|
:stateful-layout="statefulLayout"
|
|
28
29
|
/>
|
|
29
30
|
</v-row>
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { VSelect } from 'vuetify/components'
|
|
3
3
|
import { defineComponent, h, computed, ref, shallowRef } from 'vue'
|
|
4
|
-
import { getInputProps } from '../../utils/
|
|
5
|
-
import { getCompSlots } from '../../utils/slots.js'
|
|
4
|
+
import { getInputProps, getCompSlots } from '../../utils/index.js'
|
|
6
5
|
import SelectItem from '../fragments/select-item.vue'
|
|
7
6
|
import SelectSelection from '../fragments/select-selection.vue'
|
|
8
7
|
|
|
9
8
|
export default defineComponent({
|
|
10
9
|
props: {
|
|
11
10
|
modelValue: {
|
|
12
|
-
/** @type import('vue').PropType<import('
|
|
11
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfSelectNode> */
|
|
13
12
|
type: Object,
|
|
14
13
|
required: true
|
|
15
14
|
},
|
|
16
15
|
statefulLayout: {
|
|
17
|
-
/** @type import('vue').PropType<import('
|
|
16
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
18
17
|
type: Object,
|
|
19
18
|
required: true
|
|
20
19
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { VSlider } from 'vuetify/components'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
|
-
import { getInputProps } from '../../utils/
|
|
4
|
+
import { getInputProps } from '../../utils/index.js'
|
|
5
5
|
|
|
6
6
|
const props = defineProps({
|
|
7
7
|
modelValue: {
|
|
8
|
-
/** @type import('vue').PropType<import('
|
|
8
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfSliderNode> */
|
|
9
9
|
type: Object,
|
|
10
10
|
required: true
|
|
11
11
|
},
|
|
12
12
|
statefulLayout: {
|
|
13
|
-
/** @type import('vue').PropType<import('
|
|
13
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
14
14
|
type: Object,
|
|
15
15
|
required: true
|
|
16
16
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { ref, computed } from 'vue'
|
|
3
|
-
import { VStepper, VStepperHeader, VStepperItem, VContainer } from 'vuetify/components'
|
|
3
|
+
import { VStepper, VStepperHeader, VStepperItem, VStepperWindow, VStepperWindowItem, VStepperActions, VContainer, VRow, VSpacer, VBtn, VDivider } from 'vuetify/components'
|
|
4
4
|
import { isSection } from '@json-layout/core'
|
|
5
5
|
import Node from '../node.vue'
|
|
6
6
|
import SectionHeader from '../fragments/section-header.vue'
|
|
7
7
|
|
|
8
8
|
const props = defineProps({
|
|
9
9
|
modelValue: {
|
|
10
|
-
/** @type import('vue').PropType<import('
|
|
10
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStepperNode> */
|
|
11
11
|
type: Object,
|
|
12
12
|
required: true
|
|
13
13
|
},
|
|
14
14
|
statefulLayout: {
|
|
15
|
-
/** @type import('vue').PropType<import('
|
|
15
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
16
16
|
type: Object,
|
|
17
17
|
required: true
|
|
18
18
|
}
|
|
@@ -26,10 +26,8 @@ const firstErrorIndex = computed(() => {
|
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
const goNext = () => {
|
|
29
|
-
console.log(props.statefulLayout.validationState)
|
|
30
29
|
const child = props.modelValue.children[step.value]
|
|
31
30
|
props.statefulLayout.validateNodeRecurse(child)
|
|
32
|
-
console.log(props.statefulLayout.validationState)
|
|
33
31
|
if (!(child.error || child.childError)) step.value++
|
|
34
32
|
}
|
|
35
33
|
</script>
|
|
@@ -65,7 +63,7 @@ const goNext = () => {
|
|
|
65
63
|
<node
|
|
66
64
|
v-for="grandChild of isSection(child) ? child.children : [child]"
|
|
67
65
|
:key="grandChild.fullKey"
|
|
68
|
-
:model-value="/** @type import('
|
|
66
|
+
:model-value="/** @type import('../../types.js').VjsfNode */(grandChild)"
|
|
69
67
|
:stateful-layout="statefulLayout"
|
|
70
68
|
/>
|
|
71
69
|
</v-row>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { VSwitch } from 'vuetify/components'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
|
-
import { getInputProps } from '../../utils/
|
|
4
|
+
import { getInputProps } from '../../utils/index.js'
|
|
5
5
|
|
|
6
6
|
const props = defineProps({
|
|
7
7
|
modelValue: {
|
|
8
|
-
/** @type import('vue').PropType<import('
|
|
8
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfSwitchNode> */
|
|
9
9
|
type: Object,
|
|
10
10
|
required: true
|
|
11
11
|
},
|
|
12
12
|
statefulLayout: {
|
|
13
|
-
/** @type import('vue').PropType<import('
|
|
13
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
14
14
|
type: Object,
|
|
15
15
|
required: true
|
|
16
16
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { VTabs, VTab, VContainer } from 'vuetify/components'
|
|
2
|
+
import { VTabs, VTab, VContainer, VSheet, VWindow, VWindowItem, VRow, VIcon } from 'vuetify/components'
|
|
3
3
|
import { ref } from 'vue'
|
|
4
4
|
import { isSection } from '@json-layout/core'
|
|
5
5
|
import Node from '../node.vue'
|
|
@@ -7,12 +7,12 @@ import SectionHeader from '../fragments/section-header.vue'
|
|
|
7
7
|
|
|
8
8
|
defineProps({
|
|
9
9
|
modelValue: {
|
|
10
|
-
/** @type import('vue').PropType<import('
|
|
10
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfTabsNode> */
|
|
11
11
|
type: Object,
|
|
12
12
|
required: true
|
|
13
13
|
},
|
|
14
14
|
statefulLayout: {
|
|
15
|
-
/** @type import('vue').PropType<import('
|
|
15
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
16
16
|
type: Object,
|
|
17
17
|
required: true
|
|
18
18
|
}
|
|
@@ -52,7 +52,7 @@ const tab = ref(0)
|
|
|
52
52
|
<node
|
|
53
53
|
v-for="grandChild of isSection(child) ? child.children : [child]"
|
|
54
54
|
:key="grandChild.fullKey"
|
|
55
|
-
:model-value="/** @type import('
|
|
55
|
+
:model-value="/** @type import('../../types.js').VjsfNode */(grandChild)"
|
|
56
56
|
:stateful-layout="statefulLayout"
|
|
57
57
|
/>
|
|
58
58
|
</v-row>
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { defineComponent, h, computed } from 'vue'
|
|
3
3
|
import { VTextField } from 'vuetify/components'
|
|
4
|
-
import { getInputProps } from '../../utils/
|
|
5
|
-
import { getCompSlots } from '../../utils/slots.js'
|
|
4
|
+
import { getInputProps, getCompSlots } from '../../utils/index.js'
|
|
6
5
|
|
|
7
6
|
export default defineComponent({
|
|
8
7
|
props: {
|
|
9
8
|
modelValue: {
|
|
10
|
-
/** @type import('vue').PropType<import('
|
|
9
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfTextFieldNode> */
|
|
11
10
|
type: Object,
|
|
12
11
|
required: true
|
|
13
12
|
},
|
|
14
13
|
statefulLayout: {
|
|
15
|
-
/** @type import('vue').PropType<import('
|
|
14
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
16
15
|
type: Object,
|
|
17
16
|
required: true
|
|
18
17
|
}
|
|
@@ -27,3 +26,9 @@ export default defineComponent({
|
|
|
27
26
|
})
|
|
28
27
|
|
|
29
28
|
</script>
|
|
29
|
+
|
|
30
|
+
<style>
|
|
31
|
+
.vjsf-node-text-field.vjsf-readonly.vjsf-summary input {
|
|
32
|
+
text-overflow: ellipsis;
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
@@ -1,29 +1,49 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { defineComponent, h, computed } from 'vue'
|
|
2
|
+
import { defineComponent, h, computed, ref, watch } from 'vue'
|
|
3
3
|
import { VTextarea } from 'vuetify/components'
|
|
4
|
-
import { getInputProps } from '../../utils/
|
|
5
|
-
import { getCompSlots } from '../../utils/slots.js'
|
|
4
|
+
import { getInputProps, getCompSlots } from '../../utils/index.js'
|
|
6
5
|
|
|
7
6
|
export default defineComponent({
|
|
8
7
|
props: {
|
|
9
8
|
modelValue: {
|
|
10
|
-
/** @type import('vue').PropType<import('
|
|
9
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfTextareaNode> */
|
|
11
10
|
type: Object,
|
|
12
11
|
required: true
|
|
13
12
|
},
|
|
14
13
|
statefulLayout: {
|
|
15
|
-
/** @type import('vue').PropType<import('
|
|
14
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
16
15
|
type: Object,
|
|
17
16
|
required: true
|
|
18
17
|
}
|
|
19
18
|
},
|
|
20
19
|
setup (props) {
|
|
21
|
-
|
|
20
|
+
/** @type {import('vue').Ref<null | HTMLElement>} */
|
|
21
|
+
const textarea = ref(null)
|
|
22
|
+
|
|
23
|
+
const fieldProps = computed(() => {
|
|
24
|
+
const inputProps = getInputProps(props.modelValue, props.statefulLayout, ['placeholder'])
|
|
25
|
+
inputProps.ref = textarea
|
|
26
|
+
if (props.modelValue.options.readOnly && props.modelValue.options.summary) inputProps.rows = 3
|
|
27
|
+
return inputProps
|
|
28
|
+
})
|
|
22
29
|
const fieldSlots = computed(() => getCompSlots(props.modelValue, props.statefulLayout))
|
|
23
30
|
|
|
31
|
+
watch(() => props.modelValue.options.readOnly, (readOnly) => {
|
|
32
|
+
if (readOnly && textarea.value) {
|
|
33
|
+
textarea.value.scrollTop = 0
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
24
37
|
// @ts-ignore
|
|
25
38
|
return () => h(VTextarea, fieldProps.value, fieldSlots.value)
|
|
26
39
|
}
|
|
27
40
|
})
|
|
28
41
|
|
|
29
42
|
</script>
|
|
43
|
+
|
|
44
|
+
<style>
|
|
45
|
+
.vjsf-node-textarea.vjsf-readonly.vjsf-summary textarea {
|
|
46
|
+
overflow: hidden;
|
|
47
|
+
mask-image: linear-gradient(180deg, #000 66%, transparent 90%);
|
|
48
|
+
}
|
|
49
|
+
</style>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { isSection } from '@json-layout/core'
|
|
3
|
-
import { VTabs, VTab, VContainer } from 'vuetify/components'
|
|
3
|
+
import { VTabs, VTab, VContainer, VSheet, VWindow, VWindowItem, VRow, VIcon } from 'vuetify/components'
|
|
4
4
|
import { ref } from 'vue'
|
|
5
5
|
import Node from '../node.vue'
|
|
6
6
|
import SectionHeader from '../fragments/section-header.vue'
|
|
7
7
|
|
|
8
8
|
defineProps({
|
|
9
9
|
modelValue: {
|
|
10
|
-
/** @type import('vue').PropType<import('
|
|
10
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfVerticalTabsNode> */
|
|
11
11
|
type: Object,
|
|
12
12
|
required: true
|
|
13
13
|
},
|
|
14
14
|
statefulLayout: {
|
|
15
|
-
/** @type import('vue').PropType<import('
|
|
15
|
+
/** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
|
|
16
16
|
type: Object,
|
|
17
17
|
required: true
|
|
18
18
|
}
|
|
@@ -58,7 +58,7 @@ const tab = ref(0)
|
|
|
58
58
|
<node
|
|
59
59
|
v-for="grandChild of isSection(child) ? child.children : [child]"
|
|
60
60
|
:key="grandChild.fullKey"
|
|
61
|
-
:model-value="/** @type import('
|
|
61
|
+
:model-value="/** @type import('../../types.js').VjsfNode */(grandChild)"
|
|
62
62
|
:stateful-layout="statefulLayout"
|
|
63
63
|
/>
|
|
64
64
|
</v-row>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @type import("
|
|
1
|
+
/** @type import("../types.js").PartialVjsfOptions */
|
|
2
2
|
export const defaultOptions = {
|
|
3
3
|
// matches the density prop found in many vuetify components
|
|
4
4
|
density: 'default',
|
|
@@ -22,25 +22,28 @@ export const defaultOptions = {
|
|
|
22
22
|
switchProps: { hideDetails: 'auto' },
|
|
23
23
|
switchPropsReadOnly: {},
|
|
24
24
|
errorAlertProps: { type: 'error', variant: 'tonal' },
|
|
25
|
-
easyMDEOptions: {}
|
|
25
|
+
easyMDEOptions: {},
|
|
26
|
+
nodeComponents: {}
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
*
|
|
30
|
-
* @param {Partial<import("
|
|
31
|
+
* @param {Partial<import("../types.js").VjsfOptions>} options
|
|
31
32
|
* @param {any} form
|
|
32
33
|
* @param {number} width
|
|
33
34
|
* @param {import("vue").Slots} slots
|
|
35
|
+
* @param {Record<string, import('vue').Component>} nodeComponents
|
|
34
36
|
* @returns
|
|
35
37
|
*/
|
|
36
|
-
export const getFullOptions = (options, form, width, slots) => {
|
|
38
|
+
export const getFullOptions = (options, form, width, slots, nodeComponents) => {
|
|
37
39
|
const fullOptions = {
|
|
38
40
|
...defaultOptions,
|
|
39
41
|
readOnly: !!(form && (form.isDisabled.value || form.isReadonly.value)),
|
|
40
42
|
...options,
|
|
41
43
|
context: options.context ? JSON.parse(JSON.stringify(options.context)) : {},
|
|
42
44
|
width: Math.round(width ?? 0),
|
|
43
|
-
vjsfSlots: { ...slots }
|
|
45
|
+
vjsfSlots: { ...slots },
|
|
46
|
+
nodeComponents: { ...nodeComponents, ...options.nodeComponents }
|
|
44
47
|
}
|
|
45
|
-
return /** @type import('
|
|
48
|
+
return /** @type import('../types.js').VjsfOptions */ (fullOptions)
|
|
46
49
|
}
|
package/src/components/tree.vue
CHANGED
|
@@ -9,7 +9,7 @@ defineProps({
|
|
|
9
9
|
required: true
|
|
10
10
|
},
|
|
11
11
|
statefulLayout: {
|
|
12
|
-
/** @type import('vue').PropType<import('
|
|
12
|
+
/** @type import('vue').PropType<import('../types.js').VjsfStatefulLayout> */
|
|
13
13
|
type: Object,
|
|
14
14
|
required: true
|
|
15
15
|
}
|
|
@@ -20,7 +20,7 @@ defineProps({
|
|
|
20
20
|
<v-row class="vjsf-tree">
|
|
21
21
|
<node
|
|
22
22
|
:stateful-layout="statefulLayout"
|
|
23
|
-
:model-value="/** @type import('
|
|
23
|
+
:model-value="/** @type import('../types.js').VjsfNode */(modelValue.root)"
|
|
24
24
|
/>
|
|
25
25
|
</v-row>
|
|
26
26
|
</template>
|
package/src/components/vjsf.vue
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed
|
|
2
|
+
import { computed } from 'vue'
|
|
3
3
|
|
|
4
4
|
import { compile } from '@json-layout/core'
|
|
5
5
|
import Tree from './tree.vue'
|
|
6
6
|
import { useVjsf, emits } from '../composables/use-vjsf.js'
|
|
7
7
|
import '../styles/vjsf.css'
|
|
8
|
+
import { registeredNodeComponents } from '../utils/index.js'
|
|
8
9
|
|
|
9
10
|
import NodeSection from './nodes/section.vue'
|
|
10
11
|
import NodeTextField from './nodes/text-field.vue'
|
|
@@ -26,9 +27,10 @@ import NodeNumberCombobox from './nodes/number-combobox.vue'
|
|
|
26
27
|
import NodeExpansionPanels from './nodes/expansion-panels.vue'
|
|
27
28
|
import NodeStepper from './nodes/stepper.vue'
|
|
28
29
|
import NodeList from './nodes/list.vue'
|
|
29
|
-
import
|
|
30
|
+
import NodeFileInput from './nodes/file-input.vue'
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
/** @type {Record<string, import('vue').Component>} */
|
|
33
|
+
const nodeComponents = {
|
|
32
34
|
section: NodeSection,
|
|
33
35
|
'text-field': NodeTextField,
|
|
34
36
|
textarea: NodeTextarea,
|
|
@@ -49,14 +51,8 @@ const comps = {
|
|
|
49
51
|
list: NodeList,
|
|
50
52
|
combobox: NodeCombobox,
|
|
51
53
|
'number-combobox': NodeNumberCombobox,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const instance = getCurrentInstance()
|
|
56
|
-
for (const [name, comp] of Object.entries(comps)) {
|
|
57
|
-
if (!instance?.appContext.app.component(`vjsf-node-${name}`)) {
|
|
58
|
-
instance?.appContext.app.component(`vjsf-node-${name}`, comp)
|
|
59
|
-
}
|
|
54
|
+
'file-input': NodeFileInput,
|
|
55
|
+
...registeredNodeComponents
|
|
60
56
|
}
|
|
61
57
|
|
|
62
58
|
const props = defineProps({
|
|
@@ -74,7 +70,7 @@ const props = defineProps({
|
|
|
74
70
|
default: null
|
|
75
71
|
},
|
|
76
72
|
options: {
|
|
77
|
-
/** @type import('vue').PropType<import('
|
|
73
|
+
/** @type import('vue').PropType<import('../types.js').PartialVjsfOptions> */
|
|
78
74
|
type: Object,
|
|
79
75
|
required: true
|
|
80
76
|
}
|
|
@@ -86,6 +82,7 @@ const { el, statefulLayout, stateTree } = useVjsf(
|
|
|
86
82
|
computed(() => props.schema),
|
|
87
83
|
computed(() => props.modelValue),
|
|
88
84
|
computed(() => props.options),
|
|
85
|
+
nodeComponents,
|
|
89
86
|
emit,
|
|
90
87
|
compile,
|
|
91
88
|
computed(() => props.precompiledLayout)
|
|
@@ -100,7 +97,6 @@ const { el, statefulLayout, stateTree } = useVjsf(
|
|
|
100
97
|
>
|
|
101
98
|
<tree
|
|
102
99
|
v-if="statefulLayout && stateTree"
|
|
103
|
-
ref="tree"
|
|
104
100
|
:model-value="stateTree"
|
|
105
101
|
:stateful-layout="statefulLayout"
|
|
106
102
|
/>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { shallowRef, ref, computed } from 'vue'
|
|
2
|
-
import { moveArrayItem } from '../utils/
|
|
2
|
+
import { moveArrayItem } from '../utils/index.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @template T
|
|
@@ -18,10 +18,22 @@ export default function useDnd (array, callback) {
|
|
|
18
18
|
|
|
19
19
|
const sortableArray = shallowRef(array)
|
|
20
20
|
|
|
21
|
+
const hovered = ref(-1)
|
|
21
22
|
const draggable = ref(-1)
|
|
22
23
|
const dragging = ref(-1)
|
|
23
24
|
|
|
25
|
+
hovered.value = 1
|
|
26
|
+
|
|
24
27
|
const itemBind = (/** @type {number} */itemIndex) => ({
|
|
28
|
+
// hover the item
|
|
29
|
+
onMouseenter: () => {
|
|
30
|
+
hovered.value = itemIndex
|
|
31
|
+
},
|
|
32
|
+
onMouseleave: () => {
|
|
33
|
+
hovered.value = -1
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// drag the item
|
|
25
37
|
onDragstart: () => {
|
|
26
38
|
dragging.value = itemIndex
|
|
27
39
|
},
|
|
@@ -36,6 +48,7 @@ export default function useDnd (array, callback) {
|
|
|
36
48
|
})
|
|
37
49
|
|
|
38
50
|
const handleBind = (/** @type {number} */itemIndex) => ({
|
|
51
|
+
// hover the handle
|
|
39
52
|
onMouseover () {
|
|
40
53
|
draggable.value = itemIndex
|
|
41
54
|
},
|
|
@@ -47,7 +60,9 @@ export default function useDnd (array, callback) {
|
|
|
47
60
|
return {
|
|
48
61
|
activeDnd,
|
|
49
62
|
sortableArray,
|
|
63
|
+
hovered,
|
|
50
64
|
draggable,
|
|
65
|
+
dragging,
|
|
51
66
|
itemBind,
|
|
52
67
|
handleBind
|
|
53
68
|
}
|
|
@@ -9,7 +9,7 @@ export const emits = {
|
|
|
9
9
|
*/
|
|
10
10
|
'update:modelValue': (data) => true,
|
|
11
11
|
/**
|
|
12
|
-
* @arg {
|
|
12
|
+
* @arg {import('../types.js').VjsfStatefulLayout} state
|
|
13
13
|
*/
|
|
14
14
|
'update:state': (state) => true
|
|
15
15
|
}
|
|
@@ -17,16 +17,17 @@ export const emits = {
|
|
|
17
17
|
/**
|
|
18
18
|
* @param {import('vue').Ref<Object>} schema
|
|
19
19
|
* @param {import('vue').Ref<any>} modelValue
|
|
20
|
-
* @param {import('vue').Ref<import("../
|
|
20
|
+
* @param {import('vue').Ref<import("../types.js").PartialVjsfOptions>} options
|
|
21
|
+
* @param {Record<string, import('vue').Component>} nodeComponents
|
|
21
22
|
* @param {any} emit
|
|
22
23
|
* @param {typeof import('@json-layout/core').compile} [compile]
|
|
23
24
|
* @param {import('vue').Ref<import('@json-layout/core').CompiledLayout>} [precompiledLayout]
|
|
24
25
|
*/
|
|
25
|
-
export const useVjsf = (schema, modelValue, options, emit, compile, precompiledLayout) => {
|
|
26
|
+
export const useVjsf = (schema, modelValue, options, nodeComponents, emit, compile, precompiledLayout) => {
|
|
26
27
|
const el = ref(null)
|
|
27
28
|
const { width } = useElementSize(el)
|
|
28
29
|
|
|
29
|
-
/** @type import('vue').ShallowRef<
|
|
30
|
+
/** @type import('vue').ShallowRef<import('../types.js').VjsfStatefulLayout | null> */
|
|
30
31
|
const statefulLayout = shallowRef(null)
|
|
31
32
|
/** @type import('vue').ShallowRef<import('@json-layout/core').StateTree | null> */
|
|
32
33
|
const stateTree = shallowRef(null)
|
|
@@ -47,7 +48,7 @@ export const useVjsf = (schema, modelValue, options, emit, compile, precompiledL
|
|
|
47
48
|
|
|
48
49
|
const slots = useSlots()
|
|
49
50
|
|
|
50
|
-
const fullOptions = computed(() => getFullOptions(options.value, form, width.value, slots))
|
|
51
|
+
const fullOptions = computed(() => getFullOptions(options.value, form, width.value, slots, nodeComponents))
|
|
51
52
|
|
|
52
53
|
const compiledLayout = computed(() => {
|
|
53
54
|
if (precompiledLayout?.value) return precompiledLayout?.value
|
|
@@ -71,12 +72,13 @@ export const useVjsf = (schema, modelValue, options, emit, compile, precompiledL
|
|
|
71
72
|
|
|
72
73
|
const initStatefulLayout = () => {
|
|
73
74
|
if (!width.value) return
|
|
74
|
-
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
const _statefulLayout = /** @type {import('../types.js').VjsfStatefulLayout} */(new StatefulLayout(
|
|
75
77
|
toRaw(compiledLayout.value),
|
|
76
78
|
toRaw(compiledLayout.value.skeletonTree),
|
|
77
79
|
toRaw(fullOptions.value),
|
|
78
80
|
toRaw(modelValue.value)
|
|
79
|
-
)
|
|
81
|
+
))
|
|
80
82
|
statefulLayout.value = _statefulLayout
|
|
81
83
|
onStatefulLayoutUpdate()
|
|
82
84
|
_statefulLayout.events.on('update', () => {
|
|
@@ -96,7 +98,7 @@ export const useVjsf = (schema, modelValue, options, emit, compile, precompiledL
|
|
|
96
98
|
|
|
97
99
|
watch(fullOptions, (newOptions) => {
|
|
98
100
|
// in case of runtime compilation the watch on compiledLayout will be triggered
|
|
99
|
-
if (!precompiledLayout) return
|
|
101
|
+
if (!precompiledLayout?.value) return
|
|
100
102
|
|
|
101
103
|
if (statefulLayout.value) {
|
|
102
104
|
statefulLayout.value.options = newOptions
|
|
@@ -113,7 +115,7 @@ export const useVjsf = (schema, modelValue, options, emit, compile, precompiledL
|
|
|
113
115
|
// case where schema is updated from outside
|
|
114
116
|
watch(compiledLayout, (newCompiledLayout) => {
|
|
115
117
|
initStatefulLayout()
|
|
116
|
-
}
|
|
118
|
+
})
|
|
117
119
|
|
|
118
120
|
return { el, statefulLayout, stateTree }
|
|
119
121
|
}
|
package/src/index.js
CHANGED