@forcecalendar/interface 1.0.55 → 1.0.57

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,7 +1,7 @@
1
- var F = Object.defineProperty;
2
- var H = (h, t, e) => t in h ? F(h, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[t] = e;
3
- var v = (h, t, e) => H(h, typeof t != "symbol" ? t + "" : t, e);
4
- import { Calendar as I, DateUtils as L } from "@forcecalendar/core";
1
+ var H = Object.defineProperty;
2
+ var F = (h, t, e) => t in h ? H(h, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[t] = e;
3
+ var v = (h, t, e) => F(h, typeof t != "symbol" ? t + "" : t, e);
4
+ import { Calendar as L, DateUtils as I } from "@forcecalendar/core";
5
5
  class M extends HTMLElement {
6
6
  constructor() {
7
7
  super(), this.attachShadow({ mode: "open" }), this._listeners = [], this._state = null, this._props = /* @__PURE__ */ new Map(), this._initialized = !1;
@@ -11,7 +11,7 @@ class M extends HTMLElement {
11
11
  this._initialized || (this.initialize(), this._initialized = !0), this.mount();
12
12
  }
13
13
  disconnectedCallback() {
14
- this.unmount(), this.cleanup();
14
+ this.unmount(), this.cleanup(), this._styleEl = null, this._contentWrapper = null;
15
15
  }
16
16
  // To be overridden by child classes
17
17
  initialize() {
@@ -83,13 +83,51 @@ class M extends HTMLElement {
83
83
  // Template rendering
84
84
  render() {
85
85
  this.cleanup();
86
- const t = `
87
- <style>
88
- ${this.getBaseStyles()}
89
- ${this.getStyles()}
90
- </style>
91
- `, e = this.template();
92
- this.shadowRoot.innerHTML = t + e, this.afterRender();
86
+ const t = this.template();
87
+ this._styleEl || (this._styleEl = document.createElement("style"), this.shadowRoot.appendChild(this._styleEl), this._contentWrapper = document.createElement("div"), this._contentWrapper.setAttribute("id", "fc-root"), this._contentWrapper.style.display = "contents", this.shadowRoot.appendChild(this._contentWrapper)), this._styleEl.textContent = this.getBaseStyles() + `
88
+ ` + this.getStyles();
89
+ const e = this._saveScrollPositions(), r = this._getActiveElementSelector();
90
+ this._contentWrapper.innerHTML = t, this._restoreScrollPositions(e), this._restoreFocus(r), this.afterRender();
91
+ }
92
+ /**
93
+ * Save scroll positions of all scrollable containers within shadow DOM
94
+ * @returns {Map<string, {top: number, left: number}>}
95
+ */
96
+ _saveScrollPositions() {
97
+ const t = /* @__PURE__ */ new Map();
98
+ return this._contentWrapper && this._contentWrapper.querySelectorAll("[id]").forEach((r) => {
99
+ (r.scrollTop !== 0 || r.scrollLeft !== 0) && t.set(r.id, { top: r.scrollTop, left: r.scrollLeft });
100
+ }), t;
101
+ }
102
+ /**
103
+ * Restore previously saved scroll positions
104
+ * @param {Map<string, {top: number, left: number}>} positions
105
+ */
106
+ _restoreScrollPositions(t) {
107
+ !this._contentWrapper || t.size === 0 || t.forEach((e, r) => {
108
+ const i = this._contentWrapper.querySelector(`[id="${CSS.escape(r)}"]`);
109
+ i && (i.scrollTop = e.top, i.scrollLeft = e.left);
110
+ });
111
+ }
112
+ /**
113
+ * Get a CSS selector for the currently focused element within shadow DOM
114
+ * @returns {string|null}
115
+ */
116
+ _getActiveElementSelector() {
117
+ const t = this.shadowRoot.activeElement;
118
+ return !t || t === this._contentWrapper ? null : t.id ? `[id="${CSS.escape(t.id)}"]` : t.dataset && t.dataset.action ? `[data-action="${CSS.escape(t.dataset.action)}"]` : t.dataset && t.dataset.view ? `[data-view="${CSS.escape(t.dataset.view)}"]` : t.tagName ? t.tagName.toLowerCase() : null;
119
+ }
120
+ /**
121
+ * Restore focus to a previously focused element
122
+ * @param {string|null} selector
123
+ */
124
+ _restoreFocus(t) {
125
+ if (!(!t || !this._contentWrapper))
126
+ try {
127
+ const e = this._contentWrapper.querySelector(t);
128
+ e && typeof e.focus == "function" && e.focus();
129
+ } catch {
130
+ }
93
131
  }
94
132
  template() {
95
133
  return "";
@@ -111,7 +149,7 @@ class M extends HTMLElement {
111
149
  this.setProp(t, r), this._initialized && this.render();
112
150
  }
113
151
  }
114
- class T {
152
+ class S {
115
153
  constructor() {
116
154
  this.events = /* @__PURE__ */ new Map(), this.wildcardHandlers = /* @__PURE__ */ new Set();
117
155
  }
@@ -249,10 +287,10 @@ class T {
249
287
  return t;
250
288
  }
251
289
  }
252
- const U = new T();
290
+ const U = new S();
253
291
  class V {
254
292
  constructor(t = {}) {
255
- this.eventBus = new T(), this.calendar = new I({
293
+ this.eventBus = new S(), this.calendar = new L({
256
294
  view: t.view || "month",
257
295
  date: t.date || /* @__PURE__ */ new Date(),
258
296
  weekStartsOn: t.weekStartsOn ?? 0,
@@ -486,7 +524,7 @@ class V {
486
524
  this.subscribers.clear(), this._subscriberIds && (this._subscriberIds.clear(), this._subscriberIds = null), this.eventBus && (this.eventBus.clear(), this.eventBus = null), this.state = null, this.calendar = null;
487
525
  }
488
526
  }
489
- class u extends L {
527
+ class u extends I {
490
528
  /**
491
529
  * Format date for display
492
530
  */
@@ -607,7 +645,7 @@ class u extends L {
607
645
  return s && (s.toLowerCase() === "pm" && n < 12 ? o = n + 12 : s.toLowerCase() === "am" && n === 12 && (o = 0)), r.setHours(o, a || 0, 0, 0), r;
608
646
  }
609
647
  }
610
- class k {
648
+ class y {
611
649
  /**
612
650
  * Create element with attributes and children
613
651
  */
@@ -1245,7 +1283,7 @@ v(f, "breakpoints", {
1245
1283
  xl: "1200px",
1246
1284
  "2xl": "1400px"
1247
1285
  });
1248
- class E {
1286
+ class k {
1249
1287
  /**
1250
1288
  * @param {HTMLElement} container - The DOM element to render into
1251
1289
  * @param {StateManager} stateManager - The state manager instance
@@ -1284,7 +1322,7 @@ class E {
1284
1322
  * @returns {string}
1285
1323
  */
1286
1324
  escapeHTML(t) {
1287
- return t == null ? "" : k.escapeHTML(String(t));
1325
+ return t == null ? "" : y.escapeHTML(String(t));
1288
1326
  }
1289
1327
  /**
1290
1328
  * Check if a date is today
@@ -1399,18 +1437,18 @@ class E {
1399
1437
  * @returns {string} HTML string
1400
1438
  */
1401
1439
  renderTimedEvent(t, e = {}) {
1402
- const { compact: r = !0, overlapLayout: i = null } = e, s = new Date(t.start), n = new Date(t.end), a = s.getHours() * 60 + s.getMinutes(), o = Math.max((n - s) / (1e3 * 60), r ? 20 : 30), c = this.getEventColor(t), l = this.getContrastingTextColor(c), d = r ? "4px 8px" : "8px 12px", p = r ? "11px" : "13px", g = r ? 2 : 12, b = r ? 2 : 24, S = r ? "4px" : "6px";
1403
- let y, x;
1440
+ const { compact: r = !0, overlapLayout: i = null } = e, s = new Date(t.start), n = new Date(t.end), a = s.getHours() * 60 + s.getMinutes(), o = Math.max((n - s) / (1e3 * 60), r ? 20 : 30), c = this.getEventColor(t), l = this.getContrastingTextColor(c), d = r ? "4px 8px" : "8px 12px", p = r ? "11px" : "13px", g = r ? 2 : 12, b = r ? 2 : 24, T = r ? "4px" : "6px";
1441
+ let x, w;
1404
1442
  if (i && i.has(t.id)) {
1405
- const { column: C, totalColumns: _ } = i.get(t.id), $ = `(100% - ${g + b}px)`;
1406
- y = `calc(${g}px + ${C} * ${$} / ${_})`, x = `calc(${$} / ${_})`;
1443
+ const { column: C, totalColumns: E } = i.get(t.id), $ = `(100% - ${g + b}px)`;
1444
+ x = `calc(${g}px + ${C} * ${$} / ${E})`, w = `calc(${$} / ${E})`;
1407
1445
  } else
1408
- y = `${g}px`, x = `calc(100% - ${g + b}px)`;
1446
+ x = `${g}px`, w = `calc(100% - ${g + b}px)`;
1409
1447
  return `
1410
1448
  <div class="fc-event fc-timed-event" data-event-id="${this.escapeHTML(t.id)}"
1411
1449
  style="position: absolute; top: ${a}px; height: ${o}px;
1412
- left: ${y}; width: ${x};
1413
- background-color: ${c}; border-radius: ${S};
1450
+ left: ${x}; width: ${w};
1451
+ background-color: ${c}; border-radius: ${T};
1414
1452
  padding: ${d}; font-size: ${p};
1415
1453
  font-weight: 500; color: ${l}; overflow: hidden;
1416
1454
  box-shadow: 0 1px 2px rgba(0,0,0,0.1);
@@ -1445,7 +1483,7 @@ class E {
1445
1483
  });
1446
1484
  }
1447
1485
  }
1448
- class w extends E {
1486
+ class _ extends k {
1449
1487
  constructor(t, e) {
1450
1488
  super(t, e), this.maxEventsToShow = 3;
1451
1489
  }
@@ -1465,7 +1503,7 @@ class w extends E {
1465
1503
  let s = `
1466
1504
  <div class="fc-month-view" style="display: flex; flex-direction: column; height: 100%; min-height: 400px; background: var(--fc-background); border: 1px solid var(--fc-border-color);">
1467
1505
  <div class="fc-month-header" style="display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt);">
1468
- ${this._getDayNames(r).map((n) => `<div class="fc-month-header-cell" style="padding: 12px 8px; text-align: center; font-size: 11px; font-weight: 600; color: var(--fc-text-light); text-transform: uppercase;">${n}</div>`).join("")}
1506
+ ${this._getDayNames(r).map((n) => `<div class="fc-month-header-cell" style="padding: 12px 8px; text-align: center; font-size: 11px; font-weight: 600; color: var(--fc-text-light); text-transform: uppercase;">${this.escapeHTML(n)}</div>`).join("")}
1469
1507
  </div>
1470
1508
  <div class="fc-month-body" style="display: flex; flex-direction: column; flex: 1;">
1471
1509
  `;
@@ -1490,10 +1528,10 @@ class w extends E {
1490
1528
  _renderDay(t) {
1491
1529
  const e = !t.isCurrentMonth, r = t.isToday, i = e ? "var(--fc-background-hover)" : "var(--fc-background)", s = e ? "var(--fc-text-light)" : "var(--fc-text-color)", n = r ? "background: var(--fc-primary-color); color: white; border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;" : "", a = t.events || [], o = a.slice(0, this.maxEventsToShow), c = a.length - this.maxEventsToShow;
1492
1530
  return `
1493
- <div class="fc-month-day" data-date="${t.date}"
1531
+ <div class="fc-month-day" data-date="${this.escapeHTML(t.date)}"
1494
1532
  style="background: ${i}; border-right: 1px solid var(--fc-border-color); border-bottom: 1px solid var(--fc-border-color); padding: 4px; min-height: 80px; cursor: pointer; display: flex; flex-direction: column;">
1495
1533
  <div class="fc-day-number" style="font-size: 13px; font-weight: 500; color: ${s}; padding: 2px 4px; margin-bottom: 4px; ${n}">
1496
- ${t.dayOfMonth}
1534
+ ${this.escapeHTML(String(t.dayOfMonth))}
1497
1535
  </div>
1498
1536
  <div class="fc-day-events" style="display: flex; flex-direction: column; gap: 2px; flex: 1; overflow: hidden;">
1499
1537
  ${o.map((l) => this._renderEvent(l)).join("")}
@@ -1520,7 +1558,7 @@ class w extends E {
1520
1558
  }), this.attachCommonEventHandlers();
1521
1559
  }
1522
1560
  }
1523
- class z extends E {
1561
+ class z extends k {
1524
1562
  constructor(t, e) {
1525
1563
  super(t, e), this.hourHeight = 60, this.totalHeight = 24 * this.hourHeight;
1526
1564
  }
@@ -1564,10 +1602,10 @@ class z extends E {
1564
1602
  (e) => `
1565
1603
  <div style="padding: 12px 8px; text-align: center; border-right: 1px solid var(--fc-border-color);">
1566
1604
  <div style="font-size: 10px; font-weight: 700; color: var(--fc-text-light); text-transform: uppercase; letter-spacing: 0.1em;">
1567
- ${e.dayName}
1605
+ ${this.escapeHTML(e.dayName)}
1568
1606
  </div>
1569
1607
  <div style="font-size: 16px; font-weight: 500; margin-top: 4px; ${e.isToday ? "background: var(--fc-danger-color); color: white; border-radius: 50%; width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;" : "color: var(--fc-text-color);"}">
1570
- ${e.dayOfMonth}
1608
+ ${this.escapeHTML(String(e.dayOfMonth))}
1571
1609
  </div>
1572
1610
  </div>
1573
1611
  `
@@ -1659,7 +1697,7 @@ class z extends E {
1659
1697
  t && (t.scrollTop = 8 * this.hourHeight - 50, this._scrolled = !0);
1660
1698
  }
1661
1699
  }
1662
- class B extends E {
1700
+ class B extends k {
1663
1701
  constructor(t, e) {
1664
1702
  super(t, e), this.hourHeight = 60, this.totalHeight = 24 * this.hourHeight;
1665
1703
  }
@@ -1716,10 +1754,10 @@ class B extends E {
1716
1754
  <div style="border-right: 1px solid var(--fc-border-color);"></div>
1717
1755
  <div style="padding: 16px 24px;">
1718
1756
  <div style="font-size: 12px; font-weight: 700; color: var(--fc-text-light); text-transform: uppercase; letter-spacing: 0.1em;">
1719
- ${e}
1757
+ ${this.escapeHTML(e)}
1720
1758
  </div>
1721
1759
  <div style="font-size: 24px; font-weight: 600; margin-top: 4px; ${r ? "color: var(--fc-danger-color);" : "color: var(--fc-text-color);"}">
1722
- ${t.getDate()}
1760
+ ${this.escapeHTML(String(t.getDate()))}
1723
1761
  </div>
1724
1762
  </div>
1725
1763
  </div>
@@ -2081,7 +2119,7 @@ class A extends M {
2081
2119
  });
2082
2120
  }
2083
2121
  open(t = /* @__PURE__ */ new Date()) {
2084
- this.hasAttribute("open") || this.setAttribute("open", ""), this.titleGroup.classList.remove("has-error"), this.endGroup.classList.remove("has-error"), this._formData.start = t, this._formData.end = new Date(t.getTime() + this.config.defaultDuration * 60 * 1e3), this._formData.title = "", this._formData.color = this.config.colors[0].color, this.startInput && (this.titleInput.value = "", this.startInput.value = this.formatDateForInput(this._formData.start), this.endInput.value = this.formatDateForInput(this._formData.end), this.updateColorSelection(), this._cleanupFocusTrap && this._cleanupFocusTrap(), this._cleanupFocusTrap = k.trapFocus(this.modalContent));
2122
+ this.hasAttribute("open") || this.setAttribute("open", ""), this.titleGroup.classList.remove("has-error"), this.endGroup.classList.remove("has-error"), this._formData.start = t, this._formData.end = new Date(t.getTime() + this.config.defaultDuration * 60 * 1e3), this._formData.title = "", this._formData.color = this.config.colors[0].color, this.startInput && (this.titleInput.value = "", this.startInput.value = this.formatDateForInput(this._formData.start), this.endInput.value = this.formatDateForInput(this._formData.end), this.updateColorSelection(), this._cleanupFocusTrap && this._cleanupFocusTrap(), this._cleanupFocusTrap = y.trapFocus(this.modalContent));
2085
2123
  }
2086
2124
  close() {
2087
2125
  this.removeAttribute("open"), this._cleanupFocusTrap && (this._cleanupFocusTrap(), this._cleanupFocusTrap = null);
@@ -2216,7 +2254,7 @@ const m = class m extends M {
2216
2254
  if (t) {
2217
2255
  this._currentViewInstance && this._currentViewInstance.cleanup && this._currentViewInstance.cleanup();
2218
2256
  try {
2219
- const e = m.RENDERERS[this.currentView] || w, r = new e(t, this.stateManager);
2257
+ const e = m.RENDERERS[this.currentView] || _, r = new e(t, this.stateManager);
2220
2258
  r._viewType = this.currentView, this._currentViewInstance = r, r.render();
2221
2259
  } catch (e) {
2222
2260
  console.error("[ForceCalendar] Error switching view:", e);
@@ -2637,7 +2675,7 @@ const m = class m extends M {
2637
2675
  return `
2638
2676
  <div class="force-calendar">
2639
2677
  <div class="fc-error">
2640
- <p><strong>Error:</strong> ${k.escapeHTML(s.message || "An error occurred")}</p>
2678
+ <p><strong>Error:</strong> ${y.escapeHTML(s.message || "An error occurred")}</p>
2641
2679
  </div>
2642
2680
  </div>
2643
2681
  `;
@@ -2655,7 +2693,7 @@ const m = class m extends M {
2655
2693
  <button class="fc-nav-arrow" data-action="previous" title="Previous">
2656
2694
  ${this.getIcon("chevron-left")}
2657
2695
  </button>
2658
- <h2 class="fc-title">${n}</h2>
2696
+ <h2 class="fc-title">${y.escapeHTML(n)}</h2>
2659
2697
  <button class="fc-nav-arrow" data-action="next" title="Next">
2660
2698
  ${this.getIcon("chevron-right")}
2661
2699
  </button>
@@ -2700,7 +2738,7 @@ const m = class m extends M {
2700
2738
  return;
2701
2739
  this._currentViewInstance && (this._currentViewInstance.cleanup && this._currentViewInstance.cleanup(), this._viewUnsubscribe && (this._viewUnsubscribe(), this._viewUnsubscribe = null));
2702
2740
  try {
2703
- const i = m.RENDERERS[this.currentView] || w, s = new i(t, this.stateManager);
2741
+ const i = m.RENDERERS[this.currentView] || _, s = new i(t, this.stateManager);
2704
2742
  s._viewType = this.currentView, this._currentViewInstance = s, s.render();
2705
2743
  } catch (i) {
2706
2744
  console.error("[ForceCalendar] Error creating/rendering view:", i);
@@ -2811,7 +2849,7 @@ const m = class m extends M {
2811
2849
  }
2812
2850
  };
2813
2851
  v(m, "RENDERERS", {
2814
- month: w,
2852
+ month: _,
2815
2853
  week: z,
2816
2854
  day: B
2817
2855
  });
@@ -2819,13 +2857,13 @@ let D = m;
2819
2857
  customElements.get("forcecal-main") || customElements.define("forcecal-main", D);
2820
2858
  export {
2821
2859
  M as BaseComponent,
2822
- E as BaseViewRenderer,
2823
- k as DOMUtils,
2860
+ k as BaseViewRenderer,
2861
+ y as DOMUtils,
2824
2862
  u as DateUtils,
2825
2863
  B as DayViewRenderer,
2826
- T as EventBus,
2864
+ S as EventBus,
2827
2865
  D as ForceCalendar,
2828
- w as MonthViewRenderer,
2866
+ _ as MonthViewRenderer,
2829
2867
  V as StateManager,
2830
2868
  f as StyleUtils,
2831
2869
  z as WeekViewRenderer,