@ramathibodi/nuxt-commons 0.1.14 → 0.1.16

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.
Files changed (54) hide show
  1. package/README.md +96 -96
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/components/Alert.vue +53 -53
  4. package/dist/runtime/components/BarcodeReader.vue +98 -98
  5. package/dist/runtime/components/ExportCSV.vue +55 -55
  6. package/dist/runtime/components/FileBtn.vue +62 -62
  7. package/dist/runtime/components/ImportCSV.vue +64 -64
  8. package/dist/runtime/components/SplitterPanel.vue +59 -59
  9. package/dist/runtime/components/TabsGroup.vue +32 -32
  10. package/dist/runtime/components/TextBarcode.vue +52 -52
  11. package/dist/runtime/components/dialog/Confirm.vue +100 -100
  12. package/dist/runtime/components/dialog/Index.vue +72 -72
  13. package/dist/runtime/components/dialog/Loading.vue +39 -39
  14. package/dist/runtime/components/document/TemplateBuilder.vue +203 -216
  15. package/dist/runtime/components/form/Birthdate.vue +216 -216
  16. package/dist/runtime/components/form/CodeEditor.vue +37 -37
  17. package/dist/runtime/components/form/Date.vue +163 -163
  18. package/dist/runtime/components/form/DateTime.vue +107 -107
  19. package/dist/runtime/components/form/Dialog.vue +138 -138
  20. package/dist/runtime/components/form/File.vue +187 -187
  21. package/dist/runtime/components/form/Hidden.vue +32 -32
  22. package/dist/runtime/components/form/Login.vue +131 -131
  23. package/dist/runtime/components/form/Pad.vue +217 -217
  24. package/dist/runtime/components/form/SignPad.vue +186 -186
  25. package/dist/runtime/components/form/Table.vue +294 -266
  26. package/dist/runtime/components/form/Time.vue +158 -158
  27. package/dist/runtime/components/form/images/Capture.vue +230 -230
  28. package/dist/runtime/components/form/images/Edit.vue +114 -114
  29. package/dist/runtime/components/label/Date.vue +29 -29
  30. package/dist/runtime/components/label/Field.vue +42 -42
  31. package/dist/runtime/components/label/FormatMoney.vue +29 -29
  32. package/dist/runtime/components/label/Mask.vue +38 -38
  33. package/dist/runtime/components/master/Autocomplete.vue +159 -159
  34. package/dist/runtime/components/master/Combobox.vue +84 -84
  35. package/dist/runtime/components/master/RadioGroup.vue +78 -78
  36. package/dist/runtime/components/master/Select.vue +82 -82
  37. package/dist/runtime/components/model/Pad.vue +122 -122
  38. package/dist/runtime/components/model/Table.vue +242 -240
  39. package/dist/runtime/components/model/iterator.vue +312 -312
  40. package/dist/runtime/components/pdf/Print.vue +63 -63
  41. package/dist/runtime/components/pdf/View.vue +104 -104
  42. package/dist/runtime/composables/graphqlModel.mjs +1 -1
  43. package/dist/runtime/labs/Calendar.vue +99 -99
  44. package/dist/runtime/labs/form/EditMobile.vue +152 -152
  45. package/dist/runtime/labs/form/TextFieldMask.vue +43 -43
  46. package/dist/runtime/types/alert.d.ts +11 -11
  47. package/dist/runtime/types/formDialog.d.ts +4 -4
  48. package/dist/runtime/types/graphqlOperation.d.ts +23 -23
  49. package/dist/runtime/types/menu.d.ts +25 -25
  50. package/dist/runtime/types/modules.d.ts +7 -7
  51. package/package.json +120 -119
  52. package/scripts/postInstall.cjs +70 -70
  53. package/templates/.codegen/codegen.ts +32 -32
  54. package/templates/.codegen/plugin-schema-object.js +161 -154
