@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.
Files changed (162) hide show
  1. package/package.json +56 -87
  2. package/src/compat/v2.js +120 -0
  3. package/src/compile/index.js +51 -0
  4. package/src/compile/v-jsf-compiled.vue.ejs +83 -0
  5. package/src/components/fragments/help-message.vue +48 -0
  6. package/src/components/fragments/node-slot.vue +49 -0
  7. package/src/components/fragments/section-header.vue +55 -0
  8. package/src/components/fragments/select-item-icon.vue +28 -0
  9. package/src/components/fragments/select-item.vue +43 -0
  10. package/src/components/fragments/select-selection.vue +35 -0
  11. package/src/components/fragments/text-field-menu.vue +68 -0
  12. package/src/components/node.vue +69 -0
  13. package/src/components/nodes/autocomplete.vue +95 -0
  14. package/src/components/nodes/checkbox.vue +27 -0
  15. package/src/components/nodes/color-picker.vue +43 -0
  16. package/src/components/nodes/combobox.vue +73 -0
  17. package/src/components/nodes/date-picker.vue +45 -0
  18. package/src/components/nodes/date-time-picker.vue +20 -0
  19. package/src/components/nodes/expansion-panels.vue +52 -0
  20. package/src/components/nodes/list.vue +112 -0
  21. package/src/components/nodes/markdown.vue +29 -0
  22. package/src/components/nodes/number-combobox.vue +73 -0
  23. package/src/components/nodes/number-field.vue +34 -0
  24. package/src/components/nodes/one-of-select.vue +56 -0
  25. package/src/components/nodes/section.vue +30 -0
  26. package/src/components/nodes/select.vue +79 -0
  27. package/src/components/nodes/slider.vue +34 -0
  28. package/src/components/nodes/switch.vue +29 -0
  29. package/src/components/nodes/tabs.vue +63 -0
  30. package/src/components/nodes/text-field.vue +29 -0
  31. package/src/components/nodes/textarea.vue +29 -0
  32. package/src/components/nodes/time-picker.vue +7 -0
  33. package/src/components/nodes/vertical-tabs.vue +70 -0
  34. package/src/components/options.js +25 -0
  35. package/src/components/tree.vue +26 -0
  36. package/src/components/types.ts +63 -0
  37. package/src/components/vjsf.vue +195 -0
  38. package/src/index.js +3 -0
  39. package/src/utils/clone.js +3 -0
  40. package/src/utils/dates.js +52 -0
  41. package/src/utils/props.js +87 -0
  42. package/src/utils/slots.js +19 -0
  43. package/types/compat/v2.d.ts +10 -0
  44. package/types/compat/v2.d.ts.map +1 -0
  45. package/types/compile/index.d.ts +7 -0
  46. package/types/compile/index.d.ts.map +1 -0
  47. package/types/components/fragments/help-message.vue.d.ts +8 -0
  48. package/types/components/fragments/help-message.vue.d.ts.map +1 -0
  49. package/types/components/fragments/node-slot.vue.d.ts +47 -0
  50. package/types/components/fragments/node-slot.vue.d.ts.map +1 -0
  51. package/types/components/fragments/section-header.vue.d.ts +8 -0
  52. package/types/components/fragments/section-header.vue.d.ts.map +1 -0
  53. package/types/components/fragments/select-item-icon.vue.d.ts +15 -0
  54. package/types/components/fragments/select-item-icon.vue.d.ts.map +1 -0
  55. package/types/components/fragments/select-item.vue.d.ts +12 -0
  56. package/types/components/fragments/select-item.vue.d.ts.map +1 -0
  57. package/types/components/fragments/select-selection.vue.d.ts +12 -0
  58. package/types/components/fragments/select-selection.vue.d.ts.map +1 -0
  59. package/types/components/fragments/text-field-menu.vue.d.ts +20 -0
  60. package/types/components/fragments/text-field-menu.vue.d.ts.map +1 -0
  61. package/types/components/node.vue.d.ts +10 -0
  62. package/types/components/node.vue.d.ts.map +1 -0
  63. package/types/components/nodes/autocomplete.vue.d.ts +27 -0
  64. package/types/components/nodes/autocomplete.vue.d.ts.map +1 -0
  65. package/types/components/nodes/checkbox.vue.d.ts +10 -0
  66. package/types/components/nodes/checkbox.vue.d.ts.map +1 -0
  67. package/types/components/nodes/color-picker.vue.d.ts +10 -0
  68. package/types/components/nodes/color-picker.vue.d.ts.map +1 -0
  69. package/types/components/nodes/combobox.vue.d.ts +27 -0
  70. package/types/components/nodes/combobox.vue.d.ts.map +1 -0
  71. package/types/components/nodes/date-picker.vue.d.ts +10 -0
  72. package/types/components/nodes/date-picker.vue.d.ts.map +1 -0
  73. package/types/components/nodes/date-time-picker.vue.d.ts +10 -0
  74. package/types/components/nodes/date-time-picker.vue.d.ts.map +1 -0
  75. package/types/components/nodes/expansion-panels.vue.d.ts +10 -0
  76. package/types/components/nodes/expansion-panels.vue.d.ts.map +1 -0
  77. package/types/components/nodes/list.vue.d.ts +10 -0
  78. package/types/components/nodes/list.vue.d.ts.map +1 -0
  79. package/types/components/nodes/markdown.vue.d.ts +27 -0
  80. package/types/components/nodes/markdown.vue.d.ts.map +1 -0
  81. package/types/components/nodes/number-combobox.vue.d.ts +27 -0
  82. package/types/components/nodes/number-combobox.vue.d.ts.map +1 -0
  83. package/types/components/nodes/number-field.vue.d.ts +27 -0
  84. package/types/components/nodes/number-field.vue.d.ts.map +1 -0
  85. package/types/components/nodes/one-of-select.vue.d.ts +10 -0
  86. package/types/components/nodes/one-of-select.vue.d.ts.map +1 -0
  87. package/types/components/nodes/section.vue.d.ts +10 -0
  88. package/types/components/nodes/section.vue.d.ts.map +1 -0
  89. package/types/components/nodes/select.vue.d.ts +27 -0
  90. package/types/components/nodes/select.vue.d.ts.map +1 -0
  91. package/types/components/nodes/slider.vue.d.ts +10 -0
  92. package/types/components/nodes/slider.vue.d.ts.map +1 -0
  93. package/types/components/nodes/switch.vue.d.ts +10 -0
  94. package/types/components/nodes/switch.vue.d.ts.map +1 -0
  95. package/types/components/nodes/tabs.vue.d.ts +10 -0
  96. package/types/components/nodes/tabs.vue.d.ts.map +1 -0
  97. package/types/components/nodes/text-field copy.vue.d.ts +10 -0
  98. package/types/components/nodes/text-field copy.vue.d.ts.map +1 -0
  99. package/types/components/nodes/text-field.vue.d.ts +27 -0
  100. package/types/components/nodes/text-field.vue.d.ts.map +1 -0
  101. package/types/components/nodes/textarea.vue.d.ts +27 -0
  102. package/types/components/nodes/textarea.vue.d.ts.map +1 -0
  103. package/types/components/nodes/time-picker.vue.d.ts +3 -0
  104. package/types/components/nodes/time-picker.vue.d.ts.map +1 -0
  105. package/types/components/nodes/vertical-tabs.vue.d.ts +10 -0
  106. package/types/components/nodes/vertical-tabs.vue.d.ts.map +1 -0
  107. package/types/components/options.d.ts +3 -0
  108. package/types/components/options.d.ts.map +1 -0
  109. package/types/components/tree.vue.d.ts +10 -0
  110. package/types/components/tree.vue.d.ts.map +1 -0
  111. package/types/components/types.d.ts +75 -0
  112. package/types/components/types.d.ts.map +1 -0
  113. package/types/components/v-jsf.vue.d.ts +13 -0
  114. package/types/components/v-jsf.vue.d.ts.map +1 -0
  115. package/types/components/vjsf.vue.d.ts +16 -0
  116. package/types/components/vjsf.vue.d.ts.map +1 -0
  117. package/types/index.d.ts +4 -0
  118. package/types/index.d.ts.map +1 -0
  119. package/types/utils/clone.d.ts +3 -0
  120. package/types/utils/clone.d.ts.map +1 -0
  121. package/types/utils/dates.d.ts +7 -0
  122. package/types/utils/dates.d.ts.map +1 -0
  123. package/types/utils/props.d.ts +21 -0
  124. package/types/utils/props.d.ts.map +1 -0
  125. package/types/utils/slots.d.ts +7 -0
  126. package/types/utils/slots.d.ts.map +1 -0
  127. package/.eslintignore +0 -9
  128. package/.eslintrc.js +0 -38
  129. package/.github/workflows/scrape-doc.yml +0 -14
  130. package/.nvmrc +0 -1
  131. package/CONTRIBUTE.md +0 -61
  132. package/FUNDING.yml +0 -1
  133. package/README.md +0 -19
  134. package/babel.config.js +0 -4
  135. package/dist/main.css +0 -67
  136. package/dist/main.js +0 -2
  137. package/dist/main.js.LICENSE.txt +0 -10
  138. package/dist/third-party.js +0 -8
  139. package/dist/third-party.js.LICENSE.txt +0 -8
  140. package/lib/VJsf.css +0 -67
  141. package/lib/VJsf.js +0 -117
  142. package/lib/VJsfNoDeps.js +0 -528
  143. package/lib/deps/third-party.js +0 -16
  144. package/lib/mixins/ColorProperty.js +0 -45
  145. package/lib/mixins/DateProperty.js +0 -170
  146. package/lib/mixins/Dependent.js +0 -69
  147. package/lib/mixins/EditableArray.js +0 -418
  148. package/lib/mixins/FileProperty.js +0 -81
  149. package/lib/mixins/MarkdownEditor.js +0 -183
  150. package/lib/mixins/ObjectContainer.js +0 -351
  151. package/lib/mixins/SelectProperty.js +0 -400
  152. package/lib/mixins/SimpleProperty.js +0 -165
  153. package/lib/mixins/Tooltip.js +0 -42
  154. package/lib/mixins/Validatable.js +0 -119
  155. package/lib/utils/expr-eval-parser.js +0 -47
  156. package/lib/utils/is-cyclic.js +0 -34
  157. package/lib/utils/json-refs.js +0 -209
  158. package/lib/utils/options.js +0 -328
  159. package/lib/utils/rules.js +0 -81
  160. package/lib/utils/schema.js +0 -100
  161. package/lib/utils/select.js +0 -141
  162. 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,7 @@
1
+ <script setup>
2
+
3
+ </script>
4
+
5
+ <template>
6
+ TODO time
7
+ </template>
@@ -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}