@flyanra/vue-core 1.3.9 → 1.5.0

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 (53) hide show
  1. package/dist/types/components/form/index.d.ts +1 -3
  2. package/dist/types/components/form/input-renderers/country-input/FlyCountryCitySelect.vue.d.ts +19 -0
  3. package/dist/types/components/form/input-renderers/country-input/FlyCountrySelect.types.d.ts +4 -0
  4. package/dist/types/components/form/input-renderers/country-input/FlyCountrySelect.vue.d.ts +30 -0
  5. package/dist/types/components/form/input-renderers/country-input/FlyCountryStatesSelect.vue.d.ts +19 -0
  6. package/dist/types/components/form/input-renderers/country-input/countries.d.ts +49 -0
  7. package/dist/types/components/form/input-renderers/country-input/index.d.ts +5 -0
  8. package/dist/types/components/form/input-renderers/index.d.ts +8 -0
  9. package/dist/types/components/form/input-renderers/otp-input/FlyOTPInput.vue.d.ts +15 -0
  10. package/dist/types/components/form/input-renderers/otp-input/index.d.ts +3 -0
  11. package/dist/types/components/form/input-renderers/phone-number/FlyPhoneNumberInput.types.d.ts +1 -0
  12. package/dist/types/components/form/input-renderers/phone-number/FlyPhoneNumberInput.vue.d.ts +17 -0
  13. package/dist/types/components/form/input-renderers/phone-number/index.d.ts +3 -0
  14. package/dist/types/components/form/input-renderers/regional-tenant-form-renderer/FlyRegionalTenantFormRenderer.types.d.ts +8 -1
  15. package/dist/types/components/form/input-renderers/regional-tenant-form-renderer/FlyRegionalTenantFormRenderer.vue.d.ts +8 -4
  16. package/dist/types/components/form/input-renderers/regional-tenant-form-renderer/index.d.ts +4 -0
  17. package/dist/types/components/form/input-validators.d.ts +5 -0
  18. package/dist/types/composables/useLocaleInjector/index.d.ts +2 -2
  19. package/dist/types/composables/useLocaleInjector/useLocaleInjector.d.ts +13 -0
  20. package/dist/types/utils/country-utils.d.ts +3 -0
  21. package/dist/types/utils/index.d.ts +1 -0
  22. package/package.json +5 -1
  23. package/src/components/basic/typography/FlyCollapseTitleRenderer.vue +2 -2
  24. package/src/components/form/form.utils.ts +3 -3
  25. package/src/components/form/index.ts +1 -4
  26. package/src/components/form/input-renderers/country-input/FlyCountryCitySelect.vue +73 -0
  27. package/src/components/form/input-renderers/country-input/FlyCountrySelect.types.ts +4 -0
  28. package/src/components/form/input-renderers/country-input/FlyCountrySelect.vue +76 -0
  29. package/src/components/form/input-renderers/country-input/FlyCountryStatesSelect.vue +81 -0
  30. package/src/components/form/input-renderers/country-input/countries.ts +5746 -0
  31. package/src/components/form/input-renderers/country-input/index.ts +6 -0
  32. package/src/components/form/input-renderers/form-item-renderer/FlyFormItemRenderer.vue +2 -2
  33. package/src/components/form/input-renderers/index.ts +19 -0
  34. package/src/components/form/input-renderers/otp-input/FlyOTPInput.scss +27 -0
  35. package/src/components/form/input-renderers/otp-input/FlyOTPInput.vue +98 -0
  36. package/src/components/form/input-renderers/otp-input/index.ts +4 -0
  37. package/src/components/form/input-renderers/phone-number/FlyPhoneNumberInput.scss +1 -0
  38. package/src/components/form/input-renderers/phone-number/FlyPhoneNumberInput.types.ts +0 -0
  39. package/src/components/form/input-renderers/phone-number/FlyPhoneNumberInput.vue +98 -0
  40. package/src/components/form/input-renderers/phone-number/index.ts +4 -0
  41. package/src/components/form/input-renderers/regional-tenant-form-renderer/FlyRegionalTenantFormRenderer.types.ts +13 -1
  42. package/src/components/form/input-renderers/regional-tenant-form-renderer/FlyRegionalTenantFormRenderer.vue +18 -19
  43. package/src/components/form/input-renderers/regional-tenant-form-renderer/index.ts +10 -0
  44. package/src/components/form/input-validators.ts +109 -2
  45. package/src/composables/useLocaleInjector/index.ts +2 -2
  46. package/src/composables/useLocaleInjector/useLocaleInjector.ts +34 -0
  47. package/src/styles/element/overrides/date-time.scss +4 -0
  48. package/src/styles/element/overrides/form.scss +13 -2
  49. package/src/utils/country-utils.ts +27 -0
  50. package/src/utils/index.ts +2 -0
  51. package/src/utils/validators.ts +3 -3
  52. package/dist/types/composables/useLocaleInjector/UseLocaleInjector.d.ts +0 -14
  53. package/src/composables/useLocaleInjector/UseLocaleInjector.ts +0 -37
