@koumoul/vjsf 3.0.0-alpha.2 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koumoul/vjsf",
3
- "version": "3.0.0-alpha.2",
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.3.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/compat/v2.js CHANGED
@@ -1,14 +1,11 @@
1
1
  import ajvModule from 'ajv'
2
- import rfdc from 'rfdc'
3
2
  import addFormats from 'ajv-formats'
4
- import { resolveRefs } from '@json-layout/core'
3
+ import { resolveRefs, clone } from '@json-layout/core'
5
4
  import { isPartialGetItemsObj } from '@json-layout/vocabulary'
6
5
 
7
6
  // @ts-ignore
8
7
  const Ajv = /** @type {typeof ajvModule.default} */ (ajvModule)
9
8
 
10
- const clone = rfdc()
11
-
12
9
  const processFragment = (/** @type {import("ajv").SchemaObject} */schema) => {
13
10
  if (!schema.layout) {
14
11
  /** @type import('@json-layout/vocabulary').PartialCompObject */
@@ -30,7 +30,7 @@ const { el, statefulLayout, stateTree } = useVjsf(
30
30
  computed(() => props.options),
31
31
  emit,
32
32
  null,
33
- compiledLayout
33
+ computed(() => compiledLayout)
34
34
  )
35
35
  </script>
36
36
 
@@ -20,7 +20,7 @@
20
20
  </template>
21
21
 
22
22
  <script setup>
23
- import { VAlert, VBtn } from 'vuetify/components'
23
+ import { VAlert, VBtn, VSlideXReverseTransition } from 'vuetify/components'
24
24
  import { ref } from 'vue'
25
25
 
26
26
  defineProps({
@@ -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="`vjsf-node vjsf-node-${modelValue.layout.comp}`"
43
+ :class="nodeClasses"
31
44
  >
32
45
  <node-slot
33
46
  v-if="modelValue.layout.slots?.before"
@@ -87,9 +87,3 @@ export default defineComponent({
87
87
  })
88
88
 
89
89
  </script>
90
-
91
- <template>
92
- <v-select
93
- v-bind="fieldProps"
94
- />
95
- </template>
@@ -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,9 +1,8 @@
1
1
  <script setup>
2
2
  import { watch, computed, ref } from 'vue'
3
- import { VList, VListItem, VListItemAction, VBtn, VMenu, VIcon } from 'vuetify/components'
4
- import { isSection } from '@json-layout/core'
3
+ import { VList, VListItem, VListItemAction, VBtn, VMenu, VIcon, VSheet, VSpacer, VDivider, VRow, VListSubheader } from 'vuetify/components'
4
+ import { isSection, clone } from '@json-layout/core'
5
5
  import Node from '../node.vue'
6
- import clone from '../../utils/clone.js'
7
6
  import { moveArrayItem } from '../../utils/arrays.js'
8
7
  import useDnd from '../../composables/use-dnd.js'
9
8
 
@@ -21,7 +20,7 @@ const props = defineProps({
21
20
  })
22
21
 
23
22
  /* use composable for drag and drop */
24
- const { activeDnd, sortableArray, draggable, itemBind, handleBind } = useDnd(props.modelValue.children, () => {
23
+ const { activeDnd, sortableArray, draggable, hovered, dragging, itemBind, handleBind } = useDnd(props.modelValue.children, () => {
25
24
  props.statefulLayout.input(props.modelValue, sortableArray.value.map((child) => child.data))
26
25
  })
27
26
  watch(() => props.modelValue.children, (array) => { sortableArray.value = array })
@@ -30,7 +29,7 @@ watch(() => props.modelValue.children, (array) => { sortableArray.value = array
30
29
  const editedItem = computed(() => {
31
30
  return props.statefulLayout.activeItems[props.modelValue.fullKey]
32
31
  })
33
- const hoveredItem = ref(1)
32
+ const menuOpened = ref(-1)
34
33
  const activeItem = computed(() => {
35
34
  if (
36
35
  props.modelValue.layout.listActions.includes('edit') &&
@@ -39,7 +38,9 @@ const activeItem = computed(() => {
39
38
  ) {
40
39
  return editedItem.value
41
40
  }
42
- return hoveredItem.value
41
+ if (dragging.value !== -1) return -1
42
+ if (menuOpened.value !== -1) return menuOpened.value
43
+ return hovered.value
43
44
  })
44
45
 
45
46
  const buttonDensity = computed(() => {
@@ -65,8 +66,6 @@ const buttonDensity = computed(() => {
65
66
  :draggable="draggable === childIndex"
66
67
  :variant="editedItem === childIndex ? 'outlined' : 'flat'"
67
68
  class="pa-1 vjsf-list-item"
68
- @mouseenter="hoveredItem = childIndex"
69
- @mouseleave="hoveredItem = -1"
70
69
  >
71
70
  <v-row class="ma-0">
72
71
  <node
@@ -117,7 +116,10 @@ const buttonDensity = computed(() => {
117
116
  <v-list-item-action
118
117
  v-if="editedItem === undefined && (modelValue.layout.listActions.includes('delete') || modelValue.layout.listActions.includes('duplicate') || modelValue.layout.listActions.includes('sort'))"
119
118
  >
120
- <v-menu location="bottom end">
119
+ <v-menu
120
+ location="bottom end"
121
+ @update:model-value="value => {menuOpened = value ? childIndex : -1}"
122
+ >
121
123
  <template #activator="{props: activatorProps}">
122
124
  <v-btn
123
125
  v-bind="activatorProps"
@@ -1,10 +1,11 @@
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
- // import 'easymde/dist/easymde.min.css'
7
- // import EasyMDE from 'easymde'
8
+ import 'easymde/dist/easymde.min.css'
8
9
 
9
10
  export default defineComponent({
10
11
  props: {
@@ -19,30 +20,44 @@ export default defineComponent({
19
20
  required: true
20
21
  }
21
22
  },
22
- setup (props) {
23
+ setup (props, { expose }) {
23
24
  /** @type {import('vue').Ref<null | HTMLElement>} */
24
25
  const element = ref(null)
25
26
 
27
+ const renderedValue = computed(() => {
28
+ return props.modelValue.data && marked.parse(props.modelValue.data)
29
+ })
30
+
26
31
  const fieldProps = computed(() => getInputProps(props.modelValue, props.statefulLayout))
27
32
  const fieldSlots = computed(() => {
28
33
  const fieldSlots = getCompSlots(props.modelValue, props.statefulLayout)
29
- fieldSlots.default = () => [
30
- h('div', { style: 'width:100%' }, [
34
+ fieldSlots.default = () => {
35
+ const children = [
31
36
  h(VLabel, { text: fieldProps.value.label }),
32
37
  h('textarea', { ref: element })
33
- ])
34
- ]
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
+ }
35
44
  return fieldSlots
36
45
  })
37
46
 
47
+ /** @type {ReturnType<typeof setTimeout> | null} */
48
+ let blurTimeout = null
49
+
38
50
  /** @type {EasyMDE | null} */
39
51
  let easymde = null
40
52
 
41
53
  const initEasyMDE = async () => {
54
+ if (easymde) {
55
+ easymde.toTextArea()
56
+ easymde = null
57
+ }
58
+ if (props.modelValue.options.readOnly) return
42
59
  if (!element.value) throw new Error('component was not mounted for markdown editor')
43
60
 
44
- // @ts-ignore
45
- await import('easymde/dist/easymde.min.css')
46
61
  const EasyMDE = (await import('easymde')).default
47
62
 
48
63
  const messages = props.modelValue.messages
@@ -161,12 +176,9 @@ export default defineComponent({
161
176
  className: 'mdi mdi-help-circle text-success',
162
177
  title: messages.mdeGuide,
163
178
  noDisable: true
164
- }
165
- ],
179
+ }],
166
180
  ...props.modelValue.options.easyMDEOptions
167
181
  }
168
-
169
- if (easymde) easymde.toTextArea()
170
182
  // @ts-ignore
171
183
  easymde = new EasyMDE(config)
172
184
 
@@ -175,9 +187,8 @@ export default defineComponent({
175
187
  changed = true
176
188
  if (easymde) props.statefulLayout.input(props.modelValue, easymde.value())
177
189
  })
178
- /** @type {ReturnType<typeof setTimeout> | null} */
179
- let blurTimeout = null
180
190
  easymde.codemirror.on('blur', () => {
191
+ console.log('onblur')
181
192
  // timeout to prevent triggering save when clicking on a menu button
182
193
  blurTimeout = setTimeout(() => {
183
194
  if (changed) props.statefulLayout.blur(props.modelValue)
@@ -187,6 +198,10 @@ export default defineComponent({
187
198
  easymde.codemirror.on('focus', () => {
188
199
  if (blurTimeout) clearTimeout(blurTimeout)
189
200
  })
201
+
202
+ if (props.modelValue.autofocus) {
203
+ easymde.codemirror.focus()
204
+ }
190
205
  }
191
206
 
192
207
  onMounted(initEasyMDE)
@@ -203,24 +218,103 @@ export default defineComponent({
203
218
  })
204
219
 
205
220
  // update easymde config from outside
206
- watch(() => [props.modelValue.messages, props.modelValue.options.easyMDEOptions], () => {
207
- initEasyMDE()
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]) {
223
+ initEasyMDE()
224
+ }
225
+ })
226
+
227
+ props.statefulLayout.events.on('autofocus', () => {
228
+ console.log('focus code mirror ?')
229
+ if (props.modelValue.autofocus && easymde) {
230
+ easymde.codemirror.focus()
231
+ }
208
232
  })
209
233
 
210
- return () => h(VInput, fieldProps.value, fieldSlots.value)
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
+ ]
211
241
  }
212
242
  })
213
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
+
214
304
  </script>
215
305
 
216
306
  <style>
307
+ .vjsf-node-markdown .vjsf-node-markdown-content {
308
+ width: 100%;
309
+ }
310
+
311
+ /* adjust to density */
217
312
  .vjsf-node-markdown .v-input--density-compact .editor-toolbar {
218
313
  padding: 0;
219
314
  }
220
315
  .vjsf-node-markdown .v-input--density-comfortable .editor-toolbar {
221
316
  padding: 4px;
222
317
  }
223
-
224
318
  .vjsf-node-markdown .v-input--density-compact .CodeMirror-wrap {
225
319
  padding-top: 2px;
226
320
  padding-bottom: 2px;
@@ -230,4 +324,18 @@ export default defineComponent({
230
324
  padding-bottom: 6px;
231
325
  }
232
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
+
233
341
  </style>
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { VSelect } from 'vuetify/components'
2
+ import { VSelect, VRow } from 'vuetify/components'
3
3
  import { shallowRef, watch } from 'vue'
4
4
  import { isSection } from '@json-layout/core'
5
5
  import Node from '../node.vue'
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { VRow } from 'vuetify/components'
2
3
  import Node from '../node.vue'
3
4
  import SectionHeader from '../fragments/section-header.vue'
4
5
 
@@ -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'
@@ -27,3 +27,9 @@ export default defineComponent({
27
27
  })
28
28
 
29
29
  </script>
30
+
31
+ <style>
32
+ .vjsf-node-text-field.vjsf-readonly.vjsf-summary input {
33
+ text-overflow: ellipsis;
34
+ }
35
+ </style>
@@ -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
- const fieldProps = computed(() => getInputProps(props.modelValue, props.statefulLayout, ['placeholder']))
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'
@@ -88,7 +88,7 @@ const { el, statefulLayout, stateTree } = useVjsf(
88
88
  computed(() => props.options),
89
89
  emit,
90
90
  compile,
91
- props.precompiledLayout
91
+ computed(() => props.precompiledLayout)
92
92
  )
93
93
 
94
94
  </script>
@@ -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
  }
@@ -19,8 +19,8 @@ export const emits = {
19
19
  * @param {import('vue').Ref<any>} modelValue
20
20
  * @param {import('vue').Ref<import("../components/types.js").PartialVjsfOptions>} options
21
21
  * @param {any} emit
22
- * @param {typeof import('@json-layout/core').compile} compile
23
- * @param {import('@json-layout/core').CompiledLayout} [precompiledLayout]
22
+ * @param {typeof import('@json-layout/core').compile} [compile]
23
+ * @param {import('vue').Ref<import('@json-layout/core').CompiledLayout>} [precompiledLayout]
24
24
  */
25
25
  export const useVjsf = (schema, modelValue, options, emit, compile, precompiledLayout) => {
26
26
  const el = ref(null)
@@ -50,7 +50,8 @@ export const useVjsf = (schema, modelValue, options, emit, compile, precompiledL
50
50
  const fullOptions = computed(() => getFullOptions(options.value, form, width.value, slots))
51
51
 
52
52
  const compiledLayout = computed(() => {
53
- if (precompiledLayout) return precompiledLayout
53
+ if (precompiledLayout?.value) return precompiledLayout?.value
54
+ if (!compile) throw new Error('compile function is not available')
54
55
  const compiledLayout = compile(schema.value, fullOptions.value)
55
56
  return compiledLayout
56
57
  })
@@ -83,17 +84,21 @@ export const useVjsf = (schema, modelValue, options, emit, compile, precompiledL
83
84
  })
84
85
  emit('update:state', _statefulLayout)
85
86
  _statefulLayout.events.on('autofocus', () => {
87
+ console.log('autofocus ?')
86
88
  if (!el.value) return
87
89
  // @ts-ignore
88
90
  const autofocusNodeElement = el.value.querySelector('.vjsf-input--autofocus')
89
91
  if (autofocusNodeElement) {
90
- const autofocusInputElement = autofocusNodeElement.querySelector('input')
92
+ const autofocusInputElement = autofocusNodeElement.querySelector('input') ?? autofocusNodeElement.querySelector('textarea:not([style*="display: none"]')
91
93
  if (autofocusInputElement) autofocusInputElement.focus()
92
94
  }
93
95
  })
94
96
  }
95
97
 
96
98
  watch(fullOptions, (newOptions) => {
99
+ // in case of runtime compilation the watch on compiledLayout will be triggered
100
+ if (!precompiledLayout?.value) return
101
+
97
102
  if (statefulLayout.value) {
98
103
  statefulLayout.value.options = newOptions
99
104
  } else {
@@ -109,7 +114,7 @@ export const useVjsf = (schema, modelValue, options, emit, compile, precompiledL
109
114
  // case where schema is updated from outside
110
115
  watch(compiledLayout, (newCompiledLayout) => {
111
116
  initStatefulLayout()
112
- }, { immediate: true })
117
+ })
113
118
 
114
119
  return { el, statefulLayout, stateTree }
115
120
  }
@@ -1 +1 @@
1
- {"version":3,"file":"v2.d.ts","sourceRoot":"","sources":["../../src/compat/v2.js"],"names":[],"mappings":"AAiGA;;;;;;GAMG;AACH,kCALW,MAAM,+CAEN,MAAM,0BAkBhB;sBAvHqB,KAAK"}
1
+ {"version":3,"file":"v2.d.ts","sourceRoot":"","sources":["../../src/compat/v2.js"],"names":[],"mappings":"AA8FA;;;;;;GAMG;AACH,kCALW,MAAM,+CAEN,MAAM,0BAkBhB;sBApHqB,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.vue.d.ts","sourceRoot":"","sources":["../../../src/components/nodes/markdown.vue.js"],"names":[],"mappings":";;QAYM,2EAA2E;cAAjE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,aAAa,EAAE,gBAAgB,CAAC;;;;QAKxE,+EAA+E;cAArE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,mBAAmB,EAAE,cAAc,CAAC;;;;;;;QAL5E,2EAA2E;cAAjE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,aAAa,EAAE,gBAAgB,CAAC;;;;QAKxE,+EAA+E;cAArE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,mBAAmB,EAAE,cAAc,CAAC"}
1
+ {"version":3,"file":"markdown.vue.d.ts","sourceRoot":"","sources":["../../../src/components/nodes/markdown.vue.js"],"names":[],"mappings":";;QAWM,2EAA2E;cAAjE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,aAAa,EAAE,gBAAgB,CAAC;;;;QAKxE,+EAA+E;cAArE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,mBAAmB,EAAE,cAAc,CAAC;;;;;;;QAL5E,2EAA2E;cAAjE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,aAAa,EAAE,gBAAgB,CAAC;;;;QAKxE,+EAA+E;cAArE,OAAO,KAAK,EAAE,QAAQ,CAAC,OAAO,mBAAmB,EAAE,cAAc,CAAC"}
@@ -1,12 +1,12 @@
1
1
  declare const _default: import("vue").DefineComponent<{}, {
2
2
  $emit: ((event: "update:modelValue", data: any) => void) & ((event: "update:state", state: import("@json-layout/core").StatefulLayout) => void);
3
- modelValue: any;
4
3
  options: Partial<Omit<import("./types.js").VjsfOptions, "width">>;
4
+ modelValue: any;
5
5
  schema: Record<string, any>;
6
6
  precompiledLayout: import("../../../node_modules/@json-layout/core/types/compile/types.js").CompiledLayout;
7
7
  $props: {
8
- readonly modelValue?: any;
9
8
  readonly options?: Partial<Omit<import("./types.js").VjsfOptions, "width">> | undefined;
9
+ readonly modelValue?: any;
10
10
  readonly schema?: Record<string, any> | undefined;
11
11
  readonly precompiledLayout?: import("../../../node_modules/@json-layout/core/types/compile/types.js").CompiledLayout | undefined;
12
12
  };
@@ -8,7 +8,7 @@ export const emits: {
8
8
  */
9
9
  'update:state': (state: StatefulLayout) => boolean;
10
10
  };
11
- export function useVjsf(schema: import('vue').Ref<Object>, modelValue: import('vue').Ref<any>, options: import('vue').Ref<import("../components/types.js").PartialVjsfOptions>, emit: any, compile: typeof import('@json-layout/core').compile, precompiledLayout?: import("../../../node_modules/@json-layout/core/types/compile/types.js").CompiledLayout | undefined): {
11
+ export function useVjsf(schema: import('vue').Ref<Object>, modelValue: import('vue').Ref<any>, options: import('vue').Ref<import("../components/types.js").PartialVjsfOptions>, emit: any, compile?: typeof import("@json-layout/core").compile | undefined, precompiledLayout?: import("vue").Ref<import("../../../node_modules/@json-layout/core/types/compile/types.js").CompiledLayout> | undefined): {
12
12
  el: import("vue").Ref<null>;
13
13
  statefulLayout: import("vue").ShallowRef<StatefulLayout | null>;
14
14
  stateTree: import("vue").ShallowRef<import("../../../node_modules/@json-layout/core/types/state/types.js").StateTree | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"use-vjsf.d.ts","sourceRoot":"","sources":["../../src/composables/use-vjsf.js"],"names":[],"mappings":"AAKA;IACE;;MAEE;gCADO,GAAG;IAGZ;;MAEE;4BADO,cAAc;EAGxB;AAUM,gCAPI,OAAO,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,cACzB,OAAO,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,WACtB,OAAO,KAAK,EAAE,GAAG,CAAC,OAAO,wBAAwB,EAAE,kBAAkB,CAAC,QACtE,GAAG,WACH,cAAc,mBAAmB,EAAE,OAAO;;;;EA6FpD;+BAlH8B,mBAAmB"}
1
+ {"version":3,"file":"use-vjsf.d.ts","sourceRoot":"","sources":["../../src/composables/use-vjsf.js"],"names":[],"mappings":"AAKA;IACE;;MAEE;gCADO,GAAG;IAGZ;;MAEE;4BADO,cAAc;EAGxB;AAUM,gCAPI,OAAO,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,cACzB,OAAO,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,WACtB,OAAO,KAAK,EAAE,GAAG,CAAC,OAAO,wBAAwB,EAAE,kBAAkB,CAAC,QACtE,GAAG;;;;EAkGb;+BAtH8B,mBAAmB"}
@@ -1,3 +0,0 @@
1
- import rfdc from 'rfdc'
2
-
3
- export default rfdc()