@cnamts/synapse 0.0.11-alpha → 0.0.12-alpha
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/design-system-v3.js +3878 -3189
- package/dist/design-system-v3.umd.cjs +1 -1
- package/dist/src/components/Amelipro/types/languages.d.ts +6 -0
- package/dist/src/components/Amelipro/types/types.d.ts +65 -0
- package/dist/src/components/CookieBanner/CookieBanner.d.ts +1 -1
- package/dist/src/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -0
- package/dist/src/components/Customs/SyTextField/SyTextField.d.ts +29 -23
- package/dist/src/components/Customs/SyTextField/types.d.ts +1 -0
- package/dist/src/components/DatePicker/DatePicker.d.ts +70 -59
- package/dist/src/components/DatePicker/DateTextInput.d.ts +67 -56
- package/dist/src/components/ErrorPage/ErrorPage.d.ts +1 -1
- package/dist/src/components/FileList/FileList.d.ts +1 -0
- package/dist/src/components/FileList/UploadItem/UploadItem.d.ts +1 -1
- package/dist/src/components/FilterSideBar/FilterSideBar.d.ts +31 -0
- package/dist/src/components/FilterSideBar/locales.d.ts +7 -0
- package/dist/src/components/FilterSideBar/tests/FilterSideBar.spec.d.ts +1 -0
- package/dist/src/components/LangBtn/LangBtn.d.ts +2 -2
- package/dist/src/components/NirField/NirField.d.ts +940 -0
- package/dist/src/components/NotificationBar/NotificationBar.d.ts +1 -1
- package/dist/src/components/PasswordField/PasswordField.d.ts +40 -8
- package/dist/src/components/PeriodField/PeriodField.d.ts +142 -120
- package/dist/src/components/PhoneField/PhoneField.d.ts +11 -2
- package/dist/src/components/RatingPicker/EmotionPicker/EmotionPicker.d.ts +1 -1
- package/dist/src/components/RatingPicker/NumberPicker/NumberPicker.d.ts +1 -1
- package/dist/src/components/RatingPicker/StarsPicker/StarsPicker.d.ts +1 -1
- package/dist/src/components/UploadWorkflow/config.d.ts +29 -0
- package/dist/src/components/UploadWorkflow/locales.d.ts +7 -0
- package/dist/src/components/UploadWorkflow/tests/UploadWorkflow.spec.d.ts +1 -0
- package/dist/src/components/UploadWorkflow/types.d.ts +19 -0
- package/dist/src/components/UploadWorkflow/useFileList.d.ts +10 -0
- package/dist/src/components/UploadWorkflow/useFileUploadJourney.d.ts +9 -0
- package/dist/src/components/index.d.ts +2 -0
- package/dist/src/composables/rules/useFieldValidation.d.ts +1 -0
- package/dist/src/composables/validation/tests/useValidation.spec.d.ts +1 -0
- package/dist/src/composables/validation/useValidation.d.ts +39 -0
- package/dist/src/designTokens/index.d.ts +3 -1
- package/dist/src/vuetifyConfig.d.ts +81 -0
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/assets/_elevations.scss +89 -0
- package/src/assets/_fonts.scss +6 -0
- package/src/assets/_radius.scss +86 -0
- package/src/assets/_spacers.scss +149 -0
- package/src/assets/settings.scss +7 -3
- package/src/assets/tokens.scss +32 -29
- package/src/components/Amelipro/types/languages.d.ts +6 -0
- package/src/components/Amelipro/types/types.d.ts +65 -0
- package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +65 -0
- package/src/components/Customs/SyInputSelect/SyInputSelect.vue +13 -3
- package/src/components/Customs/SySelect/SySelect.stories.ts +88 -5
- package/src/components/Customs/SySelect/SySelect.vue +36 -10
- package/src/components/Customs/SySelect/tests/SySelect.spec.ts +135 -2
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +576 -85
- package/src/components/Customs/SyTextField/SyTextField.vue +132 -104
- package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +190 -38
- package/src/components/Customs/SyTextField/types.d.ts +1 -0
- package/src/components/DatePicker/DatePicker.vue +405 -137
- package/src/components/DatePicker/DateTextInput.vue +15 -0
- package/src/components/DatePicker/tests/DatePicker.spec.ts +8 -15
- package/src/components/FileList/FileList.vue +2 -1
- package/src/components/FileList/UploadItem/UploadItem.vue +10 -0
- package/src/components/FileUpload/FileUpload.stories.ts +84 -0
- package/src/components/FileUpload/FileUpload.vue +1 -0
- package/src/components/FileUpload/tests/FileUpload.spec.ts +4 -4
- package/src/components/FilterInline/FilterInline.mdx +180 -34
- package/src/components/FilterInline/FilterInline.stories.ts +363 -6
- package/src/components/FilterSideBar/FilterSideBar.mdx +237 -0
- package/src/components/FilterSideBar/FilterSideBar.stories.ts +798 -0
- package/src/components/FilterSideBar/FilterSideBar.vue +193 -0
- package/src/components/FilterSideBar/locales.ts +8 -0
- package/src/components/FilterSideBar/tests/FilterSideBar.spec.ts +305 -0
- package/src/components/FilterSideBar/tests/__snapshots__/FilterSideBar.spec.ts.snap +39 -0
- package/src/components/HeaderBar/Usages.mdx +1 -1
- package/src/components/NirField/NirField.stories.ts +573 -29
- package/src/components/NirField/NirField.vue +397 -359
- package/src/components/NirField/tests/NirField.spec.ts +88 -52
- package/src/components/NirField/tests//342/200/257dataset/342/200/257.md +12 -0
- package/src/components/NotificationBar/Accessibilite.stories.ts +4 -0
- package/src/components/NotificationBar/NotificationBar.stories.ts +18 -13
- package/src/components/PasswordField/PasswordField.mdx +129 -47
- package/src/components/PasswordField/PasswordField.stories.ts +924 -120
- package/src/components/PasswordField/PasswordField.vue +209 -99
- package/src/components/PasswordField/tests/PasswordField.spec.ts +138 -9
- package/src/components/PeriodField/PeriodField.vue +55 -54
- package/src/components/PhoneField/PhoneField.stories.ts +69 -0
- package/src/components/PhoneField/PhoneField.vue +3 -0
- package/src/components/PhoneField/indicatifs.ts +1 -1
- package/src/components/UploadWorkflow/UploadWorkflow.mdx +75 -0
- package/src/components/UploadWorkflow/UploadWorkflow.stories.ts +943 -0
- package/src/components/UploadWorkflow/UploadWorkflow.vue +230 -0
- package/src/components/UploadWorkflow/config.ts +29 -0
- package/src/components/UploadWorkflow/locales.ts +8 -0
- package/src/components/UploadWorkflow/tests/UploadWorkflow.spec.ts +257 -0
- package/src/components/UploadWorkflow/tests/__snapshots__/UploadWorkflow.spec.ts.snap +54 -0
- package/src/components/UploadWorkflow/types.ts +21 -0
- package/src/components/UploadWorkflow/useFileList.ts +84 -0
- package/src/components/UploadWorkflow/useFileUploadJourney.ts +18 -0
- package/src/components/index.ts +2 -0
- package/src/composables/rules/useFieldValidation.ts +5 -2
- package/src/composables/validation/tests/useValidation.spec.ts +154 -0
- package/src/composables/validation/useValidation.ts +165 -0
- package/src/designTokens/index.ts +4 -0
- package/src/stories/Demarrer/Accueil.mdx +1 -1
- package/src/stories/DesignTokens/ThemePA.mdx +4 -30
- package/src/stories/GuideDuDev/UtiliserLesRules.mdx +319 -76
- package/src/stories/GuideDuDev/moduleDeNotification.mdx +1 -1
- package/src/vuetifyConfig.ts +61 -0
- package/src/composables/useFilterable/__snapshots__/useFilterable.spec.ts.snap +0 -3
|
@@ -1,457 +1,495 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { ref, watch, computed, nextTick } from 'vue'
|
|
3
|
-
import { useFieldValidation } from '@/composables/rules/useFieldValidation'
|
|
2
|
+
import { ref, watch, computed, nextTick, toRef } from 'vue'
|
|
4
3
|
import { vMaska } from 'maska/vue'
|
|
5
4
|
import { checkNIR, isNIRKeyValid } from './nirValidation'
|
|
6
|
-
import useCustomizableOptions, { type CustomizableOptions } from '@/composables/useCustomizableOptions'
|
|
5
|
+
// import useCustomizableOptions, { type CustomizableOptions } from '@/composables/useCustomizableOptions'
|
|
6
|
+
import { type CustomizableOptions } from '@/composables/useCustomizableOptions'
|
|
7
7
|
import SyTextField from '../Customs/SyTextField/SyTextField.vue'
|
|
8
|
-
import { mdiInformationOutline } from '@mdi/js'
|
|
9
8
|
import { locales } from './locales'
|
|
10
|
-
import defaultOptions from './config'
|
|
11
|
-
|
|
12
|
-
type Rule = (value: string) => { error?: string, success?: string }
|
|
13
|
-
|
|
9
|
+
// import defaultOptions from './config'
|
|
10
|
+
import { useValidation, type ValidationRule } from '@/composables/validation/useValidation'
|
|
14
11
|
const props = withDefaults(defineProps<CustomizableOptions & {
|
|
15
12
|
modelValue?: string | undefined
|
|
16
|
-
|
|
17
|
-
required?: boolean
|
|
18
|
-
nirTooltip?: string
|
|
19
|
-
keyTooltip?: string
|
|
13
|
+
label?: string
|
|
20
14
|
numberLabel?: string
|
|
21
15
|
keyLabel?: string
|
|
22
16
|
displayKey?: boolean
|
|
17
|
+
outlined?: boolean
|
|
18
|
+
nirTooltip?: string
|
|
19
|
+
keyTooltip?: string
|
|
20
|
+
nirTooltipPosition?: 'prepend' | 'append'
|
|
21
|
+
keyTooltipPosition?: 'prepend' | 'append'
|
|
22
|
+
required?: boolean
|
|
23
|
+
displayAsterisk?: boolean
|
|
24
|
+
customNumberRules?: ValidationRule[]
|
|
25
|
+
customKeyRules?: ValidationRule[]
|
|
26
|
+
customNumberWarningRules?: ValidationRule[]
|
|
27
|
+
customKeyWarningRules?: ValidationRule[]
|
|
23
28
|
showSuccessMessages?: boolean
|
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
|
|
25
|
-
customNumberRules?: any
|
|
26
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
|
|
27
|
-
customKeyRules?: any
|
|
28
29
|
width?: string
|
|
30
|
+
bgColor?: string
|
|
31
|
+
isDisabled?: boolean
|
|
32
|
+
density?: 'default' | 'comfortable' | 'compact'
|
|
33
|
+
hideDetails?: boolean | 'auto'
|
|
34
|
+
hideSpinButtons?: boolean
|
|
35
|
+
placeholder?: string
|
|
36
|
+
readonly?: boolean
|
|
37
|
+
variant?: 'filled' | 'outlined' | 'plain' | 'underlined' | 'solo'
|
|
38
|
+
clearable?: boolean
|
|
39
|
+
counter?: boolean | number | string
|
|
40
|
+
hint?: string
|
|
41
|
+
persistentHint?: boolean
|
|
42
|
+
persistentPlaceholder?: boolean
|
|
29
43
|
}>(), {
|
|
30
44
|
modelValue: undefined,
|
|
31
|
-
|
|
32
|
-
required: false,
|
|
33
|
-
nirTooltip: undefined,
|
|
34
|
-
keyTooltip: undefined,
|
|
45
|
+
label: undefined,
|
|
35
46
|
numberLabel: 'Numéro de sécurité sociale',
|
|
36
47
|
keyLabel: 'Clé',
|
|
37
48
|
displayKey: true,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
outlined: true,
|
|
50
|
+
nirTooltip: undefined,
|
|
51
|
+
keyTooltip: undefined,
|
|
52
|
+
nirTooltipPosition: 'append',
|
|
53
|
+
keyTooltipPosition: 'append',
|
|
54
|
+
required: false,
|
|
55
|
+
displayAsterisk: false,
|
|
56
|
+
customNumberRules: () => [],
|
|
57
|
+
customKeyRules: () => [],
|
|
58
|
+
customNumberWarningRules: () => [],
|
|
59
|
+
customKeyWarningRules: () => [],
|
|
60
|
+
showSuccessMessages: true,
|
|
41
61
|
width: '100%',
|
|
62
|
+
bgColor: undefined,
|
|
63
|
+
isDisabled: false,
|
|
64
|
+
density: 'default',
|
|
65
|
+
hideDetails: false,
|
|
66
|
+
hideSpinButtons: false,
|
|
67
|
+
placeholder: undefined,
|
|
68
|
+
readonly: false,
|
|
69
|
+
variant: 'outlined',
|
|
70
|
+
clearable: false,
|
|
71
|
+
counter: false,
|
|
72
|
+
hint: undefined,
|
|
73
|
+
persistentHint: false,
|
|
74
|
+
persistentPlaceholder: false,
|
|
42
75
|
})
|
|
43
76
|
|
|
44
77
|
const emit = defineEmits(['update:modelValue'])
|
|
45
|
-
const
|
|
46
|
-
const
|
|
78
|
+
const modelValueRef = toRef(props, 'modelValue')
|
|
79
|
+
// const options = useCustomizableOptions(defaultOptions, props)
|
|
47
80
|
|
|
48
81
|
// Champs
|
|
49
82
|
const numberValue = ref('')
|
|
50
83
|
const keyValue = ref('')
|
|
51
|
-
const keyDeleted = ref(false)
|
|
52
84
|
|
|
53
85
|
// Refs pour les champs
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
|
|
57
|
-
const numberField = ref<any | null>(null)
|
|
86
|
+
const keyField = ref<InstanceType<typeof SyTextField> | null>(null)
|
|
87
|
+
const numberField = ref<InstanceType<typeof SyTextField> | null>(null)
|
|
58
88
|
|
|
89
|
+
// Valeurs non masquées
|
|
59
90
|
const unmaskedNumberValue = computed(() => numberValue.value.replace(/\s/g, ''))
|
|
60
|
-
|
|
61
|
-
watch(() => props.modelValue, async (value) => {
|
|
62
|
-
numberValue.value = value?.slice(0, 13) ?? ''
|
|
63
|
-
keyValue.value = value?.slice(13, 15) ?? ''
|
|
64
|
-
}, { immediate: true })
|
|
65
|
-
|
|
66
|
-
// Etats d’erreur/succès
|
|
67
|
-
const errors = ref<string[]>([])
|
|
68
|
-
const successes = ref<string[]>([])
|
|
69
|
-
|
|
70
|
-
// Flags de validation
|
|
71
|
-
const isValidating = ref(false)
|
|
91
|
+
const unmaskedKeyValue = computed(() => keyValue.value.replace(/\s/g, ''))
|
|
72
92
|
|
|
73
93
|
// Masques
|
|
74
94
|
const numberMask = {
|
|
75
95
|
mask: '# ## ## #C ### ###',
|
|
76
96
|
preProcess: (value: string) => value.toUpperCase(),
|
|
77
97
|
tokens: {
|
|
78
|
-
|
|
98
|
+
'#': {
|
|
99
|
+
pattern: /[0-9]/,
|
|
100
|
+
},
|
|
101
|
+
'C': {
|
|
79
102
|
pattern: /[0-9AB]/,
|
|
80
103
|
transform: (char: string) => char.toUpperCase(),
|
|
81
104
|
},
|
|
82
105
|
},
|
|
83
106
|
}
|
|
84
|
-
const keyMask = {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const defaultNumberRules = [
|
|
90
|
-
{
|
|
91
|
-
type: 'exactLength',
|
|
92
|
-
options: { length: 13, message: locales.errorLengthNumber(13), ignoreSpace: true, fieldIdentifier: 'numéro' },
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
type: 'custom',
|
|
96
|
-
options: {
|
|
97
|
-
validate: checkNIR,
|
|
98
|
-
message: 'Le numéro de sécurité sociale est invalide.',
|
|
99
|
-
successMessage: 'Le numéro de sécurité sociale est valide.',
|
|
100
|
-
fieldIdentifier: 'numéro',
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
...(props.required
|
|
104
|
-
? [{
|
|
105
|
-
type: 'required',
|
|
106
|
-
options: { message: 'Le numéro de sécurité sociale est requis.', fieldIdentifier: 'numéro' },
|
|
107
|
-
}]
|
|
108
|
-
: []),
|
|
109
|
-
]
|
|
110
|
-
|
|
111
|
-
const defaultKeyRules = [
|
|
112
|
-
{
|
|
113
|
-
type: 'exactLength',
|
|
114
|
-
options: { length: 2, message: locales.errorLengthKey(2), ignoreSpace: true, fieldIdentifier: 'clé' },
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
type: 'custom',
|
|
118
|
-
options: {
|
|
119
|
-
validate: () => isNIRKeyValid(`${numberValue.value}${keyValue.value}`),
|
|
120
|
-
message: 'La clé du numéro de sécurité sociale est invalide.',
|
|
121
|
-
successMessage: 'Le champ clé est valide.',
|
|
122
|
-
fieldIdentifier: 'clé',
|
|
107
|
+
const keyMask = {
|
|
108
|
+
mask: '##',
|
|
109
|
+
tokens: {
|
|
110
|
+
'#': {
|
|
111
|
+
pattern: /[0-9]/,
|
|
123
112
|
},
|
|
124
113
|
},
|
|
125
|
-
|
|
126
|
-
? [{
|
|
127
|
-
type: 'required',
|
|
128
|
-
options: { message: 'La clé est requise.', fieldIdentifier: 'clé' },
|
|
129
|
-
}]
|
|
130
|
-
: []),
|
|
131
|
-
]
|
|
114
|
+
}
|
|
132
115
|
|
|
133
|
-
//
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
: generateRules(defaultNumberRules)
|
|
146
|
-
|
|
147
|
-
const keyRules = props.displayKey
|
|
148
|
-
? (props.customKeyRules?.length
|
|
149
|
-
? generateRules(props.customKeyRules)
|
|
150
|
-
: generateRules(defaultKeyRules))
|
|
151
|
-
: []
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Valide une liste de règles sur une valeur et met à jour les tableaux d'erreurs et de succès.
|
|
155
|
-
* @param value Valeur du champ à valider
|
|
156
|
-
* @param rules Ensemble de règles
|
|
157
|
-
*/
|
|
158
|
-
function validateFieldSet(value: string, rules: Rule[]) {
|
|
159
|
-
rules.forEach((rule) => {
|
|
160
|
-
const { error, success } = rule(value)
|
|
161
|
-
if (error) errors.value.push(error)
|
|
162
|
-
if (success && success !== 'Le champ est valide.') successes.value.push(success)
|
|
116
|
+
// Fonction pour gérer le focus des champs
|
|
117
|
+
const focusField = (field: typeof numberField | typeof keyField) => {
|
|
118
|
+
nextTick(() => {
|
|
119
|
+
const input = field.value?.$el.querySelector('input')
|
|
120
|
+
if (input) {
|
|
121
|
+
// Focus and select all text
|
|
122
|
+
input.focus()
|
|
123
|
+
// Adding a slight delay to ensure focus is applied
|
|
124
|
+
setTimeout(() => {
|
|
125
|
+
input.click()
|
|
126
|
+
}, 50)
|
|
127
|
+
}
|
|
163
128
|
})
|
|
164
129
|
}
|
|
165
130
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
function validateFields(onBlur = false) {
|
|
171
|
-
errors.value = []
|
|
172
|
-
successes.value = []
|
|
173
|
-
|
|
174
|
-
const shouldValidateNumber = onBlur || isValidating.value || numberValue.value.length === 18
|
|
175
|
-
const shouldValidateKey = props.displayKey && (onBlur || isValidating.value || keyValue.value.length === 2)
|
|
176
|
-
|
|
177
|
-
if (shouldValidateNumber) {
|
|
178
|
-
validateFieldSet(numberValue.value, numberRules)
|
|
131
|
+
// Watch sur la valeur non masquée du numéro pour gérer le focus automatique
|
|
132
|
+
watch(unmaskedNumberValue, (newValue) => {
|
|
133
|
+
if (newValue.length === 13 && props.displayKey) {
|
|
134
|
+
focusField(keyField)
|
|
179
135
|
}
|
|
180
|
-
|
|
181
|
-
if (shouldValidateKey) {
|
|
182
|
-
validateFieldSet(keyValue.value, keyRules)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Unicité des succès
|
|
186
|
-
successes.value = Array.from(new Set(successes.value))
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Compteurs
|
|
190
|
-
const numberCounter = computed(() => {
|
|
191
|
-
const length = numberValue.value.replace(/\s/g, '').length
|
|
192
|
-
return `${Math.min(length, 13)}/13`
|
|
193
136
|
})
|
|
194
137
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
138
|
+
watch(unmaskedKeyValue, (newValue) => {
|
|
139
|
+
if (newValue.length === 0) {
|
|
140
|
+
focusField(numberField)
|
|
141
|
+
}
|
|
198
142
|
})
|
|
199
143
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
144
|
+
// Watch pour détecter la suppression des chiffres de la clé
|
|
145
|
+
watch(keyValue, (newValue, oldValue) => {
|
|
146
|
+
// Si l'ancienne valeur avait des chiffres et la nouvelle est vide ou ne contient que des espaces
|
|
147
|
+
if (oldValue.trim() && !newValue.trim()) {
|
|
148
|
+
focusField(numberField)
|
|
204
149
|
}
|
|
205
150
|
})
|
|
206
151
|
|
|
207
|
-
|
|
208
|
-
|
|
152
|
+
// Initialisation des validations
|
|
153
|
+
const numberValidation = useValidation({
|
|
154
|
+
showSuccessMessages: props.showSuccessMessages,
|
|
155
|
+
fieldIdentifier: props.numberLabel,
|
|
209
156
|
})
|
|
210
157
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
158
|
+
const keyValidation = useValidation({
|
|
159
|
+
showSuccessMessages: props.showSuccessMessages,
|
|
160
|
+
fieldIdentifier: props.keyLabel,
|
|
215
161
|
})
|
|
216
162
|
|
|
217
|
-
//
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
163
|
+
// Règles de validation
|
|
164
|
+
const defaultNumberRules = computed(() => {
|
|
165
|
+
const rules: ValidationRule[] = []
|
|
166
|
+
|
|
167
|
+
if (props.required) {
|
|
168
|
+
rules.push({
|
|
169
|
+
type: 'required',
|
|
170
|
+
options: {
|
|
171
|
+
message: `Le champ ${props.numberLabel} est requis.`,
|
|
172
|
+
fieldIdentifier: props.numberLabel,
|
|
173
|
+
},
|
|
174
|
+
})
|
|
226
175
|
}
|
|
227
|
-
return null
|
|
228
|
-
})
|
|
229
176
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
177
|
+
rules.push({
|
|
178
|
+
type: 'custom',
|
|
179
|
+
options: {
|
|
180
|
+
validate: (value: string) => {
|
|
181
|
+
if (!value) return true
|
|
182
|
+
// Ne valider que si tous les caractères sont saisis
|
|
183
|
+
if (value.length < 13) {
|
|
184
|
+
return 'Le numéro de sécurité sociale est invalide.'
|
|
185
|
+
}
|
|
186
|
+
const result = checkNIR(value)
|
|
187
|
+
return result === true ? true : 'Le numéro de sécurité sociale est invalide.'
|
|
188
|
+
},
|
|
189
|
+
message: 'Le numéro de sécurité sociale est invalide.',
|
|
190
|
+
successMessage: 'Le numéro de sécurité sociale est valide.',
|
|
191
|
+
fieldIdentifier: props.numberLabel,
|
|
192
|
+
},
|
|
233
193
|
})
|
|
234
|
-
})
|
|
235
194
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
195
|
+
// Ajout des règles personnalisées
|
|
196
|
+
if (props.customNumberRules) {
|
|
197
|
+
rules.push(...props.customNumberRules.map(rule => ({
|
|
198
|
+
...rule,
|
|
199
|
+
options: rule.options || {},
|
|
200
|
+
})))
|
|
201
|
+
}
|
|
241
202
|
|
|
242
|
-
|
|
243
|
-
validateOnSubmit,
|
|
203
|
+
return rules
|
|
244
204
|
})
|
|
245
|
-
</script>
|
|
246
205
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
<v-input
|
|
250
|
-
ref="vInput"
|
|
251
|
-
:class="{
|
|
252
|
-
'v-messages__message--success': successes.length > 0 && props.showSuccessMessages,
|
|
253
|
-
'v-messages__message--error': errors.length > 0
|
|
254
|
-
}"
|
|
255
|
-
:error-messages="errors"
|
|
256
|
-
:label="numberLabel"
|
|
257
|
-
:max-errors="3"
|
|
258
|
-
:messages="props.showSuccessMessages ? successes : []"
|
|
259
|
-
:model-value="[numberValue, keyValue]"
|
|
260
|
-
class="vd-nir-field__fields-wrapper multi-line"
|
|
261
|
-
validate-on="blur lazy"
|
|
262
|
-
>
|
|
263
|
-
<VTooltip v-if="nirTooltip">
|
|
264
|
-
<template #activator="{ props: iconProps }">
|
|
265
|
-
<VIcon
|
|
266
|
-
class="vd-tooltip-icon mt-4 mr-4"
|
|
267
|
-
v-bind="{ ...iconProps, ...options.tooltip }"
|
|
268
|
-
>
|
|
269
|
-
{{ infoIcon }}
|
|
270
|
-
</VIcon>
|
|
271
|
-
</template>
|
|
272
|
-
<slot name="nirTooltip">
|
|
273
|
-
{{ nirTooltip }}
|
|
274
|
-
</slot>
|
|
275
|
-
</VTooltip>
|
|
276
|
-
<SyTextField
|
|
277
|
-
ref="numberField"
|
|
278
|
-
v-model="numberValue"
|
|
279
|
-
v-maska="numberMask"
|
|
280
|
-
:append-inner-icon="hasNumberErrors ? 'error' : (hasNumberSuccess ? 'success' : undefined)"
|
|
281
|
-
:aria-errormessage="hasNumberErrors ? 'number-field-errors' : undefined"
|
|
282
|
-
:aria-invalid="hasNumberErrors"
|
|
283
|
-
:aria-required="required"
|
|
284
|
-
:color="hasNumberErrors ? 'error' : 'primary'"
|
|
285
|
-
:error="hasNumberErrors"
|
|
286
|
-
:hint="locales.numberHint"
|
|
287
|
-
:label="numberLabel"
|
|
288
|
-
:variant="outlined ? 'outlined' : 'underlined'"
|
|
289
|
-
class="vd-number-field"
|
|
290
|
-
title="nirField"
|
|
291
|
-
@blur="validateFields(true)"
|
|
292
|
-
>
|
|
293
|
-
<template #details>
|
|
294
|
-
<span class="custom-counter">
|
|
295
|
-
{{ numberCounter }}
|
|
296
|
-
</span>
|
|
297
|
-
</template>
|
|
298
|
-
</SyTextField>
|
|
299
|
-
|
|
300
|
-
<template v-if="displayKey">
|
|
301
|
-
<SyTextField
|
|
302
|
-
ref="keyField"
|
|
303
|
-
v-model="keyValue"
|
|
304
|
-
v-maska="keyMask"
|
|
305
|
-
:append-inner-icon="hasKeyErrors ? 'error' : (hasKeySuccess ? 'success' : undefined)"
|
|
306
|
-
:aria-errormessage="hasKeyErrors ? 'key-field-errors' : undefined"
|
|
307
|
-
:aria-invalid="hasKeyErrors"
|
|
308
|
-
:aria-required="required"
|
|
309
|
-
:color="hasKeyErrors ? 'error' : 'primary'"
|
|
310
|
-
:error="hasKeyErrors"
|
|
311
|
-
:hint="locales.keyHint"
|
|
312
|
-
:label="keyLabel"
|
|
313
|
-
:variant="outlined ? 'outlined' : 'underlined'"
|
|
314
|
-
class="vd-key-field"
|
|
315
|
-
title="nirKeyField"
|
|
316
|
-
@blur="validateFields(true)"
|
|
317
|
-
>
|
|
318
|
-
<template #details>
|
|
319
|
-
<span class="custom-counter">
|
|
320
|
-
{{ keyCounter }}
|
|
321
|
-
</span>
|
|
322
|
-
</template>
|
|
323
|
-
</SyTextField>
|
|
324
|
-
|
|
325
|
-
<VTooltip v-if="keyTooltip">
|
|
326
|
-
<template #activator="{ props: iconProps }">
|
|
327
|
-
<VIcon
|
|
328
|
-
class="vd-tooltip-icon mt-4 ml-4"
|
|
329
|
-
v-bind="{ ...iconProps, ...options.icon }"
|
|
330
|
-
>
|
|
331
|
-
{{ infoIcon }}
|
|
332
|
-
</VIcon>
|
|
333
|
-
</template>
|
|
334
|
-
<slot name="keyTooltip">
|
|
335
|
-
{{ keyTooltip }}
|
|
336
|
-
</slot>
|
|
337
|
-
</VTooltip>
|
|
338
|
-
</template>
|
|
339
|
-
</v-input>
|
|
340
|
-
</div>
|
|
341
|
-
</template>
|
|
206
|
+
const defaultKeyRules = computed(() => {
|
|
207
|
+
const rules: ValidationRule[] = []
|
|
342
208
|
|
|
343
|
-
|
|
344
|
-
|
|
209
|
+
if (props.required) {
|
|
210
|
+
rules.push({
|
|
211
|
+
type: 'required',
|
|
212
|
+
options: {
|
|
213
|
+
message: `Le champ ${props.keyLabel} est requis.`,
|
|
214
|
+
fieldIdentifier: props.keyLabel,
|
|
215
|
+
},
|
|
216
|
+
})
|
|
217
|
+
}
|
|
345
218
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
219
|
+
const validateKey = (value: string) => {
|
|
220
|
+
if (!value) return true
|
|
221
|
+
if (!unmaskedNumberValue.value) return true
|
|
222
|
+
const fullNir = unmaskedNumberValue.value + value
|
|
223
|
+
return isNIRKeyValid(fullNir)
|
|
224
|
+
}
|
|
349
225
|
|
|
350
|
-
|
|
351
|
-
|
|
226
|
+
// Ajout des règles personnalisées
|
|
227
|
+
if (props.customKeyRules) {
|
|
228
|
+
rules.push(...props.customKeyRules)
|
|
229
|
+
}
|
|
352
230
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
231
|
+
// Ajout de la règle de validation par défaut si pas de règle personnalisée avec validation de clé
|
|
232
|
+
if (!props.customKeyRules?.some(rule => rule.options.validate)) {
|
|
233
|
+
rules.push({
|
|
234
|
+
type: 'custom',
|
|
235
|
+
options: {
|
|
236
|
+
validate: validateKey,
|
|
237
|
+
message: 'La clé du numéro de sécurité sociale est invalide.',
|
|
238
|
+
successMessage: `Le champ ${props.keyLabel} est valide.`,
|
|
239
|
+
fieldIdentifier: props.keyLabel,
|
|
240
|
+
},
|
|
241
|
+
})
|
|
242
|
+
}
|
|
357
243
|
|
|
358
|
-
|
|
359
|
-
|
|
244
|
+
return rules
|
|
245
|
+
})
|
|
360
246
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
247
|
+
// Synchronisation avec modelValue
|
|
248
|
+
watch(modelValueRef, (newValue) => {
|
|
249
|
+
if (newValue === undefined) {
|
|
250
|
+
numberValue.value = ''
|
|
251
|
+
keyValue.value = ''
|
|
252
|
+
return
|
|
253
|
+
}
|
|
254
|
+
if (newValue.length === 15) {
|
|
255
|
+
const number = newValue.slice(0, -2)
|
|
256
|
+
const key = newValue.slice(-2)
|
|
257
|
+
numberValue.value = number
|
|
258
|
+
keyValue.value = key
|
|
259
|
+
}
|
|
260
|
+
if (newValue.length === 14) {
|
|
261
|
+
const number = newValue.slice(0, -1)
|
|
262
|
+
const key = newValue.slice(-1)
|
|
263
|
+
numberValue.value = number
|
|
264
|
+
keyValue.value = key
|
|
265
|
+
}
|
|
266
|
+
if (newValue.length === 13) {
|
|
267
|
+
const number = newValue
|
|
268
|
+
numberValue.value = number
|
|
269
|
+
keyValue.value = ''
|
|
270
|
+
}
|
|
271
|
+
}, { immediate: true })
|
|
365
272
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
273
|
+
// Émission de la valeur
|
|
274
|
+
const emitValue = () => {
|
|
275
|
+
const number = unmaskedNumberValue.value
|
|
276
|
+
const key = unmaskedKeyValue.value
|
|
369
277
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
278
|
+
if (!number && !key) {
|
|
279
|
+
emit('update:modelValue', undefined)
|
|
280
|
+
return
|
|
281
|
+
}
|
|
373
282
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
283
|
+
emit('update:modelValue', `${number}${key}`)
|
|
284
|
+
}
|
|
377
285
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
286
|
+
// Validation des champs
|
|
287
|
+
const validateFields = async (onBlur = false) => {
|
|
288
|
+
// Valider le numéro
|
|
289
|
+
const numberResult = numberValidation.validateField(
|
|
290
|
+
unmaskedNumberValue.value,
|
|
291
|
+
defaultNumberRules.value,
|
|
292
|
+
// N'appliquer les warnings que si le numéro est complet
|
|
293
|
+
unmaskedNumberValue.value?.length === 13 ? props.customNumberWarningRules : [],
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
// Valider la clé si elle est affichée
|
|
297
|
+
let keyResult = { hasError: false }
|
|
298
|
+
if (props.displayKey) {
|
|
299
|
+
keyResult = keyValidation.validateField(
|
|
300
|
+
keyValue.value,
|
|
301
|
+
defaultKeyRules.value,
|
|
302
|
+
// N'appliquer les warnings que si la clé est complète
|
|
303
|
+
keyValue.value?.length === 2 ? props.customKeyWarningRules : [],
|
|
304
|
+
)
|
|
305
|
+
}
|
|
383
306
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
307
|
+
// Si on est en mode blur et qu'il y a des erreurs, focus sur le premier champ en erreur
|
|
308
|
+
if (onBlur) {
|
|
309
|
+
await nextTick()
|
|
310
|
+
if (numberResult.hasError) {
|
|
311
|
+
numberField.value?.$el.querySelector('input')?.focus()
|
|
312
|
+
}
|
|
313
|
+
else if (keyResult.hasError) {
|
|
314
|
+
keyField.value?.$el.querySelector('input')?.focus()
|
|
315
|
+
}
|
|
316
|
+
}
|
|
387
317
|
|
|
388
|
-
.
|
|
389
|
-
|
|
390
|
-
flex: none;
|
|
391
|
-
color: rgb(0 0 0 / 54%);
|
|
392
|
-
}
|
|
318
|
+
return !numberResult.hasError && !keyResult.hasError
|
|
319
|
+
}
|
|
393
320
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
}
|
|
321
|
+
const validateOnSubmit = () => {
|
|
322
|
+
return validateFields(true)
|
|
323
|
+
}
|
|
397
324
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
325
|
+
// Computed pour statut des champs
|
|
326
|
+
const hasNumberErrors = computed(() => numberValidation.hasError.value)
|
|
327
|
+
const hasNumberWarning = computed(() => !hasNumberErrors.value && numberValidation.hasWarning.value)
|
|
328
|
+
const hasNumberSuccess = computed(() => !hasNumberErrors.value && !hasNumberWarning.value && numberValidation.hasSuccess.value)
|
|
401
329
|
|
|
402
|
-
.
|
|
403
|
-
|
|
404
|
-
|
|
330
|
+
const hasKeyErrors = computed(() => keyValidation.hasError.value)
|
|
331
|
+
const hasKeyWarning = computed(() => !hasKeyErrors.value && keyValidation.hasWarning.value)
|
|
332
|
+
const hasKeySuccess = computed(() => !hasKeyErrors.value && !hasKeyWarning.value && keyValidation.hasSuccess.value)
|
|
405
333
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
334
|
+
// Labels avec astérisque si nécessaire
|
|
335
|
+
const numberLabelWithAsterisk = computed(() => {
|
|
336
|
+
return props.required && props.displayAsterisk ? `${props.numberLabel} *` : props.numberLabel
|
|
337
|
+
})
|
|
409
338
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
339
|
+
const keyLabelWithAsterisk = computed(() => {
|
|
340
|
+
return props.required && props.displayAsterisk ? `${props.keyLabel} *` : props.keyLabel
|
|
341
|
+
})
|
|
413
342
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
343
|
+
// Gestion des événements
|
|
344
|
+
const handleNumberInput = () => {
|
|
345
|
+
emitValue()
|
|
346
|
+
validateFields()
|
|
417
347
|
}
|
|
418
|
-
}
|
|
419
348
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
}
|
|
349
|
+
const handleKeyInput = () => {
|
|
350
|
+
emitValue()
|
|
351
|
+
validateFields()
|
|
424
352
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
353
|
+
// Si on supprime le contenu de la clé, on revient au champ NIR
|
|
354
|
+
if (unmaskedKeyValue.value.length === 0) {
|
|
355
|
+
nextTick(() => {
|
|
356
|
+
numberField.value?.$el.querySelector('input')?.focus()
|
|
357
|
+
})
|
|
358
|
+
}
|
|
359
|
+
}
|
|
428
360
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
flex-wrap: wrap;
|
|
433
|
-
gap: 4px;
|
|
434
|
-
margin-bottom: 4px;
|
|
361
|
+
const handleNumberBlur = () => {
|
|
362
|
+
validateFields(true)
|
|
363
|
+
}
|
|
435
364
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
}
|
|
365
|
+
const handleKeyBlur = () => {
|
|
366
|
+
validateFields(true)
|
|
439
367
|
}
|
|
440
|
-
}
|
|
441
368
|
|
|
442
|
-
|
|
443
|
-
|
|
369
|
+
defineExpose({
|
|
370
|
+
validateOnSubmit,
|
|
371
|
+
numberMask,
|
|
372
|
+
keyMask,
|
|
373
|
+
numberValidation,
|
|
374
|
+
keyValidation,
|
|
375
|
+
} satisfies {
|
|
376
|
+
validateOnSubmit: () => Promise<boolean>
|
|
377
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
|
|
378
|
+
numberMask: { mask: string, preProcess: (value: string) => string, tokens: Record<string, any> }
|
|
379
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
|
|
380
|
+
keyMask: { mask: string, tokens: Record<string, any> }
|
|
381
|
+
numberValidation: ReturnType<typeof useValidation>
|
|
382
|
+
keyValidation: ReturnType<typeof useValidation>
|
|
383
|
+
})
|
|
384
|
+
</script>
|
|
385
|
+
|
|
386
|
+
<template>
|
|
387
|
+
<div
|
|
388
|
+
class="nir-field"
|
|
389
|
+
>
|
|
390
|
+
<div class="number-field-container">
|
|
391
|
+
<SyTextField
|
|
392
|
+
ref="numberField"
|
|
393
|
+
v-model="numberValue"
|
|
394
|
+
v-maska="numberMask"
|
|
395
|
+
:label="numberLabelWithAsterisk"
|
|
396
|
+
:variant-style="outlined ? 'outlined' : 'underlined'"
|
|
397
|
+
:prepend-icon="nirTooltip && nirTooltipPosition === 'prepend' ? 'info' : undefined"
|
|
398
|
+
:append-icon="nirTooltip && nirTooltipPosition === 'append' ? 'info' : undefined"
|
|
399
|
+
:prepend-tooltip="nirTooltip && nirTooltipPosition === 'prepend' ? nirTooltip : undefined"
|
|
400
|
+
:append-tooltip="nirTooltip && nirTooltipPosition === 'append' ? nirTooltip : undefined"
|
|
401
|
+
:max-errors="2"
|
|
402
|
+
:error-messages="[...numberValidation.errors.value, ...keyValidation.errors.value]"
|
|
403
|
+
:warning-messages="numberValidation.warnings.value"
|
|
404
|
+
:success-messages="numberValidation.successes.value"
|
|
405
|
+
:show-success-messages="showSuccessMessages"
|
|
406
|
+
:has-warning="hasNumberWarning"
|
|
407
|
+
:has-success="hasNumberSuccess"
|
|
408
|
+
:error="hasNumberErrors"
|
|
409
|
+
:messages="hasNumberErrors ? numberValidation.errors.value : (hasNumberWarning ? numberValidation.warnings.value : (hasNumberSuccess ? numberValidation.successes.value : []))"
|
|
410
|
+
:has-error="hasNumberErrors"
|
|
411
|
+
:required="required"
|
|
412
|
+
:is-disabled="isDisabled"
|
|
413
|
+
:bg-color="bgColor"
|
|
414
|
+
:density="props.density"
|
|
415
|
+
:hide-details="props.hideDetails"
|
|
416
|
+
:hide-spin-buttons="props.hideSpinButtons"
|
|
417
|
+
:placeholder="props.placeholder"
|
|
418
|
+
:readonly="props.readonly"
|
|
419
|
+
:variant="props.variant"
|
|
420
|
+
:clearable="props.clearable"
|
|
421
|
+
:counter="props.counter"
|
|
422
|
+
:persistent-hint="props.persistentHint"
|
|
423
|
+
:persistent-placeholder="props.persistentPlaceholder"
|
|
424
|
+
:hint="props.hint || locales.numberHint"
|
|
425
|
+
class="number-field"
|
|
426
|
+
:display-asterisk="false"
|
|
427
|
+
@input="handleNumberInput"
|
|
428
|
+
@blur="handleNumberBlur"
|
|
429
|
+
/>
|
|
430
|
+
</div>
|
|
431
|
+
<div
|
|
432
|
+
v-if="displayKey"
|
|
433
|
+
class="key-field-container"
|
|
434
|
+
>
|
|
435
|
+
<SyTextField
|
|
436
|
+
ref="keyField"
|
|
437
|
+
v-model="keyValue"
|
|
438
|
+
v-maska="keyMask"
|
|
439
|
+
:label="keyLabelWithAsterisk"
|
|
440
|
+
:variant-style="outlined ? 'outlined' : 'underlined'"
|
|
441
|
+
:prepend-icon="keyTooltip && keyTooltipPosition === 'prepend' ? 'info' : undefined"
|
|
442
|
+
:append-icon="keyTooltip && keyTooltipPosition === 'append' ? 'info' : undefined"
|
|
443
|
+
:prepend-tooltip="keyTooltip && keyTooltipPosition === 'prepend' ? keyTooltip : undefined"
|
|
444
|
+
:append-tooltip="keyTooltip && keyTooltipPosition === 'append' ? keyTooltip : undefined"
|
|
445
|
+
:error-messages="keyValidation.errors.value.length > 0 ? [''] : []"
|
|
446
|
+
:warning-messages="keyValidation.warnings.value"
|
|
447
|
+
:success-messages="keyValidation.successes.value"
|
|
448
|
+
:show-success-messages="showSuccessMessages"
|
|
449
|
+
:has-warning="hasKeyWarning"
|
|
450
|
+
:has-success="hasKeySuccess"
|
|
451
|
+
:hint="props.hint || locales.keyHint"
|
|
452
|
+
:messages="hasKeyErrors ? keyValidation.errors.value : (hasKeyWarning ? keyValidation.warnings.value : (hasKeySuccess ? keyValidation.successes.value : []))"
|
|
453
|
+
:has-error="hasKeyErrors"
|
|
454
|
+
:is-disabled="isDisabled"
|
|
455
|
+
:bg-color="bgColor"
|
|
456
|
+
:density="props.density"
|
|
457
|
+
:hide-details="props.hideDetails"
|
|
458
|
+
:hide-spin-buttons="props.hideSpinButtons"
|
|
459
|
+
:placeholder="props.placeholder"
|
|
460
|
+
:readonly="props.readonly"
|
|
461
|
+
:variant="props.variant"
|
|
462
|
+
:clearable="props.clearable"
|
|
463
|
+
:counter="props.counter"
|
|
464
|
+
:persistent-hint="props.persistentHint"
|
|
465
|
+
:persistent-placeholder="props.persistentPlaceholder"
|
|
466
|
+
class="key-field"
|
|
467
|
+
:display-asterisk="false"
|
|
468
|
+
@input="handleKeyInput"
|
|
469
|
+
@blur="handleKeyBlur"
|
|
470
|
+
/>
|
|
471
|
+
</div>
|
|
472
|
+
</div>
|
|
473
|
+
</template>
|
|
474
|
+
|
|
475
|
+
<style lang="scss" scoped>
|
|
476
|
+
.nir-field {
|
|
477
|
+
display: flex;
|
|
478
|
+
gap: 16px;
|
|
479
|
+
width: v-bind('props.width');
|
|
480
|
+
align-items: flex-start;
|
|
444
481
|
}
|
|
445
482
|
|
|
446
|
-
|
|
447
|
-
|
|
483
|
+
.number-field-container {
|
|
484
|
+
flex: 0 0 80%;
|
|
448
485
|
}
|
|
449
486
|
|
|
450
|
-
.
|
|
451
|
-
|
|
487
|
+
.key-field-container {
|
|
488
|
+
flex: 0 0 20%;
|
|
452
489
|
}
|
|
453
490
|
|
|
454
|
-
|
|
455
|
-
|
|
491
|
+
.number-field,
|
|
492
|
+
.key-field {
|
|
493
|
+
width: 100%;
|
|
456
494
|
}
|
|
457
495
|
</style>
|