@koumoul/vjsf 3.0.0-beta.4 → 3.0.0-beta.41

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 (164) hide show
  1. package/README.md +21 -0
  2. package/package.json +5 -4
  3. package/src/compat/v2.js +132 -27
  4. package/src/compile/index.js +18 -4
  5. package/src/compile/options.js +3 -7
  6. package/src/compile/v-jsf-compiled.vue.ejs +1 -1
  7. package/src/components/fragments/child-subtitle.vue +25 -0
  8. package/src/components/fragments/help-message.vue +33 -8
  9. package/src/components/fragments/section-header.vue +9 -7
  10. package/src/components/fragments/select-item-icon.vue +2 -2
  11. package/src/components/fragments/select-item.vue +2 -1
  12. package/src/components/fragments/select-selection.vue +2 -1
  13. package/src/components/fragments/selection-group.vue +104 -0
  14. package/src/components/fragments/text-field-menu.vue +8 -3
  15. package/src/components/node.vue +58 -41
  16. package/src/components/nodes/autocomplete.vue +14 -60
  17. package/src/components/nodes/card.vue +39 -0
  18. package/src/components/nodes/checkbox-group.vue +39 -0
  19. package/src/components/nodes/checkbox.vue +4 -1
  20. package/src/components/nodes/color-picker.vue +6 -2
  21. package/src/components/nodes/combobox.vue +4 -1
  22. package/src/components/nodes/date-picker.vue +19 -10
  23. package/src/components/nodes/date-time-picker.vue +80 -3
  24. package/src/components/nodes/expansion-panels.vue +28 -12
  25. package/src/components/nodes/file-input.vue +4 -1
  26. package/src/components/nodes/list.vue +239 -104
  27. package/src/components/nodes/number-combobox.vue +4 -1
  28. package/src/components/nodes/number-field.vue +4 -1
  29. package/src/components/nodes/one-of-select.vue +46 -24
  30. package/src/components/nodes/radio-group.vue +55 -0
  31. package/src/components/nodes/section.vue +4 -1
  32. package/src/components/nodes/select.vue +13 -52
  33. package/src/components/nodes/slider.vue +4 -1
  34. package/src/components/nodes/stepper.vue +10 -2
  35. package/src/components/nodes/switch-group.vue +39 -0
  36. package/src/components/nodes/switch.vue +4 -1
  37. package/src/components/nodes/tabs.vue +18 -5
  38. package/src/components/nodes/text-field.vue +4 -1
  39. package/src/components/nodes/textarea.vue +4 -1
  40. package/src/components/nodes/time-picker.vue +38 -1
  41. package/src/components/nodes/vertical-tabs.vue +14 -3
  42. package/src/components/options.js +21 -4
  43. package/src/components/tree.vue +1 -1
  44. package/src/components/vjsf.vue +11 -1
  45. package/src/composables/use-comp-defaults.js +19 -0
  46. package/src/composables/use-dnd.js +1 -0
  47. package/src/composables/use-get-items.js +48 -0
  48. package/src/composables/use-vjsf.js +76 -40
  49. package/src/index.js +3 -0
  50. package/src/types.ts +21 -7
  51. package/src/utils/arrays.js +37 -6
  52. package/src/utils/build.js +1 -1
  53. package/src/utils/index.js +0 -1
  54. package/src/utils/props.js +36 -12
  55. package/src/utils/slots.js +28 -0
  56. package/types/compat/v2.d.ts +10 -0
  57. package/types/compat/v2.d.ts.map +1 -0
  58. package/types/compile/index.d.ts +8 -0
  59. package/types/compile/index.d.ts.map +1 -0
  60. package/types/compile/options.d.ts +4 -0
  61. package/types/compile/options.d.ts.map +1 -0
  62. package/types/components/fragments/child-subtitle.vue.d.ts +8 -0
  63. package/types/components/fragments/child-subtitle.vue.d.ts.map +1 -0
  64. package/types/components/fragments/help-message.vue.d.ts +8 -0
  65. package/types/components/fragments/help-message.vue.d.ts.map +1 -0
  66. package/types/components/fragments/node-slot.vue.d.ts +47 -0
  67. package/types/components/fragments/node-slot.vue.d.ts.map +1 -0
  68. package/types/components/fragments/section-header.vue.d.ts +10 -0
  69. package/types/components/fragments/section-header.vue.d.ts.map +1 -0
  70. package/types/components/fragments/select-item-icon.vue.d.ts +15 -0
  71. package/types/components/fragments/select-item-icon.vue.d.ts.map +1 -0
  72. package/types/components/fragments/select-item.vue.d.ts +12 -0
  73. package/types/components/fragments/select-item.vue.d.ts.map +1 -0
  74. package/types/components/fragments/select-selection.vue.d.ts +12 -0
  75. package/types/components/fragments/select-selection.vue.d.ts.map +1 -0
  76. package/types/components/fragments/selection-group.vue.d.ts +35 -0
  77. package/types/components/fragments/selection-group.vue.d.ts.map +1 -0
  78. package/types/components/fragments/text-field-menu.vue.d.ts +20 -0
  79. package/types/components/fragments/text-field-menu.vue.d.ts.map +1 -0
  80. package/types/components/node.vue.d.ts +10 -0
  81. package/types/components/node.vue.d.ts.map +1 -0
  82. package/types/components/nodes/autocomplete.vue.d.ts +27 -0
  83. package/types/components/nodes/autocomplete.vue.d.ts.map +1 -0
  84. package/types/components/nodes/card.vue.d.ts +10 -0
  85. package/types/components/nodes/card.vue.d.ts.map +1 -0
  86. package/types/components/nodes/checkbox-group.vue.d.ts +27 -0
  87. package/types/components/nodes/checkbox-group.vue.d.ts.map +1 -0
  88. package/types/components/nodes/checkbox.vue.d.ts +10 -0
  89. package/types/components/nodes/checkbox.vue.d.ts.map +1 -0
  90. package/types/components/nodes/color-picker.vue.d.ts +10 -0
  91. package/types/components/nodes/color-picker.vue.d.ts.map +1 -0
  92. package/types/components/nodes/combobox.vue.d.ts +27 -0
  93. package/types/components/nodes/combobox.vue.d.ts.map +1 -0
  94. package/types/components/nodes/date-picker.vue.d.ts +10 -0
  95. package/types/components/nodes/date-picker.vue.d.ts.map +1 -0
  96. package/types/components/nodes/date-time-picker.vue.d.ts +10 -0
  97. package/types/components/nodes/date-time-picker.vue.d.ts.map +1 -0
  98. package/types/components/nodes/expansion-panels.vue.d.ts +10 -0
  99. package/types/components/nodes/expansion-panels.vue.d.ts.map +1 -0
  100. package/types/components/nodes/file-input.vue.d.ts +27 -0
  101. package/types/components/nodes/file-input.vue.d.ts.map +1 -0
  102. package/types/components/nodes/list.vue.d.ts +10 -0
  103. package/types/components/nodes/list.vue.d.ts.map +1 -0
  104. package/types/components/nodes/number-combobox.vue.d.ts +27 -0
  105. package/types/components/nodes/number-combobox.vue.d.ts.map +1 -0
  106. package/types/components/nodes/number-field.vue.d.ts +27 -0
  107. package/types/components/nodes/number-field.vue.d.ts.map +1 -0
  108. package/types/components/nodes/one-of-select.vue.d.ts +10 -0
  109. package/types/components/nodes/one-of-select.vue.d.ts.map +1 -0
  110. package/types/components/nodes/radio-group.vue.d.ts +27 -0
  111. package/types/components/nodes/radio-group.vue.d.ts.map +1 -0
  112. package/types/components/nodes/section.vue.d.ts +10 -0
  113. package/types/components/nodes/section.vue.d.ts.map +1 -0
  114. package/types/components/nodes/select.vue.d.ts +27 -0
  115. package/types/components/nodes/select.vue.d.ts.map +1 -0
  116. package/types/components/nodes/slider.vue.d.ts +10 -0
  117. package/types/components/nodes/slider.vue.d.ts.map +1 -0
  118. package/types/components/nodes/stepper.vue.d.ts +10 -0
  119. package/types/components/nodes/stepper.vue.d.ts.map +1 -0
  120. package/types/components/nodes/switch-group.vue.d.ts +27 -0
  121. package/types/components/nodes/switch-group.vue.d.ts.map +1 -0
  122. package/types/components/nodes/switch.vue.d.ts +10 -0
  123. package/types/components/nodes/switch.vue.d.ts.map +1 -0
  124. package/types/components/nodes/tabs.vue.d.ts +10 -0
  125. package/types/components/nodes/tabs.vue.d.ts.map +1 -0
  126. package/types/components/nodes/text-field.vue.d.ts +27 -0
  127. package/types/components/nodes/text-field.vue.d.ts.map +1 -0
  128. package/types/components/nodes/textarea.vue.d.ts +27 -0
  129. package/types/components/nodes/textarea.vue.d.ts.map +1 -0
  130. package/types/components/nodes/time-picker.vue.d.ts +10 -0
  131. package/types/components/nodes/time-picker.vue.d.ts.map +1 -0
  132. package/types/components/nodes/vertical-tabs.vue.d.ts +10 -0
  133. package/types/components/nodes/vertical-tabs.vue.d.ts.map +1 -0
  134. package/types/components/options.d.ts +4 -0
  135. package/types/components/options.d.ts.map +1 -0
  136. package/types/components/tree.vue.d.ts +10 -0
  137. package/types/components/tree.vue.d.ts.map +1 -0
  138. package/types/components/vjsf.vue.d.ts +15 -0
  139. package/types/components/vjsf.vue.d.ts.map +1 -0
  140. package/types/composables/use-comp-defaults.d.ts +8 -0
  141. package/types/composables/use-comp-defaults.d.ts.map +1 -0
  142. package/types/composables/use-dnd.d.ts +25 -0
  143. package/types/composables/use-dnd.d.ts.map +1 -0
  144. package/types/composables/use-get-items.d.ts +13 -0
  145. package/types/composables/use-get-items.d.ts.map +1 -0
  146. package/types/composables/use-vjsf.d.ts +16 -0
  147. package/types/composables/use-vjsf.d.ts.map +1 -0
  148. package/types/index.d.ts +7 -0
  149. package/types/index.d.ts.map +1 -0
  150. package/types/types.d.ts +96 -0
  151. package/types/types.d.ts.map +1 -0
  152. package/types/utils/arrays.d.ts +22 -0
  153. package/types/utils/arrays.d.ts.map +1 -0
  154. package/types/utils/build.d.ts +2 -0
  155. package/types/utils/build.d.ts.map +1 -0
  156. package/types/utils/dates.d.ts +7 -0
  157. package/types/utils/dates.d.ts.map +1 -0
  158. package/types/utils/index.d.ts +5 -0
  159. package/types/utils/index.d.ts.map +1 -0
  160. package/types/utils/props.d.ts +29 -0
  161. package/types/utils/props.d.ts.map +1 -0
  162. package/types/utils/slots.d.ts +15 -0
  163. package/types/utils/slots.d.ts.map +1 -0
  164. package/src/utils/global-register.js +0 -13
