@live-change/frontend-auto-form 0.2.6 → 0.2.8

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/ArrayInput.vue ADDED
@@ -0,0 +1,108 @@
1
+ <template>
2
+ <div>
3
+ <div class="mb-3" v-for="(value, index) in modelValue">
4
+ <div class="p-buttonset">
5
+ <Button class="" icon="pi pi-plus" @click="insertItem(index)"
6
+ label="Insert" />
7
+ <Button class="p-button-secondary" icon="pi pi-sync" @click="swapItem(index)"
8
+ label="Swap" />
9
+ <Button class="p-button-danger" icon="pi pi-trash" @click="removeItem(index)"
10
+ :label="`Remove #${ index+1 }`" />
11
+ </div>
12
+ <auto-input :modelValue="value" :definition="definition.of"
13
+ @update:modelValue="value => updateItem(index, value)"
14
+ :rootValue="props.rootValue" :propName="props.propName + '.' + index" />
15
+ </div>
16
+ <div>
17
+ <Button label="Add item" icon="pi pi-plus" @click="insertItem" />
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup>
23
+ import Button from "primevue/button";
24
+ import AutoInput from "./AutoInput.vue"
25
+
26
+ import { inputs, types } from './config.js'
27
+ import { computed, getCurrentInstance } from 'vue'
28
+ import { toRefs } from '@vueuse/core'
29
+
30
+ const props = defineProps({
31
+ modelValue: {
32
+ },
33
+ definition: {
34
+ type: Object
35
+ },
36
+ properties: {
37
+ type: Object,
38
+ default: () => ({})
39
+ },
40
+ rootValue: {
41
+ type: Object,
42
+ default: () => ({})
43
+ },
44
+ propName: {
45
+ type: String,
46
+ default: ''
47
+ },
48
+ })
49
+
50
+ const emit = defineEmits(['update:modelValue'])
51
+
52
+ const { value, definition, modelValue } = toRefs(props)
53
+
54
+ import { defaultData } from "@live-change/vue3-components"
55
+
56
+ import { useToast } from 'primevue/usetoast'
57
+ const toast = useToast()
58
+ import { useConfirm } from 'primevue/useconfirm'
59
+ const confirm = useConfirm()
60
+
61
+ function insertItem(index) {
62
+ const data = modelValue.value || []
63
+ const item = defaultData(definition.value.of)
64
+ data.splice(index ?? data.length, 0, item) /// TODO: default value
65
+ emit('update:modelValue', data)
66
+ toast.add({ severity: 'info', summary: 'Item added', life: 1500 })
67
+ }
68
+ function updateItem(index, value) {
69
+ const data = modelValue.value || []
70
+ data[index] = value
71
+ emit('update:modelValue', data)
72
+ }
73
+ function removeItem(index) {
74
+ confirm.require({
75
+ target: event.currentTarget,
76
+ message: `Are you sure you want to remove this item?`,
77
+ icon: 'pi pi-info-circle',
78
+ acceptClass: 'p-button-danger',
79
+ accept: async () => {
80
+ const data = modelValue.value || []
81
+ data.splice(index, 1)
82
+ emit('update:modelValue', data)
83
+ toast.add({ severity: 'info', summary: 'Item removed', life: 1500 })
84
+ },
85
+ reject: () => {
86
+ toast.add({ severity:'error', summary: 'Rejected', detail: 'You have rejected', life: 3000 })
87
+ }
88
+ })
89
+ }
90
+ function swapItem(index) {
91
+ const data = modelValue.value || []
92
+ if(index === 0) {
93
+ const popped = data.pop()
94
+ data.push(data.shift())
95
+ data.unshift(popped)
96
+ } else {
97
+ const tmp = data[index]
98
+ data[index] = data[index-1]
99
+ data[index-1] = tmp
100
+ }
101
+ emit('update:modelValue', data)
102
+ }
103
+
104
+ </script>
105
+
106
+ <style scoped>
107
+
108
+ </style>
package/AutoEditor.vue ADDED
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <div v-if="definition" class="grid formgrid p-fluid mt-2 mb-2">
3
+ <auto-field v-for="property in propertiesList" :key="property"
4
+ :modelValue="modelValue?.[property]"
5
+ @update:modelValue="value => updateModelProperty(property, value)"
6
+ :definition="definition.properties[property]"
7
+ :label="property"
8
+ :rootValue="props.rootValue" :propName="(propName ? propName + '.' : '') + property"
9
+ class="col-12" />
10
+ </div>
11
+ </template>
12
+
13
+ <script setup>
14
+ import AutoField from "./AutoField.vue"
15
+
16
+ import { computed, inject, getCurrentInstance } from 'vue'
17
+ import { toRefs } from '@vueuse/core'
18
+
19
+ const props = defineProps({
20
+ modelValue: {},
21
+ definition: {
22
+ type: Object
23
+ },
24
+ rootValue: {
25
+ type: Object,
26
+ default: () => ({})
27
+ },
28
+ propName: {
29
+ type: String,
30
+ default: ''
31
+ }
32
+ })
33
+
34
+ const { modelValue, definition } = toRefs(props)
35
+
36
+ const emit = defineEmits(['update:modelValue'])
37
+
38
+ const propertiesList = computed(() => Object.keys(props.definition.properties)
39
+ .filter(key => props.definition.properties[key]))
40
+
41
+ function updateModelProperty(property, value) {
42
+ const data = modelValue.value || {}
43
+ data[property] = value
44
+ console.log("UPDATE MODEL", data)
45
+ emit('update:modelValue', data)
46
+ }
47
+
48
+
49
+ </script>
50
+
51
+ <style scoped>
52
+
53
+ </style>
package/AutoField.vue ADDED
@@ -0,0 +1,137 @@
1
+ <template>
2
+ <component v-if="fieldComponent && visible" :is="fieldComponent" v-bind="attributes"
3
+ @update:modelValue="value => emit('update:modelValue', value)" />
4
+ <div v-else-if="visible" class="field" :class="fieldClass" :style="fieldStyle">
5
+ <label :for="uid">{{ label }}</label>
6
+ <slot>
7
+ <auto-input :modelValue="modelValue" :definition="definition"
8
+ :class="props.inputClass" :style="props.inputStyle"
9
+ :attributes="props.inputAttributes"
10
+ @update:modelValue="value => emit('update:modelValue', value)"
11
+ :id="uid" />
12
+ </slot>
13
+ <small v-if="validationResult" class="p-error">{{ validationResult }}</small>
14
+ </div>
15
+ </template>
16
+
17
+ <script setup>
18
+
19
+ import AutoInput from "./AutoInput.vue"
20
+
21
+ import { inputs, types } from './config.js'
22
+ import { computed, getCurrentInstance } from 'vue'
23
+ import { toRefs } from '@vueuse/core'
24
+
25
+ const props = defineProps({
26
+ modelValue: {},
27
+ error: {
28
+ type: String
29
+ },
30
+ definition: {
31
+ type: Object
32
+ },
33
+ name: {
34
+ type: String
35
+ },
36
+ label: {
37
+ type: String
38
+ },
39
+ class: {},
40
+ style: {},
41
+ inputClass: {},
42
+ inputStyle: {},
43
+ attributes: {
44
+ type: Object,
45
+ default: () => ({})
46
+ },
47
+ inputAttributes: {
48
+ type: Object,
49
+ default: () => ({})
50
+ },
51
+ rootValue: {
52
+ type: Object,
53
+ default: () => ({})
54
+ },
55
+ propName: {
56
+ type: String,
57
+ default: ''
58
+ }
59
+ })
60
+
61
+ const uid = 'field_'+getCurrentInstance().uid.toFixed().padStart(6, '0')
62
+
63
+ const emit = defineEmits(['update:modelValue'])
64
+
65
+ const { error, definition, modelValue } = toRefs(props)
66
+
67
+ const definitionIf = computed(() => {
68
+ if(definition.value?.if) {
69
+ if(definition.value?.if.function) {
70
+ return eval(`(${definition.value.if.function})`)
71
+ }
72
+ }
73
+ return false
74
+ })
75
+
76
+ const visible = computed(() => {
77
+ if(!definition.value) return false
78
+ if(definitionIf.value) {
79
+ return definitionIf.value({
80
+ source: definition.value,
81
+ props: props.rootValue,
82
+ propName: props.propName
83
+ })
84
+ }
85
+ return true
86
+ })
87
+
88
+ import { validateData } from "@live-change/vue3-components"
89
+
90
+ const validationResult = computed(() => {
91
+ const validationResult = validateData(definition.value, modelValue.value, 'validation')
92
+ const softValidationResult = validateData(definition.value, modelValue.value, 'softValidation')
93
+ return validationResult || softValidationResult || error.value
94
+ })
95
+
96
+ const inputConfig = computed(() => {
97
+ if(definition.value.input) return inputs[definition.value.input]
98
+ if(definition.value.type) return types[definition.value.type]
99
+ return inputs.default
100
+ })
101
+
102
+ const label = computed(() => props.label || definition.value.label || props.name)
103
+
104
+ const fieldClass = computed(() => [inputConfig.value?.fieldClass, definition.value?.fieldClass, props.class, {
105
+ 'p-invalid': !!error.value
106
+ }])
107
+ const fieldStyle = computed(() => [inputConfig.value?.fieldStyle, definition.value?.fieldStyle, props.style])
108
+
109
+ const configAttributes = computed(() => {
110
+ const attributes = inputConfig.value?.fieldAttributes
111
+ if(!attributes) return attributes
112
+ if(typeof attributes == 'function') return attributes(definition.value)
113
+ return attributes
114
+ })
115
+
116
+ const attributes = computed(() => ({
117
+ ...(configAttributes.value),
118
+ ...(props.attributes),
119
+ label: props.label,
120
+ modelValue: props.modelValue,
121
+ definition: props.definition,
122
+ class: fieldClass.value,
123
+ style: fieldStyle.value,
124
+ inputClass: [props.inputClass, { 'p-invalid': !!validationResult.value }],
125
+ inputStyle: props.inputStyle,
126
+ rootValue: props.rootValue,
127
+ propName: props.propName,
128
+ }))
129
+
130
+ const fieldComponent = computed(() => inputConfig.value?.fieldComponent)
131
+
132
+
133
+ </script>
134
+
135
+ <style scoped>
136
+
137
+ </style>
package/AutoInput.vue CHANGED
@@ -1,12 +1,16 @@
1
1
  <template>
