@koumoul/vjsf 3.0.0-alpha.3 → 3.0.0-alpha.4
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.
- package/package.json +2 -2
- package/src/components/fragments/help-message.vue +1 -1
- package/src/components/node.vue +15 -2
- package/src/components/nodes/autocomplete.vue +0 -6
- package/src/components/nodes/expansion-panels.vue +1 -1
- package/src/components/nodes/list.vue +10 -7
- package/src/components/nodes/markdown.vue +115 -16
- package/src/components/nodes/one-of-select.vue +1 -1
- package/src/components/nodes/section.vue +1 -0
- package/src/components/nodes/stepper.vue +1 -1
- package/src/components/nodes/tabs.vue +1 -1
- package/src/components/nodes/text-field.vue +6 -0
- package/src/components/nodes/textarea.vue +23 -2
- package/src/components/nodes/vertical-tabs.vue +1 -1
- package/src/composables/use-dnd.js +15 -0
- package/src/composables/use-vjsf.js +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koumoul/vjsf",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.4",
|
|
4
4
|
"description": "Generate forms for the vuetify UI library (vuejs) based on annotated JSON schemas.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "vitest",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"vuetify": "^3.4.2"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@json-layout/core": "0.
|
|
55
|
+
"@json-layout/core": "0.5.0",
|
|
56
56
|
"@vueuse/core": "^10.5.0",
|
|
57
57
|
"debug": "^4.3.4",
|
|
58
58
|
"easymde": "^2.18.0",
|
package/src/components/node.vue
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { useTheme } from 'vuetify'
|
|
2
4
|
import { VCol } from 'vuetify/components'
|
|
3
5
|
import NodeSlot from './fragments/node-slot.vue'
|
|
4
6
|
import HelpMessage from './fragments/help-message.vue'
|
|
5
7
|
|
|
6
|
-
defineProps({
|
|
8
|
+
const props = defineProps({
|
|
7
9
|
modelValue: {
|
|
8
10
|
/** @type import('vue').PropType<import('./types.js').VjsfNode> */
|
|
9
11
|
type: Object,
|
|
@@ -22,12 +24,23 @@ const beforeAfterClasses = {
|
|
|
22
24
|
comfortable: 'my-2',
|
|
23
25
|
default: 'my-3'
|
|
24
26
|
}
|
|
27
|
+
|
|
28
|
+
const theme = useTheme()
|
|
29
|
+
|
|
30
|
+
const nodeClasses = computed(() => {
|
|
31
|
+
let classes = `vjsf-node vjsf-node-${props.modelValue.layout.comp} vjsf-density-${props.modelValue.options.density}`
|
|
32
|
+
if (props.modelValue.options.readOnly) classes += ' vjsf-readonly'
|
|
33
|
+
if (props.modelValue.options.summary) classes += ' vjsf-summary'
|
|
34
|
+
if (theme.current.value.dark) classes += ' vjsf-dark'
|
|
35
|
+
return classes
|
|
36
|
+
})
|
|
37
|
+
|
|
25
38
|
</script>
|
|
26
39
|
|
|
27
40
|
<template>
|
|
28
41
|
<v-col
|
|
29
42
|
:cols="modelValue.cols"
|
|
30
|
-
:class="
|
|
43
|
+
:class="nodeClasses"
|
|
31
44
|
>
|
|
32
45
|
<node-slot
|
|
33
46
|
v-if="modelValue.layout.slots?.before"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { VExpansionPanels, VExpansionPanel, VExpansionPanelTitle, VContainer } from 'vuetify/components'
|
|
2
|
+
import { VExpansionPanels, VExpansionPanel, VExpansionPanelTitle, 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'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { watch, computed, ref } from 'vue'
|
|
3
|
-
import { VList, VListItem, VListItemAction, VBtn, VMenu, VIcon } from 'vuetify/components'
|
|
3
|
+
import { VList, VListItem, VListItemAction, VBtn, VMenu, VIcon, VSheet, VSpacer, VDivider, VRow, VListSubheader } from 'vuetify/components'
|
|
4
4
|
import { isSection, clone } from '@json-layout/core'
|
|
5
5
|
import Node from '../node.vue'
|
|
6
6
|
import { moveArrayItem } from '../../utils/arrays.js'
|
|
@@ -20,7 +20,7 @@ const props = defineProps({
|
|
|
20
20
|
})
|
|
21
21
|
|
|
22
22
|
/* use composable for drag and drop */
|
|
23
|
-
const { activeDnd, sortableArray, draggable, itemBind, handleBind } = useDnd(props.modelValue.children, () => {
|
|
23
|
+
const { activeDnd, sortableArray, draggable, hovered, dragging, itemBind, handleBind } = useDnd(props.modelValue.children, () => {
|
|
24
24
|
props.statefulLayout.input(props.modelValue, sortableArray.value.map((child) => child.data))
|
|
25
25
|
})
|
|
26
26
|
watch(() => props.modelValue.children, (array) => { sortableArray.value = array })
|
|
@@ -29,7 +29,7 @@ watch(() => props.modelValue.children, (array) => { sortableArray.value = array
|
|
|
29
29
|
const editedItem = computed(() => {
|
|
30
30
|
return props.statefulLayout.activeItems[props.modelValue.fullKey]
|
|
31
31
|
})
|
|
32
|
-
const
|
|
32
|
+
const menuOpened = ref(-1)
|
|
33
33
|
const activeItem = computed(() => {
|
|
34
34
|
if (
|
|
35
35
|
props.modelValue.layout.listActions.includes('edit') &&
|
|
@@ -38,7 +38,9 @@ const activeItem = computed(() => {
|
|
|
38
38
|
) {
|
|
39
39
|
return editedItem.value
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
if (dragging.value !== -1) return -1
|
|
42
|
+
if (menuOpened.value !== -1) return menuOpened.value
|
|
43
|
+
return hovered.value
|
|
42
44
|
})
|
|
43
45
|
|
|
44
46
|
const buttonDensity = computed(() => {
|
|
@@ -64,8 +66,6 @@ const buttonDensity = computed(() => {
|
|
|
64
66
|
:draggable="draggable === childIndex"
|
|
65
67
|
:variant="editedItem === childIndex ? 'outlined' : 'flat'"
|
|
66
68
|
class="pa-1 vjsf-list-item"
|
|
67
|
-
@mouseenter="hoveredItem = childIndex"
|
|
68
|
-
@mouseleave="hoveredItem = -1"
|
|
69
69
|
>
|
|
70
70
|
<v-row class="ma-0">
|
|
71
71
|
<node
|
|
@@ -116,7 +116,10 @@ const buttonDensity = computed(() => {
|
|
|
116
116
|
<v-list-item-action
|
|
117
117
|
v-if="editedItem === undefined && (modelValue.layout.listActions.includes('delete') || modelValue.layout.listActions.includes('duplicate') || modelValue.layout.listActions.includes('sort'))"
|
|
118
118
|
>
|
|
119
|
-
<v-menu
|
|
119
|
+
<v-menu
|
|
120
|
+
location="bottom end"
|
|
121
|
+
@update:model-value="value => {menuOpened = value ? childIndex : -1}"
|
|
122
|
+
>
|
|
120
123
|
<template #activator="{props: activatorProps}">
|
|
121
124
|
<v-btn
|
|
122
125
|
v-bind="activatorProps"
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { defineComponent, h, computed, onMounted, ref, onUnmounted, watch } from 'vue'
|
|
3
|
+
import { useTheme } from 'vuetify'
|
|
3
4
|
import { VInput, VLabel } from 'vuetify/components'
|
|
5
|
+
import { marked } from 'marked'
|
|
4
6
|
import { getInputProps } from '../../utils/props.js'
|
|
5
7
|
import { getCompSlots } from '../../utils/slots.js'
|
|
6
8
|
import 'easymde/dist/easymde.min.css'
|
|
@@ -18,26 +20,42 @@ export default defineComponent({
|
|
|
18
20
|
required: true
|
|
19
21
|
}
|
|
20
22
|
},
|
|
21
|
-
setup (props) {
|
|
23
|
+
setup (props, { expose }) {
|
|
22
24
|
/** @type {import('vue').Ref<null | HTMLElement>} */
|
|
23
25
|
const element = ref(null)
|
|
24
26
|
|
|
27
|
+
const renderedValue = computed(() => {
|
|
28
|
+
return props.modelValue.data && marked.parse(props.modelValue.data)
|
|
29
|
+
})
|
|
30
|
+
|
|
25
31
|
const fieldProps = computed(() => getInputProps(props.modelValue, props.statefulLayout))
|
|
26
32
|
const fieldSlots = computed(() => {
|
|
27
33
|
const fieldSlots = getCompSlots(props.modelValue, props.statefulLayout)
|
|
28
|
-
fieldSlots.default = () =>
|
|
29
|
-
|
|
34
|
+
fieldSlots.default = () => {
|
|
35
|
+
const children = [
|
|
30
36
|
h(VLabel, { text: fieldProps.value.label }),
|
|
31
|
-
h('textarea', { ref: element
|
|
32
|
-
]
|
|
33
|
-
|
|
37
|
+
h('textarea', { ref: element })
|
|
38
|
+
]
|
|
39
|
+
if (props.modelValue.options.summary) {
|
|
40
|
+
children.push(h('div', { innerHTML: renderedValue.value }))
|
|
41
|
+
}
|
|
42
|
+
return h('div', { class: 'vjsf-node-markdown-content' }, children)
|
|
43
|
+
}
|
|
34
44
|
return fieldSlots
|
|
35
45
|
})
|
|
36
46
|
|
|
47
|
+
/** @type {ReturnType<typeof setTimeout> | null} */
|
|
48
|
+
let blurTimeout = null
|
|
49
|
+
|
|
37
50
|
/** @type {EasyMDE | null} */
|
|
38
51
|
let easymde = null
|
|
39
52
|
|
|
40
53
|
const initEasyMDE = async () => {
|
|
54
|
+
if (easymde) {
|
|
55
|
+
easymde.toTextArea()
|
|
56
|
+
easymde = null
|
|
57
|
+
}
|
|
58
|
+
if (props.modelValue.options.readOnly) return
|
|
41
59
|
if (!element.value) throw new Error('component was not mounted for markdown editor')
|
|
42
60
|
|
|
43
61
|
const EasyMDE = (await import('easymde')).default
|
|
@@ -158,12 +176,9 @@ export default defineComponent({
|
|
|
158
176
|
className: 'mdi mdi-help-circle text-success',
|
|
159
177
|
title: messages.mdeGuide,
|
|
160
178
|
noDisable: true
|
|
161
|
-
}
|
|
162
|
-
],
|
|
179
|
+
}],
|
|
163
180
|
...props.modelValue.options.easyMDEOptions
|
|
164
181
|
}
|
|
165
|
-
|
|
166
|
-
if (easymde) easymde.toTextArea()
|
|
167
182
|
// @ts-ignore
|
|
168
183
|
easymde = new EasyMDE(config)
|
|
169
184
|
|
|
@@ -172,9 +187,8 @@ export default defineComponent({
|
|
|
172
187
|
changed = true
|
|
173
188
|
if (easymde) props.statefulLayout.input(props.modelValue, easymde.value())
|
|
174
189
|
})
|
|
175
|
-
/** @type {ReturnType<typeof setTimeout> | null} */
|
|
176
|
-
let blurTimeout = null
|
|
177
190
|
easymde.codemirror.on('blur', () => {
|
|
191
|
+
console.log('onblur')
|
|
178
192
|
// timeout to prevent triggering save when clicking on a menu button
|
|
179
193
|
blurTimeout = setTimeout(() => {
|
|
180
194
|
if (changed) props.statefulLayout.blur(props.modelValue)
|
|
@@ -204,32 +218,103 @@ export default defineComponent({
|
|
|
204
218
|
})
|
|
205
219
|
|
|
206
220
|
// update easymde config from outside
|
|
207
|
-
watch(() => [props.modelValue.messages, props.modelValue.options.easyMDEOptions], (newValues, oldValues) => {
|
|
208
|
-
if (newValues[0] !== oldValues[0] || newValues[1] !== oldValues[1]) {
|
|
221
|
+
watch(() => [props.modelValue.options.readOnly, props.modelValue.messages, props.modelValue.options.easyMDEOptions], (newValues, oldValues) => {
|
|
222
|
+
if (newValues[0] !== oldValues[0] || newValues[1] !== oldValues[1] || newValues[2] !== oldValues[2]) {
|
|
209
223
|
initEasyMDE()
|
|
210
224
|
}
|
|
211
225
|
})
|
|
212
226
|
|
|
213
227
|
props.statefulLayout.events.on('autofocus', () => {
|
|
228
|
+
console.log('focus code mirror ?')
|
|
214
229
|
if (props.modelValue.autofocus && easymde) {
|
|
215
230
|
easymde.codemirror.focus()
|
|
216
231
|
}
|
|
217
232
|
})
|
|
218
233
|
|
|
219
|
-
|
|
234
|
+
const theme = useTheme()
|
|
235
|
+
const darkStyle = computed(() => getDarkStyle(theme))
|
|
236
|
+
|
|
237
|
+
return () => [
|
|
238
|
+
h('style', { innerHTML: darkStyle.value }),
|
|
239
|
+
h(VInput, fieldProps.value, fieldSlots.value)
|
|
240
|
+
]
|
|
220
241
|
}
|
|
221
242
|
})
|
|
222
243
|
|
|
244
|
+
const getDarkStyle = (/** @type {import('vuetify').ThemeInstance} */theme) => {
|
|
245
|
+
// Inspired by https://github.com/Ionaru/easy-markdown-editor/issues/131#issuecomment-1738202589
|
|
246
|
+
return `
|
|
247
|
+
.vjsf-node-markdown.vjsf-dark .EasyMDEContainer .CodeMirror {
|
|
248
|
+
color: white;
|
|
249
|
+
border-color: ${theme.current.value.variables['border-color']};
|
|
250
|
+
background-color: ${theme.current.value.colors.surface};
|
|
251
|
+
}
|
|
252
|
+
.vjsf-node-markdown.vjsf-dark .EasyMDEContainer .cm-s-easymde .CodeMirror-cursor {
|
|
253
|
+
border-color: white;
|
|
254
|
+
}
|
|
255
|
+
.vjsf-node-markdown.vjsf-dark .CodeMirror-cursor {
|
|
256
|
+
border-left:1px solid white;
|
|
257
|
+
border-right:none;width:0;
|
|
258
|
+
}
|
|
259
|
+
.vjsf-node-markdown.vjsf-dark .EasyMDEContainer .editor-toolbar > * {
|
|
260
|
+
border-color: ${theme.current.value.colors.surface};
|
|
261
|
+
}
|
|
262
|
+
.vjsf-node-markdown.vjsf-dark .editor-toolbar {
|
|
263
|
+
border-top: 1px solid ${theme.current.value.variables['border-color']};
|
|
264
|
+
border-left: 1px solid ${theme.current.value.variables['border-color']};
|
|
265
|
+
border-right: 1px solid ${theme.current.value.variables['border-color']};
|
|
266
|
+
}
|
|
267
|
+
.vjsf-node-markdown.vjsf-dark .editor-toolbar i.separator {
|
|
268
|
+
border-left: 1px solid ${theme.current.value.variables['border-color']};
|
|
269
|
+
border-right: 1px solid ${theme.current.value.variables['border-color']};
|
|
270
|
+
}
|
|
271
|
+
.vjsf-node-markdown.vjsf-dark .EasyMDEContainer .editor-toolbar > .active, .editor-toolbar > button:hover, .editor-preview pre, .cm-s-easymde .cm-comment {
|
|
272
|
+
background-color: ${theme.current.value.colors.surface};
|
|
273
|
+
}
|
|
274
|
+
.vjsf-node-markdown.vjsf-dark .EasyMDEContainer .CodeMirror-fullscreen {
|
|
275
|
+
background: ${theme.current.value.colors.surface};
|
|
276
|
+
}
|
|
277
|
+
.vjsf-node-markdown.vjsf-dark .editor-toolbar.fullscreen {
|
|
278
|
+
background: ${theme.current.value.colors.surface};
|
|
279
|
+
}
|
|
280
|
+
.vjsf-node-markdown.vjsf-dark .editor-preview {
|
|
281
|
+
background: ${theme.current.value.colors.surface};
|
|
282
|
+
}
|
|
283
|
+
.vjsf-node-markdown.vjsf-dark .editor-preview-side {
|
|
284
|
+
border-color: ${theme.current.value.variables['border-color']};
|
|
285
|
+
}
|
|
286
|
+
.vjsf-node-markdown.vjsf-dark .CodeMirror-selected {
|
|
287
|
+
background: ${theme.current.value.colors.secondary};
|
|
288
|
+
}
|
|
289
|
+
.vjsf-node-markdown.vjsf-dark .CodeMirror-focused .CodeMirror-selected {
|
|
290
|
+
background: ${theme.current.value.colors.secondary};
|
|
291
|
+
}
|
|
292
|
+
.vjsf-node-markdown.vjsf-dark .CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection {
|
|
293
|
+
background:${theme.current.value.colors.secondary}
|
|
294
|
+
}
|
|
295
|
+
.vjsf-node-markdown.vjsf-dark .CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection {
|
|
296
|
+
background:${theme.current.value.colors.secondary}
|
|
297
|
+
}
|
|
298
|
+
.vjsf-node-markdown.vjsf-dark .EasyMDEContainer .CodeMirror-focused .CodeMirror-selected {
|
|
299
|
+
background: ${theme.current.value.colors.secondary}
|
|
300
|
+
}
|
|
301
|
+
`
|
|
302
|
+
}
|
|
303
|
+
|
|
223
304
|
</script>
|
|
224
305
|
|
|
225
306
|
<style>
|
|
307
|
+
.vjsf-node-markdown .vjsf-node-markdown-content {
|
|
308
|
+
width: 100%;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* adjust to density */
|
|
226
312
|
.vjsf-node-markdown .v-input--density-compact .editor-toolbar {
|
|
227
313
|
padding: 0;
|
|
228
314
|
}
|
|
229
315
|
.vjsf-node-markdown .v-input--density-comfortable .editor-toolbar {
|
|
230
316
|
padding: 4px;
|
|
231
317
|
}
|
|
232
|
-
|
|
233
318
|
.vjsf-node-markdown .v-input--density-compact .CodeMirror-wrap {
|
|
234
319
|
padding-top: 2px;
|
|
235
320
|
padding-bottom: 2px;
|
|
@@ -239,4 +324,18 @@ export default defineComponent({
|
|
|
239
324
|
padding-bottom: 6px;
|
|
240
325
|
}
|
|
241
326
|
|
|
327
|
+
/* adjust to readOnly/summary mode */
|
|
328
|
+
.vjsf-node-markdown.vjsf-readonly .EasyMDEContainer .CodeMirror {
|
|
329
|
+
border-width: 0;
|
|
330
|
+
padding: 0;
|
|
331
|
+
}
|
|
332
|
+
.vjsf-node-markdown.vjsf-summary .vjsf-node-markdown-content {
|
|
333
|
+
height: 96px;
|
|
334
|
+
overflow: hidden;
|
|
335
|
+
mask-image: linear-gradient(180deg, #000 66%, transparent 90%);
|
|
336
|
+
}
|
|
337
|
+
.vjsf-node-markdown.vjsf-readonly .vjsf-node-markdown-content textarea {
|
|
338
|
+
display: none;
|
|
339
|
+
}
|
|
340
|
+
|
|
242
341
|
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { ref, computed } from 'vue'
|
|
3
|
-
import { VStepper, VStepperHeader, VStepperItem, VContainer } from 'vuetify/components'
|
|
3
|
+
import { VStepper, VStepperHeader, VStepperItem, VStepperWindow, VStepperWindowItem, VStepperActions, VContainer, VRow, VSpacer, VBtn, VDivider } from 'vuetify/components'
|
|
4
4
|
import { isSection } from '@json-layout/core'
|
|
5
5
|
import Node from '../node.vue'
|
|
6
6
|
import SectionHeader from '../fragments/section-header.vue'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { VTabs, VTab, VContainer } from 'vuetify/components'
|
|
2
|
+
import { VTabs, VTab, VContainer, VSheet, VWindow, VWindowItem, VRow, VIcon } from 'vuetify/components'
|
|
3
3
|
import { ref } from 'vue'
|
|
4
4
|
import { isSection } from '@json-layout/core'
|
|
5
5
|
import Node from '../node.vue'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { defineComponent, h, computed } from 'vue'
|
|
2
|
+
import { defineComponent, h, computed, ref, watch } from 'vue'
|
|
3
3
|
import { VTextarea } from 'vuetify/components'
|
|
4
4
|
import { getInputProps } from '../../utils/props.js'
|
|
5
5
|
import { getCompSlots } from '../../utils/slots.js'
|
|
@@ -18,12 +18,33 @@ export default defineComponent({
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
setup (props) {
|
|
21
|
-
|
|
21
|
+
/** @type {import('vue').Ref<null | HTMLElement>} */
|
|
22
|
+
const textarea = ref(null)
|
|
23
|
+
|
|
24
|
+
const fieldProps = computed(() => {
|
|
25
|
+
const inputProps = getInputProps(props.modelValue, props.statefulLayout, ['placeholder'])
|
|
26
|
+
inputProps.ref = textarea
|
|
27
|
+
if (props.modelValue.options.readOnly && props.modelValue.options.summary) inputProps.rows = 3
|
|
28
|
+
return inputProps
|
|
29
|
+
})
|
|
22
30
|
const fieldSlots = computed(() => getCompSlots(props.modelValue, props.statefulLayout))
|
|
23
31
|
|
|
32
|
+
watch(() => props.modelValue.options.readOnly, (readOnly) => {
|
|
33
|
+
if (readOnly && textarea.value) {
|
|
34
|
+
textarea.value.scrollTop = 0
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
24
38
|
// @ts-ignore
|
|
25
39
|
return () => h(VTextarea, fieldProps.value, fieldSlots.value)
|
|
26
40
|
}
|
|
27
41
|
})
|
|
28
42
|
|
|
29
43
|
</script>
|
|
44
|
+
|
|
45
|
+
<style>
|
|
46
|
+
.vjsf-node-textarea.vjsf-readonly.vjsf-summary textarea {
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
mask-image: linear-gradient(180deg, #000 66%, transparent 90%);
|
|
49
|
+
}
|
|
50
|
+
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { isSection } from '@json-layout/core'
|
|
3
|
-
import { VTabs, VTab, VContainer } from 'vuetify/components'
|
|
3
|
+
import { VTabs, VTab, VContainer, VSheet, VWindow, VWindowItem, VRow, VIcon } from 'vuetify/components'
|
|
4
4
|
import { ref } from 'vue'
|
|
5
5
|
import Node from '../node.vue'
|
|
6
6
|
import SectionHeader from '../fragments/section-header.vue'
|
|
@@ -18,10 +18,22 @@ export default function useDnd (array, callback) {
|
|
|
18
18
|
|
|
19
19
|
const sortableArray = shallowRef(array)
|
|
20
20
|
|
|
21
|
+
const hovered = ref(-1)
|
|
21
22
|
const draggable = ref(-1)
|
|
22
23
|
const dragging = ref(-1)
|
|
23
24
|
|
|
25
|
+
hovered.value = 1
|
|
26
|
+
|
|
24
27
|
const itemBind = (/** @type {number} */itemIndex) => ({
|
|
28
|
+
// hover the item
|
|
29
|
+
onMouseenter: () => {
|
|
30
|
+
hovered.value = itemIndex
|
|
31
|
+
},
|
|
32
|
+
onMouseleave: () => {
|
|
33
|
+
hovered.value = -1
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// drag the item
|
|
25
37
|
onDragstart: () => {
|
|
26
38
|
dragging.value = itemIndex
|
|
27
39
|
},
|
|
@@ -36,6 +48,7 @@ export default function useDnd (array, callback) {
|
|
|
36
48
|
})
|
|
37
49
|
|
|
38
50
|
const handleBind = (/** @type {number} */itemIndex) => ({
|
|
51
|
+
// hover the handle
|
|
39
52
|
onMouseover () {
|
|
40
53
|
draggable.value = itemIndex
|
|
41
54
|
},
|
|
@@ -47,7 +60,9 @@ export default function useDnd (array, callback) {
|
|
|
47
60
|
return {
|
|
48
61
|
activeDnd,
|
|
49
62
|
sortableArray,
|
|
63
|
+
hovered,
|
|
50
64
|
draggable,
|
|
65
|
+
dragging,
|
|
51
66
|
itemBind,
|
|
52
67
|
handleBind
|
|
53
68
|
}
|
|
@@ -84,6 +84,7 @@ export const useVjsf = (schema, modelValue, options, emit, compile, precompiledL
|
|
|
84
84
|
})
|
|
85
85
|
emit('update:state', _statefulLayout)
|
|
86
86
|
_statefulLayout.events.on('autofocus', () => {
|
|
87
|
+
console.log('autofocus ?')
|
|
87
88
|
if (!el.value) return
|
|
88
89
|
// @ts-ignore
|
|
89
90
|
const autofocusNodeElement = el.value.querySelector('.vjsf-input--autofocus')
|
|
@@ -96,7 +97,7 @@ export const useVjsf = (schema, modelValue, options, emit, compile, precompiledL
|
|
|
96
97
|
|
|
97
98
|
watch(fullOptions, (newOptions) => {
|
|
98
99
|
// in case of runtime compilation the watch on compiledLayout will be triggered
|
|
99
|
-
if (!precompiledLayout) return
|
|
100
|
+
if (!precompiledLayout?.value) return
|
|
100
101
|
|
|
101
102
|
if (statefulLayout.value) {
|
|
102
103
|
statefulLayout.value.options = newOptions
|
|
@@ -113,7 +114,7 @@ export const useVjsf = (schema, modelValue, options, emit, compile, precompiledL
|
|
|
113
114
|
// case where schema is updated from outside
|
|
114
115
|
watch(compiledLayout, (newCompiledLayout) => {
|
|
115
116
|
initStatefulLayout()
|
|
116
|
-
}
|
|
117
|
+
})
|
|
117
118
|
|
|
118
119
|
return { el, statefulLayout, stateTree }
|
|
119
120
|
}
|