@ramathibodi/nuxt-commons 0.1.14 → 0.1.15

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 +266 -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 +154 -154
@@ -1,231 +1,231 @@
1
- <script lang="ts" setup>
2
- import {computed, onBeforeUnmount, onMounted, ref, watchEffect} from "vue"
3
- import {useDevicesList, useUserMedia} from "@vueuse/core"
4
- import {getBase64Strings, type ImageFormat} from 'exif-rotate-js'
5
- import {useAlert} from '../../../composables/alert'
6
-
7
- interface Props {
8
- imageFormat?: ImageFormat
9
- autoStart?: boolean
10
- fileOnly?: boolean
11
- required?: boolean
12
- readonly?: boolean
13
- disabled?: boolean
14
- requiredMessage?: string
15
- buttonText?: string
16
- maxHeight?: string | number
17
- maxWidth?: string | number
18
- aspectRatio?: number
19
- }
20
-
21
- const props = withDefaults(defineProps<Props>(), {
22
- imageFormat: "image/jpeg",
23
- autoStart: true,
24
- fileOnly: false,
25
- required: false,
26
- readonly: false,
27
- disabled: false,
28
- requiredMessage: "This field is required",
29
- buttonText: "Add Photo",
30
- maxWidth: 1024
31
- })
32
-
33
- const alert = useAlert()
34
-
35
- const imageData = defineModel<string>()
36
-
37
- const isLoading = ref<boolean>(false)
38
- const isCaptured = computed(()=>!!imageData.value)
39
- const isEditing = ref<boolean>(false)
40
- const showRequiredMessage = ref<boolean>(false)
41
-
42
- const videoScreen = ref<HTMLVideoElement>()
43
-
44
- const currentCameraId = ref<ConstrainDOMString | undefined>()
45
- const { videoInputs: cameras } = useDevicesList({
46
- requestPermissions: true,
47
- constraints: { audio: false, video: true },
48
- onUpdated() {
49
- if (!cameras.value.find(camera => camera.deviceId === currentCameraId.value))
50
- currentCameraId.value = cameras.value[0]?.deviceId
51
- },
52
- })
53
- const hasCamera = computed(()=>{ return !!currentCameraId.value })
54
-
55
- const { stream, start: cameraStart, stop: cameraStop, enabled: cameraEnabled } = useUserMedia({
56
- constraints: { video: { deviceId: currentCameraId.value, width: {min: 1280}, aspectRatio: props.aspectRatio}},
57
- })
58
-
59
- watchEffect(() => {
60
- if (videoScreen.value) videoScreen.value.srcObject = (stream.value) ? stream.value! : null
61
- })
62
-
63
- function startCamera() {
64
- imageData.value = undefined
65
- if (!cameraEnabled.value && hasCamera) {
66
- isLoading.value = true
67
- cameraStart().finally(()=>{
68
- isLoading.value = false
69
- })
70
- }
71
- }
72
-
73
- function stopCamera() {
74
- if (cameraEnabled.value) cameraStop()
75
- }
76
-
77
- function captureImage() {
78
- if (videoScreen.value) {
79
- const canvas = document.createElement('canvas')
80
- canvas.width = videoScreen.value.videoWidth
81
- canvas.height = videoScreen.value.videoHeight
82
- const context = canvas.getContext('2d')
83
- if (context) {
84
- context.drawImage(videoScreen.value, 0, 0, canvas.width, canvas.height)
85
- isEditing.value = false
86
- imageData.value = canvas.toDataURL(props.imageFormat)
87
- stopCamera()
88
- }
89
- }
90
- }
91
-
92
- function captureImageFile(selectedFile: File | File[] | undefined) {
93
- if (!selectedFile) {
94
- alert?.addAlert({ message: 'No file selected.', alertType: 'error' })
95
- return
96
- }
97
-
98
- const scanImageSingleFile: File = Array.isArray(selectedFile) ? selectedFile[0] : selectedFile
99
-
100
- getBase64Strings([scanImageSingleFile], { maxSize: computedMaxSize.value,type: props.imageFormat,quality: 1 }).then((returnData) => {
101
- isEditing.value = false
102
- imageData.value = returnData[0]
103
- stopCamera()
104
- }).catch((e) => void e)
105
- }
106
-
107
- onMounted(() => {
108
- if (!isCaptured.value && props.autoStart && !props.fileOnly) startCamera()
109
- })
110
-
111
- onBeforeUnmount(() => {
112
- stopCamera()
113
- })
114
-
115
- function validate() {
116
- if (!props.required || isCaptured.value) {
117
- showRequiredMessage.value = false
118
- return true
119
- } else {
120
- showRequiredMessage.value = true
121
- return false
122
- }
123
- }
124
-
125
- function reset() {
126
- imageData.value = undefined
127
- stopCamera()
128
- if (props.autoStart && !props.fileOnly) startCamera()
129
- }
130
-
131
- const computedMaxWidth = computed(() => {
132
- if (typeof props.maxWidth === 'number') {
133
- return `${props.maxWidth}px`
134
- } else if (!isNaN(Number(props.maxWidth))) {
135
- return `${props.maxWidth}px`
136
- }
137
- return props.maxWidth
138
- })
139
-
140
- const computedMaxHeight = computed(() => {
141
- if (typeof props.maxHeight === 'number') {
142
- return `${props.maxHeight}px`
143
- } else if (!isNaN(Number(props.maxHeight))) {
144
- return `${props.maxHeight}px`
145
- }
146
- return props.maxHeight
147
- })
148
-
149
- const computedMaxSize = computed(() => {
150
- let tmpMaxHeight : number = 1024
151
- let tmpMaxWidth : number = 1024
152
-
153
- if (typeof props.maxWidth === 'number') {
154
- tmpMaxWidth = <number>props.maxWidth
155
- } else if (!isNaN(Number(props.maxWidth))) {
156
- tmpMaxWidth = Number(props.maxWidth)
157
- }
158
-
159
- if (typeof props.maxHeight === 'number') {
160
- tmpMaxHeight = <number>props.maxHeight
161
- } else if (!isNaN(Number(props.maxHeight))) {
162
- tmpMaxHeight = Number(props.maxHeight)
163
- }
164
-
165
- return (tmpMaxWidth>tmpMaxHeight) ? tmpMaxWidth : tmpMaxHeight
166
- })
167
-
168
- const operation = ref({startCamera,stopCamera,reset,captureImage,captureImageFile,isLoading,isCaptured,hasCamera})
169
- </script>
170
-
171
- <template>
172
- <v-card>
173
- <v-card-text class="d-flex justify-center text-center" v-if="!isLoading && !isCaptured">
174
- <template v-if="!hasCamera || fileOnly">
175
- <FileBtn
176
- color="primary"
177
- variant="flat"
178
- accept="image/*"
179
- @update:model-value="captureImageFile"
180
- :disabled="disabled || readonly"
181
- >
182
- <v-icon>mdi mdi-image-plus</v-icon>
183
- {{ buttonText }}
184
- </FileBtn>
185
- </template>
186
- <template v-else>
187
- <div style="position: relative; display: inline-block; width: 100%;" :style="{maxWidth:computedMaxWidth,maxHeight:computedMaxHeight}">
188
- <video autoplay ref="videoScreen" width="100%" :style="{maxWidth:computedMaxWidth,maxHeight:computedMaxHeight}"></video>
189
- <div style="position: absolute; bottom: 10px; right: 10px; z-index: 2000;">
190
- <FileBtn
191
- accept="image/*"
192
- icon="mdi mdi-image-plus"
193
- icon-only
194
- @update:model-value="captureImageFile"
195
- :disabled="disabled || readonly"
196
- />
197
- </div>
198
- </div>
199
- </template>
200
- </v-card-text>
201
- <v-card-text class="d-flex justify-center" v-if="isCaptured">
202
- <div style="position: relative; display: inline-block; width: 100%;" :style="{maxWidth:computedMaxWidth,maxHeight:computedMaxHeight}" v-if="!isEditing">
203
- <v-img :src="imageData" :max-height="maxHeight" :max-width="maxWidth" contain></v-img>
204
- <div style="position: absolute; bottom: 10px; right: 10px; z-index: 2000;">
205
- <v-btn
206
- icon="mdi mdi-image-edit"
207
- icon-only
208
- @click="isEditing=true"
209
- :disabled="disabled || readonly"
210
- />
211
- </div>
212
- </div>
213
- <form-images-edit v-model="imageData" :aspect-ratio="aspectRatio" :image-format="imageFormat" @update:model-value="isEditing=false" v-else></form-images-edit>
214
- </v-card-text>
215
- <v-card-text class="d-flex justify-center" v-if="isLoading">
216
- <v-progress-circular indeterminate></v-progress-circular>
217
- </v-card-text>
218
- <v-card-text v-if="showRequiredMessage" class="text-center">
219
- <span class="red--text">{{ requiredMessage }}</span>
220
- </v-card-text>
221
- <v-card-actions v-if="!readonly && (!fileOnly || isCaptured) && !isEditing">
222
- <slot name="actions" :operation="operation">
223
- <v-spacer></v-spacer>
224
- <v-btn color="primary" variant="flat" @click="startCamera" v-if="!cameraEnabled && hasCamera && !fileOnly" :disabled="disabled">{{ (isCaptured) ? "Retake" : "Start" }}</v-btn>
225
- <v-btn color="primary" variant="flat" @click="captureImage" v-if="cameraEnabled" :disabled="disabled">Capture</v-btn>
226
- <v-btn color="primary" variant="flat" @click="reset" :disabled="disabled">Reset</v-btn>
227
- <v-spacer></v-spacer>
228
- </slot>
229
- </v-card-actions>
230
- </v-card>
1
+ <script lang="ts" setup>
2
+ import {computed, onBeforeUnmount, onMounted, ref, watchEffect} from "vue"
3
+ import {useDevicesList, useUserMedia} from "@vueuse/core"
4
+ import {getBase64Strings, type ImageFormat} from 'exif-rotate-js'
5
+ import {useAlert} from '../../../composables/alert'
6
+
7
+ interface Props {
8
+ imageFormat?: ImageFormat
9
+ autoStart?: boolean
10
+ fileOnly?: boolean
11
+ required?: boolean
12
+ readonly?: boolean
13
+ disabled?: boolean
14
+ requiredMessage?: string
15
+ buttonText?: string
16
+ maxHeight?: string | number
17
+ maxWidth?: string | number
18
+ aspectRatio?: number
19
+ }
20
+
21
+ const props = withDefaults(defineProps<Props>(), {
22
+ imageFormat: "image/jpeg",
23
+ autoStart: true,
24
+ fileOnly: false,
25
+ required: false,
26
+ readonly: false,
27
+ disabled: false,
28
+ requiredMessage: "This field is required",
29
+ buttonText: "Add Photo",
30
+ maxWidth: 1024
31
+ })
32
+
33
+ const alert = useAlert()
34
+
35
+ const imageData = defineModel<string>()
36
+
37
+ const isLoading = ref<boolean>(false)
38
+ const isCaptured = computed(()=>!!imageData.value)
39
+ const isEditing = ref<boolean>(false)
40
+ const showRequiredMessage = ref<boolean>(false)
41
+
42
+ const videoScreen = ref<HTMLVideoElement>()
43
+
44
+ const currentCameraId = ref<ConstrainDOMString | undefined>()
45
+ const { videoInputs: cameras } = useDevicesList({
46
+ requestPermissions: true,
47
+ constraints: { audio: false, video: true },
48
+ onUpdated() {
49
+ if (!cameras.value.find(camera => camera.deviceId === currentCameraId.value))
50
+ currentCameraId.value = cameras.value[0]?.deviceId
51
+ },
52
+ })
53
+ const hasCamera = computed(()=>{ return !!currentCameraId.value })
54
+
55
+ const { stream, start: cameraStart, stop: cameraStop, enabled: cameraEnabled } = useUserMedia({
56
+ constraints: { video: { deviceId: currentCameraId.value, width: {min: 1280}, aspectRatio: props.aspectRatio}},
57
+ })
58
+
59
+ watchEffect(() => {
60
+ if (videoScreen.value) videoScreen.value.srcObject = (stream.value) ? stream.value! : null
61
+ })
62
+
63
+ function startCamera() {
64
+ imageData.value = undefined
65
+ if (!cameraEnabled.value && hasCamera) {
66
+ isLoading.value = true
67
+ cameraStart().finally(()=>{
68
+ isLoading.value = false
69
+ })
70
+ }
71
+ }
72
+
73
+ function stopCamera() {
74
+ if (cameraEnabled.value) cameraStop()
75
+ }
76
+
77
+ function captureImage() {
78
+ if (videoScreen.value) {
79
+ const canvas = document.createElement('canvas')
80
+ canvas.width = videoScreen.value.videoWidth
81
+ canvas.height = videoScreen.value.videoHeight
82
+ const context = canvas.getContext('2d')
83
+ if (context) {
84
+ context.drawImage(videoScreen.value, 0, 0, canvas.width, canvas.height)
85
+ isEditing.value = false
86
+ imageData.value = canvas.toDataURL(props.imageFormat)
87
+ stopCamera()
88
+ }
89
+ }
90
+ }
91
+
92
+ function captureImageFile(selectedFile: File | File[] | undefined) {
93
+ if (!selectedFile) {
94
+ alert?.addAlert({ message: 'No file selected.', alertType: 'error' })
95
+ return
96
+ }
97
+
98
+ const scanImageSingleFile: File = Array.isArray(selectedFile) ? selectedFile[0] : selectedFile
99
+
100
+ getBase64Strings([scanImageSingleFile], { maxSize: computedMaxSize.value,type: props.imageFormat,quality: 1 }).then((returnData) => {
101
+ isEditing.value = false
102
+ imageData.value = returnData[0]
103
+ stopCamera()
104
+ }).catch((e) => void e)
105
+ }
106
+
107
+ onMounted(() => {
108
+ if (!isCaptured.value && props.autoStart && !props.fileOnly) startCamera()
109
+ })
110
+
111
+ onBeforeUnmount(() => {
112
+ stopCamera()
113
+ })
114
+
115
+ function validate() {
116
+ if (!props.required || isCaptured.value) {
117
+ showRequiredMessage.value = false
118
+ return true
119
+ } else {
120
+ showRequiredMessage.value = true
121
+ return false
122
+ }
123
+ }
124
+
125
+ function reset() {
126
+ imageData.value = undefined
127
+ stopCamera()
128
+ if (props.autoStart && !props.fileOnly) startCamera()
129
+ }
130
+
131
+ const computedMaxWidth = computed(() => {
132
+ if (typeof props.maxWidth === 'number') {
133
+ return `${props.maxWidth}px`
134
+ } else if (!isNaN(Number(props.maxWidth))) {
135
+ return `${props.maxWidth}px`
136
+ }
137
+ return props.maxWidth
138
+ })
139
+
140
+ const computedMaxHeight = computed(() => {
141
+ if (typeof props.maxHeight === 'number') {
142
+ return `${props.maxHeight}px`
143
+ } else if (!isNaN(Number(props.maxHeight))) {
144
+ return `${props.maxHeight}px`
145
+ }
146
+ return props.maxHeight
147
+ })
148
+
149
+ const computedMaxSize = computed(() => {
150
+ let tmpMaxHeight : number = 1024
151
+ let tmpMaxWidth : number = 1024
152
+
153
+ if (typeof props.maxWidth === 'number') {
154
+ tmpMaxWidth = <number>props.maxWidth
155
+ } else if (!isNaN(Number(props.maxWidth))) {
156
+ tmpMaxWidth = Number(props.maxWidth)
157
+ }
158
+
159
+ if (typeof props.maxHeight === 'number') {
160
+ tmpMaxHeight = <number>props.maxHeight
161
+ } else if (!isNaN(Number(props.maxHeight))) {
162
+ tmpMaxHeight = Number(props.maxHeight)
163
+ }
164
+
165
+ return (tmpMaxWidth>tmpMaxHeight) ? tmpMaxWidth : tmpMaxHeight
166
+ })
167
+
168
+ const operation = ref({startCamera,stopCamera,reset,captureImage,captureImageFile,isLoading,isCaptured,hasCamera})
169
+ </script>
170
+
171
+ <template>
172
+ <v-card>
173
+ <v-card-text class="d-flex justify-center text-center" v-if="!isLoading && !isCaptured">
174
+ <template v-if="!hasCamera || fileOnly">
175
+ <FileBtn
176
+ color="primary"
177
+ variant="flat"
178
+ accept="image/*"
179
+ @update:model-value="captureImageFile"
180
+ :disabled="disabled || readonly"
181
+ >
182
+ <v-icon>mdi mdi-image-plus</v-icon>
183
+ {{ buttonText }}
184
+ </FileBtn>
185
+ </template>
186
+ <template v-else>
187
+ <div style="position: relative; display: inline-block; width: 100%;" :style="{maxWidth:computedMaxWidth,maxHeight:computedMaxHeight}">
188
+ <video autoplay ref="videoScreen" width="100%" :style="{maxWidth:computedMaxWidth,maxHeight:computedMaxHeight}"></video>
189
+ <div style="position: absolute; bottom: 10px; right: 10px; z-index: 2000;">
190
+ <FileBtn
191
+ accept="image/*"
192
+ icon="mdi mdi-image-plus"
193
+ icon-only
194
+ @update:model-value="captureImageFile"
195
+ :disabled="disabled || readonly"
196
+ />
197
+ </div>
198
+ </div>
199
+ </template>
200
+ </v-card-text>
201
+ <v-card-text class="d-flex justify-center" v-if="isCaptured">
202
+ <div style="position: relative; display: inline-block; width: 100%;" :style="{maxWidth:computedMaxWidth,maxHeight:computedMaxHeight}" v-if="!isEditing">
203
+ <v-img :src="imageData" :max-height="maxHeight" :max-width="maxWidth" contain></v-img>
204
+ <div style="position: absolute; bottom: 10px; right: 10px; z-index: 2000;">
205
+ <v-btn
206
+ icon="mdi mdi-image-edit"
207
+ icon-only
208
+ @click="isEditing=true"
209
+ :disabled="disabled || readonly"
210
+ />
211
+ </div>
212
+ </div>
213
+ <form-images-edit v-model="imageData" :aspect-ratio="aspectRatio" :image-format="imageFormat" @update:model-value="isEditing=false" v-else></form-images-edit>
214
+ </v-card-text>
215
+ <v-card-text class="d-flex justify-center" v-if="isLoading">
216
+ <v-progress-circular indeterminate></v-progress-circular>
217
+ </v-card-text>
218
+ <v-card-text v-if="showRequiredMessage" class="text-center">
219
+ <span class="red--text">{{ requiredMessage }}</span>
220
+ </v-card-text>
221
+ <v-card-actions v-if="!readonly && (!fileOnly || isCaptured) && !isEditing">
222
+ <slot name="actions" :operation="operation">
223
+ <v-spacer></v-spacer>
224
+ <v-btn color="primary" variant="flat" @click="startCamera" v-if="!cameraEnabled && hasCamera && !fileOnly" :disabled="disabled">{{ (isCaptured) ? "Retake" : "Start" }}</v-btn>
225
+ <v-btn color="primary" variant="flat" @click="captureImage" v-if="cameraEnabled" :disabled="disabled">Capture</v-btn>
226
+ <v-btn color="primary" variant="flat" @click="reset" :disabled="disabled">Reset</v-btn>
227
+ <v-spacer></v-spacer>
228
+ </slot>
229
+ </v-card-actions>
230
+ </v-card>
231
231
  </template>