@ramathibodi/nuxt-commons 0.1.73 → 0.1.75

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 (111) hide show
  1. package/README.md +115 -96
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +1 -0
  4. package/dist/runtime/components/Alert.vue +58 -54
  5. package/dist/runtime/components/BarcodeReader.vue +130 -122
  6. package/dist/runtime/components/ExportCSV.vue +110 -102
  7. package/dist/runtime/components/FileBtn.vue +79 -67
  8. package/dist/runtime/components/ImportCSV.vue +151 -139
  9. package/dist/runtime/components/MrzReader.vue +168 -0
  10. package/dist/runtime/components/SplitterPanel.vue +67 -59
  11. package/dist/runtime/components/TabsGroup.vue +39 -31
  12. package/dist/runtime/components/TextBarcode.vue +66 -54
  13. package/dist/runtime/components/device/IdCardButton.vue +95 -83
  14. package/dist/runtime/components/device/IdCardWebSocket.vue +207 -195
  15. package/dist/runtime/components/device/Scanner.vue +350 -338
  16. package/dist/runtime/components/dialog/Confirm.vue +112 -100
  17. package/dist/runtime/components/dialog/Host.vue +88 -84
  18. package/dist/runtime/components/dialog/Index.vue +84 -72
  19. package/dist/runtime/components/dialog/Loading.vue +51 -39
  20. package/dist/runtime/components/dialog/default/Confirm.vue +112 -100
  21. package/dist/runtime/components/dialog/default/Loading.vue +60 -48
  22. package/dist/runtime/components/dialog/default/Notify.vue +82 -70
  23. package/dist/runtime/components/dialog/default/Printing.vue +46 -34
  24. package/dist/runtime/components/dialog/default/VerifyUser.vue +144 -132
  25. package/dist/runtime/components/document/Form.vue +50 -42
  26. package/dist/runtime/components/document/TemplateBuilder.vue +536 -524
  27. package/dist/runtime/components/form/ActionPad.vue +156 -144
  28. package/dist/runtime/components/form/Birthdate.vue +116 -104
  29. package/dist/runtime/components/form/CheckboxGroup.vue +99 -87
  30. package/dist/runtime/components/form/CodeEditor.vue +45 -37
  31. package/dist/runtime/components/form/Date.vue +270 -258
  32. package/dist/runtime/components/form/DateTime.vue +220 -208
  33. package/dist/runtime/components/form/Dialog.vue +178 -166
  34. package/dist/runtime/components/form/EditPad.vue +157 -145
  35. package/dist/runtime/components/form/File.vue +295 -283
  36. package/dist/runtime/components/form/Hidden.vue +44 -32
  37. package/dist/runtime/components/form/Iterator.vue +538 -526
  38. package/dist/runtime/components/form/Login.vue +143 -131
  39. package/dist/runtime/components/form/Pad.vue +399 -387
  40. package/dist/runtime/components/form/SignPad.vue +226 -218
  41. package/dist/runtime/components/form/System.vue +34 -26
  42. package/dist/runtime/components/form/Table.vue +391 -379
  43. package/dist/runtime/components/form/TableData.vue +236 -224
  44. package/dist/runtime/components/form/Time.vue +177 -165
  45. package/dist/runtime/components/form/images/Capture.vue +245 -237
  46. package/dist/runtime/components/form/images/Edit.vue +133 -121
  47. package/dist/runtime/components/form/images/Field.vue +331 -320
  48. package/dist/runtime/components/form/images/Pad.vue +54 -42
  49. package/dist/runtime/components/label/Date.vue +37 -29
  50. package/dist/runtime/components/label/DateAgo.vue +102 -94
  51. package/dist/runtime/components/label/DateCount.vue +152 -144
  52. package/dist/runtime/components/label/Field.vue +111 -103
  53. package/dist/runtime/components/label/FormatMoney.vue +37 -29
  54. package/dist/runtime/components/label/Mask.vue +46 -38
  55. package/dist/runtime/components/label/Object.vue +21 -13
  56. package/dist/runtime/components/master/Autocomplete.vue +89 -81
  57. package/dist/runtime/components/master/Combobox.vue +88 -80
  58. package/dist/runtime/components/master/RadioGroup.vue +90 -78
  59. package/dist/runtime/components/master/Select.vue +70 -62
  60. package/dist/runtime/components/master/label.vue +55 -47
  61. package/dist/runtime/components/model/Autocomplete.vue +91 -79
  62. package/dist/runtime/components/model/Combobox.vue +90 -78
  63. package/dist/runtime/components/model/Pad.vue +114 -102
  64. package/dist/runtime/components/model/Select.vue +78 -72
  65. package/dist/runtime/components/model/Table.vue +370 -358
  66. package/dist/runtime/components/model/iterator.vue +497 -489
  67. package/dist/runtime/components/model/label.vue +58 -50
  68. package/dist/runtime/components/pdf/Print.vue +75 -63
  69. package/dist/runtime/components/pdf/View.vue +146 -134
  70. package/dist/runtime/composables/alert.d.ts +4 -0
  71. package/dist/runtime/composables/api.d.ts +4 -0
  72. package/dist/runtime/composables/dialog.d.ts +1 -1
  73. package/dist/runtime/composables/document/templateFormHidden.d.ts +4 -0
  74. package/dist/runtime/composables/graphql.d.ts +1 -1
  75. package/dist/runtime/composables/graphqlModel.d.ts +9 -9
  76. package/dist/runtime/composables/graphqlModelItem.d.ts +7 -7
  77. package/dist/runtime/composables/graphqlModelOperation.d.ts +6 -6
  78. package/dist/runtime/composables/localStorageModel.d.ts +4 -0
  79. package/dist/runtime/composables/lookupList.d.ts +4 -0
  80. package/dist/runtime/composables/menu.d.ts +4 -0
  81. package/dist/runtime/composables/useMrzReader.d.ts +48 -0
  82. package/dist/runtime/composables/useMrzReader.js +423 -0
  83. package/dist/runtime/composables/useTesseract.d.ts +16 -0
  84. package/dist/runtime/composables/useTesseract.js +45 -0
  85. package/dist/runtime/composables/userPermission.d.ts +1 -1
  86. package/dist/runtime/labs/Calendar.vue +99 -99
  87. package/dist/runtime/labs/form/EditMobile.vue +152 -152
  88. package/dist/runtime/labs/form/TextFieldMask.vue +43 -43
  89. package/dist/runtime/plugins/clientConfig.d.ts +1 -1
  90. package/dist/runtime/plugins/default.d.ts +1 -1
  91. package/dist/runtime/plugins/dialogManager.d.ts +1 -1
  92. package/dist/runtime/plugins/permission.d.ts +1 -1
  93. package/dist/runtime/types/alert.d.ts +11 -11
  94. package/dist/runtime/types/clientConfig.d.ts +13 -13
  95. package/dist/runtime/types/dialogManager.d.ts +35 -35
  96. package/dist/runtime/types/formDialog.d.ts +5 -5
  97. package/dist/runtime/types/graphqlOperation.d.ts +23 -23
  98. package/dist/runtime/types/menu.d.ts +31 -31
  99. package/dist/runtime/types/modules.d.ts +7 -7
  100. package/dist/runtime/types/permission.d.ts +13 -13
  101. package/dist/runtime/utils/asset.d.ts +2 -0
  102. package/dist/runtime/utils/asset.js +49 -0
  103. package/package.json +131 -122
  104. package/scripts/enrich-vue-docs-from-ai.mjs +197 -0
  105. package/scripts/generate-ai-summary.mjs +321 -0
  106. package/scripts/generate-composables-md.mjs +129 -0
  107. package/scripts/postInstall.cjs +70 -70
  108. package/templates/.codegen/codegen.ts +32 -32
  109. package/templates/.codegen/plugin-schema-object.js +161 -161
  110. package/templates/public/tesseract/mrz.traineddata.gz +0 -0
  111. package/templates/public/tesseract/ocrb.traineddata.gz +0 -0
