tantee-nuxt-commons 0.0.172 → 0.0.174

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.0.172",
7
+ "version": "0.0.174",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
@@ -45,6 +45,7 @@ watch(() => alert?.hasAlert(), (hasAlert) => {
45
45
  elevation="2"
46
46
  theme="dark"
47
47
  variant="flat"
48
+ v-bind="currentItem.alertIcon ? { icon: currentItem.alertIcon } : {}"
48
49
  @click:close="renewAlert()"
49
50
  >
50
51
  {{ currentItem.statusCode ? currentItem.statusCode + ' ' : '' }} {{ currentItem.message }} {{ !isEmpty(currentItem.data) ? currentItem.data : '' }}
@@ -73,7 +73,7 @@ const loadFormData = () => {
73
73
  formData.value = cloneDeep(formDataOriginalValue.value)
74
74
  }
75
75
  else {
76
- formData.value = Object.assign({}, props.initialData)
76
+ formData.value = Object.assign({}, cloneDeep(props.initialData))
77
77
  }
78
78
  }
79
79
 
@@ -85,7 +85,7 @@ const loadFormData = () => {
85
85
  formDataOriginalValue.value = cloneDeep(props.formData)
86
86
  }
87
87
  else {
88
- formData.value = Object.assign({}, props.initialData)
88
+ formData.value = Object.assign({}, cloneDeep(props.initialData))
89
89
  }
90
90
  isSavedAndStay.value = false
91
91
  }
@@ -78,7 +78,7 @@ const loadFormData = () => {
78
78
  formDataOriginalValue.value = cloneDeep(props.formData)
79
79
  }
80
80
  else {
81
- formData.value = Object.assign({}, props.initialData)
81
+ formData.value = Object.assign({}, cloneDeep(props.initialData))
82
82
  }
83
83
  }
84
84
 
