@ramathibodi/nuxt-commons 0.1.60 → 0.1.62
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.
- package/dist/module.json +1 -1
- package/dist/runtime/components/form/ActionPad.vue +1 -0
- package/dist/runtime/components/form/Dialog.vue +1 -0
- package/dist/runtime/components/form/EditPad.vue +1 -0
- package/dist/runtime/components/form/Pad.vue +77 -16
- package/dist/runtime/components/model/Pad.vue +24 -5
- package/dist/runtime/components/model/Table.vue +22 -4
- package/dist/runtime/composables/document/template.js +1 -1
- package/dist/runtime/composables/utils/validation.d.ts +20 -0
- package/dist/runtime/composables/utils/validation.js +11 -1
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -12,11 +12,10 @@ import {
|
|
|
12
12
|
watch,
|
|
13
13
|
withDefaults
|
|
14
14
|
} from 'vue'
|
|
15
|
-
import {isObject} from 'lodash-es'
|
|
16
15
|
import {watchDebounced} from '@vueuse/core'
|
|
17
16
|
import {useRules} from '../../composables/utils/validation'
|
|
18
17
|
import {useDocumentTemplate} from '../../composables/document/template'
|
|
19
|
-
import { isArray, isString, isPlainObject } from 'lodash-es'
|
|
18
|
+
import { isObject, isArray, isString, isPlainObject, isEqual } from 'lodash-es'
|
|
20
19
|
import FormPad from './Pad.vue'
|
|
21
20
|
|
|
22
21
|
defineOptions({
|
|
@@ -25,6 +24,7 @@ defineOptions({
|
|
|
25
24
|
|
|
26
25
|
interface Props {
|
|
27
26
|
modelValue?: object
|
|
27
|
+
originalData?: object
|
|
28
28
|
template?: any
|
|
29
29
|
templateScript?: string
|
|
30
30
|
disabled?: boolean
|
|
@@ -32,6 +32,8 @@ interface Props {
|
|
|
32
32
|
isolated?: boolean
|
|
33
33
|
decoration?: object
|
|
34
34
|
parentTemplates?: string|string[]
|
|
35
|
+
dirtyClass?: string
|
|
36
|
+
dirtyOnCreate?: boolean
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -40,6 +42,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
40
42
|
isolated: false,
|
|
41
43
|
decoration: () => { return {} },
|
|
42
44
|
parentTemplates: (): string[] => [],
|
|
45
|
+
dirtyClass: "form-data-dirty",
|
|
46
|
+
dirtyOnCreate: false
|
|
43
47
|
})
|
|
44
48
|
|
|
45
49
|
const emit = defineEmits(['update:modelValue'])
|
|
@@ -80,39 +84,43 @@ const formInjected = ref()
|
|
|
80
84
|
const formData = ref<any>({})
|
|
81
85
|
|
|
82
86
|
function isBlankString(v: unknown): v is string {
|
|
83
|
-
return isString(v) && v.length === 0
|
|
87
|
+
return isString(v) && v.trim().length === 0
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
function sanitizeBlankStrings(val: any):
|
|
87
|
-
|
|
90
|
+
function sanitizeBlankStrings(val: any, original?: any): void {
|
|
91
|
+
if (!original && props.originalData) {
|
|
92
|
+
sanitizeBlankStrings(val, props.originalData)
|
|
93
|
+
return
|
|
94
|
+
}
|
|
88
95
|
|
|
89
96
|
if (isArray(val)) {
|
|
90
97
|
for (let i = val.length - 1; i >= 0; i--) {
|
|
91
98
|
const item = val[i]
|
|
92
99
|
if (isBlankString(item)) {
|
|
93
|
-
val.splice(i, 1)
|
|
94
|
-
changed = true
|
|
100
|
+
val.splice(i, 1)
|
|
95
101
|
} else if (isPlainObject(item) || isArray(item)) {
|
|
96
|
-
|
|
102
|
+
sanitizeBlankStrings(item,{})
|
|
103
|
+
} else {
|
|
104
|
+
if (item && typeof item.trimEnd == "function") val[i] = item.trimEnd()
|
|
97
105
|
}
|
|
98
106
|
}
|
|
99
|
-
return
|
|
107
|
+
return
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
if (isPlainObject(val)) {
|
|
103
111
|
for (const key of Object.keys(val)) {
|
|
104
112
|
const v = val[key]
|
|
105
113
|
if (isBlankString(v)) {
|
|
106
|
-
delete val[key]
|
|
107
|
-
|
|
114
|
+
if (original && !Object.keys(original).includes(key)) delete val[key]
|
|
115
|
+
else val[key] = null
|
|
108
116
|
} else if (isPlainObject(v) || isArray(v)) {
|
|
109
|
-
|
|
117
|
+
let originalChild = (original && (isPlainObject(original[key]) || isArray(original[key]))) ? original[key] : {}
|
|
118
|
+
sanitizeBlankStrings(v, originalChild)
|
|
119
|
+
} else {
|
|
120
|
+
if (v && typeof v.trimEnd == "function") val[key] = v.trimEnd()
|
|
110
121
|
}
|
|
111
122
|
}
|
|
112
|
-
return changed
|
|
113
123
|
}
|
|
114
|
-
|
|
115
|
-
return false
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
watch(formData, (newValue) => {
|
|
@@ -124,6 +132,52 @@ watch(() => props.modelValue, (newValue) => {
|
|
|
124
132
|
formData.value = isObject(newValue) ? newValue : {}
|
|
125
133
|
}, { deep: true, immediate: true })
|
|
126
134
|
|
|
135
|
+
function diffPaths(
|
|
136
|
+
a: any,
|
|
137
|
+
b: any,
|
|
138
|
+
base: string[] = [],
|
|
139
|
+
out: string[] = []
|
|
140
|
+
): string[] {
|
|
141
|
+
const keys = new Set<string>([
|
|
142
|
+
...Object.keys(a ?? {}),
|
|
143
|
+
...Object.keys(b ?? {}),
|
|
144
|
+
])
|
|
145
|
+
|
|
146
|
+
for (const k of keys) {
|
|
147
|
+
const av = a?.[k]
|
|
148
|
+
const bv = b?.[k]
|
|
149
|
+
if (!av && !bv) continue // ignore when both are falsy
|
|
150
|
+
|
|
151
|
+
const path = [...base, k]
|
|
152
|
+
|
|
153
|
+
if (isPlainObject(av) && isPlainObject(bv)) {
|
|
154
|
+
diffPaths(av, bv, path, out)
|
|
155
|
+
continue
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!isEqual(av, bv)) {
|
|
159
|
+
out.push(path.join('.'))
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return out
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const injectedClass = computed<Record<string, string>>(() => {
|
|
167
|
+
const data = (formData.value ?? {}) as Record<string, any>
|
|
168
|
+
const result: Record<string, string> = {}
|
|
169
|
+
|
|
170
|
+
if (!props.dirtyOnCreate && !props.originalData) return result
|
|
171
|
+
|
|
172
|
+
const original = (props.originalData ?? {}) as Record<string, any>
|
|
173
|
+
const cls = props.dirtyClass || 'form-data-dirty'
|
|
174
|
+
|
|
175
|
+
const paths = diffPaths(data, original)
|
|
176
|
+
for (const p of paths) result[p] = cls
|
|
177
|
+
|
|
178
|
+
return result
|
|
179
|
+
})
|
|
180
|
+
|
|
127
181
|
const formComponent = shallowRef()
|
|
128
182
|
|
|
129
183
|
function buildFormComponent() {
|
|
@@ -131,12 +185,13 @@ function buildFormComponent() {
|
|
|
131
185
|
const originalConsoleError = console.warn
|
|
132
186
|
console.warn = (error: any) => { throw new Error(error) } // eslint-disable-line
|
|
133
187
|
try {
|
|
134
|
-
const componentTemplate = '<form-pad ref="formPadTemplate" v-model="formComponentData" :disabled="disabled" :readonly="readonly" :decoration="decoration" :isolated="isolated"><template v-slot="{ data,isDisabled,isReadonly,rules,formProvided,decoration }">' + trimmedTemplate.value + '</template></form-pad>'
|
|
188
|
+
const componentTemplate = '<form-pad ref="formPadTemplate" v-model="formComponentData" :originalData="originalData" :disabled="disabled" :readonly="readonly" :decoration="decoration" :isolated="isolated"><template v-slot="{ data,isDisabled,isReadonly,rules,formProvided,decoration,injectedClass }">' + trimmedTemplate.value + '</template></form-pad>'
|
|
135
189
|
compile(componentTemplate)
|
|
136
190
|
formComponent.value = defineComponent({
|
|
137
191
|
components: { FormPad },
|
|
138
192
|
props: {
|
|
139
193
|
modelValue: { type: Object, default: undefined },
|
|
194
|
+
originalData: { type: Object, default: undefined },
|
|
140
195
|
disabled: { type: Boolean, default: false },
|
|
141
196
|
readonly: { type: Boolean, default: false },
|
|
142
197
|
decoration: { type: Object, default: () => { return {} } },
|
|
@@ -231,6 +286,7 @@ defineExpose({
|
|
|
231
286
|
:is-readonly="readonly"
|
|
232
287
|
:rules="rules"
|
|
233
288
|
:decoration="decoration"
|
|
289
|
+
:injectedClass="injectedClass"
|
|
234
290
|
/>
|
|
235
291
|
</template>
|
|
236
292
|
</v-form>
|
|
@@ -242,6 +298,7 @@ defineExpose({
|
|
|
242
298
|
:is-readonly="readonly"
|
|
243
299
|
:rules="rules"
|
|
244
300
|
:decoration="decoration"
|
|
301
|
+
:injectedClass="injectedClass"
|
|
245
302
|
/>
|
|
246
303
|
</template>
|
|
247
304
|
<component
|
|
@@ -249,6 +306,7 @@ defineExpose({
|
|
|
249
306
|
v-if="trimmedTemplate"
|
|
250
307
|
ref="formPad"
|
|
251
308
|
v-model="formData"
|
|
309
|
+
:originalData="originalData"
|
|
252
310
|
:disabled="disabled"
|
|
253
311
|
:readonly="readonly"
|
|
254
312
|
:decoration="decoration"
|
|
@@ -256,3 +314,6 @@ defineExpose({
|
|
|
256
314
|
:class="$attrs.class"
|
|
257
315
|
/>
|
|
258
316
|
</template>
|
|
317
|
+
<style>
|
|
318
|
+
.form-data-dirty,.form-data-dirty *{color:color-mix(in srgb,currentColor 70%,rgb(var(--v-theme-primary)))!important;text-shadow:0 0 .02em currentColor}
|
|
319
|
+
</style>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { computed, useTemplateRef, defineExpose } from 'vue'
|
|
3
3
|
import { type GraphqlModelItemProps, useGraphqlModelItem } from '../../composables/graphqlModelItem'
|
|
4
|
+
import type {FormDialogCallback} from '../../types/formDialog'
|
|
4
5
|
import EditPad from '../form/EditPad.vue'
|
|
6
|
+
import {useDialog} from "../../composables/dialog";
|
|
5
7
|
|
|
6
8
|
defineOptions({
|
|
7
9
|
inheritAttrs: false,
|
|
@@ -12,8 +14,13 @@ interface Props extends /* @vue-ignore */ InstanceType<typeof EditPad['$props']>
|
|
|
12
14
|
|
|
13
15
|
const props = withDefaults(defineProps<Props & GraphqlModelItemProps>(), {
|
|
14
16
|
fields: () => ['*'],
|
|
17
|
+
|
|
18
|
+
saveCaption: 'บันทึก',
|
|
19
|
+
cancelCaption: 'ยกเลิก',
|
|
15
20
|
})
|
|
16
21
|
|
|
22
|
+
const emit = defineEmits(['create', 'update'])
|
|
23
|
+
|
|
17
24
|
const { item,
|
|
18
25
|
canCreate, canUpdate,
|
|
19
26
|
createItem, updateItem,
|
|
@@ -27,11 +34,25 @@ const operation : any = computed(()=>{
|
|
|
27
34
|
return Object.assign({},editPad.value?.operation,{canSave,reload,item})
|
|
28
35
|
})
|
|
29
36
|
|
|
37
|
+
const onCreateItem = (item: Record<string, any>,callback?: FormDialogCallback)=>{
|
|
38
|
+
createItem(item,callback).then(()=>{
|
|
39
|
+
useDialog().notify({message: "Data created successfully",type: 'success',title:"Success"})
|
|
40
|
+
emit("create",item,callback)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const onUpdateItem = (item: Record<string, any>,callback?: FormDialogCallback)=>{
|
|
45
|
+
updateItem(item,callback).then(()=>{
|
|
46
|
+
useDialog().notify({message: "Data updated successfully",type: 'success',title:"Success"})
|
|
47
|
+
emit("update",item,callback)
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
30
51
|
defineExpose({ operation, formPad: editPad.value?.formPad })
|
|
31
52
|
</script>
|
|
32
53
|
|
|
33
54
|
<template>
|
|
34
|
-
<FormEditPad v-bind="$attrs" :form-data="item" ref="editPadRef" @create="
|
|
55
|
+
<FormEditPad v-bind="$attrs" :form-data="item" ref="editPadRef" @create="onCreateItem" @update="onUpdateItem">
|
|
35
56
|
<template #titleToolbar>
|
|
36
57
|
<slot name="titleToolbar" :operation="operation">
|
|
37
58
|
<VToolbarTitle>
|
|
@@ -57,7 +78,7 @@ defineExpose({ operation, formPad: editPad.value?.formPad })
|
|
|
57
78
|
:disabled="!slotData.operation?.isDataChange || !canSave"
|
|
58
79
|
@click="slotData.operation?.save"
|
|
59
80
|
>
|
|
60
|
-
{{ saveCaption }}
|
|
81
|
+
{{ props.saveCaption }}
|
|
61
82
|
</VBtn>
|
|
62
83
|
<VBtn
|
|
63
84
|
color="error"
|
|
@@ -65,15 +86,13 @@ defineExpose({ operation, formPad: editPad.value?.formPad })
|
|
|
65
86
|
:disabled="isLoading"
|
|
66
87
|
@click="slotData.operation?.cancel"
|
|
67
88
|
>
|
|
68
|
-
{{ cancelCaption }}
|
|
89
|
+
{{ props.cancelCaption }}
|
|
69
90
|
</VBtn>
|
|
70
91
|
</slot>
|
|
71
92
|
</template>
|
|
72
93
|
<template #default="slotData">
|
|
73
94
|
<slot
|
|
74
95
|
v-bind="slotData"
|
|
75
|
-
:is-creating="isCreating"
|
|
76
|
-
:is-data-change="isDataChange"
|
|
77
96
|
/>
|
|
78
97
|
</template>
|
|
79
98
|
</FormEditPad>
|
|
@@ -50,7 +50,7 @@ const props = withDefaults(defineProps<Props & GraphqlModelProps>(), {
|
|
|
50
50
|
onlyOwnerEdit: false,
|
|
51
51
|
})
|
|
52
52
|
|
|
53
|
-
const emit = defineEmits(['open:dialog','close:dialog'])
|
|
53
|
+
const emit = defineEmits(['open:dialog','close:dialog','create','update','delete'])
|
|
54
54
|
const attrs = useAttrs()
|
|
55
55
|
const plainAttrs = computed(() => {
|
|
56
56
|
const returnAttrs = clone(attrs)
|
|
@@ -95,7 +95,25 @@ function openDialogReadonly(item?: object) {
|
|
|
95
95
|
|
|
96
96
|
async function confirmDeleteItem(item: Record<string, any>, callback?: FormDialogCallback) {
|
|
97
97
|
let confirm = await useDialog().confirm({message: "Do you want to delete record?"})
|
|
98
|
-
if (confirm)
|
|
98
|
+
if (confirm) onDeleteItem(item,callback)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const onCreateItem = (item: Record<string, any>,callback?: FormDialogCallback)=>{
|
|
102
|
+
createItem(item,callback).then(()=>{
|
|
103
|
+
emit("create",item,callback)
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const onUpdateItem = (item: Record<string, any>,callback?: FormDialogCallback)=>{
|
|
108
|
+
updateItem(item,callback).then(()=>{
|
|
109
|
+
emit("update",item,callback)
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const onDeleteItem = (item: Record<string, any>,callback?: FormDialogCallback)=>{
|
|
114
|
+
deleteItem(item,callback).then(()=>{
|
|
115
|
+
emit("delete",item,callback)
|
|
116
|
+
})
|
|
99
117
|
}
|
|
100
118
|
|
|
101
119
|
const canEditRow = function (item: Record<string, any>) {
|
|
@@ -301,8 +319,8 @@ defineExpose({ reload,operation })
|
|
|
301
319
|
:fullscreen="dialogFullscreen"
|
|
302
320
|
:initial-data="computedInitialData"
|
|
303
321
|
:form-data="currentItem"
|
|
304
|
-
@create="
|
|
305
|
-
@update="
|
|
322
|
+
@create="onCreateItem"
|
|
323
|
+
@update="onUpdateItem"
|
|
306
324
|
@afterLeave="emit('close:dialog')"
|
|
307
325
|
:saveAndStay="saveAndStay"
|
|
308
326
|
:readonly="isDialogReadonly"
|
|
@@ -89,7 +89,7 @@ export function templateItemToString(inputItem, parentTemplates, dataVariable =
|
|
|
89
89
|
}
|
|
90
90
|
function columnWrapTemplateItemString(item, parentTemplates, dataVariable = "data") {
|
|
91
91
|
let templateString = templateItemToString(item, parentTemplates, dataVariable);
|
|
92
|
-
if (!["Separator", "FormHidden"].includes(item.inputType)) templateString = `<v-col${item.width ? ` cols="${item.width}"` : ""}${item.columnAttributes ? " " + item.columnAttributes : ""}${item.customClass ? ` class="${item.customClass}"` : ""}${item.customStyle ? ` class="${item.customStyle}"` : ""}>${templateString}</v-col>`;
|
|
92
|
+
if (!["Separator", "FormHidden"].includes(item.inputType)) templateString = `<v-col${item.width ? ` cols="${item.width}"` : ""}${item.columnAttributes ? " " + item.columnAttributes : ""} :class="(injectedClass) ? injectedClass['${item.variableName || ""}'] : undefined"${item.customClass ? ` class="${item.customClass}"` : ""}${item.customStyle ? ` class="${item.customStyle}"` : ""}>${templateString}</v-col>`;
|
|
93
93
|
if (["Header", "DocumentForm"].includes(item.inputType)) templateString = `</v-row><v-row dense${item.customClass ? ` class="${item.customClass}"` : ""}${item.customStyle ? ` class="${item.customStyle}"` : ""}>${templateString}</v-row><v-row dense>`;
|
|
94
94
|
return templateString || "";
|
|
95
95
|
}
|
|
@@ -11,6 +11,11 @@ export declare function useRules(): {
|
|
|
11
11
|
lengthGreater: (length: number, customError?: string) => (value: any) => string | true;
|
|
12
12
|
lengthLess: (length: number, customError?: string) => (value: any) => string | true;
|
|
13
13
|
telephone: (customError?: string) => (value: any) => string | true;
|
|
14
|
+
telephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
15
|
+
internationalTelephone: (customError?: string) => (value: any) => string | true;
|
|
16
|
+
internationalTelephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
17
|
+
mobilePhone: (customError?: string) => (value: any) => string | true;
|
|
18
|
+
mobilePhoneSingle: (customError?: string) => (value: any) => string | true;
|
|
14
19
|
email: (customError?: string) => (value: any) => string | true;
|
|
15
20
|
regex: (regex: RegExp | string, customError?: string) => (value: any) => string | true;
|
|
16
21
|
idcard: (customError?: string) => (value: any) => string | true;
|
|
@@ -34,6 +39,11 @@ export declare function useRules(): {
|
|
|
34
39
|
lengthGreater: (length: number, customError?: string) => (value: any) => string | true;
|
|
35
40
|
lengthLess: (length: number, customError?: string) => (value: any) => string | true;
|
|
36
41
|
telephone: (customError?: string) => (value: any) => string | true;
|
|
42
|
+
telephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
43
|
+
internationalTelephone: (customError?: string) => (value: any) => string | true;
|
|
44
|
+
internationalTelephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
45
|
+
mobilePhone: (customError?: string) => (value: any) => string | true;
|
|
46
|
+
mobilePhoneSingle: (customError?: string) => (value: any) => string | true;
|
|
37
47
|
email: (customError?: string) => (value: any) => string | true;
|
|
38
48
|
regex: (regex: RegExp | string, customError?: string) => (value: any) => string | true;
|
|
39
49
|
idcard: (customError?: string) => (value: any) => string | true;
|
|
@@ -57,6 +67,11 @@ export declare function useRules(): {
|
|
|
57
67
|
lengthGreater: (length: number, customError?: string) => (value: any) => string | true;
|
|
58
68
|
lengthLess: (length: number, customError?: string) => (value: any) => string | true;
|
|
59
69
|
telephone: (customError?: string) => (value: any) => string | true;
|
|
70
|
+
telephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
71
|
+
internationalTelephone: (customError?: string) => (value: any) => string | true;
|
|
72
|
+
internationalTelephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
73
|
+
mobilePhone: (customError?: string) => (value: any) => string | true;
|
|
74
|
+
mobilePhoneSingle: (customError?: string) => (value: any) => string | true;
|
|
60
75
|
email: (customError?: string) => (value: any) => string | true;
|
|
61
76
|
regex: (regex: RegExp | string, customError?: string) => (value: any) => string | true;
|
|
62
77
|
idcard: (customError?: string) => (value: any) => string | true;
|
|
@@ -80,6 +95,11 @@ export declare function useRules(): {
|
|
|
80
95
|
lengthGreater: (length: number, customError?: string) => (value: any) => string | true;
|
|
81
96
|
lengthLess: (length: number, customError?: string) => (value: any) => string | true;
|
|
82
97
|
telephone: (customError?: string) => (value: any) => string | true;
|
|
98
|
+
telephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
99
|
+
internationalTelephone: (customError?: string) => (value: any) => string | true;
|
|
100
|
+
internationalTelephoneSingle: (customError?: string) => (value: any) => string | true;
|
|
101
|
+
mobilePhone: (customError?: string) => (value: any) => string | true;
|
|
102
|
+
mobilePhoneSingle: (customError?: string) => (value: any) => string | true;
|
|
83
103
|
email: (customError?: string) => (value: any) => string | true;
|
|
84
104
|
regex: (regex: RegExp | string, customError?: string) => (value: any) => string | true;
|
|
85
105
|
idcard: (customError?: string) => (value: any) => string | true;
|
|
@@ -14,7 +14,12 @@ export function useRules() {
|
|
|
14
14
|
const length = (length2, customError = `Length must be ${length2}`) => (value) => condition(!value || value.length == length2, customError);
|
|
15
15
|
const lengthGreater = (length2, customError = `Length must be greater than ${length2}`) => (value) => condition(!value || value.length >= length2, customError);
|
|
16
16
|
const lengthLess = (length2, customError = `Length must be less than ${length2}`) => (value) => condition(!value || value.length <= length2, customError);
|
|
17
|
-
const telephone = (customError = "Invalid telephone number") => (value) => condition(!value || /^(?:\s*(?:
|
|
17
|
+
const telephone = (customError = "Invalid telephone number") => (value) => condition(!value || /^(?:\s*(?:\+66|0)\s?(?:[2-57](?:[\s-]?\d){7}|[689](?:[\s-]?\d){8})(?:#\d{1,5})?\s*(?:\([^()]+\)\s*)?(?:,(?=\s*\+?6?0)|,|$))*$/.test(value), customError);
|
|
18
|
+
const telephoneSingle = (customError = "Invalid telephone number") => (value) => condition(!value || /^\s*(?:\+66|0)\s?(?:[2-57](?:[\s-]?\d){7}|[689](?:[\s-]?\d){8})(?:#\d{1,5})?\s*(?:\([^()]+\)\s*)?$/.test(value), customError);
|
|
19
|
+
const internationalTelephone = (customError = "Invalid telephone number") => (value) => condition(!value || /^(?:\s*(?:\+?\d{1,3}[-\s]?)?(?:0?\d{1,4}[-\s]?)?\d{3,4}[-\s]?\d{3,4}(?:#\d{1,5})?\s*(?:\([^()]+\)\s*)?(?:,(?=\s*\+?\d)|,|$))*$/.test(value), customError);
|
|
20
|
+
const internationalTelephoneSingle = (customError = "Invalid telephone number") => (value) => condition(!value || /^\s*(?:\+?\d{1,3}[-\s]?)?(?:0?\d{1,4}[-\s]?)?\d{3,4}[-\s]?\d{3,4}(?:#\d{1,5})?\s*(?:\([^()]+\)\s*)?$/.test(value), customError);
|
|
21
|
+
const mobilePhone = (customError = "Invalid telephone number") => (value) => condition(!value || /^(?:\s*(?:\+66|0)\s?(?:6\d{8}|8\d{8}|9\d{8})\s*(?:,(?=\s*\+?6?0)|,|$))*$/.test(value), customError);
|
|
22
|
+
const mobilePhoneSingle = (customError = "Invalid telephone number") => (value) => condition(!value || /^\s*(?:\+66|0)\s?(?:6\d{8}|8\d{8}|9\d{8})\s*$/.test(value), customError);
|
|
18
23
|
const email = (customError = "Invalid email address") => (value) => condition(!value || /^([\w\-.]+)@([\w\-.]+)\.([a-z]{2,5})$/i.test(value), customError);
|
|
19
24
|
const regex = (regex2, customError = "Invalid format") => (value) => condition(!value || new RegExp(regex2).test(value), customError);
|
|
20
25
|
const idcard = (customError = "Invalid ID Card format") => (value) => condition(!value || /^\d{13}$/.test(value) && (11 - [...value].slice(0, 12).reduce((sum, n, i) => sum + +n * (13 - i), 0) % 11) % 10 === +value[12], customError);
|
|
@@ -38,6 +43,11 @@ export function useRules() {
|
|
|
38
43
|
lengthGreater,
|
|
39
44
|
lengthLess,
|
|
40
45
|
telephone,
|
|
46
|
+
telephoneSingle,
|
|
47
|
+
internationalTelephone,
|
|
48
|
+
internationalTelephoneSingle,
|
|
49
|
+
mobilePhone,
|
|
50
|
+
mobilePhoneSingle,
|
|
41
51
|
email,
|
|
42
52
|
regex,
|
|
43
53
|
idcard,
|