@@ -1,9 +1,10 @@
1
1
  <script>
2
- import { VSelect } from 'vuetify/components'
3
- import { defineComponent, h, computed, ref, shallowRef } from 'vue'
4
- import { getInputProps, getCompSlots } from '../../utils/index.js'
5
- import SelectItem from '../fragments/select-item.vue'
6
- import SelectSelection from '../fragments/select-selection.vue'
2
+ import { VSelect } from 'vuetify/components/VSelect'
3
+ import { defineComponent, h, computed } from 'vue'
4
+ import { getSelectProps, getSelectSlots } from '../../utils/index.js'
5
+ import useGetItems from '../../composables/use-get-items.js'
6
+
7
+ import { useDefaults } from 'vuetify'
7
8
 
8
9
  export default defineComponent({
9
10
  props: {
@@ -19,59 +20,19 @@ export default defineComponent({
19
20
  }
20
21
  },
21
22
  setup (props) {
22
- /** @type import('vue').Ref<import('@json-layout/vocabulary').SelectItems> */
23
- const items = shallowRef([])
24
- /** @type import('vue').Ref<boolean> */
25
- const loading = ref(false)
23
+ useDefaults({}, 'VjsfSelect')
24
+
25
+ const getItems = useGetItems(props)
26
26
 
27
27
  const fieldProps = computed(() => {
28
- const fieldProps = getInputProps(props.modelValue, props.statefulLayout, ['multiple'])
29
- if (props.modelValue.options.readOnly) fieldProps.menuProps = { modelValue: false }
30
- fieldProps.loading = loading.value
31
- fieldProps.items = items.value
32
- fieldProps['onUpdate:menu'] = refresh
28
+ const fieldProps = getSelectProps(props.modelValue, props.statefulLayout)
29
+ fieldProps.loading = getItems.loading.value
30
+ fieldProps.items = getItems.items.value
33
31
  return fieldProps
34
32
  })
35
33
 
36
- /** @type import('@json-layout/core').StateTree | null */
37
- let lastStateTree = null
38
- /** @type Record<string, any> | null */
39
- let lastContext = null
40
-
41
- const refresh = async () => {
42
- if (props.statefulLayout.stateTree === lastStateTree && props.statefulLayout.options.context === lastContext) return
43
- lastStateTree = props.statefulLayout.stateTree
44
- lastContext = props.statefulLayout.options.context ?? null
45
- loading.value = true
46
- items.value = await props.statefulLayout.getItems(props.modelValue)
47
- loading.value = false
48
- }
49
-
50
- if (!props.modelValue.layout.items) {
51
- refresh()
52
- }
53
-
54
- const fieldSlots = computed(() => {
55
- const slots = getCompSlots(props.modelValue, props.statefulLayout)
56
- if (!slots.item) {
57
- slots.item = (/** @type {any} */ context) => h(SelectItem, {
58
- multiple: props.modelValue.layout.multiple,
59
- itemProps: context.props,
60
- item: context.item.raw
61
- })
62
- }
63
- if (!slots.selection) {
64
- slots.selection = (/** @type {any} */ context) => h(SelectSelection, {
65
- multiple: props.modelValue.layout.multiple,
66
- last: props.modelValue.layout.multiple && context.index === props.modelValue.data.length - 1,
67
- item: context.item.raw
68
- })
69
- }
70
- return slots
71
- })
72
-
73
34
  // @ts-ignore
74
- return () => h(VSelect, fieldProps.value, fieldSlots.value)
35
+ return () => h(VSelect, fieldProps.value, getSelectSlots(props.modelValue, props.statefulLayout, getItems))
75
36
  }
76
37
  })
77
38
 
@@ -1,7 +1,10 @@
1
1
  <script setup>
2
- import { VSlider } from 'vuetify/components'
2
+ import { VSlider } from 'vuetify/components/VSlider'
3
3
  import { computed } from 'vue'
4
4
  import { getInputProps } from '../../utils/index.js'
5
+ import { useDefaults } from 'vuetify'
6
+
7
+ useDefaults({}, 'VjsfSlider')
5
8
 
6
9
  const props = defineProps({
7
10
  modelValue: {
@@ -1,9 +1,16 @@
1
1
  <script setup>
2
2
  import { ref, computed } from 'vue'
3
- import { VStepper, VStepperHeader, VStepperItem, VStepperWindow, VStepperWindowItem, VStepperActions, VContainer, VRow, VSpacer, VBtn, VDivider } from 'vuetify/components'
3
+ import { VStepper, VStepperHeader, VStepperItem, VStepperWindow, VStepperWindowItem, VStepperActions } from 'vuetify/components/VStepper'
4
+ import { VContainer, VRow, VSpacer } from 'vuetify/components/VGrid'
5
+ import { VBtn } from 'vuetify/components/VBtn'
6
+ import { VDivider } from 'vuetify/components/VDivider'
4
7
  import { isSection } from '@json-layout/core'
5
8
  import Node from '../node.vue'
6
9
  import SectionHeader from '../fragments/section-header.vue'
10
+ import ChildSubtitle from '../fragments/child-subtitle.vue'
11
+ import { useDefaults } from 'vuetify'
12
+
13
+ useDefaults({}, 'VjsfStepper')
7
14
 
8
15
  const props = defineProps({
9
16
  modelValue: {
@@ -59,7 +66,8 @@ const goNext = () => {
59
66
  fluid
60
67
  class="pa-0"
61
68
  >
62
- <v-row>
69
+ <child-subtitle :model-value="child" />
70
+ <v-row :dense="modelValue.options?.density === 'compact' || modelValue.options?.density === 'comfortable'">
63
71
  <node
64
72
  v-for="grandChild of isSection(child) ? child.children : [child]"
65
73
  :key="grandChild.fullKey"
@@ -0,0 +1,39 @@
1
+ <script>
2
+ import { useDefaults } from 'vuetify'
3
+ import SelectionGroup from '../fragments/selection-group.vue'
4
+ import { defineComponent, h } from 'vue'
5
+
6
+ export default defineComponent({
7
+ props: {
8
+ modelValue: {
9
+ /** @type import('vue').PropType<import('../../types.js').VjsfCheckboxGroupNode> */
10
+ type: Object,
11
+ required: true
12
+ },
13
+ statefulLayout: {
14
+ /** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
15
+ type: Object,
16
+ required: true
17
+ }
18
+ },
19
+ setup (props) {
20
+ useDefaults({}, 'VjsfSwitchGroup')
21
+
22
+ // @ts-ignore
23
+ return () => {
24
+ return h(SelectionGroup, {
25
+ modelValue: props.modelValue,
26
+ statefulLayout: props.statefulLayout,
27
+ type: 'switch'
28
+ })
29
+ }
30
+ }
31
+ })
32
+
33
+ </script>
34
+
35
+ <style>
36
+ .vjsf-node-checkbox-group .v-selection-control-group .v-checkbox .v-selection-control {
37
+ min-height: auto;
38
+ }
39
+ </style>
@@ -1,7 +1,10 @@
1
1
  <script setup>
2
- import { VSwitch } from 'vuetify/components'
2
+ import { VSwitch } from 'vuetify/components/VSwitch'
3
3
  import { computed } from 'vue'
4
4
  import { getInputProps } from '../../utils/index.js'
5
+ import { useDefaults } from 'vuetify'
6
+
7
+ useDefaults({}, 'VjsfSwitch')
5
8
 
6
9
  const props = defineProps({
7
10
  modelValue: {
@@ -1,9 +1,19 @@
1
1
  <script setup>
2
- import { VTabs, VTab, VContainer, VSheet, VWindow, VWindowItem, VRow, VIcon } from 'vuetify/components'
2
+ import { VTabs, VTab } from 'vuetify/components/VTabs'
3
+ import { VContainer, VRow } from 'vuetify/components/VGrid'
4
+ import { VIcon } from 'vuetify/components/VIcon'
5
+ import { VSheet } from 'vuetify/components/VSheet'
6
+ import { VWindow, VWindowItem } from 'vuetify/components/VWindow'
7
+ import { useDefaults } from 'vuetify'
3
8
  import { ref } from 'vue'
4
9
  import { isSection } from '@json-layout/core'
5
10
  import Node from '../node.vue'
6
11
  import SectionHeader from '../fragments/section-header.vue'
12
+ import ChildSubtitle from '../fragments/child-subtitle.vue'
13
+ import useCompDefaults from '../../composables/use-comp-defaults.js'
14
+
15
+ useDefaults({}, 'VjsfTabs')
16
+ const vSheetProps = useCompDefaults('VjsfTabs-VSheet', { border: true })
7
17
 
8
18
  defineProps({
9
19
  modelValue: {
@@ -23,13 +33,15 @@ const tab = ref(0)
23
33
 
24
34
  <template>
25
35
  <section-header :node="modelValue" />
26
- <v-sheet border>
27
- <v-tabs v-model="tab">
36
+ <v-sheet v-bind="vSheetProps">
37
+ <v-tabs
38
+ v-model="tab"
39
+ direction="horizontal"
40
+ >
28
41
  <v-tab
29
42
  v-for="(child, i) of modelValue.children"
30
43
  :key="child.key"
31
44
  :value="i"
32
- :density="modelValue.options.density"
33
45
  :color="child.validated && (child.error || child.childError) ? 'error' : undefined"
34
46
  >
35
47
  <v-icon
@@ -48,7 +60,8 @@ const tab = ref(0)
48
60
  :value="i"
49
61
  >
50
62
  <v-container fluid>
51
- <v-row>
63
+ <child-subtitle :model-value="child" />
64
+ <v-row :dense="modelValue.options?.density === 'compact' || modelValue.options?.density === 'comfortable'">
52
65
  <node
53
66
  v-for="grandChild of isSection(child) ? child.children : [child]"
54
67
  :key="grandChild.fullKey"
@@ -1,7 +1,8 @@
1
1
  <script>
2
2
  import { defineComponent, h, computed } from 'vue'
3
- import { VTextField } from 'vuetify/components'
3
+ import { VTextField } from 'vuetify/components/VTextField'
4
4
  import { getInputProps, getCompSlots } from '../../utils/index.js'
5
+ import { useDefaults } from 'vuetify'
5
6
 
6
7
  export default defineComponent({
7
8
  props: {
@@ -17,6 +18,8 @@ export default defineComponent({
17
18
  }
18
19
  },
19
20
  setup (props) {
21
+ useDefaults({}, 'VjsfTextField')
22
+
20
23
  const fieldProps = computed(() => getInputProps(props.modelValue, props.statefulLayout, ['placeholder']))
21
24
  const fieldSlots = computed(() => getCompSlots(props.modelValue, props.statefulLayout))
22
25
 
@@ -1,7 +1,8 @@
1
1
  <script>
2
2
  import { defineComponent, h, computed, ref, watch } from 'vue'
3
- import { VTextarea } from 'vuetify/components'
3
+ import { VTextarea } from 'vuetify/components/VTextarea'
4
4
  import { getInputProps, getCompSlots } from '../../utils/index.js'
5
+ import { useDefaults } from 'vuetify'
5
6
 
6
7
  export default defineComponent({
7
8
  props: {
@@ -17,6 +18,8 @@ export default defineComponent({
17
18
  }
18
19
  },
19
20
  setup (props) {
21
+ useDefaults({}, 'VjsfTextArea')
22
+
20
23
  /** @type {import('vue').Ref<null | HTMLElement>} */
21
24
  const textarea = ref(null)
22
25
 
@@ -1,7 +1,44 @@
1
1
  <script setup>
2
+ import TextFieldMenu from '../fragments/text-field-menu.vue'
3
+ import { VTimePicker } from 'vuetify/labs/VTimePicker'
4
+ import { useDate, useDefaults } from 'vuetify'
5
+ import { computed } from 'vue'
6
+ import { getCompProps, getShortTime, getLongTime } from '../../utils/index.js'
2
7
 
8
+ useDefaults({}, 'VjsfDatePicker')
9
+
10
+ const props = defineProps({
11
+ modelValue: {
12
+ /** @type import('vue').PropType<import('../../types.js').VjsfDatePickerNode> */
13
+ type: Object,
14
+ required: true
15
+ },
16
+ statefulLayout: {
17
+ /** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
18
+ type: Object,
19
+ required: true
20
+ }
21
+ })
22
+
23
+ const vDate = useDate()
24
+
25
+ const timePickerProps = computed(() => {
26
+ const timePickerProps = getCompProps(props.modelValue, true)
27
+ timePickerProps['ampm-in-title'] = true
28
+ if (props.modelValue.data) timePickerProps.modelValue = getShortTime(props.modelValue.data)
29
+ return timePickerProps
30
+ })
3
31
  </script>
4
32
 
5
33
  <template>
6
- TODO time
34
+ <text-field-menu
35
+ :model-value="modelValue"
36
+ :stateful-layout="statefulLayout"
37
+ :formatted-value="timePickerProps.modelValue && vDate.format('2010-04-13T' + timePickerProps.modelValue, 'fullTime')"
38
+ >
39
+ <v-time-picker
40
+ v-bind="timePickerProps"
41
+ @update:model-value="value => {statefulLayout.input(modelValue, value && getLongTime(value))}"
42
+ />
43
+ </text-field-menu>
7
44
  </template>
@@ -1,9 +1,19 @@
1
1
  <script setup>
2
2
  import { isSection } from '@json-layout/core'
3
- import { VTabs, VTab, VContainer, VSheet, VWindow, VWindowItem, VRow, VIcon } from 'vuetify/components'
3
+ import { VTabs, VTab} from 'vuetify/components/VTabs'
4
+ import { VContainer, VRow } from 'vuetify/components/VGrid'
5
+ import { VIcon } from 'vuetify/components/VIcon'
6
+ import { VSheet } from 'vuetify/components/VSheet'
7
+ import { VWindow, VWindowItem } from 'vuetify/components/VWindow'
4
8
  import { ref } from 'vue'
5
9
  import Node from '../node.vue'
6
10
  import SectionHeader from '../fragments/section-header.vue'
11
+ import ChildSubtitle from '../fragments/child-subtitle.vue'
12
+ import { useDefaults } from 'vuetify'
13
+ import useCompDefaults from '../../composables/use-comp-defaults.js'
14
+
15
+ useDefaults({}, 'VjsfVerticalTabs')
16
+ const vSheetProps = useCompDefaults('VjsfVerticalTabs-VSheet', { border: true })
7
17
 
8
18
  defineProps({
9
19
  modelValue: {
@@ -23,7 +33,7 @@ const tab = ref(0)
23
33
 
24
34
  <template>
25
35
  <section-header :node="modelValue" />
26
- <v-sheet border>
36
+ <v-sheet v-bind="vSheetProps">
27
37
  <div class="d-flex flex-row">
28
38
  <v-tabs
29
39
  v-model="tab"
@@ -54,7 +64,8 @@ const tab = ref(0)
54
64
  :value="i"
55
65
  >
56
66
  <v-container fluid>
57
- <v-row>
67
+ <child-subtitle :model-value="child" />
68
+ <v-row :dense="modelValue.options?.density === 'compact' || modelValue.options?.density === 'comfortable'">
58
69
  <node
59
70
  v-for="grandChild of isSection(child) ? child.children : [child]"
60
71
  :key="grandChild.fullKey"
@@ -1,7 +1,8 @@
1
1
  /** @type {import("../types.js").PartialVjsfOptions} */
2
2
  export const defaultOptions = {
3
3
  nodeComponents: {},
4
- plugins: {}
4
+ plugins: [],
5
+ pluginsOptions: {}
5
6
  }
6
7
 
7
8
  /**
@@ -10,18 +11,34 @@ export const defaultOptions = {
10
11
  * @param {any} form
11
12
  * @param {number} width
12
13
  * @param {import("vue").Slots} slots
13
- * @param {Record<string, import('vue').Component>} nodeComponents
14
+ * @param {Record<string, import('vue').Component>} defaultNodeComponents
15
+ * @param {(data: any) => void} onData
16
+ * @param {(statefulLayout: import('@json-layout/core').StatefulLayout) => void} onUpdate
17
+ * @param {(key: string) => void} onAutofocus
14
18
  * @returns
15
19
  */
16
- export const getFullOptions = (options, form, width, slots, nodeComponents) => {
20
+ export const getFullOptions = (options, form, width, slots, defaultNodeComponents, onData, onUpdate, onAutofocus) => {
21
+ const components = { ...options?.components }
22
+ const nodeComponents = { ...defaultNodeComponents, ...options?.nodeComponents }
23
+ if (options?.plugins) {
24
+ for (const plugin of options.plugins) {
25
+ components[plugin.info.name] = plugin.info
26
+ nodeComponents[plugin.info.name] = plugin.nodeComponent
27
+ }
28
+ }
29
+
17
30
  const fullOptions = {
18
31
  ...defaultOptions,
19
32
  readOnly: !!(form && (form.isDisabled.value || form.isReadonly.value)),
20
33
  ...options,
34
+ onData,
35
+ onUpdate,
36
+ onAutofocus,
21
37
  context: options?.context ? JSON.parse(JSON.stringify(options.context)) : {},
22
38
  width: Math.round(width ?? 0),
23
39
  vjsfSlots: { ...slots },
24
- nodeComponents: { ...nodeComponents, ...options?.nodeComponents }
40
+ components,
41
+ nodeComponents
25
42
  }
26
43
  return /** @type import('../types.js').VjsfOptions */ (fullOptions)
27
44
  }
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { VRow } from 'vuetify/components'
2
+ import { VRow } from 'vuetify/components/VGrid'
3
3
  import Node from './node.vue'
4
4
 
5
5
  defineProps({
@@ -14,10 +14,14 @@ import NodeSwitch from './nodes/switch.vue'
14
14
  import NodeNumberField from './nodes/number-field.vue'
15
15
  import NodeSlider from './nodes/slider.vue'
16
16
  import NodeDatePicker from './nodes/date-picker.vue'
17
+ import NodeTimePicker from './nodes/time-picker.vue'
17
18
  import NodeDateTimePicker from './nodes/date-time-picker.vue'
18
19
  import NodeColorPicker from './nodes/color-picker.vue'
19
20
  import NodeSelect from './nodes/select.vue'
20
21
  import NodeAutocomplete from './nodes/autocomplete.vue'
22
+ import NodeRadioGroup from './nodes/radio-group.vue'
23
+ import NodeCheckboxGroup from './nodes/checkbox-group.vue'
24
+ import NodeSwitchGroup from './nodes/switch-group.vue'
21
25
  import NodeOneOfSelect from './nodes/one-of-select.vue'
22
26
  import NodeTabs from './nodes/tabs.vue'
23
27
  import NodeVerticalTabs from './nodes/vertical-tabs.vue'
@@ -27,6 +31,7 @@ import NodeExpansionPanels from './nodes/expansion-panels.vue'
27
31
  import NodeStepper from './nodes/stepper.vue'
28
32
  import NodeList from './nodes/list.vue'
29
33
  import NodeFileInput from './nodes/file-input.vue'
34
+ import NodeCard from './nodes/card.vue'
30
35
 
31
36
  /** @type {Record<string, import('vue').Component>} */
32
37
  const nodeComponents = {
@@ -38,10 +43,14 @@ const nodeComponents = {
38
43
  'number-field': NodeNumberField,
39
44
  slider: NodeSlider,
40
45
  'date-picker': NodeDatePicker,
46
+ 'time-picker': NodeTimePicker,
41
47
  'date-time-picker': NodeDateTimePicker,
42
48
  'color-picker': NodeColorPicker,
43
49
  select: NodeSelect,
44
50
  autocomplete: NodeAutocomplete,
51
+ 'radio-group': NodeRadioGroup,
52
+ 'checkbox-group': NodeCheckboxGroup,
53
+ 'switch-group': NodeSwitchGroup,
45
54
  'one-of-select': NodeOneOfSelect,
46
55
  tabs: NodeTabs,
47
56
  'vertical-tabs': NodeVerticalTabs,
@@ -50,7 +59,8 @@ const nodeComponents = {
50
59
  list: NodeList,
51
60
  combobox: NodeCombobox,
52
61
  'number-combobox': NodeNumberCombobox,
53
- 'file-input': NodeFileInput
62
+ 'file-input': NodeFileInput,
63
+ card: NodeCard
54
64
  }
55
65
 
56
66
  const props = defineProps({
@@ -0,0 +1,19 @@
1
+ import { inject, computed } from 'vue'
2
+
3
+ // inspired by https://github.com/vuetifyjs/vuetify/blob/27b4b1e52060b6bee13a290a4829f935f1bd9c05/packages/vuetify/src/composables/defaults.ts#L92
4
+ /**
5
+ *
6
+ * @param {string} name
7
+ * @param {Record<string, any> | null} [localDefaults]
8
+ * @returns {import('vue').ComputedRef<Record<string, any>>}
9
+ */
10
+ export default function useCompDefaultProps (name, localDefaults = null) {
11
+ /** @type {import('vue').Ref<import('vuetify').DefaultsInstance> | undefined} */
12
+ const defaults = inject(Symbol.for('vuetify:defaults'))
13
+ if (!defaults) throw new Error('[vjsf] Could not find defaults instance')
14
+ return computed(() => {
15
+ const componentDefaults = defaults.value?.[name] ?? {}
16
+ if (!localDefaults) return componentDefaults
17
+ return { ...componentDefaults, ...localDefaults }
18
+ })
19
+ }
@@ -42,6 +42,7 @@ export default function useDnd (array, callback) {
42
42
  dragging.value = itemIndex
43
43
  },
44
44
  onDragend: () => {
45
+ hovered.value = itemIndex
45
46
  dragging.value = -1
46
47
  callback()
47
48
  }
@@ -0,0 +1,48 @@
1
+ import { watch, shallowRef, ref } from 'vue'
2
+
3
+ /**
4
+ * @param {{modelValue: import('@json-layout/core').StateNode, statefulLayout: import('../types.js').VjsfStatefulLayout}} props
5
+ */
6
+ export default function (props) {
7
+ /** @type import('vue').Ref<import('@json-layout/vocabulary').SelectItems> */
8
+ const items = shallowRef([])
9
+ /** @type import('vue').Ref<boolean> */
10
+ const loading = ref(false)
11
+ /** @type import('vue').Ref<string> */
12
+ const search = ref('')
13
+
14
+ const fetchItems = async () => {
15
+ loading.value = true
16
+ items.value = await props.statefulLayout.getItems(props.modelValue, search.value)
17
+ loading.value = false
18
+ }
19
+
20
+ watch(() => props.modelValue.itemsCacheKey, (newValue, oldValue) => {
21
+ if (newValue === oldValue) return
22
+ fetchItems()
23
+ }, { immediate: true })
24
+
25
+ watch(search, () => {
26
+ fetchItems()
27
+ })
28
+
29
+ /**
30
+ * @param {any} selectedItem
31
+ * @param {any} itemValue
32
+ */
33
+ const prepareSelectedItem = (selectedItem, itemValue) => {
34
+ let item = selectedItem
35
+ // item and value are the same when the selection is not found in items list
36
+ if (selectedItem === itemValue) {
37
+ try {
38
+ item = props.statefulLayout.prepareSelectItem(props.modelValue, selectedItem)
39
+ if (item.value === undefined) item.value = itemValue
40
+ } catch (e) {
41
+ item = { value: itemValue }
42
+ }
43
+ }
44
+ return item
45
+ }
46
+
47
+ return { items, loading, search, prepareSelectedItem }
48
+ }