@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.
Files changed (107) hide show
  1. package/package.json +27 -6
  2. package/src/compile/index.js +18 -4
  3. package/src/compile/options.js +19 -0
  4. package/src/compile/v-jsf-compiled.vue.ejs +28 -10
  5. package/src/components/fragments/help-message.vue +3 -2
  6. package/src/components/fragments/node-slot.vue +3 -3
  7. package/src/components/fragments/section-header.vue +2 -1
  8. package/src/components/fragments/text-field-menu.vue +3 -3
  9. package/src/components/node.vue +27 -10
  10. package/src/components/nodes/autocomplete.vue +3 -10
  11. package/src/components/nodes/checkbox.vue +3 -3
  12. package/src/components/nodes/color-picker.vue +3 -3
  13. package/src/components/nodes/combobox.vue +3 -4
  14. package/src/components/nodes/date-picker.vue +3 -4
  15. package/src/components/nodes/date-time-picker.vue +2 -2
  16. package/src/components/nodes/expansion-panels.vue +4 -4
  17. package/src/components/nodes/file-input.vue +43 -0
  18. package/src/components/nodes/list.vue +14 -11
  19. package/src/components/nodes/number-combobox.vue +3 -4
  20. package/src/components/nodes/number-field.vue +3 -4
  21. package/src/components/nodes/one-of-select.vue +4 -4
  22. package/src/components/nodes/section.vue +4 -3
  23. package/src/components/nodes/select.vue +3 -4
  24. package/src/components/nodes/slider.vue +3 -3
  25. package/src/components/nodes/stepper.vue +4 -6
  26. package/src/components/nodes/switch.vue +3 -3
  27. package/src/components/nodes/tabs.vue +4 -4
  28. package/src/components/nodes/text-field.vue +9 -4
  29. package/src/components/nodes/textarea.vue +26 -6
  30. package/src/components/nodes/vertical-tabs.vue +4 -4
  31. package/src/components/options.js +9 -6
  32. package/src/components/tree.vue +2 -2
  33. package/src/components/vjsf.vue +9 -13
  34. package/src/composables/use-dnd.js +16 -1
  35. package/src/composables/use-vjsf.js +11 -9
  36. package/src/index.js +1 -0
  37. package/src/{components/types.ts → types.ts} +18 -2
  38. package/src/utils/global-register.js +10 -0
  39. package/src/utils/index.js +5 -0
  40. package/src/utils/props.js +4 -4
  41. package/src/utils/slots.js +2 -3
  42. package/types/compile/index.d.ts +3 -2
  43. package/types/compile/index.d.ts.map +1 -1
  44. package/types/compile/options.d.ts +4 -0
  45. package/types/compile/options.d.ts.map +1 -0
  46. package/types/components/fragments/help-message.vue.d.ts +2 -2
  47. package/types/components/fragments/node-slot.vue.d.ts +8 -8
  48. package/types/components/fragments/node-slot.vue.d.ts.map +1 -1
  49. package/types/components/fragments/section-header.vue.d.ts +2 -2
  50. package/types/components/fragments/select-item.vue.d.ts +2 -2
  51. package/types/components/fragments/text-field-menu.vue.d.ts +4 -4
  52. package/types/components/fragments/text-field-menu.vue.d.ts.map +1 -1
  53. package/types/components/global-register.d.ts +8 -0
  54. package/types/components/global-register.d.ts.map +1 -0
  55. package/types/components/node.vue.d.ts +4 -4
  56. package/types/components/nodes/autocomplete.vue.d.ts +8 -8
  57. package/types/components/nodes/autocomplete.vue.d.ts.map +1 -1
  58. package/types/components/nodes/checkbox.vue.d.ts +4 -4
  59. package/types/components/nodes/color-picker.vue.d.ts +4 -4
  60. package/types/components/nodes/combobox.vue.d.ts +8 -8
  61. package/types/components/nodes/combobox.vue.d.ts.map +1 -1
  62. package/types/components/nodes/date-picker.vue.d.ts +4 -4
  63. package/types/components/nodes/date-time-picker.vue.d.ts +4 -4
  64. package/types/components/nodes/expansion-panels.vue.d.ts +4 -4
  65. package/types/components/nodes/file-input.vue.d.ts +27 -0
  66. package/types/components/nodes/file-input.vue.d.ts.map +1 -0
  67. package/types/components/nodes/list.vue.d.ts +4 -4
  68. package/types/components/nodes/number-combobox.vue.d.ts +8 -8
  69. package/types/components/nodes/number-combobox.vue.d.ts.map +1 -1
  70. package/types/components/nodes/number-field.vue.d.ts +8 -8
  71. package/types/components/nodes/number-field.vue.d.ts.map +1 -1
  72. package/types/components/nodes/one-of-select.vue.d.ts +4 -4
  73. package/types/components/nodes/section.vue.d.ts +4 -4
  74. package/types/components/nodes/select.vue.d.ts +8 -8
  75. package/types/components/nodes/select.vue.d.ts.map +1 -1
  76. package/types/components/nodes/slider.vue.d.ts +4 -4
  77. package/types/components/nodes/stepper.vue.d.ts +4 -4
  78. package/types/components/nodes/switch.vue.d.ts +4 -4
  79. package/types/components/nodes/tabs.vue.d.ts +4 -4
  80. package/types/components/nodes/text-field.vue.d.ts +8 -8
  81. package/types/components/nodes/text-field.vue.d.ts.map +1 -1
  82. package/types/components/nodes/textarea.vue.d.ts +8 -8
  83. package/types/components/nodes/textarea.vue.d.ts.map +1 -1
  84. package/types/components/nodes/vertical-tabs.vue.d.ts +4 -4
  85. package/types/components/options.d.ts +3 -3
  86. package/types/components/options.d.ts.map +1 -1
  87. package/types/components/tree.vue.d.ts +2 -2
  88. package/types/components/types.d.ts +14 -2
  89. package/types/components/types.d.ts.map +1 -1
  90. package/types/components/vjsf.vue.d.ts +3 -3
  91. package/types/composables/use-dnd.d.ts +5 -1
  92. package/types/composables/use-dnd.d.ts.map +1 -1
  93. package/types/composables/use-vjsf.d.ts +4 -5
  94. package/types/composables/use-vjsf.d.ts.map +1 -1
  95. package/types/index.d.ts +1 -0
  96. package/types/index.d.ts.map +1 -1
  97. package/types/types.d.ts +95 -0
  98. package/types/types.d.ts.map +1 -0
  99. package/types/utils/global-register.d.ts +8 -0
  100. package/types/utils/global-register.d.ts.map +1 -0
  101. package/types/utils/index.d.ts +6 -0
  102. package/types/utils/index.d.ts.map +1 -0
  103. package/types/utils/props.d.ts +3 -3
  104. package/types/utils/props.d.ts.map +1 -1
  105. package/types/utils/slots.d.ts +3 -3
  106. package/types/utils/slots.d.ts.map +1 -1
  107. 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/props.js'
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('../types.js').VjsfComboboxNode> */
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('@json-layout/core').StatefulLayout> */
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/props.js'
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('../types.js').VjsfNumberFieldNode> */
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('@json-layout/core').StatefulLayout> */
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('../types.js').VjsfOneOfSelectNode> */
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('@json-layout/core').StatefulLayout> */
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('../types.js').VjsfNode */(grandChild)"
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('../types.js').VjsfSectionNode> */
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('@json-layout/core').StatefulLayout> */
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('../types.js').VjsfNode */(child)"
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/props.js'
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('../types.js').VjsfSelectNode> */
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('@json-layout/core').StatefulLayout> */
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/props.js'
4
+ import { getInputProps } from '../../utils/index.js'
5
5
 
