@ramathibodi/nuxt-commons 0.1.72 → 0.1.74

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 (90) hide show
  1. package/README.md +74 -55
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +1 -0
  4. package/dist/runtime/components/Alert.vue +4 -0
  5. package/dist/runtime/components/BarcodeReader.vue +8 -0
  6. package/dist/runtime/components/ExportCSV.vue +13 -5
  7. package/dist/runtime/components/FileBtn.vue +17 -5
  8. package/dist/runtime/components/ImportCSV.vue +14 -2
  9. package/dist/runtime/components/MrzReader.vue +168 -0
  10. package/dist/runtime/components/SplitterPanel.vue +9 -1
  11. package/dist/runtime/components/TabsGroup.vue +9 -1
  12. package/dist/runtime/components/TextBarcode.vue +13 -1
  13. package/dist/runtime/components/device/IdCardButton.vue +15 -3
  14. package/dist/runtime/components/device/IdCardWebSocket.vue +18 -6
  15. package/dist/runtime/components/device/Scanner.vue +18 -6
  16. package/dist/runtime/components/dialog/Confirm.vue +20 -8
  17. package/dist/runtime/components/dialog/Host.vue +4 -0
  18. package/dist/runtime/components/dialog/Index.vue +17 -5
  19. package/dist/runtime/components/dialog/Loading.vue +14 -2
  20. package/dist/runtime/components/dialog/default/Confirm.vue +20 -8
  21. package/dist/runtime/components/dialog/default/Loading.vue +14 -2
  22. package/dist/runtime/components/dialog/default/Notify.vue +18 -6
  23. package/dist/runtime/components/dialog/default/Printing.vue +14 -2
  24. package/dist/runtime/components/dialog/default/VerifyUser.vue +20 -8
  25. package/dist/runtime/components/document/Form.vue +10 -2
  26. package/dist/runtime/components/document/TemplateBuilder.vue +14 -2
  27. package/dist/runtime/components/form/ActionPad.vue +19 -7
  28. package/dist/runtime/components/form/Birthdate.vue +15 -3
  29. package/dist/runtime/components/form/CheckboxGroup.vue +17 -5
  30. package/dist/runtime/components/form/CodeEditor.vue +11 -3
  31. package/dist/runtime/components/form/Date.vue +23 -11
  32. package/dist/runtime/components/form/DateTime.vue +29 -17
  33. package/dist/runtime/components/form/Dialog.vue +21 -9
  34. package/dist/runtime/components/form/EditPad.vue +20 -8
  35. package/dist/runtime/components/form/File.vue +18 -6
  36. package/dist/runtime/components/form/Hidden.vue +15 -3
  37. package/dist/runtime/components/form/Iterator.vue +43 -31
  38. package/dist/runtime/components/form/Login.vue +18 -6
  39. package/dist/runtime/components/form/Pad.vue +24 -12
  40. package/dist/runtime/components/form/SignPad.vue +13 -5
  41. package/dist/runtime/components/form/System.vue +10 -2
  42. package/dist/runtime/components/form/Table.vue +31 -19
  43. package/dist/runtime/components/form/TableData.vue +21 -9
  44. package/dist/runtime/components/form/Time.vue +16 -4
  45. package/dist/runtime/components/form/images/Capture.vue +17 -9
  46. package/dist/runtime/components/form/images/Edit.vue +16 -4
  47. package/dist/runtime/components/form/images/Field.vue +21 -10
  48. package/dist/runtime/components/form/images/Pad.vue +12 -0
  49. package/dist/runtime/components/label/Date.vue +12 -4
  50. package/dist/runtime/components/label/DateAgo.vue +13 -5
  51. package/dist/runtime/components/label/DateCount.vue +13 -5
  52. package/dist/runtime/components/label/Field.vue +14 -6
  53. package/dist/runtime/components/label/FormatMoney.vue +11 -3
  54. package/dist/runtime/components/label/Mask.vue +11 -3
  55. package/dist/runtime/components/label/Object.vue +11 -3
  56. package/dist/runtime/components/master/Autocomplete.vue +25 -7
  57. package/dist/runtime/components/master/Combobox.vue +26 -8
  58. package/dist/runtime/components/master/RadioGroup.vue +17 -5
  59. package/dist/runtime/components/master/Select.vue +24 -7
  60. package/dist/runtime/components/master/label.vue +14 -6
  61. package/dist/runtime/components/model/Autocomplete.vue +31 -12
  62. package/dist/runtime/components/model/Combobox.vue +30 -12
  63. package/dist/runtime/components/model/Pad.vue +15 -3
  64. package/dist/runtime/components/model/Select.vue +27 -7
  65. package/dist/runtime/components/model/Table.vue +30 -18
  66. package/dist/runtime/components/model/iterator.vue +36 -28
  67. package/dist/runtime/components/model/label.vue +16 -8
  68. package/dist/runtime/components/pdf/Print.vue +17 -5
  69. package/dist/runtime/components/pdf/View.vue +18 -6
  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/document/templateFormHidden.d.ts +4 -0
  73. package/dist/runtime/composables/localStorageModel.d.ts +4 -0
  74. package/dist/runtime/composables/lookupList.d.ts +16 -5
  75. package/dist/runtime/composables/lookupList.js +71 -21
  76. package/dist/runtime/composables/lookupListMaster.d.ts +4 -0
  77. package/dist/runtime/composables/lookupListMaster.js +9 -4
  78. package/dist/runtime/composables/menu.d.ts +4 -0
  79. package/dist/runtime/composables/useMrzReader.d.ts +48 -0
  80. package/dist/runtime/composables/useMrzReader.js +423 -0
  81. package/dist/runtime/composables/useTesseract.d.ts +16 -0
  82. package/dist/runtime/composables/useTesseract.js +45 -0
  83. package/dist/runtime/utils/asset.d.ts +2 -0
  84. package/dist/runtime/utils/asset.js +49 -0
  85. package/package.json +12 -3
  86. package/scripts/enrich-vue-docs-from-ai.mjs +197 -0
  87. package/scripts/generate-ai-summary.mjs +321 -0
  88. package/scripts/generate-composables-md.mjs +129 -0
  89. package/templates/public/tesseract/mrz.traineddata.gz +0 -0
  90. package/templates/public/tesseract/ocrb.traineddata.gz +0 -0
