@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,8 +1,14 @@
1
- import { StatefulLayout } from '@json-layout/core'
1
+ import { StatefulLayout, produceCompileOptions } from '@json-layout/core'
2
2
  import { inject, toRaw, shallowRef, computed, ref, watch, useSlots } from 'vue'
3
3
  import { useElementSize } from '@vueuse/core'
4
4
  import { getFullOptions } from '../components/options.js'
5
- import { registeredNodeComponents } from '../utils/index.js'
5
+ import { setAutoFreeze } from 'immer'
6
+ import Debug from 'debug'
7
+
8
+ const debug = Debug('vjsf:use-vjsf')
9
+
10
+ // immer freezing is disabled because it is not compatible with Vue 3 reactivity
11
+ setAutoFreeze(false)
6
12
 
7
13
  export const emits = {
8
14
  /**
@@ -26,6 +32,8 @@ export const emits = {
26
32
  */
27
33
  export const useVjsf = (schema, modelValue, options, nodeComponents, emit, compile, precompiledLayout) => {
28
34
  const el = ref(null)
35
+
36
+ // TODO: apply a debounce to width ?
29
37
  const { width } = useElementSize(el)
30
38
 
31
39
  /** @type import('vue').ShallowRef<import('../types.js').VjsfStatefulLayout | null> */
@@ -49,72 +57,100 @@ export const useVjsf = (schema, modelValue, options, nodeComponents, emit, compi
49
57
 
50
58
  const slots = useSlots()
51
59
 
52
- const fullOptions = computed(() => getFullOptions(options.value, form, width.value, slots, { ...nodeComponents, ...toRaw(registeredNodeComponents.value) }))
60
+ /* Callbacks from json layout stateful layout */
61
+ /**
62
+ * @param {import('@json-layout/core').StatefulLayout} statefulLayout
63
+ */
64
+ const onStatefulLayoutUpdate = (statefulLayout) => {
65
+ debug('onStatefulLayoutUpdate', statefulLayout)
66
+ if (!statefulLayout) return
67
+ stateTree.value = statefulLayout.stateTree
68
+ debug(' -> emit update:state')
69
+ emit('update:state', statefulLayout)
70
+ if (form) {
71
+ // cf https://vuetifyjs.com/en/components/forms/#validation-state
72
+ if (statefulLayout.valid) form.update('vjsf', true, [])
73
+ else if (statefulLayout.hasHiddenError) form.update('vjsf', null, [])
74
+ else form.update('vjsf', false, [])
75
+ }
76
+ }
77
+ /**
78
+ * @param {any} data
79
+ */
80
+ const onDataUpdate = (data) => {
81
+ debug('onDataUpdate', data)
82
+ debug(' -> emit update:modelValue')
83
+ emit('update:modelValue', data)
84
+ }
85
+ const onAutofocus = () => {
86
+ if (!el.value) return
87
+ // @ts-ignore
88
+ const autofocusNodeElement = el.value.querySelector('.vjsf-input--autofocus')
89
+ debug('onAutofocus', autofocusNodeElement)
90
+ if (autofocusNodeElement) {
91
+ const autofocusInputElement = autofocusNodeElement.querySelector('input') ?? autofocusNodeElement.querySelector('textarea:not([style*="display: none"]')
92
+ if (autofocusInputElement) autofocusInputElement.focus()
93
+ }
94
+ }
95
+
96
+ const fullOptions = computed(() => getFullOptions(options.value, form, width.value, slots, { ...nodeComponents }, onDataUpdate, onStatefulLayoutUpdate, onAutofocus))
97
+
98
+ // do not use a simple computed here as we want to prevent recompiling the layout when the options are the same
99
+ /** @type {import('vue').Ref<import('@json-layout/core').PartialCompileOptions>} */
100
+ const compileOptions = ref({})
101
+ watch(fullOptions, (newOptions) => {
102
+ if (precompiledLayout?.value) return
103
+ const newCompileOptions = produceCompileOptions(compileOptions.value, newOptions)
104
+ if (newCompileOptions !== compileOptions.value) {
105
+ debug('new compileOptions', newCompileOptions)
106
+ compileOptions.value = newCompileOptions
107
+ }
108
+ }, { immediate: true })
53
109
 
54
110
  const compiledLayout = computed(() => {
55
111
  if (precompiledLayout?.value) return precompiledLayout?.value
56
112
  if (!compile) throw new Error('compile function is not available')
57
- const compiledLayout = compile(schema.value, fullOptions.value)
113
+ const compiledLayout = compile(schema.value, compileOptions.value)
58
114
  return compiledLayout
59
115
  })
60
116
 
61
- const onStatefulLayoutUpdate = () => {
62
- if (!statefulLayout.value) return
63
- stateTree.value = statefulLayout.value.stateTree
64
- emit('update:modelValue', statefulLayout.value.data)
65
- emit('update:state', statefulLayout.value)
66
- if (form) {
67
- // cf https://vuetifyjs.com/en/components/forms/#validation-state
68
- if (statefulLayout.value.valid) form.update('vjsf', true, [])
69
- else if (statefulLayout.value.hasHiddenError) form.update('vjsf', null, [])
70
- else form.update('vjsf', false, [])
71
- }
72
- }
73
-
74
117
  const initStatefulLayout = () => {
75
118
  if (!width.value) return
76
119
  // @ts-ignore
77
- const _statefulLayout = /** @type {import('../types.js').VjsfStatefulLayout} */(new StatefulLayout(
120
+ statefulLayout.value = /** @type {import('../types.js').VjsfStatefulLayout} */(new StatefulLayout(
78
121
  toRaw(compiledLayout.value),
79
- toRaw(compiledLayout.value.skeletonTree),
122
+ toRaw(compiledLayout.value.skeletonTrees[compiledLayout.value.mainTree]),
80
123
  toRaw(fullOptions.value),
81
124
  toRaw(modelValue.value)
82
125
  ))
83
- statefulLayout.value = _statefulLayout
84
- onStatefulLayoutUpdate()
85
- _statefulLayout.events.on('update', () => {
86
- onStatefulLayoutUpdate()
87
- })
88
- emit('update:state', _statefulLayout)
89
- _statefulLayout.events.on('autofocus', () => {
90
- if (!el.value) return
91
- // @ts-ignore
92
- const autofocusNodeElement = el.value.querySelector('.vjsf-input--autofocus')
93
- if (autofocusNodeElement) {
94
- const autofocusInputElement = autofocusNodeElement.querySelector('input') ?? autofocusNodeElement.querySelector('textarea:not([style*="display: none"]')
95
- if (autofocusInputElement) autofocusInputElement.focus()
96
- }
97
- })
98
126
  }
99
127
 
128
+ // case where options are updated from outside
100
129
  watch(fullOptions, (newOptions) => {
101
- // in case of runtime compilation the watch on compiledLayout will be triggered
102
- if (!precompiledLayout?.value) return
103
-
130
+ debug('watch fullOptions', fullOptions)
104
131
  if (statefulLayout.value) {
105
- statefulLayout.value.options = newOptions
132
+ debug(' -> update statefulLayout options')
133
+ statefulLayout.value.options = toRaw(newOptions)
106
134
  } else {
135
+ debug(' -> init statefulLayout')
107
136
  initStatefulLayout()
108
137
  }
109
138
  })
110
139
 
111
140
  // case where data is updated from outside
112
141
  watch(modelValue, (newData) => {
113
- if (statefulLayout.value && statefulLayout.value.data !== newData) statefulLayout.value.data = toRaw(newData)
142
+ const rawData = toRaw(newData)
143
+ if (statefulLayout.value && statefulLayout.value.data !== rawData) {
144
+ debug('modelValue changed from outside', rawData)
145
+ debug(' -> update statefulLayout data')
146
+ statefulLayout.value.data = toRaw(rawData)
147
+ }
114
148
  })
115
149
 
116
- // case where schema is updated from outside
150
+ // case where schema or compile options are updated from outside
117
151
  watch(compiledLayout, (newCompiledLayout) => {
152
+ debug('watch compiledLayout', newCompiledLayout)
153
+ debug(' -> init statefulLayout')
118
154
  initStatefulLayout()
119
155
  })
120
156
 
package/src/index.js CHANGED
@@ -2,3 +2,6 @@ import Vjsf from './components/vjsf.vue'
2
2
  import { defaultOptions } from './components/options.js'
3
3
  export { Vjsf, defaultOptions }
4
4
  export default Vjsf
5
+
6
+ /** @typedef {import('./types.js').PartialVjsfOptions} Options */
7
+ /** @typedef {import('./types.js').PartialVjsfCompileOptions} CompileOptions */
package/src/types.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { Component } from 'vue'
2
2
 
3
+ import { ComponentInfo } from '@json-layout/vocabulary'
4
+
3
5
  import {
4
6
  StatefulLayout,
5
7
  StatefulLayoutOptions,
@@ -15,6 +17,9 @@ import {
15
17
  OneOfSelectNode,
16
18
  SectionNode,
17
19
  SelectNode,
20
+ RadioGroupNode,
21
+ CheckboxGroupNode,
22
+ SwitchGroupNode,
18
23
  SliderNode,
19
24
  SwitchNode,
20
25
  TextFieldNode,
@@ -22,32 +27,38 @@ import {
22
27
  VerticalTabsNode,
23
28
  StepperNode,
24
29
  ComboboxNode,
25
- MarkdownNode,
26
30
  FileInputNode,
31
+ CardNode,
27
32
  CompileOptions
28
33
  } from '@json-layout/core'
29
34
 
30
35
  export type Density = 'default' | 'comfortable' | 'compact'
31
36
 
37
+ export type Plugin = {
38
+ info: ComponentInfo,
39
+ nodeComponent: Component
40
+ }
41
+
32
42
  // these options used to contain many possibilities to override props in various components
33
43
  // this was unmaintainable and has been removed, customization of components should be done via slots
34
- // and vuetify defaults providers
44
+ // and defaults providers
35
45
  export type VjsfStatefulLayoutOptions = StatefulLayoutOptions & {
36
46
  vjsfSlots: Record<string, () => unknown>,
37
47
  nodeComponents: Record<string, Component>,
38
- plugins: Record<string, unknown>
48
+ plugins: Plugin[],
49
+ pluginsOptions: Record<string, unknown>
39
50
  }
40
51
 
41
52
  export type VjsfCompileOptions = CompileOptions & {
42
- nodeComponentImports: Record<string, string>
53
+ pluginsImports: string[]
43
54
  }
44
55
 
45
56
  export type VjsfOptions = VjsfCompileOptions & VjsfStatefulLayoutOptions
46
57
 
47
58
  export type VjsfStatefulLayout = Omit<StatefulLayout, 'options'> & {options: VjsfStatefulLayoutOptions}
48
59
 
49
- export type PartialVjsfCompileOptions = Partial<Omit<VjsfCompileOptions, 'width'>>
50
- export type PartialVjsfOptions = Partial<Omit<VjsfOptions, 'width'>>
60
+ export type PartialVjsfCompileOptions = Partial<VjsfCompileOptions>
61
+ export type PartialVjsfOptions = Partial<Omit<VjsfOptions, 'width' | 'vjsfSlots' | 'onData' | 'onUpdate' | 'onAutofocus'>>
51
62
 
52
63
  export type VjsfNode = Omit<StateNode, 'options'> & {options: VjsfOptions}
53
64
  export type VjsfTabsNode = Omit<TabsNode, 'options'> & {options: VjsfOptions}
@@ -61,12 +72,15 @@ export type VjsfNumberFieldNode = Omit<NumberFieldNode, 'options'> & {options: V
61
72
  export type VjsfOneOfSelectNode = Omit<OneOfSelectNode, 'options'> & {options: VjsfOptions}
62
73
  export type VjsfSectionNode = Omit<SectionNode, 'options'> & {options: VjsfOptions}
63
74
  export type VjsfSelectNode = Omit<SelectNode, 'options'> & {options: VjsfOptions}
75
+ export type VjsfRadioGroupNode = Omit<RadioGroupNode, 'options'> & {options: VjsfOptions}
76
+ export type VjsfCheckboxGroupNode = Omit<CheckboxGroupNode, 'options'> & {options: VjsfOptions}
77
+ export type VjsfSwitchGroupNode = Omit<SwitchGroupNode, 'options'> & {options: VjsfOptions}
64
78
  export type VjsfSliderNode = Omit<SliderNode, 'options'> & {options: VjsfOptions}
65
79
  export type VjsfSwitchNode = Omit<SwitchNode, 'options'> & {options: VjsfOptions}
66
80
  export type VjsfTextFieldNode = Omit<TextFieldNode, 'options'> & {options: VjsfOptions}
67
81
  export type VjsfTextareaNode = Omit<TextareaNode, 'options'> & {options: VjsfOptions}
68
- export type VjsfMarkdownNode = Omit<MarkdownNode, 'options'> & {options: VjsfOptions}
69
82
  export type VjsfVerticalTabsNode = Omit<VerticalTabsNode, 'options'> & {options: VjsfOptions}
70
83
  export type VjsfStepperNode = Omit<StepperNode, 'options'> & {options: VjsfOptions}
71
84
  export type VjsfComboboxNode = Omit<ComboboxNode, 'options'> & {options: VjsfOptions}
72
85
  export type VjsfFileInputNode = Omit<FileInputNode, 'options'> & {options: VjsfOptions}
86
+ export type VjsfCardNode = Omit<CardNode, 'options'> & {options: VjsfOptions}
@@ -1,15 +1,46 @@
1
1
  /**
2
- * @template T
3
- * @param {T[]} array
2
+ * @param {any[] | Record<string, any>} data
4
3
  * @param {number} fromIndex
5
4
  * @param {number} toIndex
6
- * @return {T[]}
5
+ * @return {any[] | Record<string, any>}
7
6
  */
8
- export function moveArrayItem (array, fromIndex, toIndex) {
9
- if (fromIndex === toIndex || fromIndex === -1 || toIndex === -1) return array
10
- const newArray = [...array]
7
+ export function moveDataItem (data, fromIndex, toIndex) {
8
+ if (fromIndex === toIndex || fromIndex === -1 || toIndex === -1) return data
9
+ if (!Array.isArray(data) && typeof data === 'object') return moveObjectItem(data, fromIndex, toIndex)
10
+ return moveArrayItem(data, fromIndex, toIndex)
11
+ }
12
+
13
+ /**
14
+ * @param {any[]} data
15
+ * @param {number} fromIndex
16
+ * @param {number} toIndex
17
+ * @return {any[]}
18
+ */
19
+ export function moveArrayItem (data, fromIndex, toIndex) {
20
+ if (fromIndex === toIndex || fromIndex === -1 || toIndex === -1) return data
21
+ // @ts-ignore
22
+ if (!Array.isArray(data) && typeof data === 'object') return moveObjectItem(data, fromIndex, toIndex)
23
+ const newArray = [...data]
11
24
  const element = newArray[fromIndex]
12
25
  newArray.splice(fromIndex, 1)
13
26
  newArray.splice(toIndex, 0, element)
14
27
  return newArray
15
28
  }
29
+
30
+ /**
31
+ * @param {Record<string, any>} data
32
+ * @param {number} fromIndex
33
+ * @param {number} toIndex
34
+ * @return {Record<string, any>}
35
+ */
36
+ export function moveObjectItem (data, fromIndex, toIndex) {
37
+ if (fromIndex === toIndex || fromIndex === -1 || toIndex === -1) return data
38
+ const newKeys = /** @type {string[] } */(moveArrayItem(Object.keys(data), fromIndex, toIndex))
39
+ /** @type {Record<string, any>} */
40
+ const newData = {}
41
+ for (const key of newKeys) {
42
+ newData[key] = data[key]
43
+ }
44
+ console.log(newData)
45
+ return newData
46
+ }
@@ -1 +1 @@
1
- export { commonjsDeps } from '@json-layout/core/utils/build'
1
+ export { commonjsDeps, commonjsDepsPaths } from '@json-layout/core/utils/build'
@@ -2,4 +2,3 @@ export * from './arrays.js'
2
2
  export * from './dates.js'
3
3
  export * from './props.js'
4
4
  export * from './slots.js'
5
- export * from './global-register.js'
@@ -6,12 +6,8 @@ import { camelize } from 'vue'
6
6
  // by a combination of layout.props, layout.getProps and vuetify defaults provider (https://vuetifyjs.com/en/components/defaults-providers/#usage)
7
7
  const defaultProps = {
8
8
  fieldPropsCompact: {
9
- density: 'compact',
10
9
  hideDetails: 'auto'
11
10
  },
12
- fieldPropsComfortable: {
13
- density: 'comfortable'
14
- },
15
11
  fieldPropsReadOnly: { hideDetails: 'auto', variant: 'plain' },
16
12
  fieldPropsSummary: { hideDetails: true }
17
13
  }
@@ -54,7 +50,6 @@ export function getInputProps (node, statefulLayout, layoutPropsMap, isMainComp
54
50
  const options = node.options
55
51
  /** @type {(Record<string, any> | undefined)[]} */
56
52
  const propsLevels = []
57
- if (options.density === 'comfortable') propsLevels.push(defaultProps.fieldPropsComfortable)
58
53
  if (options.density === 'compact') propsLevels.push(defaultProps.fieldPropsCompact)
59
54
  if (node.options.readOnly) propsLevels.push(defaultProps.fieldPropsReadOnly)
60
55
  if (isMainComp && node.props) propsLevels.push(node.props)
@@ -65,7 +60,7 @@ export function getInputProps (node, statefulLayout, layoutPropsMap, isMainComp
65
60
  if (node.error && node.validated) {
66
61
  fullProps.errorMessages = node.error
67
62
  }
68
- fullProps.modelValue = node.data
63
+ fullProps.modelValue = (typeof node.data === 'string' && node.layout.separator) ? node.data.split(/** @type {string} */(node.layout.separator)) : node.data
69
64
  if (node.options.readOnly) {
70
65
  fullProps.disabled = true
71
66
  fullProps.class.push('vjsf-input--readonly')
@@ -82,7 +77,9 @@ export function getInputProps (node, statefulLayout, layoutPropsMap, isMainComp
82
77
  }
83
78
 
84
79
  if (isMainComp) {
85
- fullProps['onUpdate:modelValue'] = (/** @type string */value) => statefulLayout.input(node, value)
80
+ fullProps['onUpdate:modelValue'] = (/** @type string */value) => {
81
+ return statefulLayout.input(node, (Array.isArray(value) && node.layout.separator) ? value.join(/** @type {string} */(node.layout.separator)) : value)
82
+ }
86
83
  fullProps.onBlur = () => statefulLayout.blur(node)
87
84
  }
88
85
 
@@ -92,18 +89,45 @@ export function getInputProps (node, statefulLayout, layoutPropsMap, isMainComp
92
89
  // calculate the props of components that are not of the field category
93
90
  /**
94
91
  * @param {import('@json-layout/core').StateNode} node
95
- * @param {string} comp
96
92
  * @param {boolean} isMainComp
97
93
  * @returns {Record<string, any>}
98
94
  */
99
- export function getCompProps (node, comp, isMainComp = true) {
95
+ export function getCompProps (node, isMainComp = true) {
100
96
  const options = /** @type import('../types.js').VjsfOptions */(node.options)
101
97
  /** @type {(Record<string, any> | undefined)[]} */
102
98
  const propsLevels = [{ density: options.density }]
103
- propsLevels.push(/** @type Record<string, any> | undefined */(options[`${comp}Props`]))
104
- if (node.options.readOnly) propsLevels.push(/** @type Record<string, any> | undefined */(options[`${comp}PropsReadOnly`]))
105
99
  if (isMainComp) propsLevels.push(node.layout.props)
106
100
  const fullProps = mergePropsLevels(propsLevels)
107
- if (isMainComp) fullProps.modelValue = node.data
101
+ return fullProps
102
+ }
103
+
104
+ /**
105
+ * shared between select and autocomplete components
106
+ * @param {import('../types.js').VjsfNode} node
107
+ * @param {import('../types.js').VjsfStatefulLayout} statefulLayout
108
+ * @returns {Record<string, any>}
109
+ */
110
+ export function getSelectProps (node, statefulLayout) {
111
+ const fullProps = getInputProps(node, statefulLayout, ['multiple'], false)
112
+ if (node.options.readOnly) fullProps.menuProps = { modelValue: false }
113
+ fullProps.clearable = fullProps.clearable ?? !node.skeleton.required
114
+ fullProps.valueComparator = (/** @type {any} */a, /** @type {any} */b) => {
115
+ const aKey = typeof a === 'object' ? statefulLayout.prepareSelectItem(node, a).key : a
116
+ const bKey = typeof b === 'object' ? statefulLayout.prepareSelectItem(node, b).key : b
117
+ return aKey === bKey
118
+ }
119
+ fullProps['onUpdate:modelValue'] = (/** @type string */value) => {
120
+ // fix some weird case where vuetify only keep the title property of an unknown item
121
+ if (Array.isArray(value) && Array.isArray(node.data)) {
122
+ for (let i = 0; i < node.data.length; i++) {
123
+ if (typeof node.data[i] === 'object' && typeof value[i] === 'string') {
124
+ value[i] = node.data[i]
125
+ }
126
+ }
127
+ }
128
+
129
+ return statefulLayout.input(node, (Array.isArray(value) && node.layout.separator) ? value.join(/** @type {string} */(node.layout.separator)) : value)
130
+ }
131
+ fullProps.onBlur = () => statefulLayout.blur(node)
108
132
  return fullProps
109
133
  }
@@ -1,5 +1,7 @@
1
1
  import { h } from 'vue'
2
2
  import NodeSlot from '../components/fragments/node-slot.vue'
3
+ import SelectItem from '../components/fragments/select-item.vue'
4
+ import SelectSelection from '../components/fragments/select-selection.vue'
3
5
 
4
6
  // calculate the slots of components
5
7
  /**
@@ -16,3 +18,29 @@ export function getCompSlots (node, statefulLayout) {
16
18
  }
17
19
  return slots
18
20
  }
21
+
22
+ /**
23
+ * shared between select and autocomplete components
24
+ * @param {import('../types.js').VjsfSelectNode} node
25
+ * @param {import('../types.js').VjsfStatefulLayout} statefulLayout
26
+ * @param {any} getItems
27
+ * @returns {Record<string, any>}
28
+ */
29
+ export function getSelectSlots (node, statefulLayout, getItems) {
30
+ const slots = getCompSlots(node, statefulLayout)
31
+ if (!slots.item) {
32
+ slots.item = (/** @type {any} */ context) => h(SelectItem, {
33
+ multiple: node.layout.multiple,
34
+ itemProps: context.props,
35
+ item: context.item.raw
36
+ })
37
+ }
38
+ if (!slots.selection) {
39
+ slots.selection = (/** @type {any} */ context) => h(SelectSelection, {
40
+ multiple: node.layout.multiple,
41
+ last: node.layout.multiple && context.index === node.data.length - 1,
42
+ item: getItems.prepareSelectedItem(context.item.raw, context.item.value)
43
+ })
44
+ }
45
+ return slots
46
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ *
3
+ * @param {object} _schema
4
+ * @param {import("ajv").default} [_ajv]
5
+ * @param {string} lang
6
+ * @returns
7
+ */
8
+ export function v2compat(_schema: object, _ajv?: ajvModule.default | undefined, lang?: string): ajvModule.SchemaObject;
9
+ import ajvModule from 'ajv';
10
+ //# sourceMappingURL=v2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2.d.ts","sourceRoot":"","sources":["../../src/compat/v2.js"],"names":[],"mappings":"AAqMA;;;;;;GAMG;AACH,kCALW,MAAM,+CAEN,MAAM,0BAoBhB;sBA7NqB,KAAK"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @param {object} schema
3
+ * @param {import('../types.js').PartialVjsfCompileOptions} [options]
4
+ * @param {string} [baseImport]
5
+ * @returns {Promise<string>}
6
+ */
7
+ export function compile(schema: object, options?: Partial<import("../types.js").VjsfCompileOptions> | undefined, baseImport?: string | undefined): Promise<string>;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compile/index.js"],"names":[],"mappings":"AAmCA;;;;;GAKG;AACH,gCALW,MAAM,6GAGJ,QAAQ,MAAM,CAAC,CAuC3B"}
@@ -0,0 +1,4 @@
1
+ /** @type import("../types.js").PartialVjsfCompileOptions */
2
+ export const defaultOptions: import("../types.js").PartialVjsfCompileOptions;
3
+ export function getFullOptions(options: import("../types.js").PartialVjsfCompileOptions): import("../types.js").VjsfCompileOptions;
4
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/compile/options.js"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,6BADU,OAAO,aAAa,EAAE,yBAAyB,CAIxD;AAOM,wCAHI,OAAO,aAAa,EAAE,yBAAyB,4CAMzD"}
@@ -0,0 +1,8 @@
1
+ declare const _default: import("vue").DefineComponent<{}, {
2
+ modelValue: import("../../../../node_modules/@json-layout/core/types/state/types.js").StateNode;
3
+ $props: {
4
+ modelValue?: import("../../../../node_modules/@json-layout/core/types/state/types.js").StateNode | undefined;
5
+ };
6
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
7
+ export default _default;
8
+ //# sourceMappingURL=child-subtitle.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-subtitle.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fragments/child-subtitle.vue.js"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ declare const _default: import("vue").DefineComponent<{}, {
2
+ node: import("../../types.js").VjsfNode;
3
+ $props: {
4
+ readonly node?: import("../../types.js").VjsfNode | undefined;
5
+ };
6
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
7
+ export default _default;
8
+ //# sourceMappingURL=help-message.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-message.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fragments/help-message.vue.js"],"names":[],"mappings":""}
@@ -0,0 +1,47 @@
1
+ declare const _default: import("vue").DefineComponent<{
2
+ layoutSlot: {
3
+ /** @type import('vue').PropType<import('@json-layout/vocabulary').Slot> */
4
+ type: import('vue').PropType<import('@json-layout/vocabulary').Slot>;
5
+ required: true;
6
+ };
7
+ node: {
8
+ /** @type import('vue').PropType<import('../../types.js').VjsfNode> */
9
+ type: import('vue').PropType<import('../../types.js').VjsfNode>;
10
+ required: true;
11
+ };
12
+ statefulLayout: {
13
+ /** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
14
+ type: import('vue').PropType<import('../../types.js').VjsfStatefulLayout>;
15
+ required: true;
16
+ };
17
+ tag: {
18
+ /** @type import('vue').PropType<string> */
19
+ type: import('vue').PropType<string>;
20
+ default: null;
21
+ };
22
+ }, any, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
23
+ layoutSlot: {
24
+ /** @type import('vue').PropType<import('@json-layout/vocabulary').Slot> */
25
+ type: import('vue').PropType<import('@json-layout/vocabulary').Slot>;
26
+ required: true;
27
+ };
28
+ node: {
29
+ /** @type import('vue').PropType<import('../../types.js').VjsfNode> */
30
+ type: import('vue').PropType<import('../../types.js').VjsfNode>;
31
+ required: true;
32
+ };
33
+ statefulLayout: {
34
+ /** @type import('vue').PropType<import('../../types.js').VjsfStatefulLayout> */
35
+ type: import('vue').PropType<import('../../types.js').VjsfStatefulLayout>;
36
+ required: true;
37
+ };
38
+ tag: {
39
+ /** @type import('vue').PropType<string> */
40
+ type: import('vue').PropType<string>;
41
+ default: null;
42
+ };
43
+ }>>, {
44
+ tag: string;
45
+ }, {}>;
46
+ export default _default;
47
+ //# sourceMappingURL=node-slot.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-slot.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fragments/node-slot.vue.js"],"names":[],"mappings":";;QAUM,2EAA2E;cAAjE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,yBAAyB,EAAE,IAAI,CAAC;;;;QAKxE,sEAAsE;cAA5D,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,gBAAgB,EAAE,QAAQ,CAAC;;;;QAKnE,gFAAgF;cAAtE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,gBAAgB,EAAE,kBAAkB,CAAC;;;;QAK7E,2CAA2C;cAAjC,OAAO,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC;;;;;QAfxC,2EAA2E;cAAjE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,yBAAyB,EAAE,IAAI,CAAC;;;;QAKxE,sEAAsE;cAA5D,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,gBAAgB,EAAE,QAAQ,CAAC;;;;QAKnE,gFAAgF;cAAtE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,gBAAgB,EAAE,kBAAkB,CAAC;;;;QAK7E,2CAA2C;cAAjC,OAAO,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC"}
@@ -0,0 +1,10 @@
1
+ declare const _default: import("vue").DefineComponent<{}, {
2
+ node: import("../../types.js").VjsfNode;
3
+ hideTitle: boolean;
4
+ $props: {
5
+ readonly node?: import("../../types.js").VjsfNode | undefined;
6
+ readonly hideTitle?: boolean | undefined;
7
+ };
8
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
9
+ export default _default;
10
+ //# sourceMappingURL=section-header.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-header.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fragments/section-header.vue.js"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ declare const _default: import("vue").DefineComponent<{
2
+ icon: {
3
+ type: StringConstructor;
4
+ required: true;
5
+ };
6
+ }, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
7
+ [key: string]: any;
8
+ }>, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
9
+ icon: {
10
+ type: StringConstructor;
11
+ required: true;
12
+ };
13
+ }>>, {}, {}>;
14
+ export default _default;
15
+ //# sourceMappingURL=select-item-icon.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-item-icon.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fragments/select-item-icon.vue.js"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ declare const _default: import("vue").DefineComponent<{}, {
2
+ multiple: boolean;
3
+ itemProps: Record<string, any>;
4
+ item: import("../../../../node_modules/@json-layout/vocabulary/types/normalized-layout/types.js").SelectItem;
5
+ $props: {
6
+ readonly multiple?: boolean | undefined;
7
+ readonly itemProps?: Record<string, any> | undefined;
8
+ readonly item?: import("../../../../node_modules/@json-layout/vocabulary/types/normalized-layout/types.js").SelectItem | undefined;
9
+ };
10
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
11
+ export default _default;
12
+ //# sourceMappingURL=select-item.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-item.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fragments/select-item.vue.js"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ declare const _default: import("vue").DefineComponent<{}, {
2
+ multiple: boolean;
3
+ item: import("../../../../node_modules/@json-layout/vocabulary/types/normalized-layout/types.js").SelectItem;
4
+ last: boolean;
5
+ $props: {
6
+ readonly multiple?: boolean | undefined;
7
+ readonly item?: import("../../../../node_modules/@json-layout/vocabulary/types/normalized-layout/types.js").SelectItem | undefined;
8
+ readonly last?: boolean | undefined;
9
+ };
10
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
11
+ export default _default;
12
+ //# sourceMappingURL=select-selection.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-selection.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fragments/select-selection.vue.js"],"names":[],"mappings":""}