@koumoul/vjsf 3.0.0-beta.3 → 3.0.0-beta.31

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 (103) 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/help-message.vue +10 -1
  8. package/src/components/fragments/section-header.vue +1 -3
  9. package/src/components/fragments/select-item-icon.vue +1 -1
  10. package/src/components/fragments/select-selection.vue +2 -1
  11. package/src/components/fragments/selection-group.vue +100 -0
  12. package/src/components/fragments/text-field-menu.vue +5 -1
  13. package/src/components/node.vue +47 -42
  14. package/src/components/nodes/autocomplete.vue +11 -35
  15. package/src/components/nodes/checkbox-group.vue +39 -0
  16. package/src/components/nodes/checkbox.vue +9 -1
  17. package/src/components/nodes/color-picker.vue +5 -1
  18. package/src/components/nodes/combobox.vue +3 -0
  19. package/src/components/nodes/date-picker.vue +4 -2
  20. package/src/components/nodes/date-time-picker.vue +3 -0
  21. package/src/components/nodes/expansion-panels.vue +24 -12
  22. package/src/components/nodes/file-input.vue +3 -0
  23. package/src/components/nodes/list.vue +145 -91
  24. package/src/components/nodes/number-combobox.vue +3 -0
  25. package/src/components/nodes/number-field.vue +3 -0
  26. package/src/components/nodes/one-of-select.vue +45 -24
  27. package/src/components/nodes/radio-group.vue +53 -0
  28. package/src/components/nodes/section.vue +3 -0
  29. package/src/components/nodes/select.vue +10 -27
  30. package/src/components/nodes/slider.vue +3 -0
  31. package/src/components/nodes/stepper.vue +3 -0
  32. package/src/components/nodes/switch-group.vue +39 -0
  33. package/src/components/nodes/switch.vue +9 -3
  34. package/src/components/nodes/tabs.vue +10 -3
  35. package/src/components/nodes/text-field.vue +3 -0
  36. package/src/components/nodes/textarea.vue +3 -0
  37. package/src/components/nodes/vertical-tabs.vue +6 -1
  38. package/src/components/options.js +21 -5
  39. package/src/components/vjsf.vue +6 -0
  40. package/src/composables/use-comp-defaults.js +19 -0
  41. package/src/composables/use-dnd.js +1 -0
  42. package/src/composables/use-get-items.js +48 -0
  43. package/src/composables/use-vjsf.js +76 -40
  44. package/src/index.js +3 -0
  45. package/src/types.ts +21 -6
  46. package/src/utils/build.js +1 -1
  47. package/src/utils/index.js +0 -1
  48. package/src/utils/props.js +9 -30
  49. package/types/compat/v2.d.ts.map +1 -1
  50. package/types/compile/index.d.ts +2 -2
  51. package/types/compile/index.d.ts.map +1 -1
  52. package/types/compile/options.d.ts.map +1 -1
  53. package/types/components/fragments/selection-group.vue.d.ts +35 -0
  54. package/types/components/fragments/selection-group.vue.d.ts.map +1 -0
  55. package/types/components/fragments/text-field-menu.vue.d.ts.map +1 -1
  56. package/types/components/nodes/autocomplete.vue.d.ts.map +1 -1
  57. package/types/components/nodes/checkbox-group copy.vue.d.ts +27 -0
  58. package/types/components/nodes/checkbox-group copy.vue.d.ts.map +1 -0
  59. package/types/components/nodes/checkbox-group.vue.d.ts +27 -0
  60. package/types/components/nodes/checkbox-group.vue.d.ts.map +1 -0
  61. package/types/components/nodes/combobox.vue.d.ts.map +1 -1
  62. package/types/components/nodes/file-input.vue.d.ts.map +1 -1
  63. package/types/components/nodes/number-combobox.vue.d.ts.map +1 -1
  64. package/types/components/nodes/number-field.vue.d.ts.map +1 -1
  65. package/types/components/nodes/radio-group.vue.d.ts +27 -0
  66. package/types/components/nodes/radio-group.vue.d.ts.map +1 -0
  67. package/types/components/nodes/radio.vue.d.ts +10 -0
  68. package/types/components/nodes/radio.vue.d.ts.map +1 -0
  69. package/types/components/nodes/select.vue.d.ts.map +1 -1
  70. package/types/components/nodes/switch-group.vue.d.ts +27 -0
  71. package/types/components/nodes/switch-group.vue.d.ts.map +1 -0
  72. package/types/components/nodes/text-field.vue.d.ts.map +1 -1
  73. package/types/components/nodes/textarea.vue.d.ts.map +1 -1
  74. package/types/components/options.d.ts +1 -1
  75. package/types/components/options.d.ts.map +1 -1
  76. package/types/components/vjsf.vue.d.ts +2 -2
  77. package/types/composables/use-comp-defaults.d.ts +8 -0
  78. package/types/composables/use-comp-defaults.d.ts.map +1 -0
  79. package/types/composables/use-dnd.d.ts.map +1 -1
  80. package/types/composables/use-get-items.d.ts +13 -0
  81. package/types/composables/use-get-items.d.ts.map +1 -0
  82. package/types/composables/use-vjsf.d.ts.map +1 -1
  83. package/types/index.d.ts +2 -0
  84. package/types/index.d.ts.map +1 -1
  85. package/types/types.d.ts +20 -8
  86. package/types/types.d.ts.map +1 -1
  87. package/types/utils/build.d.ts +1 -1
  88. package/types/utils/index.d.ts +0 -1
  89. package/types/utils/props.d.ts +3 -4
  90. package/types/utils/props.d.ts.map +1 -1
  91. package/src/utils/global-register.js +0 -13
  92. package/types/components/global-register.d.ts +0 -8
  93. package/types/components/global-register.d.ts.map +0 -1
  94. package/types/components/nodes/markdown.vue.d.ts +0 -27
  95. package/types/components/nodes/markdown.vue.d.ts.map +0 -1
  96. package/types/components/nodes/text-field copy.vue.d.ts +0 -10
  97. package/types/components/nodes/text-field copy.vue.d.ts.map +0 -1
  98. package/types/components/types.d.ts +0 -91
  99. package/types/components/types.d.ts.map +0 -1
  100. package/types/components/v-jsf.vue.d.ts +0 -13
  101. package/types/components/v-jsf.vue.d.ts.map +0 -1
  102. package/types/utils/clone.d.ts +0 -3
  103. package/types/utils/clone.d.ts.map +0 -1
