lau-ecom-design-system 1.0.23 → 1.0.27
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/lau-ecom-design-system.esm.css +4 -1
- package/dist/lau-ecom-design-system.esm.js +1144 -547
- package/dist/lau-ecom-design-system.min.css +4 -1
- package/dist/lau-ecom-design-system.min.js +1 -1
- package/dist/lau-ecom-design-system.ssr.css +4 -1
- package/dist/lau-ecom-design-system.ssr.js +1149 -503
- package/dist/style.css +192 -318
- package/package.json +1 -2
- package/src/components/LauEcomIcon/LauEcomUpcIconClose.vue +29 -0
- package/src/components/LauEcomIcon/LauEcomUpcIconNavArrow.vue +1 -1
- package/src/components/LauEcomIcon/LauEcomUpcIconSearch.vue +6 -16
- package/src/components/LauEcomInputSearch/LauEcomInputSearch.vue +154 -511
- package/src/components/LauEcomInputSearchHeader/LauEcomInputSearchHeader.vue +432 -0
- package/src/components/LauEcomInputSearchHeader/LauEcomInputSearchHeaderDesktop.vue +324 -0
- package/src/components/LauEcomInputSearchHeader/LauEcomInputSearchHeaderMobile.vue +279 -0
@@ -1,511 +1,154 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import { ref, computed
|
3
|
-
import {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
placeholder:
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
const
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
}
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
} else if (rect.top > viewportHeight) {
|
156
|
-
topPosition = '20px';
|
157
|
-
} else {
|
158
|
-
topPosition = `${rect.top}px`;
|
159
|
-
}
|
160
|
-
|
161
|
-
// Mantenemos la posición original del input
|
162
|
-
const leftPosition = `${rect.left}px`;
|
163
|
-
|
164
|
-
expandedContainer.value.style.position = 'fixed';
|
165
|
-
expandedContainer.value.style.top = topPosition;
|
166
|
-
expandedContainer.value.style.left = leftPosition;
|
167
|
-
expandedContainer.value.style.transform = 'none';
|
168
|
-
expandedContainer.value.style.width = props.expandedWidth;
|
169
|
-
expandedContainer.value.style.maxWidth = '90vw';
|
170
|
-
|
171
|
-
// Ajustamos si se sale por la derecha
|
172
|
-
const expandedWidth = parseInt(props.expandedWidth);
|
173
|
-
if (rect.left + expandedWidth > viewportWidth) {
|
174
|
-
// Si se sale por la derecha, ajustamos el ancho para que quepa
|
175
|
-
const availableWidth = viewportWidth - rect.left - 32; // 32px de margen
|
176
|
-
expandedContainer.value.style.width = `${availableWidth}px`;
|
177
|
-
}
|
178
|
-
|
179
|
-
// Log para debugging
|
180
|
-
console.log('🔍 Expanded position updated:', {
|
181
|
-
top: topPosition,
|
182
|
-
left: leftPosition,
|
183
|
-
width: expandedContainer.value.style.width,
|
184
|
-
originalLeft: rect.left,
|
185
|
-
viewportWidth,
|
186
|
-
originalWidth: rect.width
|
187
|
-
});
|
188
|
-
}
|
189
|
-
};
|
190
|
-
|
191
|
-
onMounted(() => {
|
192
|
-
console.log('🔍 Component mounted with props:', {
|
193
|
-
buttonColorClass: props.buttonColorClass,
|
194
|
-
buttonTextColorClass: props.buttonTextColorClass,
|
195
|
-
arrowColorClass: props.arrowColorClass,
|
196
|
-
isMobileSearch: props.isMobileSearch,
|
197
|
-
mobileInputWidth: props.mobileInputWidth,
|
198
|
-
mobileInputHeight: props.mobileInputHeight
|
199
|
-
});
|
200
|
-
checkMobileView();
|
201
|
-
window.addEventListener('resize', updateExpandedPosition);
|
202
|
-
window.addEventListener('resize', checkMobileView);
|
203
|
-
});
|
204
|
-
|
205
|
-
onBeforeUnmount(() => {
|
206
|
-
console.log('🔍 Component will unmount');
|
207
|
-
window.removeEventListener('resize', updateExpandedPosition);
|
208
|
-
window.removeEventListener('resize', checkMobileView);
|
209
|
-
});
|
210
|
-
|
211
|
-
watch(isExpanded, (newValue) => {
|
212
|
-
console.log('🔍 isExpanded changed:', {
|
213
|
-
newValue,
|
214
|
-
searchQuery: searchQuery.value,
|
215
|
-
showOverlay: showOverlay.value
|
216
|
-
});
|
217
|
-
if (newValue) {
|
218
|
-
nextTick(updateExpandedPosition);
|
219
|
-
}
|
220
|
-
});
|
221
|
-
|
222
|
-
watch(() => props.forceClose, (newValue) => {
|
223
|
-
console.log('🔍 forceClose prop changed:', newValue);
|
224
|
-
if (newValue) {
|
225
|
-
closeSearch();
|
226
|
-
}
|
227
|
-
});
|
228
|
-
|
229
|
-
watch(() => props.modelValue, (newValue) => {
|
230
|
-
console.log('🔍 modelValue prop changed:', {
|
231
|
-
newValue,
|
232
|
-
currentSearchQuery: searchQuery.value
|
233
|
-
});
|
234
|
-
if (newValue !== searchQuery.value) {
|
235
|
-
searchQuery.value = newValue;
|
236
|
-
}
|
237
|
-
});
|
238
|
-
|
239
|
-
const buttonClasses = computed(() => {
|
240
|
-
const defaultClasses = "dsEcom-absolute dsEcom-right-0 dsEcom-top-1/2 -dsEcom-translate-y-1/2 dsEcom-p-2 dsEcom-rounded-r-lg dsEcom-transition-all dsEcom-duration-300";
|
241
|
-
|
242
|
-
// Si hay buttonClass, usamos esas clases directamente
|
243
|
-
if (props.buttonClass) {
|
244
|
-
return [defaultClasses, props.buttonClass];
|
245
|
-
}
|
246
|
-
|
247
|
-
// Si no, usamos las clases de color tradicionales
|
248
|
-
return [
|
249
|
-
defaultClasses,
|
250
|
-
props.buttonColorClass,
|
251
|
-
props.buttonTextColorClass
|
252
|
-
];
|
253
|
-
});
|
254
|
-
|
255
|
-
const checkMobileView = () => {
|
256
|
-
const wasMobile = isMobileView.value;
|
257
|
-
isMobileView.value = window.innerWidth < 768;
|
258
|
-
if (wasMobile !== isMobileView.value) {
|
259
|
-
console.log('🔍 Mobile view changed:', {
|
260
|
-
isMobileView: isMobileView.value,
|
261
|
-
width: window.innerWidth,
|
262
|
-
buttonColorClass: props.buttonColorClass,
|
263
|
-
buttonTextColorClass: props.buttonTextColorClass
|
264
|
-
});
|
265
|
-
}
|
266
|
-
};
|
267
|
-
|
268
|
-
const handleMobileSearchClick = () => {
|
269
|
-
console.log('🔍 Mobile Search Click:', {
|
270
|
-
buttonColorClass: props.buttonColorClass,
|
271
|
-
buttonTextColorClass: props.buttonTextColorClass,
|
272
|
-
arrowColorClass: props.arrowColorClass,
|
273
|
-
isMobileView: isMobileView.value
|
274
|
-
});
|
275
|
-
isMobileSearchOpen.value = true;
|
276
|
-
nextTick(() => {
|
277
|
-
if (expandedContainer.value) {
|
278
|
-
const input = expandedContainer.value.querySelector('input');
|
279
|
-
input?.focus();
|
280
|
-
}
|
281
|
-
});
|
282
|
-
};
|
283
|
-
|
284
|
-
const handleMobileSearchClose = () => {
|
285
|
-
console.log('🔍 Mobile Search Close:', {
|
286
|
-
buttonColorClass: props.buttonColorClass,
|
287
|
-
buttonTextColorClass: props.buttonTextColorClass,
|
288
|
-
arrowColorClass: props.arrowColorClass
|
289
|
-
});
|
290
|
-
isMobileSearchOpen.value = false;
|
291
|
-
searchQuery.value = '';
|
292
|
-
emit('update:modelValue', '');
|
293
|
-
};
|
294
|
-
|
295
|
-
const handleMobileSearch = () => {
|
296
|
-
if (searchQuery.value && searchQuery.value.trim()) {
|
297
|
-
emit("search", searchQuery.value);
|
298
|
-
emit("update:modelValue", searchQuery.value);
|
299
|
-
emit("click:search-icon");
|
300
|
-
handleMobileSearchClose();
|
301
|
-
}
|
302
|
-
};
|
303
|
-
|
304
|
-
const handleMobileClear = () => {
|
305
|
-
clearSearch();
|
306
|
-
};
|
307
|
-
</script>
|
308
|
-
|
309
|
-
<template>
|
310
|
-
<div class="dsEcom-relative">
|
311
|
-
<!-- Versión móvil - Solo botón de búsqueda -->
|
312
|
-
<button
|
313
|
-
v-if="isMobileView && !isMobileSearchOpen"
|
314
|
-
@click="handleMobileSearchClick"
|
315
|
-
class="dsEcom-p-2 dsEcom-rounded-lg"
|
316
|
-
:class="[buttonColorClass]"
|
317
|
-
>
|
318
|
-
<LauEcomUpcIconSearch
|
319
|
-
width="24"
|
320
|
-
height="24"
|
321
|
-
:class="[buttonTextColorClass]"
|
322
|
-
/>
|
323
|
-
</button>
|
324
|
-
|
325
|
-
<!-- Capa blanca móvil -->
|
326
|
-
<div
|
327
|
-
v-if="isMobileView && isMobileSearchOpen"
|
328
|
-
class="dsEcom-fixed dsEcom-inset-0 dsEcom-z-50"
|
329
|
-
:class="[mobilePanelClass]"
|
330
|
-
>
|
331
|
-
<div class="dsEcom-flex dsEcom-items-center dsEcom-gap-2 dsEcom-p-4">
|
332
|
-
<!-- Input y botones -->
|
333
|
-
<div class="dsEcom-flex dsEcom-items-center dsEcom-gap-2 dsEcom-flex-1">
|
334
|
-
<button
|
335
|
-
@click="handleMobileSearchClose"
|
336
|
-
class="dsEcom-p-2 dsEcom-rounded-lg"
|
337
|
-
:class="[arrowButtonClass]"
|
338
|
-
>
|
339
|
-
<LauEcomUpcIconNavArrow
|
340
|
-
width="24"
|
341
|
-
height="24"
|
342
|
-
class="dsEcom-transform dsEcom-rotate-[-90deg]"
|
343
|
-
:class="[arrowColorClass]"
|
344
|
-
color="currentColor"
|
345
|
-
/>
|
346
|
-
</button>
|
347
|
-
|
348
|
-
<div class="dsEcom-flex dsEcom-items-center dsEcom-gap-0 dsEcom-flex-1">
|
349
|
-
<input
|
350
|
-
v-model="searchQuery"
|
351
|
-
type="text"
|
352
|
-
:placeholder="placeholder"
|
353
|
-
:disabled="isDisabled"
|
354
|
-
:style="{
|
355
|
-
width: props.mobileInputWidth,
|
356
|
-
height: props.mobileInputHeight
|
357
|
-
}"
|
358
|
-
class="lau-ecom-input dsEcom-pl-4 dsEcom-pr-4 dsEcom-border dsEcom-border-neutral-80 dsEcom-rounded-l-lg dsEcom-focus:outline-none dsEcom-focus:ring-2 dsEcom-focus:ring-primary-60 dsEcom-flex-1"
|
359
|
-
@input="handleInput"
|
360
|
-
@keyup.enter="handleMobileSearch"
|
361
|
-
/>
|
362
|
-
<button
|
363
|
-
@click="handleMobileSearch"
|
364
|
-
:style="{ height: props.mobileInputHeight }"
|
365
|
-
:class="[
|
366
|
-
'dsEcom-px-3 dsEcom-rounded-r-lg dsEcom-border-0',
|
367
|
-
buttonColorClass,
|
368
|
-
buttonTextColorClass
|
369
|
-
]"
|
370
|
-
>
|
371
|
-
<LauEcomUpcIconSearch width="20" height="20" color="currentColor" />
|
372
|
-
</button>
|
373
|
-
</div>
|
374
|
-
|
375
|
-
<button
|
376
|
-
v-if="searchQuery.length >= 3"
|
377
|
-
@click="handleMobileClear"
|
378
|
-
class="dsEcom-p-2 dsEcom-text-neutral-100 hover:dsEcom-text-neutral-80"
|
379
|
-
>
|
380
|
-
<LauEcomUpcIconClose width="16" height="16" />
|
381
|
-
</button>
|
382
|
-
</div>
|
383
|
-
</div>
|
384
|
-
</div>
|
385
|
-
|
386
|
-
<!-- Versión desktop -->
|
387
|
-
<div v-if="!isMobileView">
|
388
|
-
<div
|
389
|
-
:class="[containerClasses, props.containerClass]"
|
390
|
-
ref="originalContainer"
|
391
|
-
>
|
392
|
-
<div class="dsEcom-relative" :class="{ 'dsEcom-invisible': isExpanded }">
|
393
|
-
<input
|
394
|
-
v-model="searchQuery"
|
395
|
-
type="text"
|
396
|
-
:placeholder="placeholder"
|
397
|
-
:disabled="isDisabled"
|
398
|
-
:class="[
|
399
|
-
'lau-ecom-input dsEcom-border dsEcom-border-neutral-80 dsEcom-pl-4 dsEcom-pr-24 dsEcom-w-full dsEcom-focus:outline-none dsEcom-focus:ring-2 dsEcom-focus:ring-primary-60',
|
400
|
-
props.inputClass,
|
401
|
-
{ 'dsEcom-opacity-0': isExpanded }
|
402
|
-
]"
|
403
|
-
@focus="handleFocus"
|
404
|
-
@input="handleInput"
|
405
|
-
@keyup.enter="handleSearch"
|
406
|
-
/>
|
407
|
-
<div class="dsEcom-absolute dsEcom-right-0 dsEcom-inset-y-0 dsEcom-flex dsEcom-items-stretch">
|
408
|
-
<button
|
409
|
-
v-if="searchQuery.length >= 3"
|
410
|
-
@click="clearSearch"
|
411
|
-
:class="[
|
412
|
-
'dsEcom-flex dsEcom-items-center dsEcom-px-1.5 dsEcom-text-neutral-100 hover:dsEcom-text-neutral-80 dsEcom-transition-all dsEcom-duration-300',
|
413
|
-
props.inputClass
|
414
|
-
]"
|
415
|
-
>
|
416
|
-
<LauEcomUpcIconClose width="16" height="16" />
|
417
|
-
</button>
|
418
|
-
|
419
|
-
<button
|
420
|
-
@click="handleSearch"
|
421
|
-
:class="[
|
422
|
-
'dsEcom-flex dsEcom-items-center dsEcom-px-3 dsEcom-transition-all dsEcom-duration-300',
|
423
|
-
props.inputClass?.includes('rounded') ? props.inputClass : 'dsEcom-rounded-r-lg',
|
424
|
-
props.buttonColorClass,
|
425
|
-
props.buttonTextColorClass,
|
426
|
-
'dsEcom-border-0'
|
427
|
-
]"
|
428
|
-
style="margin: 1px; height: calc(100% - 2px);"
|
429
|
-
>
|
430
|
-
<LauEcomUpcIconSearch width="20" height="20" color="currentColor" />
|
431
|
-
</button>
|
432
|
-
</div>
|
433
|
-
</div>
|
434
|
-
</div>
|
435
|
-
|
436
|
-
<!-- Overlay -->
|
437
|
-
<div
|
438
|
-
v-show="isExpanded"
|
439
|
-
:class="overlayClasses"
|
440
|
-
@click="closeSearch"
|
441
|
-
></div>
|
442
|
-
|
443
|
-
<!-- Versión expandida -->
|
444
|
-
<div
|
445
|
-
v-show="isExpanded"
|
446
|
-
class="dsEcom-fixed dsEcom-z-50 dsEcom-shadow-lg dsEcom-overflow-hidden"
|
447
|
-
:class="[
|
448
|
-
props.inputClass?.includes('rounded') ? props.inputClass : 'dsEcom-rounded-lg',
|
449
|
-
expandedBackgroundClass
|
450
|
-
]"
|
451
|
-
ref="expandedContainer"
|
452
|
-
>
|
453
|
-
<div class="dsEcom-relative">
|
454
|
-
<input
|
455
|
-
v-model="searchQuery"
|
456
|
-
type="text"
|
457
|
-
:placeholder="placeholder"
|
458
|
-
:disabled="isDisabled"
|
459
|
-
:class="[
|
460
|
-
'lau-ecom-input dsEcom-border dsEcom-border-neutral-80 dsEcom-pl-4 dsEcom-pr-24 dsEcom-w-full dsEcom-focus:outline-none dsEcom-focus:ring-2 dsEcom-focus:ring-primary-60',
|
461
|
-
props.inputClass
|
462
|
-
]"
|
463
|
-
@input="handleInput"
|
464
|
-
@keyup.enter="handleSearch"
|
465
|
-
autofocus
|
466
|
-
/>
|
467
|
-
<div class="dsEcom-absolute dsEcom-right-0 dsEcom-inset-y-0 dsEcom-flex dsEcom-items-stretch">
|
468
|
-
<button
|
469
|
-
v-if="searchQuery.length >= 3"
|
470
|
-
@click="clearSearch"
|
471
|
-
:class="[
|
472
|
-
'dsEcom-flex dsEcom-items-center dsEcom-px-1.5 dsEcom-text-neutral-100 hover:dsEcom-text-neutral-80 dsEcom-transition-all dsEcom-duration-300',
|
473
|
-
props.inputClass
|
474
|
-
]"
|
475
|
-
>
|
476
|
-
<LauEcomUpcIconClose width="16" height="16" />
|
477
|
-
</button>
|
478
|
-
|
479
|
-
<button
|
480
|
-
@click="handleSearch"
|
481
|
-
:class="[
|
482
|
-
'dsEcom-flex dsEcom-items-center dsEcom-px-3 dsEcom-transition-all dsEcom-duration-300',
|
483
|
-
{ 'dsEcom-rounded-r-lg': !props.inputClass?.includes('rounded') },
|
484
|
-
props.buttonColorClass,
|
485
|
-
props.buttonTextColorClass,
|
486
|
-
'dsEcom-border-0'
|
487
|
-
]"
|
488
|
-
style="margin: 1px; height: calc(100% - 2px);"
|
489
|
-
>
|
490
|
-
<LauEcomUpcIconSearch width="20" height="20" color="currentColor" />
|
491
|
-
</button>
|
492
|
-
</div>
|
493
|
-
</div>
|
494
|
-
</div>
|
495
|
-
</div>
|
496
|
-
</div>
|
497
|
-
</template>
|
498
|
-
|
499
|
-
<style scoped>
|
500
|
-
.lau-ecom-input {
|
501
|
-
transition: all 0.3s ease-in-out;
|
502
|
-
}
|
503
|
-
|
504
|
-
.dsEcom-transform-gpu {
|
505
|
-
transform: translateZ(0);
|
506
|
-
backface-visibility: hidden;
|
507
|
-
perspective: 1000px;
|
508
|
-
}
|
509
|
-
</style>
|
510
|
-
|
511
|
-
|
1
|
+
<script lang="ts" setup>
|
2
|
+
import { ref, computed } from 'vue';
|
3
|
+
import { LauEcomUpcIconSearch, LauEcomUpcIconClose } from '../LauEcomIcon';
|
4
|
+
|
5
|
+
interface Props {
|
6
|
+
modelValue?: string;
|
7
|
+
placeholder?: string;
|
8
|
+
width?: string;
|
9
|
+
inputClass?: string;
|
10
|
+
inputBorderClass?: string;
|
11
|
+
inputBgClass?: string;
|
12
|
+
inputTextClass?: string;
|
13
|
+
inputFocusClass?: string;
|
14
|
+
|
15
|
+
// Props para el icono de búsqueda
|
16
|
+
searchIconClass?: string;
|
17
|
+
searchIconBgClass?: string;
|
18
|
+
searchIconSize?: {
|
19
|
+
width: string;
|
20
|
+
height: string;
|
21
|
+
};
|
22
|
+
|
23
|
+
// Props para el icono de limpiar
|
24
|
+
clearIconClass?: string;
|
25
|
+
clearIconBgClass?: string;
|
26
|
+
clearIconSize?: {
|
27
|
+
width: string;
|
28
|
+
height: string;
|
29
|
+
};
|
30
|
+
}
|
31
|
+
|
32
|
+
const props = withDefaults(defineProps<Props>(), {
|
33
|
+
modelValue: '',
|
34
|
+
placeholder: 'Buscar...',
|
35
|
+
width: '100%',
|
36
|
+
inputClass: 'dsEcom-rounded-lg',
|
37
|
+
inputBorderClass: 'dsEcom-border dsEcom-border-neutral-80',
|
38
|
+
inputBgClass: 'dsEcom-bg-white',
|
39
|
+
inputTextClass: 'dsEcom-text-neutral-900',
|
40
|
+
inputFocusClass: 'focus:dsEcom-ring-1 focus:dsEcom-ring-primary-60 focus:dsEcom-border-primary-60',
|
41
|
+
|
42
|
+
searchIconClass: 'dsEcom-text-neutral-60',
|
43
|
+
searchIconBgClass: 'dsEcom-bg-transparent',
|
44
|
+
searchIconSize: () => ({ width: '20', height: '20' }),
|
45
|
+
|
46
|
+
clearIconClass: 'dsEcom-text-neutral-60',
|
47
|
+
clearIconBgClass: 'dsEcom-bg-transparent',
|
48
|
+
clearIconSize: () => ({ width: '20', height: '20' })
|
49
|
+
});
|
50
|
+
|
51
|
+
const emit = defineEmits<{
|
52
|
+
(e: 'update:modelValue', value: string): void;
|
53
|
+
(e: 'search', value: string): void;
|
54
|
+
(e: 'clear'): void;
|
55
|
+
(e: 'focus', event: FocusEvent): void;
|
56
|
+
(e: 'blur', event: FocusEvent): void;
|
57
|
+
}>();
|
58
|
+
|
59
|
+
const inputValue = ref(props.modelValue);
|
60
|
+
|
61
|
+
const inputClasses = computed(() => [
|
62
|
+
'dsEcom-w-full',
|
63
|
+
'dsEcom-py-2 dsEcom-pl-4 dsEcom-pr-12',
|
64
|
+
'dsEcom-transition-all dsEcom-duration-300',
|
65
|
+
props.inputClass,
|
66
|
+
props.inputBorderClass,
|
67
|
+
props.inputBgClass,
|
68
|
+
props.inputTextClass,
|
69
|
+
'focus:dsEcom-outline-none',
|
70
|
+
props.inputFocusClass
|
71
|
+
]);
|
72
|
+
|
73
|
+
const handleInput = (event: Event) => {
|
74
|
+
const value = (event.target as HTMLInputElement).value;
|
75
|
+
inputValue.value = value;
|
76
|
+
emit('update:modelValue', value);
|
77
|
+
};
|
78
|
+
|
79
|
+
const handleClear = () => {
|
80
|
+
inputValue.value = '';
|
81
|
+
emit('update:modelValue', '');
|
82
|
+
emit('clear');
|
83
|
+
};
|
84
|
+
|
85
|
+
const handleKeyUp = (event: KeyboardEvent) => {
|
86
|
+
if (event.key === 'Enter' && inputValue.value) {
|
87
|
+
emit('search', inputValue.value);
|
88
|
+
}
|
89
|
+
};
|
90
|
+
</script>
|
91
|
+
|
92
|
+
<template>
|
93
|
+
<div
|
94
|
+
class="dsEcom-relative dsEcom-inline-block"
|
95
|
+
:style="{ width }"
|
96
|
+
>
|
97
|
+
<input
|
98
|
+
type="text"
|
99
|
+
v-model="inputValue"
|
100
|
+
:placeholder="placeholder"
|
101
|
+
:class="inputClasses"
|
102
|
+
@input="handleInput"
|
103
|
+
@keyup="handleKeyUp"
|
104
|
+
@focus="(e) => emit('focus', e)"
|
105
|
+
@blur="(e) => emit('blur', e)"
|
106
|
+
/>
|
107
|
+
|
108
|
+
<!-- Botón de limpiar -->
|
109
|
+
<button
|
110
|
+
v-if="inputValue"
|
111
|
+
type="button"
|
112
|
+
@click="handleClear"
|
113
|
+
:class="[
|
114
|
+
'dsEcom-absolute dsEcom-right-8 dsEcom-top-1/2 dsEcom-transform dsEcom--translate-y-1/2',
|
115
|
+
'dsEcom-p-1 dsEcom-rounded-full dsEcom-transition-colors dsEcom-duration-300',
|
116
|
+
clearIconBgClass,
|
117
|
+
'hover:dsEcom-opacity-80'
|
118
|
+
]"
|
119
|
+
>
|
120
|
+
<LauEcomUpcIconClose
|
121
|
+
:width="clearIconSize.width"
|
122
|
+
:height="clearIconSize.height"
|
123
|
+
:class="[clearIconClass, 'dsEcom-transition-colors dsEcom-duration-300']"
|
124
|
+
/>
|
125
|
+
</button>
|
126
|
+
|
127
|
+
<!-- Icono de búsqueda -->
|
128
|
+
<button
|
129
|
+
type="button"
|
130
|
+
:class="[
|
131
|
+
'dsEcom-absolute dsEcom-right-0 dsEcom-top-0 dsEcom-bottom-0',
|
132
|
+
'dsEcom-flex dsEcom-items-center dsEcom-justify-center',
|
133
|
+
'dsEcom-px-4',
|
134
|
+
'dsEcom-transition-colors dsEcom-duration-300',
|
135
|
+
'dsEcom-rounded-r-lg',
|
136
|
+
searchIconBgClass,
|
137
|
+
'hover:dsEcom-opacity-80'
|
138
|
+
]"
|
139
|
+
@click="$emit('search', inputValue)"
|
140
|
+
>
|
141
|
+
<LauEcomUpcIconSearch
|
142
|
+
:width="searchIconSize.width"
|
143
|
+
:height="searchIconSize.height"
|
144
|
+
:class="[searchIconClass, 'dsEcom-transition-colors dsEcom-duration-300']"
|
145
|
+
/>
|
146
|
+
</button>
|
147
|
+
</div>
|
148
|
+
</template>
|
149
|
+
|
150
|
+
<style scoped>
|
151
|
+
.dsEcom-transform {
|
152
|
+
transform: translateY(-50%);
|
153
|
+
}
|
154
|
+
</style>
|