@forcecalendar/interface 1.3.0 → 1.4.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.
@@ -1099,7 +1099,213 @@ var n = class extends HTMLElement {
1099
1099
  t && e.setAttribute("aria-label", `Event: ${t}`);
1100
1100
  }
1101
1101
  }
1102
- }, u = class extends l {
1102
+ }, u = 4, d = 15, f = 1;
1103
+ function p(e, t = d) {
1104
+ return Math.round(e / t) * t;
1105
+ }
1106
+ function m(e, t) {
1107
+ return Math.max(0, Math.min(e, 1440 - t));
1108
+ }
1109
+ function h(e, t) {
1110
+ let n = new Date(e);
1111
+ return n.setHours(t.getHours(), t.getMinutes(), t.getSeconds(), t.getMilliseconds()), n;
1112
+ }
1113
+ var g = class {
1114
+ constructor(e) {
1115
+ this.renderer = e, this.container = e.container, this.stateManager = e.stateManager, this._active = null, this._docListeners = [];
1116
+ }
1117
+ enableMonthMove() {
1118
+ this.renderer.addListener(this.container, "pointerdown", (e) => {
1119
+ if (e.button !== 0) return;
1120
+ let t = e.target.closest(".fc-event");
1121
+ !t || !this.container.contains(t) || t.closest(".fc-month-day") && this._arm(e, {
1122
+ mode: "month-move",
1123
+ eventEl: t,
1124
+ eventId: t.dataset.eventId,
1125
+ onDragMove: (e) => this._monthDragMove(e),
1126
+ onDrop: (e) => this._monthDrop(e)
1127
+ });
1128
+ });
1129
+ }
1130
+ enableTimeGrid(e) {
1131
+ this._columnSelector = e, this._injectResizeHandles(), this.renderer.addListener(this.container, "pointerdown", (t) => {
1132
+ if (t.button !== 0) return;
1133
+ let n = t.target.closest(".fc-resize-handle");
1134
+ if (n) {
1135
+ let e = n.closest(".fc-timed-event");
1136
+ if (!e) return;
1137
+ t.preventDefault(), this._arm(t, {
1138
+ mode: "resize",
1139
+ eventEl: e,
1140
+ eventId: e.dataset.eventId,
1141
+ originTop: parseFloat(e.style.top) || 0,
1142
+ originHeight: parseFloat(e.style.height) || 30,
1143
+ onDragMove: (e) => this._resizeDragMove(e),
1144
+ onDrop: () => this._resizeDrop()
1145
+ });
1146
+ return;
1147
+ }
1148
+ let r = t.target.closest(".fc-timed-event");
1149
+ if (r && this.container.contains(r)) {
1150
+ this._arm(t, {
1151
+ mode: "time-move",
1152
+ eventEl: r,
1153
+ eventId: r.dataset.eventId,
1154
+ originTop: parseFloat(r.style.top) || 0,
1155
+ originColumn: r.closest(e),
1156
+ onDragMove: (e) => this._timeMoveDragMove(e),
1157
+ onDrop: () => this._timeMoveDrop()
1158
+ });
1159
+ return;
1160
+ }
1161
+ let i = t.target.closest(e);
1162
+ i && !t.target.closest(".fc-event") && this._arm(t, {
1163
+ mode: "create",
1164
+ column: i,
1165
+ onDragMove: (e) => this._createDragMove(e),
1166
+ onDrop: () => this._createDrop()
1167
+ });
1168
+ });
1169
+ }
1170
+ _arm(e, t) {
1171
+ this._active = {
1172
+ ...t,
1173
+ startX: e.clientX,
1174
+ startY: e.clientY,
1175
+ dragging: !1
1176
+ };
1177
+ let n = (e) => this._onPointerMove(e), r = (e) => this._onPointerUp(e), i = () => this._cancel(), a = (e) => {
1178
+ e.key === "Escape" && this._cancel();
1179
+ }, o = this.container.ownerDocument;
1180
+ o.addEventListener("pointermove", n), o.addEventListener("pointerup", r), o.addEventListener("pointercancel", i), o.addEventListener("keydown", a), this._docListeners = [
1181
+ ["pointermove", n],
1182
+ ["pointerup", r],
1183
+ ["pointercancel", i],
1184
+ ["keydown", a]
1185
+ ];
1186
+ }
1187
+ _onPointerMove(e) {
1188
+ let t = this._active;
1189
+ if (t) {
1190
+ if (!t.dragging) {
1191
+ if (Math.abs(e.clientX - t.startX) < u && Math.abs(e.clientY - t.startY) < u) return;
1192
+ t.dragging = !0, t.eventEl && t.eventEl.classList.add("fc-dragging");
1193
+ }
1194
+ e.preventDefault(), t.onDragMove(e);
1195
+ }
1196
+ }
1197
+ _onPointerUp(e) {
1198
+ let t = this._active;
1199
+ if (this._teardownDocListeners(), t) {
1200
+ if (t.dragging) {
1201
+ let n = this.container.ownerDocument, r = (e) => {
1202
+ e.stopPropagation(), e.preventDefault();
1203
+ };
1204
+ n.addEventListener("click", r, {
1205
+ capture: !0,
1206
+ once: !0
1207
+ }), setTimeout(() => n.removeEventListener("click", r, { capture: !0 }), 0), t.onDrop(e);
1208
+ }
1209
+ this._cleanupVisuals(t), this._active = null;
1210
+ }
1211
+ }
1212
+ _cancel() {
1213
+ let e = this._active;
1214
+ this._teardownDocListeners(), this._active = null, e && this._cleanupVisuals(e);
1215
+ }
1216
+ _teardownDocListeners() {
1217
+ let e = this.container.ownerDocument;
1218
+ for (let [t, n] of this._docListeners) e.removeEventListener(t, n);
1219
+ this._docListeners = [];
1220
+ }
1221
+ _cleanupVisuals(e) {
1222
+ e.eventEl && (e.eventEl.classList.remove("fc-dragging"), e.eventEl.style.transform = ""), this.container.querySelectorAll(".fc-drop-target").forEach((e) => e.classList.remove("fc-drop-target")), this._selectionEl?.remove(), this._selectionEl = null;
1223
+ }
1224
+ _cellAtPoint(e, t) {
1225
+ for (let n of this.container.querySelectorAll(".fc-month-day")) {
1226
+ let r = n.getBoundingClientRect();
1227
+ if (e >= r.left && e < r.right && t >= r.top && t < r.bottom) return n;
1228
+ }
1229
+ return null;
1230
+ }
1231
+ _monthDragMove(e) {
1232
+ let t = this._active;
1233
+ t.eventEl.style.transform = `translate(${e.clientX - t.startX}px, ${e.clientY - t.startY}px)`;
1234
+ let n = this._cellAtPoint(e.clientX, e.clientY);
1235
+ n !== t.dropCell && (t.dropCell?.classList.remove("fc-drop-target"), n?.classList.add("fc-drop-target"), t.dropCell = n);
1236
+ }
1237
+ _monthDrop() {
1238
+ let e = this._active ?? {}, t = e.dropCell;
1239
+ if (!t) return;
1240
+ let n = this.stateManager.getEvents().find((t) => t.id === e.eventId);
1241
+ if (!n) return;
1242
+ let r = new Date(n.start), i = h(new Date(t.dataset.date), r), a = i.getTime() - r.getTime();
1243
+ a !== 0 && this.stateManager.updateEvent(e.eventId, {
1244
+ start: i,
1245
+ end: new Date(new Date(n.end).getTime() + a)
1246
+ });
1247
+ }
1248
+ _columnAtPoint(e) {
1249
+ for (let t of this.container.querySelectorAll(this._columnSelector)) {
1250
+ let n = t.getBoundingClientRect();
1251
+ if (e >= n.left && e < n.right) return t;
1252
+ }
1253
+ return null;
1254
+ }
1255
+ _timeMoveDragMove(e) {
1256
+ let t = this._active, n = this._columnAtPoint(e.clientX) || t.originColumn;
1257
+ t.dropColumn = n, t.deltaMinutes = p((e.clientY - t.startY) / f);
1258
+ let r = t.originColumn.getBoundingClientRect(), i = n.getBoundingClientRect();
1259
+ t.eventEl.style.transform = `translate(${i.left - r.left}px, ${t.deltaMinutes * f}px)`;
1260
+ }
1261
+ _timeMoveDrop() {
1262
+ let e = this._active ?? {}, t = this.stateManager.getEvents().find((t) => t.id === e.eventId);
1263
+ if (!t || !e.deltaMinutes && e.dropColumn === e.originColumn) return;
1264
+ let n = new Date(t.start), r = new Date(t.end).getTime() - n.getTime(), i = h(e.dropColumn ? new Date(e.dropColumn.dataset.date) : n, n), a = m(i.getHours() * 60 + i.getMinutes() + (e.deltaMinutes || 0), Math.round(r / 6e4)), o = new Date(i);
1265
+ o.setHours(Math.floor(a / 60), a % 60, 0, 0), o.getTime() !== n.getTime() && this.stateManager.updateEvent(e.eventId, {
1266
+ start: o,
1267
+ end: new Date(o.getTime() + r)
1268
+ });
1269
+ }
1270
+ _resizeDragMove(e) {
1271
+ let t = this._active, n = p((e.clientY - t.startY) / f);
1272
+ t.newHeight = Math.max(d, t.originHeight + n), t.newHeight = Math.min(t.newHeight, 1440 - t.originTop), t.eventEl.style.height = `${t.newHeight}px`;
1273
+ }
1274
+ _resizeDrop() {
1275
+ let e = this._active ?? {};
1276
+ if (!e.newHeight || e.newHeight === e.originHeight) return;
1277
+ let t = this.stateManager.getEvents().find((t) => t.id === e.eventId);
1278
+ if (!t) return;
1279
+ let n = new Date(new Date(t.start).getTime() + e.newHeight * 6e4);
1280
+ this.stateManager.updateEvent(e.eventId, { end: n });
1281
+ }
1282
+ _createDragMove(e) {
1283
+ let t = this._active, n = t.column.getBoundingClientRect(), r = t.startY - n.top, i = e.clientY - n.top;
1284
+ t.fromMinutes = p(Math.min(r, i) / f), t.toMinutes = p(Math.max(r, i) / f), t.fromMinutes = Math.max(0, t.fromMinutes), t.toMinutes = Math.min(1440, Math.max(t.toMinutes, t.fromMinutes + d)), this._selectionEl || (this._selectionEl = this.container.ownerDocument.createElement("div"), this._selectionEl.className = "fc-drag-selection", t.column.appendChild(this._selectionEl)), this._selectionEl.style.top = `${t.fromMinutes * f}px`, this._selectionEl.style.height = `${(t.toMinutes - t.fromMinutes) * f}px`;
1285
+ }
1286
+ _createDrop() {
1287
+ let e = this._active ?? {};
1288
+ if (e.fromMinutes == null) return;
1289
+ let t = new Date(e.column.dataset.date);
1290
+ t.setHours(Math.floor(e.fromMinutes / 60), e.fromMinutes % 60, 0, 0);
1291
+ let n = new Date(e.column.dataset.date);
1292
+ n.setHours(Math.floor(e.toMinutes / 60), e.toMinutes % 60, 0, 0), this.container.dispatchEvent(new CustomEvent("range-select", {
1293
+ detail: {
1294
+ start: t,
1295
+ end: n
1296
+ },
1297
+ bubbles: !0,
1298
+ composed: !0
1299
+ }));
1300
+ }
1301
+ _injectResizeHandles() {
1302
+ for (let e of this.container.querySelectorAll(".fc-timed-event")) {
1303
+ if (e.querySelector(".fc-resize-handle")) continue;
1304
+ let t = this.container.ownerDocument.createElement("div");
1305
+ t.className = "fc-resize-handle", t.setAttribute("aria-hidden", "true"), e.appendChild(t);
1306
+ }
1307
+ }
1308
+ }, _ = class extends l {
1103
1309
  constructor(e, t) {
1104
1310
  super(e, t), this.maxEventsToShow = 3;
1105
1311
  }
@@ -1232,7 +1438,7 @@ var n = class extends HTMLElement {
1232
1438
  let e = new Date(t.dataset.date);
1233
1439
  e.setDate(e.getDate() + (i - r)), this._pendingFocusMs = e.getTime(), i < 0 ? this.stateManager.previous() : this.stateManager.next();
1234
1440
  }
1235
- }), this.attachCommonEventHandlers();
1441
+ }), this.attachCommonEventHandlers(), new g(this).enableMonthMove();
1236
1442
  }