@@ -0,0 +1,6 @@
1
+ import FlyCountryCitySelect from './FlyCountryCitySelect.vue'
2
+ import FlyCountrySelect from './FlyCountrySelect.vue'
3
+ import FlyCountryStatesSelect from './FlyCountryStatesSelect.vue'
4
+
5
+ export default FlyCountrySelect
6
+ export { FlyCountrySelect, FlyCountryCitySelect, FlyCountryStatesSelect }
@@ -20,7 +20,7 @@ import { computed } from 'vue'
20
20
 
21
21
  import { ElFormItem } from 'element-plus'
22
22
 
23
- import { UseLocaleInjector } from '../../../../composables/useLocaleInjector/UseLocaleInjector'
23
+ import { useLocaleInjector } from '../../../../composables/useLocaleInjector/useLocaleInjector'
24
24
  import FlyInfoTooltip from '../../../feedback/tooltip/FlyInfoTooltip.vue'
25
25
  import type { T_InputRendererBase } from '../input-renderer.types'
26
26
  import FlyInputRenderer from '../input-renderer/FlyInputRenderer.vue'
@@ -39,7 +39,7 @@ const emit = defineEmits<{
39
39
  (e: 'focus'): void
40
40
  }>()
41
41
 
42
- const { t } = UseLocaleInjector()
42
+ const { t } = useLocaleInjector()
43
43
 
