@koumoul/vjsf 3.0.0-beta.43 → 3.0.0-beta.45

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 (96) hide show
  1. package/package.json +12 -18
  2. package/src/components/fragments/selection-group.vue +11 -10
  3. package/src/components/fragments/text-field-menu.vue +10 -6
  4. package/src/components/nodes/autocomplete.vue +6 -6
  5. package/src/components/nodes/checkbox.vue +29 -27
  6. package/src/components/nodes/color-picker.vue +6 -4
  7. package/src/components/nodes/combobox.vue +14 -40
  8. package/src/components/nodes/date-picker.vue +14 -6
  9. package/src/components/nodes/date-time-picker.vue +14 -11
  10. package/src/components/nodes/expansion-panels.vue +6 -3
  11. package/src/components/nodes/file-input.vue +11 -10
  12. package/src/components/nodes/list.vue +21 -15
  13. package/src/components/nodes/number-combobox.vue +16 -40
  14. package/src/components/nodes/number-field.vue +13 -10
  15. package/src/components/nodes/one-of-select.vue +14 -10
  16. package/src/components/nodes/radio-group.vue +8 -5
  17. package/src/components/nodes/select.vue +8 -8
  18. package/src/components/nodes/slider.vue +30 -30
  19. package/src/components/nodes/switch.vue +29 -27
  20. package/src/components/nodes/text-field.vue +6 -6
  21. package/src/components/nodes/textarea.vue +16 -11
  22. package/src/components/nodes/time-picker.vue +9 -6
  23. package/src/composables/use-dnd.js +1 -1
  24. package/src/composables/use-get-items.js +12 -7
  25. package/src/composables/use-node.js +136 -0
  26. package/src/composables/use-select-node.js +67 -0
  27. package/src/composables/use-vjsf.js +3 -2
  28. package/types/components/fragments/child-subtitle.vue.d.ts +1 -1
  29. package/types/components/fragments/help-message.vue.d.ts +1 -1
  30. package/types/components/fragments/node-slot.vue.d.ts +4 -4
  31. package/types/components/fragments/section-header.vue.d.ts +1 -1
  32. package/types/components/fragments/select-item-icon.vue.d.ts +4 -4
  33. package/types/components/fragments/select-item.vue.d.ts +3 -3
  34. package/types/components/fragments/select-selection.vue.d.ts +1 -1
  35. package/types/components/fragments/selection-group.vue.d.ts +4 -4
  36. package/types/components/fragments/text-field-menu.vue.d.ts +1 -1
  37. package/types/components/fragments/text-field-menu.vue.d.ts.map +1 -1
  38. package/types/components/node.vue.d.ts +1 -1
  39. package/types/components/nodes/autocomplete.vue.d.ts +4 -4
  40. package/types/components/nodes/autocomplete.vue.d.ts.map +1 -1
  41. package/types/components/nodes/card.vue.d.ts +1 -1
  42. package/types/components/nodes/checkbox-group.vue.d.ts +4 -4
  43. package/types/components/nodes/checkbox.vue.d.ts +25 -8
  44. package/types/components/nodes/checkbox.vue.d.ts.map +1 -1
  45. package/types/components/nodes/color-picker.vue.d.ts +1 -1
  46. package/types/components/nodes/combobox.vue.d.ts +4 -4
  47. package/types/components/nodes/combobox.vue.d.ts.map +1 -1
  48. package/types/components/nodes/date-picker.vue.d.ts +1 -1
  49. package/types/components/nodes/date-time-picker.vue.d.ts +1 -1
  50. package/types/components/nodes/expansion-panels.vue.d.ts +1 -1
  51. package/types/components/nodes/file-input.vue.d.ts +4 -4
  52. package/types/components/nodes/list.vue.d.ts +1 -1
  53. package/types/components/nodes/number-combobox.vue.d.ts +4 -4
  54. package/types/components/nodes/number-combobox.vue.d.ts.map +1 -1
  55. package/types/components/nodes/number-field.vue.d.ts +4 -4
  56. package/types/components/nodes/one-of-select.vue.d.ts +1 -1
  57. package/types/components/nodes/radio-group.vue.d.ts +4 -4
  58. package/types/components/nodes/section.vue.d.ts +1 -1
  59. package/types/components/nodes/select.vue.d.ts +4 -4
  60. package/types/components/nodes/select.vue.d.ts.map +1 -1
  61. package/types/components/nodes/slider.vue.d.ts +25 -8
  62. package/types/components/nodes/slider.vue.d.ts.map +1 -1
  63. package/types/components/nodes/stepper.vue.d.ts +1 -1
  64. package/types/components/nodes/switch-group.vue.d.ts +4 -4
  65. package/types/components/nodes/switch.vue.d.ts +25 -8
  66. package/types/components/nodes/switch.vue.d.ts.map +1 -1
  67. package/types/components/nodes/tabs.vue.d.ts +1 -1
  68. package/types/components/nodes/text-field.vue.d.ts +4 -4
  69. package/types/components/nodes/textarea.vue.d.ts +4 -4
  70. package/types/components/nodes/time-picker.vue.d.ts +1 -1
  71. package/types/components/nodes/vertical-tabs.vue.d.ts +1 -1
  72. package/types/components/tree.vue.d.ts +1 -1
  73. package/types/components/vjsf.vue.d.ts +1 -1
  74. package/types/composables/use-dnd.d.ts +3 -3
  75. package/types/composables/use-field-props.d.ts +30 -0
  76. package/types/composables/use-field-props.d.ts.map +1 -0
  77. package/types/composables/use-field.d.ts +31 -0
  78. package/types/composables/use-field.d.ts.map +1 -0
  79. package/types/composables/use-get-items.d.ts +7 -8
  80. package/types/composables/use-get-items.d.ts.map +1 -1
  81. package/types/composables/use-node.d.ts +32 -0
  82. package/types/composables/use-node.d.ts.map +1 -0
  83. package/types/composables/use-select-field.d.ts +21 -0
  84. package/types/composables/use-select-field.d.ts.map +1 -0
  85. package/types/composables/use-select-node.d.ts +27 -0
  86. package/types/composables/use-select-node.d.ts.map +1 -0
  87. package/types/composables/use-select-props.d.ts +21 -0
  88. package/types/composables/use-select-props.d.ts.map +1 -0
  89. package/types/composables/use-select.d.ts +21 -0
  90. package/types/composables/use-select.d.ts.map +1 -0
  91. package/types/composables/use-vjsf.d.ts +2 -2
  92. package/types/composables/use-vjsf.d.ts.map +1 -1
  93. package/types/utils/index.d.ts +0 -2
  94. package/src/utils/index.js +0 -4
  95. package/src/utils/props.js +0 -136
  96. package/src/utils/slots.js +0 -46
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koumoul/vjsf",
3
- "version": "3.0.0-beta.43",
3
+ "version": "3.0.0-beta.45",
4
4
  "description": "Generate forms for the vuetify UI library (vuejs) based on annotated JSON schemas.",