package/README.md CHANGED
@@ -1,45 +1,54 @@
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
1
  # @ramathibodi/nuxt-commons
10
2
 
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
-
3
+ Nuxt 3 module that provides shared runtime building blocks for Rama projects:
4
+ - globally auto-imported UI components
5
+ - auto-imported composables
6
+ - runtime plugins for permission/dialog/default behavior
7
+ - utility and lab exports
16
8
 
17
- ## Quick Setup
18
-
19
- 1. Add `'@ramathibodi/nuxt-commons'` dependency to your project
9
+ ## Install
20
10
 
21
11
  ```bash
22
- # Using pnpm
12
+ # pnpm
23
13
  pnpm add -D @ramathibodi/nuxt-commons
24
14
 
25
- # Using yarn
15
+ # yarn
26
16
  yarn add --dev @ramathibodi/nuxt-commons
27
17
 
28
- # Using npm
18
+ # npm
29
19
  npm install --save-dev @ramathibodi/nuxt-commons
30
20
  ```
31
21
 
32
- 2. Add `my-module` to the `modules` section of `nuxt.config.ts`
22
+ ## Nuxt Setup
33
23
 
34
- ```js
24
+ ```ts
25
+ // nuxt.config.ts
35
26
  export default defineNuxtConfig({
36
- modules: [
37
- '@ramathibodi/nuxt-commons'
38
- ]
27
+ modules: ['@ramathibodi/nuxt-commons'],
39
28
  })