2
- <component v-if="inputConfig" :is="inputConfig.component" v-bind="properties" @update:modelValue="updateValue"
3
- :class="props.class" :style="props.style" />
4
- <div v-else class="font-bold text-red-600">No input found for definition {{ JSON.stringify(definition) }}</div>
2
+ <component v-if="inputConfig && visible" :is="inputConfig.component" v-bind="attributes"
3
+ @update:modelValue="updateValue" :class="inputClass" :style="inputStyle" />
4
+ <div v-else-if="visible" class="font-bold text-red-600">
5
+ No input found for definition:
6
+ <pre style="white-space: pre-wrap; word-wrap: break-word;">{{ JSON.stringify(definition, null, " ") }}</pre>
7
+ </div>
5
8
  </template>
6
9
 
7
10
  <script setup>
8
11
  import { inputs, types } from './config.js'
9
12
  import { computed, inject } from 'vue'
13
+ import { toRefs } from '@vueuse/core'
10
14
 
11
15
  const props = defineProps({
12
16
  modelValue: {
@@ -14,42 +18,74 @@
14
18
  definition: {
15
19
  type: Object
16
20
  },
17
- name: {
18
- type: String
19
- },
20
- class: {
21
- type: String
22
- },
23
- style: {
24
- type: String
25
- },
21
+ class: {},
22
+ style: {},
26
23
  properties: {
27
24
  type: Object,
28
25
  default: () => ({})
26
+ },
27
+ rootValue: {
28
+ type: Object,
29
+ default: () => ({})
30
+ },
31
+ propName: {
32
+ type: String,
33
+ default: ''
29
34
  }
30
35
  })
31
36
 
32
37
  const emit = defineEmits(['update:modelValue'])
33
38
 
34
- const form = inject('form')
39
+ const { definition, modelValue } = toRefs(props)
35
40
 
36
- const value = computed(() => props.name ? form.getFieldValue(props.name) : props.modelValue)
37
- const definition = computed(() => props.name ? form.getFieldDefinition(props.name) : props.definition)
38
41
  const inputConfig = computed(() => {
39
- console.log("definition", definition.value)
40
42
  if(definition.value.input) return inputs[definition.value.input]
41
43
  if(definition.value.type) return types[definition.value.type]
42
44
  return inputs.default
43
45
  })
44
46
 
45
- const properties = computed(() => ({
46
- ...(inputConfig.value.properties),
47
- ...(props.properties),
48
- modelValue: value.value
47
+ const definitionIf = computed(() => {
48
+ if(definition.value?.if) {
49
+ if(definition.value?.if.function) {
50
+ return eval(`(${definition.value.if.function})`)
51
+ }
52
+ }
53
+ return false
54
+ })
55
+
56
+ const visible = computed(() => {
57
+ if(!definition.value) return false
58
+ if(definitionIf.value) {
59
+ return definitionIf.value({
60
+ source: definition.value,
61
+ props: props.rootValue,
62
+ propName: props.propName
63
+ })
64
+ }
65
+ return true
66
+ })
67
+
68
+ const configAttributes = computed(() => {
69
+ const attributes = inputConfig.value?.attributes
70
+ if(!attributes) return attributes
71
+ if(typeof attributes == 'function') return attributes(definition.value)
72
+ return attributes
73
+ })
74
+
75
+ const attributes = computed(() => ({
76
+ ...(configAttributes.value),
77
+ ...(props.attributes),
78
+ ...(definition.value.inputAttributes),
79
+ modelValue: modelValue.value,
80
+ definition: definition.value,
81
+ rootValue: props.rootValue,
82
+ propName: props.propName
49
83
  }))
50
84
 
85
+ const inputClass = computed(() => [inputConfig.value?.inputClass, definition.value?.inputClass, props.class])
86
+ const inputStyle = computed(() => [inputConfig.value?.inputStyle, definition.value?.inputStyle, props.style])
87
+
51
88
  function updateValue(value) {
52
- if(props.name) form.setFieldValue(props.name, value)
53
89
  emit('update:modelValue', value)
54
90
  }
55
91
 
package/GroupField.vue ADDED
@@ -0,0 +1,96 @@
1
+ <template>
2
+ <div v-if="visible" class="pl-3 border-left-3 border-400 mb-3" :class="fieldClass" :style="fieldStyle">
3
+ <h3>{{ label }}:</h3>
4
+ <auto-input :modelValue="modelValue" :definition="definition" :name="props.name"
5
+ :class="props.inputClass" :style="props.inputStyle"
6
+ :properties="props.inputAttributes"
7
+ :rootValue="props.rootValue" :propName="props.propName"
8
+ @update:modelValue="value => emit('update:modelValue', value)" />
9
+ </div>
10
+ </template>
11
+
12
+ <script setup>
13
+ import AutoInput from "./AutoInput.vue"
14
+ import {inputs, types} from "./config";
15
+ import { computed, inject } from 'vue'
16
+ import { toRefs } from '@vueuse/core'
17
+
18
+ const props = defineProps({
19
+ modelValue: {},
20
+ error: {
21
+ type: String
22
+ },
23
+ definition: {
24
+ type: Object
25
+ },
26
+ name: {
27
+ type: String
28
+ },
29
+ label: {
30
+ type: String
31
+ },
32
+ class: {},
33
+ style: {},
34
+ inputClass: {},
35
+ inputStyle: {},
36
+ attributes: {
37
+ type: Object,
38
+ default: () => ({})
39
+ },
40
+ inputAttributes: {
41
+ type: Object,
42
+ default: () => ({})
43
+ },
44
+ rootValue: {
45
+ type: Object,
46
+ default: () => ({})
47
+ },
48
+ propName: {
49
+ type: String,
50
+ default: ''
51
+ }
52
+ })
53
+
54
+ const emit = defineEmits(['update:modelValue'])
55
+
56
+ const { error, definition, modelValue } = toRefs(props)
57
+
58
+ const definitionIf = computed(() => {
59
+ if(definition.value?.if) {
60
+ if(definition.value?.if.function) {
61
+ return eval(`(${definition.value.if.function})`)
62
+ }
63
+ }
64
+ return false
65
+ })
66
+
67
+ const visible = computed(() => {
68
+ if(!definition.value) return false
69
+ if(definitionIf.value) {
70
+ return definitionIf.value({
71
+ source: definition.value,
72
+ props: props.rootValue,
73
+ propName: props.propName
74
+ })
75
+ }
76
+ return true
77
+ })
78
+
79
+ const inputConfig = computed(() => {
80
+ if(definition.value?.input) return inputs[definition.value.input]
81
+ if(definition.value?.type) return types[definition.value.type]
82
+ return inputs.default
83
+ })
84
+
85
+ const label = computed(() => props.label || definition.value?.label || props.name)
86
+
87
+ const fieldClass = computed(() => [inputConfig.value?.fieldClass, definition.value?.fieldClass, props.class, {
88
+ 'p-invalid': !!error.value
89
+ }])
90
+ const fieldStyle = computed(() => [inputConfig.value?.fieldStyle, definition.value?.fieldStyle, props.style])
91
+
92
+ </script>
93
+
94
+ <style scoped>
95
+
96
+ </style>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <div>
3
+
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+
9
+
10
+ const props = defineProps({
11
+ modelValue: {
12
+ },
13
+ definition: {
14
+ type: Object
15
+ },
16
+ properties: {
17
+ type: Object,
18
+ default: () => ({})
19
+ }
20
+ })
21
+
22
+ const emit = defineEmits(['update:modelValue'])
23
+
24
+ const { value, definition, modelValue } = toRefs(props)
25
+
26
+ </script>
27
+
28
+ <style scoped>
29
+
30
+ </style>
package/config.js CHANGED
@@ -5,20 +5,39 @@ export const inputs = {
5
5
  export const types = {
6
6
  }
7
7
 
8
- export function input(src, params) {
8
+ export function input(src, config) {
9
9
  return {
10
- component: defineAsyncComponent(src),
11
- params,
12
- with(params) {
13
- return { component: this.component, params }
10
+ component: src && defineAsyncComponent(src),
11
+ ...config,
12
+ with(config) {
13
+ return { component: this.component, ...config }
14
14
  }
15
15
  }
16
16
  }
17
17
 
18
18
  types.String = inputs.decimal = input( () => import('primevue/inputtext'))
19
+ inputs.textarea = input(() => import('primevue/textarea'), { attributes: { autoResize: true } })
20
+
19
21
  inputs.password = input(() => import('primevue/password'))
20
22
 
21
23
  const number = input(() => import('primevue/inputnumber'))
22
24
  inputs.integer = number
23
- types.Number = inputs.decimal = number.with({ mode: 'decimal' })
25
+ types.Number = inputs.decimal = number.with({ attributes: { mode: 'decimal' } })
26
+
27
+ types.Object = inputs.object = input(() => import('./AutoEditor.vue'), {
28
+ fieldComponent: defineAsyncComponent(() => import('./GroupField.vue'))
29
+ })
30
+
31
+ types.Array = inputs.list = input(() => import('./ArrayInput.vue'), {
32
+ fieldComponent: defineAsyncComponent(() => import('./GroupField.vue'))
33
+ })
34
+
35
+ types.Date = inputs.datetime = input(() => import('primevue/calendar'), { attributes: { showTime: true } })
36
+
37
+ inputs.select = input(() => import('primevue/dropdown'), {
38
+ attributes: (definition) => ({ options: definition.options })
39
+ })
24
40
 
41
+ inputs.duration = input(() => import('primevue/inputmask'), {
42
+ attributes: { mask: '99:99:99' }
43
+ })
package/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import AutoInput from './AutoInput.vue'
2
+ import AutoField from './AutoField.vue'
3
+ import AutoEditor from './AutoEditor.vue'
2
4
 
3
- export { AutoInput }
5
+ export { AutoInput, AutoField, AutoEditor }
4
6
 
5
- import inputConfig from './config.js'
7
+ import * as inputConfig from './config.js'
6
8
  export { inputConfig }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/frontend-auto-form",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "scripts": {
5
5
  "memDev": "lcli memDev --enableSessions --initScript ./init.js --dbAccess",
6
6
  "localDevInit": "rm tmp.db; lcli localDev --enableSessions --initScript ./init.js",
@@ -28,8 +28,8 @@
28
28
  "@live-change/framework": "0.7.4",
29
29
  "@live-change/image-service": "0.3.2",
30
30
  "@live-change/session-service": "0.3.2",
31
- "@live-change/vue3-components": "0.2.15",
32
- "@live-change/vue3-ssr": "0.2.15",
31
+ "@live-change/vue3-components": "0.2.16",
32
+ "@live-change/vue3-ssr": "0.2.16",
33
33
  "@tiptap/extension-highlight": "^2.0.0-beta.33",
34
34
  "@tiptap/extension-underline": "2.0.0-beta.23",
35
35
  "@tiptap/starter-kit": "^2.0.0-beta.185",
@@ -66,5 +66,5 @@
66
66
  "author": "",
67
67
  "license": "ISC",
68
68
  "description": "",
69
- "gitHead": "323185f6d910912093b3c92df102d0f938cef367"
69
+ "gitHead": "72bd46680370e7804b168fec5dde28de205487e0"
70
70
  }