@@ -0,0 +1,168 @@
1
+ <script lang="ts" setup>
2
+ /**
3
+ * MrzReader captures passport/ID images from camera or upload, runs OCR + MRZ parsing,
4
+ * and emits normalized MRZ data once checksum validation passes.
5
+ */
6
+ import { computed, onBeforeUnmount, onMounted, ref, watchEffect } from 'vue'
7
+ import { useDevicesList, useUserMedia } from '@vueuse/core'
8
+ import { useAlert } from '../composables/alert'
9
+ import { useMrzReader, type MrzResult } from '../composables/useMrzReader'
10
+
11
+ const mrzReaderControl = ref<number | null>(null)
12
+
13
+ const alert = useAlert()
14
+ const isLoading = ref(false)
15
+
16
+ interface Props {
17
+ intervalMs?: number // Scan interval (ms) for periodic camera-frame OCR attempts.
18
+ scaleFactor?: number // Upscale factor applied before OCR to improve small-text readability.
19
+ useOpenCv?: boolean // Enables OpenCV-assisted region detection before OCR.
20
+ }
21
+
22
+ const props = withDefaults(defineProps<Props>(), {
23
+ intervalMs: 900,
24
+ scaleFactor: 2,
25
+ useOpenCv: true,
26
+ })
27
+
28
+ const emit = defineEmits<{
29
+ (event: 'decode', value: MrzResult): void // Emitted when a valid MRZ payload is parsed.
30
+ (event: 'error', error: string | unknown): void // Emitted when camera/OCR/parsing fails.
31
+ }>()
32
+
33
+ const videoScreen = ref<HTMLVideoElement>()
34
+
35
+ const currentCameraId = ref<ConstrainDOMString | undefined>()
36
+ const { videoInputs: cameras } = useDevicesList({
37
+ requestPermissions: true,
38
+ constraints: { audio: false, video: true },
39
+ onUpdated() {
40
+ if (!cameras.value.find(camera => camera.deviceId === currentCameraId.value))
41
+ currentCameraId.value = cameras.value[0]?.deviceId
42
+ },
43
+ })
44
+
45
+ const hasCamera = computed(() => !!currentCameraId.value)
46
+
47
+ const { stream, start: cameraStart, stop: cameraStop, enabled: cameraEnabled } = useUserMedia({
48
+ constraints: { video: { deviceId: currentCameraId.value } },
49
+ })
50
+
51
+ watchEffect(() => {
52
+ if (videoScreen.value)
53
+ videoScreen.value.srcObject = stream.value ?? null
54
+ })
55
+
56
+ const mrzReader = useMrzReader({
57
+ scaleFactor: props.scaleFactor,
58
+ useOpenCv: props.useOpenCv,
59
+ lang: 'ocrb',
60
+ langPath: '/tesseract/',
61
+ })
62
+
63
+ async function scanOnce() {
64
+ if (!videoScreen.value || !cameraEnabled.value) return
65
+
66
+ try {
67
+ const parsed = await mrzReader.decodeFromVideoElement(videoScreen.value)
68
+ if (parsed) {
69
+ emit('decode', parsed)
70
+ stopCamera()
71
+ }
72
+ }
73
+ catch (err) {
74
+ emit('error', err)
75
+ }
76
+ }
77
+
78
+ function startCamera() {
79
+ if (cameraEnabled.value) return
80
+
81
+ isLoading.value = true
82
+ cameraStart()
83
+ .then(() => {
84
+ if (mrzReaderControl.value) {
85
+ window.clearInterval(mrzReaderControl.value)
86
+ mrzReaderControl.value = null
87
+ }
88
+
89
+ mrzReaderControl.value = window.setInterval(() => {
90
+ void scanOnce()
91
+ }, props.intervalMs)
92
+ })
93
+ .catch((err) => {
94
+ emit('error', err)
95
+ })
96
+ .finally(() => {
97
+ isLoading.value = false
98
+ })
99
+ }
100
+
101
+ function stopCamera() {
102
+ if (mrzReaderControl.value) {
103
+ window.clearInterval(mrzReaderControl.value)
104
+ mrzReaderControl.value = null
105
+ }
106
+ if (cameraEnabled.value)
107
+ cameraStop()
108
+ }
109
+
110
+ function scanImageFile(selectedFile: File | File[] | undefined) {
111
+ if (!selectedFile) {
112
+ alert?.addAlert({ message: 'No file selected.', alertType: 'error' })
113
+ return
114
+ }
115
+
116
+ const file = Array.isArray(selectedFile) ? selectedFile[0] : selectedFile
117
+
118
+ void mrzReader.decodeFromImageFile(file)
119
+ .then((parsed) => {
120
+ if (parsed)
121
+ emit('decode', parsed)
122
+ else
123
+ alert?.addAlert({ message: 'MRZ not found or checksum invalid.', alertType: 'warning' })
124
+ })
125
+ .catch((err) => {
126
+ emit('error', err)
127
+ })
128
+ }
129
+
130
+ onMounted(() => {
131
+ void mrzReader.ensureOpenCvReady()
132
+ startCamera()
133
+ })
134
+
135
+ onBeforeUnmount(() => {
136
+ stopCamera()
137
+ })
138
+ </script>
139
+
140
+ <template>
141
+ <v-card flat>
142
+ <v-card-text class="d-flex justify-center" v-if="isLoading">
143
+ <v-progress-circular indeterminate />
144
+ </v-card-text>
145
+ <v-card-text v-else>
146
+ <v-col v-if="hasCamera">
147
+ <div style="position: relative; display: inline-block; width: 100%;" :style="{ maxWidth: '1024px' }">
148
+ <video autoplay ref="videoScreen" width="100%" :style="{ maxWidth: '1024px' }"></video>
149
+ <div style="position: absolute; bottom: 10px; right: 10px; z-index: 2000;">
150
+ <FileBtn
151
+ accept="image/*"
152
+ icon="mdi mdi-image-plus"
153
+ icon-only
154
+ @update:model-value="scanImageFile"
155
+ />
156
+ </div>
157
+ </div>
158
+ </v-col>
159
+ <v-col v-else>
160
+ <FileBtn
161
+ accept="image/*"
162
+ text="Upload Image"
163
+ @update:model-value="scanImageFile"
164
+ />
165
+ </v-col>
166
+ </v-card-text>
167
+ </v-card>
168
+ </template>
@@ -1,61 +1,69 @@
1
- <script setup lang="ts">
2
- import { ref } from 'vue'
3
- import { VCard } from 'vuetify/components/VCard'
4
-
5
- const isResizing = ref(false)
6
- const pane1Width = ref('50%')
7
- const containerRef = ref<HTMLElement>()
8
- interface Props extends /* @vue-ignore */ InstanceType<typeof VCard['$props']> {
9
- height?: number | string
10
- }
11
- const props = defineProps<Props>()
12
-
13
- const startResize = () => {
14
- isResizing.value = true
15
- }
16
-
17
- const stopResize = () => {
18
- isResizing.value = false
19
- }
20
-
21
- const resize = (event: MouseEvent) => {
22
- if (isResizing.value && containerRef.value) {
23
- const containerRect = containerRef.value.getBoundingClientRect()
24
- const newWidth = event.clientX - containerRect.left
25
- pane1Width.value = `${(newWidth / containerRect.width) * 100}%`
26
- }
27
- }
28
- </script>
29
-
30
- <template>
31
- <v-card :="$attrs">
32
- <v-sheet
33
- border
34
- :height="props.height"
35
- >
36
- <div
37
- ref="containerRef"
38
- class="d-flex"
39
- @mouseup="stopResize"
40
- @mousemove="resize"
41
- >
42
- <v-sheet :width="pane1Width">
43
- <slot name="left" />
44
- </v-sheet>
45
- <v-divider
46
- :thickness="3"
47
- vertical
48
- class="cursor-move"
49
- @mousedown="startResize"
50
- />
51
- <v-sheet :width="`calc(100% - ${pane1Width})`">
52
- <slot name="right" />
53
- </v-sheet>
54
- </div>
55
- </v-sheet>
56
- </v-card>
57
- </template>
58
-
1
+ <script setup lang="ts">
2
+ /**
3
+ * SplitterPanel provides a resizable split layout panel for flexible, user-adjustable page composition.
4
+ * This doc block is consumed by vue-docgen for generated API documentation.
5
+ */
6
+ import { ref } from 'vue'
7
+ import { VCard } from 'vuetify/components/VCard'
8
+
9
+ const isResizing = ref(false)
10
+ const pane1Width = ref('50%')
11
+ const containerRef = ref<HTMLElement>()
12
+ interface Props extends /* @vue-ignore */ InstanceType<typeof VCard['$props']> {
13
+ height?: number | string // Fixed or minimum height applied to the component container.
14
+ }
15
+ /**
16
+ * Public props accepted by SplitterPanel.
17
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
18
+ */
19
+ const props = defineProps<Props>()
20
+
21
+ const startResize = () => {
22
+ isResizing.value = true
23
+ }
24
+
25
+ const stopResize = () => {
26
+ isResizing.value = false
27
+ }
28
+
29
+ const resize = (event: MouseEvent) => {
30
+ if (isResizing.value && containerRef.value) {
31
+ const containerRect = containerRef.value.getBoundingClientRect()
32
+ const newWidth = event.clientX - containerRect.left
33
+ pane1Width.value = `${(newWidth / containerRect.width) * 100}%`
34
+ }
35
+ }
36
+ </script>
37
+
38
+ <template>
39
+ <v-card :="$attrs">
40
+ <v-sheet
41
+ border
42
+ :height="props.height"
43
+ >
44
+ <div
45
+ ref="containerRef"
46
+ class="d-flex"
47
+ @mouseup="stopResize"
48
+ @mousemove="resize"
49
+ >
50
+ <v-sheet :width="pane1Width">
51
+ <slot name="left" />
52
+ </v-sheet>
53
+ <v-divider
54
+ :thickness="3"
55
+ vertical
56
+ class="cursor-move"
57
+ @mousedown="startResize"
58
+ />
59
+ <v-sheet :width="`calc(100% - ${pane1Width})`">
60
+ <slot name="right" />
61
+ </v-sheet>
62
+ </div>
63
+ </v-sheet>
64
+ </v-card>
65
+ </template>
66
+
59
67
  <style scoped>
