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.
- package/dist/module.json +1 -1
- package/dist/runtime/components/DigitBadge.vue +57 -0
- package/dist/runtime/components/DigitBadge.vue.d.ts +21 -0
- package/dist/runtime/components/Header.vue +3 -2
- package/dist/runtime/components/accordion/Accordion.vue +149 -0
- package/dist/runtime/components/accordion/Accordion.vue.d.ts +41 -0
- package/dist/runtime/components/accordion/types.d.ts +15 -0
- package/dist/runtime/components/accordion/types.js +0 -0
- package/dist/runtime/components/accordion/ui.config.d.ts +22 -0
- package/dist/runtime/components/accordion/ui.config.js +21 -0
- package/dist/runtime/components/checkbox/Checkbox.vue +123 -0
- package/dist/runtime/components/checkbox/Checkbox.vue.d.ts +45 -0
- package/dist/runtime/components/forms/input/standard/InputStandard.vue +300 -0
- package/dist/runtime/components/forms/input/standard/InputStandard.vue.d.ts +0 -0
- package/dist/runtime/components/forms/input/textarea/ATextarea.vue +157 -0
- package/dist/runtime/components/forms/input/textarea/ATextarea.vue.d.ts +43 -0
- package/dist/runtime/components/forms/request-demo/RequestDemo.vue +67 -0
- package/dist/runtime/components/forms/request-demo/RequestDemo.vue.d.ts +23 -0
- package/dist/runtime/components/header/AlmatyContacts.vue +2 -1
- package/dist/runtime/components/header/ContactMenu.vue +47 -6
- package/dist/runtime/components/header/ProductMenu.vue +36 -0
- package/dist/runtime/components/header/TopHeader.vue +1 -1
- package/dist/runtime/components/pill-tabs/PillTabs.vue +134 -0
- package/dist/runtime/components/pill-tabs/PillTabs.vue.d.ts +37 -0
- package/dist/runtime/components/pill-tabs/types.d.ts +18 -0
- package/dist/runtime/components/pill-tabs/types.js +0 -0
- package/dist/runtime/components/radio-button/RadioButton.vue +75 -0
- package/dist/runtime/components/radio-button/RadioButton.vue.d.ts +33 -0
- package/dist/runtime/composables/projectState.d.ts +1 -0
- package/dist/runtime/composables/projectState.js +1 -0
- package/dist/runtime/i18n.d.ts +1 -1
- package/dist/runtime/icons/checkbox/checkbox-active.vue +19 -0
- package/dist/runtime/icons/checkbox/checkbox-active.vue.d.ts +2 -0
- package/dist/runtime/icons/checkbox/checkbox-empty.vue +20 -0
- package/dist/runtime/icons/checkbox/checkbox-empty.vue.d.ts +2 -0
- package/dist/runtime/icons/checkbox/checkbox-intermediate.vue +19 -0
- package/dist/runtime/icons/checkbox/checkbox-intermediate.vue.d.ts +2 -0
- package/dist/runtime/icons/radio/radio-check.vue +24 -0
- package/dist/runtime/icons/radio/radio-check.vue.d.ts +2 -0
- package/dist/runtime/icons/radio/radio-empty.vue +20 -0
- package/dist/runtime/icons/radio/radio-empty.vue.d.ts +2 -0
- 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>
|
|
File without changes
|
|
@@ -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
|
{
|