@@ -1,7 +1,9 @@
1
1
  <script>
2
2
  import { VAutocomplete } from 'vuetify/components'
3
- import { defineComponent, computed, ref, shallowRef, h } from 'vue'
3
+ import { useDefaults } from 'vuetify'
4
+ import { defineComponent, computed, h } from 'vue'
4
5
  import { getInputProps, getCompSlots } from '../../utils/index.js'
6
+ import useGetItems from '../../composables/use-get-items.js'
5
7
  import SelectItem from '../fragments/select-item.vue'
6
8
  import SelectSelection from '../fragments/select-selection.vue'
7
9
 
@@ -13,54 +15,28 @@ export default defineComponent({
13
15
  required: true
14
16
  },
15
17
  statefulLayout: {
16
- /** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
18
+ /** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
17
19
  type: Object,
18
20
  required: true
19
21
  }
20
22
  },
21
23
  setup (props) {
22
- /** @type import('vue').ShallowRef<import('@json-layout/vocabulary').SelectItems> */
23
- const items = shallowRef([])
24
- /** @type import('vue').Ref<boolean> */
25
- const loading = ref(false)
26
- /** @type import('vue').Ref<string> */
27
- const search = ref('')
24
+ useDefaults({}, 'VjsfAutocomplete')
25
+ const getItems = useGetItems(props)
28
26
 
29
27
  const fieldProps = computed(() => {
30
28
  const fieldProps = getInputProps(props.modelValue, props.statefulLayout, ['multiple'])
31
29
  if (props.modelValue.options.readOnly) fieldProps.menuProps = { modelValue: false }
32
30
  fieldProps.noFilter = true
33
31
  fieldProps['onUpdate:search'] = (/** @type string */searchValue) => {
34
- search.value = searchValue
35
- refresh()
32
+ getItems.search.value = searchValue
36
33
  }
37
- fieldProps['onUpdate:menu'] = refresh
38
- fieldProps.items = items.value
39
- fieldProps.loading = loading.value
34
+ fieldProps.items = getItems.items.value
35
+ fieldProps.loading = getItems.loading.value
36
+ fieldProps.clearable = fieldProps.clearable ?? !props.modelValue.skeleton.required
40
37
  return fieldProps
41
38
  })
42
39
 
43
- /** @type import('@json-layout/core').StateTree | null */
44
- let lastStateTree = null
45
- /** @type Record<string, any> | null */
46
- let lastContext = null
47
- /** @type string */
48
- let lastSearch = ''
49
-
50
- const refresh = async () => {
51
- if (props.statefulLayout.stateTree === lastStateTree && props.statefulLayout.options.context === lastContext && search.value === lastSearch) return
52
- loading.value = true
53
- items.value = await props.statefulLayout.getItems(props.modelValue, search.value)
54
- lastStateTree = props.statefulLayout.stateTree
55
- lastContext = props.statefulLayout.options.context ?? null
56
- lastSearch = search.value
57
- loading.value = false
58
- }
59
-
60
- if (!props.modelValue.layout.items) {
61
- refresh()
62
- }
63
-
64
40
  const fieldSlots = computed(() => {
65
41
  const slots = getCompSlots(props.modelValue, props.statefulLayout)
66
42
  if (!slots.item) {
@@ -74,7 +50,7 @@ export default defineComponent({
74
50
  slots.selection = (/** @type {any} */ context) => h(SelectSelection, {
75
51
  multiple: props.modelValue.layout.multiple,
76
52
  last: props.modelValue.layout.multiple && context.index === props.modelValue.data.length - 1,
77
- item: context.item.raw
53
+ item: getItems.prepareSelectedItem(context.item.raw, context.item.value)
78
54
  })
79
55
  }
80
56
  return slots
@@ -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({}, 'VjsfCheckboxGroup')
21
+
22
+ // @ts-ignore
23
+ return () => {
24
+ return h(SelectionGroup, {
25
+ modelValue: props.modelValue,
26
+ statefulLayout: props.statefulLayout,
27
+ type: 'checkbox'
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>
@@ -2,6 +2,9 @@
2
2
  import { VCheckbox } from 'vuetify/components'
3
3
  import { computed } from 'vue'
4
4
  import { getInputProps } from '../../utils/index.js'
5
+ import { useDefaults } from 'vuetify'
6
+
7
+ useDefaults({}, 'VjsfCheckbox')
5
8
 
6
9
  const props = defineProps({
7
10
  modelValue: {
@@ -16,7 +19,12 @@ const props = defineProps({
16
19
  }
17
20
  })
18
21
 
19
- const fieldProps = computed(() => getInputProps(props.modelValue, props.statefulLayout))
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
+ })
20
28
  </script>
21
29
 
22
30
  <template>
@@ -3,6 +3,9 @@ import TextFieldMenu from '../fragments/text-field-menu.vue'
3
3
  import { VColorPicker } from 'vuetify/components'
4
4
  import { computed } from 'vue'
5
5
  import { getCompProps } from '../../utils/index.js'
6
+ import { useDefaults } from 'vuetify'
7
+
8
+ useDefaults({}, 'VjsfColorPicker')
6
9
 
7
10
  const props = defineProps({
8
11
  modelValue: {
@@ -18,7 +21,8 @@ const props = defineProps({
18
21
  })
19
22
 
20
23
  const colorPickerProps = computed(() => {
21
- const colorPickerProps = getCompProps(props.modelValue, 'colorPicker', true)
24
+ const colorPickerProps = getCompProps(props.modelValue, true)
25
+ colorPickerProps.modelValue = props.modelValue.data
22
26
  return colorPickerProps
23
27
  })
24
28
  </script>
@@ -2,6 +2,7 @@
2
2
  import { defineComponent, h, computed, shallowRef, ref } from 'vue'
3
3
  import { VCombobox } from 'vuetify/components'
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({}, 'VjsfCombobox')
22
+
20
23
  /** @type import('vue').Ref<import('@json-layout/vocabulary').SelectItems> */
21
24
  const items = shallowRef(props.modelValue.layout.items ?? [])
22
25
  /** @type import('vue').Ref<boolean> */
@@ -1,10 +1,12 @@
1
1
  <script setup>
2
2
  import TextFieldMenu from '../fragments/text-field-menu.vue'
3
3
  import { VDatePicker } from 'vuetify/components/VDatePicker'
4
- import { useDate } from 'vuetify'
4
+ import { useDate, useDefaults } from 'vuetify'
5
5
  import { computed } from 'vue'
6
6
  import { getCompProps, getDateTimeParts } from '../../utils/index.js'
7
7
 
8
+ useDefaults({}, 'VjsfDatePicker')
9
+
8
10
  const props = defineProps({
9
11
  modelValue: {
10
12
  /** @type import('vue').PropType<import('../../types.js').VjsfDatePickerNode> */
@@ -21,7 +23,7 @@ const props = defineProps({
21
23
  const vDate = useDate()
22
24
 
23
25
  const datePickerProps = computed(() => {
24
- const datePickerProps = getCompProps(props.modelValue, 'datePicker', true)
26
+ const datePickerProps = getCompProps(props.modelValue, true)
25
27
  datePickerProps.hideActions = true
26
28
  if (props.modelValue.data) datePickerProps.modelValue = new Date(props.modelValue.data)
27
29
  return datePickerProps
@@ -1,4 +1,7 @@
1
1
  <script setup>
2
+ import { useDefaults } from 'vuetify'
3
+
4
+ useDefaults({}, 'VjsfDateTimePicker')
2
5
 
3
6
  defineProps({
4
7
  modelValue: {
@@ -1,8 +1,12 @@
1
1
  <script setup>
2
- import { VExpansionPanels, VExpansionPanel, VExpansionPanelTitle, VContainer, VRow, VIcon } from 'vuetify/components'
2
+ import { VExpansionPanels, VExpansionPanel, VExpansionPanelTitle, VExpansionPanelText, VContainer, VRow, VIcon } from 'vuetify/components'
3
3
  import { isSection } from '@json-layout/core'
4
4
  import Node from '../node.vue'
5
5
  import SectionHeader from '../fragments/section-header.vue'
6
+ import { getCompProps } from '../../utils/index.js'
7
+ import { useDefaults } from 'vuetify'
8
+
9
+ useDefaults({}, 'VjsfExpansionPanels')
6
10
 
7
11
  defineProps({
8
12
  modelValue: {
@@ -21,7 +25,7 @@ defineProps({
21
25
 
22
26
  <template>
23
27
  <section-header :node="modelValue" />
24
- <v-expansion-panels>
28
+ <v-expansion-panels v-bind="getCompProps(modelValue, true)">
25
29
  <v-expansion-panel
26
30
  v-for="(child, i) of modelValue.children"
27
31
  :key="child.key"
@@ -37,16 +41,24 @@ defineProps({
37
41
  </v-icon>
38
42
  {{ child.layout.title ?? child.layout.label }}
39
43
  </v-expansion-panel-title>
40
- <v-container fluid>
41
- <v-row>
42
- <node
43
- v-for="grandChild of isSection(child) ? child.children : [child]"
44
- :key="grandChild.fullKey"
45
- :model-value="/** @type import('../../types.js').VjsfNode */(grandChild)"
46
- :stateful-layout="statefulLayout"
47
- />
48
- </v-row>
49
- </v-container>
44
+ <v-expansion-panel-text>
45
+ <v-container fluid>
46
+ <v-row>
47
+ <node
48
+ v-for="grandChild of isSection(child) ? child.children : [child]"
49
+ :key="grandChild.fullKey"
50
+ :model-value="/** @type import('../../types.js').VjsfNode */(grandChild)"
51
+ :stateful-layout="statefulLayout"
52
+ />
53
+ </v-row>
54
+ </v-container>
55
+ </v-expansion-panel-text>
50
56
  </v-expansion-panel>
51
57
  </v-expansion-panels>
52
58
  </template>
59
+
60
+ <style>
61
+ .vjsf-node-expansion-panels .v-expansion-panel-text__wrapper {
62
+ padding: 0;
63
+ }
64
+ </style>
@@ -2,6 +2,7 @@
2
2
  import { defineComponent, h, computed } from 'vue'
3
3
  import { VFileInput } from 'vuetify/components'
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({}, 'VjsfFileInput')
22
+
20
23
  const fieldProps = computed(() => {
21
24
  const fieldProps = getInputProps(props.modelValue, props.statefulLayout, ['placeholder', 'accept'])
22
25
  if (props.modelValue.layout.multiple) {
@@ -1,10 +1,15 @@
1
1
  <script setup>
2
2
  import { watch, computed, ref } from 'vue'
3
+ import { useDefaults, useTheme } from 'vuetify'
3
4
  import { VList, VListItem, VListItemAction, VBtn, VMenu, VIcon, VSheet, VSpacer, VDivider, VRow, VListSubheader } from 'vuetify/components'
4
5
  import { isSection, clone } from '@json-layout/core'
5
6
  import Node from '../node.vue'
6
7
  import { moveArrayItem } from '../../utils/index.js'
7
8
  import useDnd from '../../composables/use-dnd.js'
9
+ import useCompDefaults from '../../composables/use-comp-defaults.js'
10
+
11
+ useDefaults({}, 'VjsfList')
12
+ const vSheetProps = useCompDefaults('VjsfList-VSheet', { border: true })
8
13
 
9
14
  const props = defineProps({
10
15
  modelValue: {
@@ -19,6 +24,8 @@ const props = defineProps({
19
24
  }
20
25
  })
21
26
 
27
+ const theme = useTheme()
28
+
22
29
  /* use composable for drag and drop */
23
30
  const { activeDnd, sortableArray, draggable, hovered, dragging, itemBind, handleBind } = useDnd(props.modelValue.children, () => {
24
31
  props.statefulLayout.input(props.modelValue, sortableArray.value.map((child) => child.data))
@@ -27,7 +34,7 @@ watch(() => props.modelValue.children, (array) => { sortableArray.value = array
27
34
 
28
35
  /* manage hovered and edited items */
29
36
  const editedItem = computed(() => {
30
- return props.statefulLayout.activeItems[props.modelValue.fullKey]
37
+ return props.statefulLayout.activatedItems[props.modelValue.fullKey]
31
38
  })
32
39
  const menuOpened = ref(-1)
33
40
  const activeItem = computed(() => {
@@ -48,11 +55,49 @@ const buttonDensity = computed(() => {
48
55
  return props.modelValue.options.density
49
56
  })
50
57
 
58
+ const pushEmptyItem = () => {
59
+ const newData = (props.modelValue.data ?? []).concat([undefined])
60
+ props.statefulLayout.input(props.modelValue, newData)
61
+ if (props.modelValue.layout.listEditMode === 'inline-single') {
62
+ props.statefulLayout.activateItem(props.modelValue, newData.length - 1)
63
+ }
64
+ }
65
+
66
+ /**
67
+ * @param {number} childIndex
68
+ */
69
+ const deleteItem = (childIndex) => {
70
+ const newData = [...props.modelValue.data.slice(0, childIndex), ...props.modelValue.data.slice(childIndex + 1)]
71
+ props.statefulLayout.input(props.modelValue, newData)
72
+ menuOpened.value = -1
73
+ }
74
+
75
+ /**
76
+ * @param {import('@json-layout/core').StateNode} child
77
+ * @param {number} childIndex
78
+ */
79
+ const duplicateItem = (child, childIndex) => {
80
+ const newData = [...props.modelValue.data.slice(0, childIndex), clone(child.data), ...props.modelValue.data.slice(childIndex)]
81
+ props.statefulLayout.input(props.modelValue, newData)
82
+ if (props.modelValue.layout.listEditMode === 'inline-single') {
83
+ props.statefulLayout.activateItem(props.modelValue, childIndex + 1)
84
+ }
85
+ menuOpened.value = -1
86
+ }
87
+
88
+ const itemBorderColor = computed(() => (/** @type {import('@json-layout/core').StateNode} */child, /** @type {number} */childIndex) => {
89
+ if (editedItem.value === childIndex) return theme.current.value.colors.primary
90
+ if (child.validated && (child.error || child.childError)) return theme.current.value.colors.error
91
+ if (props.modelValue.options.readOnly) return 'transparent'
92
+ if (activeItem.value === childIndex) return theme.current.value.colors.primary
93
+ return 'transparent'
94
+ })
95
+
51
96
  </script>
52
97
 
53
98
  <template>
54
- <v-sheet :elevation="1">
55
- <v-list :density="modelValue.options.density">
99
+ <v-sheet v-bind="vSheetProps">
100
+ <v-list>
56
101
  <v-list-subheader v-if="modelValue.layout.title">
57
102
  {{ modelValue.layout.title }}
58
103
  </v-list-subheader>
@@ -62,9 +107,9 @@ const buttonDensity = computed(() => {
62
107
  >
63
108
  <v-list-item
64
109
  v-bind="itemBind(childIndex)"
65
- :density="modelValue.options.density"
66
110
  :draggable="draggable === childIndex"
67
- :variant="editedItem === childIndex ? 'outlined' : 'flat'"
111
+ variant="flat"
112
+ :style="`border: 1px solid ${itemBorderColor(child, childIndex)}`"
68
113
  class="pa-1 vjsf-list-item"
69
114
  >
70
115
  <v-row class="ma-0">
@@ -76,100 +121,110 @@ const buttonDensity = computed(() => {
76
121
  />
77
122
  </v-row>
78
123
  <template
79
- v-if="activeItem === childIndex"
124
+ v-if="!modelValue.options.readOnly && modelValue.layout.listActions.length"
80
125
  #append
81
126
  >
82
127
  <div>
83
- <v-list-item-action
84
- v-if="modelValue.layout.listActions.includes('edit') && modelValue.layout.listEditMode === 'inline-single'"
85
- >
128
+ <v-list-item-action v-if="activeItem !== childIndex">
86
129
  <v-btn
87
- v-if="editedItem !== childIndex"
88
- :title="modelValue.messages.edit"
89
- icon="mdi-pencil"
130
+ style="visibility:hidden"
90
131
  variant="text"
91
- color="primary"
92
132
  :density="buttonDensity"
93
- @click="statefulLayout.activateItem(modelValue, childIndex)"
94
- />
95
- <v-btn
96
- v-else
97
- :title="modelValue.messages.edit"
98
133
  icon="mdi-pencil"
99
- variant="flat"
100
- color="primary"
101
- :density="buttonDensity"
102
- @click="statefulLayout.deactivateItem(modelValue)"
103
134
  />
104
135
  </v-list-item-action>
105
- <v-list-item-action
106
- v-if="editedItem === undefined && modelValue.layout.listActions.includes('sort') && activeDnd"
107
- >
108
- <v-btn
109
- :title="modelValue.messages.sort"
110
- icon="mdi-arrow-up-down"
111
- variant="plain"
112
- :density="buttonDensity"
113
- v-bind="handleBind(childIndex)"
114
- />
115
- </v-list-item-action>
116
- <v-list-item-action
117
- v-if="editedItem === undefined && (modelValue.layout.listActions.includes('delete') || modelValue.layout.listActions.includes('duplicate') || modelValue.layout.listActions.includes('sort'))"
118
- >
119
- <v-menu
120
- location="bottom end"
121
- @update:model-value="value => {menuOpened = value ? childIndex : -1}"
136
+ <template v-else>
137
+ <v-list-item-action
138
+ v-if="modelValue.layout.listActions.includes('edit') && modelValue.layout.listEditMode === 'inline-single'"
122
139
  >
123
- <template #activator="{props: activatorProps}">
124
- <v-btn
125
- v-bind="activatorProps"
126
- icon="mdi-dots-vertical"
127
- variant="plain"
128
- slim
129
- :density="buttonDensity"
130
- />
131
- </template>
132
- <v-list :density="modelValue.options.density">
133
- <v-list-item
134
- v-if="modelValue.layout.listActions.includes('delete')"
135
- base-color="warning"
136
- @click="statefulLayout.input(modelValue, [...modelValue.data.slice(0, childIndex), ...modelValue.data.slice(childIndex + 1)])"
137
- >
138
- <template #prepend>
139
- <v-icon icon="mdi-delete" />
140
- </template>
141
- {{ modelValue.messages.delete }}
142
- </v-list-item>
143
- <v-list-item
144
- v-if="modelValue.layout.listActions.includes('duplicate')"
145
- @click="statefulLayout.input(modelValue, [...modelValue.data.slice(0, childIndex), clone(child.data), ...modelValue.data.slice(childIndex)])"
146
- >
147
- <template #prepend>
148
- <v-icon icon="mdi-content-duplicate" />
149
- </template>
150
- {{ modelValue.messages.duplicate }}
151
- </v-list-item>
152
- <v-list-item
153
- v-if="modelValue.layout.listActions.includes('sort')"
154
- @click="statefulLayout.input(modelValue, moveArrayItem(modelValue.data, childIndex, childIndex - 1))"
155
- >
156
- <template #prepend>
157
- <v-icon icon="mdi-arrow-up" />
158
- </template>
159
- {{ modelValue.messages.up }}
160
- </v-list-item>
161
- <v-list-item
162
- v-if="modelValue.layout.listActions.includes('sort')"
163
- @click="statefulLayout.input(modelValue, moveArrayItem(modelValue.data, childIndex, childIndex + 1))"
164
- >
165
- <template #prepend>
166
- <v-icon icon="mdi-arrow-down" />
167
- </template>
168
- {{ modelValue.messages.down }}
169
- </v-list-item>
170
- </v-list>
171
- </v-menu>
172
- </v-list-item-action>
140
+ <v-btn
141
+ v-if="editedItem !== childIndex"
142
+ :title="modelValue.messages.edit"
143
+ icon="mdi-pencil"
144
+ variant="text"
145
+ color="primary"
146
+ :density="buttonDensity"
147
+ @click="statefulLayout.activateItem(modelValue, childIndex)"
148
+ />
149
+ <v-btn
150
+ v-else
151
+ :title="modelValue.messages.close"
152
+ icon="mdi-close"
153
+ variant="flat"
154
+ color="primary"
155
+ :density="buttonDensity"
156
+ @click="statefulLayout.deactivateItem(modelValue)"
157
+ />
158
+ </v-list-item-action>
159
+ <v-list-item-action
160
+ v-if="editedItem === undefined && modelValue.layout.listActions.includes('sort') && activeDnd"
161
+ >
162
+ <v-btn
163
+ :title="modelValue.messages.sort"
164
+ icon="mdi-arrow-up-down"
165
+ variant="plain"
166
+ :density="buttonDensity"
167
+ v-bind="handleBind(childIndex)"
168
+ />
169
+ </v-list-item-action>
170
+ <v-list-item-action
171
+ v-if="editedItem === undefined && (modelValue.layout.listActions.includes('delete') || modelValue.layout.listActions.includes('duplicate') || modelValue.layout.listActions.includes('sort'))"
172
+ >
173
+ <v-menu
174
+ location="bottom end"
175
+ @update:model-value="value => {menuOpened = value ? childIndex : -1}"
176
+ >
177
+ <template #activator="{props: activatorProps}">
178
+ <v-btn
179
+ v-bind="activatorProps"
180
+ icon="mdi-dots-vertical"
181
+ variant="plain"
182
+ slim
183
+ :density="buttonDensity"
184
+ />
185
+ </template>
186
+ <v-list>
187
+ <v-list-item
188
+ v-if="modelValue.layout.listActions.includes('delete')"
189
+ base-color="warning"
190
+ @click="deleteItem(childIndex)"
191
+ >
192
+ <template #prepend>
193
+ <v-icon icon="mdi-delete" />
194
+ </template>
195
+ {{ modelValue.messages.delete }}
196
+ </v-list-item>
197
+ <v-list-item
198
+ v-if="modelValue.layout.listActions.includes('duplicate')"
199
+ @click="duplicateItem(child, childIndex)"
200
+ >
201
+ <template #prepend>
202
+ <v-icon icon="mdi-content-duplicate" />
203
+ </template>
204
+ {{ modelValue.messages.duplicate }}
205
+ </v-list-item>
206
+ <v-list-item
207
+ v-if="modelValue.layout.listActions.includes('sort')"
208
+ @click="statefulLayout.input(modelValue, moveArrayItem(modelValue.data, childIndex, childIndex - 1))"
209
+ >
210
+ <template #prepend>
211
+ <v-icon icon="mdi-arrow-up" />
212
+ </template>
213
+ {{ modelValue.messages.up }}
214
+ </v-list-item>
215
+ <v-list-item
216
+ v-if="modelValue.layout.listActions.includes('sort')"
217
+ @click="statefulLayout.input(modelValue, moveArrayItem(modelValue.data, childIndex, childIndex + 1))"
218
+ >
219
+ <template #prepend>
220
+ <v-icon icon="mdi-arrow-down" />
221
+ </template>
222
+ {{ modelValue.messages.down }}
223
+ </v-list-item>
224
+ </v-list>
225
+ </v-menu>
226
+ </v-list-item-action>
227
+ </template>
173
228
  </div>
174
229
  </template>
175
230
  </v-list-item>
@@ -179,8 +234,7 @@ const buttonDensity = computed(() => {
179
234
  <v-spacer />
180
235
  <v-btn
181
236
  color="primary"
182
- :density="modelValue.options.density"
183
- @click="statefulLayout.input(modelValue, (modelValue.data ?? []).concat([undefined]))"
237
+ @click="pushEmptyItem"
184
238
  >
185
239
  {{ modelValue.messages.addItem }}
186
240
  </v-btn>
@@ -2,6 +2,7 @@
2
2
  import { defineComponent, h, computed, shallowRef, ref } from 'vue'
3
3
  import { VCombobox } from 'vuetify/components'
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({}, 'VjsfNumberCombobox')
22
+
20
23
  /** @type import('vue').Ref<import('@json-layout/vocabulary').SelectItems> */
21
24
  const items = shallowRef(props.modelValue.layout.items ?? [])
22
25
  /** @type import('vue').Ref<boolean> */
@@ -2,6 +2,7 @@
2
2
  import { defineComponent, h, computed } from 'vue'
3
3
  import { VTextField } from 'vuetify/components'
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({}, 'VjsfNumberField')
22
+
20
23
  const fieldProps = computed(() => {
21
24
  const fieldProps = getInputProps(props.modelValue, props.statefulLayout, ['step', 'min', 'max', 'placeholder'])
22
25
  fieldProps.type = 'number'