60
68
 
61
- </style>
69
+ </style>
@@ -1,31 +1,39 @@
1
- <script lang="ts" setup>
2
- import {VTabs} from 'vuetify/components'
3
-
4
- interface Props extends /* @vue-ignore */ InstanceType<typeof VTabs['$props']> {
5
- flat?: boolean
6
- }
7
-
8
- defineOptions({
9
- inheritAttrs: false,
10
- })
11
-
12
- const props = defineProps<Props>()
13
- const currentTab = defineModel<string|number>()
14
- </script>
15
-
16
- <template>
17
- <v-card :flat="props.flat">
18
- <v-tabs
19
- v-bind="$attrs"
20
- v-model="currentTab"
21
- show-arrows
22
- >
23
- <slot name="tabs" />
24
- </v-tabs>
25
- <v-card-text>
26
- <v-tabs-window v-model="currentTab">
27
- <slot name="items" />
28
- </v-tabs-window>
29
- </v-card-text>
30
- </v-card>
31
- </template>
1
+ <script lang="ts" setup>
2
+ /**
3
+ * TabsGroup renders grouped tab content and keeps tab state consistent across controlled and uncontrolled usage.
4
+ * This doc block is consumed by vue-docgen for generated API documentation.
5
+ */
6
+ import {VTabs} from 'vuetify/components'
7
+
8
+ interface Props extends /* @vue-ignore */ InstanceType<typeof VTabs['$props']> {
9
+ flat?: boolean // Uses a flatter tab style with reduced elevation and borders.
10
+ }
11
+
12
+ defineOptions({
13
+ inheritAttrs: false,
14
+ })
15
+
16
+ /**
17
+ * Public props accepted by TabsGroup.
18
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
19
+ */
20
+ const props = defineProps<Props>()
21
+ const currentTab = defineModel<string|number>()
22
+ </script>
23
+
24
+ <template>
25
+ <v-card :flat="props.flat">
26
+ <v-tabs
27
+ v-bind="$attrs"
28
+ v-model="currentTab"
29
+ show-arrows
30
+ >
31
+ <slot name="tabs" />
32
+ </v-tabs>
33
+ <v-card-text>
34
+ <v-tabs-window v-model="currentTab">
35
+ <slot name="items" />
36
+ </v-tabs-window>
37
+ </v-card-text>
38
+ </v-card>
39
+ </template>
@@ -1,54 +1,66 @@
1
- <script lang="ts" setup>
2
- import {ref, watch} from 'vue'
3
- import {useAlert} from '../composables/alert'
4
-
5
- interface Props {
6
- modelValue?: string
7
- }
8
-
9
- const props = defineProps<Props>()
10
- const emit = defineEmits<{
11
- (event: 'update:modelValue', value: string | undefined): void
12
- (event: 'decode', value: string | undefined): void
13
- }>()
14
- const alert = useAlert()
15
-
16
- const scanCode = ref<boolean>(false)
17
- const currentValue = ref<string>()
18
-
19
- const handleData = (data: string) => {
20
- currentValue.value = data
21
- scanCode.value = false
22
- emit('decode',data)
23
- }
24
-
25
- const handleError = (error: string | unknown) => {
26
- alert?.addAlert({ message: error as string, alertType: 'error' })
27
- }
28
-
29
- watch(() => props.modelValue, () => {
30
- currentValue.value = props.modelValue
31
- }, { immediate: true })
32
-
33
- watch(currentValue, (newValue) => {
34
- emit('update:modelValue', newValue)
35
- })
36
- </script>
37
-
38
- <template>
39
- <v-text-field
40
- v-model="currentValue"
41
- v-bind="$attrs"
42
- append-inner-icon="mdi mdi-qrcode-scan"
43
- @click:append-inner="scanCode = true"
44
- />
45
- <v-dialog
46
- v-model="scanCode"
47
- width="auto"
48
- >
49
- <BarcodeReader
50
- @decode="handleData"
51
- @error="handleError"
52
- />
53
- </v-dialog>
54
- </template>
1
+ <script lang="ts" setup>
2
+ /**
3
+ * TextBarcode renders barcode output from plain text and updates when bound values change.
4
+ * This doc block is consumed by vue-docgen for generated API documentation.
5
+ */
6
+ import {ref, watch} from 'vue'
7
+ import {useAlert} from '../composables/alert'
8
+
9
+ interface Props {
10
+ modelValue?: string // Bound value for v-model synchronization with the parent component.
11
+ }
12
+
13
+ /**
14
+ * Public props accepted by TextBarcode.
15
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
16
+ */
17
+ const props = defineProps<Props>()
18
+ /**
19
+ * Custom events emitted by TextBarcode.
20
+ * Parents can listen to these events to react to user actions and internal state changes.
21
+ */
22
+ const emit = defineEmits<{
23
+ (event: 'update:modelValue', value: string | undefined): void
24
+ (event: 'decode', value: string | undefined): void
25
+ }>()
26
+ const alert = useAlert()
27
+
28
+ const scanCode = ref<boolean>(false)
29
+ const currentValue = ref<string>()
30
+
31
+ const handleData = (data: string) => {
32
+ currentValue.value = data
33
+ scanCode.value = false
34
+ emit('decode',data)
35
+ }
36
+
37
+ const handleError = (error: string | unknown) => {
38
+ alert?.addAlert({ message: error as string, alertType: 'error' })
39
+ }
40
+
41
+ watch(() => props.modelValue, () => {
42
+ currentValue.value = props.modelValue
43
+ }, { immediate: true })
44
+
45
+ watch(currentValue, (newValue) => {
46
+ emit('update:modelValue', newValue)
47
+ })
48
+ </script>
49
+
50
+ <template>
51
+ <v-text-field
52
+ v-model="currentValue"
53
+ v-bind="$attrs"
54
+ append-inner-icon="mdi mdi-qrcode-scan"
55
+ @click:append-inner="scanCode = true"
56
+ />
57
+ <v-dialog
58
+ v-model="scanCode"
59
+ width="auto"
60
+ >
61
+ <BarcodeReader
62
+ @decode="handleData"
63
+ @error="handleError"
64
+ />
65
+ </v-dialog>
66
+ </template>