adata-ui 4.0.19 → 4.0.21

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 (42) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/DigitBadge.vue +57 -0
  3. package/dist/runtime/components/DigitBadge.vue.d.ts +21 -0
  4. package/dist/runtime/components/Header.vue +3 -2
  5. package/dist/runtime/components/accordion/Accordion.vue +149 -0
  6. package/dist/runtime/components/accordion/Accordion.vue.d.ts +41 -0
  7. package/dist/runtime/components/accordion/types.d.ts +15 -0
  8. package/dist/runtime/components/accordion/types.js +0 -0
  9. package/dist/runtime/components/accordion/ui.config.d.ts +22 -0
  10. package/dist/runtime/components/accordion/ui.config.js +21 -0
  11. package/dist/runtime/components/checkbox/Checkbox.vue +123 -0
  12. package/dist/runtime/components/checkbox/Checkbox.vue.d.ts +45 -0
  13. package/dist/runtime/components/forms/input/standard/InputStandard.vue +300 -0
  14. package/dist/runtime/components/forms/input/standard/InputStandard.vue.d.ts +0 -0
  15. package/dist/runtime/components/forms/input/textarea/ATextarea.vue +157 -0
  16. package/dist/runtime/components/forms/input/textarea/ATextarea.vue.d.ts +43 -0
  17. package/dist/runtime/components/forms/request-demo/RequestDemo.vue +67 -0
  18. package/dist/runtime/components/forms/request-demo/RequestDemo.vue.d.ts +23 -0
  19. package/dist/runtime/components/header/AlmatyContacts.vue +2 -1
  20. package/dist/runtime/components/header/ContactMenu.vue +47 -6
  21. package/dist/runtime/components/header/ProductMenu.vue +36 -0
  22. package/dist/runtime/components/header/TopHeader.vue +1 -1
  23. package/dist/runtime/components/pill-tabs/PillTabs.vue +134 -0
  24. package/dist/runtime/components/pill-tabs/PillTabs.vue.d.ts +37 -0
  25. package/dist/runtime/components/pill-tabs/types.d.ts +18 -0
  26. package/dist/runtime/components/pill-tabs/types.js +0 -0
  27. package/dist/runtime/components/radio-button/RadioButton.vue +75 -0
  28. package/dist/runtime/components/radio-button/RadioButton.vue.d.ts +33 -0
  29. package/dist/runtime/composables/projectState.d.ts +1 -0
  30. package/dist/runtime/composables/projectState.js +1 -0
  31. package/dist/runtime/i18n.d.ts +1 -1
  32. package/dist/runtime/icons/checkbox/checkbox-active.vue +19 -0
  33. package/dist/runtime/icons/checkbox/checkbox-active.vue.d.ts +2 -0
  34. package/dist/runtime/icons/checkbox/checkbox-empty.vue +20 -0
  35. package/dist/runtime/icons/checkbox/checkbox-empty.vue.d.ts +2 -0
  36. package/dist/runtime/icons/checkbox/checkbox-intermediate.vue +19 -0
  37. package/dist/runtime/icons/checkbox/checkbox-intermediate.vue.d.ts +2 -0
  38. package/dist/runtime/icons/radio/radio-check.vue +24 -0
  39. package/dist/runtime/icons/radio/radio-check.vue.d.ts +2 -0
  40. package/dist/runtime/icons/radio/radio-empty.vue +20 -0
  41. package/dist/runtime/icons/radio/radio-empty.vue.d.ts +2 -0
  42. package/package.json +3 -1
