@glatam/calendar-ui 1.0.0

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.
@@ -0,0 +1,1518 @@
1
+ import { css as E, LitElement as O, html as d } from "lit";
2
+ import { property as s, customElement as T, state as m } from "lit/decorators.js";
3
+ import { isTimeBlocked as M, formatISODate as N, generateMonthDays as j, generateWeekDays as _ } from "@glatam/calendar-core";
4
+ import { formatISODate as st, isTimeBlocked as lt, parseISODate as nt } from "@glatam/calendar-core";
5
+ import { classMap as I } from "lit/directives/class-map.js";
6
+ const A = E`
7
+ :host {
8
+ /* Fonts */
9
+ --glatam-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
10
+
11
+ /* Colors - Premium Apple Light Theme */
12
+ --glatam-primary: #5856d6;
13
+ --glatam-primary-hover: #4745b4;
14
+ --glatam-primary-light: rgba(88, 86, 214, 0.1);
15
+ --glatam-primary-light-hover: rgba(88, 86, 214, 0.25);
16
+
17
+ --glatam-bg: #ffffff;
18
+ --glatam-surface: #f5f5f7;
19
+ --glatam-border: #e5e5ea;
20
+ --glatam-text: #1d1d1f;
21
+ --glatam-text-secondary: #86868b;
22
+ --glatam-text-light: #ffffff;
23
+
24
+ /* Blocked/Unavailable states */
25
+ --glatam-blocked-bg: #fcfcfd;
26
+ --glatam-blocked-stripe: #f2f2f7;
27
+ --glatam-blocked-text: #aeaeae;
28
+ --glatam-blocked-border: #e5e5ea;
29
+
30
+ /* Selection Colors */
31
+ --glatam-selection-bg: rgba(88, 86, 214, 0.15);
32
+ --glatam-selection-border: #5856d6;
33
+
34
+ /* Today highlighting */
35
+ --glatam-today-text: #5856d6;
36
+ --glatam-today-bg: rgba(88, 86, 214, 0.08);
37
+
38
+ /* Dimensions & Layout */
39
+ --glatam-border-radius: 12px;
40
+ --glatam-padding: 16px;
41
+ --glatam-grid-border-radius: 8px;
42
+ --glatam-day-min-height: 72px;
43
+ --glatam-time-col-width: 60px;
44
+ --glatam-slot-height: 48px;
45
+
46
+ /* Animation duration */
47
+ --glatam-transition-fast: 0.15s ease;
48
+ --glatam-transition-normal: 0.25s ease;
49
+ }
50
+
51
+ :host(.dark-mode) {
52
+ /* Colors - Premium Apple Dark Theme */
53
+ --glatam-primary: #5e5ce6;
54
+ --glatam-primary-hover: #7d7aff;
55
+ --glatam-primary-light: rgba(94, 92, 230, 0.15);
56
+ --glatam-primary-light-hover: rgba(94, 92, 230, 0.3);
57
+
58
+ --glatam-bg: #1c1c1e;
59
+ --glatam-surface: #2c2c2e;
60
+ --glatam-border: #38383a;
61
+ --glatam-text: #f5f5f7;
62
+ --glatam-text-secondary: #8e8e93;
63
+
64
+ /* Blocked/Unavailable states */
65
+ --glatam-blocked-bg: #242426;
66
+ --glatam-blocked-stripe: #2c2c2e;
67
+ --glatam-blocked-text: #707074;
68
+ --glatam-blocked-border: #38383a;
69
+
70
+ /* Selection Colors */
71
+ --glatam-selection-bg: rgba(94, 92, 230, 0.25);
72
+ --glatam-selection-border: #5e5ce6;
73
+
74
+ /* Today highlighting */
75
+ --glatam-today-text: #7d7aff;
76
+ --glatam-today-bg: rgba(94, 92, 230, 0.12);
77
+ }
78
+
79
+ :host([size="small"]) {
80
+ --glatam-day-min-height: 48px;
81
+ --glatam-slot-height: 36px;
82
+ --glatam-time-col-width: 48px;
83
+ --glatam-padding: 10px;
84
+ font-size: 0.8rem;
85
+ }
86
+
87
+ :host([size="large"]) {
88
+ --glatam-day-min-height: 96px;
89
+ --glatam-slot-height: 60px;
90
+ --glatam-time-col-width: 72px;
91
+ --glatam-padding: 24px;
92
+ font-size: 1.1rem;
93
+ }
94
+ `, P = E`
95
+ :host {
96
+ display: grid;
97
+ min-width: 0;
98
+ font-family: var(--glatam-font-family);
99
+ color: var(--glatam-text);
100
+ background-color: var(--glatam-bg);
101
+ border-radius: var(--glatam-border-radius);
102
+ padding: var(--glatam-padding);
103
+ box-shadow: 0 4px 25px rgba(0, 0, 0, 0.05);
104
+ border: 1px solid var(--glatam-border);
105
+ box-sizing: border-box;
106
+ width: 100%;
107
+ max-width: 100%;
108
+ overflow: hidden;
109
+ transition: background-color var(--glatam-transition-normal), border-color var(--glatam-transition-normal);
110
+ }
111
+
112
+ *, *::before, *::after {
113
+ box-sizing: border-box;
114
+ }
115
+
116
+ .calendar-header {
117
+ display: flex;
118
+ justify-content: space-between;
119
+ align-items: center;
120
+ margin-bottom: var(--glatam-padding);
121
+ flex-wrap: wrap;
122
+ gap: 12px;
123
+ }
124
+
125
+ .nav-group, .view-group {
126
+ display: flex;
127
+ align-items: center;
128
+ gap: 8px;
129
+ }
130
+
131
+ .nav-title {
132
+ font-size: 1.25rem;
133
+ font-weight: 600;
134
+ min-width: 140px;
135
+ text-align: center;
136
+ letter-spacing: -0.01em;
137
+ }
138
+
139
+ .btn {
140
+ font-family: inherit;
141
+ font-size: 0.875rem;
142
+ font-weight: 500;
143
+ padding: 8px 12px;
144
+ border-radius: 8px;
145
+ border: 1px solid var(--glatam-border);
146
+ background-color: var(--glatam-bg);
147
+ color: var(--glatam-text);
148
+ cursor: pointer;
149
+ transition: background-color var(--glatam-transition-fast), border-color var(--glatam-transition-fast), transform var(--glatam-transition-fast);
150
+ display: inline-flex;
151
+ align-items: center;
152
+ justify-content: center;
153
+ min-width: 36px;
154
+ height: 36px;
155
+ }
156
+
157
+ .btn:hover:not(:disabled) {
158
+ background-color: var(--glatam-surface);
159
+ border-color: var(--glatam-text-secondary);
160
+ }
161
+
162
+ .btn:active:not(:disabled) {
163
+ transform: scale(0.97);
164
+ }
165
+
166
+ .btn:disabled {
167
+ opacity: 0.5;
168
+ cursor: not-allowed;
169
+ }
170
+
171
+ .btn-primary {
172
+ background-color: var(--glatam-primary);
173
+ color: var(--glatam-text-light);
174
+ border: none;
175
+ }
176
+
177
+ .btn-primary:hover:not(:disabled) {
178
+ background-color: var(--glatam-primary-hover);
179
+ }
180
+
181
+ .btn-group {
182
+ display: flex;
183
+ border-radius: 8px;
184
+ overflow: hidden;
185
+ border: 1px solid var(--glatam-border);
186
+ }
187
+
188
+ .btn-group .btn {
189
+ border-radius: 0;
190
+ border: none;
191
+ border-right: 1px solid var(--glatam-border);
192
+ }
193
+
194
+ .btn-group .btn:last-child {
195
+ border-right: none;
196
+ }
197
+
198
+ .btn-group .btn.active {
199
+ background-color: var(--glatam-primary-light);
200
+ color: var(--glatam-primary);
201
+ font-weight: 600;
202
+ }
203
+
204
+ /* Timezone Selector Styles */
205
+ .timezone-badge {
206
+ font-size: 0.75rem;
207
+ padding: 4px 8px;
208
+ background: var(--glatam-surface);
209
+ border: 1px solid var(--glatam-border);
210
+ border-radius: 20px;
211
+ display: inline-flex;
212
+ align-items: center;
213
+ gap: 4px;
214
+ color: var(--glatam-text-secondary);
215
+ }
216
+
217
+ .timezone-select {
218
+ background: transparent;
219
+ border: none;
220
+ color: var(--glatam-text);
221
+ font-family: inherit;
222
+ font-size: 0.75rem;
223
+ font-weight: 600;
224
+ cursor: pointer;
225
+ outline: none;
226
+ padding-right: 4px;
227
+ }
228
+
229
+ /* Mini Popover Variant Styles */
230
+ .dropdown-container {
231
+ position: relative;
232
+ display: inline-block;
233
+ width: 100%;
234
+ }
235
+
236
+ .dropdown-toggle {
237
+ width: 100%;
238
+ justify-content: space-between;
239
+ padding: 12px 16px;
240
+ border-radius: 12px;
241
+ font-weight: 600;
242
+ height: 48px;
243
+ }
244
+
245
+ .dropdown-card {
246
+ position: absolute;
247
+ top: calc(100% + 8px);
248
+ left: 0;
249
+ width: 320px;
250
+ background: var(--glatam-bg);
251
+ border-radius: 16px;
252
+ border: 1px solid var(--glatam-border);
253
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1);
254
+ z-index: 100;
255
+ padding: 16px;
256
+ display: flex;
257
+ flex-direction: column;
258
+ gap: 12px;
259
+ animation: fadeInUp 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
260
+ }
261
+
262
+ .slot-list {
263
+ display: flex;
264
+ flex-direction: column;
265
+ gap: 8px;
266
+ max-height: 220px;
267
+ overflow-y: auto;
268
+ padding-right: 4px;
269
+ }
270
+
271
+ .slot-btn {
272
+ width: 100%;
273
+ padding: 10px;
274
+ border-radius: 8px;
275
+ border: 1px solid var(--glatam-border);
276
+ background: var(--glatam-bg);
277
+ color: var(--glatam-text);
278
+ cursor: pointer;
279
+ font-family: inherit;
280
+ font-size: 0.85rem;
281
+ font-weight: 500;
282
+ text-align: center;
283
+ transition: background-color var(--glatam-transition-fast);
284
+ }
285
+
286
+ .slot-btn:hover:not(.blocked) {
287
+ background-color: var(--glatam-surface);
288
+ border-color: var(--glatam-text-secondary);
289
+ }
290
+
291
+ .slot-btn.blocked {
292
+ background-color: var(--glatam-surface);
293
+ color: var(--glatam-blocked-text);
294
+ text-decoration: line-through;
295
+ cursor: not-allowed;
296
+ border-color: var(--glatam-border);
297
+ opacity: 0.6;
298
+ }
299
+
300
+ /* Smooth Apple Animation */
301
+ .calendar-body {
302
+ position: relative;
303
+ width: 100%;
304
+ overflow-x: auto;
305
+ animation: fadeInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
306
+ }
307
+
308
+ @keyframes fadeInUp {
309
+ from {
310
+ opacity: 0;
311
+ transform: translateY(8px) scale(0.995);
312
+ }
313
+ to {
314
+ opacity: 1;
315
+ transform: translateY(0) scale(1);
316
+ }
317
+ }
318
+
319
+ @media (max-width: 600px) {
320
+ :host {
321
+ padding: 8px;
322
+ }
323
+ .calendar-header {
324
+ flex-direction: column;
325
+ align-items: stretch;
326
+ gap: 10px;
327
+ }
328
+ .nav-group, .view-group {
329
+ width: 100%;
330
+ justify-content: space-between;
331
+ flex-wrap: wrap;
332
+ gap: 6px;
333
+ }
334
+ .nav-title {
335
+ flex: 1;
336
+ font-size: 1.1rem;
337
+ min-width: unset;
338
+ text-align: right;
339
+ white-space: nowrap;
340
+ overflow: hidden;
341
+ text-overflow: ellipsis;
342
+ }
343
+ .btn {
344
+ font-size: 0.8rem;
345
+ padding: 6px 10px;
346
+ height: 32px;
347
+ min-width: 32px;
348
+ }
349
+ }
350
+ `;
351
+ function C(e, t, a) {
352
+ if (t === a) return 0;
353
+ const i = (r, l) => {
354
+ const o = {
355
+ year: "numeric",
356
+ month: "numeric",
357
+ day: "numeric",
358
+ hour: "numeric",
359
+ minute: "numeric",
360
+ second: "numeric",
361
+ hour12: !1
362
+ };
363
+ l !== "local" && (o.timeZone = l);
364
+ const n = new Intl.DateTimeFormat("en-US", o).formatToParts(r), g = new Map(n.map((S) => [S.type, S.value])), u = Number(g.get("hour")), v = u === 24 ? 0 : u;
365
+ return new Date(
366
+ Number(g.get("year")),
367
+ Number(g.get("month")) - 1,
368
+ Number(g.get("day")),
369
+ v,
370
+ Number(g.get("minute")),
371
+ Number(g.get("second"))
372
+ );
373
+ };
374
+ try {
375
+ const r = i(e, t);
376
+ return (i(e, a).getTime() - r.getTime()) / (60 * 1e3);
377
+ } catch {
378
+ return 0;
379
+ }
380
+ }
381
+ function W(e, t) {
382
+ if (t === 0)
383
+ return { start: e.start, end: e.end, dayShift: 0 };
384
+ const a = (g) => {
385
+ const [u, v] = g.split(":").map(Number);
386
+ return u * 60 + v;
387
+ }, i = (g) => {
388
+ let u = g % 1440;
389
+ u < 0 && (u += 1440);
390
+ const v = String(Math.floor(u / 60)).padStart(2, "0"), S = String(u % 60).padStart(2, "0");
391
+ return `${v}:${S}`;
392
+ }, r = a(e.start), l = a(e.end), o = r + t, c = l + t;
393
+ let n = 0;
394
+ return o < 0 ? n = -1 : o >= 1440 && (n = 1), {
395
+ start: i(o),
396
+ end: i(c),
397
+ dayShift: n
398
+ };
399
+ }
400
+ var U = Object.defineProperty, L = Object.getOwnPropertyDescriptor, k = (e, t, a, i) => {
401
+ for (var r = i > 1 ? void 0 : i ? L(t, a) : t, l = e.length - 1, o; l >= 0; l--)
402
+ (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
403
+ return i && r && U(t, a, r), r;
404
+ };
405
+ let f = class extends O {
406
+ constructor() {
407
+ super(...arguments), this.days = [], this.locale = "es", this.startOfWeekDay = 0, this.selectedDates = [], this.role = "provider", this.size = "medium", this.minDate = "", this.maxDate = "", this.showNeighboringMonth = !0, this.tileClassName = null;
408
+ }
409
+ getWeekdayNames() {
410
+ const e = [], t = new Date(2026, 6, 12 + this.startOfWeekDay), a = new Intl.DateTimeFormat(this.locale, { weekday: "short" });
411
+ for (let i = 0; i < 7; i++)
412
+ e.push(a.format(t)), t.setDate(t.getDate() + 1);
413
+ return e;
414
+ }
415
+ handleDayClick(e) {
416
+ this.role === "buyer" && e.isBlocked || this.dispatchEvent(new CustomEvent("day-select", {
417
+ detail: { dateString: e.dateString, isBlocked: e.isBlocked },
418
+ bubbles: !0,
419
+ composed: !0
420
+ }));
421
+ }
422
+ render() {
423
+ const e = this.getWeekdayNames();
424
+ return d`
425
+ ${e.map((t) => d`<div class="weekday">${t}</div>`)}
426
+
427
+ ${this.days.map((t) => {
428
+ var c;
429
+ if (!t.isCurrentMonth && !this.showNeighboringMonth)
430
+ return d`<div class="day-cell empty"></div>`;
431
+ const a = t.dateString === (/* @__PURE__ */ new Date()).toISOString().split("T")[0], i = this.selectedDates.includes(t.dateString), r = t.slots.filter((n) => n.isBlocked), l = this.minDate && t.dateString < this.minDate || this.maxDate && t.dateString > this.maxDate, o = this.tileClassName ? this.tileClassName({ date: t.date, dateString: t.dateString }) : "";
432
+ return d`
433
+ <div
434
+ class=${I({
435
+ "day-cell": !0,
436
+ padding: !t.isCurrentMonth,
437
+ blocked: t.isBlocked,
438
+ today: a,
439
+ selected: i,
440
+ disabled: !!l,
441
+ [o]: !!o
442
+ })}
443
+ part="day-cell ${o}"
444
+ @click=${() => this.handleDayClick(t)}
445
+ >
446
+ <div class="day-number">${t.dayNumber}</div>
447
+
448
+ <div class="slot-indicator">
449
+ ${t.isBlocked ? d`<div class="badge blocked-day">${((c = t.rule) == null ? void 0 : c.description) || "Bloqueado"}</div>` : r.slice(0, 2).map((n) => {
450
+ var g, u;
451
+ return d`
452
+ <div class="badge blocked-slot" title=${((g = n.rule) == null ? void 0 : g.description) || ""}>
453
+ 🚫 ${((u = n.rule) == null ? void 0 : u.description) || n.start}
454
+ </div>
455
+ `;
456
+ })}
457
+ ${!t.isBlocked && r.length > 2 ? d`<div style="text-align: center; font-size: 0.65rem; color: var(--glatam-text-secondary);">+${r.length - 2} tareas</div>` : ""}
458
+ </div>
459
+ </div>
460
+ `;
461
+ })}
462
+ `;
463
+ }
464
+ };
465
+ f.styles = E`
466
+ :host { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; width: 100%; }
467
+ .weekday { font-size: 0.75rem; font-weight: 600; color: var(--glatam-text-secondary); text-transform: uppercase; text-align: center; padding: 8px 0; letter-spacing: 0.05em; }
468
+ .day-cell {
469
+ min-height: var(--glatam-day-min-height); border: 1px solid var(--glatam-border); border-radius: var(--glatam-grid-border-radius);
470
+ padding: 8px; display: flex; flex-direction: column; justify-content: space-between; cursor: pointer;
471
+ transition: background-color var(--glatam-transition-fast), border-color var(--glatam-transition-fast); background-color: var(--glatam-bg); position: relative;
472
+ }
473
+ .day-cell:hover:not(.blocked):not(.disabled) { background-color: var(--glatam-surface); border-color: var(--glatam-text-secondary); }
474
+ .day-cell.padding { opacity: 0.4; }
475
+ .day-cell.blocked {
476
+ background: repeating-linear-gradient(45deg, var(--glatam-blocked-bg), var(--glatam-blocked-bg) 10px, var(--glatam-blocked-stripe) 10px, var(--glatam-blocked-stripe) 20px);
477
+ border-color: var(--glatam-blocked-border); color: var(--glatam-blocked-text); cursor: not-allowed;
478
+ }
479
+ .day-cell.today { background-color: var(--glatam-today-bg); border-color: var(--glatam-primary); }
480
+ .day-cell.selected { background-color: var(--glatam-selection-bg); border-color: var(--glatam-selection-border); box-shadow: inset 0 0 0 1px var(--glatam-selection-border); }
481
+ .day-cell.disabled { opacity: 0.2; cursor: not-allowed; background-color: var(--glatam-surface); border-color: var(--glatam-border); pointer-events: none; }
482
+ .day-cell.empty { border: none; background: transparent; cursor: default; pointer-events: none; }
483
+ .day-number { font-size: 0.875rem; font-weight: 500; margin-bottom: 4px; }
484
+ .day-cell.today .day-number { color: var(--glatam-today-text); font-weight: 700; }
485
+ .slot-indicator { display: flex; flex-direction: column; gap: 3px; font-size: 0.7rem; overflow: hidden; margin-top: 4px; }
486
+ .badge { padding: 2px 6px; border-radius: 4px; font-weight: 500; text-align: center; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }
487
+ .badge.blocked-day { background-color: rgba(255, 69, 58, 0.12); color: #ff453a; font-weight: 600; }
488
+ .badge.blocked-slot { background-color: var(--glatam-surface); border: 1px solid var(--glatam-border); color: var(--glatam-text-secondary); }
489
+ :host([size="small"]) .day-cell { min-height: 38px; padding: 4px; justify-content: center; align-items: center; }
490
+ :host([size="small"]) .slot-indicator { display: none; }
491
+ :host([size="small"]) .day-number { margin-bottom: 0; font-size: 0.8rem; }
492
+ @media (max-width: 600px) {
493
+ .day-cell { min-height: 38px; padding: 4px; justify-content: center; align-items: center; }
494
+ .slot-indicator { display: none; }
495
+ .day-number { margin-bottom: 0; font-size: 0.8rem; }
496
+ }
497
+ `;
498
+ k([
499
+ s({ type: Array })
500
+ ], f.prototype, "days", 2);
501
+ k([
502
+ s({ type: String })
503
+ ], f.prototype, "locale", 2);
504
+ k([
505
+ s({ type: Number })
506
+ ], f.prototype, "startOfWeekDay", 2);
507
+ k([
508
+ s({ type: Array })
509
+ ], f.prototype, "selectedDates", 2);
510
+ k([
511
+ s({ type: String })
512
+ ], f.prototype, "role", 2);
513
+ k([
514
+ s({ type: String, reflect: !0 })
515
+ ], f.prototype, "size", 2);
516
+ k([
517
+ s({ type: String })
518
+ ], f.prototype, "minDate", 2);
519
+ k([
520
+ s({ type: String })
521
+ ], f.prototype, "maxDate", 2);
522
+ k([
523
+ s({ type: Boolean })
524
+ ], f.prototype, "showNeighboringMonth", 2);
525
+ k([
526
+ s({ attribute: !1 })
527
+ ], f.prototype, "tileClassName", 2);
528
+ f = k([
529
+ T("glatam-calendar-month-view")
530
+ ], f);
531
+ var F = Object.defineProperty, H = Object.getOwnPropertyDescriptor, R = (e, t, a, i) => {
532
+ for (var r = i > 1 ? void 0 : i ? H(t, a) : t, l = e.length - 1, o; l >= 0; l--)
533
+ (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
534
+ return i && r && F(t, a, r), r;
535
+ };
536
+ let w = class extends O {
537
+ constructor() {
538
+ super(...arguments), this.days = [], this.slots = [], this.locale = "es", this.selectedRange = null, this.role = "provider", this.isDragging = !1, this.dragDayIndex = null, this.dragStartSlotIndex = null, this.dragEndSlotIndex = null, this.handleMouseUp = () => {
539
+ if (!this.isDragging || this.dragDayIndex === null || this.dragStartSlotIndex === null || this.dragEndSlotIndex === null) {
540
+ this.isDragging = !1;
541
+ return;
542
+ }
543
+ this.isDragging = !1;
544
+ const e = Math.min(this.dragStartSlotIndex, this.dragEndSlotIndex), t = Math.max(this.dragStartSlotIndex, this.dragEndSlotIndex), a = this.days[this.dragDayIndex], i = a.slots.slice(e, t + 1);
545
+ i.some((r) => r.isBlocked) || this.dispatchEvent(new CustomEvent("range-select", {
546
+ detail: { dateString: a.dateString, start: i[0].start, end: i[i.length - 1].end },
547
+ bubbles: !0,
548
+ composed: !0
549
+ })), this.dragDayIndex = null, this.dragStartSlotIndex = null, this.dragEndSlotIndex = null;
550
+ };
551
+ }
552
+ connectedCallback() {
553
+ super.connectedCallback(), window.addEventListener("mouseup", this.handleMouseUp);
554
+ }
555
+ disconnectedCallback() {
556
+ window.removeEventListener("mouseup", this.handleMouseUp), super.disconnectedCallback();
557
+ }
558
+ handleMouseDown(e, t, a) {
559
+ if (a) {
560
+ if (this.role === "buyer") return;
561
+ this.dispatchEvent(new CustomEvent("slot-click", {
562
+ detail: { dateString: this.days[e].dateString, slot: this.days[e].slots[t], isBlocked: !0 },
563
+ bubbles: !0,
564
+ composed: !0
565
+ }));
566
+ return;
567
+ }
568
+ this.isDragging = !0, this.dragDayIndex = e, this.dragStartSlotIndex = t, this.dragEndSlotIndex = t;
569
+ }
570
+ handleMouseEnter(e, t, a) {
571
+ this.isDragging && e === this.dragDayIndex && !a && (this.dragEndSlotIndex = t);
572
+ }
573
+ isSlotSelected(e, t) {
574
+ return !this.selectedRange || this.selectedRange.dateString !== e ? !1 : t.start >= this.selectedRange.start && t.end <= this.selectedRange.end;
575
+ }
576
+ isSlotDragSelecting(e, t) {
577
+ if (!this.isDragging || e !== this.dragDayIndex) return !1;
578
+ const a = Math.min(this.dragStartSlotIndex, this.dragEndSlotIndex), i = Math.max(this.dragStartSlotIndex, this.dragEndSlotIndex);
579
+ return t >= a && t <= i;
580
+ }
581
+ render() {
582
+ const e = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
583
+ return d`
584
+ <div class="time-col">
585
+ <div class="header-cell">Hora</div>
586
+ ${this.slots.map((t) => d`<div class="slot-cell time-slot-label">${t.start}</div>`)}
587
+ </div>
588
+
589
+ ${this.days.map((t, a) => {
590
+ const i = t.dateString === e, r = new Intl.DateTimeFormat(this.locale, { weekday: "short" }).format(t.date);
591
+ return d`
592
+ <div class="day-col">
593
+ <div class="header-cell ${i ? "today" : ""}">
594
+ <div>${r}</div>
595
+ <div class="day-num">${t.dayNumber}</div>
596
+ </div>
597
+
598
+ ${t.slots.map((l, o) => {
599
+ var u, v;
600
+ const c = l.isBlocked, n = this.isSlotSelected(t.dateString, l), g = this.isSlotDragSelecting(a, o);
601
+ return d`
602
+ <div
603
+ class=${I({
604
+ "slot-cell": !0,
605
+ available: !c,
606
+ blocked: c,
607
+ selected: n,
608
+ "drag-selecting": g
609
+ })}
610
+ @mousedown=${() => this.handleMouseDown(a, o, c)}
611
+ @mouseenter=${() => this.handleMouseEnter(a, o, c)}
612
+ title=${c && ((u = l.rule) != null && u.description) ? l.rule.description : ""}
613
+ >
614
+ ${c ? ((v = l.rule) == null ? void 0 : v.description) || "Ocupado" : n ? "Reservado" : ""}
615
+ </div>
616
+ `;
617
+ })}
618
+ </div>
619
+ `;
620
+ })}
621
+ `;
622
+ }
623
+ };
624
+ w.styles = E`
625
+ :host {
626
+ display: grid; grid-template-columns: var(--glatam-time-col-width) repeat(7, 1fr); gap: 2px;
627
+ width: 100%; background-color: var(--glatam-border); border: 1px solid var(--glatam-border);
628
+ border-radius: var(--glatam-grid-border-radius); overflow: hidden; user-select: none;
629
+ }
630
+ @media (max-width: 600px) {
631
+ :host {
632
+ grid-template-columns: 40px repeat(7, 1fr);
633
+ overflow-x: hidden;
634
+ }
635
+ .slot-cell {
636
+ font-size: 0.65rem;
637
+ }
638
+ .slot-cell.blocked, .slot-cell.selected {
639
+ font-size: 0;
640
+ padding: 0;
641
+ }
642
+ .time-slot-label {
643
+ font-size: 0.65rem;
644
+ }
645
+ .header-cell {
646
+ font-size: 0.7rem;
647
+ }
648
+ .header-cell .day-num {
649
+ font-size: 0.8rem;
650
+ }
651
+ }
652
+ .time-col { background-color: var(--glatam-surface); display: flex; flex-direction: column; }
653
+ .day-col { background-color: var(--glatam-bg); display: flex; flex-direction: column; }
654
+ .header-cell {
655
+ height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center;
656
+ background-color: var(--glatam-surface); border-bottom: 2px solid var(--glatam-border);
657
+ font-size: 0.8rem; font-weight: 500; text-transform: capitalize;
658
+ }
659
+ .header-cell.today { color: var(--glatam-primary); font-weight: 700; }
660
+ .header-cell .day-num { font-size: 0.95rem; font-weight: 600; margin-top: 2px; }
661
+ .slot-cell {
662
+ height: var(--glatam-slot-height); border-bottom: 1px solid var(--glatam-border);
663
+ display: flex; align-items: center; justify-content: center; font-size: 0.75rem;
664
+ cursor: pointer; transition: background-color var(--glatam-transition-fast); position: relative;
665
+ }
666
+ .time-slot-label { font-size: 0.7rem; color: var(--glatam-text-secondary); }
667
+ .slot-cell.available:hover { background-color: var(--glatam-surface); }
668
+ .slot-cell.blocked {
669
+ background-color: var(--glatam-blocked-bg);
670
+ background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, var(--glatam-blocked-stripe) 5px, var(--glatam-blocked-stripe) 10px);
671
+ color: var(--glatam-blocked-text); cursor: not-allowed; font-weight: 600; padding: 0 4px;
672
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: center;
673
+ }
674
+ .slot-cell.selected { background-color: var(--glatam-selection-bg); border-left: 3px solid var(--glatam-selection-border); }
675
+ .slot-cell.drag-selecting { background-color: var(--glatam-primary-light); }
676
+ `;
677
+ R([
678
+ s({ type: Array })
679
+ ], w.prototype, "days", 2);
680
+ R([
681
+ s({ type: Array })
682
+ ], w.prototype, "slots", 2);
683
+ R([
684
+ s({ type: String })
685
+ ], w.prototype, "locale", 2);
686
+ R([
687
+ s({ type: Object })
688
+ ], w.prototype, "selectedRange", 2);
689
+ R([
690
+ s({ type: String })
691
+ ], w.prototype, "role", 2);
692
+ R([
693
+ m()
694
+ ], w.prototype, "isDragging", 2);
695
+ R([
696
+ m()
697
+ ], w.prototype, "dragDayIndex", 2);
698
+ R([
699
+ m()
700
+ ], w.prototype, "dragStartSlotIndex", 2);
701
+ R([
702
+ m()
703
+ ], w.prototype, "dragEndSlotIndex", 2);
704
+ w = R([
705
+ T("glatam-calendar-week-view")
706
+ ], w);
707
+ var q = Object.defineProperty, G = Object.getOwnPropertyDescriptor, z = (e, t, a, i) => {
708
+ for (var r = i > 1 ? void 0 : i ? G(t, a) : t, l = e.length - 1, o; l >= 0; l--)
709
+ (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
710
+ return i && r && q(t, a, r), r;
711
+ };
712
+ let D = class extends O {
713
+ constructor() {
714
+ super(...arguments), this.day = null, this.slots = [], this.locale = "es", this.selectedRange = null, this.role = "provider", this.isDragging = !1, this.dragStartSlotIndex = null, this.dragEndSlotIndex = null, this.handleMouseUp = () => {
715
+ if (!this.isDragging || !this.day || this.dragStartSlotIndex === null || this.dragEndSlotIndex === null) {
716
+ this.isDragging = !1;
717
+ return;
718
+ }
719
+ this.isDragging = !1;
720
+ const e = Math.min(this.dragStartSlotIndex, this.dragEndSlotIndex), t = Math.max(this.dragStartSlotIndex, this.dragEndSlotIndex), a = this.day.slots.slice(e, t + 1);
721
+ a.some((i) => i.isBlocked) || this.dispatchEvent(new CustomEvent("range-select", {
722
+ detail: { dateString: this.day.dateString, start: a[0].start, end: a[a.length - 1].end },
723
+ bubbles: !0,
724
+ composed: !0
725
+ })), this.dragStartSlotIndex = null, this.dragEndSlotIndex = null;
726
+ };
727
+ }
728
+ connectedCallback() {
729
+ super.connectedCallback(), window.addEventListener("mouseup", this.handleMouseUp);
730
+ }
731
+ disconnectedCallback() {
732
+ window.removeEventListener("mouseup", this.handleMouseUp), super.disconnectedCallback();
733
+ }
734
+ handleMouseDown(e, t) {
735
+ if (t && this.day) {
736
+ if (this.role === "buyer") return;
737
+ this.dispatchEvent(new CustomEvent("slot-click", {
738
+ detail: { dateString: this.day.dateString, slot: this.day.slots[e], isBlocked: !0 },
739
+ bubbles: !0,
740
+ composed: !0
741
+ }));
742
+ return;
743
+ }
744
+ this.isDragging = !0, this.dragStartSlotIndex = e, this.dragEndSlotIndex = e;
745
+ }
746
+ handleMouseEnter(e, t) {
747
+ this.isDragging && !t && (this.dragEndSlotIndex = e);
748
+ }
749
+ isSlotSelected(e) {
750
+ return !this.day || !this.selectedRange || this.selectedRange.dateString !== this.day.dateString ? !1 : e.start >= this.selectedRange.start && e.end <= this.selectedRange.end;
751
+ }
752
+ isSlotDragSelecting(e) {
753
+ if (!this.isDragging) return !1;
754
+ const t = Math.min(this.dragStartSlotIndex, this.dragEndSlotIndex), a = Math.max(this.dragStartSlotIndex, this.dragEndSlotIndex);
755
+ return e >= t && e <= a;
756
+ }
757
+ render() {
758
+ if (!this.day) return d`<div>Cargando...</div>`;
759
+ const e = this.day.dateString === (/* @__PURE__ */ new Date()).toISOString().split("T")[0], t = new Intl.DateTimeFormat(this.locale, { weekday: "long", day: "numeric", month: "long" }).format(this.day.date);
760
+ return d`
761
+ <div class="time-col">
762
+ <div class="header-cell">Hora</div>
763
+ ${this.slots.map((a) => d`<div class="slot-cell time-slot-label">${a.start}</div>`)}
764
+ </div>
765
+
766
+ <div class="day-col">
767
+ <div class="header-cell ${e ? "today" : ""}">
768
+ <div style="text-transform: capitalize;">${t}</div>
769
+ </div>
770
+
771
+ ${this.day.slots.map((a, i) => {
772
+ var c, n;
773
+ const r = a.isBlocked, l = this.isSlotSelected(a), o = this.isSlotDragSelecting(i);
774
+ return d`
775
+ <div
776
+ class=${I({
777
+ "slot-cell": !0,
778
+ available: !r,
779
+ blocked: r,
780
+ selected: l,
781
+ "drag-selecting": o
782
+ })}
783
+ @mousedown=${() => this.handleMouseDown(i, r)}
784
+ @mouseenter=${() => this.handleMouseEnter(i, r)}
785
+ title=${r && ((c = a.rule) != null && c.description) ? a.rule.description : ""}
786
+ >
787
+ ${r ? ((n = a.rule) == null ? void 0 : n.description) || "Ocupado" : l ? "Reservado" : ""}
788
+ </div>
789
+ `;
790
+ })}
791
+ </div>
792
+ `;
793
+ }
794
+ };
795
+ D.styles = E`
796
+ :host {
797
+ display: grid; grid-template-columns: var(--glatam-time-col-width) 1fr; gap: 2px;
798
+ width: 100%; background-color: var(--glatam-border); border: 1px solid var(--glatam-border);
799
+ border-radius: var(--glatam-grid-border-radius); overflow: hidden; user-select: none;
800
+ }
801
+ .time-col { background-color: var(--glatam-surface); display: flex; flex-direction: column; }
802
+ .day-col { background-color: var(--glatam-bg); display: flex; flex-direction: column; }
803
+ .header-cell {
804
+ height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center;
805
+ background-color: var(--glatam-surface); border-bottom: 2px solid var(--glatam-border);
806
+ font-size: 0.875rem; font-weight: 500;
807
+ }
808
+ .header-cell.today { color: var(--glatam-primary); font-weight: 700; }
809
+ .slot-cell {
810
+ height: var(--glatam-slot-height); border-bottom: 1px solid var(--glatam-border);
811
+ display: flex; align-items: center; justify-content: center; font-size: 0.75rem;
812
+ cursor: pointer; transition: background-color var(--glatam-transition-fast); position: relative;
813
+ }
814
+ .time-slot-label { font-size: 0.7rem; color: var(--glatam-text-secondary); }
815
+ .slot-cell.available:hover { background-color: var(--glatam-surface); }
816
+ .slot-cell.blocked {
817
+ background-color: var(--glatam-blocked-bg);
818
+ background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, var(--glatam-blocked-stripe) 5px, var(--glatam-blocked-stripe) 10px);
819
+ color: var(--glatam-blocked-text); cursor: not-allowed; font-weight: 600; padding: 0 10px;
820
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
821
+ }
822
+ .slot-cell.selected { background-color: var(--glatam-selection-bg); border-left: 3px solid var(--glatam-selection-border); }
823
+ .slot-cell.drag-selecting { background-color: var(--glatam-primary-light); }
824
+ `;
825
+ z([
826
+ s({ type: Object })
827
+ ], D.prototype, "day", 2);
828
+ z([
829
+ s({ type: Array })
830
+ ], D.prototype, "slots", 2);
831
+ z([
832
+ s({ type: String })
833
+ ], D.prototype, "locale", 2);
834
+ z([
835
+ s({ type: Object })
836
+ ], D.prototype, "selectedRange", 2);
837
+ z([
838
+ s({ type: String })
839
+ ], D.prototype, "role", 2);
840
+ z([
841
+ m()
842
+ ], D.prototype, "isDragging", 2);
843
+ z([
844
+ m()
845
+ ], D.prototype, "dragStartSlotIndex", 2);
846
+ z([
847
+ m()
848
+ ], D.prototype, "dragEndSlotIndex", 2);
849
+ D = z([
850
+ T("glatam-calendar-day-view")
851
+ ], D);
852
+ var V = Object.defineProperty, Y = Object.getOwnPropertyDescriptor, $ = (e, t, a, i) => {
853
+ for (var r = i > 1 ? void 0 : i ? Y(t, a) : t, l = e.length - 1, o; l >= 0; l--)
854
+ (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
855
+ return i && r && V(t, a, r), r;
856
+ };
857
+ let x = class extends O {
858
+ constructor() {
859
+ super(...arguments), this.open = !1, this.dateString = "", this.startTime = "", this.endTime = "", this.isRange = !1, this.existingRule = null, this.description = "", this.blockAllDay = !0, this.isRecurring = !1, this.selectedDays = [];
860
+ }
861
+ willUpdate(e) {
862
+ e.has("open") && this.open && (this.existingRule ? (this.description = "Bloqueo", this.blockAllDay = !this.existingRule.slots || this.existingRule.slots.length === 0, this.isRecurring = this.existingRule.type === "weekly", this.selectedDays = this.existingRule.daysOfWeek || []) : (this.description = "", this.blockAllDay = !this.isRange, this.isRecurring = !1, this.selectedDays = [(/* @__PURE__ */ new Date(this.dateString + "T00:00:00")).getDay()]));
863
+ }
864
+ toggleDay(e) {
865
+ this.selectedDays.indexOf(e) > -1 ? this.selectedDays = this.selectedDays.filter((a) => a !== e) : this.selectedDays = [...this.selectedDays, e];
866
+ }
867
+ handleSave() {
868
+ const e = {
869
+ title: this.description || "Bloqueo",
870
+ blockAllDay: this.blockAllDay,
871
+ isRecurring: this.isRecurring,
872
+ selectedDays: this.selectedDays,
873
+ dateString: this.dateString,
874
+ startTime: this.startTime,
875
+ endTime: this.endTime
876
+ };
877
+ this.dispatchEvent(new CustomEvent("save-rule", { detail: e, bubbles: !0, composed: !0 }));
878
+ }
879
+ handleDelete() {
880
+ this.existingRule && this.dispatchEvent(new CustomEvent("delete-rule", {
881
+ detail: { id: this.existingRule.id },
882
+ bubbles: !0,
883
+ composed: !0
884
+ }));
885
+ }
886
+ render() {
887
+ const e = ["D", "L", "M", "M", "J", "V", "S"], t = this.isRange ? `${this.dateString} (${this.startTime} - ${this.endTime})` : this.dateString;
888
+ return d`
889
+ <div class=${I({ "modal-overlay": !0, open: this.open })}>
890
+ <div class="modal-content">
891
+ <h3>${this.existingRule ? "Gestionar Bloqueo" : "Crear Bloqueo"}</h3>
892
+
893
+ <div style="font-size: 0.85rem; color: var(--glatam-text-secondary);">
894
+ Selección: <strong>${t}</strong>
895
+ </div>
896
+
897
+ <div class="form-group">
898
+ <label>Descripción / Nota</label>
899
+ <input
900
+ type="text"
901
+ .value=${this.description}
902
+ @input=${(a) => this.description = a.target.value}
903
+ placeholder="Ej. Reunión de equipo, Vacaciones"
904
+ />
905
+ </div>
906
+
907
+ <div class="switch-row">
908
+ <label>Bloquear todo el día</label>
909
+ <label class="switch">
910
+ <input
911
+ type="checkbox"
912
+ .checked=${this.blockAllDay}
913
+ @change=${(a) => this.blockAllDay = a.target.checked}
914
+ />
915
+ <span class="slider"></span>
916
+ </label>
917
+ </div>
918
+
919
+ <div class="switch-row">
920
+ <label>Repetir semanalmente</label>
921
+ <label class="switch">
922
+ <input
923
+ type="checkbox"
924
+ .checked=${this.isRecurring}
925
+ @change=${(a) => this.isRecurring = a.target.checked}
926
+ />
927
+ <span class="slider"></span>
928
+ </label>
929
+ </div>
930
+
931
+ ${this.isRecurring ? d`
932
+ <div class="form-group">
933
+ <label>Repetir los días</label>
934
+ <div class="days-grid">
935
+ ${[1, 2, 3, 4, 5, 6, 0].map((a) => d`
936
+ <button
937
+ class="day-btn ${this.selectedDays.includes(a) ? "selected" : ""}"
938
+ @click=${() => this.toggleDay(a)}
939
+ >
940
+ ${e[a]}
941
+ </button>
942
+ `)}
943
+ </div>
944
+ </div>
945
+ ` : ""}
946
+
947
+ <div class="btn-actions">
948
+ ${this.existingRule ? d`<button class="btn btn-danger" @click=${this.handleDelete}>Eliminar</button>` : ""}
949
+ <button class="btn btn-cancel" @click=${() => this.dispatchEvent(new CustomEvent("close"))}>Cancelar</button>
950
+ <button class="btn btn-save" @click=${this.handleSave}>Guardar</button>
951
+ </div>
952
+ </div>
953
+ </div>
954
+ `;
955
+ }
956
+ };
957
+ x.styles = E`
958
+ .modal-overlay {
959
+ position: fixed;
960
+ top: 0; left: 0; right: 0; bottom: 0;
961
+ background: rgba(0, 0, 0, 0.35);
962
+ backdrop-filter: blur(10px);
963
+ display: flex;
964
+ align-items: center;
965
+ justify-content: center;
966
+ z-index: 1000;
967
+ opacity: 0; pointer-events: none;
968
+ transition: opacity var(--glatam-transition-normal);
969
+ }
970
+ .modal-overlay.open {
971
+ opacity: 1; pointer-events: auto;
972
+ }
973
+ .modal-content {
974
+ background: var(--glatam-bg);
975
+ color: var(--glatam-text);
976
+ border-radius: 24px;
977
+ padding: 28px;
978
+ width: 90%;
979
+ max-width: 400px;
980
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.12);
981
+ border: 1px solid var(--glatam-border);
982
+ transform: scale(0.92) translateY(10px);
983
+ transition: transform var(--glatam-transition-normal), background-color var(--glatam-transition-normal);
984
+ display: flex;
985
+ flex-direction: column;
986
+ gap: 18px;
987
+ }
988
+ .modal-overlay.open .modal-content {
989
+ transform: scale(1) translateY(0);
990
+ }
991
+ h3 { margin: 0; font-size: 1.3rem; font-weight: 700; letter-spacing: -0.02em; }
992
+ .form-group { display: flex; flex-direction: column; gap: 6px; }
993
+ label { font-size: 0.8rem; color: var(--glatam-text-secondary); font-weight: 600; }
994
+ input[type="text"] {
995
+ background: var(--glatam-surface);
996
+ border: 1px solid var(--glatam-border);
997
+ border-radius: 10px;
998
+ padding: 10px 14px;
999
+ color: var(--glatam-text);
1000
+ font-family: inherit;
1001
+ font-size: 0.9rem;
1002
+ outline: none;
1003
+ transition: border-color var(--glatam-transition-fast);
1004
+ }
1005
+ input[type="text"]:focus {
1006
+ border-color: var(--glatam-primary);
1007
+ }
1008
+ .switch-row {
1009
+ display: flex;
1010
+ justify-content: space-between;
1011
+ align-items: center;
1012
+ padding: 4px 0;
1013
+ }
1014
+
1015
+ /* Apple Switch Style */
1016
+ .switch {
1017
+ position: relative;
1018
+ display: inline-block;
1019
+ width: 46px;
1020
+ height: 26px;
1021
+ }
1022
+ .switch input { opacity: 0; width: 0; height: 0; }
1023
+ .slider {
1024
+ position: absolute;
1025
+ cursor: pointer;
1026
+ top: 0; left: 0; right: 0; bottom: 0;
1027
+ background-color: var(--glatam-border);
1028
+ transition: .25s cubic-bezier(0.16, 1, 0.3, 1);
1029
+ border-radius: 26px;
1030
+ }
1031
+ .slider:before {
1032
+ position: absolute;
1033
+ content: "";
1034
+ height: 20px;
1035
+ width: 20px;
1036
+ left: 3px;
1037
+ bottom: 3px;
1038
+ background-color: white;
1039
+ transition: .25s cubic-bezier(0.16, 1, 0.3, 1);
1040
+ border-radius: 50%;
1041
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
1042
+ }
1043
+ input:checked + .slider {
1044
+ background-color: var(--glatam-primary);
1045
+ }
1046
+ input:checked + .slider:before {
1047
+ transform: translateX(20px);
1048
+ }
1049
+
1050
+ .days-grid {
1051
+ display: grid;
1052
+ grid-template-columns: repeat(7, 1fr);
1053
+ gap: 6px;
1054
+ margin-top: 4px;
1055
+ }
1056
+ .day-btn {
1057
+ width: 36px;
1058
+ height: 36px;
1059
+ margin: 0 auto;
1060
+ border-radius: 50%;
1061
+ border: 1px solid var(--glatam-border);
1062
+ background: var(--glatam-bg);
1063
+ color: var(--glatam-text);
1064
+ font-size: 0.8rem;
1065
+ font-weight: 600;
1066
+ cursor: pointer;
1067
+ display: flex;
1068
+ align-items: center;
1069
+ justify-content: center;
1070
+ transition: background-color var(--glatam-transition-fast), color var(--glatam-transition-fast), border-color var(--glatam-transition-fast);
1071
+ }
1072
+ .day-btn:hover {
1073
+ background-color: var(--glatam-surface);
1074
+ }
1075
+ .day-btn.selected {
1076
+ background: var(--glatam-primary);
1077
+ color: var(--glatam-text-light);
1078
+ border-color: var(--glatam-primary);
1079
+ }
1080
+ .btn-actions { display: flex; gap: 10px; margin-top: 10px; justify-content: flex-end; }
1081
+ .btn {
1082
+ padding: 10px 18px;
1083
+ border-radius: 20px;
1084
+ font-size: 0.875rem;
1085
+ font-weight: 600;
1086
+ cursor: pointer;
1087
+ border: none;
1088
+ transition: opacity var(--glatam-transition-fast), transform var(--glatam-transition-fast);
1089
+ display: inline-flex;
1090
+ align-items: center;
1091
+ justify-content: center;
1092
+ }
1093
+ .btn:active { transform: scale(0.97); }
1094
+ .btn-cancel { background: transparent; color: var(--glatam-text); border: 1px solid var(--glatam-border); }
1095
+ .btn-cancel:hover { background-color: var(--glatam-surface); }
1096
+ .btn-save { background: var(--glatam-primary); color: var(--glatam-text-light); }
1097
+ .btn-save:hover { opacity: 0.95; }
1098
+ .btn-danger {
1099
+ background: rgba(255, 69, 58, 0.12);
1100
+ color: #ff453a;
1101
+ margin-right: auto;
1102
+ }
1103
+ .btn-danger:hover {
1104
+ background: rgba(255, 69, 58, 0.18);
1105
+ }
1106
+ `;
1107
+ $([
1108
+ s({ type: Boolean })
1109
+ ], x.prototype, "open", 2);
1110
+ $([
1111
+ s({ type: String })
1112
+ ], x.prototype, "dateString", 2);
1113
+ $([
1114
+ s({ type: String })
1115
+ ], x.prototype, "startTime", 2);
1116
+ $([
1117
+ s({ type: String })
1118
+ ], x.prototype, "endTime", 2);
1119
+ $([
1120
+ s({ type: Boolean })
1121
+ ], x.prototype, "isRange", 2);
1122
+ $([
1123
+ s({ type: Object })
1124
+ ], x.prototype, "existingRule", 2);
1125
+ $([
1126
+ m()
1127
+ ], x.prototype, "description", 2);
1128
+ $([
1129
+ m()
1130
+ ], x.prototype, "blockAllDay", 2);
1131
+ $([
1132
+ m()
1133
+ ], x.prototype, "isRecurring", 2);
1134
+ $([
1135
+ m()
1136
+ ], x.prototype, "selectedDays", 2);
1137
+ x = $([
1138
+ T("glatam-calendar-modal")
1139
+ ], x);
1140
+ var Z = Object.defineProperty, J = Object.getOwnPropertyDescriptor, h = (e, t, a, i) => {
1141
+ for (var r = i > 1 ? void 0 : i ? J(t, a) : t, l = e.length - 1, o; l >= 0; l--)
1142
+ (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
1143
+ return i && r && Z(t, a, r), r;
1144
+ };
1145
+ const X = [
1146
+ { start: "09:00", end: "10:00" },
1147
+ { start: "10:00", end: "11:00" },
1148
+ { start: "11:00", end: "12:00" },
1149
+ { start: "12:00", end: "13:00" },
1150
+ { start: "13:00", end: "14:00" },
1151
+ { start: "14:00", end: "15:00" },
1152
+ { start: "15:00", end: "16:00" },
1153
+ { start: "16:00", end: "17:00" },
1154
+ { start: "17:00", end: "18:00" }
1155
+ ];
1156
+ let p = class extends O {
1157
+ constructor() {
1158
+ super(...arguments), this.role = "provider", this.size = "medium", this.view = "month", this.locale = "es", this.startOfWeekDay = 0, this.rules = [], this.selectedDates = [], this.selectedRange = null, this.hostTimezone = "America/Bogota", this.activeTimezone = "local", this.slots = X, this.minDate = "", this.maxDate = "", this.showNeighboringMonth = !0, this.tileClassName = null, this.activeDate = /* @__PURE__ */ new Date(), this.localRules = [], this.darkMode = !1, this.modalOpen = !1, this.modalDateString = "", this.modalStartTime = "", this.modalEndTime = "", this.modalIsRange = !1, this.modalExistingRule = null;
1159
+ }
1160
+ firstUpdated() {
1161
+ this.darkMode = window.matchMedia("(prefers-color-scheme: dark)").matches, this.localRules = [...this.rules];
1162
+ }
1163
+ willUpdate(e) {
1164
+ e.has("rules") && this.rules.length > 0 && this.localRules.length === 0 && (this.localRules = [...this.rules]);
1165
+ }
1166
+ updated(e) {
1167
+ e.has("darkMode") && this.classList.toggle("dark-mode", this.darkMode);
1168
+ }
1169
+ handlePrev() {
1170
+ const e = new Date(this.activeDate);
1171
+ this.view === "month" ? e.setMonth(e.getMonth() - 1) : this.view === "week" ? e.setDate(e.getDate() - 7) : e.setDate(e.getDate() - 1), this.activeDate = e;
1172
+ }
1173
+ handleNext() {
1174
+ const e = new Date(this.activeDate);
1175
+ this.view === "month" ? e.setMonth(e.getMonth() + 1) : this.view === "week" ? e.setDate(e.getDate() + 7) : e.setDate(e.getDate() + 1), this.activeDate = e;
1176
+ }
1177
+ getHeaderTitle() {
1178
+ const e = this.view === "month" ? { month: "long", year: "numeric" } : this.view === "week" ? { month: "short", year: "numeric" } : { day: "numeric", month: "long", year: "numeric" };
1179
+ return new Intl.DateTimeFormat(this.locale, e).format(this.activeDate);
1180
+ }
1181
+ handleDaySelect(e) {
1182
+ const { dateString: t, isBlocked: a } = e.detail;
1183
+ this.role === "buyer" && a || (this.activeDate = /* @__PURE__ */ new Date(t + "T00:00:00"), this.view = "day", this.dispatchEvent(new CustomEvent("date-selected", { detail: { dateString: t }, bubbles: !0, composed: !0 })));
1184
+ }
1185
+ handleRangeSelect(e) {
1186
+ var u, v;
1187
+ const { dateString: t, start: a, end: i } = e.detail, r = this.activeTimezone === "local" ? C(this.activeDate, this.hostTimezone, "local") : 0, l = this.getDisplaySlots(r), o = l.findIndex((S) => S.start === a), c = l.findIndex((S) => S.end === i), n = ((u = this.slots[o]) == null ? void 0 : u.start) || a, g = ((v = this.slots[c]) == null ? void 0 : v.end) || i;
1188
+ if (this.role === "buyer") {
1189
+ this.selectedRange = { dateString: t, start: a, end: i }, this.dispatchEvent(new CustomEvent("booking-selected", { detail: { dateString: t, start: a, end: i, hostStart: n, hostEnd: g }, bubbles: !0, composed: !0 }));
1190
+ return;
1191
+ }
1192
+ this.openModal(t, n, g, !0, null);
1193
+ }
1194
+ handleSlotClick(e) {
1195
+ const { dateString: t, slot: a } = e.detail, i = /* @__PURE__ */ new Date(t + "T00:00:00"), r = this.activeTimezone === "local" ? C(this.activeDate, this.hostTimezone, "local") : 0, l = this.getDisplaySlots(r), o = l.findIndex((g) => g.start === a.start), c = this.slots[o] || a;
1196
+ if (this.role === "buyer") {
1197
+ this.selectedRange = { dateString: t, start: a.start, end: a.end }, this.dispatchEvent(new CustomEvent("booking-selected", { detail: { dateString: t, start: a.start, end: a.end, hostStart: c.start, hostEnd: c.end }, bubbles: !0, composed: !0 }));
1198
+ return;
1199
+ }
1200
+ const n = this.localRules.find((g) => M(i, c, [g]));
1201
+ this.openModal(t, c.start, c.end, !0, n || null);
1202
+ }
1203
+ handleBlockDayAction() {
1204
+ const e = N(this.activeDate), t = this.localRules.find((a) => M(this.activeDate, void 0, [a]));
1205
+ this.openModal(e, "", "", !1, t || null);
1206
+ }
1207
+ openModal(e, t, a, i, r) {
1208
+ this.modalDateString = e, this.modalStartTime = t, this.modalEndTime = a, this.modalIsRange = i, this.modalExistingRule = r, this.modalOpen = !0;
1209
+ }
1210
+ handleSaveRule(e) {
1211
+ const t = e.detail, a = this.modalExistingRule ? this.modalExistingRule.id : `rule-${Date.now()}`, i = {
1212
+ id: a,
1213
+ type: t.isRecurring ? "weekly" : "date-range",
1214
+ slots: t.blockAllDay ? void 0 : [{ start: t.startTime, end: t.endTime }],
1215
+ daysOfWeek: t.isRecurring ? t.selectedDays : void 0,
1216
+ startDate: t.isRecurring ? void 0 : t.dateString,
1217
+ endDate: t.isRecurring ? void 0 : t.dateString,
1218
+ description: t.title
1219
+ };
1220
+ this.localRules = this.modalExistingRule ? this.localRules.map((r) => r.id === a ? i : r) : [...this.localRules, i], this.modalOpen = !1, this.dispatchEvent(new CustomEvent("rules-changed", { detail: { rules: this.localRules }, bubbles: !0, composed: !0 }));
1221
+ }
1222
+ handleDeleteRule(e) {
1223
+ this.localRules = this.localRules.filter((t) => t.id !== e.detail.id), this.modalOpen = !1, this.dispatchEvent(new CustomEvent("rules-changed", { detail: { rules: this.localRules }, bubbles: !0, composed: !0 }));
1224
+ }
1225
+ getDisplaySlots(e) {
1226
+ return e === 0 ? this.slots : this.slots.map((t) => {
1227
+ const a = W(t, e), i = a.dayShift > 0 ? " (+1d)" : a.dayShift < 0 ? " (-1d)" : "";
1228
+ return { start: a.start + i, end: a.end + i };
1229
+ });
1230
+ }
1231
+ render() {
1232
+ var c;
1233
+ const e = this.activeDate.getFullYear(), t = this.activeDate.getMonth(), a = M(this.activeDate, void 0, this.localRules), i = this.activeTimezone === "local" ? C(this.activeDate, this.hostTimezone, "local") : 0, r = this.getDisplaySlots(i), l = (n) => n.map((g) => ({ ...g, slots: g.slots.map((u, v) => {
1234
+ var S, B;
1235
+ return { ...u, start: ((S = r[v]) == null ? void 0 : S.start) || u.start, end: ((B = r[v]) == null ? void 0 : B.end) || u.end };
1236
+ }) })), o = ((c = this.hostTimezone.split("/").pop()) == null ? void 0 : c.replace("_", " ")) || "Anfitrión";
1237
+ return d`
1238
+ <div class="calendar-header">
1239
+ <div class="nav-group">
1240
+ <button class="btn" @click=${() => this.activeDate = /* @__PURE__ */ new Date()}>Hoy</button>
1241
+ <button class="btn" @click=${this.handlePrev}>&lt;</button>
1242
+ <button class="btn" @click=${this.handleNext}>&gt;</button>
1243
+ <span class="nav-title" style="text-transform: capitalize;">${this.getHeaderTitle()}</span>
1244
+ </div>
1245
+
1246
+ <div class="view-group">
1247
+ ${this.role === "provider" ? d`
1248
+ <div class="timezone-badge">
1249
+ 🌐 Zona:
1250
+ <select class="timezone-select" @change=${(n) => this.activeTimezone = n.target.value}>
1251
+ <option value="local" ?selected=${this.activeTimezone === "local"}>Mi Hora</option>
1252
+ <option value="host" ?selected=${this.activeTimezone === "host"}>Hora ${o}</option>
1253
+ </select>
1254
+ </div>
1255
+ ` : ""}
1256
+ ${this.role === "provider" && this.view === "day" ? d`<button class="btn btn-primary" @click=${this.handleBlockDayAction} style="margin-right: 8px;">${a ? "Liberar Día" : "Bloquear Día"}</button>` : ""}
1257
+ <button class="btn" @click=${() => this.darkMode = !this.darkMode} style="margin-right: 8px;">${this.darkMode ? "☀️" : "🌙"}</button>
1258
+ <div class="btn-group">
1259
+ <button class="btn ${this.view === "month" ? "active" : ""}" @click=${() => this.view = "month"}>Mes</button>
1260
+ <button class="btn ${this.view === "week" ? "active" : ""}" @click=${() => this.view = "week"}>Semana</button>
1261
+ <button class="btn ${this.view === "day" ? "active" : ""}" @click=${() => this.view = "day"}>Día</button>
1262
+ </div>
1263
+ </div>
1264
+ </div>
1265
+
1266
+ <div class="calendar-body">
1267
+ ${this.view === "month" ? d`<glatam-calendar-month-view .days=${j(e, t, this.localRules, this.slots, this.startOfWeekDay)} .locale=${this.locale} .startOfWeekDay=${this.startOfWeekDay} .role=${this.role} .size=${this.size} .minDate=${this.minDate} .maxDate=${this.maxDate} .showNeighboringMonth=${this.showNeighboringMonth} .tileClassName=${this.tileClassName} @day-select=${this.handleDaySelect}></glatam-calendar-month-view>` : this.view === "week" ? d`<glatam-calendar-week-view .days=${l(_(this.activeDate, this.localRules, this.slots, this.startOfWeekDay))} .slots=${r} .locale=${this.locale} .selectedRange=${this.selectedRange} .role=${this.role} @range-select=${this.handleRangeSelect} @slot-click=${this.handleSlotClick}></glatam-calendar-week-view>` : d`<glatam-calendar-day-view .day=${l(_(this.activeDate, this.localRules, this.slots, this.startOfWeekDay)).find((n) => n.dateString === N(this.activeDate)) || null} .slots=${r} .locale=${this.locale} .selectedRange=${this.selectedRange} .role=${this.role} @range-select=${this.handleRangeSelect} @slot-click=${this.handleSlotClick}></glatam-calendar-day-view>`}
1268
+ </div>
1269
+
1270
+ <glatam-calendar-modal
1271
+ .open=${this.modalOpen} .dateString=${this.modalDateString} .startTime=${this.modalStartTime} .endTime=${this.modalEndTime}
1272
+ .isRange=${this.modalIsRange} .existingRule=${this.modalExistingRule} @save-rule=${this.handleSaveRule}
1273
+ @delete-rule=${this.handleDeleteRule} @close=${() => this.modalOpen = !1}
1274
+ ></glatam-calendar-modal>
1275
+ `;
1276
+ }
1277
+ };
1278
+ p.styles = [A, P];
1279
+ h([
1280
+ s({ type: String })
1281
+ ], p.prototype, "role", 2);
1282
+ h([
1283
+ s({ type: String, reflect: !0 })
1284
+ ], p.prototype, "size", 2);
1285
+ h([
1286
+ s({ type: String })
1287
+ ], p.prototype, "view", 2);
1288
+ h([
1289
+ s({ type: String })
1290
+ ], p.prototype, "locale", 2);
1291
+ h([
1292
+ s({ type: Number })
1293
+ ], p.prototype, "startOfWeekDay", 2);
1294
+ h([
1295
+ s({ type: Array })
1296
+ ], p.prototype, "rules", 2);
1297
+ h([
1298
+ s({ type: Array })
1299
+ ], p.prototype, "selectedDates", 2);
1300
+ h([
1301
+ s({ type: Object })
1302
+ ], p.prototype, "selectedRange", 2);
1303
+ h([
1304
+ s({ type: String })
1305
+ ], p.prototype, "hostTimezone", 2);
1306
+ h([
1307
+ s({ type: String })
1308
+ ], p.prototype, "activeTimezone", 2);
1309
+ h([
1310
+ s({ type: Array })
1311
+ ], p.prototype, "slots", 2);
1312
+ h([
1313
+ s({ type: String })
1314
+ ], p.prototype, "minDate", 2);
1315
+ h([
1316
+ s({ type: String })
1317
+ ], p.prototype, "maxDate", 2);
1318
+ h([
1319
+ s({ type: Boolean })
1320
+ ], p.prototype, "showNeighboringMonth", 2);
1321
+ h([
1322
+ s({ attribute: !1 })
1323
+ ], p.prototype, "tileClassName", 2);
1324
+ h([
1325
+ m()
1326
+ ], p.prototype, "activeDate", 2);
1327
+ h([
1328
+ m()
1329
+ ], p.prototype, "localRules", 2);
1330
+ h([
1331
+ m()
1332
+ ], p.prototype, "darkMode", 2);
1333
+ h([
1334
+ m()
1335
+ ], p.prototype, "modalOpen", 2);
1336
+ h([
1337
+ m()
1338
+ ], p.prototype, "modalDateString", 2);
1339
+ h([
1340
+ m()
1341
+ ], p.prototype, "modalStartTime", 2);
1342
+ h([
1343
+ m()
1344
+ ], p.prototype, "modalEndTime", 2);
1345
+ h([
1346
+ m()
1347
+ ], p.prototype, "modalIsRange", 2);
1348
+ h([
1349
+ m()
1350
+ ], p.prototype, "modalExistingRule", 2);
1351
+ p = h([
1352
+ T("glatam-calendar")
1353
+ ], p);
1354
+ var K = Object.defineProperty, Q = Object.getOwnPropertyDescriptor, y = (e, t, a, i) => {
1355
+ for (var r = i > 1 ? void 0 : i ? Q(t, a) : t, l = e.length - 1, o; l >= 0; l--)
1356
+ (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
1357
+ return i && r && K(t, a, r), r;
1358
+ };
1359
+ let b = class extends O {
1360
+ constructor() {
1361
+ super(...arguments), this.role = "buyer", this.locale = "es", this.startOfWeekDay = 0, this.rules = [], this.selectedRange = null, this.size = "medium", this.hostTimezone = "America/Bogota", this.activeTimezone = "local", this.minDate = "", this.maxDate = "", this.showNeighboringMonth = !0, this.tileClassName = null, this.slots = [
1362
+ { start: "09:00", end: "10:00" },
1363
+ { start: "10:00", end: "11:00" },
1364
+ { start: "11:00", end: "12:00" },
1365
+ { start: "12:00", end: "13:00" },
1366
+ { start: "13:00", end: "14:00" },
1367
+ { start: "14:00", end: "15:00" },
1368
+ { start: "15:00", end: "16:00" },
1369
+ { start: "16:00", end: "17:00" },
1370
+ { start: "17:00", end: "18:00" }
1371
+ ], this.activeDate = /* @__PURE__ */ new Date(), this.dropdownOpen = !1, this.dropdownSelectedDateString = "";
1372
+ }
1373
+ handleDropdownDaySelect(e) {
1374
+ this.dropdownSelectedDateString = e.detail.dateString;
1375
+ }
1376
+ selectDropdownSlot(e) {
1377
+ const t = {
1378
+ dateString: this.dropdownSelectedDateString,
1379
+ start: e.displayStart,
1380
+ end: e.displayEnd,
1381
+ hostStart: e.start,
1382
+ hostEnd: e.end
1383
+ };
1384
+ this.selectedRange = { dateString: this.dropdownSelectedDateString, start: e.displayStart, end: e.displayEnd }, this.dispatchEvent(new CustomEvent("booking-selected", { detail: t, bubbles: !0, composed: !0 })), this.dropdownOpen = !1, this.dropdownSelectedDateString = "";
1385
+ }
1386
+ render() {
1387
+ const e = this.selectedRange ? `Reserva: ${this.selectedRange.dateString} (${this.selectedRange.start} - ${this.selectedRange.end})` : "Seleccionar Fecha y Hora", t = this.activeDate.getFullYear(), a = this.activeDate.getMonth(), i = this.dropdownSelectedDateString ? /* @__PURE__ */ new Date(this.dropdownSelectedDateString + "T00:00:00") : null, r = i && this.activeTimezone === "local" ? C(i, this.hostTimezone, "local") : 0, l = i ? this.slots.map((o) => {
1388
+ const c = M(i, o, this.rules), n = W(o, r), g = n.dayShift > 0 ? " (+1d)" : n.dayShift < 0 ? " (-1d)" : "";
1389
+ return {
1390
+ ...o,
1391
+ displayStart: n.start + g,
1392
+ displayEnd: n.end + g,
1393
+ isBlocked: c
1394
+ };
1395
+ }) : [];
1396
+ return d`
1397
+ <div class="dropdown-container">
1398
+ <button class="btn btn-primary dropdown-toggle" @click=${() => this.dropdownOpen = !this.dropdownOpen}>
1399
+ <span>${e}</span> <span>${this.dropdownOpen ? "▲" : "▼"}</span>
1400
+ </button>
1401
+
1402
+ ${this.dropdownOpen ? d`
1403
+ <div class="dropdown-card" style="--glatam-day-min-height: 38px;">
1404
+ ${this.dropdownSelectedDateString ? d`
1405
+ <div style="display:flex; justify-content:space-between; align-items:center; border-bottom: 1px solid var(--glatam-border); padding-bottom:8px;">
1406
+ <button class="btn" style="height:28px; padding:0 8px; font-size:0.75rem;" @click=${() => this.dropdownSelectedDateString = ""}>&lt; Volver</button>
1407
+ <span style="font-size:0.8rem; font-weight:600; color: var(--glatam-text);">${this.dropdownSelectedDateString}</span>
1408
+ </div>
1409
+ <div class="slot-list">
1410
+ ${l.map((o) => d`
1411
+ <button
1412
+ class="slot-btn ${o.isBlocked ? "blocked" : ""}"
1413
+ ?disabled=${o.isBlocked}
1414
+ @click=${() => this.selectDropdownSlot(o)}
1415
+ >
1416
+ ${o.displayStart} - ${o.displayEnd} ${o.isBlocked ? "(Ocupado)" : ""}
1417
+ </button>
1418
+ `)}
1419
+ </div>
1420
+ ` : d`
1421
+ <div style="font-weight:600; font-size:0.9rem; text-align:center; color: var(--glatam-text);">Selecciona un Día</div>
1422
+ <glatam-calendar-month-view
1423
+ .days=${j(t, a, this.rules, this.slots, this.startOfWeekDay)}
1424
+ .locale=${this.locale}
1425
+ .startOfWeekDay=${this.startOfWeekDay}
1426
+ .role=${this.role}
1427
+ size="small"
1428
+ .minDate=${this.minDate}
1429
+ .maxDate=${this.maxDate}
1430
+ .showNeighboringMonth=${this.showNeighboringMonth}
1431
+ .tileClassName=${this.tileClassName}
1432
+ @day-select=${this.handleDropdownDaySelect}
1433
+ ></glatam-calendar-month-view>
1434
+ `}
1435
+ </div>
1436
+ ` : ""}
1437
+ </div>
1438
+ `;
1439
+ }
1440
+ };
1441
+ b.styles = [
1442
+ A,
1443
+ P,
1444
+ E`
1445
+ :host {
1446
+ display: inline-block;
1447
+ background: transparent;
1448
+ border: none;
1449
+ padding: 0;
1450
+ box-shadow: none;
1451
+ width: 100%;
1452
+ }
1453
+ `
1454
+ ];
1455
+ y([
1456
+ s({ type: String })
1457
+ ], b.prototype, "role", 2);
1458
+ y([
1459
+ s({ type: String })
1460
+ ], b.prototype, "locale", 2);
1461
+ y([
1462
+ s({ type: Number })
1463
+ ], b.prototype, "startOfWeekDay", 2);
1464
+ y([
1465
+ s({ type: Array })
1466
+ ], b.prototype, "rules", 2);
1467
+ y([
1468
+ s({ type: Object })
1469
+ ], b.prototype, "selectedRange", 2);
1470
+ y([
1471
+ s({ type: String, reflect: !0 })
1472
+ ], b.prototype, "size", 2);
1473
+ y([
1474
+ s({ type: String })
1475
+ ], b.prototype, "hostTimezone", 2);
1476
+ y([
1477
+ s({ type: String })
1478
+ ], b.prototype, "activeTimezone", 2);
1479
+ y([
1480
+ s({ type: String })
1481
+ ], b.prototype, "minDate", 2);
1482
+ y([
1483
+ s({ type: String })
1484
+ ], b.prototype, "maxDate", 2);
1485
+ y([
1486
+ s({ type: Boolean })
1487
+ ], b.prototype, "showNeighboringMonth", 2);
1488
+ y([
1489
+ s({ attribute: !1 })
1490
+ ], b.prototype, "tileClassName", 2);
1491
+ y([
1492
+ s({ type: Array })
1493
+ ], b.prototype, "slots", 2);
1494
+ y([
1495
+ m()
1496
+ ], b.prototype, "activeDate", 2);
1497
+ y([
1498
+ m()
1499
+ ], b.prototype, "dropdownOpen", 2);
1500
+ y([
1501
+ m()
1502
+ ], b.prototype, "dropdownSelectedDateString", 2);
1503
+ b = y([
1504
+ T("glatam-calendar-mini")
1505
+ ], b);
1506
+ export {
1507
+ p as GlatamCalendar,
1508
+ D as GlatamCalendarDayView,
1509
+ b as GlatamCalendarMini,
1510
+ x as GlatamCalendarModal,
1511
+ f as GlatamCalendarMonthView,
1512
+ w as GlatamCalendarWeekView,
1513
+ P as calendarStyles,
1514
+ st as formatISODate,
1515
+ lt as isTimeBlocked,
1516
+ nt as parseISODate,
1517
+ A as variablesStyles
1518
+ };