@ramathibodi/nuxt-commons 0.1.38 → 0.1.40

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/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.0.0"
6
6
  },
7
- "version": "0.1.38",
7
+ "version": "0.1.40",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.3",
10
10
  "unbuild": "2.0.0"
@@ -0,0 +1,43 @@
1
+ <script lang="ts" setup>
2
+ import {ref, withDefaults,watch,computed} from 'vue'
3
+ import {graphqlOperation} from '#imports'
4
+
5
+ interface Props {
6
+ templateCode: string
7
+ parentTemplates?: string|string[]
8
+ }
9
+
10
+ const props = withDefaults(defineProps<Props>(), {
11
+ parentTemplates: (): string[] => [],
12
+ })
13
+
14
+ const template = ref<any>()
15
+ const templateScript = ref<string>()
16
+
17
+ const parentTemplates = computed(()=>{
18
+ if (typeof props.parentTemplates === 'string') {
19
+ if (props.parentTemplates && props.parentTemplates!="") return props.parentTemplates.split("|")
20
+ else return []
21
+ } else {
22
+ return props.parentTemplates
23
+ }
24
+ })
25
+
26
+ const parentTemplatesNext = computed(()=>{
27
+ return [...parentTemplates.value,props.templateCode]
28
+ })
29
+
30
+ watch(()=>props.templateCode,()=>{
31
+ if (!parentTemplates.value.includes(props.templateCode) && props.templateCode) {
32
+ if (graphqlOperation["documentTemplateByTemplateCode"]) {
33
+ graphqlOperation["documentTemplateByTemplateCode"].call(["*"],{templateCode: props.templateCode}).then((result: any)=>{
34
+ template.value = result.editTemplate
35
+ templateScript.value = result.templateScript
36
+ })
37
+ }
38
+ }
39
+ },{immediate: true})
40
+ </script>
41
+ <template>
42
+ <form-pad :template="template" :template-script="templateScript" :parent-templates="parentTemplatesNext"></form-pad>
43
+ </template>
@@ -2,7 +2,15 @@
2
2
  import {computed, ref, watch} from 'vue'
3
3
  import * as prettier from 'prettier'
4
4
  import prettierPluginHtml from 'prettier/plugins/html'
5
- import {useDocumentTemplate, validationRulesRegex} from '../../composables/document/template'
5
+ import {useDocumentTemplate, validationRulesRegex,optionStringToChoiceObject} from '../../composables/document/template'
6
+
7
+ interface Props {
8
+ title?: string
9
+ }
10
+
11
+ const props = withDefaults(defineProps<Props>(), {
12
+ title: "Document Template"
13
+ })
6
14
 
7
15
  const emit = defineEmits(['update:modelValue'])
8
16
  const modelValue = defineModel<string>()
@@ -49,6 +57,33 @@ const headers = ref([
49
57
  },
50
58
  ])
51
59
 
