@koumoul/vjsf 3.0.0-beta.27 → 3.0.0-beta.28

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-beta.27",
3
+ "version": "3.0.0-beta.28",
4
4
  "description": "Generate forms for the vuetify UI library (vuejs) based on annotated JSON schemas.",
5
5
  "scripts": {
6
6
  "test": "vitest",
@@ -76,7 +76,7 @@
76
76
  "vuetify": "^3.6.8"
77
77
  },
78
78
  "dependencies": {
79
- "@json-layout/core": "0.23.0",
79
+ "@json-layout/core": "0.24.0",
80
80
  "@vueuse/core": "^10.5.0",
81
81
  "debug": "^4.3.4",
82
82
  "ejs": "^3.1.9"
@@ -12,9 +12,12 @@ export const defaultOptions = {
12
12
  * @param {number} width
13
13
  * @param {import("vue").Slots} slots
14
14
  * @param {Record<string, import('vue').Component>} defaultNodeComponents
15
+ * @param {(data: any) => void} onData
16
+ * @param {(statefulLayout: import('@json-layout/core').StatefulLayout) => void} onUpdate
17
+ * @param {(key: string) => void} onAutofocus
15
18
  * @returns
16
19
  */
17
- export const getFullOptions = (options, form, width, slots, defaultNodeComponents) => {
20
+ export const getFullOptions = (options, form, width, slots, defaultNodeComponents, onData, onUpdate, onAutofocus) => {
18
21
  const components = { ...options?.components }
19
22
  const nodeComponents = { ...defaultNodeComponents, ...options?.nodeComponents }
20
23
  if (options?.plugins) {
@@ -28,6 +31,9 @@ export const getFullOptions = (options, form, width, slots, defaultNodeComponent
28
31
  ...defaultOptions,
29
32
  readOnly: !!(form && (form.isDisabled.value || form.isReadonly.value)),
30
33
  ...options,
34
+ onData,
35
+ onUpdate,
36
+ onAutofocus,
31
37
  context: options?.context ? JSON.parse(JSON.stringify(options.context)) : {},
32
38
  width: Math.round(width ?? 0),
33
39
  vjsfSlots: { ...slots },
@@ -3,6 +3,9 @@ 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
5
  import { setAutoFreeze } from 'immer'
6
+ import Debug from 'debug'
7
+
8
+ const debug = Debug('vjsf:use-vjsf')
6
9
 
7
10
  // immer freezing is disabled because it is not compatible with Vue 3 reactivity
8
11
  setAutoFreeze(false)
@@ -54,60 +57,65 @@ export const useVjsf = (schema, modelValue, options, nodeComponents, emit, compi
54
57
 
55
58
  const slots = useSlots()
56
59
 
57
- const fullOptions = computed(() => getFullOptions(options.value, form, width.value, slots, { ...nodeComponents }))
58
-
59
- // do not use a simple computed here as we want to prevent recompiling the layout when the options are the same
60
- /** @type {import('vue').Ref<import('@json-layout/core').PartialCompileOptions>} */
61
- const compileOptions = ref({})
62
- watch(fullOptions, (newOptions) => {
63
- if (precompiledLayout?.value) return
64
- const newCompileOptions = produceCompileOptions(compileOptions.value, newOptions)
65
- if (newCompileOptions !== compileOptions.value) compileOptions.value = newCompileOptions
66
- }, { immediate: true })
67
-
68
- const compiledLayout = computed(() => {
69
- if (precompiledLayout?.value) return precompiledLayout?.value
70
- if (!compile) throw new Error('compile function is not available')
71
- const compiledLayout = compile(schema.value, compileOptions.value)
72
- return compiledLayout
73
- })
74
-
75
- const onStatefulLayoutUpdate = () => {
76
- if (!statefulLayout.value) return
77
- stateTree.value = statefulLayout.value.stateTree
78
- emit('update:state', statefulLayout.value)
60
+ /* Callbacks from json layout stateful layout */
61
+ /**
62
+ * @param {import('../types.js').VjsfStatefulLayout} 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)
79
70
  if (form) {
80
71
  // cf https://vuetifyjs.com/en/components/forms/#validation-state
81
- if (statefulLayout.value.valid) form.update('vjsf', true, [])
82
- else if (statefulLayout.value.hasHiddenError) form.update('vjsf', null, [])
72
+ if (statefulLayout.valid) form.update('vjsf', true, [])
73
+ else if (statefulLayout.hasHiddenError) form.update('vjsf', null, [])
83
74
  else form.update('vjsf', false, [])
84
75
  }
85
76
  }
86
-
87
- const onDataUpdate = () => {
88
- if (statefulLayout.value && modelValue !== statefulLayout.value.data) {
89
- emit('update:modelValue', statefulLayout.value.data)
90
- }
77
+ /**
78
+ * @param {any} data
79
+ */
80
+ const onDataUpdate = (data) => {
81
+ debug('onDataUpdate', data)
82
+ debug(' -> emit update:modelValue')
83
+ emit('update:modelValue', data)
91
84
  }
92
-
93
85
  const onAutofocus = () => {
94
86
  if (!el.value) return
95
87
  // @ts-ignore
96
88
  const autofocusNodeElement = el.value.querySelector('.vjsf-input--autofocus')
89
+ debug('onAutofocus', autofocusNodeElement)
97
90
  if (autofocusNodeElement) {
98
91
  const autofocusInputElement = autofocusNodeElement.querySelector('input') ?? autofocusNodeElement.querySelector('textarea:not([style*="display: none"]')
99
92
  if (autofocusInputElement) autofocusInputElement.focus()
100
93
  }
101
94
  }
102
95
 
103
- const initStatefulLayout = () => {
104
- if (!width.value) return
105
- if (statefulLayout.value) {
106
- statefulLayout.value.events.off('update', onStatefulLayoutUpdate)
107
- statefulLayout.value.events.off('data', onDataUpdate)
108
- statefulLayout.value.events.off('autofocus', onAutofocus)
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
109
107
  }
108
+ }, { immediate: true })
110
109
 
110
+ const compiledLayout = computed(() => {
111
+ if (precompiledLayout?.value) return precompiledLayout?.value
112
+ if (!compile) throw new Error('compile function is not available')
113
+ const compiledLayout = compile(schema.value, compileOptions.value)
114
+ return compiledLayout
115
+ })
116
+
117
+ const initStatefulLayout = () => {
118
+ if (!width.value) return
111
119
  // @ts-ignore
112
120
  statefulLayout.value = /** @type {import('../types.js').VjsfStatefulLayout} */(new StatefulLayout(
113
121
  toRaw(compiledLayout.value),
@@ -115,29 +123,34 @@ export const useVjsf = (schema, modelValue, options, nodeComponents, emit, compi
115
123
  toRaw(fullOptions.value),
116
124
  toRaw(modelValue.value)
117
125
  ))
118
- onStatefulLayoutUpdate()
119
- onDataUpdate()
120
- statefulLayout.value.events.on('update', onStatefulLayoutUpdate)
121
- statefulLayout.value.events.on('data', onDataUpdate)
122
- statefulLayout.value.events.on('autofocus', onAutofocus)
123
126
  }
124
127
 
125
128
  // case where options are updated from outside
126
129
  watch(fullOptions, (newOptions) => {
130
+ debug('watch fullOptions', fullOptions)
127
131
  if (statefulLayout.value) {
132
+ debug(' -> update statefulLayout options')
128
133
  statefulLayout.value.options = newOptions
129
134
  } else {
135
+ debug(' -> init statefulLayout')
130
136
  initStatefulLayout()
131
137
  }
132
138
  })
133
139
 
134
140
  // case where data is updated from outside
135
141
  watch(modelValue, (newData) => {
136
- 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
+ }
137
148
  })
138
149
 
139
150
  // case where schema or compile options are updated from outside
140
151
  watch(compiledLayout, (newCompiledLayout) => {
152
+ debug('watch compiledLayout', newCompiledLayout)
153
+ debug(' -> init statefulLayout')
141
154
  initStatefulLayout()
142
155
  })
143
156
 
@@ -1,4 +1,4 @@
1
1
  /** @type {import("../types.js").PartialVjsfOptions} */
2
2
  export const defaultOptions: import("../types.js").PartialVjsfOptions;
3
- export function getFullOptions(options: Partial<import("../types.js").VjsfOptions> | null, form: any, width: number, slots: import("vue").Slots, defaultNodeComponents: Record<string, import('vue').Component>): import("../types.js").VjsfOptions;
3
+ export function getFullOptions(options: Partial<import("../types.js").VjsfOptions> | null, form: any, width: number, slots: import("vue").Slots, defaultNodeComponents: Record<string, import('vue').Component>, onData: (data: any) => void, onUpdate: (statefulLayout: import('@json-layout/core').StatefulLayout) => void, onAutofocus: (key: string) => void): import("../types.js").VjsfOptions;
4
4
  //# sourceMappingURL=options.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/components/options.js"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,6BADW,OAAO,aAAa,EAAE,kBAAkB,CAKlD;AAWM,wCAPI,QAAQ,OAAO,aAAa,EAAE,WAAW,CAAC,GAAG,IAAI,QACjD,GAAG,SACH,MAAM,SACN,OAAO,KAAK,EAAE,KAAK,yBACnB,OAAO,MAAM,EAAE,OAAO,KAAK,EAAE,SAAS,CAAC,qCAwBjD"}
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/components/options.js"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,6BADW,OAAO,aAAa,EAAE,kBAAkB,CAKlD;AAcM,wCAVI,QAAQ,OAAO,aAAa,EAAE,WAAW,CAAC,GAAG,IAAI,QACjD,GAAG,SACH,MAAM,SACN,OAAO,KAAK,EAAE,KAAK,yBACnB,OAAO,MAAM,EAAE,OAAO,KAAK,EAAE,SAAS,CAAC,iBAChC,GAAG,KAAK,IAAI,6BACF,OAAO,mBAAmB,EAAE,cAAc,KAAK,IAAI,qBAC9D,MAAM,KAAK,IAAI,qCA2B/B"}
@@ -1,13 +1,13 @@
1
1
  declare const _default: import("vue").DefineComponent<{}, {
2
- $emit: ((event: "update:modelValue", data: any) => void) & ((event: "update:state", state: import("../types.js").VjsfStatefulLayout) => void);
2
+ $emit: ((event: "update:state", state: import("../types.js").VjsfStatefulLayout) => void) & ((event: "update:modelValue", data: any) => void);
3
+ options: Partial<Omit<import("../types.js").VjsfOptions, "width" | "vjsfSlots">> | null;
3
4
  schema: Record<string, any>;
4
5
  modelValue: any;
5
- options: Partial<Omit<import("../types.js").VjsfOptions, "width" | "vjsfSlots">> | null;
6
6
  precompiledLayout: import("../../../node_modules/@json-layout/core/types/compile/types.js").CompiledLayout;
7
7
  $props: {
8
+ readonly options?: Partial<Omit<import("../types.js").VjsfOptions, "width" | "vjsfSlots">> | null | undefined;
8
9
  readonly schema?: Record<string, any> | undefined;
9
10
  readonly modelValue?: any;
10
- readonly options?: Partial<Omit<import("../types.js").VjsfOptions, "width" | "vjsfSlots">> | null | undefined;
11
11
  readonly precompiledLayout?: import("../../../node_modules/@json-layout/core/types/compile/types.js").CompiledLayout | undefined;
12
12
  };
13
13
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
@@ -1 +1 @@
1
- {"version":3,"file":"use-vjsf.d.ts","sourceRoot":"","sources":["../../src/composables/use-vjsf.js"],"names":[],"mappings":"AASA;IACE;;MAEE;gCADO,GAAG;IAGZ;;MAEE;4BADO,OAAO,aAAa,EAAE,kBAAkB;EAGlD;AAWM,gCARI,OAAO,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,cACzB,OAAO,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,WACtB,OAAO,KAAK,EAAE,GAAG,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC,kBAClE,OAAO,MAAM,EAAE,OAAO,KAAK,EAAE,SAAS,CAAC,QACvC,GAAG;;;;EAuHb"}
1
+ {"version":3,"file":"use-vjsf.d.ts","sourceRoot":"","sources":["../../src/composables/use-vjsf.js"],"names":[],"mappings":"AAYA;IACE;;MAEE;gCADO,GAAG;IAGZ;;MAEE;4BADO,OAAO,aAAa,EAAE,kBAAkB;EAGlD;AAWM,gCARI,OAAO,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,cACzB,OAAO,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,WACtB,OAAO,KAAK,EAAE,GAAG,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC,kBAClE,OAAO,MAAM,EAAE,OAAO,KAAK,EAAE,SAAS,CAAC,QACvC,GAAG;;;;EAiIb"}