@ramathibodi/nuxt-commons 0.0.1

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 (49) hide show
  1. package/README.md +81 -0
  2. package/dist/module.cjs +5 -0
  3. package/dist/module.d.mts +7 -0
  4. package/dist/module.d.ts +7 -0
  5. package/dist/module.json +8 -0
  6. package/dist/module.mjs +34 -0
  7. package/dist/runtime/components/Alert.vue +52 -0
  8. package/dist/runtime/components/BarcodeReader.vue +98 -0
  9. package/dist/runtime/components/Calendar.vue +99 -0
  10. package/dist/runtime/components/Camera.vue +116 -0
  11. package/dist/runtime/components/ExportCSV.vue +55 -0
  12. package/dist/runtime/components/FileBtn.vue +56 -0
  13. package/dist/runtime/components/ImportCSV.vue +64 -0
  14. package/dist/runtime/components/Pdf/Print.vue +63 -0
  15. package/dist/runtime/components/Pdf/View.vue +70 -0
  16. package/dist/runtime/components/TabsGroup.vue +28 -0
  17. package/dist/runtime/components/TextBarcode.vue +52 -0
  18. package/dist/runtime/components/dialog/Confirm.vue +100 -0
  19. package/dist/runtime/components/dialog/Index.vue +72 -0
  20. package/dist/runtime/components/dialog/Loading.vue +34 -0
  21. package/dist/runtime/components/form/Date.vue +163 -0
  22. package/dist/runtime/components/form/DateTime.vue +107 -0
  23. package/dist/runtime/components/form/File.vue +187 -0
  24. package/dist/runtime/components/form/Login.vue +131 -0
  25. package/dist/runtime/components/form/Pad.vue +179 -0
  26. package/dist/runtime/components/form/SignPad.vue +186 -0
  27. package/dist/runtime/components/form/Time.vue +158 -0
  28. package/dist/runtime/components/form/images/CameraCrop.vue +58 -0
  29. package/dist/runtime/components/form/images/Edit.vue +143 -0
  30. package/dist/runtime/components/form/images/Preview.vue +48 -0
  31. package/dist/runtime/components/label/Date.vue +29 -0
  32. package/dist/runtime/components/label/FormatMoney.vue +29 -0
  33. package/dist/runtime/composables/alert.d.ts +13 -0
  34. package/dist/runtime/composables/alert.mjs +44 -0
  35. package/dist/runtime/composables/utils/validation.d.ts +32 -0
  36. package/dist/runtime/composables/utils/validation.mjs +36 -0
  37. package/dist/runtime/labs/form/EditMobile.vue +153 -0
  38. package/dist/runtime/labs/form/TextFieldMask.vue +43 -0
  39. package/dist/runtime/plugins/vueSignaturePad.d.ts +2 -0
  40. package/dist/runtime/plugins/vueSignaturePad.mjs +5 -0
  41. package/dist/runtime/types/alert.d.ts +11 -0
  42. package/dist/runtime/types/modules.d.ts +5 -0
  43. package/dist/runtime/utils/datetime.d.ts +25 -0
  44. package/dist/runtime/utils/datetime.mjs +166 -0
  45. package/dist/runtime/utils/object.d.ts +8 -0
  46. package/dist/runtime/utils/object.mjs +28 -0
  47. package/dist/types.d.mts +16 -0
  48. package/dist/types.d.ts +16 -0
  49. package/package.json +90 -0