44
44
  const modelProxy = computed({
45
45
  get: () => props.modelValue,
@@ -0,0 +1,19 @@
1
+ export * from './form-item-renderer'
2
+ export * from './input-renderer'
3
+
4
+ export * from './country-input'
5
+ export * from './phone-number'
6
+ export * from './otp-input'
7
+ export * from './regional-tenant-form-renderer'
8
+
9
+ export type { T_InputRendererBase } from './input-renderer.types'
10
+ export type {
11
+ T_FormSchemaLookupData,
12
+ T_InputSchema,
13
+ T_InputSchemaText,
14
+ T_InputSchemaNumber,
15
+ T_InputSchemaBoolean,
16
+ T_InputSchemaSelect,
17
+ T_InputSchemaValueUnit,
18
+ T_InputSchemaDateTime
19
+ } from './form-schema.types'
@@ -0,0 +1,27 @@
1
+ @use 'element-plus/theme-chalk/src/input.scss';
2
+
3
+ .fly-otp-input-group {
4
+ display: flex;
5
+ justify-content: center;
6
+ align-self: center;
7
+ flex-wrap: wrap;
8
+ gap: 1rem; // tw:gap-4
9
+ }
10
+
11
+ .fly-otp-input-slot {
12
+ width: 3rem; // tw:w-12
13
+ }
14
+
15
+ .fly-otp-input {
16
+ .el-input__wrapper {
17
+ aspect-ratio: 1 / 1; // tw:aspect-square
18
+ padding: 0;
19
+ }
20
+
21
+ .el-input__inner {
22
+ text-align: center; // tw:text-center
23
+ font-weight: 700; // tw:font-bold
24
+ font-size: 1.5rem; // tw:text-2xl
25
+ line-height: 2rem;
26
+ }
27
+ }
@@ -0,0 +1,98 @@
1
+ <template>
2
+ <div class="fly-otp-input-group">
3
+ <div v-for="(_, index) in slots" :key="index" class="fly-otp-input-slot">
4
+ <el-input
5
+ :ref="(el) => (inputRefs[index] = el as InstanceType<typeof ElInput> | null)"
6
+ v-model="slots[index]"
7
+ :disabled="disabled"
8
+ :maxlength="1"
9
+ class="fly-otp-input"
10
+ @input="handleInput(index)"
11
+ @keydown="(e: KeyboardEvent | Event) => handleKeydown(e, index)"
12
+ @paste.prevent="handlePaste"
13
+ />
14
+ </div>
15
+ </div>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ import { ref, watch } from 'vue'
20
+
21
+ import { ElInput } from 'element-plus'
22
+
23
+ import './FlyOTPInput.scss'
24
+
25
+ const props = defineProps<{
26
+ modelValue: string
27
+ length?: number
28
+ disabled?: boolean
29
+ }>()
30
+
31
+ const emit = defineEmits<{
32
+ (e: 'update:modelValue', value: string): void
33
+ (e: 'complete', value: string): void
34
+ }>()
35
+
36
+ const resolvedLength = props.length ?? 4
37
+
38
+ const slots = ref<string[]>(Array(resolvedLength).fill(''))
39
+ const inputRefs = ref<(InstanceType<typeof ElInput> | null)[]>([])
40
+
41
+ const emitValue = () => {
42
+ const joined = slots.value.join('')
43
+ emit('update:modelValue', joined)
44
+ if (joined.length === resolvedLength && slots.value.every((s) => s.length === 1)) {
45
+ emit('complete', joined)
46
+ }
47
+ }
48
+
49
+ const handleInput = (index: number) => {
50
+ const val = slots.value[index]
51
+ if (!val) return
52
+ // Only keep the last character in case browser allows more than 1
53
+ slots.value[index] = val.slice(-1).replace(/\D/, '')
54
+ if (!slots.value[index]) return
55
+ inputRefs.value[index + 1]?.focus()
56
+ emitValue()
57
+ }
58
+
59
+ const handleKeydown = (event: KeyboardEvent | Event, index: number) => {
60
+ if (!(event instanceof KeyboardEvent)) return
61
+ if (event.key === 'Backspace') {
62
+ if (slots.value[index]) {
63
+ slots.value[index] = ''
64
+ emitValue()
65
+ } else {
66
+ inputRefs.value[index - 1]?.focus()
67
+ }
68
+ } else if (event.key === 'ArrowLeft') {
69
+ inputRefs.value[index - 1]?.focus()
70
+ } else if (event.key === 'ArrowRight') {
71
+ inputRefs.value[index + 1]?.focus()
72
+ } else if (event.key === 'Enter') {
73
+ emit('complete', slots.value.join(''))
74
+ }
75
+ }
76
+
77
+ const handlePaste = (event: ClipboardEvent) => {
78
+ const pasted = event.clipboardData?.getData('text') ?? ''
79
+ const digits = pasted.replace(/\D/g, '').slice(0, resolvedLength).split('')
80
+ digits.forEach((d, i) => {
81
+ slots.value[i] = d
82
+ })
83
+ const lastFilled = Math.min(digits.length, resolvedLength - 1)
84
+ inputRefs.value[lastFilled]?.focus()
85
+ emitValue()
86
+ }
87
+
88
+ watch(
89
+ () => props.modelValue,
90
+ (value) => {
91
+ const incoming = (value ?? '').slice(0, resolvedLength).split('')
92
+ slots.value = Array(resolvedLength)
93
+ .fill('')
94
+ .map((_, i) => incoming[i] ?? '')
95
+ },
96
+ { immediate: true }
97
+ )
98
+ </script>
@@ -0,0 +1,4 @@
1
+ import FlyOTPInput from './FlyOTPInput.vue'
2
+
3
+ export default FlyOTPInput
4
+ export { FlyOTPInput }
@@ -0,0 +1 @@
1
+ @use '../text/FlyText.scss';
@@ -0,0 +1,98 @@
1
+ <template>
2
+ <el-input
3
+ v-model="localInput"
4
+ :disabled="!countryCode"
5
+ :maxlength="phoneMaxLength"
6
+ clearable
7
+ @input="updateModel"
8
+ @change="emit('change', props.modelValue)"
9
+ @blur="emit('blur')"
10
+ @focus="emit('focus')"
11
+ >
12
+ <template #prepend>
13
+ <FlyCountrySelect
14
+ v-model="countryCode"
15
+ style="width: 115px"
16
+ @update:model-value="handleCountryChange"
17
+ >
18
+ <template #label="{ scope }">
19
+ <span v-if="scope.value"> +{{ getCountryCallingCode(scope.value as CountryCode) }} </span>
20
+ </template>
21
+ </FlyCountrySelect>
22
+ </template>
23
+ </el-input>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { computed, ref, watch } from 'vue'
28
+
29
+ import { ElInput } from 'element-plus'
30
+
31
+ import {
32
+ type CountryCode,
33
+ getCountryCallingCode,
34
+ getExampleNumber,
35
+ parsePhoneNumberFromString
36
+ } from 'libphonenumber-js'
37
+ import examples from 'libphonenumber-js/examples.mobile.json'
38
+
39
+ import FlyCountrySelect from '../country-input/FlyCountrySelect.vue'
40
+
41
+ import './FlyPhoneNumberInput.scss'
42
+
43
+ const props = defineProps<{
44
+ modelValue?: string
45
+ }>()
46
+
47
+ const emit = defineEmits<{
48
+ (e: 'update:modelValue', value: string | undefined): void
49
+ (e: 'change', value: string | undefined): void
50
+ (e: 'blur'): void
51
+ (e: 'focus'): void
52
+ }>()
53
+
54
+ const countryCode = ref<CountryCode>()
55
+ const localInput = ref('')
56
+
57
+ const phoneMaxLength = computed(() => {
58
+ if (!countryCode.value) return 15
59
+
60
+ return getExampleNumber(countryCode.value, examples)?.nationalNumber.length ?? 15
61
+ })
62
+
63
+ const updateModel = () => {
64
+ if (!countryCode.value || !localInput.value.trim()) {
65
+ emit('update:modelValue', undefined)
66
+ return
67
+ }
68
+
69
+ const phone = parsePhoneNumberFromString(localInput.value, countryCode.value)
70
+
71
+ emit('update:modelValue', phone?.number)
72
+ }
73
+
74
+ const handleCountryChange = (value?: string) => {
75
+ countryCode.value = value as CountryCode | undefined
76
+ localInput.value = ''
77
+ emit('update:modelValue', undefined)
78
+ emit('change', undefined)
79
+ }
80
+
81
+ watch(
82
+ () => props.modelValue,
83
+ (value) => {
84
+ if (!value) {
85
+ localInput.value = ''
86
+ return
87
+ }
88
+
89
+ const phone = parsePhoneNumberFromString(value)
90
+
91
+ if (!phone?.country) return
92
+
93
+ countryCode.value = phone.country
94
+ localInput.value = phone.nationalNumber
95
+ },
96
+ { immediate: true }
97
+ )
98
+ </script>
@@ -0,0 +1,4 @@
1
+ import FlyPhoneNumberInput from './FlyPhoneNumberInput.vue'
2
+
3
+ export default FlyPhoneNumberInput
4
+ export { FlyPhoneNumberInput }
@@ -1,5 +1,16 @@
1
1
  import type { T_FormSchemaLookupData, T_InputSchema } from '../form-schema.types'
2
2
 
3
+ import type FlyRegionalTenantFormRenderer from './FlyRegionalTenantFormRenderer.vue'
4
+
5
+ export type T_FlyRegionalTenantFormRendererInstance = InstanceType<
6
+ typeof FlyRegionalTenantFormRenderer
7
+ > | null
8
+
9
+ export type T_TenantRegionalFormMainSection = {
10
+ key: string
11
+ title: string
12
+ }
13
+
3
14
  export type T_TenantRegionalFormSection = {
4
15
  key: string
5
16
  fields: T_InputSchema[]
@@ -10,6 +21,7 @@ export type T_TenantRegionalFormSection = {
10
21
  }
11
22
 
12
23
  export type T_TenantRegionalFormProps = {
13
- mainFormTitle: string
24
+ mainSections: T_TenantRegionalFormMainSection[]
14
25
  sections?: T_TenantRegionalFormSection[]
26
+ activeSection?: string | number
15
27
  }
@@ -1,15 +1,17 @@
1
1
  <template>
2
2
  <div class="fly-regional-tenant-form-renderer">
3
3
  <el-collapse v-if="sections?.length" v-model="activeNames" accordion>
4
- <el-collapse-item :name="E_CollapsibleSections.mainForm">
5
- <template #title>
6
- <FlyCollapseTitleRenderer :title="mainFormTitle" />
7
- </template>
4
+ <template v-for="mainSection in mainSections" :key="mainSection.key">
5
+ <el-collapse-item :name="mainSection.key">
6
+ <template #title>
7
+ <FlyCollapseTitleRenderer :title="mainSection.title" />
8
+ </template>
8
9
 
9
- <div style="padding: 1rem">
10
- <slot></slot>
11
- </div>
12
- </el-collapse-item>
10
+ <div style="padding: 1rem">
11
+ <slot :name="mainSection.key"></slot>
12
+ </div>
13
+ </el-collapse-item>
14
+ </template>
13
15
 
14
16
  <template v-for="section in sections">
15
17
  <el-collapse-item v-if="section.fields?.length" :key="section.key" :name="section.key">
@@ -19,7 +21,7 @@
19
21
  <div style="padding: 1rem">
20
22
  <div v-if="section.description" style="margin-bottom: 1.25rem">
21
23
  <p style="font-size: 0.875; line-height: 1.25rem">
22
- {{ t(section.description) }}
24
+ {{ section.description }}
23
25
  </p>
24
26
  </div>
25
27
 
@@ -42,11 +44,10 @@
42
44
  </template>
43
45
 
44
46
  <script setup lang="ts">
45
- import { type ComponentPublicInstance, reactive, ref } from 'vue'
47
+ import { type ComponentPublicInstance, computed, reactive } from 'vue'
46
48
 
47
49
  import { ElCollapse, ElCollapseItem } from 'element-plus'
48
50
 
49
- import { UseLocaleInjector } from '../../../../composables/useLocaleInjector/UseLocaleInjector'
50
51
  import '../../../../styles/element/overrides/collapse.scss'
51
52
  import FlyCollapseTitleRenderer from '../../../basic/typography/FlyCollapseTitleRenderer.vue'
52
53
  import type { T_FlyFormSchemaRendererInstance } from '../form-schema-renderer/FlyFormSchemaRenderer.types'
@@ -54,15 +55,13 @@ import FlyFormSchemaRenderer from '../form-schema-renderer/FlyFormSchemaRenderer
54
55
 
55
56
  import type { T_TenantRegionalFormProps } from './FlyRegionalTenantFormRenderer.types'
56
57
 
57
- enum E_CollapsibleSections {
58
- mainForm
59
- }
60
-
61
- defineProps<T_TenantRegionalFormProps>()
58
+ const props = defineProps<T_TenantRegionalFormProps>()
59
+ const emit = defineEmits<{ 'update:activeSection': [value: string | number] }>()
62
60
 
63
- const { t } = UseLocaleInjector()
64
-
65
- const activeNames = ref<string | number>(E_CollapsibleSections.mainForm)
61
+ const activeNames = computed<string | number>({
62
+ get: () => props.activeSection ?? props.mainSections[0]?.key ?? '',
63
+ set: (val) => emit('update:activeSection', val)
64
+ })
66
65
  const formRefs = reactive<{ [K: string]: T_FlyFormSchemaRendererInstance }>({})
67
66
 
68
67
  function setFormRef(formRef: Element | ComponentPublicInstance | null, key: string) {
@@ -0,0 +1,10 @@
1
+ import FlyRegionalTenantFormRenderer from './FlyRegionalTenantFormRenderer.vue'
2
+
3
+ export default FlyRegionalTenantFormRenderer
4
+ export { FlyRegionalTenantFormRenderer }
5
+ export type {
6
+ T_TenantRegionalFormMainSection,
7
+ T_TenantRegionalFormSection,
8
+ T_TenantRegionalFormProps,
9
+ T_FlyRegionalTenantFormRendererInstance
10
+ } from './FlyRegionalTenantFormRenderer.types'
@@ -1,8 +1,9 @@
1
1
  import type { FormItemRule } from 'element-plus'
2
2
 
3
+ import { isValidPhoneNumber } from 'libphonenumber-js'
3
4
  import { isNil } from 'lodash-es'
4
5
 
5
- import { UseLocaleInjector } from '../../composables/useLocaleInjector/UseLocaleInjector'
6
+ import { useLocaleInjector } from '../../composables/useLocaleInjector/useLocaleInjector'
6
7
  import { type checkInputRange, isRequiredError } from '../../utils/validators'
7
8
 
8
9
  import type { T_ValueUnitValue } from './input-renderers/value-unit/FlyValueUnit.types'
@@ -33,7 +34,7 @@ export const requiredFieldNumber = (
33
34
  languageKey = 'validation.field',
34
35
  trigger: InputTriggers = 'change'
35
36
  ): FormItemRule => {
36
- const { t } = UseLocaleInjector()
37
+ const { t } = useLocaleInjector()
37
38
 
38
39
  return {
39
40
  type: 'number',
@@ -97,3 +98,109 @@ export const requiredFieldArray = (
97
98
  trigger: trigger,
98
99
  message: useRequiredMessage ? isRequiredError(label) : label
99
100
  })
101
+
102
+ const emailRegexValidation = (value: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)
103
+
104
+ export const requiredFieldEmail = (
105
+ label = 'validation.field',
106
+ trigger: InputTriggers = 'blur',
107
+ useRequiredMessage = true
108
+ ): FormItemRule => ({
109
+ required: true,
110
+ trigger: trigger,
111
+ message: useRequiredMessage ? isRequiredError(label) : label
112
+ })
113
+
114
+ export const fieldEmail = (
115
+ languageKey = 'validation.field',
116
+ trigger: InputTriggers = 'blur'
117
+ ): FormItemRule => {
118
+ const { t } = useLocaleInjector()
119
+
120
+ return {
121
+ trigger: trigger,
122
+ validator: (_rule, value, callback) => {
123
+ // used in element form validator
124
+ if (!value) return callback()
125
+
126
+ if (!emailRegexValidation(value)) {
127
+ return callback(
128
+ new Error(
129
+ t('validation.fieldMustBeValidEmail', {
130
+ fieldName: t(languageKey)
131
+ })
132
+ )
133
+ )
134
+ }
135
+
136
+ return callback()
137
+ }
138
+ }
139
+ }
140
+
141
+ export const requiredFieldEmailArray = (
142
+ label = 'validation.field',
143
+ trigger: InputTriggers = 'blur',
144
+ useRequiredMessage = true,
145
+ required = true
146
+ ): FormItemRule => {
147
+ const { t } = useLocaleInjector()
148
+
149
+ return {
150
+ required: required,
151
+ trigger: trigger,
152
+ validator: (_rule, value: string[], callback) => {
153
+ // not required
154
+ if (value.length === 0 && !required) {
155
+ return callback()
156
+ }
157
+
158
+ // required but empty data passed
159
+ if (value.length === 0) {
160
+ return callback(new Error(useRequiredMessage ? isRequiredError(label) : label))
161
+ }
162
+
163
+ const invalidEmails = value.filter((email) => !emailRegexValidation(email))
164
+
165
+ if (invalidEmails.length > 0) {
166
+ return callback(
167
+ new Error(
168
+ t('validation.theseEmailsMustBeValid', {
169
+ emails: invalidEmails.join(', ')
170
+ })
171
+ )
172
+ )
173
+ }
174
+
175
+ return callback()
176
+ }
177
+ }
178
+ }
179
+
180
+ export const requiredFieldE164PhoneNumber = (
181
+ label = 'validation.field',
182
+ trigger: InputTriggers = 'blur',
183
+ useRequiredMessage = true
184
+ ): FormItemRule => ({
185
+ required: true,
186
+ trigger: trigger,
187
+ message: useRequiredMessage ? isRequiredError(label) : label
188
+ })
189
+
190
+ export const fieldE164PhoneNumber = (trigger: InputTriggers = 'blur'): FormItemRule => {
191
+ const { t } = useLocaleInjector()
192
+
193
+ return {
194
+ trigger: trigger,
195
+ validator: (_rule, value: string, callback) => {
196
+ // used in element form validator
197
+ if (!value) return callback()
198
+
199
+ if (!isValidPhoneNumber(value)) {
200
+ return callback(new Error(t('validation.phoneNumberInvalid')))
201
+ }
202
+
203
+ return callback()
204
+ }
205
+ }
206
+ }
@@ -1,2 +1,2 @@
1
- export { initLocaleInjector, UseLocaleInjector } from './UseLocaleInjector'
2
- export type { T_LocaleInjector } from './UseLocaleInjector'
1
+ export { initLocaleInjector, useLocaleInjector } from './useLocaleInjector'
2
+ export type { T_LocaleInjector, T_I18nAdapter as I18nAdapter } from './useLocaleInjector'
@@ -0,0 +1,34 @@
1
+ import { computed, isRef } from 'vue'
2
+ import type { ComputedRef, MaybeRef } from 'vue'
3
+
4
+ import { FallbackTranslateFn } from '@flyanra/js-utils/constants'
5
+ import type { Locale } from '@flyanra/js-utils/locales'
6
+ import type { ComposerTranslation } from 'vue-i18n'
7
+
8
+ export type T_LocaleInjector = {
9
+ t: ComposerTranslation
10
+ locale: ComputedRef<Locale>
11
+ }
12
+
13
+ export type T_I18nAdapter = {
14
+ t: ComposerTranslation
15
+ locale: MaybeRef<Locale>
16
+ }
17
+
18
+ let _t: ComposerTranslation = FallbackTranslateFn
19
+ let _locale: ComputedRef<Locale> = computed(() => 'en')
20
+ let _initialized = false
21
+
22
+ export function initLocaleInjector(i18n: T_I18nAdapter): void {
23
+ _t = i18n.t
24
+ _locale = computed(() => (isRef(i18n.locale) ? i18n.locale.value : i18n.locale))
25
+ _initialized = true
26
+ }
27
+
28
+ export function useLocaleInjector(): T_LocaleInjector {
29
+ if (!_initialized) {
30
+ console.warn('[vue-core] useLocaleInjector: call initLocaleInjector() before use.')
31
+ }
32
+
33
+ return { t: _t, locale: _locale }
34
+ }
@@ -9,3 +9,7 @@
9
9
 
10
10
  @use 'element-plus/theme-chalk/src/popper.scss';
11
11
  @use 'element-plus/theme-chalk/src/scrollbar.scss';
12
+
13
+ .el-date-editor.el-input {
14
+ --el-date-editor-width: 100%;
15
+ }
@@ -78,8 +78,6 @@
78
78
  }
79
79
 
80
80
  .el-select__wrapper {
81
- --el-fill-color-blank: var(--anra-bg-20);
82
-
83
81
  &.is-disabled {
84
82
  background-color: var(--anra-disabled-bg);
85
83
  }
@@ -119,3 +117,16 @@
119
117
  line-height: 1px;
120
118
  font-weight: bolder;
121
119
  }
120
+
121
+ .el-input-group--prepend .el-input-group__prepend .el-select .el-select__wrapper.is-disabled {
122
+ --el-input-border-color: var(--el-disabled-border-color);
123
+ }
124
+
125
+ .el-tag {
126
+ &.el-tag--info {
127
+ &.el-tag--light {
128
+ --el-tag-text-color: var(--default-text-color);
129
+ --el-tag-bg-color: var(--el-color-info-light-7);
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,27 @@
1
+ const AdministrativeAreaLabels: Partial<Record<string, string>> = {
2
+ AE: 'address.administrativeAreaLabel.emirate',
3
+ GB: 'address.administrativeAreaLabel.county',
4
+ JP: 'address.administrativeAreaLabel.prefecture'
5
+ }
6
+
7
+ function getAdministrativeAreaLabel(countryCode?: string): string {
8
+ return (
9
+ AdministrativeAreaLabels[countryCode?.toUpperCase() ?? ''] ??
10
+ 'address.administrativeAreaLabel.stateOrProvince'
11
+ )
12
+ }
13
+
14
+ const nationalIdLabels: Partial<Record<string, string>> = {
15
+ AE: 'user.nationalIdLabels.emiratesId',
16
+ GB: 'user.nationalIdLabels.nationalInsuranceNumber',
17
+ US: 'user.nationalIdLabels.socialSecurityNumber',
18
+ NG: 'user.nationalIdLabels.nationalIdentificationNumber'
19
+ }
20
+
21
+ function getNationalIdLabel(countryCode?: string) {
22
+ return countryCode
23
+ ? (nationalIdLabels[countryCode] ?? 'user.nationalIdLabels.defaultLabel')
24
+ : 'user.nationalIdLabels.defaultLabel'
25
+ }
26
+
27
+ export { getAdministrativeAreaLabel, getNationalIdLabel }
@@ -1,2 +1,4 @@
1
1
  export { checkRange } from './pure-functions'
2
2
  export { checkInputRange, isRequiredError } from './validators'
3
+
4
+ export * from './country-utils'
@@ -1,11 +1,11 @@
1
1
  import type { FormItemRule } from 'element-plus'
2
2
 
3
- import { UseLocaleInjector } from '../composables/useLocaleInjector/UseLocaleInjector'
3
+ import { useLocaleInjector } from '../composables/useLocaleInjector/useLocaleInjector'
4
4
 
5
5
  import { checkRange } from './pure-functions'
6
6
 
7
7
  export const isRequiredError = (languageKey: string) => {
8
- const { t } = UseLocaleInjector()
8
+ const { t } = useLocaleInjector()
9
9
 
10
10
  return t('validation.fieldIsRequired', {
11
11
  fieldName: t(languageKey)
@@ -22,7 +22,7 @@ export const checkInputRange = (
22
22
  valueTypeLanguageKey: string = 'validation.valueTypes.characters',
23
23
  errorMessage?: string
24
24
  ): FormItemRule['validator'] => {
25
- const { t } = UseLocaleInjector()
25
+ const { t } = useLocaleInjector()
26
26
 
27
27
  // used in element form validator
28
28
  return (_rule: unknown, value: unknown, callback: (_?: string | Error | undefined) => void) => {
@@ -1,14 +0,0 @@
1
- import type { MaybeRef } from 'vue';
2
- import type { Locale } from '@flyanra/js-utils/locales';
3
- import type { ComposerTranslation } from 'vue-i18n';
4
- export type T_LocaleInjector = {
5
- t: ComposerTranslation;
6
- locale: Locale;
7
- };
8
- type I18nLike = {
9
- t: ComposerTranslation;
10
- locale: MaybeRef<Locale>;
11
- };
12
- export declare function initLocaleInjector(i18n: I18nLike): void;
13
- export declare function UseLocaleInjector(): T_LocaleInjector;
14
- export {};