1237
1443
  _applyRovingTabindex(e = null) {
1238
1444
  let t = Array.from(this.container.querySelectorAll(".fc-month-day"));
@@ -1242,7 +1448,7 @@ var n = class extends HTMLElement {
1242
1448
  for (let e of t) e.setAttribute("tabindex", e === n ? "0" : "-1");
1243
1449
  return n;
1244
1450
  }
1245
- }, d = class extends l {
1451
+ }, v = class extends l {
1246
1452
  constructor(e, t) {
1247
1453
  super(e, t), this.hourHeight = 60, this.totalHeight = 24 * this.hourHeight;
1248
1454
  }
@@ -1367,14 +1573,14 @@ var n = class extends HTMLElement {
1367
1573
  day: "numeric",
1368
1574
  year: "numeric"
1369
1575
  }).format(n)}`;
1370
- this._enhanceTimeGridAccessibility(".fc-week-day-column", r);
1576
+ this._enhanceTimeGridAccessibility(".fc-week-day-column", r), new g(this).enableTimeGrid(".fc-week-day-column");
1371
1577
  }
1372
1578
  _scrollToCurrentTime() {
1373
1579
  if (this._scrolled) return;
1374
1580
  let e = this.container.querySelector("#week-scroll-container");
1375
1581
  e && (e.scrollTop = 8 * this.hourHeight - 50, this._scrolled = !0);
1376
1582
  }
1377
- }, f = class extends l {
1583
+ }, y = class extends l {
1378
1584
  constructor(e, t) {
1379
1585
  super(e, t), this.hourHeight = 60, this.totalHeight = 24 * this.hourHeight;
1380
1586
  }
@@ -1511,14 +1717,14 @@ var n = class extends HTMLElement {
1511
1717
  day: "numeric",
1512
1718
  year: "numeric"
1513
1719
  }).format(t);
1514
- this._enhanceTimeGridAccessibility(".fc-day-column", n);
1720
+ this._enhanceTimeGridAccessibility(".fc-day-column", n), new g(this).enableTimeGrid(".fc-day-column");
1515
1721
  }
1516
1722
  _scrollToCurrentTime() {
1517
1723
  if (this._scrolled) return;
1518
1724
  let e = this.container.querySelector("#day-scroll-container");
1519
1725
  e && (e.scrollTop = 8 * this.hourHeight - 50, this._scrolled = !0);
1520
1726
  }
1521
- }, p = class extends n {
1727
+ }, b = class extends n {
1522
1728
  constructor() {
1523
1729
  super(), this._isVisible = !1, this._cleanupFocusTrap = null, this.config = {
1524
1730
  title: "New Event",
@@ -1838,14 +2044,14 @@ var n = class extends HTMLElement {
1838
2044
  this._cleanupFocusTrap && this._cleanupFocusTrap(), this._handleKeyDown && (window.removeEventListener("keydown", this._handleKeyDown), this._handleKeyDown = null, this._keydownListenerAdded = !1);
1839
2045
  }
1840
2046
  };
1841
- customElements.get("forcecal-event-form") || customElements.define("forcecal-event-form", p);
2047
+ customElements.get("forcecal-event-form") || customElements.define("forcecal-event-form", b);
1842
2048
  //#endregion
1843
2049
  //#region src/components/ForceCalendar.js
1844
- var m = class e extends n {
2050
+ var x = class e extends n {
1845
2051
  static RENDERERS = {
1846
- month: u,
1847
- week: d,
1848
- day: f
2052
+ month: _,
2053
+ week: v,
2054
+ day: y
1849
2055
  };
1850
2056
  static get observedAttributes() {
1851
2057
  return [
@@ -1955,7 +2161,7 @@ var m = class e extends n {
1955
2161
  if (t) {
1956
2162
  this._currentViewInstance && this._currentViewInstance.cleanup && this._currentViewInstance.cleanup();
1957
2163
  try {
1958
- let n = new (e.RENDERERS[this.currentView] || u)(t, this.stateManager);
2164
+ let n = new (e.RENDERERS[this.currentView] || _)(t, this.stateManager);
1959
2165
  n._viewType = this.currentView, this._currentViewInstance = n, n.render();
1960
2166
  } catch (e) {
1961
2167
  console.error("[ForceCalendar] Error switching view:", e);
@@ -2089,6 +2295,39 @@ var m = class e extends n {
2089
2295
  outline-offset: -2px;
2090
2296
  }
2091
2297
 
2298
+ .fc-event { touch-action: none; }
2299
+
2300
+ .fc-dragging {
2301
+ opacity: 0.6;
2302
+ z-index: 30;
2303
+ pointer-events: none;
2304
+ }
2305
+
2306
+ .fc-drop-target {
2307
+ outline: 2px dashed var(--fc-primary-color);
2308
+ outline-offset: -2px;
2309
+ }
2310
+
2311
+ .fc-resize-handle {
2312
+ position: absolute;
2313
+ left: 0;
2314
+ right: 0;
2315
+ bottom: 0;
2316
+ height: 6px;
2317
+ cursor: ns-resize;
2318
+ }
2319
+
2320
+ .fc-drag-selection {
2321
+ position: absolute;
2322
+ left: 2px;
2323
+ right: 2px;
2324
+ background: color-mix(in srgb, var(--fc-primary-color) 18%, transparent);
2325
+ border: 1px solid var(--fc-primary-color);
2326
+ border-radius: 4px;
2327
+ pointer-events: none;
2328
+ z-index: 20;
2329
+ }
2330
+
2092
2331
  .fc-nav-arrow:focus-visible,
2093
2332
  .fc-btn:focus-visible,
2094
2333
  .fc-btn-today:focus-visible,
@@ -2449,7 +2688,7 @@ var m = class e extends n {
2449
2688
  if (this._currentViewInstance && this._currentViewInstance._viewType === this.currentView && t.children.length > 0) return;
2450
2689
  this._currentViewInstance && (this._currentViewInstance.cleanup && this._currentViewInstance.cleanup(), this._viewUnsubscribe &&= (this._viewUnsubscribe(), null));
2451
2690
  try {
2452
- let n = new (e.RENDERERS[this.currentView] || u)(t, this.stateManager);
2691
+ let n = new (e.RENDERERS[this.currentView] || _)(t, this.stateManager);
2453
2692
  n._viewType = this.currentView, this._currentViewInstance = n, n.render();
2454
2693
  } catch (e) {
2455
2694
  console.error("[ForceCalendar] Error creating/rendering view:", e);
@@ -2465,6 +2704,8 @@ var m = class e extends n {
2465
2704
  n.open(/* @__PURE__ */ new Date());
2466
2705
  }), this.addListener(this.shadowRoot, "day-click", (e) => {
2467
2706
  n && n.open(e.detail.date);
2707
+ }), this.addListener(this.shadowRoot, "range-select", (e) => {
2708
+ this.emit("calendar-range-select", e.detail), n && n.open(e.detail.start);
2468
2709
  }), n && this.addListener(n, "save", (e) => {
2469
2710
  let t = e.detail, n = window.crypto && typeof window.crypto.randomUUID == "function" ? window.crypto.randomUUID() : Math.random().toString(36).substring(2, 15);
2470
2711
  this.stateManager.addEvent({
@@ -2543,8 +2784,8 @@ var m = class e extends n {
2543
2784
  this._busUnsubscribers.forEach((e) => e()), this._busUnsubscribers = [], this._stateUnsubscribe &&= (this._stateUnsubscribe(), null), this._currentViewInstance && this._currentViewInstance.cleanup && (this._currentViewInstance.cleanup(), this._currentViewInstance = null), this.stateManager && this.stateManager.destroy(), super.cleanup();
2544
2785
  }
2545
2786
  };
2546
- customElements.get("forcecal-main") || customElements.define("forcecal-main", m);
2787
+ customElements.get("forcecal-main") || customElements.define("forcecal-main", x);
2547
2788
  //#endregion
2548
- export { n as BaseComponent, l as BaseViewRenderer, s as DOMUtils, o as DateUtils, f as DayViewRenderer, r as EventBus, m as ForceCalendar, u as MonthViewRenderer, a as StateManager, c as StyleUtils, d as WeekViewRenderer, i as eventBus };
2789
+ export { n as BaseComponent, l as BaseViewRenderer, s as DOMUtils, o as DateUtils, y as DayViewRenderer, r as EventBus, x as ForceCalendar, _ as MonthViewRenderer, a as StateManager, c as StyleUtils, v as WeekViewRenderer, i as eventBus };
2549
2790
 
2550
2791
  //# sourceMappingURL=force-calendar-interface.esm.js.map