lau-ecom-design-system 1.0.21 β†’ 1.0.23

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.
@@ -1,244 +1,511 @@
1
- <script lang="ts" setup>
2
- import { ref, computed, onMounted, onBeforeUnmount, watch, nextTick } from "vue";
3
- import {
4
- LauEcomUpcIconCheck as LauEcomUpcIconSearch,
5
- LauEcomCoreIconNavClose as LauEcomUpcIconClose,
6
- } from "../LauEcomIcon";
7
-
8
- // Log de versiΓ³n del componente
9
- console.log('πŸ” InputSearch Version: 1.0.20 - Debug Mode');
10
-
11
- interface Props {
12
- placeholder?: string;
13
- isDisabled?: boolean;
14
- modelValue?: string;
15
- forceClose?: boolean;
16
- }
17
-
18
- const props = withDefaults(defineProps<Props>(), {
19
- placeholder: "Quiero aprender...",
20
- isDisabled: false,
21
- modelValue: "",
22
- forceClose: false,
23
- });
24
-
25
- // Log de props iniciales
26
- console.log('πŸ” InputSearch Props:', {
27
- placeholder: props.placeholder,
28
- isDisabled: props.isDisabled,
29
- modelValue: props.modelValue,
30
- forceClose: props.forceClose
31
- });
32
-
33
- const emit = defineEmits({
34
- "update:modelValue": (value: string) => true,
35
- "search": (value: string) => true,
36
- });
37
-
38
- const searchQuery = ref(props.modelValue);
39
- const isExpanded = ref(false);
40
- const showOverlay = ref(false);
41
-
42
- const handleSearch = () => {
43
- console.log('πŸ” Search triggered:', {
44
- query: searchQuery.value,
45
- isExpanded: isExpanded.value,
46
- showOverlay: showOverlay.value
47
- });
48
-
49
- if (searchQuery.value && searchQuery.value.trim()) {
50
- emit("search", searchQuery.value);
51
- emit("update:modelValue", searchQuery.value);
52
- closeSearch();
53
- }
54
- };
55
-
56
- const handleInput = () => {
57
- console.log('πŸ” Input changed:', {
58
- value: searchQuery.value,
59
- length: searchQuery.value.length,
60
- isExpanded: isExpanded.value
61
- });
62
- emit("update:modelValue", searchQuery.value);
63
- };
64
-
65
- const clearSearch = () => {
66
- console.log('πŸ” Clear search triggered');
67
- searchQuery.value = "";
68
- emit("update:modelValue", "");
69
- };
70
-
71
- const closeSearch = () => {
72
- console.log('πŸ” Close search triggered');
73
- showOverlay.value = false;
74
- setTimeout(() => {
75
- console.log('πŸ” Closing search after timeout');
76
- isExpanded.value = false;
77
- }, 300);
78
- };
79
-
80
- const handleFocus = () => {
81
- console.log('πŸ” Focus triggered:', {
82
- currentValue: searchQuery.value,
83
- wasExpanded: isExpanded.value
84
- });
85
- isExpanded.value = true;
86
- showOverlay.value = true;
87
- };
88
-
89
- const containerClasses = computed(() => {
90
- const classes = [
91
- "dsEcom-transition-transform dsEcom-duration-300 dsEcom-ease-in-out",
92
- {
93
- "dsEcom-relative dsEcom-w-[250px] md:dsEcom-w-[350px]": !isExpanded.value
94
- }
95
- ];
96
- console.log('πŸ” Container classes updated:', { isExpanded: isExpanded.value });
97
- return classes;
98
- });
99
-
100
- const overlayClasses = computed(() => [
101
- "dsEcom-fixed dsEcom-inset-0 dsEcom-bg-black dsEcom-transition-opacity dsEcom-duration-300 dsEcom-ease-in-out dsEcom-z-40",
102
- {
103
- "dsEcom-opacity-50": showOverlay.value,
104
- "dsEcom-opacity-0 dsEcom-pointer-events-none": !showOverlay.value
105
- }
106
- ]);
107
-
108
- const originalContainer = ref<HTMLElement | null>(null);
109
- const expandedContainer = ref<HTMLElement | null>(null);
110
-
111
- const updateExpandedPosition = () => {
112
- if (originalContainer.value && expandedContainer.value) {
113
- const rect = originalContainer.value.getBoundingClientRect();
114
- const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
115
- expandedContainer.value.style.top = `${rect.top + scrollTop}px`;
116
- console.log('πŸ” Updated expanded position:', { top: rect.top + scrollTop });
117
- }
118
- };
119
-
120
- onMounted(() => {
121
- console.log('πŸ” Component mounted');
122
- window.addEventListener('resize', updateExpandedPosition);
123
- });
124
-
125
- onBeforeUnmount(() => {
126
- console.log('πŸ” Component will unmount');
127
- window.removeEventListener('resize', updateExpandedPosition);
128
- });
129
-
130
- watch(isExpanded, (newValue) => {
131
- console.log('πŸ” isExpanded changed:', {
132
- newValue,
133
- searchQuery: searchQuery.value,
134
- showOverlay: showOverlay.value
135
- });
136
- if (newValue) {
137
- nextTick(updateExpandedPosition);
138
- }
139
- });
140
-
141
- watch(() => props.forceClose, (newValue) => {
142
- console.log('πŸ” forceClose prop changed:', newValue);
143
- if (newValue) {
144
- closeSearch();
145
- }
146
- });
147
-
148
- watch(() => props.modelValue, (newValue) => {
149
- console.log('πŸ” modelValue prop changed:', {
150
- newValue,
151
- currentSearchQuery: searchQuery.value
152
- });
153
- if (newValue !== searchQuery.value) {
154
- searchQuery.value = newValue;
155
- }
156
- });
157
- </script>
158
-
159
- <template>
160
- <div class="dsEcom-relative">
161
- <div
162
- :class="containerClasses"
163
- ref="originalContainer"
164
- >
165
- <input
166
- v-model="searchQuery"
167
- type="text"
168
- :placeholder="placeholder"
169
- :disabled="isDisabled"
170
- class="lau-ecom-input dsEcom-border dsEcom-border-neutral-80 dsEcom-rounded-lg dsEcom-px-4 dsEcom-h-10 dsEcom-w-full dsEcom-focus:outline-none dsEcom-focus:ring-2 dsEcom-focus:ring-primary-60"
171
- @focus="handleFocus"
172
- @input="handleInput"
173
- @keyup.enter="handleSearch"
174
- :class="{ 'dsEcom-invisible': isExpanded }"
175
- />
176
- <button
177
- v-if="searchQuery.length >= 3 && !isExpanded"
178
- @click="handleSearch"
179
- class="dsEcom-absolute dsEcom-right-2 dsEcom-top-1/2 -dsEcom-translate-y-1/2 dsEcom-bg-primary-60 hover:dsEcom-bg-primary-70 dsEcom-text-white dsEcom-p-2 dsEcom-rounded-lg dsEcom-transition-all dsEcom-duration-300"
180
- >
181
- <LauEcomUpcIconSearch width="20" height="20" />
182
- </button>
183
- </div>
184
-
185
- <!-- Overlay -->
186
- <div
187
- :class="overlayClasses"
188
- @click="closeSearch"
189
- ></div>
190
-
191
- <!-- VersiΓ³n expandida -->
192
- <div
193
- v-show="isExpanded"
194
- class="dsEcom-fixed dsEcom-w-[656px] dsEcom-left-1/2 dsEcom-transform -dsEcom-translate-x-1/2 dsEcom-z-50"
195
- :style="{ top: isExpanded ? `${originalContainer?.getBoundingClientRect().top}px` : '0' }"
196
- ref="expandedContainer"
197
- >
198
- <div class="dsEcom-relative">
199
- <input
200
- v-model="searchQuery"
201
- type="text"
202
- :placeholder="placeholder"
203
- :disabled="isDisabled"
204
- class="lau-ecom-input dsEcom-border dsEcom-border-neutral-80 dsEcom-rounded-lg dsEcom-px-4 dsEcom-h-10 dsEcom-w-full dsEcom-focus:outline-none dsEcom-focus:ring-2 dsEcom-focus:ring-primary-60 dsEcom-bg-white"
205
- @input="handleInput"
206
- @keyup.enter="handleSearch"
207
- autofocus
208
- />
209
-
210
- <div class="dsEcom-absolute dsEcom-right-2 dsEcom-top-1/2 -dsEcom-translate-y-1/2 dsEcom-flex dsEcom-gap-2">
211
- <button
212
- v-if="searchQuery.length >= 3"
213
- @click="clearSearch"
214
- class="dsEcom-text-neutral-100 hover:dsEcom-text-neutral-80 dsEcom-transition-all dsEcom-duration-300"
215
- >
216
- <LauEcomUpcIconClose width="16" height="16" />
217
- </button>
218
-
219
- <button
220
- v-if="searchQuery.length >= 3"
221
- @click="handleSearch"
222
- class="dsEcom-bg-primary-60 hover:dsEcom-bg-primary-70 dsEcom-text-white dsEcom-p-2 dsEcom-rounded-lg dsEcom-transition-all dsEcom-duration-300"
223
- >
224
- <LauEcomUpcIconSearch width="20" height="20" />
225
- </button>
226
- </div>
227
- </div>
228
- </div>
229
- </div>
230
- </template>
231
-
232
- <style scoped>
233
- .lau-ecom-input {
234
- transition: all 0.3s ease-in-out;
235
- }
236
-
237
- .dsEcom-transform-gpu {
238
- transform: translateZ(0);
239
- backface-visibility: hidden;
240
- perspective: 1000px;
241
- }
242
- </style>
243
-
1
+ <script lang="ts" setup>
2
+ import { ref, computed, onMounted, onBeforeUnmount, watch, nextTick } from "vue";
3
+ import {
4
+ LauEcomUpcIconSearch,
5
+ LauEcomCoreIconNavClose as LauEcomUpcIconClose,
6
+ LauEcomUpcIconNavArrow,
7
+ } from "../LauEcomIcon";
8
+
9
+ // Log de versiΓ³n del componente
10
+ console.log('πŸ” InputSearch Version: 1.0.25 - Debug Mode');
11
+
12
+ interface Props {
13
+ placeholder?: string;
14
+ isDisabled?: boolean;
15
+ modelValue?: string;
16
+ forceClose?: boolean;
17
+ buttonColorClass?: string;
18
+ buttonTextColorClass?: string;
19
+ buttonClass?: string;
20
+ inputClass?: string;
21
+ containerClass?: string;
22
+ expandedWidth?: string;
23
+ isMobileSearch?: boolean;
24
+ arrowColorClass?: string;
25
+ arrowButtonClass?: string;
26
+ mobileInputWidth?: string;
27
+ mobileInputHeight?: string;
28
+ mobilePanelClass?: string;
29
+ expandedBackgroundClass?: string;
30
+ overlayClass?: string;
31
+ }
32
+
33
+ const props = withDefaults(defineProps<Props>(), {
34
+ placeholder: "Quiero aprender...",
35
+ isDisabled: false,
36
+ modelValue: "",
37
+ forceClose: false,
38
+ buttonColorClass: "dsEcom-bg-primary-60 hover:dsEcom-bg-primary-70",
39
+ buttonTextColorClass: "dsEcom-text-white",
40
+ buttonClass: "",
41
+ inputClass: "dsEcom-h-10 dsEcom-rounded-lg",
42
+ containerClass: "",
43
+ expandedWidth: "50vw",
44
+ isMobileSearch: false,
45
+ arrowColorClass: "dsEcom-text-neutral-100",
46
+ arrowButtonClass: "",
47
+ mobileInputWidth: "240px",
48
+ mobileInputHeight: "40px",
49
+ mobilePanelClass: "dsEcom-bg-white",
50
+ expandedBackgroundClass: "dsEcom-bg-white",
51
+ overlayClass: "dsEcom-bg-black dsEcom-opacity-50"
52
+ });
53
+
54
+ // Log de props iniciales
55
+ console.log('πŸ” InputSearch Props:', {
56
+ placeholder: props.placeholder,
57
+ isDisabled: props.isDisabled,
58
+ modelValue: props.modelValue,
59
+ forceClose: props.forceClose
60
+ });
61
+
62
+ const emit = defineEmits({
63
+ "update:modelValue": (value: string) => true,
64
+ "search": (value: string) => true,
65
+ "click:search-icon": () => true
66
+ });
67
+
68
+ const searchQuery = ref(props.modelValue);
69
+ const isExpanded = ref(false);
70
+ const showOverlay = ref(false);
71
+
72
+ const isMobileView = ref(false);
73
+ const isMobileSearchOpen = ref(false);
74
+
75
+ const handleSearch = () => {
76
+ console.log('πŸ” Search triggered:', {
77
+ query: searchQuery.value,
78
+ isExpanded: isExpanded.value,
79
+ showOverlay: showOverlay.value
80
+ });
81
+
82
+ if (searchQuery.value && searchQuery.value.trim()) {
83
+ emit("search", searchQuery.value);
84
+ emit("update:modelValue", searchQuery.value);
85
+ emit("click:search-icon");
86
+ closeSearch();
87
+ }
88
+ };
89
+
90
+ const handleInput = () => {
91
+ console.log('πŸ” Input changed:', {
92
+ value: searchQuery.value,
93
+ length: searchQuery.value.length,
94
+ isExpanded: isExpanded.value
95
+ });
96
+ emit("update:modelValue", searchQuery.value);
97
+ };
98
+
99
+ const clearSearch = () => {
100
+ console.log('πŸ” Clear search triggered');
101
+ searchQuery.value = "";
102
+ emit("update:modelValue", "");
103
+ };
104
+
105
+ const closeSearch = () => {
106
+ console.log('πŸ” Close search triggered');
107
+ showOverlay.value = false;
108
+ setTimeout(() => {
109
+ console.log('πŸ” Closing search after timeout');
110
+ isExpanded.value = false;
111
+ }, 300);
112
+ };
113
+
114
+ const handleFocus = () => {
115
+ console.log('πŸ” Focus triggered:', {
116
+ currentValue: searchQuery.value,
117
+ wasExpanded: isExpanded.value
118
+ });
119
+ isExpanded.value = true;
120
+ showOverlay.value = true;
121
+ };
122
+
123
+ const containerClasses = computed(() => {
124
+ const classes = [
125
+ "dsEcom-transition-transform dsEcom-duration-300 dsEcom-ease-in-out dsEcom-relative",
126
+ {
127
+ "dsEcom-w-[250px] md:dsEcom-w-[350px]": !isExpanded.value
128
+ }
129
+ ];
130
+ console.log('πŸ” Container classes updated:', { isExpanded: isExpanded.value });
131
+ return classes;
132
+ });
133
+
134
+ const overlayClasses = computed(() => [
135
+ "dsEcom-fixed dsEcom-inset-0 dsEcom-transition-opacity dsEcom-duration-300 dsEcom-ease-in-out dsEcom-z-40",
136
+ props.overlayClass,
137
+ {
138
+ "dsEcom-opacity-100": showOverlay.value,
139
+ "dsEcom-opacity-0 dsEcom-pointer-events-none": !showOverlay.value
140
+ }
141
+ ]);
142
+
143
+ const originalContainer = ref<HTMLElement | null>(null);
144
+ const expandedContainer = ref<HTMLElement | null>(null);
145
+
146
+ const updateExpandedPosition = () => {
147
+ if (originalContainer.value && expandedContainer.value) {
148
+ const rect = originalContainer.value.getBoundingClientRect();
149
+ const viewportHeight = window.innerHeight;
150
+ const viewportWidth = window.innerWidth;
151
+
152
+ let topPosition;
153
+ if (rect.top < 0) {
154
+ topPosition = '20px';
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
+
244
511