@@ -0,0 +1,63 @@
1
+ <script setup lang="ts">
2
+ import printJS from 'print-js'
3
+ import { ref, watch } from 'vue'
4
+ import { useAlert } from '../../composables/alert'
5
+
6
+ interface Props {
7
+ base64String?: string
8
+ fileName?: string
9
+ print?: boolean
10
+ title?: string
11
+ disabled?: boolean
12
+ }
13
+
14
+ const props = withDefaults(defineProps<Props>(), {
15
+ print: false,
16
+ disabled: false,
17
+ })
18
+ const emit = defineEmits(['update:print'])
19
+
20
+ const isMobile = ref(false)
21
+ const alert = useAlert()
22
+
23
+ const openPdf = () => {
24
+ if (/Android|Mobi|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Macintosh/i.test(navigator.userAgent)) {
25
+ isMobile.value = true
26
+ }
27
+ else {
28
+ printJS({
29
+ printable: props.base64String,
30
+ type: 'pdf',
31
+ base64: true,
32
+ onPrintDialogClose: endLoadPdf,
33
+ onError: (error: any) => {
34
+ alert?.addAlert({ message: error, alertType: 'error' })
35
+ },
36
+ })
37
+ }
38
+ }
39
+
40
+ const endLoadPdf = () => {
41
+ emit('update:print', false)
42
+ isMobile.value = false
43
+ }
44
+
45
+ watch(() => props.print, () => {
46
+ if (props.print) openPdf()
47
+ })
48
+ </script>
49
+
50
+ <template>
51
+ <v-dialog
52
+ v-model="isMobile"
53
+ fullscreen
54
+ >
55
+ <PdfView
56
+ :base64-string="props.base64String"
57
+ :disabled="props.disabled"
58
+ :title="props.title"
59
+ :file-name="props.fileName"
60
+ @close-dialog="endLoadPdf"
61
+ />
62
+ </v-dialog>
63
+ </template>
@@ -0,0 +1,70 @@
1
+ <script setup lang="ts">
2
+ import PDF from 'pdf-vue3'
3
+ import { uid } from 'uid'
4
+
5
+ const props = defineProps<{
6
+ base64String?: string
7
+ title?: string
8
+ fileName?: string
9
+ disabled?: boolean
10
+ }>()
11
+
12
+ const emit = defineEmits(['closeDialog'])
13
+
14
+ const generateUniqueId = (): string => {
15
+ const uniqueId: string = uid()
16
+ return props.fileName ? `${props.fileName}` : uniqueId
17
+ }
18
+
19
+ const downloadPdf = (): void => {
20
+ const byteString = atob(props.base64String || '')
21
+ const byteArray = new Uint8Array(byteString.length)
22
+
23
+ for (let i = 0; i < byteString.length; i++) {
24
+ byteArray[i] = byteString.charCodeAt(i)
25
+ }
26
+
27
+ const blob = new Blob([byteArray], { type: 'application/pdf' })
28
+ const link = URL.createObjectURL(blob)
29
+ const anchorElement = document.createElement('a')
30
+ anchorElement.style.display = 'none'
31
+ anchorElement.href = link
32
+ anchorElement.download = `${generateUniqueId()}.pdf`
33
+
34
+ document.body.appendChild(anchorElement)
35
+ anchorElement.click()
36
+ URL.revokeObjectURL(link)
37
+ document.body.removeChild(anchorElement)
38
+ }
39
+ </script>
40
+
41
+ <template>
42
+ <v-card>
43
+ <v-toolbar density="compact">
44
+ <v-toolbar-title>{{ props.title }}</v-toolbar-title>
45
+ <v-spacer />
46
+ <v-btn
47
+ v-if="!props.disabled"
48
+ icon="mdi mdi-download"
49
+ variant="plain"
50
+ @click="downloadPdf"
51
+ />
52
+ <v-btn
53
+ icon="mdi mdi-close"
54
+ variant="plain"
55
+ @click="emit('closeDialog', false)"
56
+ />
57
+ </v-toolbar>
58
+ <v-card-text>
59
+ <v-row justify="center">
60
+ <PDF
61
+ :show-progress="true"
62
+ pdf-width="100%"
63
+ :src="props.base64String"
64
+ :show-page-tooltip="false"
65
+ :show-back-to-top-btn="false"
66
+ />
67
+ </v-row>
68
+ </v-card-text>
69
+ </v-card>
70
+ </template>
@@ -0,0 +1,28 @@
1
+ <script lang="ts" setup>
2
+ import { ref } from 'vue'
3
+ import { VTabs } from 'vuetify/components'
4
+
5
+ interface Props extends /* @vue-ignore */ InstanceType<typeof VTabs['$props']> {
6
+ flat?: boolean
7
+ }
8
+
9
+ const props = defineProps<Props>()
10
+ const currentTab = ref<number | null>(null)
11
+ </script>
12
+
13
+ <template>
14
+ <v-card :flat="props.flat">
15
+ <v-tabs
16
+ v-model="currentTab"
17
+ v-bind="$attrs"
18
+ show-arrows
19
+ >
20
+ <slot name="tabs" />
21
+ </v-tabs>
22
+ <v-card>
23
+ <v-window v-model="currentTab">
24
+ <slot name="items" />
25
+ </v-window>
26
+ </v-card>
27
+ </v-card>
28
+ </template>
@@ -0,0 +1,52 @@
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
+ }>()
13
+ const alert = useAlert()
14
+
15
+ const scanCode = ref<boolean>(false)
16
+ const currentValue = ref<string>()
17
+
18
+ const handleData = (data: string) => {
19
+ currentValue.value = data
20
+ scanCode.value = false
21
+ }
22
+
23
+ const handleError = (error: string | unknown) => {
24
+ alert?.addAlert({ message: error as string, alertType: 'error' })
25
+ }
26
+
27
+ watch(() => props.modelValue, () => {
28
+ currentValue.value = props.modelValue
29
+ }, { immediate: true })
30
+
31
+ watch(currentValue, (newValue) => {
32
+ emit('update:modelValue', newValue)
33
+ })
34
+ </script>
35
+
36
+ <template>
37
+ <v-text-field
38
+ v-model="currentValue"
39
+ v-bind="$attrs"
40
+ append-inner-icon="mdi mdi-qrcode-scan"
41
+ @click:append-inner="scanCode = true"
42
+ />
43
+ <v-dialog
44
+ v-model="scanCode"
45
+ width="auto"
46
+ >
47
+ <BarcodeReader
48
+ @decode="handleData"
49
+ @error="handleError"
50
+ />
51
+ </v-dialog>
52
+ </template>
@@ -0,0 +1,100 @@
1
+ <script lang="ts" setup>
2
+ import { type Ref, ref, watch, computed } from 'vue'
3
+ import { isEqual, isUndefined, isEmpty } from 'lodash-es'
4
+
5
+ interface DialogProps {
6
+ title?: string
7
+ modelValue: boolean
8
+ message?: string
9
+ buttonTrueText?: string
10
+ buttonFalseText?: string
11
+ type?: 'primary' | 'success' | 'warning' | 'info' | 'error'
12
+ confirmData?: string
13
+ width?: string
14
+ }
15
+
16
+ const props = withDefaults(defineProps<DialogProps>(), {
17
+ title: 'ยืนยัน',
18
+ message: 'ยืนยันทำรายการนี้',
19
+ buttonTrueText: 'ตกลง',
20
+ buttonFalseText: 'ยกเลิก',
21
+ width: 'auto',
22
+ })
23
+
24
+ const emit = defineEmits<{
25
+ (e: 'update:result', value: boolean): void
26
+ (e: 'update:modelValue', value: boolean): void
27
+ }>()
28
+
29
+ const dialogVisible: Ref<boolean> = ref(false)
30
+ dialogVisible.value = props.modelValue
31
+ watch(
32
+ () => props.modelValue,
33
+ () => {
34
+ dialogVisible.value = props.modelValue
35
+ },
36
+ )
37
+
38
+ const txtConfirm = ref<string>()
39
+
40
+ const isDisabled = computed(() => {
41
+ if (isUndefined(props.confirmData)) return false
42
+ if (isEmpty(props.confirmData)) return true
43
+ return props.confirmData ? !isEqual(txtConfirm.value, props.confirmData) : false
44
+ })
45
+
46
+ const handleResult = (result: boolean) => {
47
+ dialogVisible.value = false
48
+ emit('update:modelValue', dialogVisible.value)
49
+ emit('update:result', result)
50
+ txtConfirm.value = ''
51
+ }
52
+ </script>
53
+
54
+ <template>
55
+ <v-row justify="center">
56
+ <v-dialog
57
+ v-model="dialogVisible"
58
+ persistent
59
+ :width="props.width"
60
+ >
61
+ <v-card>
62
+ <v-toolbar
63
+ :color="props.type"
64
+ :title="props.title"
65
+ />
66
+ <v-card-text>{{ props.message }}</v-card-text>
67
+ <v-card-text v-if="props.confirmData">
68
+ <v-text-field
69
+ v-model="txtConfirm"
70
+ variant="underlined"
71
+ >
72
+ <template #label>
73
+ <slot
74
+ name="labelTextConfirm"
75
+ :text="props.confirmData"
76
+ />
77
+ </template>
78
+ </v-text-field>
79
+ </v-card-text>
80
+ <v-card-actions>
81
+ <v-spacer />
82
+ <v-btn
83
+ variant="text"
84
+ @click="handleResult(false)"
85
+ >
86
+ {{ props.buttonFalseText }}
87
+ </v-btn>
88
+ <v-btn
89
+ :color="props.type"
90
+ variant="text"
91
+ :disabled="isDisabled"
92
+ @click="handleResult(true)"
93
+ >
94
+ {{ props.buttonTrueText }}
95
+ </v-btn>
96
+ </v-card-actions>
97
+ </v-card>
98
+ </v-dialog>
99
+ </v-row>
100
+ </template>
@@ -0,0 +1,72 @@
1
+ <script lang="ts" setup>
2
+ import { computed } from 'vue'
3
+
4
+ interface DialogProps {
5
+ modelValue?: boolean
6
+ title?: string
7
+ message?: string
8
+ type?: 'success' | 'error' | 'warning' | 'info'
9
+ width?: number | string
10
+ }
11
+
12
+ const props = defineProps<DialogProps>()
13
+ const emit = defineEmits(['update:modelValue'])
14
+
15
+ const dialogIcon = computed(() => {
16
+ switch (props.type) {
17
+ case 'success':
18
+ return 'mdi mdi-check-circle'
19
+ case 'error':
20
+ return 'mdi mdi-alert-circle'
21
+ case 'warning':
22
+ return 'mdi mdi-alert'
23
+ case 'info':
24
+ return 'mdi mdi-information-variant-circle'
25
+ default:
26
+ return ''
27
+ }
28
+ })
29
+ </script>
30
+
31
+ <template>
32
+ <VDialog
33
+ :model-value="modelValue"
34
+ :width="width"
35
+ max-width="800"
36
+ @update:model-value="emit('update:modelValue', false)"
37
+ >
38
+ <VCard>
39
+ <VToolbar :color="type">
40
+ <VToolbarTitle>
41
+ <VIcon :icon="dialogIcon" />
42
+ {{ title }}
43
+ </VToolbarTitle>
44
+ <VBtn
45
+ icon="mdi mdi-close"
46
+ size="x-small"
47
+ @click="emit('update:modelValue', false)"
48
+ />
49
+ </VToolbar>
50
+ <VCardText>
51
+ <slot>
52
+ {{ message }}
53
+ </slot>
54
+ </VCardText>
55
+ <VDivider />
56
+ <VCardActions>
57
+ <VBtn
58
+ :color="type"
59
+ block
60
+ class="ma-auto"
61
+ @click="emit('update:modelValue', false)"
62
+ >
63
+ ตกลง
64
+ </VBtn>
65
+ </VCardActions>
66
+ </VCard>
67
+ </VDialog>
68
+ </template>
69
+
70
+ <style lang="">
71
+
72
+ </style>
@@ -0,0 +1,34 @@
1
+ <script setup lang="ts">
2
+ import { ref, watch } from 'vue'
3
+
4
+ interface DialogProps {
5
+ modelValue: boolean
6
+ color?: string
7
+ }
8
+
9
+ const props = defineProps<DialogProps>()
10
+ const dialogVisible = ref<boolean>(false)
11
+
12
+ watch(() => props.modelValue, (newValue) => {
13
+ dialogVisible.value = newValue
14
+ })
15
+ </script>
16
+
17
+ <template>
18
+ <v-dialog
19
+ v-model="dialogVisible"
20
+ persistent
21
+ max-width="500"
22
+ >
23
+ <v-card :color="props.color">
24
+ <v-card-text>
25
+ <v-row>
26
+ <v-col class="text-center">
27
+ กรุณารอสักครู่
28
+ </v-col>
29
+ </v-row>
30
+ </v-card-text>
31
+ <v-progress-linear indeterminate />
32
+ </v-card>
33
+ </v-dialog>
34
+ </template>
@@ -0,0 +1,163 @@
1
+ <script lang="ts" setup>
2
+ import Datepicker from '@vuepic/vue-datepicker'
3
+ import '@vuepic/vue-datepicker/dist/main.css'
4
+ import { ref, watch, watchEffect, nextTick } from 'vue'
5
+ import { type dateFormat, Datetime } from '../../utils/datetime'
6
+
7
+ interface Props {
8
+ readonly?: boolean
9
+ locale?: 'TH' | 'EN'
10
+ format?: dateFormat | string
11
+ modelValue?: string | null
12
+ holiday?: object[] | undefined
13
+ minDate?: Date | string
14
+ maxDate?: Date | string
15
+ pickerOnly?: boolean
16
+ flow?: ('month' | 'year' | 'calendar' | 'time' | 'minutes' | 'hours' | 'seconds')[]
17
+ }
18
+
19
+ const props = withDefaults(defineProps<Props>(), {
20
+ readonly: false,
21
+ locale: 'TH',
22
+ format: 'shortDate',
23
+ pickerOnly: false,
24
+ flow: () => [],
25
+ })
26
+
27
+ const emit = defineEmits(['update:modelValue'])
28
+
29
+ const selectedDate = ref<string | null>(null)
30
+ const displayedDate = ref<string | null>(null)
31
+
32
+ const isMenuOpen = ref(false)
33
+ const isTextFieldFocused = ref(false)
34
+ const hasTextFieldInput = ref(false)
35
+
36
+ function handleTextFieldFocus(event: Event) {
37
+ isTextFieldFocused.value = true
38
+ nextTick(() => {
39
+ (event.target as HTMLInputElement).select()
40
+ })
41
+ }
42
+
43
+ function handleTextFieldInput() {
44
+ if (!hasTextFieldInput.value) {
45
+ hasTextFieldInput.value = true
46
+ isMenuOpen.value = false
47
+ }
48
+ }
49
+
50
+ function handleTextFieldBlur() {
51
+ if (hasTextFieldInput.value) {
52
+ updateDate(displayedDate.value)
53
+ hasTextFieldInput.value = false
54
+ }
55
+ isTextFieldFocused.value = false
56
+ }
57
+
58
+ function handleTextFieldEnterKey() {
59
+ handleTextFieldBlur()
60
+ }
61
+
62
+ function updateDatePicker(dateString: string | null) {
63
+ isMenuOpen.value = false
64
+ updateDate(dateString)
65
+ }
66
+
67
+ function updateDate(dateString: string | null) {
68
+ const dateTime = Datetime().fromString(dateString, undefined, props.locale)
69
+ if (!dateTime.luxonDateTime.isValid) {
70
+ displayedDate.value = null
71
+ selectedDate.value = null
72
+ }
73
+ else {
74
+ selectedDate.value = dateTime.toFormat('yyyy-MM-dd', 'EN')
75
+ displayedDate.value = selectedDate.value
76
+ }
77
+
78
+ if (!isTextFieldFocused.value) displayedDate.value = formatDate(displayedDate.value)
79
+ }
80
+
81
+ function formatDate(dateString: string | null) {
82
+ if (!dateString) return null
83
+
84
+ const dateTime = Datetime().fromString(dateString, undefined, props.locale)
85
+ return dateTime.toFormat(props.format, props.locale)
86
+ }
87
+
88
+ function handleTextFieldClear() {
89
+ resetDatePicker()
90
+ }
91
+
92
+ function resetDatePicker() {
93
+ selectedDate.value = null
94
+ displayedDate.value = null
95
+ }
96
+
97
+ watchEffect(() => {
98
+ if (!isTextFieldFocused.value && selectedDate.value) {
99
+ const dateTime = Datetime().fromString(selectedDate.value, undefined, props.locale)
100
+ displayedDate.value = dateTime.toFormat(props.format, props.locale)
101
+ }
102
+ else {
103
+ displayedDate.value = selectedDate.value
104
+ }
105
+ })
106
+
107
+ watch(selectedDate, (newValue) => {
108
+ emit('update:modelValue', newValue)
109
+ })
110
+
111
+ watch(() => props.modelValue, () => {
112
+ updateDate(props.modelValue || null)
113
+ }, { immediate: true })
114
+
115
+ function toggleMenuOpen(trigger: string) {
116
+ if ((trigger === 'textField' && props.pickerOnly) || (trigger === 'icon' && !props.pickerOnly)) {
117
+ isMenuOpen.value = true
118
+ }
119
+ }
120
+ </script>
121
+
122
+ <template>
123
+ <v-menu
124
+ v-model="isMenuOpen"
125
+ :open-on-click="false"
126
+ >
127
+ <template #activator="{ props: activatorProps }">
128
+ <v-text-field
129
+ ref="textField"
130
+ v-model="displayedDate"
131
+ :readonly="readonly"
132
+ v-bind="$attrs"
133
+ @focus="handleTextFieldFocus"
134
+ @blur="handleTextFieldBlur"
135
+ @keydown="handleTextFieldInput"
136
+ @keyup.enter="handleTextFieldEnterKey"
137
+ @click:clear="handleTextFieldClear"
138
+ @click="toggleMenuOpen('textField')"
139
+ >
140
+ <template #append-inner>
141
+ <v-icon
142
+ v-bind="activatorProps"
143
+ @click="toggleMenuOpen('icon')"
144
+ >
145
+ fa:fa-regular fa-calendar
146
+ </v-icon>
147
+ </template>
148
+ </v-text-field>
149
+ </template>
150
+ <Datepicker
151
+ v-model="selectedDate"
152
+ model-type="yyyy-MM-dd"
153
+ :enable-time-picker="false"
154
+ :flow="flow"
155
+ :min-date="props.minDate"
156
+ :max-date="props.maxDate"
157
+ auto-apply
158
+ inline
159
+ :locale="locale"
160
+ @update:model-value="updateDatePicker"
161
+ />
162
+ </v-menu>
163
+ </template>
@@ -0,0 +1,107 @@
1
+ <script lang="ts" setup>
2
+ import { ref, computed, watch, watchEffect } from 'vue'
3
+ import { union } from 'lodash-es'
4
+ import { type dateFormat, Datetime } from '../../utils/datetime'
5
+
6
+ interface Props {
7
+ modelValue?: string | null
8
+ format?: dateFormat | string
9
+ label?: string
10
+ enableSeconds?: boolean
11
+ rules?: typeof import('vuetify/components')['VTextField']['rules']
12
+ dateRules?: typeof import('vuetify/components')['VTextField']['rules']
13
+ timeRules?: typeof import('vuetify/components')['VTextField']['rules']
14
+ dense?: boolean
15
+ pickerOnly?: boolean
16
+ minDate?: Date | string
17
+ maxDate?: Date | string
18
+ readonly?: boolean
19
+ locale?: 'TH' | 'EN'
20
+ }
21
+
22
+ const props = withDefaults(defineProps<Props>(), {
23
+ dense: false,
24
+ locale: 'TH',
25
+ enableSeconds: false,
26
+ format: 'shortDate',
27
+ pickerOnly: false,
28
+ readonly: false,
29
+ })
30
+
31
+ const emit = defineEmits(['update:modelValue'])
32
+
33
+ const computedDateRules = computed(() => union(props.rules, props.dateRules))
34
+ const computedTimeRules = computed(() => union(props.rules, props.timeRules))
35
+
36
+ const datePart = ref<string | null>(null)
37
+ const timePart = ref<string | null>(null)
38
+ const pauseEmit = ref(false)
39
+
40
+ function reset() {
41
+ datePart.value = null
42
+ timePart.value = null
43
+ }
44
+
45
+ watchEffect(() => {
46
+ if (!pauseEmit.value) {
47
+ if (datePart.value && timePart.value) {
48
+ emit('update:modelValue', Datetime().fromString(`${datePart.value}T${timePart.value}`).toISO())
49
+ }
50
+ else if (!datePart.value) {
51
+ emit('update:modelValue', null)
52
+ }
53
+ }
54
+ })
55
+
56
+ watch(() => props.modelValue, () => {
57
+ pauseEmit.value = true
58
+ if (!props.modelValue) {
59
+ reset()
60
+ }
61
+ else {
62
+ const dateTime = Datetime().fromString(props.modelValue)
63
+ if (dateTime.luxonDateTime.isValid) {
64
+ datePart.value = dateTime.toFormat('yyyy-MM-dd')
65
+ timePart.value = dateTime.toFormat('HH:mm:ss')
66
+ }
67
+ else {
68
+ reset()
69
+ }
70
+ }
71
+ pauseEmit.value = false
72
+ }, { immediate: true })
73
+ </script>
74
+
75
+ <template>
76
+ <v-container
77
+ :fluid="true"
78
+ class="pa-0"
79
+ >
80
+ <v-row :dense="dense">
81
+ <v-col cols="8">
82
+ <FormDate
83
+ v-model="datePart"
84
+ :rules="computedDateRules"
85
+ :label="label"
86
+ :format="format"
87
+ :picker-only="pickerOnly"
88
+ :readonly="readonly"
89
+ :min-date="minDate"
90
+ :max-date="maxDate"
91
+ v-bind="$attrs"
92
+ />
93
+ </v-col>
94
+ <v-col cols="4">
95
+ <FormTime
96
+ v-model="timePart"
97
+ :rules="computedTimeRules"
98
+ :label="label"
99
+ :enable-seconds="enableSeconds"
100
+ :picker-only="pickerOnly"
101
+ :readonly="readonly"
102
+ v-bind="$attrs"
103
+ />
104
+ </v-col>
105
+ </v-row>
106
+ </v-container>
107
+ </template>