6
6
  const props = defineProps({
7
7
  modelValue: {
8
- /** @type import('vue').PropType<import('../types.js').VjsfSliderNode> */
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('@json-layout/core').StatefulLayout> */
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('../types.js').VjsfStepperNode> */
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('@json-layout/core').StatefulLayout> */
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('../types.js').VjsfNode */(grandChild)"
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/props.js'
4
+ import { getInputProps } from '../../utils/index.js'
5
5
 
6
6
  const props = defineProps({
7
7
  modelValue: {
8
- /** @type import('vue').PropType<import('../types.js').VjsfSwitchNode> */
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('@json-layout/core').StatefulLayout> */
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('../types.js').VjsfTabsNode> */
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('@json-layout/core').StatefulLayout> */
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('../types.js').VjsfNode */(grandChild)"
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/props.js'
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('../types.js').VjsfTextFieldNode> */
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('@json-layout/core').StatefulLayout> */
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/props.js'
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('../types.js').VjsfTextareaNode> */
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('@json-layout/core').StatefulLayout> */
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
- const fieldProps = computed(() => getInputProps(props.modelValue, props.statefulLayout, ['placeholder']))
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('../types.js').VjsfVerticalTabsNode> */
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('@json-layout/core').StatefulLayout> */
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('../types.js').VjsfNode */(grandChild)"
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("./types.js").PartialVjsfOptions */
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("./types.js").VjsfOptions>} options
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('./types.js').VjsfOptions */ (fullOptions)
48
+ return /** @type import('../types.js').VjsfOptions */ (fullOptions)
46
49
  }
@@ -9,7 +9,7 @@ defineProps({
9
9
  required: true
10
10
  },
11
11
  statefulLayout: {
12
- /** @type import('vue').PropType<import('@json-layout/core').StatefulLayout> */
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('./types.js').VjsfNode */(modelValue.root)"
23
+ :model-value="/** @type import('../types.js').VjsfNode */(modelValue.root)"
24
24
  />
25
25
  </v-row>
26
26
  </template>
@@ -1,10 +1,11 @@
1
1
  <script setup>
2
- import { computed, getCurrentInstance } from 'vue'
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 NodeMarkdown from './nodes/markdown.vue'
30
+ import NodeFileInput from './nodes/file-input.vue'
30
31
 
31
- const comps = {
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
- markdown: NodeMarkdown
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('./types.js').PartialVjsfOptions> */
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/arrays.js'
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 {StatefulLayout} state
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("../components/types.js").PartialVjsfOptions>} options
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<StatefulLayout | null> */
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
- const _statefulLayout = new StatefulLayout(
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
- }, { immediate: true })
118
+ })
117
119
 
118
120
  return { el, statefulLayout, stateTree }
119
121
  }
package/src/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  import Vjsf from './components/vjsf.vue'
2
2
  import { defaultOptions } from './components/options.js'
3
3
  export { Vjsf, defaultOptions }
4
+ export default Vjsf