40
29
  ```
41
30
 
42
- That's it! You can now use My Module in your Nuxt app ✨
31
+ ## What The Module Registers
32
+
33
+ Configured in `src/module.ts`:
34
+ - Components from `src/runtime/components` (global + prefixed)
35
+ - Composables from `src/runtime/composables/**` (auto-imported)
36
+ - Plugins:
37
+ - `src/runtime/plugins/permission.ts`
38
+ - `src/runtime/plugins/dialogManager.ts` (client)
39
+ - `src/runtime/plugins/clientConfig.ts` (client)
40
+ - `src/runtime/plugins/default.ts` (client)
41
+ - Type templates from `src/runtime/types/*.d.ts`
42
+
43
+ ## Runtime Config
44
+
45
+ This module uses public runtime config at:
46
+
47
+ ```ts
48
+ runtimeConfig.public['nuxt-commons']
49
+ ```
50
+
51
+ Module options are merged into this key by module setup.
43
52
 
44
53
  ## Development
45
54
 
@@ -47,50 +56,60 @@ That's it! You can now use My Module in your Nuxt app ✨
47
56
  # Install dependencies
48
57
  npm install
49
58
 
50
- # Generate type stubs
59
+ # Prepare stubs/types
51
60
  npm run dev:prepare
52
61
 
53
- # Develop with the playground
62
+ # Run playground
54
63
  npm run dev
55
64
 
56
- # Build the playground
65
+ # Build playground
57
66
  npm run dev:build
58
67
 
59
- # Run ESLint
68
+ # Lint and test
60
69
  npm run lint
61
-
62
- # Run Vitest
63
70
  npm run test
64
- npm run test:watch
65
-
66
- # Release new version
67
- npm run release
68
71
  ```
69
72
 
70
- ## NPM Login
71
- ```bash
72
- npm login
73
- ```
74
- - จะส่ง link url มาให้เข้าไปที่ url login npm
73
+ ## Documentation
74
+
75
+ Generate documentation artifacts from source:
75
76
 
76
- ## NPM PUBLISH
77
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. เสร็จสิ้น
78
+ # Vue component API docs (vue-docgen)
79
+ npm run docs:api:components
80
+
81
+ # Composable API docs (typedoc)
82
+ npm run docs:api:composables
83
+
84
+ # Both API docs
85
+ npm run docs:api
86
+
87
+ # AI-focused summary + type index
88
+ npm run docs:ai:summary
83
89
  ```
84
90
 
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
91
+ `docs:api:components` now runs a post-process step that enriches missing prop/event descriptions and missing type/default cells in generated markdown using `docs/ai-summary.json`.
88
92
 
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
93
+ Documentation config files:
94
+ - [`docs/vue-docgen.config.cjs`](docs/vue-docgen.config.cjs) for component docs generation
95
+ - [`docs/typedoc.json`](docs/typedoc.json) for composable docs generation
96
+ - [`docs/typedoc.tsconfig.json`](docs/typedoc.tsconfig.json) for docs-only TypeScript scope
91
97
 
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
98
+ Generated outputs:
99
+ - [`docs/components/`](docs/components/) (vue-docgen output)
100
+ - [`docs/composables/`](docs/composables/) (typedoc output)
101
+ - [`docs/ai-summary.md`](docs/ai-summary.md) (compact AI-oriented markdown summary)
102
+ - [`docs/ai-summary.json`](docs/ai-summary.json) (machine-readable component/composable metadata)
103
+ - [`docs/type-index.json`](docs/type-index.json) (type index for tooling/AI pipelines)
94
104
 
95
- [nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt.js
96
- [nuxt-href]: https://nuxt.com
105
+ `docs:ai:summary` generates:
106
+ - `docs/ai-summary.md`
107
+ - `docs/ai-summary.json`
108
+ - `docs/type-index.json`
109
+
110
+ ## Publish Notes
111
+
112
+ ```bash
113
+ npm run dev:build
114
+ npm publish --access public
115
+ ```
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.0.0"
6
6
  },
7
- "version": "0.1.72",
7
+ "version": "0.1.74",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -20,6 +20,7 @@ const module = defineNuxtModule({
20
20
  global: true
21
21
  });
22
22
  addImportsDir(resolver.resolve("runtime/composables/**"));
23
+ addImportsDir(resolver.resolve("runtime/utils/**"));
23
24
  addPlugin({
24
25
  src: resolver.resolve("runtime/plugins/permission")
25
26
  });
@@ -1,4 +1,8 @@
1
1
  <script lang="ts" setup>
2
+ /**
3
+ * Alert displays runtime alert messages and bridges alert-store entries to a consistent UI variant system.
4
+ * This doc block is consumed by vue-docgen for generated API documentation.
5
+ */
2
6
  import { ref, watch } from 'vue'