package/README.md CHANGED
@@ -1,96 +1,96 @@
1
- <!--
2
- Get your module up and running quickly.
3
-
4
- Find and replace all on all files (CMD+SHIFT+F):
5
- - Name: Ramahis Common Component
6
- - Package name: @ramahis/common-components
7
- -->
8
-
9
- # @ramathibodi/nuxt-commons
10
-
11
- [![npm version][npm-version-src]][npm-version-href]
12
- [![npm downloads][npm-downloads-src]][npm-downloads-href]
13
- [![License][license-src]][license-href]
14
- [![Nuxt][nuxt-src]][nuxt-href]
15
-
16
-
17
- ## Quick Setup
18
-
19
- 1. Add `'@ramathibodi/nuxt-commons'` dependency to your project
20
-
21
- ```bash
22
- # Using pnpm
23
- pnpm add -D @ramathibodi/nuxt-commons
24
-
25
- # Using yarn
26
- yarn add --dev @ramathibodi/nuxt-commons
27
-
28
- # Using npm
29
- npm install --save-dev @ramathibodi/nuxt-commons
30
- ```
31
-
32
- 2. Add `my-module` to the `modules` section of `nuxt.config.ts`
33
-
34
- ```js
35
- export default defineNuxtConfig({
36
- modules: [
37
- '@ramathibodi/nuxt-commons'
38
- ]
39
- })
40
- ```
41
-
42
- That's it! You can now use My Module in your Nuxt app ✨
43
-
44
- ## Development
45
-
46
- ```bash
47
- # Install dependencies
48
- npm install
49
-
50
- # Generate type stubs
51
- npm run dev:prepare
52
-
53
- # Develop with the playground
54
- npm run dev
55
-
56
- # Build the playground
57
- npm run dev:build
58
-
59
- # Run ESLint
60
- npm run lint
61
-
62
- # Run Vitest
63
- npm run test
64
- npm run test:watch
65
-
66
- # Release new version
67
- npm run release
68
- ```
69
-
70
- ## NPM Login
71
- ```bash
72
- npm login
73
- ```
74
- - จะส่ง link url มาให้เข้าไปที่ url login npm
75
-
76
- ## NPM PUBLISH
77
- ```bash
78
- 1. ตรวจสอบ source code, ตรวจสอบ Branch ว่าเป็น master แล้ว จากนั้นตรวจสอบ version ของ npm ว่ามีการเปลี่ยนและไม่ชนกับ version บน npm
79
- 2. npm run dev:build
80
- 3. npm publish --access public
81
- 4. set token ใน link ที่ npm ให้มา
82
- 5. เสร็จสิ้น
83
- ```
84
-
85
- <!-- Badges -->
86
- [npm-version-src]: https://img.shields.io/npm/v/my-module/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
87
- [npm-version-href]: https://npmjs.com/package/my-module
88
-
89
- [npm-downloads-src]: https://img.shields.io/npm/dm/my-module.svg?style=flat&colorA=18181B&colorB=28CF8D
90
- [npm-downloads-href]: https://npmjs.com/package/my-module
91
-
92
- [license-src]: https://img.shields.io/npm/l/my-module.svg?style=flat&colorA=18181B&colorB=28CF8D
93
- [license-href]: https://npmjs.com/package/my-module
94
-
95
- [nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt.js
96
- [nuxt-href]: https://nuxt.com
1
+ <!--
2
+ Get your module up and running quickly.
3
+
4
+ Find and replace all on all files (CMD+SHIFT+F):
5
+ - Name: Ramahis Common Component
6
+ - Package name: @ramahis/common-components
7
+ -->
8
+
9
+ # @ramathibodi/nuxt-commons
10
+
11
+ [![npm version][npm-version-src]][npm-version-href]
12
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
13
+ [![License][license-src]][license-href]
14
+ [![Nuxt][nuxt-src]][nuxt-href]
15
+
16
+
17
+ ## Quick Setup
18
+
19
+ 1. Add `'@ramathibodi/nuxt-commons'` dependency to your project
20
+
21
+ ```bash
22
+ # Using pnpm
23
+ pnpm add -D @ramathibodi/nuxt-commons
24
+
25
+ # Using yarn
26
+ yarn add --dev @ramathibodi/nuxt-commons
27
+
28
+ # Using npm
29
+ npm install --save-dev @ramathibodi/nuxt-commons
30
+ ```
31
+
32
+ 2. Add `my-module` to the `modules` section of `nuxt.config.ts`
33
+
34
+ ```js
35
+ export default defineNuxtConfig({
36
+ modules: [
37
+ '@ramathibodi/nuxt-commons'
38
+ ]
39
+ })
40
+ ```
41
+
42
+ That's it! You can now use My Module in your Nuxt app ✨
43
+
44
+ ## Development
45
+
46
+ ```bash
47
+ # Install dependencies
48
+ npm install
49
+
50
+ # Generate type stubs
51
+ npm run dev:prepare
52
+
53
+ # Develop with the playground
54
+ npm run dev
55
+
56
+ # Build the playground
57
+ npm run dev:build
58
+
59
+ # Run ESLint
60
+ npm run lint
61
+
62
+ # Run Vitest
63
+ npm run test
64
+ npm run test:watch
65
+
66
+ # Release new version
67
+ npm run release
68
+ ```
69
+
70
+ ## NPM Login
71
+ ```bash
72
+ npm login
73
+ ```
74
+ - จะส่ง link url มาให้เข้าไปที่ url login npm
75
+
76
+ ## NPM PUBLISH
77
+ ```bash
78
+ 1. ตรวจสอบ source code, ตรวจสอบ Branch ว่าเป็น master แล้ว จากนั้นตรวจสอบ version ของ npm ว่ามีการเปลี่ยนและไม่ชนกับ version บน npm
79
+ 2. npm run dev:build
80
+ 3. npm publish --access public
81
+ 4. set token ใน link ที่ npm ให้มา
82
+ 5. เสร็จสิ้น
83
+ ```
84
+
85
+ <!-- Badges -->
86
+ [npm-version-src]: https://img.shields.io/npm/v/my-module/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
87
+ [npm-version-href]: https://npmjs.com/package/my-module
88
+
89
+ [npm-downloads-src]: https://img.shields.io/npm/dm/my-module.svg?style=flat&colorA=18181B&colorB=28CF8D
90
+ [npm-downloads-href]: https://npmjs.com/package/my-module
91
+
92
+ [license-src]: https://img.shields.io/npm/l/my-module.svg?style=flat&colorA=18181B&colorB=28CF8D
93
+ [license-href]: https://npmjs.com/package/my-module
94
+
95
+ [nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt.js
96
+ [nuxt-href]: https://nuxt.com
package/dist/module.json CHANGED
@@ -4,5 +4,5 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.0.0"
6
6
  },
7
- "version": "0.1.14"
7
+ "version": "0.1.16"
8
8
  }