@@ -497,8 +497,6 @@ defineExpose({
497
497
  show-first-last-page
498
498
  @first="footerProps.setPage(1)"
499
499
  @last="footerProps.setPage(footerProps.pageCount)"
500
- @next="footerProps.nextPage"
501
- @prev="footerProps.prevPage"
502
500
  @update:model-value="footerProps.setPage"
503
501
  />
504
502
  </v-row>
@@ -34,6 +34,7 @@ interface Props {
34
34
  parentTemplates?: string|string[]
35
35
  dirtyClass?: string
36
36
  dirtyOnCreate?: boolean
37
+ sanitizeDelay?: number
37
38
  }
38
39
 
39
40
  const props = withDefaults(defineProps<Props>(), {
@@ -43,7 +44,8 @@ const props = withDefaults(defineProps<Props>(), {
43
44
  decoration: () => { return {} },
44
45
  parentTemplates: (): string[] => [],
45
46
  dirtyClass: "form-data-dirty",
46
- dirtyOnCreate: false
47
+ dirtyOnCreate: false,
48
+ sanitizeDelay: 2000,
47
49
  })
48
50
 
49
51
  const emit = defineEmits(['update:modelValue'])
@@ -87,7 +89,7 @@ function isBlankString(v: unknown): v is string {
87
89
  return isString(v) && v.trim().length === 0
88
90
  }
89
91
 
90
- const sanitizeBlankStrings = debounce(sanitizeBlankStringsRaw, 500)
92
+ const sanitizeBlankStrings = debounce(sanitizeBlankStringsRaw, props.sanitizeDelay)
91
93
 
92
94
  function sanitizeBlankStringsRaw(val: any, original?: any): void {
93
95
  if (!original && props.originalData) {
@@ -125,6 +127,71 @@ function sanitizeBlankStringsRaw(val: any, original?: any): void {
125
127
  }
126
128
  }
127
129
 
130
+ function autoSanitizedDisplay(item: any, separator: string = ","): string | undefined {
131
+ const isEmptyScalar = (v: any) =>
132
+ v === null ||
133
+ v === undefined ||
134
+ (typeof v === "string" && v.trim() === "") ||
135
+ (typeof v === "number" && Number.isNaN(v));
136
+
137
+ const toStr = (v: any): string | undefined => {
138
+ if (isEmptyScalar(v)) return undefined;
139
+ if (typeof v === "string") return v.trim();
140
+ if (typeof v === "number" || typeof v === "boolean" || typeof v === "bigint") return String(v);
141
+ if (typeof v === "symbol") return v.description ?? String(v);
142
+ if (typeof v === "function") return v.name ? `[Function ${v.name}]` : "[Function]";
143
+ return undefined;
144
+ };
145
+
146
+ // 1) empty -> undefined
147
+ if (isEmptyScalar(item)) return undefined;
148
+
149
+ // 2) array -> recurse + join
150
+ if (Array.isArray(item)) {
151
+ const parts = item
152
+ .map((x) => autoSanitizedDisplay(x, separator))
153
+ .filter((s): s is string => typeof s === "string" && s.trim() !== "");
154
+ return parts.length ? parts.join(separator) : undefined;
155
+ }
156
+
157
+ // simple scalars
158
+ const scalar = toStr(item);
159
+ if (scalar !== undefined) return scalar;
160
+
161
+ // 3) object
162
+ if (typeof item === "object") {
163
+ // 3.1 label
164
+ if ("label" in item) {
165
+ const v = autoSanitizedDisplay((item as any).label, separator) ?? toStr((item as any).label);
166
+ if (v !== undefined) return v;
167
+ }
168
+ // 3.2 value
169
+ if ("value" in item) {
170
+ const v = autoSanitizedDisplay((item as any).value, separator) ?? toStr((item as any).value);
171
+ if (v !== undefined) return v;
172
+ }
173
+
174
+ // 3.3 stringify attributes as key:value (recurse values)
175
+ const entries = Object.entries(item as Record<string, any>)
176
+ .map(([k, v]) => {
177
+ const rendered = autoSanitizedDisplay(v, separator) ?? toStr(v);
178
+ if (rendered === undefined || rendered.trim() === "") return undefined;
179
+ return `${k}:${rendered}`;
180
+ })
181
+ .filter((x): x is string => typeof x === "string" && x.trim() !== "");
182
+
183
+ return entries.length ? entries.join(separator) : undefined;
184
+ }
185
+
186
+ // fallback
187
+ try {
188
+ const s = String(item);
189
+ return s.trim() ? s : undefined;
190
+ } catch {
191
+ return undefined;
192
+ }
193
+ }
194
+
128
195
  watch(formData, (newValue) => {
129
196
  sanitizeBlankStrings(newValue)
130
197
  emit('update:modelValue', newValue)
@@ -219,6 +286,7 @@ function buildFormComponent() {
219
286
  resetValidate: () => formPadTemplate.value.resetValidate(),
220
287
  isValid,
221
288
  ...templateScriptFunction.value(props, ctx, ...Object.values(vueFunctions)),
289
+ autoSanitizedDisplay
222
290
  }
223
291
  },
224
292
  template: componentTemplate,
@@ -279,6 +347,7 @@ defineExpose({
279
347
  :disabled="disabled"
280
348
  :readonly="readonly"
281
349
  :class="$attrs.class"
350
+ autocomplete="off"
282
351
  >
283
352
  <template #default="formProvided">
284
353
  <slot
@@ -230,58 +230,65 @@ defineExpose({
230
230
  <template>
231
231
  <v-input v-model="images" v-bind="$attrs" ref="inputRef">
232
232
  <template #default="{ isReadonly, isDisabled }">
233
- <VCard>
234
- <VToolbar density="compact">
235
- <VToolbarTitle>{{ label }}</VToolbarTitle>
236
- <v-spacer />
237
- <VToolbarItems v-if="!readonly">
238
- <FileBtn
239
- v-model="uploadImages"
240
- :accept="accept"
241
- color="primary"
242
- icon="mdi:mdi-image-plus"
243
- icon-only
244
- multiple
245
- variant="text"
246
- @update:model-value="uploadImageFile"
247
- :disabled="isDisabled?.value" :readonly="isReadonly?.value"
248
- />
249
- <v-btn color="primary" icon @click="dialog = true" :disabled="isDisabled?.value" :readonly="isReadonly?.value">
250
- <v-icon>mdi mdi-camera-plus</v-icon>
251
- </v-btn>
252
- </VToolbarItems>
253
- </VToolbar>
254
-
255
- <VCardText>
256
- <VRow dense justify="center">
257
- <VCol v-for="(image, index) in images" :key="`${imageKey(image)}-${index}`" cols="4">
258
- <VCard>
259
- <VToolbar density="compact">
260
- <VToolbarTitle>
261
- {{ image.imageTitle }}
262
- </VToolbarTitle>
263
- <VSpacer />
264
- <VToolbarItems v-if="!readonly">
265
- <v-btn icon @click="remove(index)" :disabled="isDisabled?.value" :readonly="isReadonly?.value">
266
- <v-icon>mdi mdi-delete-outline</v-icon>
267
- </v-btn>
268
- <v-btn color="primary" icon @click="setDataUpdate(image)" v-if="!image.imageData?.id" :disabled="isDisabled?.value" :readonly="isReadonly?.value">
269
- <v-icon>mdi mdi-image-edit-outline</v-icon>
270
- </v-btn>
271
- </VToolbarItems>
272
- </VToolbar>
273
-
274
- <v-img
275
- :src="imageSrcFromImageData(image)"
276
- height="250"
277
- @click="() => { (props.readonly || image.imageData?.id || isReadonly?.value) ? openImageFullScreen(image) : setDataUpdate(image) }"
278
- :disabled="isDisabled?.value"
279
- />
280
- </VCard>
281
- </VCol>
282
- </VRow>
283
- </VCardText>
284
- </VCard>
233
+ <v-container fluid>
234
+ <v-row>
235
+ <v-col class="pa-0">
236
+ <VCard>
237
+ <VToolbar density="compact">
238
+ <VToolbarTitle>{{ label }}</VToolbarTitle>
239
+ <v-spacer />
240
+ <VToolbarItems v-if="!readonly">
241
+ <FileBtn
242
+ v-model="uploadImages"
243
+ :accept="accept"
244
+ color="primary"
245
+ icon="mdi:mdi-image-plus"
246
+ icon-only
247
+ multiple
248
+ variant="text"
249
+ @update:model-value="uploadImageFile"
250
+ :disabled="isDisabled?.value" :readonly="isReadonly?.value"
251
+ />
252
+ <v-btn color="primary" icon @click="dialog = true" :disabled="isDisabled?.value" :readonly="isReadonly?.value">
253
+ <v-icon>mdi mdi-camera-plus</v-icon>
254
+ </v-btn>
255
+ </VToolbarItems>
256
+ </VToolbar>
257
+
258
+ <VCardText>
259
+ <VRow dense justify="start">
260
+ <VCol v-for="(image, index) in images" :key="`${imageKey(image)}-${index}`" cols="4">
261
+ <VCard>
262
+ <VToolbar density="compact">
263
+ <VToolbarTitle>
264
+ {{ image.imageTitle }}
265
+ </VToolbarTitle>
266
+ <VSpacer />
267
+ <VToolbarItems v-if="!readonly">
268
+ <v-btn icon @click="remove(index)" :disabled="isDisabled?.value" :readonly="isReadonly?.value">
269
+ <v-icon>mdi mdi-delete-outline</v-icon>
270
+ </v-btn>
271
+ <v-btn color="primary" icon @click="setDataUpdate(image)" v-if="!image.imageData?.id" :disabled="isDisabled?.value" :readonly="isReadonly?.value">
272
+ <v-icon>mdi mdi-image-edit-outline</v-icon>
273
+ </v-btn>
274
+ </VToolbarItems>
275
+ </VToolbar>
276
+
277
+ <v-img
278
+ :src="imageSrcFromImageData(image)"
279
+ height="250"
280
+ @click="() => { (props.readonly || image.imageData?.id || isReadonly?.value) ? openImageFullScreen(image) : setDataUpdate(image) }"
281
+ :disabled="isDisabled?.value"
282
+ />
283
+ </VCard>
284
+ </VCol>
285
+ </VRow>
286
+ </VCardText>
287
+ </VCard>
288
+ </v-col>
289
+ </v-row>
290
+ </v-container>
291
+
285
292
 
286
293
  <!-- Edit dialog -->
287
294
  <VDialog v-model="dialogUpdate" fullscreen transition="dialog-bottom-transition">
@@ -2,39 +2,143 @@
2
2
  import { DateTime } from "luxon";
3
3
  import { computed } from "vue";
4
4
 
5
- type Locale = "th" | "en" | "en-US" | "th-TH";
5
+ type Unit = 'years' | 'months' | 'days' | 'hours' | 'minutes' | 'seconds';
6
+ type Locale = 'th' | 'en' | 'en-US' | 'th-TH';
6
7
 
7
8
  interface Props {
8
9
  modelValue: DateTime;
9
10
  endDate?: DateTime;
10
11
  locale?: Locale;
11
- zeroBase?: boolean; // true = start at 0, false = start at 1
12
+ showSuffix?: boolean;
13
+ units?: Unit[];
14
+ zeroBase?: boolean; // true = start at 0, false = start at 1 (inclusive)
12
15
  }
13
16
 
14
17
  const props = withDefaults(defineProps<Props>(), {
15
- locale: "th",
18
+ locale: 'th',
19
+ showSuffix: true,
16
20
  zeroBase: true,
17
21
  });
18
22
 
19
- const normalizeLocale = (locale: Locale): "en" | "th" =>
20
- locale.startsWith("en") ? "en" : "th";
23
+ // Fallback map: map complex locale (e.g., en-US) to base (e.g., en)
24
+ const normalizeLocale = (locale: Locale): 'en' | 'th' => {
25
+ if (locale.startsWith('en')) return 'en';
26
+ if (locale.startsWith('th')) return 'th';
27
+ return 'th'; // default fallback
28
+ };
21
29
 
22
- const countDate = computed(() => {
23
- const base = props.endDate ?? DateTime.now();
30
+ const labelsEnPlural: Record<Unit, string> = {
31
+ years: 'years',
32
+ months: 'months',
33
+ days: 'days',
34
+ hours: 'hours',
35
+ minutes: 'minutes',
36
+ seconds: 'seconds',
37
+ };
38
+ const labelsEnSingular: Record<Unit, string> = {
39
+ years: 'year',
40
+ months: 'month',
41
+ days: 'day',
42
+ hours: 'hour',
43
+ minutes: 'minute',
44
+ seconds: 'second',
45
+ };
46
+
47
+ const localizedLabels: Record<'en' | 'th', Record<Unit, string>> = {
48
+ en: labelsEnPlural, // จะสลับเป็น singular ตามค่าจริงตอน render
49
+ th: {
50
+ years: 'ปี',
51
+ months: 'เดือน',
52
+ days: 'วัน',
53
+ hours: 'ชั่วโมง',
54
+ minutes: 'นาที',
55
+ seconds: 'วินาที',
56
+ },
57
+ };
58
+
59
+ const localizedSuffix: Record<'en' | 'th', string> = {
60
+ en: 'ago',
61
+ th: 'ที่ผ่านมา',
62
+ };
63
+
64
+ const outputText = computed(() => {
65
+ const base = props.endDate ?? DateTime.now(); // ใช้ endDate ถ้ามี ไม่งั้น now
24
66
  const baseLocale = normalizeLocale(props.locale);
25
67
 
26
- let days = Math.floor(base.diff(props.modelValue, "days").days ?? 0);
68
+ const units: Unit[] = props.units?.length
69
+ ? props.units
70
+ : ['years', 'months', 'days', 'hours', 'minutes', 'seconds'];
71
+
72
+ const diffObj = base.diff(props.modelValue, units).toObject();
73
+
74
+ // helper: คืน label ตาม singular/plural (เฉพาะ en)
75
+ const labelFor = (unit: Unit, value: number) => {
76
+ if (baseLocale === 'en') {
77
+ return value === 1 ? labelsEnSingular[unit] : labelsEnPlural[unit];
78
+ }
79
+ return localizedLabels[baseLocale][unit];
80
+ };
81
+
82
+ // ---------- โหมด single unit ----------
83
+ if (!props.units) {
84
+ const foundUnit = units.find((unit) => (diffObj[unit] ?? 0) >= 1);
85
+ if (foundUnit) {
86
+ const raw = Math.floor(diffObj[foundUnit] ?? 0); // >= 1
87
+ const value = props.zeroBase ? raw : raw + 1; // inclusive (+1)
88
+ const label = labelFor(foundUnit, value);
89
+ const suffix = props.showSuffix ? localizedSuffix[baseLocale] : '';
90
+ return `${value} ${label}${suffix ? ` ${suffix}` : ''}`;
91
+ }
92
+
93
+ // ถ้าไม่มีหน่วยใด >= 1 ให้ใช้หน่วยเล็กสุด
94
+ const lastUnit = units.at(-1)!;
95
+ const raw = Math.max(0, Math.floor(diffObj[lastUnit] ?? 0));
96
+ const value = props.zeroBase ? raw : 1; // inclusive: อย่างน้อย 1
97
+ const label = labelFor(lastUnit, value);
98
+ const suffix = props.showSuffix ? localizedSuffix[baseLocale] : '';
99
+ return `${value} ${label}${suffix ? ` ${suffix}` : ''}`;
100
+ }
101
+
102
+ // ---------- โหมด multi-unit ----------
103
+ // เก็บค่าแบบตัวเลขก่อน แล้วค่อยเรนเดอร์
104
+ const values = units.map((unit) => ({
105
+ unit,
106
+ raw: Math.max(0, Math.floor(diffObj[unit] ?? 0)),
107
+ }));
108
+
109
+ // เลือกหน่วยที่เล็กที่สุด
110
+ const smallest = values[values.length - 1];
111
+
112
+ // ถ้ามีค่าอย่างน้อยหนึ่งหน่วย > 0 และเป็น inclusive (zeroBase=false) => +1 ที่หน่วยเล็กสุด
113
+ const anyPositive = values.some((v) => v.raw > 0);
114
+ const adjusted = values.map((v, idx) => {
115
+ if (!props.zeroBase && anyPositive && idx === values.length - 1) {
116
+ return { ...v, raw: v.raw + 1 };
117
+ }
118
+ return v;
119
+ });
27
120
 
28
- if (!props.zeroBase) days += 1;
121
+ // สร้างข้อความจากหน่วยที่มีค่า > 0
122
+ const parts = adjusted
123
+ .filter((v) => v.raw > 0)
124
+ .map((v) => `${v.raw} ${labelFor(v.unit, v.raw)}`);
29
125
 
30
- if (baseLocale === "en") {
31
- return days === 1 ? "1 day" : `${days} days`;
126
+ // หากทั้งหมดเป็น 0:
127
+ if (parts.length === 0) {
128
+ const minValue = props.zeroBase ? 0 : 1;
129
+ const label = labelFor(smallest.unit, minValue);
130
+ const suffix = props.showSuffix ? localizedSuffix[baseLocale] : '';
131
+ return `${minValue} ${label}${suffix ? ` ${suffix}` : ''}`;
32
132
  }
33
133
 
34
- return `${days} วัน`;
134
+ const suffix = props.showSuffix ? localizedSuffix[baseLocale] : '';
135
+ return `${parts.join(' ')}${suffix ? ` ${suffix}` : ''}`;
35
136
  });
36
137
  </script>
37
138
 
38
139
  <template>
39
- <span>{{ countDate }}</span>
140
+ <span>
141
+ <i v-if="props.zeroBase" class="mdi mdi-clock-time-twelve-outline"></i>
142
+ <span v-if="props.zeroBase">&nbsp;</span>{{ outputText }}
143
+ </span>
40
144
  </template>
@@ -15,12 +15,12 @@ interface Props extends /* @vue-ignore */ InstanceType<typeof PDF['$props']> {
15
15
  }
16
16
 
17
17
  const props = withDefaults(defineProps<Props>(), {
18
- base64String: "",
19
- title: "",
20
- fileName: "",
18
+ base64String: '',
19
+ title: '',
20
+ fileName: '',
21
21
  disabled: false,
22
22
  isPrint: false,
23
- showBackToTopBtn: false
23
+ showBackToTopBtn: false,
24
24
  })
25
25
 
26
26
  const emit = defineEmits(['closeDialog'])
@@ -33,25 +33,34 @@ const generateUniqueId = (): string => {
33
33
  }
34
34
 
35
35
  const downloadPdf = (): void => {
36
- const byteString = atob(props.base64String || '')
37
- const byteArray = new Uint8Array(byteString.length)
36
+ try {
37
+ if (!props.base64String) alert?.addAlert({ message: 'No Base64 provided', alertType: 'error' })
38
38
 
39
- for (let i = 0; i < byteString.length; i++) {
40
- byteArray[i] = byteString.charCodeAt(i)
41
- }
39
+ const byteString = atob(props.base64String || '')
40
+ const byteArray = new Uint8Array(byteString.length)
42
41
 
43
- const blob = new Blob([byteArray], { type: 'application/pdf' })
44
- const link = URL.createObjectURL(blob)
45
- const anchorElement = document.createElement('a')
46
- anchorElement.style.display = 'none'
47
- anchorElement.href = link
48
- anchorElement.download = `${generateUniqueId()}.pdf`
49
-
50
- document.body.appendChild(anchorElement)
51
- anchorElement.click()
52
- URL.revokeObjectURL(link)
53
- document.body.removeChild(anchorElement)
54
- base64.value = ''
42
+ for (let i = 0; i < byteString.length; i++) {
43
+ byteArray[i] = byteString.charCodeAt(i)
44
+ }
45
+
46
+ const blob = new Blob([byteArray], { type: 'application/pdf' })
47
+ const link = URL.createObjectURL(blob)
48
+ const anchorElement = document.createElement('a')
49
+ anchorElement.style.display = 'none'
50
+ anchorElement.href = link
51
+ anchorElement.download = `${generateUniqueId()}.pdf`
52
+
53
+ document.body.appendChild(anchorElement)
54
+ anchorElement.click()
55
+ URL.revokeObjectURL(link)
56
+ document.body.removeChild(anchorElement)
57
+ base64.value = ''
58
+
59
+ alert?.addAlert({ message: 'Download success', alertType: 'success' })
60
+ }
61
+ catch (error) {
62
+ alert?.addAlert({ message: `Download unsuccess : ${error}`, alertType: 'error' })
63
+ }
55
64
  }
56
65
 
57
66
  const printPdf = () => {
@@ -60,7 +69,7 @@ const printPdf = () => {
60
69
  type: 'pdf',
61
70
  base64: true,
62
71
  onPrintDialogClose: endLoadPdf,
63
- onError: (error: any) => {
72
+ onError: (error) => {
64
73
  alert?.addAlert({ message: error, alertType: 'error' })
65
74
  },
66
75
  })
@@ -73,18 +82,19 @@ const endLoadPdf = () => {
73
82
  }
74
83
 
75
84
  const isMobile = () => {
76
- return /Android|Mobi|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Macintosh/i.test(navigator.userAgent);
85
+ return /Android|Mobi|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Macintosh/i.test(navigator.userAgent)
77
86
  }
78
87
 
79
88
  const checkMobileAndPrint = computed(() => {
80
- return !isMobile() && props.isPrint;
81
- });
89
+ return !isMobile() && props.isPrint
90
+ })
82
91
 
83
92
  const setWidthPdf = computed(() => {
84
93
  if (isMobile()) {
85
- return "100%"
86
- } else {
87
- return "100dvh"
94
+ return '100%'
95
+ }
96
+ else {
97
+ return '100dvh'
88
98
  }
89
99
  })
90
100
  </script>
@@ -114,10 +124,10 @@ const setWidthPdf = computed(() => {
114
124
  </v-toolbar>
115
125
  <v-card-text class="justify-center h-screen">
116
126
  <PDF
117
- v-bind="$attrs"
118
- :pdf-width="setWidthPdf"
119
- :src="base64"
120
- :show-back-to-top-btn="props.showBackToTopBtn"
127
+ v-bind="$attrs"
128
+ :pdf-width="setWidthPdf"
129
+ :src="base64"
130
+ :show-back-to-top-btn="props.showBackToTopBtn"
121
131
  />
122
132
  </v-card-text>
123
133
  </v-card>
@@ -34,13 +34,16 @@ function guessWidth(width) {
34
34
  export function processTemplateFormTable(item, parentTemplates, dataVariable) {
35
35
  let tableOptions = Object.assign({ title: item.inputLabel || "", formTemplate: "" }, item.inputOptions);
36
36
  let tableHeader = tableOptions.headers || [];
37
- if (!tableHeader.some((h) => h.key === "action")) tableHeader.push({ title: "Action", key: "action", width: "100px" });
38
37
  let tableItemTemplate = "";
39
38
  tableHeader.forEach((h) => {
40
39
  if (h.template) {
41
40
  tableItemTemplate += `\r
42
41
  <template #item.${h.key}="props">${h.template}</template>`;
42
+ } else {
43
+ tableItemTemplate += `\r
44
+ <template #item.${h.key}="props">{{autoSanitizedDisplay(props.item.${h.key})}}</template>`;
43
45
  }
44
46
  });
47
+ if (!tableHeader.some((h) => h.key === "action")) tableHeader.push({ title: "Action", key: "action", width: "100px" });
45
48
  return processDefaultTemplate(item, `<template #form="{data,rules}">${useDocumentTemplate(tableOptions.formTemplate)}</template>${tableItemTemplate}`, `title="${tableOptions.title}" :headers='${escapeObjectForInlineBinding(tableHeader)}'`, void 0, dataVariable);
46
49
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tantee-nuxt-commons",
3
- "version": "0.0.172",
3
+ "version": "0.0.174",
4
4
  "description": "Ramathibodi Nuxt modules for common components",
5
5
  "repository": {
6
6
  "type": "git",