plugin-ui-for-kzt 0.0.9 → 0.0.11

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 (128) hide show
  1. package/dist/example/App.vue.d.ts +46 -0
  2. package/dist/example/main.d.ts +1 -0
  3. package/dist/index.js +57224 -3923
  4. package/dist/index.js.map +1 -0
  5. package/dist/sprite.svg +4 -0
  6. package/dist/src/components/BaseBreadCrumbs/BaseBreadCrumbs.vue.d.ts +34 -0
  7. package/dist/src/components/BaseButton/BaseButton.vue.d.ts +189 -0
  8. package/dist/src/components/BaseCalendar/BaseCalendar.vue.d.ts +176 -0
  9. package/dist/src/components/BaseCheckbox/BaseCheckbox.vue.d.ts +174 -0
  10. package/dist/src/components/BaseDropdown/BaseDropdown.vue.d.ts +151 -0
  11. package/dist/src/components/BaseIcon/BaseIcon.vue.d.ts +29 -0
  12. package/dist/src/components/BaseInputCalendar/BaseInputCalendar.vue.d.ts +202 -0
  13. package/dist/src/components/BaseInputEmail/BaseInputEmail.vue.d.ts +176 -0
  14. package/dist/src/components/BaseInputPhone/BaseInputPhone.vue.d.ts +251 -0
  15. package/dist/src/components/BaseLoader/BaseLoader.vue.d.ts +4 -0
  16. package/dist/src/components/BaseOpenedListItem/BaseOpenedListItem.vue.d.ts +148 -0
  17. package/dist/src/components/BaseRadio/BaseRadio.vue.d.ts +173 -0
  18. package/dist/src/components/BaseSegmentedButtons/BaseSegmentedButtons.vue.d.ts +142 -0
  19. package/dist/src/components/BaseSelect/BaseSelect.vue.d.ts +265 -0
  20. package/dist/src/components/BaseSiteInput/BaseSiteInput.vue.d.ts +119 -0
  21. package/dist/src/components/BaseTextarea/BaseTextarea.vue.d.ts +195 -0
  22. package/dist/src/components/BaseToggle/BaseToggle.vue.d.ts +166 -0
  23. package/dist/src/components/BaseTooltip/BaseTooltip.vue.d.ts +76 -0
  24. package/dist/src/components/DataTable/DataTable.vue.d.ts +42 -0
  25. package/dist/src/components/Modal/Modal.vue.d.ts +36 -0
  26. package/dist/src/components/Spinner/Spinner.vue.d.ts +46 -0
  27. package/dist/src/components/Toaster/Toaster.vue.d.ts +117 -0
  28. package/dist/src/components/Tooltip/Tooltip.vue.d.ts +43 -0
  29. package/dist/src/composables/kit/color.d.ts +6 -0
  30. package/dist/src/composables/kit/interactive.d.ts +7 -0
  31. package/dist/src/composables/kit/size.d.ts +6 -0
  32. package/dist/src/composables/kit/state.d.ts +17 -0
  33. package/dist/src/composables/kit/style.d.ts +8 -0
  34. package/dist/src/composables/kit/utils.d.ts +1 -0
  35. package/dist/src/icons/index.d.ts +4 -0
  36. package/dist/src/index.d.ts +33 -0
  37. package/example/App.vue +355 -0
  38. package/example/index.html +12 -0
  39. package/example/main.ts +8 -0
  40. package/example/shims-vue.d.ts +5 -0
  41. package/package.json +17 -7
  42. package/src/assets/icons/arrow-down.svg +3 -0
  43. package/src/assets/icons/calendar.svg +12 -0
  44. package/src/assets/icons/checkbox-circle.svg +3 -0
  45. package/src/assets/icons/checkbox.svg +3 -0
  46. package/src/assets/icons/email-sms.svg +4 -0
  47. package/src/assets/icons/help.svg +3 -0
  48. package/src/assets/icons/kg.svg +16 -0
  49. package/src/assets/icons/kz.svg +42 -0
  50. package/src/assets/icons/loader.svg +13 -0
  51. package/src/assets/icons/ru.svg +12 -0
  52. package/src/assets/icons/uz.svg +26 -0
  53. package/src/components/BaseBreadCrumbs/BaseBreadCrumbs.vue +142 -0
  54. package/src/components/BaseBreadCrumbs/README.md +49 -0
  55. package/src/components/BaseButton/BaseButton.vue +489 -0
  56. package/src/components/BaseButton/README.md +53 -0
  57. package/src/components/BaseCalendar/BaseCalendar.vue +231 -0
  58. package/src/components/BaseCalendar/README.md +126 -0
  59. package/src/components/BaseCheckbox/BaseCheckbox.vue +252 -0
  60. package/src/components/BaseCheckbox/README.md +110 -0
  61. package/src/components/BaseDropdown/BaseDropdown.vue +160 -0
  62. package/src/components/BaseDropdown/README.md +91 -0
  63. package/src/components/BaseIcon/BaseIcon.vue +47 -0
  64. package/src/components/BaseIcon/README.md +35 -0
  65. package/src/components/BaseInput/BaseInput.vue +300 -0
  66. package/src/components/BaseInput/README.md +85 -0
  67. package/src/components/BaseInputCalendar/BaseInputCalendar.vue +242 -0
  68. package/src/components/BaseInputCalendar/README.md +84 -0
  69. package/src/components/BaseInputCurrency/BaseInputCurrency.vue +198 -0
  70. package/src/components/BaseInputCurrency/README.md +57 -0
  71. package/src/components/BaseInputEmail/BaseInputEmail.vue +89 -0
  72. package/src/components/BaseInputEmail/README.md +71 -0
  73. package/src/components/BaseInputPhone/BaseInputPhone.vue +175 -0
  74. package/src/components/BaseLoader/BaseLoader.vue +45 -0
  75. package/src/components/BaseLoader/README.md +29 -0
  76. package/src/components/BaseOpenedListItem/BaseOpenedListItem.vue +216 -0
  77. package/src/components/BaseOpenedListItem/README.md +67 -0
  78. package/src/components/BaseRadio/BaseRadio.vue +283 -0
  79. package/src/components/BaseRadio/README.md +74 -0
  80. package/src/components/BaseSegmentedButtons/BaseSegmentedButtons.vue +89 -0
  81. package/src/components/BaseSegmentedButtons/README.md +75 -0
  82. package/src/components/BaseSelect/BaseSelect.vue +370 -0
  83. package/src/components/BaseSelect/README.md +95 -0
  84. package/src/components/BaseSiteInput/BaseSiteInput.vue +153 -0
  85. package/src/components/BaseTextarea/BaseTextarea.vue +212 -0
  86. package/src/components/BaseTextarea/README.md +75 -0
  87. package/src/components/BaseToggle/BaseToggle.vue +271 -0
  88. package/src/components/BaseToggle/README.md +76 -0
  89. package/src/components/BaseTooltip/BaseTooltip.vue +318 -0
  90. package/src/components/BaseTooltip/README.md +74 -0
  91. package/src/components/Modal/Modal.vue +3 -1
  92. package/src/components/Spinner/Spinner.vue +2 -1
  93. package/src/composables/kit/color.ts +14 -0
  94. package/src/composables/kit/interactive.ts +53 -0
  95. package/src/composables/kit/size.ts +15 -0
  96. package/src/composables/kit/state.ts +28 -0
  97. package/src/composables/kit/style.ts +18 -0
  98. package/src/composables/kit/utils.ts +7 -0
  99. package/src/icons/index.ts +9 -0
  100. package/src/index.ts +93 -2
  101. package/src/shims-context.d.ts +19 -0
  102. package/src/styles/index.scss +2 -1
  103. package/src/styles/root.scss +167 -0
  104. package/src/styles/variables.scss +160 -0
  105. package/src/types/breadcrumbs.d.ts +13 -0
  106. package/src/types/button.d.ts +13 -0
  107. package/src/types/calendar.d.ts +16 -0
  108. package/src/types/checkbox-radio.d.ts +15 -0
  109. package/src/types/dropdown.d.ts +20 -0
  110. package/src/types/icon.d.ts +8 -0
  111. package/src/types/input.d.ts +56 -0
  112. package/src/types/toggle.d.ts +12 -0
  113. package/src/types/tooltip.d.ts +8 -0
  114. package/src/types/utils.d.ts +37 -0
  115. package/src/vue-virtual-scroller.d.ts +9 -0
  116. package/tsconfig.json +3 -1
  117. package/webpack.config.js +90 -35
  118. package/dist/components/DataTable/DataTable.vue.d.ts +0 -3
  119. package/dist/components/Modal/Modal.vue.d.ts +0 -3
  120. package/dist/components/Spinner/Spinner.vue.d.ts +0 -3
  121. package/dist/components/Toaster/Toaster.vue.d.ts +0 -3
  122. package/dist/components/Tooltip/Tooltip.vue.d.ts +0 -3
  123. package/dist/index.d.ts +0 -11
  124. /package/dist/{components → src/components}/Toaster/timer.d.ts +0 -0
  125. /package/dist/{plugins → src/plugins}/modalPlugin.d.ts +0 -0
  126. /package/dist/{plugins → src/plugins}/toasterPlugin.d.ts +0 -0
  127. /package/dist/{store → src/store}/modal.d.ts +0 -0
  128. /package/dist/{types → src/types}/index.d.ts +0 -0