@@ -1,53 +1,53 @@
1
- <script lang="ts" setup>
2
- import { ref, watch } from 'vue'
3
- import { isEmpty } from 'lodash-es'
4
- import { useAlert } from '../composables/alert'
5
- import type { AlertItem } from '../types/alert'
6
-
7
- const isAlertOpen = ref(false)
8
- const timeout = ref(3000)
9
- const alert = useAlert()
10
- const currentItem = ref<AlertItem | undefined>()
11
-
12
- const renewAlert = () => {
13
- if (alert?.hasAlert()) {
14
- currentItem.value = alert?.takeAlert()
15
- isAlertOpen.value = true
16
- }
17
- else {
18
- currentItem.value = undefined
19
- isAlertOpen.value = false
20
- }
21
- }
22
-
23
- watch(() => alert?.hasAlert(), (hasAlert) => {
24
- if (hasAlert) {
25
- renewAlert()
26
- }
27
- })
28
- </script>
29
-
30
- <template>
31
- <VSnackbar
32
- v-if="currentItem"
33
- v-model="isAlertOpen"
34
- :timeout="timeout"
35
- location="center"
36
- multi-line
37
- variant="text"
38
- @update:model-value="renewAlert()"
39
- >
40
- <!-- @vue-expected-error Type conversion problem -->
41
- <VAlert
42
- v-model="isAlertOpen"
43
- closable
44
- :type="currentItem.alertType"
45
- elevation="2"
46
- theme="dark"
47
- variant="flat"
48
- @click:close="renewAlert()"
49
- >
50
- {{ currentItem.statusCode ? currentItem.statusCode + ' ' : '' }} {{ currentItem.message }} {{ !isEmpty(currentItem.data) ? currentItem.data : '' }}
51
- </VAlert>
52
- </VSnackbar>
53
- </template>
1
+ <script lang="ts" setup>
2
+ import { ref, watch } from 'vue'
3
+ import { isEmpty } from 'lodash-es'
4
+ import { useAlert } from '../composables/alert'
5
+ import type { AlertItem } from '../types/alert'
6
+
7
+ const isAlertOpen = ref(false)
8
+ const timeout = ref(3000)
9
+ const alert = useAlert()
10
+ const currentItem = ref<AlertItem | undefined>()
11
+
12
+ const renewAlert = () => {
13
+ if (alert?.hasAlert()) {
14
+ currentItem.value = alert?.takeAlert()
15
+ isAlertOpen.value = true
16
+ }
17
+ else {
18
+ currentItem.value = undefined
19
+ isAlertOpen.value = false
20
+ }
21
+ }
22
+
23
+ watch(() => alert?.hasAlert(), (hasAlert) => {
24
+ if (hasAlert) {
25
+ renewAlert()
26
+ }
27
+ })
28
+ </script>
29
+
30
+ <template>
31
+ <VSnackbar
32
+ v-if="currentItem"
33
+ v-model="isAlertOpen"
34
+ :timeout="timeout"
35
+ location="center"
36
+ multi-line
37
+ variant="text"
38
+ @update:model-value="renewAlert()"
39
+ >
40
+ <!-- @vue-expected-error Type conversion problem -->
41
+ <VAlert
42
+ v-model="isAlertOpen"
43
+ closable
44
+ :type="currentItem.alertType"
45
+ elevation="2"
46
+ theme="dark"
47
+ variant="flat"
48
+ @click:close="renewAlert()"
49
+ >
50
+ {{ currentItem.statusCode ? currentItem.statusCode + ' ' : '' }} {{ currentItem.message }} {{ !isEmpty(currentItem.data) ? currentItem.data : '' }}
51
+ </VAlert>
52
+ </VSnackbar>
53
+ </template>
@@ -1,98 +1,98 @@
1
- <script lang="ts" setup>
2
- import { BrowserMultiFormatReader } from '@zxing/browser'
3
- import { type IScannerControls } from '@zxing/browser/esm'
4
- import type { Exception, Result } from '@zxing/library'
5
- import { ref, onMounted } from 'vue'
6
- import { useAlert } from '../composables/alert'
7
-
8
- const videoElementRef = ref<HTMLVideoElement | null>(null)
9
- const barcodeReader = new BrowserMultiFormatReader()
10
- const alert = useAlert()
11
- const hasCameraAvailable = ref(false)
12
-
13
- const emit = defineEmits<{
14
- (event: 'decode', barcodeValue: string): void
15
- (event: 'error', error: string | unknown): void
16
- }>()
17
-
18
- async function checkCameraAvailability() {
19
- const devices = await navigator.mediaDevices.enumerateDevices()
20
- hasCameraAvailable.value = devices.some(device => device.kind === 'videoinput')
21
- }
22
-
23
- async function startCamera() {
24
- try {
25
- const videoInputDevices = await BrowserMultiFormatReader.listVideoInputDevices()
26
- if (videoInputDevices.length === 0) {
27
- alert?.addAlert({ message: 'No camera devices found.', alertType: 'error' })
28
- return
29
- }
30
-
31
- const selectedDeviceId = videoInputDevices[0].deviceId
32
- barcodeReader.decodeFromVideoDevice(selectedDeviceId, videoElementRef.value, (result: Result | undefined, error: Exception | undefined, controls: IScannerControls) => {
33
- if (result) {
34
- emit('decode', result.getText())
35
- controls.stop()
36
- }
37
- })
38
- }
39
- catch (error) {
40
- emit('error', error)
41
- alert?.addAlert({ message: 'Error starting camera.', alertType: 'error' })
42
- }
43
- }
44
-
45
- function scanImageFile(selectedFile: File | File[] | undefined) {
46
- if (!selectedFile) {
47
- alert?.addAlert({ message: 'No file selected.', alertType: 'error' })
48
- return
49
- }
50
-
51
- const reader = new FileReader()
52
- reader.onload = async (event) => {
53
- try {
54
- const result = await barcodeReader.decodeFromImageUrl(event.target?.result as string)
55
- emit('decode', result.getText())
56
- }
57
- catch (error) {
58
- alert?.addAlert({ message: 'Unable to read barcode from image.', alertType: 'error' })
59
- }
60
- }
61
- const scanImageSingleFile: File = Array.isArray(selectedFile) ? selectedFile[0] : selectedFile
62
- reader.readAsDataURL(scanImageSingleFile)
63
- }
64
-
65
- onMounted(async () => {
66
- await checkCameraAvailability()
67
- if (hasCameraAvailable.value) await startCamera()
68
- })
69
- </script>
70
-
71
- <template>
72
- <v-card flat>
73
- <v-card-item>
74
- <v-col v-if="hasCameraAvailable">
75
- <video
76
- ref="videoElementRef"
77
- autoplay
78
- style="max-width: 1024px"
79
- />
80
- <div style="z-index: 2000; position: relative; bottom: 84px; left: 550px">
81
- <FileBtn
82
- accept="image/*"
83
- icon="mdi mdi-image-plus"
84
- icon-only
85
- @update:model-value="scanImageFile"
86
- />
87
- </div>
88
- </v-col>
89
- <v-col v-else>
90
- <FileBtn
91
- accept="image/*"
92
- text="Upload Image"
93
- @update:model-value="scanImageFile"
94
- />
95
- </v-col>
96
- </v-card-item>
97
- </v-card>
98
- </template>
1
+ <script lang="ts" setup>
2
+ import { BrowserMultiFormatReader } from '@zxing/browser'
3
+ import { type IScannerControls } from '@zxing/browser/esm'
4
+ import type { Exception, Result } from '@zxing/library'
5
+ import { ref, onMounted } from 'vue'
6
+ import { useAlert } from '../composables/alert'
7
+
8
+ const videoElementRef = ref<HTMLVideoElement | null>(null)
9
+ const barcodeReader = new BrowserMultiFormatReader()
10
+ const alert = useAlert()
11
+ const hasCameraAvailable = ref(false)
12
+
13
+ const emit = defineEmits<{
14
+ (event: 'decode', barcodeValue: string): void
15
+ (event: 'error', error: string | unknown): void
16
+ }>()
17
+
18
+ async function checkCameraAvailability() {
19
+ const devices = await navigator.mediaDevices.enumerateDevices()
20
+ hasCameraAvailable.value = devices.some(device => device.kind === 'videoinput')
21
+ }
22
+
23
+ async function startCamera() {
24
+ try {
25
+ const videoInputDevices = await BrowserMultiFormatReader.listVideoInputDevices()
26
+ if (videoInputDevices.length === 0) {
27
+ alert?.addAlert({ message: 'No camera devices found.', alertType: 'error' })
28
+ return
29
+ }
30
+
31
+ const selectedDeviceId = videoInputDevices[0].deviceId
32
+ barcodeReader.decodeFromVideoDevice(selectedDeviceId, videoElementRef.value, (result: Result | undefined, error: Exception | undefined, controls: IScannerControls) => {
33
+ if (result) {
34
+ emit('decode', result.getText())
35
+ controls.stop()
36
+ }
37
+ })
38
+ }
39
+ catch (error) {
40
+ emit('error', error)
41
+ alert?.addAlert({ message: 'Error starting camera.', alertType: 'error' })
42
+ }
43
+ }
44
+
45
+ function scanImageFile(selectedFile: File | File[] | undefined) {
46
+ if (!selectedFile) {
47
+ alert?.addAlert({ message: 'No file selected.', alertType: 'error' })
48
+ return
49
+ }
50
+
51
+ const reader = new FileReader()
52
+ reader.onload = async (event) => {
53
+ try {
54
+ const result = await barcodeReader.decodeFromImageUrl(event.target?.result as string)
55
+ emit('decode', result.getText())
56
+ }
57
+ catch (error) {
58
+ alert?.addAlert({ message: 'Unable to read barcode from image.', alertType: 'error' })
59
+ }
60
+ }
61
+ const scanImageSingleFile: File = Array.isArray(selectedFile) ? selectedFile[0] : selectedFile
62
+ reader.readAsDataURL(scanImageSingleFile)
63
+ }
64
+
65
+ onMounted(async () => {
66
+ await checkCameraAvailability()
67
+ if (hasCameraAvailable.value) await startCamera()
68
+ })
69
+ </script>
70
+
71
+ <template>
72
+ <v-card flat>
73
+ <v-card-item>
74
+ <v-col v-if="hasCameraAvailable">
75
+ <video
76
+ ref="videoElementRef"
77
+ autoplay
78
+ style="max-width: 1024px"
79
+ />
80
+ <div style="z-index: 2000; position: relative; bottom: 84px; left: 550px">
81
+ <FileBtn
82
+ accept="image/*"
83
+ icon="mdi mdi-image-plus"
84
+ icon-only
85
+ @update:model-value="scanImageFile"
86
+ />
87
+ </div>
88
+ </v-col>
89
+ <v-col v-else>
90
+ <FileBtn
91
+ accept="image/*"
92
+ text="Upload Image"
93
+ @update:model-value="scanImageFile"
94
+ />
95
+ </v-col>
96
+ </v-card-item>
97
+ </v-card>
98
+ </template>
@@ -1,55 +1,55 @@
1
- <script lang="ts" setup>
2
- import {ref, withDefaults} from 'vue'
3
- import * as XLSX from 'xlsx'
4
- import {VBtn} from 'vuetify/components/VBtn'
5
- import {useAlert} from '../composables/alert'
6
-
7
- interface ExportButtonProps extends /* @vue-ignore */ InstanceType<typeof VBtn['$props']> {
8
- fileName?: string
9
- modelValue?: object[]
10
- }
11
-
12
- const props = withDefaults(defineProps<ExportButtonProps>(), {
13
- fileName: 'download',
14
- })
15
-
16
- const alert = useAlert()
17
- const loading = ref(false)
18
-
19
- function exportFile() {
20
- if (props.modelValue && Array.isArray(props.modelValue)) {
21
- loading.value = true
22
- const workbook = XLSX.utils.book_new()
23
- const worksheet = XLSX.utils.json_to_sheet(props.modelValue)
24
- const fileName = `${props.fileName}.xlsx`
25
- XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
26
- XLSX.writeFile(workbook, fileName)
27
- loading.value = false
28
- }
29
- else {
30
- alert?.addAlert({ message: 'Invalid or no data to export', alertType: 'error' })
31
- }
32
- }
33
- </script>
34
-
35
- <template>
36
- <VBtn
37
- v-bind="$attrs"
38
- color="primary"
39
- :loading="loading"
40
- :disabled="loading"
41
- text="Export CSV"
42
- @click="exportFile"
43
- >
44
- <template
45
- v-for="(_, name, index) in ($slots as {})"
46
- :key="index"
47
- #[name]="slotData"
48
- >
49
- <slot
50
- :name="name"
51
- v-bind="((slotData || {}) as object)"
52
- />
53
- </template>
54
- </VBtn>
55
- </template>
1
+ <script lang="ts" setup>
2
+ import {ref, withDefaults} from 'vue'
3
+ import * as XLSX from 'xlsx'
4
+ import {VBtn} from 'vuetify/components/VBtn'
5
+ import {useAlert} from '../composables/alert'
6
+
7
+ interface ExportButtonProps extends /* @vue-ignore */ InstanceType<typeof VBtn['$props']> {
8
+ fileName?: string
9
+ modelValue?: object[]
10
+ }
11
+
12
+ const props = withDefaults(defineProps<ExportButtonProps>(), {
13
+ fileName: 'download',
14
+ })
15
+
16
+ const alert = useAlert()
17
+ const loading = ref(false)
18
+
19
+ function exportFile() {
20
+ if (props.modelValue && Array.isArray(props.modelValue)) {
21
+ loading.value = true
22
+ const workbook = XLSX.utils.book_new()
23
+ const worksheet = XLSX.utils.json_to_sheet(props.modelValue)
24
+ const fileName = `${props.fileName}.xlsx`
25
+ XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
26
+ XLSX.writeFile(workbook, fileName)
27
+ loading.value = false
28
+ }
29
+ else {
30
+ alert?.addAlert({ message: 'Invalid or no data to export', alertType: 'error' })
31
+ }
32
+ }
33
+ </script>
34
+
35
+ <template>
36
+ <VBtn
37
+ v-bind="$attrs"
38
+ color="primary"
39
+ :loading="loading"
40
+ :disabled="loading"
41
+ text="Export CSV"
42
+ @click="exportFile"
43
+ >
44
+ <template
45
+ v-for="(_, name, index) in ($slots as {})"
46
+ :key="index"
47
+ #[name]="slotData"
48
+ >
49
+ <slot
50
+ :name="name"
51
+ v-bind="((slotData || {}) as object)"
52
+ />
53
+ </template>
54
+ </VBtn>
55
+ </template>