60
+ const formTableHeaders = ref([
61
+ {
62
+ title: 'Title',
63
+ key: 'title',
64
+ },
65
+ {
66
+ title: 'Key',
67
+ key: 'key',
68
+ },
69
+ {
70
+ title: 'Width',
71
+ key: 'width',
72
+ },
73
+ ])
74
+
75
+ const choiceHeaders = ref([
76
+ {
77
+ title: 'Label',
78
+ key: 'label',
79
+ },
80
+ {
81
+ title: 'Value',
82
+ key: 'value',
83
+ },
84
+ ])
85
+
86
+
52
87
  function isValidJsonArrayOfObjects(str: string | undefined) {
53
88
  try {
54
89
  const parsed = JSON.parse(str as string)
@@ -72,17 +107,48 @@ async function convertToAdvanceMode() {
72
107
  modelValue.value = await prettier.format(useDocumentTemplate(templateItems.value).replaceAll('>', '>\n'), { parser: 'html', plugins: [prettierPluginHtml] })
73
108
  }
74
109
  }
110
+ const inputTypeChoice = ref([
111
+ { label: 'Text Field', value: 'VTextField' },
112
+ { label: 'Text Area', value: 'VTextarea' },
113
+ { label: 'Text Date Picker', value: 'FormDate' },
114
+ { label: 'Text Time Picker', value: 'FormTime' },
115
+ { label: 'Text Date & Time Picker', value: 'FormDateTime' },
116
+ { label: 'Select Dropdown', value: 'VSelect' },
117
+ { label: 'Select Combobox', value: 'VCombobox' },
118
+ { label: 'Autocomplete', value: 'VAutocomplete' },
119
+ { label: 'Autocomplete from Master', value: 'MasterAutocomplete' },
120
+ { label: 'Radio Buttons', value: 'VRadio' },
121
+ { label: 'Radio Buttons Inline', value: 'VRadioInline' },
122
+ { label: 'Checkbox', value: 'VCheckbox' },
123
+ { label: 'Switch', value: 'VSwitch' },
124
+ { label: 'File Upload', value: 'FormFile' },
125
+ { label: 'Signature Pad', value: 'FormSignPad' },
126
+ { label: 'Table', value: 'FormTable' },
127
+ { label: '[Decoration] Header', value: 'Header' },
128
+ { label: '[Decoration] Separator', value: 'Separator' },
129
+ { label: '[Advanced] Hidden Field', value: 'FormHidden' },
130
+ { label: '[Advanced] Inherit Form', value: 'DocumentForm' },
131
+ { label: '[Advanced] Custom Code', value: 'CustomCode' },
132
+ ]);
133
+
134
+ const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete','FormTable','DocumentForm'])
135
+ const notRequireVariable = ref(['Header', 'Separator', 'CustomCode','DocumentForm'])
136
+ const notRequireLabel = ref(['Separator', 'CustomCode', 'FormFile', 'FormHidden','DocumentForm'])
137
+ const notRequireWidth = ref(['Separator', 'FormHidden','DocumentForm'])
138
+ const notRequireOptions = ref(['Separator','CustomCode', 'FormFile'])
139
+ const notRequireRules = ref(['Separator','Header','CustomCode','FormHidden','DocumentForm'])
140
+ const notRequireInputAttributes = ref(['CustomCode','Header', 'FormHidden','DocumentForm'])
141
+ const notRequireColumnAttributes = ref(['Separator', 'FormHidden','DocumentForm'])
142
+ const notRequireAdvancedSetting = ref(['Separator','CustomCode', 'FormHidden'])
75
143
 
76
- const inputTypeChoice = ref(['VTextField', 'VTextarea', 'VSelect', 'VAutocomplete', 'FormDate', 'FormTime', 'FormDateTime', 'VCombobox', 'VRadio', 'VRadioInline', 'VCheckbox', 'VSwitch', 'MasterAutocomplete', 'Header', 'Separator', 'CustomCode', 'FormTable', 'FormHidden', 'FormFile', 'FormSignPad'])
77
- const requireOption = ref(['VSelect', 'VAutocomplete', 'VCombobox', 'VRadio', 'VRadioInline', 'MasterAutocomplete'])
78
- const notRequireVariable = ref(['Header', 'Separator', 'CustomCode'])
79
- const notRequireLabel = ref(['Separator', 'CustomCode', 'FormFile', 'FormSignPad', 'FormTable', 'FormHidden'])
80
- const notRequireOptions = ref(['CustomCode', 'FormSignPad', 'FormFile', 'FormTable'])
81
- const notRequireRules = ref(['CustomCode', 'FormSignPad', 'FormFile', 'FormTable' ,'FormHidden'])
82
- const notRequireInputAttributes = ref(['CustomCode', 'FormHidden'])
83
- const notRequireColumnAttributes = ref(['Separator', 'FormHidden'])
144
+ const hasSpecificOption = ref(['FormHidden','FormTable'])
84
145
 
85
- const choiceOption = ref(['VSelect', 'VRadio', 'VRadioInline'])
146
+ const choiceOption = ref(['VRadio', 'VRadioInline','VSelect', 'VAutocomplete', 'VCombobox'])
147
+ const inputOptionsLabel = ref<Record<string,string>>({
148
+ 'MasterAutocomplete' : "Group Key",
149
+ 'Header' : "Class",
150
+ 'DocumentForm': "Template Code",
151
+ })
86
152
 
87
153
  const ruleOptions = (inputType: string) => (value: any) => {
88
154
  if (choiceOption.value.includes(inputType) && !(/^[^'",]+(,[^'",]+)*$/.test(value))) return 'Invalid options format'
@@ -96,7 +162,7 @@ const ruleOptions = (inputType: string) => (value: any) => {
96
162
  v-if="!isAdvanceMode"
97
163
  v-model="templateItems"
98
164
  :headers="headers"
99
- title="Document Template"
165
+ :title="props.title"
100
166
  >
101
167
  <template #toolbarItems>
102
168
  <VBtn
@@ -118,19 +184,20 @@ const ruleOptions = (inputType: string) => (value: any) => {
118
184
  v-model="data.inputType"
119
185
  label="Input Type"
120
186
  :items="inputTypeChoice"
187
+ item-title="label"
188
+ item-value="value"
189
+ :return-object="false"
121
190
  :rules="[rules.require()]"
122
191
  />
123
192
  </v-col>
124
- <v-col
125
- v-if="data.inputType!='Separator'"
126
- cols="1"
127
- >
193
+ <v-col cols="1" v-if="!notRequireWidth.includes(data.inputType)">
128
194
  <v-text-field
129
195
  v-model="data.width"
130
196
  label="Width"
131
197
  :rules="[rules.require()]"
132
198
  type="number"
133
199
  />
200
+ <form-hidden v-model="data.inputOptions" :item-value="data.inputType" :hook="()=>undefined"></form-hidden>
134
201
  </v-col>
135
202
  <v-col cols="4" v-if="!notRequireLabel.includes(data.inputType)">
136
203
  <v-text-field
@@ -150,32 +217,67 @@ const ruleOptions = (inputType: string) => (value: any) => {
150
217
  v-if="!notRequireOptions.includes(data.inputType)"
151
218
  cols="12"
152
219
  >
220
+ <form-pad v-model="data.inputOptions" v-if="data.inputType=='FormTable'">
221
+ <template #default="{data: optionData}">
222
+ <v-row dense>
223
+ <v-col cols="12">
224
+ <form-table v-model="optionData.headers" :headers="formTableHeaders" title="Headers">
225
+ <template #form="{data: headerData,rules}">
226
+ <v-container fluid>
227
+ <v-row dense>
228
+ <v-col cols="6"><v-text-field v-model="headerData.title" label="Title"></v-text-field></v-col>
229
+ <v-col cols="3"><v-text-field v-model="headerData.key" label="Key" :rules="[rules.require()]"></v-text-field></v-col>
230
+ <v-col cols="3"><v-text-field v-model="headerData.width" label="Width"></v-text-field></v-col>
231
+ </v-row>
232
+ </v-container>
233
+ </template>
234
+ </form-table>
235
+ </v-col>
236
+ <v-col cols="12">
237
+ <document-template-builder v-model="optionData.formTemplate" title="Form Template"></document-template-builder>
238
+ </v-col>
239
+ </v-row>
240
+ </template>
241
+ </form-pad>
242
+ <form-pad v-model="data.inputOptions" v-if="data.inputType=='FormHidden'">
243
+ <template #default="{data: optionData}">
244
+ <v-row dense>
245
+ <v-col cols="12">
246
+ <v-text-field
247
+ v-model="optionData.hook"
248
+ label="Hook"
249
+ :rules="[rules.require()]"
250
+ />
251
+ </v-col>
252
+ <v-col cols="12">
253
+ <v-text-field
254
+ v-model="optionData.itemValue"
255
+ label="Item Value"
256
+ />
257
+ </v-col>
258
+ </v-row>
259
+ </template>
260
+ </form-pad>
261
+ <form-table v-model="data.inputOptions" :headers="choiceHeaders" title="Choices" v-if="choiceOption.includes(data.inputType) && (!data.inputOptions || typeof data.inputOptions === 'object')">
262
+ <template #form="{data: optionData,rules}">
263
+ <v-container fluid>
264
+ <v-row dense>
265
+ <v-col cols="6"><v-text-field v-model="optionData.label" label="Label"></v-text-field></v-col>
266
+ <v-col cols="6"><v-text-field v-model="optionData.value" label="Value" :rules="[rules.require()]"></v-text-field></v-col>
267
+ </v-row>
268
+ </v-container>
269
+ </template>
270
+ </form-table>
271
+ <form-hidden v-model="data.inputOptions" :itemValue="data.inputOptions" :hook="(option: any)=>optionStringToChoiceObject(option)" v-if="choiceOption.includes(data.inputType) && data.inputOptions && typeof data.inputOptions === 'string'"></form-hidden>
153
272
  <v-textarea
154
273
  v-model="data.inputOptions"
155
- label="Input Options"
274
+ :label="inputOptionsLabel[data.inputType] || 'Input Options'"
156
275
  auto-grow
157
276
  :rules="[rules.requireIf(requireOption.includes(data.inputType)), ruleOptions(data.inputType)]"
277
+ v-if="!hasSpecificOption.includes(data.inputType) && !choiceOption.includes(data.inputType)"
158
278
  />
159
279
  </v-col>
160
- <v-col v-if="data.inputType!='CustomCode'">
161
- <v-text-field
162
- v-model="data.validationRules"
163
- label="Validation Rules"
164
- :rules="[rules.regex(validationRulesRegex)]"
165
- />
166
- </v-col>
167
- <v-col v-if="data.inputType!='CustomCode'">
168
- <v-text-field
169
- v-model="data.inputAttributes"
170
- label="Input Attributes"
171
- />
172
- </v-col>
173
- <v-col v-if="data.inputType!='Separator'">
174
- <v-text-field
175
- v-model="data.columnAttributes"
176
- label="Column Attributes"
177
- />
178
- </v-col>
280
+
179
281
  <v-col
180
282
  v-if="data.inputType=='CustomCode'"
181
283
  cols="12"
@@ -186,25 +288,67 @@ const ruleOptions = (inputType: string) => (value: any) => {
186
288
  :rules="[rules.require()]"
187
289
  />
188
290
  </v-col>
189
- <v-col
190
- v-if="data.inputType=='FormTable'"
191
- cols="12"
192
- >
193
- <FormCodeEditor
194
- v-model="data.inputFormTable"
195
- label="Form Table"
196
- :rules="[rules.require()]"
197
- />
198
- </v-col>
199
- <v-col
200
- v-if="data.inputType=='FormHidden'"
201
- cols="12"
202
- >
203
- <FormCodeEditor
204
- v-model="data.inputFormHidden"
205
- label="Form Table"
206
- :rules="[rules.require()]"
207
- />
291
+ </v-row>
292
+ <v-row dense>
293
+ <v-col>
294
+ <v-expansion-panels>
295
+ <v-expansion-panel v-if="!notRequireRules.includes(data.inputType)">
296
+ <v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Validations</v-expansion-panel-title>
297
+ <v-expansion-panel-text>
298
+ <v-container fluid>
299
+ <v-row dense>
300
+ <v-col cols="12">
301
+ <v-text-field
302
+ v-model="data.validationRules"
303
+ label="Validation Rules"
304
+ :rules="[rules.regex(validationRulesRegex)]"
305
+ />
306
+ <b>Available rules :</b> require, requireIf(condition), requireTrue, requireTrueIf(condition), numeric, range(min,max), integer, unique, length(length), lengthGreater(length), lengthLess(length), telephone, email, regex(regex), idcard, DateFuture, DatetimeFuture, DateHappen, DatetimeHappen, DateAfter(date), DateBefore(Date), DateEqual(date)
307
+ </v-col>
308
+ </v-row>
309
+ </v-container>
310
+ </v-expansion-panel-text>
311
+ </v-expansion-panel>
312
+ <v-expansion-panel v-if="!notRequireAdvancedSetting.includes(data.inputType)">
313
+ <v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Advanced settings</v-expansion-panel-title>
314
+ <v-expansion-panel-text>
315
+ <v-container fluid>
316
+ <v-row dense>
317
+ <v-col cols="12" md="6" v-if="!notRequireInputAttributes.includes(data.inputType)">
318
+ <v-text-field
319
+ v-model="data.inputAttributes"
320
+ label="Input Attributes"
321
+ />
322
+ </v-col>
323
+ <v-col cols="12" md="6" v-if="!notRequireColumnAttributes.includes(data.inputType)">
324
+ <v-text-field
325
+ v-model="data.columnAttributes"
326
+ label="Column Attributes"
327
+ />
328
+ </v-col>
329
+ <v-col cols="12" md="6">
330
+ <v-text-field
331
+ v-model="data.conditionalDisplay"
332
+ label="Conditional Display"
333
+ />
334
+ </v-col>
335
+ <v-col cols="12" md="6">
336
+ <v-text-field
337
+ v-model="data.computedValue"
338
+ label="Computed Value"
339
+ />
340
+ </v-col>
341
+ <v-col cols="12" md="6">
342
+ <v-text-field
343
+ v-model="data.retrievedValue"
344
+ label="Retrieved Value"
345
+ />
346
+ </v-col>
347
+ </v-row>
348
+ </v-container>
349
+ </v-expansion-panel-text>
350
+ </v-expansion-panel>
351
+ </v-expansion-panels>
208
352
  </v-col>
209
353
  </v-row>
210
354
  </v-container>
@@ -223,14 +367,6 @@ const ruleOptions = (inputType: string) => (value: any) => {
223
367
  <template v-if="props.item.inputAttributes">
224
368
  <b>Input Attributes :</b> {{ props.item.inputAttributes }}<br>
225
369
  </template>
226
- <template v-if="props.item.inputType=='FormTable'">
227
- <b>Form Table :</b><br>
228
- <span style="white-space: pre-line">{{ props.item.inputFormTable }}</span>
229
- </template>
230
- <template v-if="props.item.inputType=='FormHidden'">
231
- <b>Form Hidden :</b><br>
232
- <span style="white-space: pre-line">{{ props.item.inputFormHidden }}</span>
233
- </template>
234
370
  </template>
235
371
  </FormTable>
236
372
  <FormCodeEditor
@@ -30,6 +30,7 @@ interface Props {
30
30
  readonly?: boolean
31
31
  isolated?: boolean
32
32
  decoration?: object
33
+ parentTemplates?: string|string[]
33
34
  }
34
35
 
35
36
  const props = withDefaults(defineProps<Props>(), {
@@ -37,6 +38,7 @@ const props = withDefaults(defineProps<Props>(), {
37
38
  readonly: false,
38
39
  isolated: false,
39
40
  decoration: () => { return {} },
41
+ parentTemplates: (): string[] => [],
40
42
  })
41
43
 
42
44
  const emit = defineEmits(['update:modelValue'])
@@ -89,7 +91,7 @@ const formComponent = shallowRef()
89
91
  function buildFormComponent() {
90
92
  if (!trimmedTemplate.value) return
91
93
  const originalConsoleError = console.warn
92
- console.warn = (error) => { throw new Error(error) } // eslint-disable-line
94
+ console.warn = (error: any) => { throw new Error(error) } // eslint-disable-line
93
95
  try {
94
96
  const componentTemplate = '<form-pad ref="formPadTemplate" v-model="formComponentData" :disabled="disabled" :readonly="readonly" :decoration="decoration" :isolated="isolated"><template v-slot="{ data,isDisabled,isReadonly,rules,formProvided,decoration }">' + trimmedTemplate.value + '</template></form-pad>'
95
97
  compile(componentTemplate)
@@ -159,7 +161,7 @@ onMounted(() => {
159
161
  })
160
162
 
161
163
  watchDebounced(() => props.template, (newValue) => {
162
- trimmedTemplate.value = useDocumentTemplate(newValue).trim() || ''
164
+ trimmedTemplate.value = useDocumentTemplate(newValue,props.parentTemplates).trim() || ''
163
165
  buildFormComponent()
164
166
  }, { debounce: 500, maxWait: 5000, deep: true, immediate: true })
165
167
  watchDebounced(() => props.templateScript, buildFormComponent, { debounce: 500, maxWait: 5000 })
@@ -1,113 +1,56 @@
1
1
  <script lang="ts" setup>
2
2
  import {VAutocomplete} from 'vuetify/components/VAutocomplete'
3
- import {concat, isEmpty, sortBy} from 'lodash-es'
4
- import {computed, ref, watch,watchEffect} from 'vue'
5
- import {watchDebounced} from '@vueuse/core'
6
- import {useFuzzy} from '../../composables/utils/fuzzy'
7
- import {useGraphQl} from '../../composables/graphql'
3
+ import {concat} from 'lodash-es'
4
+ import {computed} from 'vue'
8
5
 
9
6
  interface Props extends /* @vue-ignore */ InstanceType<typeof VAutocomplete['$props']> {
10
- fuzzy?: boolean
7
+ sortBy?: 'itemCode' | 'itemValue'
8
+ showCode?: boolean
9
+
11
10
  groupKey: string
11
+ itemCodes?: string[]
12
12
  lang?: 'TH' | 'EN'
13
- fields?: string[]
13
+ fields?: Array<string | object>
14
14
  noDataText?: string
15
15
  filterText?: string
16
16
  waitForFilter?: boolean
17
17
  waitForFilterText?: string
18
- modelValue?: string
19
- sortBy?: 'itemCode' | 'itemValue'
20
- showCode?: boolean
21
18
  }
22
19
 
23
20
  const props = withDefaults(defineProps<Props>(), {
24
- fuzzy: false,
25
- noDataText: 'ไม่พบข้อมูล',
21
+ sortBy: 'itemValue',
22
+ showCode: false,
23
+
26
24
  lang: 'TH',
25
+ noDataText: 'ไม่พบข้อมูล',
27
26
  waitForFilter: false,
28
- sortBy: 'itemValue',
29
- showCode: false
30
27
  })
31
28
 
32
- const emit = defineEmits(['update:modelValue'])
33
-
34
- const masterItems = ref<Array<any>>([])
35
- const items = ref<Array<any>>([])
36
- const selectedItem = ref<any>()
37
-
38
- const searchData = ref<string>('')
39
-
40
- const isLoading = ref(false)
41
- const isErrorLoading = ref(false)
42
-
43
- function query(groupKey: string, filterText: string | undefined) {
29
+ const computedModelName = computed(()=>{
44
30
  let operation = 'masterItemByGroupKey'
31
+ if (props.filterText) operation = 'masterItemByGroupKeyAndFilterText'
32
+ if (props.itemCodes && props.itemCodes.length>0) operation = 'masterItemByGroupKeyAndItemCodeIn'
33
+ if (props.waitForFilter && !props.filterText) operation = ""
34
+ return operation
35
+ })
45
36
 
46
- const variables: Record<string, any> = { groupKey: { value: groupKey, required: true } }
47
- if (filterText) {
48
- variables['filterText'] = { value: filterText }
49
- operation = 'masterItemByGroupKeyAndFilterText'
37
+ const computedModelBy = computed(()=>{
38
+ let modelBy : Record<string,any> = {groupKey: props.groupKey}
39
+ if (props.filterText) {
40
+ modelBy["filterText"] = props.filterText
50
41
  }
51
-
52
- let fields: any[] = ['itemCode', 'itemValue', 'itemValueAlternative']
53
- if (props.fields) fields = concat(fields, props.fields)
54
-
55
- isLoading.value = true
56
-
57
- useGraphQl().queryPromise(operation, fields, variables).then((result: any) => {
58
- masterItems.value = result
59
- items.value = result
60
- isErrorLoading.value = false
61
- }).catch((_error) => {
62
- isErrorLoading.value = true
63
- }).finally(() => {
64
- isLoading.value = false
65
- })
66
- }
67
-
68
- watchEffect(()=>{
69
- if (props.waitForFilter && !props.filterText) {
70
- masterItems.value = []
71
- items.value = []
72
- selectedItem.value = undefined
73
- } else {
74
- query(props.groupKey, props.filterText)
42
+ if (props.itemCodes && props.itemCodes.length>0) {
43
+ modelBy["itemCodes"] = props.itemCodes
75
44
  }
45
+ return modelBy
76
46
  })
77
47
 
78
- watch(() => props.modelValue, (newValue) => {
79
- selectedItem.value = newValue
80
- }, { immediate: true })
81
-
82
- watch(selectedItem, (newValue) => {
83
- emit('update:modelValue', newValue)
48
+ const computedFields = computed(()=>{
49
+ return concat(['itemCode', 'itemValue', 'itemValueAlternative'],props.fields)
84
50
  })
85
51
 
86
- async function fuzzySearch() {
87
- if (props.fuzzy) {
88
- if (isEmpty(searchData.value)) {
89
- items.value = masterItems.value
90
- }
91
- else {
92
- let fields: any[] = ['itemCode', 'itemValue', 'itemValueAlternative']
93
- if (props.fields) fields = concat(fields, props.fields)
94
-
95
- const results: any = useFuzzy(searchData.value, masterItems.value, fields)
96
- items.value = []
97
- if (results.value.length) {
98
- for (let i = 0; results.value.length > i; i++) {
99
- if (results.value[i].item) items.value.push(results.value[i].item)
100
- }
101
- }
102
- }
103
- }
104
- }
105
-
106
- watchDebounced(searchData, fuzzySearch, { debounce: 1000, maxWait: 5000 })
107
-
108
52
  const itemTitleField = computed(() => {
109
- if (props.lang == 'TH') return 'itemValue'
110
- else return 'itemValueAlternative'
53
+ return (props.lang == 'TH') ? 'itemValue' : 'itemValueAlternative'
111
54
  })
112
55
 
113
56
  const computedNoDataText = computed(() => {
@@ -116,64 +59,34 @@ const computedNoDataText = computed(() => {
116
59
  })
117
60
 
118
61
  const computedSortBy = computed(()=>{
119
- let sortByField = props.sortBy
120
- if (sortByField == 'itemValue') {
62
+ if (props.sortBy == 'itemValue') {
121
63
  if (props.showCode) return ['itemCode']
122
64
  else return [itemTitleField.value,'itemValue','itemCode']
123
65
  } else {
124
- return [sortByField]
125
- }
126
- })
127
-
128
- const computedItems = computed(()=>{
129
- if (props.fuzzy && !isEmpty(searchData.value)) {
130
- return items.value
131
- } else {
132
- return sortBy(items.value, computedSortBy.value)
66
+ return [props.sortBy]
133
67
  }
134
68
  })
135
69
  </script>
136
70
 
137
71
  <template>
138
- <v-autocomplete
139
- v-model="selectedItem"
140
- v-model:search="searchData"
141
- v-bind="$attrs"
142
- :items="computedItems"
143
- :no-filter="props.fuzzy"
144
- :item-title="itemTitleField"
145
- item-value="itemCode"
146
- :no-data-text="computedNoDataText"
147
- :loading="isLoading"
72
+ <model-autocomplete
73
+ :model-name="computedModelName"
74
+ :model-by="computedModelBy"
75
+ :fields="computedFields"
76
+ :sort-by="computedSortBy"
77
+ :item-title="itemTitleField"
78
+ item-value="itemCode"
79
+ :no-data-text="computedNoDataText"
80
+ :show-code="props.showCode"
148
81
  >
149
- <!-- @ts-ignore -->
150
82
  <template
151
- v-for="(_, name, index) in ($slots as {})"
152
- :key="index"
153
- #[name]="slotData"
154
- >
155
- <slot
156
- :name="name"
157
- v-bind="((slotData || {}) as object)"
158
- :operation="operation"
159
- />
160
- </template>
161
- <template
162
- v-if="!$slots.item"
163
- #item="{ props, item }"
83
+ v-if="!$slots.item"
84
+ #item="{ props, item }"
164
85
  >
165
86
  <v-list-item
166
- v-bind="props"
167
- :title="(showCode ? item.raw.itemCode+'-' : '')+(item.title || item.raw.itemValue || item.raw.itemCode)"
87
+ v-bind="props"
88
+ :title="(showCode ? item.raw.itemCode+'-' : '')+(item.title || item.raw.itemValue || item.raw.itemCode)"
168
89
  />
169
90
  </template>
170
- <template
171
- v-if="isErrorLoading"
172
- #append
173
- >
174
- <v-icon color="error">
175
- mdi mdi-alert
176
- </v-icon>
177
- </template>
178
- </v-autocomplete>
91
+ </model-autocomplete>
179
92
  </template>
@@ -1,11 +1,9 @@
1
1
  <script lang="ts" setup>
2
- import { computedAsync } from '@vueuse/core'
3
- import { useGraphQl } from '../../composables/graphql'
4
-
5
2
  interface Props {
6
3
  groupKey?: string | null
7
4
  itemCode?: string | null
8
5
  locale?: string
6
+
9
7
  notFoundText?: string
10
8
  placeholder?: string
11
9
  }
@@ -14,24 +12,27 @@ const props = withDefaults(defineProps<Props>(), {
14
12
  locale: 'TH',
15
13
  })
16
14
 
17
- const masterItemValue = computedAsync<string>(async () => {
18
- if (props.groupKey && props.itemCode) {
19
- try {
20
- const result = await useGraphQl().queryPromise<any>("masterItemByGroupKeyAndItemCode",['itemValue', 'itemValueAlternative'],{ groupKey: props.groupKey, itemCode: props.itemCode })
21
-
22
- if (result) {
23
- return props.locale === 'TH'
24
- ? result.itemValue
25
- : result.itemValueAlternative || result.itemValue
26
- }
27
- } catch (e) {
28
- console.error(e)
29
- }
30
- }
15
+ const computedNotFoundText = computed(()=>{
31
16
  return props.notFoundText || `${props.itemCode}`
32
- }, props.placeholder || `${props.groupKey}(${props.itemCode})`)
17
+ })
18
+
19
+ const computedPlaceholder = computed(()=>{
20
+ return props.placeholder || `${props.groupKey}(${props.itemCode})`
21
+ })
22
+
23
+ const computedItemTitle = computed(()=>{
24
+ return (props.locale == 'TH')
25
+ ? "itemValue"
26
+ : (result : Record<string,any>) => result["itemValueAlternative"] || result["itemValue"]
27
+ })
33
28
  </script>
34
29
 
35
30
  <template>
36
- {{ masterItemValue }}
31
+ <model-label
32
+ model-name="masterItemByGroupKeyAndItemCode"
33
+ :model-by="{groupKey: props.groupKey, itemCode: props.itemCode}"
34
+ :item-title="computedItemTitle"
35
+ :not-found-text="computedNotFoundText"
36
+ :placeholder="computedPlaceholder"
37
+ ></model-label>
37
38
  </template>
@@ -8,7 +8,7 @@ import {useGraphQlOperation} from "../../composables/graphqlOperation";
8
8
 
9
9
  interface Props extends /* @vue-ignore */ InstanceType<typeof VAutocomplete['$props']> {
10
10
  fuzzy?: boolean
11
- sortBy?: string
11
+ sortBy?: string | string[]
12
12
  showCode?: boolean
13
13
 
14
14
  modelName: string
@@ -48,21 +48,28 @@ watchEffect(()=>{
48
48
  variables[props.serverSearchKey] = searchData.value
49
49
  }
50
50
 
51
- isLoading.value = true
51
+ if (props.modelName) {
52
+ isLoading.value = true
52
53
 
53
- useGraphQlOperation('Query',props.modelName,fields,variables,props.cache).then((result: any) => {
54
- if (isArray(result)) {
55
- modelItems.value = result
56
- items.value = result
57
- isErrorLoading.value = false
58
- } else {
54
+ useGraphQlOperation('Query',props.modelName,fields,variables,props.cache).then((result: any) => {
55
+ if (isArray(result)) {
56
+ modelItems.value = result
57
+ items.value = result
58
+ isErrorLoading.value = false
59
+ } else {
60
+ isErrorLoading.value = true
61
+ }
62
+ }).catch((_error) => {
63
+ modelItems.value = []
64
+ items.value = []
59
65
  isErrorLoading.value = true
60
- }
61
- }).catch((_error) => {
62
- isErrorLoading.value = true
63
- }).finally(() => {
64
- isLoading.value = false
65
- })
66
+ }).finally(() => {
67
+ isLoading.value = false
68
+ })
69
+ } else {
70
+ modelItems.value = []
71
+ items.value = []
72
+ }
66
73
  })
67
74
 
68
75
  async function fuzzySearch() {
@@ -88,12 +95,12 @@ async function fuzzySearch() {
88
95
  watchDebounced(searchData, fuzzySearch, { debounce: 1000, maxWait: 5000 })
89
96
 
90
97
  const computedItems = computed(()=>{
91
- let sortByField = props.sortBy || ((props.showCode) ? props.itemValue : props.itemTitle)
98
+ let sortByField = (!props.sortBy || typeof props.sortBy === "string") ? [props.sortBy || ((props.showCode) ? props.itemValue : props.itemTitle)] : props.sortBy
92
99
 
93
100
  if (props.fuzzy && !isEmpty(searchData.value)) {
94
101
  return items.value
95
102
  } else {
96
- return sortBy(items.value, [sortByField])
103
+ return sortBy(items.value, sortByField)
97
104
  }
98
105
  })
99
106
  </script>
@@ -117,7 +124,6 @@ const computedItems = computed(()=>{
117
124
  <slot
118
125
  :name="name"
119
126
  v-bind="((slotData || {}) as object)"
120
- :operation="operation"
121
127
  />
122
128
  </template>
123
129
  <template
@@ -1,11 +1,12 @@
1
1
  <script lang="ts" setup>
2
2
  import { computedAsync } from '@vueuse/core'
3
3
  import { useGraphQlOperation } from '../../composables/graphqlOperation'
4
+ import {concat} from "lodash-es";
4
5
 
5
6
  interface Props {
6
7
  modelName: string
7
8
  modelBy?: object
8
- itemTitle: string
9
+ itemTitle: string | ((result:Record<string,any>)=>void)
9
10
  fields?: Array<string | object>
10
11
  cache?: boolean
11
12
 
@@ -19,14 +20,16 @@ const props = withDefaults(defineProps<Props>(), {
19
20
 
20
21
  const modelItemValue = computedAsync<string>(async () => {
21
22
  if (props.modelName && props.itemTitle) {
22
- let fields: any[] = [props.itemTitle]
23
+ let fields: any[] = (typeof props.itemTitle === "string") ? [props.itemTitle] : []
24
+ if (props.fields) fields = concat(fields, props.fields)
25
+
23
26
  const variables: Record<string, any> = Object.assign({},props.modelBy)
27
+ const result : Record<string, any> = await useGraphQlOperation('Query',props.modelName,fields,variables,props.cache)
24
28
 
25
29
  try {
26
- const result : Record<string, any> = await useGraphQlOperation('Query',props.modelName,fields,variables,props.cache)
27
-
28
30
  if (result) {
29
- return result[props.itemTitle]
31
+ if (typeof props.itemTitle === "string") return result[props.itemTitle]
32
+ else return props.itemTitle(result)
30
33
  }
31
34
  } catch (e) {
32
35
  console.error(e)
@@ -1,2 +1,24 @@
1
+ export interface DocumentTemplateItem {
2
+ inputType: string;
3
+ width?: string | number;
4
+ inputLabel?: string;
5
+ variableName?: string;
6
+ validationRules?: string;
7
+ inputOptions?: string | object;
8
+ inputAttributes?: string;
9
+ inputCustomCode?: string;
10
+ columnAttributes?: string;
11
+ conditionalDisplay?: string;
12
+ computedValue?: string;
13
+ retrievedValue?: string;
14
+ }
15
+ export interface ChoiceItem {
16
+ label: string;
17
+ value: string;
18
+ }
1
19
  export declare const validationRulesRegex: RegExp;
2
- export declare function useDocumentTemplate(items: string | object): string;
20
+ export declare function useDocumentTemplate(items: string | object, parentTemplates?: string | string[]): string;
21
+ export declare function optionStringToChoiceObject(option: string | object): ChoiceItem[];
22
+ export declare function escapeObjectForInlineBinding(obj: object): string;
23
+ export declare function buildValidationRules(validationString: string): string;
24
+ export declare function processDefaultTemplate(item: DocumentTemplateItem, insideTemplate?: string, optionString?: string, validationRules?: string): string;
@@ -1,5 +1,7 @@
1
+ import { processTemplateFormTable } from "./templateFormTable.js";
2
+ import { processTemplateFormHidden } from "./templateFormHidden.js";
1
3
  export const validationRulesRegex = /^(require(?:\([^)]*\))?|requireIf(?:\([^)]*\))?|requireTrue(?:\([^)]*\))?|requireTrueIf(?:\([^)]*\))?|numeric(?:\([^)]*\))?|range(?:\([^)]*\))?|integer(?:\([^)]*\))?|unique(?:\([^)]*\))?|length(?:\([^)]*\))?|lengthGreater(?:\([^)]*\))?|lengthLess(?:\([^)]*\))?|telephone(?:\([^)]*\))?|email(?:\([^)]*\))?|regex(?:\([^)]*\))?)(,(require(?:\([^)]*\))?|requireIf(?:\([^)]*\))?|requireTrue(?:\([^)]*\))?|requireTrueIf(?:\([^)]*\))?|numeric(?:\([^)]*\))?|range(?:\([^)]*\))?|integer(?:\([^)]*\))?|unique(?:\([^)]*\))?|length(?:\([^)]*\))?|lengthGreater(?:\([^)]*\))?|lengthLess(?:\([^)]*\))?|telephone(?:\([^)]*\))?|email(?:\([^)]*\))?|regex(?:\([^)]*\))?))*$/;
2
- export function useDocumentTemplate(items) {
4
+ export function useDocumentTemplate(items, parentTemplates) {
3
5
  if (!items) return "";
4
6
  if (typeof items === "string") {
5
7
  try {
@@ -11,94 +13,108 @@ export function useDocumentTemplate(items) {
11
13
  if (!Array.isArray(items) || !items.every((item) => typeof item === "object" && item !== null)) {
12
14
  return "";
13
15
  }
14
- let templateString = items.map((item) => templateItemToString(item)).join("");
15
- templateString = `<v-container fluid><v-row dense>${templateString}</v-row></v-container>`;
16
- return templateString;
16
+ const templateString = items.map((item) => templateItemToString(item, parentTemplates || [])).join("");
17
+ return !parentTemplates || parentTemplates.length == 0 ? `<v-container fluid><v-row dense>${templateString}</v-row></v-container>` : `<v-row dense>${templateString}</v-row>`;
17
18
  }
18
- function templateItemToString(item) {
19
+ function templateItemToString(item, parentTemplates) {
19
20
  let optionString = "";
20
- let validationRules = "";
21
21
  if (item.inputOptions) {
22
- if (item.inputType == "MasterAutocomplete") {
23
- optionString += 'groupKey="' + item.inputOptions + '" ';
22
+ if (item.inputType === "MasterAutocomplete") {
23
+ optionString += `groupKey="${item.inputOptions}" `;
24
24
  }
25
- if (item.inputType == "VSelect" || item.inputType == "VAutocomplete" || item.inputType == "VCombobox") {
25
+ if (["VSelect", "VAutocomplete", "VCombobox"].includes(item.inputType)) {
26
26
  const choice = optionStringToChoiceObject(item.inputOptions);
27
- optionString = `item-value="value" item-title="label" :items='` + JSON.stringify(choice).replaceAll("'", "&#39;") + "' ";
27
+ optionString = `item-value="value" item-title="label" :items='${escapeObjectForInlineBinding(choice)}' `;
28
28
  }
29
- if (item.inputType == "VRadio" || item.inputType == "VRadioInline") {
29
+ if (["VRadio", "VRadioInline"].includes(item.inputType)) {
30
30
  const choice = optionStringToChoiceObject(item.inputOptions);
31
- optionString = choice.map((choiceItem) => `<v-radio label="${choiceItem.label}" value="${choiceItem.value}" ${item.inputAttributes ? " " + item.inputAttributes : ""}></v-radio>`).join("");
31
+ optionString = choice.map((choiceItem) => `<v-radio label="${choiceItem.label || ""}" value="${choiceItem.value || ""}" ${item.inputAttributes ? " " + item.inputAttributes : ""}></v-radio>`).join("");
32
32
  }
33
- if (item.inputType == "Header") {
34
- optionString = item.inputOptions.split(",").join(" ");
33
+ if (item.inputType === "Header") {
34
+ if (typeof item.inputOptions === "string") optionString = item.inputOptions.split(",").join(" ");
35
35
  }
36
36
  }
37
- if (item.inputType == "FormDateTime" && !item.inputAttributes?.includes("dense")) item.inputAttributes = (item.inputAttributes?.trim() + " dense").trim();
38
- if (item.validationRules) validationRules = buildValidationRules(item.validationRules);
37
+ if (item.conditionalDisplay) {
38
+ item.inputAttributes = `${item.inputAttributes?.trim() || ""} v-if="${item.conditionalDisplay}"`.trim();
39
+ }
40
+ if (item.inputType === "FormDateTime" && !item.inputAttributes?.includes("dense")) {
41
+ item.inputAttributes = `${item.inputAttributes?.trim() || ""} dense`.trim();
42
+ }
39
43
  let templateString;
40
44
  switch (item.inputType) {
41
45
  case "CustomCode":
42
- templateString = `${item.inputCustomCode}`;
46
+ templateString = item.inputCustomCode || "";
43
47
  break;
44
48
  case "VRadio":
45
- templateString = `<v-radio-group v-model="data.${item.variableName}" label="${item.inputLabel || item.variableName}"${validationRules ? " " + validationRules.trim() : ""}>${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
46
- break;
47
49
  case "VRadioInline":
48
- templateString = `<v-radio-group v-model="data.${item.variableName}" inline${validationRules ? " " + validationRules.trim() : ""}><template #prepend>${item.inputLabel || item.variableName}</template>${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
50
+ const inlineAttr = item.inputType === "VRadioInline" ? " inline" : "";
51
+ const validationRules = item.validationRules ? buildValidationRules(item.validationRules) || "" : "";
52
+ templateString = `<v-radio-group v-model="data.${item.variableName || ""}"${inlineAttr}${validationRules ? " " + validationRules.trim() : ""}>${item.inputLabel ? `<template #prepend>${item.inputLabel}</template>` : ""}${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
49
53
  break;
50
54
  case "Separator":
51
- templateString = `</v-row><v-row dense>`;
55
+ templateString = "</v-row><v-row dense>";
52
56
  break;
53
57
  case "Header":
54
- templateString = `<div class="${optionString ? optionString.trim() : "text-h4 font-weight-medium"}">${item.inputLabel || item.variableName}</div>`;
58
+ templateString = `<div class="${optionString || "text-h4 font-weight-medium"}">${item.inputLabel || item.variableName || ""}</div>`;
55
59
  break;
56
60
  case "FormTable":
57
- templateString = `<form-table v-model="data.${item.variableName}" label="${item.inputLabel || item.variableName}"${validationRules ? " " + validationRules.trim() : ""} ${item.inputAttributes ? " " + item.inputAttributes : ""}>${optionString ? " " + optionString.trim() : ""}
58
- <template #form>${item.inputFormTable}</template>
59
- </form-table>`;
61
+ templateString = processTemplateFormTable(item, parentTemplates);
60
62
  break;
61
63
  case "FormHidden":
62
- templateString = `${item.inputOptions} / ${item.inputFormHidden} <form-hidden v-model="data.${item.variableName}" :item-value="${item.inputOptions ? item.inputOptions : "data"}" :hook="() => {${item.inputFormHidden}}">
63
- </form-hidden>`;
64
+ templateString = processTemplateFormHidden(item, parentTemplates);
65
+ break;
66
+ case "DocumentForm":
67
+ const parentTemplatesString = typeof parentTemplates === "string" ? parentTemplates : parentTemplates.join("|");
68
+ templateString = `<document-form v-model="data" templateCode="${item.inputOptions || ""}" parent-templates="${parentTemplatesString}"></document-form>`;
64
69
  break;
65
70
  default:
66
- templateString = `<${item.inputType} v-model="data.${item.variableName}" label="${item.inputLabel || item.variableName}"${item.inputAttributes ? " " + item.inputAttributes : ""}${optionString ? " " + optionString.trim() : ""}${validationRules ? " " + validationRules.trim() : ""}></${item.inputType}>`;
71
+ templateString = processDefaultTemplate(item, void 0, optionString);
72
+ }
73
+ if (!["Separator"].includes(item.inputType)) templateString = `<v-col${item.width ? ` cols="${item.width}"` : ""}${item.columnAttributes ? " " + item.columnAttributes : ""}>${templateString}</v-col>`;
74
+ if (["Header", "DocumentForm"].includes(item.inputType)) templateString = `</v-row><v-row dense>${templateString}</v-row><v-row dense>`;
75
+ if (item.computedValue && item.variableName) {
76
+ templateString = `${templateString || ""}<FormHidden v-model="data.${item.variableName}" :item-value="data" :hook="()=>${item.computedValue}"/>`.trim();
67
77
  }
68
- if (!["Separator", "Header"].includes(item.inputType)) templateString = `<v-col${item.width ? ' cols="' + item.width + '"' : ""}${item.columnAttributes ? " " + item.columnAttributes : ""}>${templateString}</v-col>`;
69
- if (["Header"].includes(item.inputType)) templateString = `</v-row><v-row dense><v-col${item.columnAttributes ? " " + item.columnAttributes : ""}>${templateString}</v-col></v-row><v-row dense>`;
70
- return templateString;
78
+ return templateString || "";
71
79
  }
72
- function optionStringToChoiceObject(option) {
73
- let returnObject = [];
74
- if (/^[^'",]+(,[^'",]+)*$/.test(option.trim())) {
75
- returnObject = option.split(",").map((item) => {
80
+ export function optionStringToChoiceObject(option) {
81
+ if (typeof option === "string") {
82
+ if (!/^[^'",]+(,[^'",]+)*$/.test(option.trim())) return [];
83
+ return option.split(",").map((item) => {
76
84
  item = item.trim();
77
85
  if (item.includes("|")) {
78
86
  const [label, value] = item.split("|").map((str) => str.trim().replace(/^['"]|['"]$/g, ""));
79
- return { label, value };
80
- } else {
81
- item = item.replace(/^['"]|['"]$/g, "");
82
- return { label: item, value: item };
87
+ return { label: label || "", value: value || "" };
83
88
  }
89
+ item = item.replace(/^['"]|['"]$/g, "");
90
+ return { label: item, value: item };
84
91
  });
85
92
  }
86
- return returnObject;
93
+ if (Array.isArray(option) && option.every((item) => typeof item === "object" && item !== null)) {
94
+ return option.sort((a, b) => (a.id ?? Infinity) - (b.id ?? Infinity)).map((item) => ({
95
+ label: item.label || item.value || "",
96
+ // Default to empty string if label is undefined
97
+ value: item.value || ""
98
+ // Default to empty string if value is undefined
99
+ }));
100
+ }
101
+ return [];
102
+ }
103
+ export function escapeObjectForInlineBinding(obj) {
104
+ return JSON.stringify(obj).replace(/'/g, "&#39;");
87
105
  }
88
- function buildValidationRules(validationString) {
89
- validationString = validationString.trim();
90
- if (validationString.startsWith("[")) validationString = validationString.substring(1);
91
- if (validationString.endsWith("]")) validationString = validationString.substring(0, validationString.length - 1);
106
+ export function buildValidationRules(validationString) {
107
+ validationString = validationString.replace(/^\[|]$/g, "").trim();
92
108
  if (!validationRulesRegex.test(validationString)) return "";
93
- validationString = validationString.split(",").map((rule) => {
109
+ const rules = validationString.split(",").map((rule) => {
94
110
  rule = rule.trim();
95
- if (!rule.startsWith("rules.")) {
96
- rule = "rules." + rule;
97
- }
98
- if (!/\(.+\)$/.test(rule)) {
99
- rule = rule + "()";
100
- }
101
- return rule.replaceAll('"', "'");
102
- }).join(",");
103
- return `:rules="[${validationString}]"`;
111
+ if (!rule.startsWith("rules.")) rule = `rules.${rule}`;
112
+ if (!/\(.+\)$/.test(rule)) rule += "()";
113
+ return rule.replace(/"/g, "'");
114
+ });
115
+ return `:rules="[${rules.join(",")}]"`;
116
+ }
117
+ export function processDefaultTemplate(item, insideTemplate, optionString, validationRules) {
118
+ if (!validationRules) validationRules = item.validationRules ? buildValidationRules(item.validationRules) || "" : "";
119
+ return `<${item.inputType} v-model="data.${item.variableName || ""}" label="${item.inputLabel || item.variableName || ""}"${item.inputAttributes ? " " + item.inputAttributes : ""}${optionString ? " " + optionString.trim() : ""}${validationRules ? " " + validationRules.trim() : ""}>${insideTemplate || ""}</${item.inputType}>`;
104
120
  }
@@ -0,0 +1,2 @@
1
+ import { type DocumentTemplateItem } from './template.js';
2
+ export declare function processTemplateFormHidden(item: DocumentTemplateItem, parentTemplates: string | string[]): string;
@@ -0,0 +1,10 @@
1
+ export function processTemplateFormHidden(item, parentTemplates) {
2
+ let formHiddenOptions = Object.assign({ itemValue: "", hook: "" }, item.inputOptions);
3
+ if (formHiddenOptions.hook.trim()) {
4
+ formHiddenOptions.hook = formHiddenOptions.hook.replace(/\n/g, ";").trim();
5
+ if (!/^return\s/.test(formHiddenOptions.hook)) {
6
+ formHiddenOptions.hook = `return ${formHiddenOptions.hook}`;
7
+ }
8
+ }
9
+ return `<form-hidden v-model="data.${item.variableName || ""}" :item-value="${formHiddenOptions.itemValue || "data"}" :hook="(data,modelValue) => {${formHiddenOptions.hook}}"></form-hidden>`;
10
+ }
@@ -0,0 +1,2 @@
1
+ import { type DocumentTemplateItem } from './template.js';
2
+ export declare function processTemplateFormTable(item: DocumentTemplateItem, parentTemplates: string | string[]): string;
@@ -0,0 +1,9 @@
1
+ import {
2
+ escapeObjectForInlineBinding,
3
+ processDefaultTemplate,
4
+ useDocumentTemplate
5
+ } from "./template.js";
6
+ export function processTemplateFormTable(item, parentTemplates) {
7
+ let tableOptions = Object.assign({ title: item.inputLabel || "", formTemplate: "" }, item.inputOptions);
8
+ return processDefaultTemplate(item, `<template #form="{data,rules}">${useDocumentTemplate(tableOptions.formTemplate)}</template>`, `title="${tableOptions.title}" :headers='${escapeObjectForInlineBinding(tableOptions.headers || {})}'`);
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramathibodi/nuxt-commons",
3
- "version": "0.1.38",
3
+ "version": "0.1.40",
4
4
  "description": "Ramathibodi Nuxt modules for common components",
5
5
  "repository": {
6
6
  "type": "git",