5
5
  "scripts": {
6
6
  "test": "vitest",
@@ -29,28 +29,22 @@
29
29
  "default": "./src/types.js"
30
30
  }
31
31
  },
32
- "./components/*": {
32
+ "./components/vjsf.vue": {
33
33
  "import": {
34
- "types": "./types/components/*.d.ts",
35
- "default": "./src/components/*"
34
+ "types": "./types/components/vjsf.d.ts",
35
+ "default": "./src/components/vjs.vue"
36
36
  }
37
37
  },
38
- "./composables/*": {
38
+ "./utils/build.js": {
39
39
  "import": {
40
- "types": "./types/composables/*.d.ts",
41
- "default": "./src/composables/*"
40
+ "types": "./types/utils/build.d.ts",
41
+ "default": "./src/utils/build.js"
42
42
  }
43
43
  },
44
- "./utils": {
44
+ "./composables/use-node": {
45
45
  "import": {
46
- "types": "./types/utils/index.d.ts",
47
- "default": "./src/utils/index.js"
48
- }
49
- },
50
- "./utils/*": {
51
- "import": {
52
- "types": "./types/utils/*.d.ts",
53
- "default": "./src/utils/*"
46
+ "types": "./types/composables/use-node.d.ts",
47
+ "default": "./src/composables/use-node.js"
54
48
  }
55
49
  },
56
50
  "./styles/*": {
@@ -76,7 +70,7 @@
76
70
  "vuetify": "^3.6.13"
77
71
  },
78
72
  "dependencies": {
79
- "@json-layout/core": "0.31.2",
73
+ "@json-layout/core": "0.32.1",
80
74
  "@vueuse/core": "^10.5.0",
81
75
  "debug": "^4.3.4",
82
76
  "ejs": "^3.1.9"
@@ -85,7 +79,7 @@
85
79
  "@types/debug": "^4.1.8",
86
80
  "@types/ejs": "^3.1.2",
87
81
  "vitest": "^1.1.1",
88
- "vue": "^3.4.3",
82
+ "vue": "^3.5.6",
89
83
  "vue-tsc": "^1.8.27"
90
84
  }
91
85
  }
@@ -4,8 +4,8 @@ import { VInput } from 'vuetify/components/VInput'
4
4
  import { VLabel } from 'vuetify/components/VLabel'
5
5
  import { VCheckbox } from 'vuetify/components/VCheckbox'
6
6
  import { VSwitch } from 'vuetify/components/VSwitch'
7
- import { defineComponent, h, computed } from 'vue'
8
- import { getInputProps, getCompSlots } from '../../utils/index.js'
7
+ import { defineComponent, h, computed, toRef } from 'vue'
8
+ import useField from '../../composables/use-node.js'
9
9
  import useGetItems from '../../composables/use-get-items.js'
10
10
 
11
11
  export default defineComponent({
@@ -26,17 +26,19 @@ export default defineComponent({
26
26
  }
27
27
  },
28
28
  setup (props) {
29
- const getItems = useGetItems(props)
29
+ const nodeRef = toRef(props, 'modelValue')
30
+ const getItems = useGetItems(nodeRef, props.statefulLayout)
31
+ const { inputProps, compSlots, localData, layout } = useField(nodeRef, props.statefulLayout, { bindData: false })
30
32
 
31
33
  const fieldProps = computed(() => {
32
- const fieldProps = getInputProps(props.modelValue, props.statefulLayout)
34
+ const fieldProps = { ...inputProps.value }
33
35
  fieldProps.class.push('v-radio-group') // reuse some styles from radio-group
34
36
  fieldProps.class.push('vjsf-selection-group')
35
37
  return fieldProps
36
38
  })
37
39
 
38
40
  const fieldSlots = computed(() => {
39
- const slots = getCompSlots(props.modelValue, props.statefulLayout)
41
+ const slots = { ...compSlots.value }
40
42
 
41
43
  if (!slots.default) {
42
44
  slots.default = () => {
@@ -49,10 +51,10 @@ export default defineComponent({
49
51
  const checkboxes = []
50
52
  for (const item of getItems.items.value) {
51
53
  let modelValue = false
52
- if (props.modelValue.layout.multiple) {
53
- modelValue = props.modelValue.data?.includes(item.value)
54
+ if (layout.value.multiple) {
55
+ modelValue = localData.value?.includes(item.value)
54
56
  } else {
55
- modelValue = props.modelValue.data === item.value
57
+ modelValue = localData.value === item.value
56
58
  }
57
59
  checkboxes.push(h(props.type === 'switch' ? VSwitch : VCheckbox, {
58
60
  label: item.title,
@@ -61,7 +63,7 @@ export default defineComponent({
61
63
  modelValue,
62
64
  onClick: () => {
63
65
  let newValue
64
- if (props.modelValue.layout.multiple) {
66
+ if (layout.value.multiple) {
65
67
  newValue = props.modelValue.data ? [...props.modelValue.data] : []
66
68
  if (newValue.includes(item.value)) {
67
69
  newValue = newValue.filter((/** @type {any} */v) => v !== item.value)
@@ -88,7 +90,6 @@ export default defineComponent({
88
90
  return slots
89
91
  })
90
92
 
91
- // @ts-ignore
92
93
  return () => {
93
94
  return h(VInput, fieldProps.value, fieldSlots.value)
94
95
  }
@@ -1,8 +1,8 @@
1
1
  <script setup>
2
2
  import { VMenu } from 'vuetify/components/VMenu'
3
3
  import { VTextField } from 'vuetify/components/VTextField'
4
- import { computed, ref } from 'vue'
5
- import { getCompProps, getInputProps } from '../../utils/index.js'
4
+ import { computed, ref, toRef } from 'vue'
5
+ import useField from '../../composables/use-node.js'
6
6
 
7
7
  const props = defineProps({
8
8
  modelValue: {
@@ -22,10 +22,14 @@ const props = defineProps({
22
22
  }
23
23
  })
24
24
 
25
+ const { inputProps, skeleton, compProps, data } = useField(
26
+ toRef(props, 'modelValue'), props.statefulLayout, { isMainComp: false, bindData: false }
27
+ )
28
+
25
29
  const fieldProps = computed(() => {
26
- const fieldProps = getInputProps(props.modelValue, props.statefulLayout, [], false)
30
+ const fieldProps = { ...inputProps.value }
27
31
  fieldProps.readonly = true
28
- fieldProps.clearable = fieldProps.clearable ?? !props.modelValue.skeleton.required
32
+ fieldProps.clearable = fieldProps.clearable ?? !skeleton.value.required
29
33
  fieldProps['onClick:clear'] = () => {
30
34
  props.statefulLayout.input(props.modelValue, null)
31
35
  }
@@ -33,7 +37,7 @@ const fieldProps = computed(() => {
33
37
  })
34
38
 
35
39
  const menuProps = computed(() => {
36
- const menuProps = getCompProps(props.modelValue)
40
+ const menuProps = { ...compProps.value }
37
41
  menuProps.closeOnContentClick = false
38
42
  menuProps.disabled = true
39
43
  return menuProps
@@ -48,7 +52,7 @@ const menuOpened = defineModel('menuOpened', { type: Boolean, default: false })
48
52
  <v-text-field
49
53
  ref="textField"
50
54
  v-bind="fieldProps"
51
- :model-value="formattedValue ?? modelValue.data"
55
+ :model-value="formattedValue ?? data"
52
56
  @click:control="e => {menuOpened = !menuOpened; e.stopPropagation()}"
53
57
  >
54
58
  <template #prepend-inner>
@@ -1,9 +1,8 @@
1
1
  <script>
2
2
  import { VAutocomplete } from 'vuetify/components/VAutocomplete'
3
3
  import { useDefaults } from 'vuetify'
4
- import { defineComponent, computed, h } from 'vue'
5
- import { getSelectProps, getSelectSlots } from '../../utils/index.js'
6
- import useGetItems from '../../composables/use-get-items.js'
4
+ import { defineComponent, computed, h, toRef } from 'vue'
5
+ import useSelectNode from '../../composables/use-select-node.js'
7
6
 
8
7
  export default defineComponent({
9
8
  props: {
@@ -21,21 +20,22 @@ export default defineComponent({
21
20
  setup (props) {
22
21
  useDefaults({}, 'VjsfAutocomplete')
23
22
 
24
- const getItems = useGetItems(props)
23
+ const { getItems, selectProps, selectSlots, localData } = useSelectNode(toRef(props, 'modelValue'), props.statefulLayout)
25
24
 
26
25
  const fieldProps = computed(() => {
27
- const fieldProps = getSelectProps(props.modelValue, props.statefulLayout)
26
+ const fieldProps = { ...selectProps.value }
28
27
  fieldProps.noFilter = true
29
28
  fieldProps['onUpdate:search'] = (/** @type string */searchValue) => {
30
29
  getItems.search.value = searchValue
31
30
  }
32
31
  fieldProps.items = getItems.items.value
33
32
  fieldProps.loading = getItems.loading.value
33
+ fieldProps.modelValue = localData.value
34
34
  return fieldProps
35
35
  })
36
36
 
37
37
  // @ts-ignore
38
- return () => h(VAutocomplete, fieldProps.value, getSelectSlots(props.modelValue, props.statefulLayout, getItems))
38
+ return () => h(VAutocomplete, fieldProps.value, selectSlots.value)
39
39
  }
40
40
  })
41
41
 
@@ -1,35 +1,37 @@
1
- <script setup>
1
+ <script>
2
+ import { defineComponent, h, computed, toRef } from 'vue'
2
3
  import { VCheckbox } from 'vuetify/components/VCheckbox'
3
- import { computed } from 'vue'
4
- import { getInputProps } from '../../utils/index.js'
4
+ import useNode from '../../composables/use-node.js'
5
5
  import { useDefaults } from 'vuetify'
6
6
 
7
- useDefaults({}, 'VjsfCheckbox')
8
-
9
- const props = defineProps({
10
- modelValue: {
11
- /** @type import('vue').PropType<import('../../types.js').VjsfCheckboxNode> */
12
- type: Object,
13
- required: true
7
+ export default defineComponent({
8
+ props: {
9
+ modelValue: {
10
+ /** @type import('vue').PropType<import('../../types.js').VjsfCheckboxNode> */
11
+ type: Object,
12
+ required: true
13
+ },
14
+ statefulLayout: {
15
+ /** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
16
+ type: Object,
17
+ required: true
18
+ }
14
19
  },
15
- statefulLayout: {
16
- /** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
17
- type: Object,
18
- required: true
20
+ setup (props) {
21
+ useDefaults({}, 'VjsfCheckbox')
22
+
23
+ const { inputProps, localData, compSlots } = useNode(toRef(props, 'modelValue'), props.statefulLayout)
24
+
25
+ const fullProps = computed(() => {
26
+ const fullProps = { ...inputProps.value }
27
+ // it is not very common to show an error below checkboxes and switches and without hide-details=auto they take a lot of space
28
+ if (!('hideDetails' in inputProps)) fullProps.hideDetails = 'auto'
29
+ fullProps.modelValue = localData.value
30
+ return fullProps
31
+ })
32
+
33
+ return () => h(VCheckbox, fullProps.value, compSlots.value)
19
34
  }
20
35
  })
21
36
 
22
- const fieldProps = computed(() => {
23
- const inputProps = getInputProps(props.modelValue, props.statefulLayout)
24
- // it is not very common to show an error below checkboxes and switches and without hide-details=auto they take a lot of space
25
- if (!('hideDetails' in inputProps)) inputProps.hideDetails = 'auto'
26
- return inputProps
27
- })
28
37
  </script>
29
-
30
- <template>
31
- <v-checkbox
32
- v-bind="fieldProps"
33
- @update:model-value="value => statefulLayout.input(modelValue, value)"
34
- />
35
- </template>
@@ -1,8 +1,8 @@
1
1
  <script setup>
2
2
  import TextFieldMenu from '../fragments/text-field-menu.vue'
3
3
  import { VColorPicker } from 'vuetify/components/VColorPicker'
4
- import { computed } from 'vue'
5
- import { getCompProps } from '../../utils/index.js'
4
+ import { computed, toRef } from 'vue'
5
+ import useNode from '../../composables/use-node.js'
6
6
  import { useDefaults } from 'vuetify'
7
7
 
8
8
  useDefaults({}, 'VjsfColorPicker')
@@ -20,9 +20,11 @@ const props = defineProps({
20
20
  }
21
21
  })
22
22
 
23
+ const { compProps, localData } = useNode(toRef(props, 'modelValue'), props.statefulLayout)
24
+
23
25
  const colorPickerProps = computed(() => {
24
- const colorPickerProps = getCompProps(props.modelValue, true)
25
- colorPickerProps.modelValue = props.modelValue.data
26
+ const colorPickerProps = { ...compProps.value }
27
+ colorPickerProps.modelValue = localData.value
26
28
  return colorPickerProps
27
29
  })
28
30
  </script>
@@ -1,7 +1,8 @@
1
1
  <script>
2
- import { defineComponent, h, computed, shallowRef, ref } from 'vue'
2
+ import { defineComponent, h, computed, toRef } from 'vue'
3
3
  import { VCombobox } from 'vuetify/components/VCombobox'
4
- import { getInputProps, getCompSlots } from '../../utils/index.js'
4
+ import useNode from '../../composables/use-node.js'
5
+ import useGetItems from '../../composables/use-get-items.js'
5
6
  import { useDefaults } from 'vuetify'
6
7
 
7
8
  export default defineComponent({
@@ -20,55 +21,28 @@ export default defineComponent({
20
21
  setup (props) {
21
22
  useDefaults({}, 'VjsfCombobox')
22
23
 
23
- /** @type import('vue').Ref<import('@json-layout/vocabulary').SelectItems> */
24
- const items = shallowRef(props.modelValue.layout.items ?? [])
25
- /** @type import('vue').Ref<boolean> */
26
- const loading = ref(false)
27
-
28
- /** @type import('@json-layout/core').StateTree | null */
29
- let lastStateTree = null
30
- /** @type Record<string, any> | null */
31
- let lastContext = null
32
-
33
- const hasItems = computed(() => {
34
- return !!(props.modelValue.layout.items || props.modelValue.layout.getItems)
35
- })
36
-
37
- const refresh = async () => {
38
- if (props.modelValue.layout.items) return
39
- if (props.statefulLayout.stateTree === lastStateTree && props.statefulLayout.options.context === lastContext) return
40
- lastStateTree = props.statefulLayout.stateTree
41
- lastContext = props.statefulLayout.options.context ?? null
42
- if (hasItems.value) {
43
- loading.value = true
44
- items.value = await props.statefulLayout.getItems(props.modelValue)
45
- loading.value = false
46
- }
47
- }
48
-
49
- if (!props.modelValue.layout.items) {
50
- refresh()
51
- }
24
+ const nodeRef = toRef(props, 'modelValue')
25
+ const getItems = useGetItems(nodeRef, props.statefulLayout)
26
+ const { inputProps, compSlots, localData, layout, options } = useNode(nodeRef, props.statefulLayout)
52
27
 
53
28
  const fieldProps = computed(() => {
54
- const fieldProps = getInputProps(props.modelValue, props.statefulLayout)
55
- fieldProps.loading = loading.value
29
+ const fieldProps = { ...inputProps.value }
56
30
  fieldProps.returnObject = false
57
- if (hasItems.value) fieldProps.items = items.value
58
- if (props.modelValue.options.readOnly) fieldProps.menuProps = { modelValue: false }
59
- if (props.modelValue.layout.multiple) {
31
+ if (options.value.readOnly) fieldProps.menuProps = { modelValue: false }
32
+ if (getItems.hasItems.value) {
33
+ fieldProps.items = getItems.items.value
34
+ fieldProps.loading = getItems.loading.value
35
+ }
36
+ if (layout.value.multiple) {
60
37
  fieldProps.multiple = true
61
38
  fieldProps.chips = true
62
39
  fieldProps.closableChips = true
63
40
  }
64
- fieldProps['onUpdate:menu'] = () => refresh()
65
41
  return fieldProps
66
42
  })
67
43
 
68
- const fieldSlots = computed(() => getCompSlots(props.modelValue, props.statefulLayout))
69
-
70
44
  // @ts-ignore
71
- return () => h(VCombobox, fieldProps.value, fieldSlots.value)
45
+ return () => h(VCombobox, { ...fieldProps.value, modelValue: localData.value }, compSlots.value)
72
46
  }
73
47
  })
74
48
 
@@ -2,8 +2,9 @@
2
2
  import TextFieldMenu from '../fragments/text-field-menu.vue'
3
3
  import { VDatePicker } from 'vuetify/components/VDatePicker'
4
4
  import { useDate, useDefaults } from 'vuetify'
5
- import { computed, ref } from 'vue'
6
- import { getCompProps, getDateTimeParts, getDateTimeWithOffset } from '../../utils/index.js'
5
+ import { computed, ref, toRef } from 'vue'
6
+ import { getDateTimeParts, getDateTimeWithOffset } from '../../utils/dates.js'
7
+ import useNode from '../../composables/use-node.js'
7
8
 
8
9
  useDefaults({}, 'VjsfDatePicker')
9
10
 
@@ -24,10 +25,12 @@ const vDate = useDate()
24
25
 
25
26
  const menuOpened = ref(false)
26
27
 
28
+ const { compProps, localData } = useNode(toRef(props, 'modelValue'), props.statefulLayout)
29
+
27
30
  const datePickerProps = computed(() => {
28
- const datePickerProps = getCompProps(props.modelValue, true)
31
+ const datePickerProps = { ...compProps.value }
29
32
  datePickerProps.hideActions = true
30
- if (props.modelValue.data) datePickerProps.modelValue = new Date(props.modelValue.data)
33
+ if (localData.value) datePickerProps.modelValue = new Date(/** @type {string} */(localData.value))
31
34
  datePickerProps['onUpdate:modelValue'] = (/** @type {Date} */value) => {
32
35
  if (!value) return
33
36
  if (props.modelValue.layout.format === 'date-time') {
@@ -39,14 +42,19 @@ const datePickerProps = computed(() => {
39
42
  }
40
43
  return datePickerProps
41
44
  })
45
+
46
+ const formattedValue = computed(() => {
47
+ return localData.value ? vDate.format(/** @type {string} */(localData.value), 'fullDateWithWeekday') : null
48
+ })
49
+
42
50
  </script>
43
51
 
44
52
  <template>
45
53
  <text-field-menu
46
54
  v-model:menu-opened="menuOpened"
47
- :model-value="modelValue"
55
+ :model-value="props.modelValue"
48
56
  :stateful-layout="statefulLayout"
49
- :formatted-value="modelValue.data && vDate.format(modelValue.data, 'fullDateWithWeekday')"
57
+ :formatted-value="formattedValue"
50
58
  >
51
59
  <v-date-picker v-bind="datePickerProps" />
52
60
  </text-field-menu>
@@ -6,8 +6,9 @@ import { VTabs, VTab, VTabsWindow, VTabsWindowItem } from 'vuetify/components/VT
6
6
  import { VIcon } from 'vuetify/components/VIcon'
7
7
  import { VSheet } from 'vuetify/components/VSheet'
8
8
  import { useDate, useDefaults } from 'vuetify'
9
- import { computed, ref, watch } from 'vue'
10
- import { getCompProps, getDateTimeParts, getDateTimeWithOffset, getShortTime } from '../../utils/index.js'
9
+ import { computed, ref, watch, toRef } from 'vue'
10
+ import { getDateTimeParts, getDateTimeWithOffset, getShortTime } from '../../utils/dates.js'
11
+ import useNode from '../../composables/use-node.js'
11
12
 
12
13
  useDefaults({}, 'VjsfDatePicker')
13
14
 
@@ -30,17 +31,19 @@ const tab = ref('date')
30
31
  const menuOpened = ref(false)
31
32
  watch(menuOpened, () => { tab.value = 'date' })
32
33
 
34
+ const { compProps, localData } = useNode(toRef(props, 'modelValue'), props.statefulLayout)
35
+
33
36
  const datePickerProps = computed(() => {
34
- const datePickerProps = getCompProps(props.modelValue, false)
37
+ const datePickerProps = { ...compProps.value }
35
38
  datePickerProps.hideActions = true
36
- if (props.modelValue.data) datePickerProps.modelValue = new Date(props.modelValue.data)
39
+ if (localData.value) datePickerProps.modelValue = new Date(localData.value)
37
40
  datePickerProps['onUpdate:modelValue'] = (/** @type {Date} */value) => {
38
41
  if (!value) return
39
42
 
40
- if (props.modelValue.data) {
43
+ if (localData.value) {
41
44
  // replace date part of current value
42
45
  const datePart = value && getDateTimeParts(/** @type Date */(/** @type unknown */(value)))[0]
43
- props.statefulLayout.input(props.modelValue, datePart + props.modelValue.data.slice(10))
46
+ props.statefulLayout.input(props.modelValue, datePart + localData.value.slice(10))
44
47
  } else {
45
48
  props.statefulLayout.input(props.modelValue, getDateTimeWithOffset(value))
46
49
  }
@@ -50,13 +53,13 @@ const datePickerProps = computed(() => {
50
53
  })
51
54
 
52
55
  const timePickerProps = computed(() => {
53
- const timePickerProps = getCompProps(props.modelValue, false)
56
+ const timePickerProps = { ...compProps.value }
54
57
  timePickerProps['ampm-in-title'] = true
55
- if (props.modelValue.data) timePickerProps.modelValue = getShortTime(props.modelValue.data.slice(11))
58
+ if (localData.value) timePickerProps.modelValue = getShortTime(localData.value.slice(11))
56
59
  timePickerProps['onUpdate:modelValue'] = (/** @type {string} */value) => {
57
- if (!props.modelValue.data) return
58
- console.log('set time', value, props.modelValue.data.slice(0, 10), props.modelValue.data.slice(15))
59
- props.statefulLayout.input(props.modelValue, props.modelValue.data.slice(0, 11) + value + props.modelValue.data.slice(16))
60
+ if (!localData.value) return
61
+ console.log('set time', value, localData.value.slice(0, 10), localData.value.slice(15))
62
+ props.statefulLayout.input(props.modelValue, localData.value.slice(0, 11) + value + localData.value.slice(16))
60
63
  }
61
64
  return timePickerProps
62
65
  })
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { toRef } from 'vue'
2
3
  import { VExpansionPanels, VExpansionPanel, VExpansionPanelTitle, VExpansionPanelText } from 'vuetify/components/VExpansionPanel'
3
4
  import { VContainer, VRow } from 'vuetify/components/VGrid'
4
5
  import { VIcon } from 'vuetify/components/VIcon'
@@ -6,12 +7,12 @@ import { isSection } from '@json-layout/core'
6
7
  import Node from '../node.vue'
7
8
  import SectionHeader from '../fragments/section-header.vue'
8
9
  import ChildSubtitle from '../fragments/child-subtitle.vue'
9
- import { getCompProps } from '../../utils/index.js'
10
+ import useNode from '../../composables/use-node.js'
10
11
  import { useDefaults } from 'vuetify'
11
12
 
12
13
  useDefaults({}, 'VjsfExpansionPanels')
13
14
 
14
- defineProps({
15
+ const props = defineProps({
15
16
  modelValue: {
16
17
  /** @type import('vue').PropType<import('../../types.js').VjsfExpansionPanelsNode> */
17
18
  type: Object,
@@ -24,11 +25,13 @@ defineProps({
24
25
  }
25
26
  })
26
27
 
28
+ const { compProps } = useNode(toRef(props, 'modelValue'), props.statefulLayout)
29
+
27
30
  </script>
28
31
 
29
32
  <template>
30
33
  <section-header :node="modelValue" />
31
- <v-expansion-panels v-bind="getCompProps(modelValue, true)">
34
+ <v-expansion-panels v-bind="compProps">
32
35
  <v-expansion-panel
33
36
  v-for="(child, i) of modelValue.children"
34
37
  :key="child.key"
@@ -1,7 +1,7 @@
1
1
  <script>
2
- import { defineComponent, h, computed } from 'vue'
2
+ import { defineComponent, h, computed, toRef } from 'vue'
3
3
  import { VFileInput } from 'vuetify/components/VFileInput'
4
- import { getInputProps, getCompSlots } from '../../utils/index.js'
4
+ import useNode from '../../composables/use-node.js'
5
5
  import { useDefaults } from 'vuetify'
6
6
 
7
7
  export default defineComponent({
@@ -20,20 +20,21 @@ export default defineComponent({
20
20
  setup (props) {
21
21
  useDefaults({}, 'VjsfFileInput')
22
22
 
23
+ const { inputProps, localData, compSlots } = useNode(
24
+ toRef(props, 'modelValue'), props.statefulLayout, { layoutPropsMap: ['placeholder', 'accept', 'multiple'] }
25
+ )
26
+
23
27
  const fieldProps = computed(() => {
24
- const fieldProps = getInputProps(props.modelValue, props.statefulLayout, ['placeholder', 'accept'])
25
- if (props.modelValue.layout.multiple) {
26
- fieldProps.multiple = true
27
- } else {
28
- fieldProps.modelValue = props.modelValue.data ? [props.modelValue.data] : props.modelValue.data
29
- fieldProps['onUpdate:modelValue'] = (/** @type string */value) => props.statefulLayout.input(props.modelValue, Array.isArray(value) ? value[0] : value)
28
+ const fieldProps = { ...inputProps.value }
29
+ if (fieldProps.multiple) console.error('File input doesn\'t support multiple inputs yet')
30
+ fieldProps['onUpdate:modelValue'] = (/** @type {File} */value) => {
31
+ props.statefulLayout.input(props.modelValue, value)
30
32
  }
31
33
  return fieldProps
32
34
  })
33
- const fieldSlots = computed(() => getCompSlots(props.modelValue, props.statefulLayout))
34
35
 
35
36
  // @ts-ignore
36
- return () => h(VFileInput, fieldProps.value, fieldSlots.value)
37
+ return () => h(VFileInput, { ...fieldProps.value, modelValue: localData.value }, compSlots.value)
37
38
  }
38
39
  })
39
40