@tasknotes/calendar 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +6 -0
- package/dist/calendar.css +341 -44
- package/dist/cjs/index.cjs +279 -58
- package/dist/cjs/react.cjs +279 -58
- package/dist/esm/{chunk-EDRCVOY7.js → chunk-EXKFHPW2.js} +279 -58
- package/dist/esm/index.js +1 -1
- package/dist/esm/react.js +1 -1
- package/dist/types/core/types.d.cts +1 -0
- package/dist/types/core/types.d.ts +1 -0
- package/dist/types/dom/calendar.d.cts +10 -1
- package/dist/types/dom/calendar.d.ts +10 -1
- package/dist/types/dom/options.d.cts +2 -2
- package/dist/types/dom/options.d.ts +2 -2
- package/dist/types/dom/views/daygrid.d.cts +1 -1
- package/dist/types/dom/views/daygrid.d.ts +1 -1
- package/dist/types/dom/views/year.d.cts +1 -0
- package/dist/types/dom/views/year.d.ts +1 -0
- package/package.json +1 -1
|
@@ -359,8 +359,9 @@ var DayGridView = class {
|
|
|
359
359
|
constructor(ctx) {
|
|
360
360
|
this.ctx = ctx;
|
|
361
361
|
const { doc, opts, days } = ctx;
|
|
362
|
-
this.dotsMode = opts.monthDisplay === "dots";
|
|
362
|
+
this.dotsMode = opts.monthDisplay === "dots" || opts.monthDisplay === "chips";
|
|
363
363
|
this.el = h(doc, "div", this.dotsMode ? "tnc-dg tnc-dg--dots" : "tnc-dg");
|
|
364
|
+
this.el.classList.toggle("tnc-dg--chips", opts.monthDisplay === "chips");
|
|
364
365
|
this.scroller = h(doc, "div", "tnc-dg-scroll");
|
|
365
366
|
this.grid = h(doc, "div", "tnc-dg-grid", { role: "grid", "aria-label": ctx.view.title });
|
|
366
367
|
const perWeek = this.daysPerWeek();
|
|
@@ -390,14 +391,14 @@ var DayGridView = class {
|
|
|
390
391
|
const cell = h(doc, "div", cls.join(" "), { role: "gridcell", "aria-label": ctx.fmt.longDate(d), "data-date": arg.dateStr });
|
|
391
392
|
if (this.dotsMode) cell.tabIndex = 0;
|
|
392
393
|
const num = ctx.fmt.dayNumber(d);
|
|
393
|
-
const label = ymdOfDay(d).day === 1 ? `${ctx.fmt.monthShort(d)} ${num}` : num;
|
|
394
|
+
const label = !this.dotsMode && ymdOfDay(d).day === 1 ? `${ctx.fmt.monthShort(d)} ${num}` : num;
|
|
394
395
|
cell.append(
|
|
395
396
|
h(
|
|
396
397
|
doc,
|
|
397
398
|
"div",
|
|
398
399
|
"tnc-dg-top",
|
|
399
400
|
null,
|
|
400
|
-
opts.navLinks ? ctx.navLink(d, label, "tnc-dg-num") : h(doc, "span", "tnc-dg-num", null, label)
|
|
401
|
+
opts.navLinks && !this.dotsMode ? ctx.navLink(d, label, "tnc-dg-num") : h(doc, "span", "tnc-dg-num", null, label)
|
|
401
402
|
)
|
|
402
403
|
);
|
|
403
404
|
dates.append(cell);
|
|
@@ -411,20 +412,20 @@ var DayGridView = class {
|
|
|
411
412
|
layer.append(content);
|
|
412
413
|
row.append(dates, layer);
|
|
413
414
|
this.grid.append(row);
|
|
414
|
-
const dots =
|
|
415
|
+
const dots = cells.map((cell) => {
|
|
415
416
|
const box = h(doc, "div", "tnc-dg-dots", { "aria-hidden": "true" });
|
|
416
417
|
if (opts.dayMaxEvents === false) box.classList.add("is-unlimited");
|
|
417
418
|
const count = h(doc, "span", "tnc-dg-dots-more");
|
|
418
419
|
cell.append(box);
|
|
419
420
|
return { box, pool: new ItemPool(ctx, box), count };
|
|
420
|
-
})
|
|
421
|
+
});
|
|
421
422
|
this.weeks.push({ days: wdays, row, cells, layer, sel, more, pool: new ItemPool(ctx, content), dots });
|
|
422
423
|
}
|
|
423
424
|
this.scroller.append(this.grid);
|
|
424
425
|
this.el.append(this.scroller);
|
|
425
426
|
this.el.classList.toggle("tnc-dg--auto", opts.height === "auto");
|
|
426
427
|
const RO = ctx.win.ResizeObserver;
|
|
427
|
-
if (RO
|
|
428
|
+
if (RO) {
|
|
428
429
|
this.resizeObs = new RO(() => {
|
|
429
430
|
if (this.sizeKey() !== this.lastHeights) this.render(null);
|
|
430
431
|
});
|
|
@@ -455,14 +456,35 @@ var DayGridView = class {
|
|
|
455
456
|
}
|
|
456
457
|
render(_change) {
|
|
457
458
|
const { ctx } = this;
|
|
459
|
+
this.dotsMode = ctx.opts.monthDisplay !== "full" || this.grid.clientWidth / this.daysPerWeek() < 72;
|
|
460
|
+
this.el.classList.toggle("tnc-dg--dots", this.dotsMode);
|
|
461
|
+
this.el.classList.toggle("tnc-dg--compact", this.dotsMode && ctx.opts.monthDisplay === "full");
|
|
462
|
+
this.el.classList.toggle("tnc-dg--chips", ctx.opts.monthDisplay === "chips" && this.weeks[0].dots[0].box.clientHeight >= 44);
|
|
458
463
|
const cs = ctx.win.getComputedStyle(this.el);
|
|
459
464
|
this.barPx = px(cs, "--tnc-bar-h", 20);
|
|
460
465
|
this.topPx = this.weeks[0]?.cells[0]?.querySelector(".tnc-dg-top")?.offsetHeight || px(cs, "--tnc-dg-top-h", 24);
|
|
461
466
|
this.morePx = this.measureMore(cs);
|
|
462
467
|
this.lastHeights = this.sizeKey();
|
|
463
468
|
for (const w of this.weeks) {
|
|
464
|
-
|
|
465
|
-
|
|
469
|
+
for (const cell of w.cells) {
|
|
470
|
+
if (this.dotsMode) cell.tabIndex = 0;
|
|
471
|
+
else cell.removeAttribute("tabindex");
|
|
472
|
+
if (this.dotsMode && ctx.opts.monthDisplay === "full") cell.setAttribute("aria-haspopup", "dialog");
|
|
473
|
+
else cell.removeAttribute("aria-haspopup");
|
|
474
|
+
}
|
|
475
|
+
for (const cell of w.dots) cell.box.hidden = !this.dotsMode;
|
|
476
|
+
if (this.dotsMode) {
|
|
477
|
+
w.pool.begin();
|
|
478
|
+
w.pool.end();
|
|
479
|
+
w.more.replaceChildren();
|
|
480
|
+
this.renderDots(w);
|
|
481
|
+
} else {
|
|
482
|
+
for (const cell of w.dots) {
|
|
483
|
+
cell.pool.begin();
|
|
484
|
+
cell.pool.end();
|
|
485
|
+
}
|
|
486
|
+
this.renderWeek(w);
|
|
487
|
+
}
|
|
466
488
|
}
|
|
467
489
|
}
|
|
468
490
|
/** Height of a "+N more" link as the host styles it (`--tnc-more-h`, or a taller min-height). */
|
|
@@ -561,7 +583,8 @@ var DayGridView = class {
|
|
|
561
583
|
w.more.append(link);
|
|
562
584
|
}
|
|
563
585
|
existing.delete(key);
|
|
564
|
-
link.
|
|
586
|
+
link.setAttribute("aria-label", ctx.text.more(items.length));
|
|
587
|
+
link.textContent = w.row.clientWidth / n < 72 ? `+${new Intl.NumberFormat(ctx.opts.locale).format(items.length)}` : ctx.text.more(items.length);
|
|
565
588
|
setStyle(link, {
|
|
566
589
|
left: `calc(${pct(col / n)} + 2px)`,
|
|
567
590
|
width: `calc(${pct(1 / n)} - 4px)`,
|
|
@@ -591,10 +614,11 @@ var DayGridView = class {
|
|
|
591
614
|
const { dayMaxEvents } = ctx.opts;
|
|
592
615
|
const first = w.dots[0].box;
|
|
593
616
|
const cs = ctx.win.getComputedStyle(first);
|
|
594
|
-
const
|
|
617
|
+
const chips = this.el.classList.contains("tnc-dg--chips");
|
|
618
|
+
const size = chips ? px(cs, "--tnc-chip-h", 14) : px(cs, "--tnc-dot-size", 8);
|
|
595
619
|
const gap = px(cs, "--tnc-dot-gap", 3);
|
|
596
620
|
const step = size + gap;
|
|
597
|
-
const perRow = Math.max(1, Math.floor((first.clientWidth + gap) / step));
|
|
621
|
+
const perRow = chips ? 1 : Math.max(1, Math.floor((first.clientWidth + gap) / step));
|
|
598
622
|
const rows = Math.max(1, Math.floor((first.clientHeight + gap) / step));
|
|
599
623
|
const fits = dayMaxEvents === false ? Infinity : perRow * rows;
|
|
600
624
|
const cap = typeof dayMaxEvents === "number" && dayMaxEvents > 0 ? Math.min(dayMaxEvents, fits) : fits;
|
|
@@ -603,7 +627,7 @@ var DayGridView = class {
|
|
|
603
627
|
w.days.forEach((day, i) => {
|
|
604
628
|
const cell = w.dots[i];
|
|
605
629
|
const items = this.itemsOn(day);
|
|
606
|
-
const shown = items.length <= cap ? items.length : cap >= fits ? Math.max(
|
|
630
|
+
const shown = items.length <= cap ? items.length : cap >= fits ? Math.max(1, cap - (chips ? 1 : 2)) : Math.max(1, cap);
|
|
607
631
|
cell.pool.begin();
|
|
608
632
|
const els = items.slice(0, shown).map((n) => cell.pool.place(n.id, { n, day, isStart: n.startDay >= day, isEnd: n.endDay <= day + 1, variant: "indicator", mirror: false }));
|
|
609
633
|
cell.pool.end();
|
|
@@ -720,6 +744,7 @@ var ListView = class {
|
|
|
720
744
|
const leadItems = [];
|
|
721
745
|
const inLead = /* @__PURE__ */ new Set();
|
|
722
746
|
const keep = /* @__PURE__ */ new Set();
|
|
747
|
+
let itemCount = 0;
|
|
723
748
|
let prev = null;
|
|
724
749
|
for (const day of days) {
|
|
725
750
|
let items = this.itemsOn(day);
|
|
@@ -733,7 +758,7 @@ var ListView = class {
|
|
|
733
758
|
return false;
|
|
734
759
|
});
|
|
735
760
|
}
|
|
736
|
-
if (!items.length && !agenda) continue;
|
|
761
|
+
if (!items.length && !agenda && opts.listDayCount !== 1) continue;
|
|
737
762
|
keep.add(day);
|
|
738
763
|
let section = this.sections.get(day);
|
|
739
764
|
let pool = this.pools.get(day);
|
|
@@ -752,6 +777,7 @@ var ListView = class {
|
|
|
752
777
|
this.pools.set(day, pool);
|
|
753
778
|
}
|
|
754
779
|
section.classList.toggle("is-empty", !items.length);
|
|
780
|
+
itemCount += items.length;
|
|
755
781
|
this.fill(pool, items, () => day);
|
|
756
782
|
if (prev ? prev.nextSibling !== section : this.body.firstChild !== section) {
|
|
757
783
|
if (prev) prev.after(section);
|
|
@@ -767,13 +793,14 @@ var ListView = class {
|
|
|
767
793
|
this.sections.delete(day);
|
|
768
794
|
}
|
|
769
795
|
this.renderLead(leadItems);
|
|
770
|
-
let empty = this.body.querySelector("
|
|
771
|
-
if (!
|
|
796
|
+
let empty = this.body.querySelector(".tnc-list-empty");
|
|
797
|
+
if (!itemCount && !leadItems.length && (!agenda || opts.listEmptyContent)) {
|
|
772
798
|
if (!empty) {
|
|
773
799
|
empty = h(doc, "div", "tnc-list-empty", { role: "listitem" }, ctx.text.noItems);
|
|
774
800
|
const content = ctx.opts.listEmptyContent?.();
|
|
775
801
|
if (content) empty.replaceChildren(content);
|
|
776
|
-
this.
|
|
802
|
+
if (this.sections.size === 1) this.sections.values().next().value.append(empty);
|
|
803
|
+
else this.body.prepend(empty);
|
|
777
804
|
}
|
|
778
805
|
} else empty?.remove();
|
|
779
806
|
this.ctx.strip?.draw();
|
|
@@ -831,7 +858,7 @@ var ListView = class {
|
|
|
831
858
|
const section = day === this.ctx.days[0] && this.lead ? this.lead.section : this.sections.get(day);
|
|
832
859
|
if (!section) return;
|
|
833
860
|
this.ctx.strip?.measure();
|
|
834
|
-
section.
|
|
861
|
+
this.scroller.scrollTop += section.getBoundingClientRect().top - this.scroller.getBoundingClientRect().top;
|
|
835
862
|
this.ctx.strip?.setFocus(day);
|
|
836
863
|
this.pinned = true;
|
|
837
864
|
}
|
|
@@ -920,8 +947,7 @@ var DateStrip = class {
|
|
|
920
947
|
head.append(this.title, this.todayBtn, prev, next, this.slot);
|
|
921
948
|
this.dows = h(doc, "div", "tnc-strip-dows", { "aria-hidden": "true" });
|
|
922
949
|
this.grid = h(doc, "div", "tnc-strip-grid", { role: "group" });
|
|
923
|
-
const handle = h(doc, "
|
|
924
|
-
handle.addEventListener("click", () => this.setExpanded(!this.expanded));
|
|
950
|
+
const handle = h(doc, "div", "tnc-strip-handle", { "aria-hidden": "true" });
|
|
925
951
|
this.el.append(head, this.dows, this.grid, handle);
|
|
926
952
|
this.grid.addEventListener("click", this.onClick);
|
|
927
953
|
this.grid.addEventListener("keydown", this.onKeyDown);
|
|
@@ -1500,8 +1526,15 @@ var TimeGridView = class {
|
|
|
1500
1526
|
link.classList.toggle("tnc-more--collision", collapse);
|
|
1501
1527
|
link.textContent = `+${rec.count}`;
|
|
1502
1528
|
if (collapse) {
|
|
1503
|
-
|
|
1504
|
-
|
|
1529
|
+
const items = placements.filter((placement) => placement.cluster === cluster).map((placement) => placement.item.item.title);
|
|
1530
|
+
const count = ctx.text.appointments(rec.count);
|
|
1531
|
+
const interval = `${ctx.fmt.time(rec.start)} \u2013 ${ctx.fmt.time(rec.end)}`;
|
|
1532
|
+
link.replaceChildren(
|
|
1533
|
+
h(ctx.doc, "span", "tnc-collision-count", null, String(rec.count)),
|
|
1534
|
+
h(ctx.doc, "span", "tnc-collision-range", null, interval),
|
|
1535
|
+
h(ctx.doc, "span", "tnc-collision-title", { "aria-hidden": "true" }, items.join(" \xB7 "))
|
|
1536
|
+
);
|
|
1537
|
+
link.setAttribute("aria-label", `${count}, ${interval}: ${items.join(", ")}`);
|
|
1505
1538
|
link.title = link.getAttribute("aria-label");
|
|
1506
1539
|
} else {
|
|
1507
1540
|
link.removeAttribute("aria-label");
|
|
@@ -1510,6 +1543,7 @@ var TimeGridView = class {
|
|
|
1510
1543
|
const cols = maxStack;
|
|
1511
1544
|
setStyle(link, {
|
|
1512
1545
|
top: top(rec.start),
|
|
1546
|
+
height: collapse ? pct((rec.end - rec.start) / this.minutes) : "",
|
|
1513
1547
|
...inLane(lane, rec.split, (cols - 1) / cols, 1 / cols)
|
|
1514
1548
|
});
|
|
1515
1549
|
}
|
|
@@ -1576,12 +1610,10 @@ var TimeGridView = class {
|
|
|
1576
1610
|
const r2 = cells[i2].getBoundingClientRect();
|
|
1577
1611
|
if (x >= r2.left && x < r2.right) return i2;
|
|
1578
1612
|
}
|
|
1579
|
-
const firstR = cells[0]?.getBoundingClientRect();
|
|
1580
|
-
const lastR = cells[cells.length - 1]?.getBoundingClientRect();
|
|
1581
|
-
if (firstR && x < firstR.left) return 0;
|
|
1582
|
-
if (lastR && x >= lastR.right) return cells.length - 1;
|
|
1583
1613
|
return -1;
|
|
1584
1614
|
};
|
|
1615
|
+
const bounds = this.scroller.getBoundingClientRect();
|
|
1616
|
+
if (x < bounds.left || x >= bounds.right || y < bounds.top || y >= bounds.bottom) return null;
|
|
1585
1617
|
if (this.allDayRow) {
|
|
1586
1618
|
const r2 = this.allDayRow.getBoundingClientRect();
|
|
1587
1619
|
if (y >= r2.top && y < r2.bottom || !this.body && y >= r2.top) {
|
|
@@ -2304,6 +2336,14 @@ ${this.ctx.text.more(items.length - 8)}` : ""}` : label;
|
|
|
2304
2336
|
setScroll(s) {
|
|
2305
2337
|
this.scroller.scrollTop = s.top;
|
|
2306
2338
|
}
|
|
2339
|
+
revealDay(day) {
|
|
2340
|
+
const month = this.cells.find((cell) => cell.day === day)?.el.closest(".tnc-ym");
|
|
2341
|
+
if (!month) return;
|
|
2342
|
+
const bounds = month.getBoundingClientRect();
|
|
2343
|
+
const viewport = this.scroller.getBoundingClientRect();
|
|
2344
|
+
if (bounds.top < viewport.top) this.scroller.scrollTop += bounds.top - viewport.top;
|
|
2345
|
+
else if (bounds.bottom > viewport.bottom) this.scroller.scrollTop += bounds.bottom - viewport.bottom;
|
|
2346
|
+
}
|
|
2307
2347
|
elementsFor(_id) {
|
|
2308
2348
|
return [];
|
|
2309
2349
|
}
|
|
@@ -2383,6 +2423,11 @@ var Calendar = class {
|
|
|
2383
2423
|
conflicts = /* @__PURE__ */ new Map();
|
|
2384
2424
|
slot = { min: 0, max: MINUTES_PER_DAY, duration: 30, snap: 30, scroll: 480 };
|
|
2385
2425
|
draggingId = null;
|
|
2426
|
+
listDragPreview = null;
|
|
2427
|
+
dragSources = [];
|
|
2428
|
+
dragScrollFrame = null;
|
|
2429
|
+
dragScrollOrigins = /* @__PURE__ */ new Map();
|
|
2430
|
+
itemWriteStates = /* @__PURE__ */ new Map();
|
|
2386
2431
|
dragRow = null;
|
|
2387
2432
|
strip = null;
|
|
2388
2433
|
stripSize = null;
|
|
@@ -2396,6 +2441,7 @@ var Calendar = class {
|
|
|
2396
2441
|
session = null;
|
|
2397
2442
|
selection = null;
|
|
2398
2443
|
suppressClick = false;
|
|
2444
|
+
cancelledPointerId = null;
|
|
2399
2445
|
selectedIds = /* @__PURE__ */ new Set();
|
|
2400
2446
|
popover = null;
|
|
2401
2447
|
timer = null;
|
|
@@ -2413,6 +2459,7 @@ var Calendar = class {
|
|
|
2413
2459
|
this.positionMore();
|
|
2414
2460
|
});
|
|
2415
2461
|
this.resizeObs.observe(this.root);
|
|
2462
|
+
this.resizeObs.observe(this.toolbarEl);
|
|
2416
2463
|
}
|
|
2417
2464
|
}
|
|
2418
2465
|
onAdoptCheck = () => {
|
|
@@ -2539,7 +2586,12 @@ var Calendar = class {
|
|
|
2539
2586
|
gotoDate(date) {
|
|
2540
2587
|
const day = this.toDay(date);
|
|
2541
2588
|
if (day === null) return;
|
|
2589
|
+
const sameMonth = this.opts.view === "month" && startOfMonth(day) === startOfMonth(this.anchor);
|
|
2542
2590
|
this.anchor = day;
|
|
2591
|
+
if (sameMonth) {
|
|
2592
|
+
this.view = { ...this.view, anchor: day };
|
|
2593
|
+
return;
|
|
2594
|
+
}
|
|
2543
2595
|
this.rebuild(true);
|
|
2544
2596
|
}
|
|
2545
2597
|
prev() {
|
|
@@ -2685,7 +2737,8 @@ var Calendar = class {
|
|
|
2685
2737
|
out.push(...classList(this.opts.dayClassNames?.(this.dayArg(day))));
|
|
2686
2738
|
return out;
|
|
2687
2739
|
}
|
|
2688
|
-
isEditable(n, what) {
|
|
2740
|
+
isEditable(n, what, presentation = false) {
|
|
2741
|
+
if (!presentation && this.itemWriteStates.get(n.id) === "pending") return false;
|
|
2689
2742
|
if (n.id === EXTERNAL_ID || n.item.preview || this.opts.view === "year") return false;
|
|
2690
2743
|
if (this.opts.view === "list" && (!this.opts.listAgenda || what === "duration")) return false;
|
|
2691
2744
|
const it = n.item;
|
|
@@ -2725,13 +2778,14 @@ var Calendar = class {
|
|
|
2725
2778
|
if (preview || n.id === EXTERNAL_ID) el.classList.add("is-mirror");
|
|
2726
2779
|
if (this.conflicts.has(n.id)) el.classList.add("is-conflict");
|
|
2727
2780
|
const indicator = variant === "indicator";
|
|
2728
|
-
if (!preview && !indicator && (this.isEditable(n, "start") || this.isEditable(n, "duration"))) el.classList.add("is-draggable");
|
|
2781
|
+
if (!preview && !indicator && (this.isEditable(n, "start", true) || this.isEditable(n, "duration", true))) el.classList.add("is-draggable");
|
|
2729
2782
|
if (this.draggingId === n.id) el.classList.add("is-dragging");
|
|
2730
2783
|
if (this.selectedIds.has(n.id) && !preview) el.classList.add("is-selected");
|
|
2731
2784
|
el.classList.add(...classList(it.className));
|
|
2732
2785
|
const arg = this.itemArg(el, meta);
|
|
2733
2786
|
el.classList.add(...classList(this.opts.itemClassNames?.(arg)));
|
|
2734
2787
|
el.dataset.id = n.id;
|
|
2788
|
+
this.applyItemWriteState(el, n.id);
|
|
2735
2789
|
if (it.kind) el.dataset.kind = it.kind;
|
|
2736
2790
|
const color = it.color ?? it.borderColor;
|
|
2737
2791
|
if (color) el.style.setProperty("--tnc-c", color);
|
|
@@ -2748,6 +2802,7 @@ var Calendar = class {
|
|
|
2748
2802
|
const custom = variant === "list" ? this.opts.listItemContent?.(arg) : null;
|
|
2749
2803
|
const content = indicator ? null : custom ?? this.opts.itemContent?.(arg);
|
|
2750
2804
|
if (indicator) {
|
|
2805
|
+
if (this.opts.monthDisplay === "chips") el.append(h(this.doc, "span", "tnc-item-title", null, it.title));
|
|
2751
2806
|
} else if (content != null) {
|
|
2752
2807
|
const wrap = h(this.doc, "div", "tnc-item-main");
|
|
2753
2808
|
wrap.append(content);
|
|
@@ -2760,6 +2815,7 @@ var Calendar = class {
|
|
|
2760
2815
|
return el;
|
|
2761
2816
|
}
|
|
2762
2817
|
refreshItemEl(el, meta) {
|
|
2818
|
+
this.applyItemWriteState(el, meta.n.id);
|
|
2763
2819
|
const time = el.querySelector(":scope .tnc-item-time");
|
|
2764
2820
|
if (time) this.fillTime(time, meta.n, meta.variant, meta.day);
|
|
2765
2821
|
el.classList.toggle("is-dragging", this.draggingId === meta.n.id);
|
|
@@ -2942,6 +2998,7 @@ var Calendar = class {
|
|
|
2942
2998
|
this.current.scrollToTime(this.slot.scroll);
|
|
2943
2999
|
this.current.revealDay(this.anchor);
|
|
2944
3000
|
} else if (this.current instanceof TimelineView) this.current.scrollToDay(this.anchor);
|
|
3001
|
+
else if (this.current instanceof YearView) this.current.revealDay(this.anchor);
|
|
2945
3002
|
if (rangeChanged) this.opts.onRangeChange?.(this.view);
|
|
2946
3003
|
}
|
|
2947
3004
|
/** Sets the visible days and view info from the anchor. */
|
|
@@ -2967,9 +3024,11 @@ var Calendar = class {
|
|
|
2967
3024
|
}
|
|
2968
3025
|
/** The range, run on to the end of the strip's days so their dots are right. */
|
|
2969
3026
|
dataRangeFor(range) {
|
|
2970
|
-
const
|
|
2971
|
-
|
|
2972
|
-
|
|
3027
|
+
const window = this.strip?.window();
|
|
3028
|
+
const start = window ? Math.min(range.startDay, window.start) : range.startDay;
|
|
3029
|
+
const end = window ? Math.max(range.endDay, window.end) : range.endDay;
|
|
3030
|
+
if (start === range.startDay && end === range.endDay) return range;
|
|
3031
|
+
return { ...range, startDay: start, start: new Date(toInstant(start, 0, this.zone)), endDay: end, end: new Date(toInstant(end, 0, this.zone)) };
|
|
2973
3032
|
}
|
|
2974
3033
|
/** Adds, updates or removes the date strip for the current view. */
|
|
2975
3034
|
syncStrip(navigated) {
|
|
@@ -3016,20 +3075,24 @@ var Calendar = class {
|
|
|
3016
3075
|
stripShown() {
|
|
3017
3076
|
if (!this.strip || this.rebuilding || !this.view) return;
|
|
3018
3077
|
const next = this.dataRangeFor(this.view.range);
|
|
3019
|
-
if (next.endDay === this.view.dataRange.endDay) return;
|
|
3078
|
+
if (next.startDay === this.view.dataRange.startDay && next.endDay === this.view.dataRange.endDay) return;
|
|
3020
3079
|
this.view = { ...this.view, dataRange: next };
|
|
3021
3080
|
this.opts.onRangeChange?.(this.view);
|
|
3022
3081
|
}
|
|
3023
3082
|
/** What is under a point, the date strip included. */
|
|
3024
3083
|
hitAt(x, y) {
|
|
3084
|
+
const target = this.doc.elementFromPoint(x, y);
|
|
3085
|
+
if (!target || !this.root.contains(target)) {
|
|
3086
|
+
this.strip?.markTarget(null);
|
|
3087
|
+
return null;
|
|
3088
|
+
}
|
|
3025
3089
|
const strip = this.strip;
|
|
3026
3090
|
if (strip) {
|
|
3027
|
-
const
|
|
3028
|
-
const day = el ? strip.dayAt(el) : null;
|
|
3091
|
+
const day = strip.dayAt(target);
|
|
3029
3092
|
strip.markTarget(day !== null && this.draggingId ? day : null);
|
|
3030
3093
|
if (day !== null) return { kind: "day", day };
|
|
3031
3094
|
}
|
|
3032
|
-
return this.current?.hit(x, y)
|
|
3095
|
+
return this.current?.el.contains(target) ? this.current.hit(x, y) : null;
|
|
3033
3096
|
}
|
|
3034
3097
|
agendaList() {
|
|
3035
3098
|
return this.opts.view === "list" && this.opts.listAgenda && this.current instanceof ListView ? this.current : null;
|
|
@@ -3143,11 +3206,13 @@ var Calendar = class {
|
|
|
3143
3206
|
buttons.style.display = "flex";
|
|
3144
3207
|
select.style.display = "none";
|
|
3145
3208
|
const startWidth = Array.from(start.children).reduce((width, child) => width + child.scrollWidth, 0);
|
|
3146
|
-
const
|
|
3209
|
+
const availableWidth = Math.min(this.root.clientWidth, this.toolbarEl.clientWidth);
|
|
3210
|
+
const compact = mode === "select" || mode === "auto" && startWidth + buttons.scrollWidth + 32 > availableWidth;
|
|
3147
3211
|
buttons.hidden = compact;
|
|
3148
3212
|
select.hidden = !compact;
|
|
3149
3213
|
buttons.style.display = compact ? "none" : "flex";
|
|
3150
3214
|
select.style.display = compact ? "" : "none";
|
|
3215
|
+
select.parentElement?.classList.toggle("tnc-toolbar-end--compact", compact);
|
|
3151
3216
|
}
|
|
3152
3217
|
applyChange(change) {
|
|
3153
3218
|
if (!change.added.length && !change.updated.length && !change.removed.length && !change.days.size && !change.spans) return;
|
|
@@ -3212,7 +3277,7 @@ var Calendar = class {
|
|
|
3212
3277
|
const s = wallTime(n.startMs, this.zone);
|
|
3213
3278
|
const start = this.fmt.time(s.minute, true);
|
|
3214
3279
|
if (variant === "dot" || variant === "bar" || variant === "indicator") return { start: s.day === day ? start : "", end: "" };
|
|
3215
|
-
if (n.startMs === n.endMs) return { start, end: "" };
|
|
3280
|
+
if (n.startMs === n.endMs || n.item.timeDisplay === "start") return { start, end: "" };
|
|
3216
3281
|
return { start, end: this.fmt.time(wallTime(n.endMs, this.zone).minute, true) };
|
|
3217
3282
|
}
|
|
3218
3283
|
fillTime(el, n, variant, day) {
|
|
@@ -3228,7 +3293,8 @@ var Calendar = class {
|
|
|
3228
3293
|
}
|
|
3229
3294
|
const s = wallTime(n.startMs, this.zone);
|
|
3230
3295
|
const e = wallTime(n.endMs, this.zone);
|
|
3231
|
-
|
|
3296
|
+
const start = `${n.item.title}, ${this.fmt.longDate(s.day)} ${this.fmt.time(s.minute)}`;
|
|
3297
|
+
return n.item.timeDisplay === "start" || n.startMs === n.endMs ? start : `${start} \u2013 ${this.fmt.time(e.minute)}`;
|
|
3232
3298
|
}
|
|
3233
3299
|
defaultContent(meta) {
|
|
3234
3300
|
const { n, variant, day } = meta;
|
|
@@ -3256,7 +3322,7 @@ var Calendar = class {
|
|
|
3256
3322
|
addHandles(el, meta) {
|
|
3257
3323
|
const { n, variant } = meta;
|
|
3258
3324
|
const ports = variant === "timeline" && !meta.mirror && n.id !== EXTERNAL_ID && !!this.opts.timeline?.onLink;
|
|
3259
|
-
if (variant === "dot" || !this.isEditable(n, "duration")) {
|
|
3325
|
+
if (variant === "dot" || !this.isEditable(n, "duration", true)) {
|
|
3260
3326
|
if (ports) this.addPorts(el, n);
|
|
3261
3327
|
return;
|
|
3262
3328
|
}
|
|
@@ -3384,6 +3450,10 @@ var Calendar = class {
|
|
|
3384
3450
|
return el && this.root.contains(el) && this.meta.has(el) && !this.meta.get(el)?.n.item.preview ? el : null;
|
|
3385
3451
|
}
|
|
3386
3452
|
onDocPointerDown = (ev) => {
|
|
3453
|
+
if (this.cancelledPointerId !== null) {
|
|
3454
|
+
this.cancelledPointerId = null;
|
|
3455
|
+
this.listenDoc(false);
|
|
3456
|
+
}
|
|
3387
3457
|
const t = ev.target;
|
|
3388
3458
|
if (this.popover && !this.popover.el.contains(t) && !this.popover.anchor.contains(t)) this.closeMore();
|
|
3389
3459
|
if (this.selection && !this.root.contains(t)) this.unselect();
|
|
@@ -3391,6 +3461,7 @@ var Calendar = class {
|
|
|
3391
3461
|
onPointerDown = (ev) => {
|
|
3392
3462
|
if (ev.button !== 0 || this.session) return;
|
|
3393
3463
|
const target = ev.target;
|
|
3464
|
+
if (target.closest(".tnc-dg--compact .tnc-dg-day")) return;
|
|
3394
3465
|
if (target.closest("button, a, input, select, textarea, .tnc-toolbar, .tnc-port, [data-tnc-no-drag]")) {
|
|
3395
3466
|
if (!target.closest(".tnc-item")) return;
|
|
3396
3467
|
if (target.closest(".tnc-port, [data-tnc-no-drag], input, select, textarea")) return;
|
|
@@ -3423,7 +3494,7 @@ var Calendar = class {
|
|
|
3423
3494
|
y0: ev.clientY,
|
|
3424
3495
|
active: false,
|
|
3425
3496
|
origin,
|
|
3426
|
-
grab: overflowOrigin
|
|
3497
|
+
grab: overflowOrigin ? this.current instanceof TimeGridView && !origin?.allDay ? { kind: "time", day: overflowOrigin.day, minute: overflowOrigin.minute } : { kind: "day", day: this.meta.get(itemEl).day } : this.current?.hit(ev.clientX, ev.clientY) ?? null,
|
|
3427
3498
|
proposal: null,
|
|
3428
3499
|
denied: false,
|
|
3429
3500
|
timer: null,
|
|
@@ -3448,16 +3519,79 @@ var Calendar = class {
|
|
|
3448
3519
|
};
|
|
3449
3520
|
activate(s) {
|
|
3450
3521
|
s.active = true;
|
|
3522
|
+
if (s.lastEvent) this.leaveHover(s.lastEvent);
|
|
3451
3523
|
if (s.timer !== null) this.win.clearTimeout(s.timer);
|
|
3452
3524
|
s.timer = null;
|
|
3453
3525
|
if (s.origin) {
|
|
3454
3526
|
this.draggingId = s.origin.id;
|
|
3455
|
-
for (const el of this.elementsFor(s.origin.id))
|
|
3527
|
+
for (const el of this.elementsFor(s.origin.id)) {
|
|
3528
|
+
if (this.opts.view !== "list" && s.mode === "move") {
|
|
3529
|
+
const source = el.cloneNode(true);
|
|
3530
|
+
source.classList.remove("is-selected");
|
|
3531
|
+
source.classList.add("tnc-drag-source");
|
|
3532
|
+
source.setAttribute("aria-hidden", "true");
|
|
3533
|
+
source.inert = true;
|
|
3534
|
+
for (const node of [source, ...source.querySelectorAll("[id], [data-id], [data-task-path]")]) {
|
|
3535
|
+
node.removeAttribute("id");
|
|
3536
|
+
node.removeAttribute("data-id");
|
|
3537
|
+
node.removeAttribute("data-task-path");
|
|
3538
|
+
}
|
|
3539
|
+
el.before(source);
|
|
3540
|
+
this.dragSources.push(source);
|
|
3541
|
+
}
|
|
3542
|
+
if (this.opts.view === "list" && !this.listDragPreview && s.mode === "move") {
|
|
3543
|
+
const bounds = el.getBoundingClientRect();
|
|
3544
|
+
const preview = el.cloneNode(true);
|
|
3545
|
+
preview.classList.add("tnc-drag-preview", "is-dragging");
|
|
3546
|
+
preview.removeAttribute("data-id");
|
|
3547
|
+
preview.removeAttribute("data-task-path");
|
|
3548
|
+
preview.setAttribute("aria-hidden", "true");
|
|
3549
|
+
preview.inert = true;
|
|
3550
|
+
preview.style.width = `${bounds.width}px`;
|
|
3551
|
+
this.root.append(preview);
|
|
3552
|
+
this.listDragPreview = { element: preview, offsetX: s.x0 - bounds.left, offsetY: s.y0 - bounds.top, width: bounds.width, height: bounds.height };
|
|
3553
|
+
}
|
|
3554
|
+
el.classList.add("is-dragging");
|
|
3555
|
+
}
|
|
3456
3556
|
}
|
|
3457
3557
|
this.closeMore();
|
|
3458
3558
|
if (s.mode !== "select") this.unselectSilently();
|
|
3459
3559
|
this.root.classList.add("tnc-dragging", `tnc-dragging-${s.mode}`);
|
|
3460
3560
|
if (s.lastEvent) this.track(s, s.lastEvent);
|
|
3561
|
+
this.startDragScroll();
|
|
3562
|
+
}
|
|
3563
|
+
startDragScroll() {
|
|
3564
|
+
if (this.dragScrollFrame !== null) return;
|
|
3565
|
+
const tick = () => {
|
|
3566
|
+
this.dragScrollFrame = null;
|
|
3567
|
+
const session = this.session;
|
|
3568
|
+
const pointer = session?.lastEvent;
|
|
3569
|
+
if (!session?.active || !pointer) return;
|
|
3570
|
+
const origin = session.origin ? this.elementsFor(session.origin.id)[0] : this.viewHost;
|
|
3571
|
+
const underPointer = this.doc.elementFromPoint(pointer.clientX, pointer.clientY);
|
|
3572
|
+
let moved = false;
|
|
3573
|
+
if (origin && underPointer && this.root.contains(underPointer)) {
|
|
3574
|
+
for (const axis of ["x", "y"]) {
|
|
3575
|
+
const scroller = scrollerOf(origin, axis);
|
|
3576
|
+
if (!scroller) continue;
|
|
3577
|
+
const viewport = scroller === this.doc.scrollingElement ? { left: 0, top: 0, right: this.win.innerWidth, bottom: this.win.innerHeight } : scroller.getBoundingClientRect();
|
|
3578
|
+
const coordinate = axis === "x" ? pointer.clientX : pointer.clientY;
|
|
3579
|
+
const lower = Math.max(0, axis === "x" ? viewport.left : viewport.top);
|
|
3580
|
+
const upper = Math.min(axis === "x" ? this.win.innerWidth : this.win.innerHeight, axis === "x" ? viewport.right : viewport.bottom);
|
|
3581
|
+
if (coordinate < lower || coordinate > upper) continue;
|
|
3582
|
+
const delta = coordinate < lower + 32 ? -Math.min(12, (lower + 32 - coordinate) / 2) : coordinate > upper - 32 ? Math.min(12, (coordinate - upper + 32) / 2) : 0;
|
|
3583
|
+
if (!delta) continue;
|
|
3584
|
+
if (!this.dragScrollOrigins.has(scroller)) this.dragScrollOrigins.set(scroller, { top: scroller.scrollTop, left: scroller.scrollLeft });
|
|
3585
|
+
const before = axis === "x" ? scroller.scrollLeft : scroller.scrollTop;
|
|
3586
|
+
if (axis === "x") scroller.scrollLeft += delta;
|
|
3587
|
+
else scroller.scrollTop += delta;
|
|
3588
|
+
moved ||= before !== (axis === "x" ? scroller.scrollLeft : scroller.scrollTop);
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
if (moved) this.track(session, pointer);
|
|
3592
|
+
this.dragScrollFrame = this.win.requestAnimationFrame(tick);
|
|
3593
|
+
};
|
|
3594
|
+
this.dragScrollFrame = this.win.requestAnimationFrame(tick);
|
|
3461
3595
|
}
|
|
3462
3596
|
onTouchMove = (ev) => {
|
|
3463
3597
|
if (this.session?.active) ev.preventDefault();
|
|
@@ -3487,6 +3621,12 @@ var Calendar = class {
|
|
|
3487
3621
|
this.track(s, ev);
|
|
3488
3622
|
};
|
|
3489
3623
|
onPointerUp = (ev) => {
|
|
3624
|
+
if (ev.pointerId === this.cancelledPointerId) {
|
|
3625
|
+
this.cancelledPointerId = null;
|
|
3626
|
+
this.suppressNextClick();
|
|
3627
|
+
this.listenDoc(false);
|
|
3628
|
+
return;
|
|
3629
|
+
}
|
|
3490
3630
|
const s = this.session;
|
|
3491
3631
|
if (!s || ev.pointerId !== s.pointerId) return;
|
|
3492
3632
|
if (!s.active) {
|
|
@@ -3499,28 +3639,49 @@ var Calendar = class {
|
|
|
3499
3639
|
return;
|
|
3500
3640
|
}
|
|
3501
3641
|
this.suppressNextClick();
|
|
3642
|
+
this.track(s, ev);
|
|
3502
3643
|
this.endSession(ev, false);
|
|
3503
3644
|
};
|
|
3504
3645
|
onPointerCancel = (ev) => {
|
|
3646
|
+
if (ev.pointerId === this.cancelledPointerId) {
|
|
3647
|
+
this.cancelledPointerId = null;
|
|
3648
|
+
this.listenDoc(false);
|
|
3649
|
+
}
|
|
3505
3650
|
if (this.session && ev.pointerId === this.session.pointerId) this.endSession(null, true);
|
|
3506
3651
|
};
|
|
3507
3652
|
onDocKeyDown = (ev) => {
|
|
3508
3653
|
if (ev.key === "Escape" && this.session) {
|
|
3509
3654
|
ev.preventDefault();
|
|
3510
3655
|
ev.stopPropagation();
|
|
3656
|
+
const pointerId = this.session.active ? this.session.pointerId : null;
|
|
3511
3657
|
this.endSession(null, true);
|
|
3658
|
+
if (pointerId !== null) {
|
|
3659
|
+
this.cancelledPointerId = pointerId;
|
|
3660
|
+
this.listenDoc(true);
|
|
3661
|
+
}
|
|
3512
3662
|
}
|
|
3513
3663
|
};
|
|
3514
3664
|
/** Proposal for the current pointer position. */
|
|
3515
3665
|
track(s, ev) {
|
|
3666
|
+
if (this.listDragPreview) {
|
|
3667
|
+
const preview = this.listDragPreview;
|
|
3668
|
+
const bounds = this.root.getBoundingClientRect();
|
|
3669
|
+
preview.element.style.left = `${Math.max(8, Math.min(this.win.innerWidth - preview.width - 8, ev.clientX - preview.offsetX)) - bounds.left}px`;
|
|
3670
|
+
preview.element.style.top = `${Math.max(8, Math.min(this.win.innerHeight - preview.height - 8, ev.clientY - preview.offsetY)) - bounds.top}px`;
|
|
3671
|
+
}
|
|
3516
3672
|
const hit = this.hitAt(ev.clientX, ev.clientY);
|
|
3517
3673
|
if (s.mode === "external") {
|
|
3518
3674
|
this.trackExternal(s, hit);
|
|
3519
3675
|
return;
|
|
3520
3676
|
}
|
|
3521
3677
|
if (!s.grab) s.grab = hit;
|
|
3522
|
-
if (!hit || !s.grab)
|
|
3678
|
+
if (!hit || !s.grab) {
|
|
3679
|
+
this.invalidateProposal(s);
|
|
3680
|
+
return;
|
|
3681
|
+
}
|
|
3523
3682
|
if (s.mode === "select") {
|
|
3683
|
+
s.denied = false;
|
|
3684
|
+
this.root.classList.remove("tnc-drop-denied");
|
|
3524
3685
|
const sel = this.selectionFor(s.grab, hit);
|
|
3525
3686
|
if (!sel) return;
|
|
3526
3687
|
this.selection = sel;
|
|
@@ -3529,25 +3690,40 @@ var Calendar = class {
|
|
|
3529
3690
|
}
|
|
3530
3691
|
const origin = s.origin;
|
|
3531
3692
|
const p = s.mode === "move" ? this.moveProposal(origin, s.grab, hit) : this.resizeProposal(origin, hit, s.mode === "resize-start");
|
|
3532
|
-
if (!p)
|
|
3693
|
+
if (!p) {
|
|
3694
|
+
this.invalidateProposal(s);
|
|
3695
|
+
return;
|
|
3696
|
+
}
|
|
3533
3697
|
const allowed = this.opts.canDrop?.({ item: origin.item, start: new Date(p.startMs), end: new Date(p.endMs), allDay: p.allDay, rowId: p.rowId }) ?? true;
|
|
3534
3698
|
s.denied = !allowed;
|
|
3535
3699
|
this.root.classList.toggle("tnc-drop-denied", !allowed);
|
|
3536
|
-
if (!allowed
|
|
3700
|
+
if (!allowed) {
|
|
3701
|
+
this.invalidateProposal(s);
|
|
3702
|
+
return;
|
|
3703
|
+
}
|
|
3704
|
+
if (sameProposal(p, s.proposal)) return;
|
|
3537
3705
|
s.proposal = p;
|
|
3538
3706
|
this.dragRow = p.rowId !== void 0 ? { id: origin.id, rowId: p.rowId } : null;
|
|
3539
|
-
this.applyChange(this.store.upsert([this.withProposal(origin, p)]));
|
|
3707
|
+
if (this.opts.view !== "list") this.applyChange(this.store.upsert([this.withProposal(origin, p)]));
|
|
3708
|
+
}
|
|
3709
|
+
invalidateProposal(s) {
|
|
3710
|
+
const hadProposal = s.proposal !== null;
|
|
3711
|
+
s.proposal = null;
|
|
3712
|
+
s.hit = null;
|
|
3713
|
+
s.denied = true;
|
|
3714
|
+
this.dragRow = null;
|
|
3715
|
+
this.root.classList.add("tnc-drop-denied");
|
|
3716
|
+
this.strip?.markTarget(null);
|
|
3717
|
+
this.unselectSilently();
|
|
3718
|
+
if (s.mode === "external") this.applyChange(this.store.remove([EXTERNAL_ID]));
|
|
3719
|
+
else if (hadProposal && s.origin) this.applyChange(this.store.upsert([s.origin.item]));
|
|
3540
3720
|
}
|
|
3541
3721
|
trackExternal(s, raw) {
|
|
3542
3722
|
const src = s.source;
|
|
3543
3723
|
const hit = raw?.kind === "timeline" && raw.area !== "track" && raw.area !== "header" ? null : raw;
|
|
3544
3724
|
s.hit = hit;
|
|
3545
3725
|
if (!hit) {
|
|
3546
|
-
|
|
3547
|
-
s.proposal = null;
|
|
3548
|
-
this.applyChange(this.store.remove([EXTERNAL_ID]));
|
|
3549
|
-
}
|
|
3550
|
-
this.unselectSilently();
|
|
3726
|
+
this.invalidateProposal(s);
|
|
3551
3727
|
return;
|
|
3552
3728
|
}
|
|
3553
3729
|
const dur = src.durationMinutes ?? this.opts.defaultTimedMinutes;
|
|
@@ -3566,6 +3742,10 @@ var Calendar = class {
|
|
|
3566
3742
|
const allowed = this.opts.canDrop?.({ item: this.externalItem(src, p), start: new Date(p.startMs), end: new Date(p.endMs), allDay: p.allDay, rowId: p.rowId }) ?? true;
|
|
3567
3743
|
s.denied = !allowed;
|
|
3568
3744
|
this.root.classList.toggle("tnc-drop-denied", !allowed);
|
|
3745
|
+
if (!allowed) {
|
|
3746
|
+
this.invalidateProposal(s);
|
|
3747
|
+
return;
|
|
3748
|
+
}
|
|
3569
3749
|
if (sameProposal(p, s.proposal)) return;
|
|
3570
3750
|
s.proposal = p;
|
|
3571
3751
|
if (hit.kind === "timeline" && p.rowId === void 0) {
|
|
@@ -3758,7 +3938,18 @@ var Calendar = class {
|
|
|
3758
3938
|
endSession(ev, cancel) {
|
|
3759
3939
|
const s = this.session;
|
|
3760
3940
|
if (!s) return;
|
|
3941
|
+
if (this.dragScrollFrame !== null) this.win.cancelAnimationFrame(this.dragScrollFrame);
|
|
3942
|
+
this.dragScrollFrame = null;
|
|
3943
|
+
if (cancel || s.denied) for (const [scroller, position] of this.dragScrollOrigins) {
|
|
3944
|
+
scroller.scrollTop = position.top;
|
|
3945
|
+
scroller.scrollLeft = position.left;
|
|
3946
|
+
}
|
|
3947
|
+
this.dragScrollOrigins.clear();
|
|
3761
3948
|
this.session = null;
|
|
3949
|
+
this.listDragPreview?.element.remove();
|
|
3950
|
+
this.listDragPreview = null;
|
|
3951
|
+
for (const source of this.dragSources) source.remove();
|
|
3952
|
+
this.dragSources = [];
|
|
3762
3953
|
if (s.timer !== null) this.win.clearTimeout(s.timer);
|
|
3763
3954
|
this.listenDoc(false);
|
|
3764
3955
|
this.root.classList.remove(
|
|
@@ -3827,10 +4018,16 @@ var Calendar = class {
|
|
|
3827
4018
|
revert();
|
|
3828
4019
|
return;
|
|
3829
4020
|
}
|
|
4021
|
+
if (this.opts.view === "list") this.applyChange(this.store.upsert([this.withProposal(origin, p)]));
|
|
3830
4022
|
this.flush();
|
|
3831
4023
|
this.commit(s.mode === "move" ? "drop" : "resize", origin, p, ev, revert);
|
|
3832
4024
|
}
|
|
3833
4025
|
commit(kind, origin, p, ev, revert) {
|
|
4026
|
+
let reverted = false;
|
|
4027
|
+
const mark = (state) => {
|
|
4028
|
+
this.itemWriteStates.set(origin.id, state);
|
|
4029
|
+
for (const element of this.elementsFor(origin.id)) this.applyItemWriteState(element, origin.id);
|
|
4030
|
+
};
|
|
3834
4031
|
const arg = {
|
|
3835
4032
|
item: origin.item,
|
|
3836
4033
|
start: new Date(p.startMs),
|
|
@@ -3846,19 +4043,32 @@ var Calendar = class {
|
|
|
3846
4043
|
jsEvent: ev,
|
|
3847
4044
|
source: ev && "key" in ev ? "keyboard" : "pointer",
|
|
3848
4045
|
view: this.view,
|
|
3849
|
-
revert
|
|
4046
|
+
revert: () => {
|
|
4047
|
+
reverted = true;
|
|
4048
|
+
revert();
|
|
4049
|
+
mark("failed");
|
|
4050
|
+
}
|
|
3850
4051
|
};
|
|
3851
4052
|
const handler = kind === "drop" ? this.opts.onItemDrop : this.opts.onItemResize;
|
|
3852
4053
|
try {
|
|
4054
|
+
mark("pending");
|
|
3853
4055
|
const res = handler?.(arg);
|
|
3854
4056
|
if (res && typeof res.then === "function") {
|
|
3855
|
-
Promise.resolve(res).
|
|
3856
|
-
|
|
4057
|
+
void Promise.resolve(res).then(() => {
|
|
4058
|
+
if (!reverted) mark("changed");
|
|
4059
|
+
}, () => arg.revert());
|
|
4060
|
+
} else if (!reverted) mark("changed");
|
|
3857
4061
|
} catch (err) {
|
|
3858
|
-
revert();
|
|
4062
|
+
arg.revert();
|
|
3859
4063
|
throw err;
|
|
3860
4064
|
}
|
|
3861
4065
|
}
|
|
4066
|
+
applyItemWriteState(element, id) {
|
|
4067
|
+
const state = this.itemWriteStates.get(id);
|
|
4068
|
+
for (const name of ["pending", "failed", "changed"]) element.classList.toggle(`is-write-${name}`, state === name);
|
|
4069
|
+
if (state === "pending") element.setAttribute("aria-busy", "true");
|
|
4070
|
+
else element.removeAttribute("aria-busy");
|
|
4071
|
+
}
|
|
3862
4072
|
/* --------------------------------------------------------- click / keys */
|
|
3863
4073
|
/** Runs in the capture phase so the click ending a drag never reaches content inside the calendar, React portals included. */
|
|
3864
4074
|
onClickCapture = (ev) => {
|
|
@@ -3868,6 +4078,12 @@ var Calendar = class {
|
|
|
3868
4078
|
ev.preventDefault();
|
|
3869
4079
|
};
|
|
3870
4080
|
onClick = (ev) => {
|
|
4081
|
+
const compactDay = ev.target.closest?.(".tnc-dg--compact .tnc-dg-day");
|
|
4082
|
+
if (compactDay && this.root.contains(compactDay) && !ev.target.closest(".tnc-navlink")) {
|
|
4083
|
+
const day = parseDay(compactDay.dataset.date ?? "");
|
|
4084
|
+
if (day !== null) this.openMore(day, compactDay, ev);
|
|
4085
|
+
return;
|
|
4086
|
+
}
|
|
3871
4087
|
const yearDay = ev.target.closest?.(".tnc-ym-day");
|
|
3872
4088
|
if (yearDay && this.root.contains(yearDay)) {
|
|
3873
4089
|
const day = parseDay(yearDay.dataset.date ?? "");
|
|
@@ -3956,7 +4172,8 @@ var Calendar = class {
|
|
|
3956
4172
|
const day = parseDay(target.dataset.date ?? "");
|
|
3957
4173
|
if (day !== null) {
|
|
3958
4174
|
ev.preventDefault();
|
|
3959
|
-
|
|
4175
|
+
if (target.closest(".tnc-dg--compact")) this.openMore(day, target, ev);
|
|
4176
|
+
else this.clickSlot({ kind: "day", day }, ev, true);
|
|
3960
4177
|
}
|
|
3961
4178
|
return;
|
|
3962
4179
|
}
|
|
@@ -4044,9 +4261,13 @@ var Calendar = class {
|
|
|
4044
4261
|
const dt = ev.dataTransfer;
|
|
4045
4262
|
if (!dt || !this.opts.acceptNativeDrop?.(dt) || !this.current) return;
|
|
4046
4263
|
ev.preventDefault();
|
|
4264
|
+
const hit = this.hitAt(ev.clientX, ev.clientY);
|
|
4265
|
+
if (!hit || hit.kind === "timeline" && hit.area !== "track" && hit.area !== "header") {
|
|
4266
|
+
dt.dropEffect = "none";
|
|
4267
|
+
this.unselectSilently();
|
|
4268
|
+
return;
|
|
4269
|
+
}
|
|
4047
4270
|
dt.dropEffect = "copy";
|
|
4048
|
-
const hit = this.current.hit(ev.clientX, ev.clientY);
|
|
4049
|
-
if (!hit || hit.kind === "timeline" && hit.area !== "track" && hit.area !== "header") return;
|
|
4050
4271
|
const sel = this.selectionFor(hit, hit);
|
|
4051
4272
|
if (!sel) return;
|
|
4052
4273
|
this.selection = sel;
|
|
@@ -4060,7 +4281,7 @@ var Calendar = class {
|
|
|
4060
4281
|
const dt = ev.dataTransfer;
|
|
4061
4282
|
if (!dt || !this.opts.acceptNativeDrop?.(dt) || !this.current) return;
|
|
4062
4283
|
ev.preventDefault();
|
|
4063
|
-
const hit = this.
|
|
4284
|
+
const hit = this.hitAt(ev.clientX, ev.clientY);
|
|
4064
4285
|
this.unselectSilently();
|
|
4065
4286
|
if (!hit || hit.kind === "timeline" && hit.area !== "track" && hit.area !== "header") return;
|
|
4066
4287
|
const sel = this.selectionFor(hit, hit);
|
|
@@ -4091,7 +4312,7 @@ function scrollerOf(el, axis) {
|
|
|
4091
4312
|
return doc.scrollingElement;
|
|
4092
4313
|
}
|
|
4093
4314
|
function rangeMoved(prev, next) {
|
|
4094
|
-
return !prev || prev.type !== next.type || prev.range.startDay !== next.range.startDay || prev.range.endDay !== next.range.endDay || prev.dataRange.endDay !== next.dataRange.endDay;
|
|
4315
|
+
return !prev || prev.type !== next.type || prev.range.startDay !== next.range.startDay || prev.range.endDay !== next.range.endDay || prev.dataRange.startDay !== next.dataRange.startDay || prev.dataRange.endDay !== next.dataRange.endDay;
|
|
4095
4316
|
}
|
|
4096
4317
|
|
|
4097
4318
|
export {
|