@ederzeel/nuxt-schema-form-nightly 0.1.0-29031029.c108247 → 0.1.0-29031030.c34683e

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.
@@ -0,0 +1,235 @@
1
+ <script lang="ts" setup>
2
+ import { Draft2019 } from 'json-schema-library'
3
+ import SComponent from './SComponent.vue'
4
+ import { ref, computed } from 'vue'
5
+
6
+ const props = defineProps<{
7
+ id: string
8
+ title?: string
9
+ description?: string
10
+ jsonSchemaPath: string
11
+ items: PropertiesType
12
+ modelValue: unknown[]
13
+ isRequired: boolean
14
+ minItems?: number
15
+ maxItems?: number
16
+ edit?: boolean
17
+ columns?: ColumnItem[]
18
+ editInline?: boolean
19
+ }>()
20
+
21
+ type ColumnItem = {
22
+ key: string
23
+ label?: string
24
+ class?: string
25
+ }
26
+
27
+ type PropertiesType = {
28
+ properties: {
29
+ [key: string]: unknown
30
+ }
31
+ [key: string]: unknown
32
+ }
33
+ const emit = defineEmits(['update:modelValue', 'submit'])
34
+ const onInput = (value: unknown, index: number) => {
35
+ props.modelValue[index] = value
36
+ emit('update:modelValue', props.modelValue)
37
+ }
38
+
39
+ const schemaObject = ref(new Draft2019(props.items))
40
+
41
+ const values = computed(() => {
42
+ if (props.modelValue.length > 0) {
43
+ return props.modelValue.map((x, i) => ({ ...x, __id: i }))
44
+ } else if (props.minItems && props.minItems > 0) {
45
+ const template = schemaObject.value.getTemplate()
46
+ return [...Array(props.minItems)].map((_, i) => ({ ...template, __id: i }))
47
+ }
48
+
49
+ return []
50
+ })
51
+
52
+ const add = () => {
53
+ emit('update:modelValue', [...props.modelValue, schemaObject.value.getTemplate()])
54
+ }
55
+
56
+ const remove = (index: number) => {
57
+ const res = props.modelValue.splice(index, 1)
58
+ emit('update:modelValue', res)
59
+ }
60
+
61
+ const massRemove = () => {
62
+ let res = props.modelValue
63
+ for (const index of selectedRows.value.map(x => x.__id)) {
64
+ res.splice(index, 1)
65
+ }
66
+
67
+ emit('update:modelValue', res)
68
+ }
69
+
70
+ const model = ref({
71
+ open: false,
72
+ index: 0
73
+ })
74
+
75
+ const open = (index: number) => {
76
+ model.value = { open: true, index: index }
77
+ }
78
+
79
+ const actions = (i: number) => [
80
+ [
81
+ {
82
+ label: 'edit',
83
+ click: () => open(i)
84
+ }
85
+ ],
86
+ [
87
+ {
88
+ label: 'delete',
89
+ click: () => {
90
+ remove(i)
91
+ selectedRows.value = []
92
+ }
93
+ }
94
+ ]
95
+ ]
96
+
97
+ const massActions = [
98
+ [
99
+ {
100
+ label: 'delete',
101
+ click: () => {
102
+ massRemove()
103
+ selectedRows.value = []
104
+ }
105
+ }
106
+ ]
107
+ ]
108
+
109
+ const columns = computed(() => {
110
+ const columns = props.columns ?? []
111
+
112
+ if (props.items.type === 'object') {
113
+ for (const column of Object.keys(props?.items?.properties).map(x => ({ key: x, label: x }))) {
114
+ columns.push(column)
115
+ }
116
+ }
117
+
118
+ if (props.edit) {
119
+ columns.push({
120
+ key: 'actions',
121
+ class: 'w-2'
122
+ })
123
+ }
124
+
125
+ return columns
126
+ })
127
+
128
+ const selectedRows = ref([])
129
+
130
+ const todoStatus = [
131
+ {
132
+ key: 'uncompleted',
133
+ label: 'In Progress',
134
+ value: false
135
+ },
136
+ {
137
+ key: 'completed',
138
+ label: 'Completed',
139
+ value: true
140
+ }
141
+ ]
142
+
143
+ const expand = ref({
144
+ openedRows: [],
145
+ row: null
146
+ })
147
+
148
+ const options = computed(() => {
149
+ const res = {}
150
+ if (props.edit) {
151
+ res.modelValue = selectedRows.value
152
+ res['onUpdate:modelValue'] = value => (selectedRows.value = value)
153
+ }
154
+ if (props.editInline) {
155
+ res.expand = expand.value
156
+ res['update:expand'] = value => (expand.value = value)
157
+ }
158
+ return res
159
+ })
160
+ </script>
161
+
162
+ <template>
163
+ <div>
164
+ <h2 v-if="props.title" class="mb-4 text-2xl leading-none tracking-tight">{{ props.title }}</h2>
165
+ <p v-if="props.description" class="mb-4">{{ props.description }}</p>
166
+
167
+ <div>
168
+ <div class="flex justify-between items-center w-full px-4 py-3">
169
+ <div class="flex gap-1.5 items-center">
170
+ <UButton
171
+ v-if="edit"
172
+ :disabled="maxItems && values.length >= maxItems"
173
+ @click="add"
174
+ icon="i-heroicons-plus"
175
+ trailing
176
+ color="gray"
177
+ size="xs"
178
+ />
179
+ </div>
180
+ <div class="flex gap-1.5 items-center">
181
+ <UDropdown v-if="selectedRows.length > 0" :items="massActions">
182
+ <UButton icon="i-heroicons-chevron-down" trailing color="gray" size="xs"> Action </UButton>
183
+ </UDropdown>
184
+ </div>
185
+ </div>
186
+ <UTable v-bind="options" by="__id" :rows="values" :columns="columns">
187
+ <template #name-data="{ row }">
188
+ <span :class="[selected.find(person => person.id === row.id) && 'text-primary-500 dark:text-primary-400']">{{
189
+ row.name
190
+ }}</span>
191
+ </template>
192
+
193
+ <template #expand="{ row, index }">
194
+ <div class="p-4">
195
+ <SComponent
196
+ :id="id.length <= 0 ? `${index}` : `${id}[${index}].${items.id}`"
197
+ :model-value="row"
198
+ :json-schema-path="jsonSchemaPath?.length <= 0 ? `properties.${index}` : `${jsonSchemaPath}[${index}]`"
199
+ v-bind="items"
200
+ :isRequired="false"
201
+ class="mt-4"
202
+ @update:model-value="event => onInput(event, index)"
203
+ @submit="() => emit('submit')"
204
+ />
205
+ </div>
206
+ </template>
207
+
208
+ <template #actions-data="{ index }">
209
+ <UDropdown :items="actions(index)">
210
+ <UButton color="gray" variant="ghost" icon="i-heroicons-ellipsis-horizontal-20-solid" />
211
+ </UDropdown>
212
+ </template>
213
+ </UTable>
214
+ </div>
215
+ <UModal v-model="model.open">
216
+ <UCard>
217
+ <SComponent
218
+ :id="id.length <= 0 ? `${model.index}` : `${id}[0].${items.id}`"
219
+ :model-value="values[model.index]"
220
+ :json-schema-path="
221
+ jsonSchemaPath?.length <= 0 ? `properties.${model.index}` : `${jsonSchemaPath}[${model.index}]`
222
+ "
223
+ v-bind="items"
224
+ :isRequired="false"
225
+ class="mt-4"
226
+ @update:model-value="event => onInput(event, model.index)"
227
+ @submit="() => emit('submit')"
228
+ />
229
+ <template #footer>
230
+ <UButton>Save</UButton>
231
+ </template>
232
+ </UCard>
233
+ </UModal>
234
+ </div>
235
+ </template>
@@ -9,7 +9,7 @@ export type SComponentProps = {
9
9
  id?: string
10
10
  title?: string
11
11
  renderer?: string
12
- type: string
12
+ type?: string
13
13
  properties?: Properties
14
14
  enum?: string[]
15
15
  enum_titles?: string[]
@@ -18,10 +18,15 @@ export type SComponentProps = {
18
18
  jsonSchemaPath?: string
19
19
  required?: string[]
20
20
  isRequired: boolean
21
+ items?: { [key: string]: unknown }
22
+ edit?: boolean
23
+ minItems?: number
24
+ maxItems?: number
25
+ editInline?: boolean
21
26
  validateFields?: (fields: string[]) => Promise<boolean>
22
27
  }
23
28
 
24
- const props = withDefaults(defineProps<SComponentProps>(), { id: '', jsonSchemaPath: 'test' })
29
+ const props = withDefaults(defineProps<SComponentProps>(), { id: '', jsonSchemaPath: '' })
25
30
  const value = defineModel<unknown>({ required: true, default: '' })
26
31
  const emit = defineEmits(['submit'])
27
32
 
@@ -36,13 +41,19 @@ const onSubmit = () => {
36
41
 
37
42
  <template>
38
43
  <div class="s-form-group">
39
- <component v-if="renderer" v-bind="options" v-model="value"
40
- :is="typeof renderer === 'string' ? renderer : undefined" @submit="onSubmit" />
44
+ <component
45
+ v-if="renderer"
46
+ v-bind="options"
47
+ v-model="value"
48
+ :is="typeof renderer === 'string' ? renderer : undefined"
49
+ @submit="onSubmit"
50
+ />
41
51
 
42
52
  <SDate v-else-if="type === 'string' && format === 'full-date'" v-bind="options" v-model="value" />
43
53
  <SInputField v-else-if="type === 'string'" v-bind="options" v-model="value" />
44
54
  <SToggle v-else-if="type === 'boolean'" v-bind="options" v-model="value" />
45
55
  <SObject v-else-if="type === 'object'" v-bind="options" v-model="value" @submit="onSubmit" />
56
+ <SArray v-else-if="type === 'array'" v-bind="options" v-model="value" />
46
57
  <div v-else>else</div>
47
58
  </div>
48
59
  </template>
@@ -52,14 +52,19 @@ const submit = () => {
52
52
 
53
53
  <template>
54
54
  <div>
55
- <!-- {{ formRef ? formRef.errors : undefined }} -->
55
+ {{ formRef ? formRef.errors : undefined }}
56
56
  <UForm ref="formRef" :state="value" :schema="formValidationSchema" autocomplete="on" @submit="onSubmit">
57
- <SComponent v-model="value" v-bind="schema" :validate-fields="validateFields" @submit="submit"
58
- :isRequired="true" />
57
+ <SComponent
58
+ v-model="value"
59
+ v-bind="schema"
60
+ :validate-fields="validateFields"
61
+ @submit="submit"
62
+ :isRequired="true"
63
+ />
59
64
  <slot />
60
65
 
61
66
  <slot name="submit">
62
- <UButton class="btn" type="submit"> Submit </UButton>
67
+ <UButton class="btn mt-4" type="submit"> Submit </UButton>
63
68
  </slot>
64
69
  </UForm>
65
70
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ederzeel/nuxt-schema-form-nightly",
3
- "version": "0.1.0-29031029.c108247",
3
+ "version": "0.1.0-29031030.c34683e",
4
4
  "description": "A runtime form generator for nuxt",
5
5
  "type": "module",
6
6
  "exports": {