3
7
  import { isEmpty } from 'lodash-es'
4
8
  import { useAlert } from '../composables/alert'
@@ -1,4 +1,8 @@
1
1
  <script lang="ts" setup>
2
+ /**
3
+ * BarcodeReader starts and stops barcode scans, then emits parsed scan results back to parent workflows.
4
+ * This doc block is consumed by vue-docgen for generated API documentation.
5
+ */
2
6
  import {BrowserMultiFormatReader} from '@zxing/browser'
3
7
  import {type IScannerControls} from '@zxing/browser/esm'
4
8
  import type {Exception, Result} from '@zxing/library'
@@ -12,6 +16,10 @@ const barcodeReaderControl = ref()
12
16
  const alert = useAlert()
13
17
  const isLoading = ref<boolean>(false)
14
18
 
19
+ /**
20
+ * Custom events emitted by BarcodeReader.
21
+ * Parents can listen to these events to react to user actions and internal state changes.
22
+ */
15
23
  const emit = defineEmits<{
16
24
  (event: 'decode', barcodeValue: string): void
17
25
  (event: 'error', error: string | unknown): void
@@ -1,17 +1,25 @@
1
1
  <script lang="ts" setup>
2
+ /**
3
+ * ExportCSV exports array data to spreadsheet files, flattening nested fields before file generation.
4
+ * This doc block is consumed by vue-docgen for generated API documentation.
5
+ */
2
6
  import { ref } from 'vue'
3
7
  import * as XLSX from 'xlsx'
4
8
  import { VBtn } from 'vuetify/components/VBtn'
5
9
  import { useAlert } from '../composables/alert'
6
10
 
7
11
  interface ExportButtonProps extends /* @vue-ignore */ InstanceType<typeof VBtn['$props']> {
8
- fileName?: string
9
- sheetName?: string
10
- modelValue?: object[]
11
- stringFields?: Array<string>
12
- tooltip?: string | Record<string,any> | undefined
12
+ fileName?: string // File name used when downloading or printing generated files.
13
+ sheetName?: string // Configuration option used by ExportCSV.
14
+ modelValue?: object[] // Bound value for v-model synchronization with the parent component.
15
+ stringFields?: Array<string> // Field paths that must stay as string values (no nested object conversion).
16
+ tooltip?: string | Record<string,any> | undefined // Tooltip text or config object shown for the action control.
13
17
  }
14
18
 
19
+ /**
20
+ * Public props accepted by ExportCSV.
21
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
22
+ */
15
23
  const props = withDefaults(defineProps<ExportButtonProps>(), {
16
24
  fileName: 'download',
17
25
  sheetName: 'Sheet1',
@@ -1,21 +1,33 @@
1
1
  <script lang="ts" setup>
2
+ /**
3
+ * FileBtn wraps file selection behavior into a reusable button interface that works with form and upload flows.
4
+ * This doc block is consumed by vue-docgen for generated API documentation.
5
+ */
2
6
  import {ref} from 'vue'
3
7
  import {VBtn} from 'vuetify/components/VBtn'
4
8
 
5
9
  interface Props extends /* @vue-ignore */ InstanceType<typeof VBtn['$props']> {
6
- accept?: string
7
- multiple?: boolean
8
- iconOnly?: boolean
9
- modelValue?: File | File[] | undefined
10
- tooltip?: string | Record<string,any> | undefined
10
+ accept?: string // Accepted file MIME types or extensions for file selection.
11
+ multiple?: boolean // Allows selecting or uploading more than one file.
12
+ iconOnly?: boolean // icon name/class used in UI rendering
13
+ modelValue?: File | File[] | undefined // Bound value for v-model synchronization with the parent component.
14
+ tooltip?: string | Record<string,any> | undefined // Tooltip text or config object shown for the action control.
11
15
  }
12
16
 
17
+ /**
18
+ * Public props accepted by FileBtn.
19
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
20
+ */
13
21
  const props = withDefaults(defineProps<Props>(), {
14
22
  multiple: false,
15
23
  accept: '*',
16
24
  tooltip: 'Upload File',
17
25
  })
18
26
 
27
+ /**
28
+ * Custom events emitted by FileBtn.
29
+ * Parents can listen to these events to react to user actions and internal state changes.
30
+ */
19
31
  const emit = defineEmits<{
20
32
  (event: 'update:modelValue', value: File | File[] | undefined): void
21
33
  }>()
@@ -1,20 +1,32 @@
1
1
  <script lang="ts" setup>
2
+ /**
3
+ * ImportCSV imports spreadsheet rows, maps nested object keys, and emits normalized records for downstream processing.
4
+ * This doc block is consumed by vue-docgen for generated API documentation.
5
+ */
2
6
  import * as XLSX from 'xlsx'
3
7
  import { ref } from 'vue'
4
8
  import { useAlert } from '../composables/alert'
5
9
  import { VBtn } from 'vuetify/components/VBtn'
6
10
 
7
11
  interface ImportButtonProps extends /* @vue-ignore */ InstanceType<typeof VBtn['$props']> {
8
- stringFields?: Array<string>
9
- tooltip?: string | Record<string,any> | undefined
12
+ stringFields?: Array<string> // Field paths that must stay as string values (no nested object conversion).
13
+ tooltip?: string | Record<string,any> | undefined // Tooltip text or config object shown for the action control.
10
14
  }
11
15
 
16
+ /**
17
+ * Public props accepted by ImportCSV.
18
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
19
+ */
12
20
  const props = withDefaults(defineProps<ImportButtonProps>(), {
13
21
  stringFields: ()=>[],
14
22
  tooltip: ()=>({text: 'Import', location: 'bottom'}),
15
23
  })
16
24
 
17
25
  const alert = useAlert()
26
+ /**
27
+ * Custom events emitted by ImportCSV.
28
+ * Parents can listen to these events to react to user actions and internal state changes.
29
+ */
18
30
  const emit = defineEmits<{
19
31
  (e: 'import', value: object[]): void
20
32
  }>()
@@ -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,4 +1,8 @@
1
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
+ */
2
6
  import { ref } from 'vue'
3
7
  import { VCard } from 'vuetify/components/VCard'
4
8
 
@@ -6,8 +10,12 @@ const isResizing = ref(false)
6
10
  const pane1Width = ref('50%')
7
11
  const containerRef = ref<HTMLElement>()
8
12
  interface Props extends /* @vue-ignore */ InstanceType<typeof VCard['$props']> {
9
- height?: number | string
13
+ height?: number | string // Fixed or minimum height applied to the component container.
10
14
  }
15
+ /**
16
+ * Public props accepted by SplitterPanel.
17
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
18
+ */
11
19
  const props = defineProps<Props>()
12
20
 
13
21
  const startResize = () => {
@@ -1,14 +1,22 @@
1
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
+ */
2
6
  import {VTabs} from 'vuetify/components'
3
7
 
4
8
  interface Props extends /* @vue-ignore */ InstanceType<typeof VTabs['$props']> {
5
- flat?: boolean
9
+ flat?: boolean // Uses a flatter tab style with reduced elevation and borders.
6
10
  }
7
11
 
8
12
  defineOptions({
9
13
  inheritAttrs: false,
10
14
  })
11
15
 
16
+ /**
17
+ * Public props accepted by TabsGroup.
18
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
19
+ */
12
20
  const props = defineProps<Props>()
13
21
  const currentTab = defineModel<string|number>()
14
22
  </script>
@@ -1,12 +1,24 @@
1
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
+ */
2
6
  import {ref, watch} from 'vue'
3
7
  import {useAlert} from '../composables/alert'
4
8
 
5
9
  interface Props {
6
- modelValue?: string
10
+ modelValue?: string // Bound value for v-model synchronization with the parent component.
7
11
  }
8
12
 
13
+ /**
14
+ * Public props accepted by TextBarcode.
15
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
16
+ */
9
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
+ */
10
22
  const emit = defineEmits<{
11
23
  (event: 'update:modelValue', value: string | undefined): void
12
24
  (event: 'decode', value: string | undefined): void
@@ -1,4 +1,8 @@
1
1
  <script setup lang="ts">
2
+ /**
3
+ * DeviceIdCardButton bridges UI actions with host-agent hardware/device operations and emits runtime scan/read results.
4
+ * This doc block is consumed by vue-docgen for generated API documentation.
5
+ */
2
6
  import { computed, ref, useAttrs } from 'vue'
3
7
  import { VBtn } from 'vuetify/components/VBtn'
4
8
  import { useAlert } from '../../composables/alert'
@@ -6,19 +10,27 @@ import { useHostAgent, type PatientRegisterPayload } from '../../composables/hos
6
10
 
7
11
  interface Props extends /* @vue-ignore */ InstanceType<typeof VBtn['$props']> {
8
12
  /** If true -> call /idcard/infoAndPhoto, else /idcard/info */
9
- withPhoto?: boolean
13
+ withPhoto?: boolean // Includes portrait/photo data in ID card read results.
10
14
  /** Optional reader name/query string */
11
- reader?: string | null
15
+ reader?: string | null // Preferred hardware reader identifier to connect or switch to.
12
16
  /** Auto-disable button while reading */
13
- disableWhileLoading?: boolean
17
+ disableWhileLoading?: boolean // Disables the trigger button while a read operation is in progress.
14
18
  }
15
19
 
20
+ /**
21
+ * Public props accepted by DeviceIdCardButton.
22
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
23
+ */
16
24
  const props = withDefaults(defineProps<Props>(), {
17
25
  withPhoto: false,
18
26
  reader: null,
19
27
  disableWhileLoading: true,
20
28
  })
21
29
 
30
+ /**
31
+ * Custom events emitted by DeviceIdCardButton.
32
+ * Parents can listen to these events to react to user actions and internal state changes.
33
+ */
22
34
  const emit = defineEmits<{
23
35
  (e: 'read', payload: PatientRegisterPayload): void
24
36
  (e: 'error', err: unknown): void
@@ -1,23 +1,31 @@
1
1
  <script setup lang="ts">
2
+ /**
3
+ * DeviceIdCardWebSocket bridges UI actions with host-agent hardware/device operations and emits runtime scan/read results.
4
+ * This doc block is consumed by vue-docgen for generated API documentation.
5
+ */
2
6
  import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
3
7
  import { type IdCardWsServerMessage, type PatientRegisterPayload } from '../../composables/hostAgent'
4
8
  import { useHostAgentWs } from "../../composables/hostAgentWs";
5
9
 
6
10
  interface Props {
7
11
  /** Subscribe withPhoto=true => server will push payload that includes photo when available */
8
- withPhoto?: boolean
12
+ withPhoto?: boolean // Includes portrait/photo data in ID card read results.
9
13
  /** Optional reader name; null/undefined means "any/default" */
10
- reader?: string | null
14
+ reader?: string | null // Preferred hardware reader identifier to connect or switch to.
11
15
  /** Auto-connect on mount (default true) */
12
- autoConnect?: boolean
16
+ autoConnect?: boolean // Connects to the device WebSocket automatically on mount.
13
17
  /** Auto-subscribe after connect (default true) */
14
- autoSubscribe?: boolean
18
+ autoSubscribe?: boolean // Subscribes to live reader events automatically after connect.
15
19
  /** If true, try to reconnect when socket closes unexpectedly */
16
- autoReconnect?: boolean
20
+ autoReconnect?: boolean // Retries connection automatically when the socket closes unexpectedly.
17
21
  /** Reconnect delay in ms */
18
- reconnectDelayMs?: number
22
+ reconnectDelayMs?: number // Delay in milliseconds before each reconnect attempt.
19
23
  }
20
24
 
25
+ /**
26
+ * Public props accepted by DeviceIdCardWebSocket.
27
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
28
+ */
21
29
  const props = withDefaults(defineProps<Props>(), {
22
30
  withPhoto: false,
23
31
  reader: null,
@@ -27,6 +35,10 @@ const props = withDefaults(defineProps<Props>(), {
27
35
  reconnectDelayMs: 1000,
28
36
  })
29
37
 
38
+ /**
39
+ * Custom events emitted by DeviceIdCardWebSocket.
40
+ * Parents can listen to these events to react to user actions and internal state changes.
41
+ */
30
42
  const emit = defineEmits<{
31
43
  (e: 'connected'): void
32
44
  (e: 'disconnected', info?: { code?: number; reason?: string }): void