@@ -0,0 +1,300 @@
1
+ <script setup>
2
+ import { twMerge, twJoin } from "tailwind-merge";
3
+ import AAlert from "../../../Alert.vue";
4
+ const props = defineProps({
5
+ disabled: { type: Boolean, required: false, default: false },
6
+ label: { type: String, required: false, default: "" },
7
+ size: { type: String, required: false, default: "md" },
8
+ error: { type: [String, Boolean], required: false, default: false },
9
+ required: { type: Boolean, required: false, default: false },
10
+ readonly: { type: Boolean, required: false, default: false },
11
+ clearable: { type: Boolean, required: false, default: false },
12
+ startIcon: { type: [String, Object], required: false, default: "" },
13
+ endIcon: { type: [String, Object], required: false, default: "" },
14
+ autocompleteList: { type: Array, required: false, default: () => [] },
15
+ type: { type: String, required: false, default: "text" },
16
+ autocompleteOption: { type: null, required: false, default: void 0 },
17
+ autocompleteKey: { type: null, required: false, default: void 0 },
18
+ autocompleteFn: { type: Function, required: false, default: void 0 },
19
+ colorClasses: { type: String, required: false }
20
+ });
21
+ const { t } = useI18n();
22
+ const uiConfig = {
23
+ "wrapper": "transition duration-500 w-full",
24
+ "input-wrapper": {
25
+ base: "relative inline-block w-full text-sm sm:min-w-full",
26
+ readonly: "pointer-events-none user-select-none",
27
+ disabled: "pointer-events-none user-select-none opacity-40"
28
+ },
29
+ "base": "w-full border-0 rounded-md text-deepblue-900 dark:text-gray-200 hover:outline outline-offset-[-1px] hover:outline-1 hover:outline-blue-700 hover:dark:outline-blue-500 focus:outline focus:outline-blue-700 focus:dark:outline-blue-500 mt-0",
30
+ "size": {
31
+ sm: "h-8 px-4 py-1.5 sm",
32
+ md: "h-10 px-4 pb-1.5 pt-[18px] md",
33
+ smEx: "h-8 pl-4 pr-10 py-1.5 sm",
34
+ mdEx: "h-10 pl-4 pr-10 pb-1.5 pt-[18px] md"
35
+ },
36
+ "color": "bg-deepblue-50 dark:bg-gray-200 dark:bg-opacity-5",
37
+ "error": "outline outline-1 outline-red-500 focus:outline-0 focus:border-red-500 hover:border-red-500",
38
+ "readonly": "bg-white opacity-30",
39
+ "label": {
40
+ "base": "absolute left-4 top-[50%] d-flex text-gray-500 pointer-events-none transition-all ease duration-300 transform translate-y-[-50%] whitespace-nowrap text-ellipsis md:max-w-[90%] overflow-hidden",
41
+ "move-label": "!left-10 md:max-w-[calc(90%-40px)]"
42
+ },
43
+ "default": {
44
+ size: "md",
45
+ color: "gray"
46
+ },
47
+ "move-input": "!ps-10",
48
+ "move-input-left": "!pe-10"
49
+ };
50
+ const emit = defineEmits(["updateValue", "onEnter", "clear", "selectOption"]);
51
+ function customTrim(input2) {
52
+ if (input2 === void 0 || input2 === null) {
53
+ return "";
54
+ }
55
+ if (input2 === " " || /\d/.test(input2)) {
56
+ return input2.trim();
57
+ }
58
+ return input2;
59
+ }
60
+ const input = ref();
61
+ const [modelValue, modelModifiers] = defineModel({ type: null, ...{ default: "", set(value) {
62
+ if (modelModifiers["custom-trim"]) {
63
+ return customTrim(value);
64
+ }
65
+ return value;
66
+ } } });
67
+ const isFocused = ref();
68
+ const isClearable = computed(
69
+ () => props.clearable && !props.disabled && !!modelValue.value
70
+ );
71
+ const mobileAutocomMoved = ref(false);
72
+ const wrapperClass = uiConfig.wrapper;
73
+ const inputWrapperClass = computed(
74
+ () => twMerge(
75
+ twJoin(
76
+ uiConfig["input-wrapper"].base,
77
+ props.readonly ? uiConfig["input-wrapper"].readonly : "",
78
+ props.disabled ? uiConfig["input-wrapper"].disabled : ""
79
+ )
80
+ )
81
+ );
82
+ const inputClass = computed(
83
+ () => twMerge(
84
+ twJoin(
85
+ uiConfig.base,
86
+ uiConfig.size[props.clearable ? `${props.size}Ex` : props.size],
87
+ props.error ? uiConfig.error : "",
88
+ props.startIcon ? uiConfig["move-input"] : "",
89
+ props.endIcon ? uiConfig["move-input-left"] : "",
90
+ props.readonly ? uiConfig.readonly : "",
91
+ props.colorClasses ? props.colorClasses : uiConfig.color
92
+ )
93
+ )
94
+ );
95
+ const labelClass = computed(
96
+ () => twMerge(twJoin(uiConfig.label.base, isClearable.value ? "max-w-[calc(80%-40px)]" : "max-w-[80%]", props.startIcon ? uiConfig.label["move-label"] : ""))
97
+ );
98
+ const currentItemIndex = ref(-1);
99
+ const assignValue = () => {
100
+ if (props.autocompleteFn) {
101
+ modelValue.value = props.autocompleteFn(props.autocompleteList[currentItemIndex.value]);
102
+ } else {
103
+ modelValue.value = props.autocompleteKey ? props.autocompleteList[currentItemIndex.value][props.autocompleteKey] : props.autocompleteList[currentItemIndex.value];
104
+ }
105
+ };
106
+ const handleKeydown = (e) => {
107
+ if (!props.autocompleteList.length) return;
108
+ if (e.key === "ArrowDown" && currentItemIndex.value < props.autocompleteList.length - 1) {
109
+ e.preventDefault();
110
+ currentItemIndex.value++;
111
+ assignValue();
112
+ } else if (e.key === "ArrowUp" && currentItemIndex.value > 0) {
113
+ e.preventDefault();
114
+ currentItemIndex.value--;
115
+ assignValue();
116
+ } else if (e.key === "Enter") {
117
+ if (currentItemIndex.value !== -1) assignValue();
118
+ emit("onEnter", props.autocompleteList[currentItemIndex.value]);
119
+ input.value?.blur();
120
+ }
121
+ };
122
+ const onSelectOption = (item) => {
123
+ if (props.autocompleteKey) {
124
+ modelValue.value = item[props.autocompleteKey];
125
+ emit("selectOption", item[props.autocompleteKey]);
126
+ } else {
127
+ modelValue.value = item;
128
+ emit("selectOption", item);
129
+ }
130
+ };
131
+ const onSelectOptionMobile = (item) => {
132
+ if (!mobileAutocomMoved.value) {
133
+ onSelectOption(item);
134
+ } else {
135
+ mobileAutocomMoved.value = false;
136
+ }
137
+ };
138
+ const onClear = () => {
139
+ modelValue.value = "";
140
+ emit("clear");
141
+ };
142
+ const autocompleteContainer = ref();
143
+ const scrollToElement = (container) => {
144
+ if (container) {
145
+ const selectedItem = container.children[currentItemIndex.value];
146
+ const containerHeight = container.clientHeight;
147
+ const itemTop = selectedItem.offsetTop;
148
+ const itemHeight = selectedItem.clientHeight;
149
+ if (itemTop < container.scrollTop) {
150
+ container.scrollTop = itemTop;
151
+ } else if (itemTop + itemHeight > container.scrollTop + containerHeight) {
152
+ container.scrollTop = itemTop + itemHeight - containerHeight;
153
+ }
154
+ }
155
+ };
156
+ const focus = () => {
157
+ input.value?.focus();
158
+ };
159
+ watch(currentItemIndex, () => {
160
+ scrollToElement(autocompleteContainer.value);
161
+ });
162
+ const isDropdownUp = ref(false);
163
+ const checkDropdownPosition = () => {
164
+ const rect = input.value?.getBoundingClientRect();
165
+ const dropdownHeight = 250;
166
+ const windowHeight = window.visualViewport ? window.visualViewport.height : window.innerHeight;
167
+ if (rect) {
168
+ isDropdownUp.value = windowHeight - rect.bottom < dropdownHeight;
169
+ }
170
+ };
171
+ watch(isFocused, (newVal) => {
172
+ if (newVal) {
173
+ checkDropdownPosition();
174
+ }
175
+ });
176
+ watch(modelValue, () => {
177
+ checkDropdownPosition();
178
+ });
179
+ defineExpose({
180
+ focus
181
+ });
182
+ </script>
183
+
184
+ <template>
185
+ <div :class="wrapperClass">
186
+ <div :class="inputWrapperClass">
187
+ <Transition name="autocomplete-fade">
188
+ <div
189
+ v-if="autocompleteList.length && isFocused"
190
+ :class="[
191
+ 'absolute z-[31] w-full flex flex-col gap-4 rounded bg-gray-200 p-2 dark:bg-gray-800',
192
+ isDropdownUp ? 'bottom-[44px]' : 'top-[44px]'
193
+ ]"
194
+ >
195
+ <ul
196
+ ref="autocompleteContainer"
197
+ class="max-h-[250px] w-full overflow-y-auto"
198
+ >
199
+ <li
200
+ v-for="(item, idx) in autocompleteList"
201
+ :key="idx"
202
+ class="cursor-pointer rounded px-4 py-[10px] transition-colors hover:bg-gray-50 hover:dark:bg-gray-900"
203
+ :class="{ 'bg-gray-100 dark:bg-gray-700': currentItemIndex === idx }"
204
+ @mousedown="onSelectOption(item)"
205
+ @touchend="onSelectOptionMobile(item)"
206
+ @touchmove="mobileAutocomMoved = true"
207
+ >
208
+ <slot
209
+ name="autocomplete-option"
210
+ :item="item"
211
+ >
212
+ {{ autocompleteOption ? item[autocompleteOption] : item }}
213
+ </slot>
214
+ </li>
215
+ </ul>
216
+ <slot
217
+ name="autocomplete-buttons"
218
+ :value="modelValue"
219
+ />
220
+ </div>
221
+ </Transition>
222
+ <input
223
+ :id="label"
224
+ ref="input"
225
+ v-model="modelValue"
226
+ :type="type"
227
+ :class="inputClass"
228
+ class="input"
229
+ required
230
+ :tabindex="disabled ? -1 : 0"
231
+ v-bind="$attrs"
232
+ @input="emit('updateValue', modelValue)"
233
+ @keydown="handleKeydown"
234
+ @focus="isFocused = true"
235
+ @blur="isFocused = false"
236
+ >
237
+ <label
238
+ :for="label"
239
+ :class="[labelClass]"
240
+ class="label"
241
+ >
242
+ <span class="text">{{ label }}</span>
243
+ <span
244
+ v-if="required"
245
+ class="text-red-600"
246
+ > *</span>
247
+ </label>
248
+
249
+ <component
250
+ :is="startIcon"
251
+ v-if="startIcon"
252
+ class="pointer-events-none absolute left-4 top-1/2 translate-y-[-50%] transform fill-gray-500 text-base text-gray-500"
253
+ filled
254
+ />
255
+ <component
256
+ :is="endIcon"
257
+ v-if="endIcon"
258
+ class="pointer-events-none absolute right-4 top-1/2 translate-y-[-50%] transform fill-gray-500 text-base text-gray-500"
259
+ filled
260
+ />
261
+ <button
262
+ v-if="isClearable"
263
+ class="pointer-events-click absolute right-4 top-1/2 translate-y-[-50%] transform rounded-full bg-deepblue-900 bg-opacity-10 p-1 text-2xl hover:opacity-80 dark:bg-gray-200 dark:bg-opacity-10"
264
+ type="button"
265
+ @click="onClear"
266
+ >
267
+ <i-x-mark
268
+ filled
269
+ class="!mb-0 fill-gray-600 dark:fill-gray-300"
270
+ />
271
+ </button>
272
+ <slot name="endButton" />
273
+ </div>
274
+ <Transition name="slide-in">
275
+ <div
276
+ v-if="error && typeof error === 'string'"
277
+ class="mt-1"
278
+ >
279
+ <a-alert
280
+ :size="size === 'sm' ? 'xs' : 'sm'"
281
+ :color="'red'"
282
+ icon-type="triangle"
283
+ >
284
+ <template #default>
285
+ <div class="flex flex-col">
286
+ <span
287
+ v-for="(err, index) in error.split(', ')"
288
+ :key="index"
289
+ >{{ err }}<br></span>
290
+ </div>
291
+ </template>
292
+ </a-alert>
293
+ </div>
294
+ </Transition>
295
+ </div>
296
+ </template>
297
+
298
+ <style scoped>
299
+ .input:-webkit-autofill~.label,.input:focus~.label,.input:not(:focus):valid~.label{font-size:10px;transform:translateY(-10px)}.input.sm:-webkit-autofill~.label,.input.sm:focus~.label,.input.sm:not(:focus):valid~.label{display:none}.input::-ms-clear,.input::-ms-reveal{display:none}.slide-in-enter-active{opacity:0;transform:translateY(-50%);transition:transform .5s;z-index:0}.slide-in-enter-to{z-index:auto}.slide-in-enter-to,.slide-in-leave-active{opacity:1;transform:translateY(0)}.slide-in-leave-to{opacity:0;transform:translateY(-100%)}.autocomplete-fade-enter-active,.autocomplete-fade-leave-active{transition:opacity .15s ease}.autocomplete-fade-enter-from,.autocomplete-fade-leave-to{opacity:0}.move-input{padding-left:40px!important}
300
+ </style>
@@ -0,0 +1,157 @@
1
+ <script setup>
2
+ import { twMerge, twJoin } from "tailwind-merge";
3
+ import AAlert from "../../../Alert.vue";
4
+ const props = defineProps({
5
+ disabled: { type: Boolean, required: false, default: false },
6
+ label: { type: String, required: false, default: "" },
7
+ size: { type: String, required: false, default: "md" },
8
+ error: { type: [String, Boolean], required: false, default: false },
9
+ required: { type: Boolean, required: false, default: false },
10
+ readonly: { type: Boolean, required: false, default: false },
11
+ clearable: { type: Boolean, required: false, default: false },
12
+ resizeable: { type: [Boolean, String], required: false, default: true },
13
+ startIcon: { type: [String, Object], required: false, default: "" },
14
+ colorClasses: { type: String, required: false, default: "" }
15
+ });
16
+ const uiConfig = {
17
+ "wrapper": "transition duration-500 w-full",
18
+ "input-wrapper": {
19
+ base: "relative inline-block h-full w-full text-sm sm:min-w-full pt-5 hover:outline hover:outline-1 outline-offset-[-1px] hover:outline-blue-700 hover:dark:outline-blue-500 focus:outline focus:outline-blue-700 focus:dark:outline-blue-500",
20
+ readonly: "pointer-events-none user-select-none",
21
+ disabled: "pointer-events-none user-select-none opacity-40",
22
+ color: "bg-deepblue-900/5 dark:bg-gray-200/5"
23
+ },
24
+ "base": "w-full border-0 rounded-md text-deepblue-900 dark:text-gray-200 outline-none mt-0",
25
+ "size": {
26
+ sm: "h-8 px-4 py-1.5 sm",
27
+ md: "h-10 px-4 pb-1.5 pt-[8px] md"
28
+ },
29
+ "color": "bg-deepblue-900/0 dark:bg-gray-200/0",
30
+ "error": "outline outline-1 outline-red-500 focus:outline-0 focus:border-red-500 hover:border-red-500",
31
+ "readonly": "bg-white opacity-30",
32
+ "label": {
33
+ "base": "absolute left-4 top-5 d-flex text-gray-500 pointer-events-none transition-all ease duration-300 transform translate-y-[-50%] whitespace-nowrap",
34
+ "move-label": "!left-10"
35
+ },
36
+ "default": {
37
+ size: "md",
38
+ color: "gray"
39
+ },
40
+ "resize": {
41
+ none: "resize-none",
42
+ both: "resize",
43
+ x: "resize-x",
44
+ y: "resize-y"
45
+ },
46
+ "move-input": "!ps-10"
47
+ };
48
+ const modelValue = defineModel({ type: [String, Number], ...{ default: "" } });
49
+ const isClearable = computed(
50
+ () => props.clearable && !props.disabled && !!modelValue.value
51
+ );
52
+ const isResizeable = computed(
53
+ () => props.resizeable && props.resizeable !== "none" && !props.disabled && !!modelValue.value
54
+ );
55
+ const resizeable = computed(() => {
56
+ if (typeof props.resizeable === "boolean") return props.resizeable ? "both" : "none";
57
+ return props.resizeable;
58
+ });
59
+ const wrapperClass = uiConfig.wrapper;
60
+ const inputWrapperClass = computed(
61
+ () => twMerge(
62
+ twJoin(
63
+ uiConfig["input-wrapper"].base,
64
+ uiConfig.base,
65
+ props.colorClasses ? props.colorClasses : uiConfig["input-wrapper"].color,
66
+ props.error ? uiConfig.error : "",
67
+ props.readonly ? uiConfig["input-wrapper"].readonly : "",
68
+ props.disabled ? uiConfig["input-wrapper"].disabled : ""
69
+ )
70
+ )
71
+ );
72
+ const inputClass = computed(
73
+ () => twMerge(
74
+ twJoin(
75
+ uiConfig.base,
76
+ uiConfig.color,
77
+ uiConfig.size[props.size],
78
+ props.startIcon ? uiConfig["move-input"] : "",
79
+ props.readonly ? uiConfig.readonly : "",
80
+ isResizeable.value ? uiConfig.resize[resizeable] : uiConfig.resize.none
81
+ )
82
+ )
83
+ );
84
+ const labelClass = computed(
85
+ () => twMerge(twJoin(uiConfig.label.base, props.startIcon ? uiConfig.label["move-label"] : ""))
86
+ );
87
+ </script>
88
+
89
+ <template>
90
+ <div :class="wrapperClass">
91
+ <div :class="inputWrapperClass">
92
+ <textarea
93
+ :id="label"
94
+ ref="input"
95
+ v-model="modelValue"
96
+ :class="inputClass"
97
+ :tabindex="disabled ? -1 : 0"
98
+ class="input"
99
+ required
100
+ v-bind="$attrs"
101
+ />
102
+ <label
103
+ :class="labelClass"
104
+ :for="label"
105
+ class="label cursor-pointer"
106
+ >
107
+ <span class="text">{{ label }}</span>
108
+ <span
109
+ v-if="required"
110
+ class="text-red-600"
111
+ > *</span>
112
+ </label>
113
+
114
+ <component
115
+ :is="startIcon"
116
+ v-if="startIcon"
117
+ class="pointer-events-none absolute left-4 top-5 translate-y-[-50%] transform fill-gray-500 text-base text-gray-500"
118
+ filled
119
+ />
120
+ <button
121
+ v-if="isClearable"
122
+ class="pointer-events-click absolute right-4 top-5 translate-y-[-50%] transform rounded-full bg-deepblue-900 bg-opacity-10 p-1 text-2xl hover:opacity-80 dark:bg-gray-200 dark:bg-opacity-10"
123
+ type="button"
124
+ @click="modelValue = ''"
125
+ >
126
+ <i-x-mark
127
+ class="!mb-0 fill-gray-600 dark:fill-gray-300"
128
+ filled
129
+ />
130
+ </button>
131
+ <slot name="endButton" />
132
+ </div>
133
+ <Transition name="slide-in">
134
+ <div
135
+ v-if="error && typeof error === 'string'"
136
+ class="mt-1"
137
+ >
138
+ <a-alert
139
+ :color="'red'"
140
+ :size="size === 'sm' ? 'sm' : 'lg'"
141
+ icon-type="triangle"
142
+ >
143
+ <template #default>
144
+ <span
145
+ v-for="(err, index) in error.split(', ')"
146
+ :key="index"
147
+ >{{ err }}<br></span>
148
+ </template>
149
+ </a-alert>
150
+ </div>
151
+ </Transition>
152
+ </div>
153
+ </template>
154
+
155
+ <style scoped>
156
+ .input::-webkit-scrollbar{display:none}.input:-webkit-autofill~.label,.input:focus~.label,.input:not(:focus):valid~.label{font-size:10px;transform:translateY(-10px)}.slide-in-enter-active{opacity:0;transform:translateY(-50%);transition:transform .5s;z-index:0}.slide-in-enter-to{z-index:auto}.slide-in-enter-to,.slide-in-leave-active{opacity:1;transform:translateY(0)}.slide-in-leave-to{opacity:0;transform:translateY(-100%)}.move-input{padding-left:40px!important}
157
+ </style>
@@ -0,0 +1,43 @@
1
+ interface Props {
2
+ disabled?: boolean;
3
+ label?: string;
4
+ size?: 'sm' | 'md';
5
+ error?: string | boolean;
6
+ required?: boolean;
7
+ readonly?: boolean;
8
+ clearable?: boolean;
9
+ resizeable?: boolean | 'none' | 'both' | 'x' | 'y';
10
+ startIcon?: string | object;
11
+ colorClasses?: string;
12
+ }
13
+ type __VLS_Props = Props;
14
+ type __VLS_PublicProps = __VLS_Props & {
15
+ modelValue?: string | number;
16
+ };
17
+ declare var __VLS_9: {};
18
+ type __VLS_Slots = {} & {
19
+ endButton?: (props: typeof __VLS_9) => any;
20
+ };
21
+ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
22
+ "update:modelValue": (value: string | number) => any;
23
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
24
+ "onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
25
+ }>, {
26
+ size: "sm" | "md";
27
+ error: string | boolean;
28
+ disabled: boolean;
29
+ required: boolean;
30
+ label: string;
31
+ readonly: boolean;
32
+ clearable: boolean;
33
+ startIcon: string | object;
34
+ colorClasses: string;
35
+ resizeable: boolean | "none" | "both" | "x" | "y";
36
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
37
+ declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
38
+ export default _default;
39
+ type __VLS_WithSlots<T, S> = T & {
40
+ new (): {
41
+ $slots: S;
42
+ };
43
+ };
@@ -0,0 +1,67 @@
1
+ <script setup>
2
+ import AButton from "../../button/Button.vue";
3
+ import InputStandard from "../input/standard/InputStandard.vue";
4
+ import ATextarea from "../input/textarea/ATextarea.vue";
5
+ import { ref, useI18n } from "#imports";
6
+ const emit = defineEmits(["onSend"]);
7
+ const { t } = useI18n();
8
+ const isLoading = defineModel("loading", { type: Boolean, ...{ default: false } });
9
+ const isModalOpen = defineModel("modal", { type: Boolean, ...{ default: false } });
10
+ const fullName = ref("");
11
+ const phone = ref("");
12
+ const comment = ref("");
13
+ </script>
14
+
15
+ <template>
16
+ <div class="flex flex-col gap-8 rounded-[20px] bg-white p-8 dark:bg-gray-900">
17
+ <div class="flex flex-col gap-2">
18
+ <h3 class="heading-01">
19
+ {{ t("forms.demo.t") }}
20
+ </h3>
21
+ <p class="text-base">
22
+ {{ t("forms.demo.st") }}
23
+ </p>
24
+ </div>
25
+ <form
26
+ action=""
27
+ class="flex flex-col justify-between gap-2 sm:flex-row sm:gap-4"
28
+ >
29
+ <div class="flex flex-col gap-2 sm:w-1/2 sm:gap-4">
30
+ <input-standard
31
+ v-model="fullName"
32
+ color-classes="bg-gray-50 dark:bg-gray-800"
33
+ :label="t('forms.demo.n')"
34
+ required
35
+ size="md"
36
+ :disabled="isLoading"
37
+ />
38
+ <input-standard
39
+ v-model="phone"
40
+ v-maska
41
+ color-classes="bg-gray-50 dark:bg-gray-800"
42
+ type="tel"
43
+ :label="t('forms.demo.p')"
44
+ data-maska="8 (###) ###-##-##"
45
+ required
46
+ size="md"
47
+ :disabled="isLoading"
48
+ />
49
+ </div>
50
+ <div class="sm:w-1/2">
51
+ <a-textarea
52
+ v-model="comment"
53
+ :label="t('forms.demo.c')"
54
+ :resizeable="false"
55
+ class="min-h-[72px]"
56
+ color-classes="dark:bg-gray-800 bg-gray-50"
57
+ required
58
+ size="sm"
59
+ :disabled="isLoading"
60
+ />
61
+ </div>
62
+ </form>
63
+ <a-button class="w-full self-end sm:w-[215px] font-semibold" :disabled="isLoading">
64
+ {{ t("forms.demo.b") }}
65
+ </a-button>
66
+ </div>
67
+ </template>
@@ -0,0 +1,23 @@
1
+ type __VLS_PublicProps = {
2
+ 'loading'?: boolean;
3
+ 'modal'?: boolean;
4
+ };
5
+ declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
6
+ "update:loading": (value: boolean) => any;
7
+ "update:modal": (value: boolean) => any;
8
+ } & {
9
+ onSend: (form: {
10
+ sender_name: string;
11
+ phone_number: string;
12
+ message: string;
13
+ }) => any;
14
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
15
+ onOnSend?: ((form: {
16
+ sender_name: string;
17
+ phone_number: string;
18
+ message: string;
19
+ }) => any) | undefined;
20
+ "onUpdate:loading"?: ((value: boolean) => any) | undefined;
21
+ "onUpdate:modal"?: ((value: boolean) => any) | undefined;
22
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
23
+ export default _default;
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { useContacts } from "../../composables/projectState";
2
3
  import Location from "#icons/navigation/location.vue";
3
4
  import Mail from "#icons/communication/mail.vue";
4
5
  import Clock from "#icons/clock.vue";
@@ -6,7 +7,7 @@ import ExpandWindow from "#icons/navigation/expand-window.vue";
6
7
  import { computed, ref, useI18n } from "#imports";
7
8
  import Phone from "#icons/communication/phone.vue";
8
9
  import Whatsapp from "#icons/socials/whatsapp.vue";
9
- const contacts = ref([]);
10
+ const contacts = ref(useContacts());
10
11
  const { t } = useI18n();
11
12
  const AlmatyItems = [
12
13
  {