@@ -0,0 +1,84 @@
1
+ ### BaseInputCalendar
2
+
3
+ Компонент для ввода даты (или диапазона дат) с возможностью выбора даты через календарь. Поддерживает валидацию формата даты и отображение ошибок.
4
+
5
+ ---
6
+
7
+ #### Props
8
+
9
+ - `modelValue: string`
10
+ Значение поля ввода даты. Используется для двусторонней привязки данных.
11
+
12
+ - `size: 'small' | 'medium' | 'large'`
13
+ Размер компонента. Определяет размеры иконок и поля ввода. По умолчанию — `medium`.
14
+
15
+ - `placeholder: string`
16
+ Текст-заполнитель для поля ввода. По умолчанию пустое значение.
17
+
18
+ - `error: string | boolean`
19
+ Ошибка, которая будет отображаться под полем ввода. Может быть строкой с сообщением об ошибке или булевым значением, где `true` указывает на наличие ошибки.
20
+
21
+ - `hint: string`
22
+ Подсказка, отображаемая под полем ввода.
23
+
24
+ - `range: boolean`
25
+ Определяет, будет ли выбран диапазон дат (если `true`) или одиночная дата (если `false`). По умолчанию — `false`.
26
+
27
+ - `minDate: Date | null`
28
+ Минимальная дата, которая может быть выбрана. Если не указано, ограничения на дату отсутствуют.
29
+
30
+ ---
31
+
32
+ #### Важные особенности
33
+
34
+ - **Календарь:**
35
+ Компонент использует `BaseCalendar` для выбора даты. При выборе даты из календаря автоматически обновляется значение поля ввода.
36
+
37
+ - **Иконка слева:**
38
+ В поле ввода отображается иконка календаря с помощью компонента `BaseIcon`, что визуально подсказывает пользователю, что это поле для ввода даты.
39
+
40
+ - **Валидация:**
41
+ Реализована валидация формата даты по шаблону `dd.MM.yyyy`. Если поле ввода не соответствует этому формату, будет отображаться ошибка, например: "Некорректный формат. Используйте dd.MM.yyyy".
42
+
43
+ - **Диапазон дат:**
44
+ Если свойство `range` установлено в `true`, компонент позволяет вводить диапазон дат в формате `dd.MM.yyyy - dd.MM.yyyy`. Для этого также выполняется соответствующая валидация.
45
+
46
+ - **Двусторонняя привязка:**
47
+ Компонент использует `v-model` для двусторонней привязки значения даты/диапазона дат и обновления его в родительском компоненте.
48
+
49
+ - **Форматирование даты:**
50
+ При изменении значения поля ввода, введенная дата форматируется в строку в виде `dd.MM.yyyy`. Если это диапазон дат, то форматируется в виде `dd.MM.yyyy - dd.MM.yyyy`.
51
+
52
+ ---
53
+
54
+ #### Пример использования
55
+
56
+ ```vue
57
+ <BaseInputCalendar
58
+ v-model="selectedDate"
59
+ placeholder="Выберите дату"
60
+ :range="true"
61
+ error="Некорректный формат даты"
62
+ :minDate="new Date('2023-01-01')"
63
+ />
64
+ ```
65
+
66
+ ---
67
+
68
+ #### Логика валидации
69
+
70
+ - Для одиночной даты используется регулярное выражение, которое проверяет формат `dd.MM.yyyy`.
71
+ - Для диапазона дат используется регулярное выражение, проверяющее формат `dd.MM.yyyy - dd.MM.yyyy`.
72
+ - Если формат некорректен, будет отображено сообщение об ошибке: "Некорректный формат. Используйте dd.MM.yyyy".
73
+ - Если дата не существует (например, 31.02.2023), также будет показана ошибка: "Некорректная дата".
74
+
75
+ ---
76
+
77
+ #### Стилизация
78
+
79
+ - Компонент использует стандартные стили для поля ввода и иконки календаря.
80
+ - В случае выбора диапазона дат или одиночной даты, данные обновляются в поле ввода и отображаются в формате, соответствующем локализации.
81
+
82
+ ---
83
+
84
+ Этот компонент идеально подходит для форм, где требуется ввод даты или диапазона дат, с возможностью выбора даты через календарь и поддержкой валидации ввода.
@@ -0,0 +1,198 @@
1
+ <template>
2
+ <div :class="classList">
3
+ <div class="base-input-currency__wrapper">
4
+ <div class="base-input-currency__input-container">
5
+ <span class="base-input-currency__symbol">{{ selectedOption.symbol }}</span>
6
+ <base-input
7
+ id="input-currency"
8
+ type="text"
9
+ :modelValue="modelValue"
10
+ v-bind="componentAttrs"
11
+ v-maska
12
+ :data-maska="selectedOption.mask"
13
+ :size="size"
14
+ :placeholder="placeholder || '0.00'"
15
+ class="base-input-currency__input"
16
+ @update:modelValue="handleInput"
17
+ ></base-input>
18
+ </div>
19
+ <base-select
20
+ id="select-currency"
21
+ v-model="selectedOptionId"
22
+ :options="optionsCurrency"
23
+ :size="size"
24
+ :error="error"
25
+ class="base-input-currency__select"
26
+ >
27
+ </base-select>
28
+ </div>
29
+ </div>
30
+ </template>
31
+
32
+ <script setup lang="ts">
33
+ import { computed, useAttrs, ref, watch } from 'vue';
34
+ import { vMaska } from 'maska/vue';
35
+ import BaseInput from '../BaseInput/BaseInput.vue';
36
+ import BaseSelect from '../BaseSelect/BaseSelect.vue';
37
+ import { useKitState } from '../../composables/kit/state';
38
+ import { useKitSize } from '../../composables/kit/size';
39
+ import type { ICoreInputProps } from '../../types/input';
40
+
41
+ const props = withDefaults(defineProps<ICoreInputProps>(), {
42
+ size: 'medium',
43
+ type: 'text',
44
+ modelValue: '',
45
+ placeholder: '0.00',
46
+ error: '',
47
+ hint: '',
48
+ });
49
+
50
+ const emit: (event: 'update:modelValue', value: string) => void = defineEmits();
51
+
52
+ const optionsCurrency = ref([
53
+ { id: '1', name: 'KZT', value: 'kzt', mask: '# ##0.##', symbol: '₸' },
54
+ { id: '2', name: 'RUB', value: 'rub', mask: '# ##0.##', symbol: '₽' },
55
+ { id: '3', name: 'KGS', value: 'kgs', mask: '# ##0.##', symbol: '⃀' },
56
+ { id: '4', name: 'UZS', value: 'uzs', mask: '# ##0.##', symbol: 'сў' },
57
+ ]);
58
+
59
+ const selectedOption = ref(optionsCurrency.value[0]);
60
+
61
+ const selectedOptionId = ref(selectedOption.value.id);
62
+
63
+ watch(selectedOptionId, (newId) => {
64
+ const newOption = optionsCurrency.value.find((option) => option.id === newId);
65
+ if (newOption) {
66
+ selectedOption.value = newOption;
67
+ }
68
+ });
69
+
70
+ const { stateClassList, stateAttrs } = useKitState(props);
71
+ const { sizeClassList } = useKitSize(props);
72
+ const attrs = useAttrs();
73
+
74
+ const componentAttrs = computed(() => ({
75
+ ...attrs,
76
+ ...stateAttrs.value,
77
+ label: props.label,
78
+ error: props.error,
79
+ hint: props.hint,
80
+ placeholder: props.placeholder,
81
+ }));
82
+
83
+ const classList = computed(() => [
84
+ stateClassList.value,
85
+ sizeClassList.value,
86
+ 'base-input-currency',
87
+ ]);
88
+
89
+ const modelValue = computed({
90
+ get: () => props.modelValue,
91
+ set: (value) => emit('update:modelValue', value),
92
+ });
93
+
94
+ const handleInput = (value: string) => {
95
+ emit('update:modelValue', value);
96
+ };
97
+ </script>
98
+
99
+ <style lang="scss" scoped>
100
+ .base-input-currency {
101
+ $input: &;
102
+
103
+ display: flex;
104
+ align-items: center;
105
+ width: 100%;
106
+
107
+ &__wrapper {
108
+ position: relative;
109
+ display: flex;
110
+ align-items: center;
111
+ width: 100%;
112
+ }
113
+
114
+ &__input-container {
115
+ display: flex;
116
+ align-items: center;
117
+ }
118
+
119
+ &__symbol {
120
+ position: absolute;
121
+ top: 50%;
122
+ left: 12px;
123
+ transform: translateY(-50%);
124
+ z-index: 1;
125
+ font-size: var(--typography-text-m-regular);
126
+ color: var(--primary-text-tertiary);
127
+ }
128
+
129
+ &__input {
130
+ flex-grow: 1;
131
+
132
+ :deep(.base-input__field) {
133
+ border-top-right-radius: 0 !important;
134
+ border-bottom-right-radius: 0 !important;
135
+ border-right: none;
136
+ }
137
+ }
138
+
139
+ &__select {
140
+ min-width: unset;
141
+
142
+ :deep(.base-select__header) {
143
+ border-top-left-radius: 0;
144
+ border-bottom-left-radius: 0;
145
+ border-left: none;
146
+ }
147
+
148
+ :deep(.base-select__hint) {
149
+ display: none;
150
+ }
151
+ }
152
+
153
+ &.--small-size {
154
+ #{$input} {
155
+ :deep(.base-select) {
156
+ width: 71px;
157
+ }
158
+ &__symbol {
159
+ font-size: var(--typography-text-s-regular);
160
+ }
161
+ }
162
+
163
+ :deep(.base-input__field) {
164
+ padding-left: 30px;
165
+ }
166
+ }
167
+
168
+ &.--medium-size {
169
+ #{$input} {
170
+ :deep(.base-select) {
171
+ width: 75px;
172
+ }
173
+ &__symbol {
174
+ font-size: var(--typography-text-m-regular);
175
+ }
176
+ }
177
+
178
+ :deep(.base-input__field) {
179
+ padding-left: 30px;
180
+ }
181
+ }
182
+
183
+ &.--large-size {
184
+ #{$input} {
185
+ :deep(.base-select) {
186
+ width: 87px;
187
+ }
188
+ &__symbol {
189
+ font-size: var(--typography-text-l-regular);
190
+ }
191
+ }
192
+
193
+ :deep(.base-input__field) {
194
+ padding-left: 30px;
195
+ }
196
+ }
197
+ }
198
+ </style>
@@ -0,0 +1,57 @@
1
+ # BaseInputCurrency
2
+
3
+ Vue-компонент для ввода денежных сумм с выбором валюты. Включает поле ввода с маской форматирования чисел и выпадающий список для выбора валюты. Символ валюты отображается как текст слева от поля ввода.
4
+
5
+ ## Пропсы
6
+
7
+ | Проп | Тип | По умолчанию | Описание |
8
+ |---------------|---------------------|--------------|-----------------------------------------------------------------------------|
9
+ | `modelValue` | `string` | `''` | Значение поля ввода, поддерживает двустороннюю привязку через `v-model`. |
10
+ | `size` | `'small' \| 'medium' \| 'large'` | `'medium'` | Размер компонента, влияет на размеры поля и списка. |
11
+ | `type` | `string` | `'text'` | Тип поля ввода, для валюты используйте `'text'`. |
12
+ | `placeholder` | `string` | `'0.00'` | Текст-заполнитель для поля ввода. |
13
+ | `error` | `string \| boolean` | `''` | Сообщение об ошибке или булево значение для отображения ошибки под полем. |
14
+ | `hint` | `string` | `''` | Подсказка, отображаемая под полем, если нет ошибки. |
15
+
16
+ ## Особенности
17
+
18
+ - **Символ валюты**: Текстовый символ (₸, ₽, лв, сў) отображается слева от поля ввода, обновляется при выборе валюты.
19
+ - **Выбор валюты**: Выпадающий список (`<base-select>`) справа для выбора валют (KZT, RUB, KGS, UZS) с иконками.
20
+ - **Маска ввода**: Использует `maska` для форматирования чисел (например, `1234567.89` → `1 234 567.89`).
21
+ - **Размеры**: Поддерживает `small`, `medium`, `large` с адаптивными стилями.
22
+ - **Состояния**: Ошибка, фокус и отключение стилизуются через CSS-классы.
23
+
24
+ ## Использование
25
+
26
+ ```vue
27
+ <template>
28
+ <base-input-currency
29
+ id="currency"
30
+ v-model="amount"
31
+ size="medium"
32
+ label="Сумма"
33
+ placeholder="0.00"
34
+ :error="errorMessage"
35
+ hint="Введите сумму в выбранной валюте"
36
+ />
37
+ </template>
38
+
39
+ <script setup lang="ts">
40
+ import { ref } from 'vue';
41
+
42
+ const amount = ref('');
43
+ const errorMessage = ref('');
44
+ </script>
45
+ ```
46
+
47
+ ## Зависимости
48
+
49
+ - **`maska`**: Для форматирования ввода.
50
+ - **Компоненты**: `<base-input>`, `<base-select>`, `<base-icon>`.
51
+ - **Компосаблы**: `useKitState`, `useKitSize`.
52
+
53
+ ## Примечания
54
+
55
+ - Поле ввода стыкуется с выпадающим списком: левая часть без правой границы, правая — без левой.
56
+ - Символ валюты позиционируется абсолютно внутри поля ввода для экономии пространства.
57
+ - Поддерживает состояния ошибки и фокуса через стили и пропсы.
@@ -0,0 +1,89 @@
1
+ <template>
2
+ <div class="base-input-email">
3
+ <div class="base-input-email__wrapper">
4
+ <base-input
5
+ v-bind="{...$props, ...$attrs}"
6
+ v-model="modelValue"
7
+ type="email"
8
+ :error="emailError || props.error"
9
+ @update:modelValue="onUpdateModelValue"
10
+ >
11
+ <template #left-icon>
12
+ <base-icon
13
+ name="email-sms"
14
+ :size="size"
15
+ />
16
+ </template>
17
+
18
+ <template #right-icon>
19
+ <div v-if="tooltipOptions?.title" class="base-input-email__tooltip-container">
20
+ <base-tooltip
21
+ :title="tooltipOptions.title"
22
+ :content="tooltipOptions.content"
23
+ :theme="tooltipOptions.theme"
24
+ :trigger="tooltipOptions.trigger"
25
+ :position="tooltipOptions.position"
26
+ >
27
+ <template #trigger>
28
+ <slot name="right-icon" />
29
+ </template>
30
+ </base-tooltip>
31
+ </div>
32
+ </template>
33
+ </base-input>
34
+ </div>
35
+ </div>
36
+ </template>
37
+
38
+ <script setup lang="ts">
39
+ import { computed, ref, watch } from 'vue';
40
+ import BaseInput from '../BaseInput/BaseInput.vue';
41
+ import BaseTooltip from '../BaseTooltip/BaseTooltip.vue';
42
+ import BaseIcon from '../BaseIcon/BaseIcon.vue';
43
+ import type { ICoreInputProps } from '../../types/input';
44
+
45
+ const props = withDefaults(defineProps<ICoreInputProps>(), {
46
+ size: 'medium',
47
+ type: 'email',
48
+ modelValue: '',
49
+ placeholder: '' as string,
50
+ error: '',
51
+ hint: '',
52
+ });
53
+
54
+ const emit = defineEmits<{
55
+ (event: 'update:modelValue', value: string): void;
56
+ }>();
57
+
58
+ const modelValue = computed({
59
+ get: () => props.modelValue,
60
+ set: value => emit('update:modelValue', value),
61
+ });
62
+
63
+ function onUpdateModelValue(value: string) {
64
+ emit('update:modelValue', value);
65
+ }
66
+
67
+ const emailError = ref('');
68
+
69
+ watch(modelValue, (value) => {
70
+ if (!/^[\w\-.]+@(?:[\w\-]+\.)+[\w\-]{2,4}$/.test(String(value))) {
71
+ emailError.value = props.validationText || 'Некорректный email';
72
+ } else {
73
+ emailError.value = '';
74
+ }
75
+ });
76
+ </script>
77
+
78
+ <style scoped lang="scss">
79
+ .base-input-email {
80
+ width: max-content;
81
+
82
+ &__tooltip-container {
83
+ position: relative;
84
+ display: flex;
85
+ align-items: center;
86
+ justify-content: center;
87
+ }
88
+ }
89
+ </style>
@@ -0,0 +1,71 @@
1
+ ### BaseInputEmail
2
+
3
+ Компонент для ввода email с валидацией и иконками, представляющими визуальную подсказку и дополнительную информацию.
4
+
5
+ ---
6
+
7
+ #### Props
8
+
9
+ - `modelValue: string`
10
+ Значение поля ввода email. Двусторонняя привязка, обновляется при изменении значения.
11
+
12
+ - `size: 'small' | 'medium' | 'large'`
13
+ Размер компонента. Определяет размеры иконок и поля ввода. По умолчанию — `medium`.
14
+
15
+ - `placeholder: string`
16
+ Текст-заполнитель для поля ввода. По умолчанию пустое значение.
17
+
18
+ - `error: string | boolean`
19
+ Ошибка, которая будет отображаться под полем ввода. Может быть строкой с сообщением об ошибке или булевым значением, где `true` указывает на наличие ошибки. По умолчанию — пустое значение.
20
+
21
+ - `hint: string`
22
+ Подсказка, отображаемая под полем ввода.
23
+
24
+ ---
25
+
26
+ #### Важные особенности
27
+
28
+ - **Иконка слева:**
29
+ В поле ввода по умолчанию отображается иконка `email`, предоставляемая компонентом `BaseIcon`, которая будет визуально отображать цель поля ввода.
30
+
31
+ - **Иконка справа:**
32
+ С правой стороны поля ввода отображается иконка помощи (`help`), на которую можно навести курсор, чтобы открыть подсказку в виде тултипа. Тултип использует компонент `BaseTooltip` для отображения дополнительной информации при наведении.
33
+
34
+ - **Валидация email:**
35
+ В компоненте реализована базовая валидация email. Если введенный текст не соответствует формату email, то отображается ошибка "Некорректный email". Если поле пустое, показывается ошибка "Введите email".
36
+
37
+ - **Двусторонняя привязка:**
38
+ Компонент использует `v-model` для двусторонней привязки значения email и обновления его в родительском компоненте.
39
+
40
+ ---
41
+
42
+ #### Пример использования
43
+
44
+ ```vue
45
+ <BaseInputEmail
46
+ v-model="email"
47
+ placeholder="Введите ваш email"
48
+ :error="emailError"
49
+ size="large"
50
+ hint="Мы никогда не передадим ваш email третьим лицам."
51
+ />
52
+ ```
53
+
54
+ ---
55
+
56
+ #### Логика валидации
57
+
58
+ - Если значение поля пустое, в переменную `emailError` записывается сообщение "Введите email".
59
+ - Если введенный текст не соответствует регулярному выражению для email, показывается ошибка "Некорректный email".
60
+ - Если валидация проходит, ошибка очищается.
61
+
62
+ ---
63
+
64
+ #### Стилизация
65
+
66
+ - Поле ввода использует стандартные стили компонента `BaseInput`, включая стили для иконок и ошибок.
67
+ - Стили для тултипа контейнера и для самой иконки добавляют интерактивности и четкости в отображении ошибок и подсказок.
68
+
69
+ ---
70
+
71
+ Этот компонент идеально подходит для реализации форм, где требуется ввод email, с интерактивными и визуально понятными подсказками для пользователя.
@@ -0,0 +1,175 @@
1
+ <template>
2
+ <div :class="classList">
3
+ <div class="base-input-phone__wrapper">
4
+ <base-select
5
+ id="select-phone"
6
+ v-model="selectedOptionId"
7
+ :options="optionsPhone"
8
+ :size="size"
9
+ :error="error"
10
+ class="base-input-phone__select"
11
+ >
12
+ <template #iconItem="{ item }">
13
+ <base-icon
14
+ :name="item.icon"
15
+ :size="size"
16
+ />
17
+ </template>
18
+ </base-select>
19
+ <base-input
20
+ id="input-phone"
21
+ type="tel"
22
+ :modelValue="modelValue"
23
+ v-bind="componentAttrs"
24
+ :mask="selectedOption.mask"
25
+ :size="size"
26
+ :placeholder="placeholder || ''"
27
+ class="base-input-phone__input"
28
+ @update:modelValue="handleInput"
29
+ ></base-input>
30
+ </div>
31
+ </div>
32
+ </template>
33
+
34
+ <script setup lang="ts">
35
+ import { computed, useAttrs, ref, watch } from 'vue';
36
+ import BaseInput from '../BaseInput/BaseInput.vue';
37
+ import BaseSelect from '../BaseSelect/BaseSelect.vue';
38
+ import { useKitState } from '../../composables/kit/state';
39
+ import { useKitSize } from '../../composables/kit/size';
40
+ import type { ICoreInputProps } from '../../types/input';
41
+
42
+ const props = withDefaults(defineProps<ICoreInputProps>(), {
43
+ size: 'medium',
44
+ type: 'text',
45
+ modelValue: '',
46
+ placeholder: '' as string,
47
+ error: '',
48
+ hint: '',
49
+ });
50
+
51
+ const emit: (event: 'update:modelValue', value: string) => void = defineEmits();
52
+
53
+ const optionsPhone = ref([
54
+ { id: '1', name: 'KZ', value: 'kz', mask: '+7 (###) ###-##-##', icon: 'kz' },
55
+ { id: '2', name: 'RU', value: 'ru', mask: '+7 (###) ###-##-##', icon: 'ru' },
56
+ { id: '3', name: 'KG', value: 'kg', mask:'+996 (###) ###-###', icon: 'kg' },
57
+ { id: '4', name: 'UZ', value: 'uz', mask: '+998 (##) ###-##-##', icon: 'uz' },
58
+ ]);
59
+
60
+ const selectedOption = ref(optionsPhone.value[0]);
61
+
62
+ const selectedOptionId = ref(selectedOption.value.id);
63
+
64
+ watch(selectedOptionId, (newId) => {
65
+ const newOption = optionsPhone.value.find((option) => option.id === newId);
66
+ if (newOption) {
67
+ selectedOption.value = newOption;
68
+ }
69
+ });
70
+
71
+ const { stateClassList, stateAttrs } = useKitState(props);
72
+ const { sizeClassList } = useKitSize(props);
73
+ const attrs = useAttrs();
74
+
75
+ const componentAttrs = computed(() => ({
76
+ ...attrs,
77
+ ...stateAttrs.value,
78
+ label: props.label,
79
+ error: props.error,
80
+ hint: props.hint,
81
+ placeholder: props.placeholder,
82
+ }));
83
+
84
+ const classList = computed(() => [
85
+ stateClassList.value,
86
+ sizeClassList.value,
87
+ 'base-input-phone',
88
+ ]);
89
+
90
+ const modelValue = computed({
91
+ get: () => props.modelValue,
92
+ set: value => emit('update:modelValue', value),
93
+ });
94
+ const handleInput = (value: string) => {
95
+ emit('update:modelValue', value);
96
+ };
97
+ </script>
98
+
99
+ <style lang="scss" scoped>
100
+ .base-input-phone {
101
+ $input: &;
102
+
103
+ display: flex;
104
+ align-items: center;
105
+ width: 100%;
106
+
107
+ &__wrapper {
108
+ display: flex;
109
+ align-items: center;
110
+ width: 100%;
111
+
112
+ :deep(.base-select__header) {
113
+ border-top-right-radius: 0;
114
+ border-bottom-right-radius: 0;
115
+ border-right: none;
116
+ }
117
+
118
+ :deep(.base-input__field) {
119
+ border-top-left-radius: 0 !important;
120
+ border-bottom-left-radius: 0 !important;
121
+ border-left: none;
122
+ }
123
+
124
+ :deep(.base-select__hint) {
125
+ display: none;
126
+ }
127
+ }
128
+
129
+ &__input {
130
+ flex-grow: 1;
131
+ }
132
+
133
+ &__select {
134
+ min-width: unset;
135
+ }
136
+
137
+ &.--small-size {
138
+ #{$input} {
139
+ :deep(.base-select) {
140
+ width: 71px;
141
+ }
142
+ }
143
+ :deep(.base-input__label-text),
144
+ :deep(.base-input__hint) {
145
+ transform: translateX(-54px);
146
+ }
147
+ }
148
+
149
+ &.--medium-size {
150
+ #{$input} {
151
+ &__select {
152
+ width: 75px;
153
+ }
154
+ }
155
+
156
+ :deep(.base-input__label-text),
157
+ :deep(.base-input__hint) {
158
+ transform: translateX(-75px);
159
+ }
160
+ }
161
+
162
+ &.--large-size {
163
+ #{$input} {
164
+ &__select {
165
+ width: 87px;
166
+ }
167
+ }
168
+
169
+ :deep(.base-input__label-text),
170
+ :deep(.base-input__hint) {
171
+ transform: translateX(-86px);
172
+ }
173
+ }
174
+ }
175
+ </style>