@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
package/dist/cjs/react.cjs
CHANGED
|
@@ -982,8 +982,9 @@ var DayGridView = class {
|
|
|
982
982
|
constructor(ctx) {
|
|
983
983
|
this.ctx = ctx;
|
|
984
984
|
const { doc, opts, days } = ctx;
|
|
985
|
-
this.dotsMode = opts.monthDisplay === "dots";
|
|
985
|
+
this.dotsMode = opts.monthDisplay === "dots" || opts.monthDisplay === "chips";
|
|
986
986
|
this.el = h(doc, "div", this.dotsMode ? "tnc-dg tnc-dg--dots" : "tnc-dg");
|
|
987
|
+
this.el.classList.toggle("tnc-dg--chips", opts.monthDisplay === "chips");
|
|
987
988
|
this.scroller = h(doc, "div", "tnc-dg-scroll");
|
|
988
989
|
this.grid = h(doc, "div", "tnc-dg-grid", { role: "grid", "aria-label": ctx.view.title });
|
|
989
990
|
const perWeek = this.daysPerWeek();
|
|
@@ -1013,14 +1014,14 @@ var DayGridView = class {
|
|
|
1013
1014
|
const cell = h(doc, "div", cls.join(" "), { role: "gridcell", "aria-label": ctx.fmt.longDate(d), "data-date": arg.dateStr });
|
|
1014
1015
|
if (this.dotsMode) cell.tabIndex = 0;
|
|
1015
1016
|
const num = ctx.fmt.dayNumber(d);
|
|
1016
|
-
const label = ymdOfDay(d).day === 1 ? `${ctx.fmt.monthShort(d)} ${num}` : num;
|
|
1017
|
+
const label = !this.dotsMode && ymdOfDay(d).day === 1 ? `${ctx.fmt.monthShort(d)} ${num}` : num;
|
|
1017
1018
|
cell.append(
|
|
1018
1019
|
h(
|
|
1019
1020
|
doc,
|
|
1020
1021
|
"div",
|
|
1021
1022
|
"tnc-dg-top",
|
|
1022
1023
|
null,
|
|
1023
|
-
opts.navLinks ? ctx.navLink(d, label, "tnc-dg-num") : h(doc, "span", "tnc-dg-num", null, label)
|
|
1024
|
+
opts.navLinks && !this.dotsMode ? ctx.navLink(d, label, "tnc-dg-num") : h(doc, "span", "tnc-dg-num", null, label)
|
|
1024
1025
|
)
|
|
1025
1026
|
);
|
|
1026
1027
|
dates.append(cell);
|
|
@@ -1034,20 +1035,20 @@ var DayGridView = class {
|
|
|
1034
1035
|
layer.append(content);
|
|
1035
1036
|
row.append(dates, layer);
|
|
1036
1037
|
this.grid.append(row);
|
|
1037
|
-
const dots =
|
|
1038
|
+
const dots = cells.map((cell) => {
|
|
1038
1039
|
const box = h(doc, "div", "tnc-dg-dots", { "aria-hidden": "true" });
|
|
1039
1040
|
if (opts.dayMaxEvents === false) box.classList.add("is-unlimited");
|
|
1040
1041
|
const count = h(doc, "span", "tnc-dg-dots-more");
|
|
1041
1042
|
cell.append(box);
|
|
1042
1043
|
return { box, pool: new ItemPool(ctx, box), count };
|
|
1043
|
-
})
|
|
1044
|
+
});
|
|
1044
1045
|
this.weeks.push({ days: wdays, row, cells, layer, sel, more, pool: new ItemPool(ctx, content), dots });
|
|
1045
1046
|
}
|
|
1046
1047
|
this.scroller.append(this.grid);
|
|
1047
1048
|
this.el.append(this.scroller);
|
|
1048
1049
|
this.el.classList.toggle("tnc-dg--auto", opts.height === "auto");
|
|
1049
1050
|
const RO = ctx.win.ResizeObserver;
|
|
1050
|
-
if (RO
|
|
1051
|
+
if (RO) {
|
|
1051
1052
|
this.resizeObs = new RO(() => {
|
|
1052
1053
|
if (this.sizeKey() !== this.lastHeights) this.render(null);
|
|
1053
1054
|
});
|
|
@@ -1078,14 +1079,35 @@ var DayGridView = class {
|
|
|
1078
1079
|
}
|
|
1079
1080
|
render(_change) {
|
|
1080
1081
|
const { ctx } = this;
|
|
1082
|
+
this.dotsMode = ctx.opts.monthDisplay !== "full" || this.grid.clientWidth / this.daysPerWeek() < 72;
|
|
1083
|
+
this.el.classList.toggle("tnc-dg--dots", this.dotsMode);
|
|
1084
|
+
this.el.classList.toggle("tnc-dg--compact", this.dotsMode && ctx.opts.monthDisplay === "full");
|
|
1085
|
+
this.el.classList.toggle("tnc-dg--chips", ctx.opts.monthDisplay === "chips" && this.weeks[0].dots[0].box.clientHeight >= 44);
|
|
1081
1086
|
const cs = ctx.win.getComputedStyle(this.el);
|
|
1082
1087
|
this.barPx = px(cs, "--tnc-bar-h", 20);
|
|
1083
1088
|
this.topPx = this.weeks[0]?.cells[0]?.querySelector(".tnc-dg-top")?.offsetHeight || px(cs, "--tnc-dg-top-h", 24);
|
|
1084
1089
|
this.morePx = this.measureMore(cs);
|
|
1085
1090
|
this.lastHeights = this.sizeKey();
|
|
1086
1091
|
for (const w of this.weeks) {
|
|
1087
|
-
|
|
1088
|
-
|
|
1092
|
+
for (const cell of w.cells) {
|
|
1093
|
+
if (this.dotsMode) cell.tabIndex = 0;
|
|
1094
|
+
else cell.removeAttribute("tabindex");
|
|
1095
|
+
if (this.dotsMode && ctx.opts.monthDisplay === "full") cell.setAttribute("aria-haspopup", "dialog");
|
|
1096
|
+
else cell.removeAttribute("aria-haspopup");
|
|
1097
|
+
}
|
|
1098
|
+
for (const cell of w.dots) cell.box.hidden = !this.dotsMode;
|
|
1099
|
+
if (this.dotsMode) {
|
|
1100
|
+
w.pool.begin();
|
|
1101
|
+
w.pool.end();
|
|
1102
|
+
w.more.replaceChildren();
|
|
1103
|
+
this.renderDots(w);
|
|
1104
|
+
} else {
|
|
1105
|
+
for (const cell of w.dots) {
|
|
1106
|
+
cell.pool.begin();
|
|
1107
|
+
cell.pool.end();
|
|
1108
|
+
}
|
|
1109
|
+
this.renderWeek(w);
|
|
1110
|
+
}
|
|
1089
1111
|
}
|
|
1090
1112
|
}
|
|
1091
1113
|
/** Height of a "+N more" link as the host styles it (`--tnc-more-h`, or a taller min-height). */
|
|
@@ -1184,7 +1206,8 @@ var DayGridView = class {
|
|
|
1184
1206
|
w.more.append(link);
|
|
1185
1207
|
}
|
|
1186
1208
|
existing.delete(key);
|
|
1187
|
-
link.
|
|
1209
|
+
link.setAttribute("aria-label", ctx.text.more(items.length));
|
|
1210
|
+
link.textContent = w.row.clientWidth / n < 72 ? `+${new Intl.NumberFormat(ctx.opts.locale).format(items.length)}` : ctx.text.more(items.length);
|
|
1188
1211
|
setStyle(link, {
|
|
1189
1212
|
left: `calc(${pct(col / n)} + 2px)`,
|
|
1190
1213
|
width: `calc(${pct(1 / n)} - 4px)`,
|
|
@@ -1214,10 +1237,11 @@ var DayGridView = class {
|
|
|
1214
1237
|
const { dayMaxEvents } = ctx.opts;
|
|
1215
1238
|
const first = w.dots[0].box;
|
|
1216
1239
|
const cs = ctx.win.getComputedStyle(first);
|
|
1217
|
-
const
|
|
1240
|
+
const chips = this.el.classList.contains("tnc-dg--chips");
|
|
1241
|
+
const size = chips ? px(cs, "--tnc-chip-h", 14) : px(cs, "--tnc-dot-size", 8);
|
|
1218
1242
|
const gap = px(cs, "--tnc-dot-gap", 3);
|
|
1219
1243
|
const step = size + gap;
|
|
1220
|
-
const perRow = Math.max(1, Math.floor((first.clientWidth + gap) / step));
|
|
1244
|
+
const perRow = chips ? 1 : Math.max(1, Math.floor((first.clientWidth + gap) / step));
|
|
1221
1245
|
const rows = Math.max(1, Math.floor((first.clientHeight + gap) / step));
|
|
1222
1246
|
const fits = dayMaxEvents === false ? Infinity : perRow * rows;
|
|
1223
1247
|
const cap = typeof dayMaxEvents === "number" && dayMaxEvents > 0 ? Math.min(dayMaxEvents, fits) : fits;
|
|
@@ -1226,7 +1250,7 @@ var DayGridView = class {
|
|
|
1226
1250
|
w.days.forEach((day, i) => {
|
|
1227
1251
|
const cell = w.dots[i];
|
|
1228
1252
|
const items = this.itemsOn(day);
|
|
1229
|
-
const shown = items.length <= cap ? items.length : cap >= fits ? Math.max(
|
|
1253
|
+
const shown = items.length <= cap ? items.length : cap >= fits ? Math.max(1, cap - (chips ? 1 : 2)) : Math.max(1, cap);
|
|
1230
1254
|
cell.pool.begin();
|
|
1231
1255
|
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 }));
|
|
1232
1256
|
cell.pool.end();
|
|
@@ -1343,6 +1367,7 @@ var ListView = class {
|
|
|
1343
1367
|
const leadItems = [];
|
|
1344
1368
|
const inLead = /* @__PURE__ */ new Set();
|
|
1345
1369
|
const keep = /* @__PURE__ */ new Set();
|
|
1370
|
+
let itemCount = 0;
|
|
1346
1371
|
let prev = null;
|
|
1347
1372
|
for (const day of days) {
|
|
1348
1373
|
let items = this.itemsOn(day);
|
|
@@ -1356,7 +1381,7 @@ var ListView = class {
|
|
|
1356
1381
|
return false;
|
|
1357
1382
|
});
|
|
1358
1383
|
}
|
|
1359
|
-
if (!items.length && !agenda) continue;
|
|
1384
|
+
if (!items.length && !agenda && opts.listDayCount !== 1) continue;
|
|
1360
1385
|
keep.add(day);
|
|
1361
1386
|
let section = this.sections.get(day);
|
|
1362
1387
|
let pool = this.pools.get(day);
|
|
@@ -1375,6 +1400,7 @@ var ListView = class {
|
|
|
1375
1400
|
this.pools.set(day, pool);
|
|
1376
1401
|
}
|
|
1377
1402
|
section.classList.toggle("is-empty", !items.length);
|
|
1403
|
+
itemCount += items.length;
|
|
1378
1404
|
this.fill(pool, items, () => day);
|
|
1379
1405
|
if (prev ? prev.nextSibling !== section : this.body.firstChild !== section) {
|
|
1380
1406
|
if (prev) prev.after(section);
|
|
@@ -1390,13 +1416,14 @@ var ListView = class {
|
|
|
1390
1416
|
this.sections.delete(day);
|
|
1391
1417
|
}
|
|
1392
1418
|
this.renderLead(leadItems);
|
|
1393
|
-
let empty = this.body.querySelector("
|
|
1394
|
-
if (!
|
|
1419
|
+
let empty = this.body.querySelector(".tnc-list-empty");
|
|
1420
|
+
if (!itemCount && !leadItems.length && (!agenda || opts.listEmptyContent)) {
|
|
1395
1421
|
if (!empty) {
|
|
1396
1422
|
empty = h(doc, "div", "tnc-list-empty", { role: "listitem" }, ctx.text.noItems);
|
|
1397
1423
|
const content = ctx.opts.listEmptyContent?.();
|
|
1398
1424
|
if (content) empty.replaceChildren(content);
|
|
1399
|
-
this.
|
|
1425
|
+
if (this.sections.size === 1) this.sections.values().next().value.append(empty);
|
|
1426
|
+
else this.body.prepend(empty);
|
|
1400
1427
|
}
|
|
1401
1428
|
} else empty?.remove();
|
|
1402
1429
|
this.ctx.strip?.draw();
|
|
@@ -1454,7 +1481,7 @@ var ListView = class {
|
|
|
1454
1481
|
const section = day === this.ctx.days[0] && this.lead ? this.lead.section : this.sections.get(day);
|
|
1455
1482
|
if (!section) return;
|
|
1456
1483
|
this.ctx.strip?.measure();
|
|
1457
|
-
section.
|
|
1484
|
+
this.scroller.scrollTop += section.getBoundingClientRect().top - this.scroller.getBoundingClientRect().top;
|
|
1458
1485
|
this.ctx.strip?.setFocus(day);
|
|
1459
1486
|
this.pinned = true;
|
|
1460
1487
|
}
|
|
@@ -1543,8 +1570,7 @@ var DateStrip = class {
|
|
|
1543
1570
|
head.append(this.title, this.todayBtn, prev, next, this.slot);
|
|
1544
1571
|
this.dows = h(doc, "div", "tnc-strip-dows", { "aria-hidden": "true" });
|
|
1545
1572
|
this.grid = h(doc, "div", "tnc-strip-grid", { role: "group" });
|
|
1546
|
-
const handle = h(doc, "
|
|
1547
|
-
handle.addEventListener("click", () => this.setExpanded(!this.expanded));
|
|
1573
|
+
const handle = h(doc, "div", "tnc-strip-handle", { "aria-hidden": "true" });
|
|
1548
1574
|
this.el.append(head, this.dows, this.grid, handle);
|
|
1549
1575
|
this.grid.addEventListener("click", this.onClick);
|
|
1550
1576
|
this.grid.addEventListener("keydown", this.onKeyDown);
|
|
@@ -2123,8 +2149,15 @@ var TimeGridView = class {
|
|
|
2123
2149
|
link.classList.toggle("tnc-more--collision", collapse);
|
|
2124
2150
|
link.textContent = `+${rec.count}`;
|
|
2125
2151
|
if (collapse) {
|
|
2126
|
-
|
|
2127
|
-
|
|
2152
|
+
const items = placements.filter((placement) => placement.cluster === cluster).map((placement) => placement.item.item.title);
|
|
2153
|
+
const count = ctx.text.appointments(rec.count);
|
|
2154
|
+
const interval = `${ctx.fmt.time(rec.start)} \u2013 ${ctx.fmt.time(rec.end)}`;
|
|
2155
|
+
link.replaceChildren(
|
|
2156
|
+
h(ctx.doc, "span", "tnc-collision-count", null, String(rec.count)),
|
|
2157
|
+
h(ctx.doc, "span", "tnc-collision-range", null, interval),
|
|
2158
|
+
h(ctx.doc, "span", "tnc-collision-title", { "aria-hidden": "true" }, items.join(" \xB7 "))
|
|
2159
|
+
);
|
|
2160
|
+
link.setAttribute("aria-label", `${count}, ${interval}: ${items.join(", ")}`);
|
|
2128
2161
|
link.title = link.getAttribute("aria-label");
|
|
2129
2162
|
} else {
|
|
2130
2163
|
link.removeAttribute("aria-label");
|
|
@@ -2133,6 +2166,7 @@ var TimeGridView = class {
|
|
|
2133
2166
|
const cols = maxStack;
|
|
2134
2167
|
setStyle(link, {
|
|
2135
2168
|
top: top(rec.start),
|
|
2169
|
+
height: collapse ? pct((rec.end - rec.start) / this.minutes) : "",
|
|
2136
2170
|
...inLane(lane, rec.split, (cols - 1) / cols, 1 / cols)
|
|
2137
2171
|
});
|
|
2138
2172
|
}
|
|
@@ -2199,12 +2233,10 @@ var TimeGridView = class {
|
|
|
2199
2233
|
const r2 = cells[i2].getBoundingClientRect();
|
|
2200
2234
|
if (x >= r2.left && x < r2.right) return i2;
|
|
2201
2235
|
}
|
|
2202
|
-
const firstR = cells[0]?.getBoundingClientRect();
|
|
2203
|
-
const lastR = cells[cells.length - 1]?.getBoundingClientRect();
|
|
2204
|
-
if (firstR && x < firstR.left) return 0;
|
|
2205
|
-
if (lastR && x >= lastR.right) return cells.length - 1;
|
|
2206
2236
|
return -1;
|
|
2207
2237
|
};
|
|
2238
|
+
const bounds = this.scroller.getBoundingClientRect();
|
|
2239
|
+
if (x < bounds.left || x >= bounds.right || y < bounds.top || y >= bounds.bottom) return null;
|
|
2208
2240
|
if (this.allDayRow) {
|
|
2209
2241
|
const r2 = this.allDayRow.getBoundingClientRect();
|
|
2210
2242
|
if (y >= r2.top && y < r2.bottom || !this.body && y >= r2.top) {
|
|
@@ -2927,6 +2959,14 @@ ${this.ctx.text.more(items.length - 8)}` : ""}` : label;
|
|
|
2927
2959
|
setScroll(s) {
|
|
2928
2960
|
this.scroller.scrollTop = s.top;
|
|
2929
2961
|
}
|
|
2962
|
+
revealDay(day) {
|
|
2963
|
+
const month = this.cells.find((cell) => cell.day === day)?.el.closest(".tnc-ym");
|
|
2964
|
+
if (!month) return;
|
|
2965
|
+
const bounds = month.getBoundingClientRect();
|
|
2966
|
+
const viewport = this.scroller.getBoundingClientRect();
|
|
2967
|
+
if (bounds.top < viewport.top) this.scroller.scrollTop += bounds.top - viewport.top;
|
|
2968
|
+
else if (bounds.bottom > viewport.bottom) this.scroller.scrollTop += bounds.bottom - viewport.bottom;
|
|
2969
|
+
}
|
|
2930
2970
|
elementsFor(_id) {
|
|
2931
2971
|
return [];
|
|
2932
2972
|
}
|
|
@@ -3006,6 +3046,11 @@ var Calendar = class {
|
|
|
3006
3046
|
conflicts = /* @__PURE__ */ new Map();
|
|
3007
3047
|
slot = { min: 0, max: MINUTES_PER_DAY, duration: 30, snap: 30, scroll: 480 };
|
|
3008
3048
|
draggingId = null;
|
|
3049
|
+
listDragPreview = null;
|
|
3050
|
+
dragSources = [];
|
|
3051
|
+
dragScrollFrame = null;
|
|
3052
|
+
dragScrollOrigins = /* @__PURE__ */ new Map();
|
|
3053
|
+
itemWriteStates = /* @__PURE__ */ new Map();
|
|
3009
3054
|
dragRow = null;
|
|
3010
3055
|
strip = null;
|
|
3011
3056
|
stripSize = null;
|
|
@@ -3019,6 +3064,7 @@ var Calendar = class {
|
|
|
3019
3064
|
session = null;
|
|
3020
3065
|
selection = null;
|
|
3021
3066
|
suppressClick = false;
|
|
3067
|
+
cancelledPointerId = null;
|
|
3022
3068
|
selectedIds = /* @__PURE__ */ new Set();
|
|
3023
3069
|
popover = null;
|
|
3024
3070
|
timer = null;
|
|
@@ -3036,6 +3082,7 @@ var Calendar = class {
|
|
|
3036
3082
|
this.positionMore();
|
|
3037
3083
|
});
|
|
3038
3084
|
this.resizeObs.observe(this.root);
|
|
3085
|
+
this.resizeObs.observe(this.toolbarEl);
|
|
3039
3086
|
}
|
|
3040
3087
|
}
|
|
3041
3088
|
onAdoptCheck = () => {
|
|
@@ -3162,7 +3209,12 @@ var Calendar = class {
|
|
|
3162
3209
|
gotoDate(date) {
|
|
3163
3210
|
const day = this.toDay(date);
|
|
3164
3211
|
if (day === null) return;
|
|
3212
|
+
const sameMonth = this.opts.view === "month" && startOfMonth(day) === startOfMonth(this.anchor);
|
|
3165
3213
|
this.anchor = day;
|
|
3214
|
+
if (sameMonth) {
|
|
3215
|
+
this.view = { ...this.view, anchor: day };
|
|
3216
|
+
return;
|
|
3217
|
+
}
|
|
3166
3218
|
this.rebuild(true);
|
|
3167
3219
|
}
|
|
3168
3220
|
prev() {
|
|
@@ -3308,7 +3360,8 @@ var Calendar = class {
|
|
|
3308
3360
|
out.push(...classList(this.opts.dayClassNames?.(this.dayArg(day))));
|
|
3309
3361
|
return out;
|
|
3310
3362
|
}
|
|
3311
|
-
isEditable(n, what) {
|
|
3363
|
+
isEditable(n, what, presentation = false) {
|
|
3364
|
+
if (!presentation && this.itemWriteStates.get(n.id) === "pending") return false;
|
|
3312
3365
|
if (n.id === EXTERNAL_ID || n.item.preview || this.opts.view === "year") return false;
|
|
3313
3366
|
if (this.opts.view === "list" && (!this.opts.listAgenda || what === "duration")) return false;
|
|
3314
3367
|
const it = n.item;
|
|
@@ -3348,13 +3401,14 @@ var Calendar = class {
|
|
|
3348
3401
|
if (preview || n.id === EXTERNAL_ID) el.classList.add("is-mirror");
|
|
3349
3402
|
if (this.conflicts.has(n.id)) el.classList.add("is-conflict");
|
|
3350
3403
|
const indicator = variant === "indicator";
|
|
3351
|
-
if (!preview && !indicator && (this.isEditable(n, "start") || this.isEditable(n, "duration"))) el.classList.add("is-draggable");
|
|
3404
|
+
if (!preview && !indicator && (this.isEditable(n, "start", true) || this.isEditable(n, "duration", true))) el.classList.add("is-draggable");
|
|
3352
3405
|
if (this.draggingId === n.id) el.classList.add("is-dragging");
|
|
3353
3406
|
if (this.selectedIds.has(n.id) && !preview) el.classList.add("is-selected");
|
|
3354
3407
|
el.classList.add(...classList(it.className));
|
|
3355
3408
|
const arg = this.itemArg(el, meta);
|
|
3356
3409
|
el.classList.add(...classList(this.opts.itemClassNames?.(arg)));
|
|
3357
3410
|
el.dataset.id = n.id;
|
|
3411
|
+
this.applyItemWriteState(el, n.id);
|
|
3358
3412
|
if (it.kind) el.dataset.kind = it.kind;
|
|
3359
3413
|
const color = it.color ?? it.borderColor;
|
|
3360
3414
|
if (color) el.style.setProperty("--tnc-c", color);
|
|
@@ -3371,6 +3425,7 @@ var Calendar = class {
|
|
|
3371
3425
|
const custom = variant === "list" ? this.opts.listItemContent?.(arg) : null;
|
|
3372
3426
|
const content = indicator ? null : custom ?? this.opts.itemContent?.(arg);
|
|
3373
3427
|
if (indicator) {
|
|
3428
|
+
if (this.opts.monthDisplay === "chips") el.append(h(this.doc, "span", "tnc-item-title", null, it.title));
|
|
3374
3429
|
} else if (content != null) {
|
|
3375
3430
|
const wrap = h(this.doc, "div", "tnc-item-main");
|
|
3376
3431
|
wrap.append(content);
|
|
@@ -3383,6 +3438,7 @@ var Calendar = class {
|
|
|
3383
3438
|
return el;
|
|
3384
3439
|
}
|
|
3385
3440
|
refreshItemEl(el, meta) {
|
|
3441
|
+
this.applyItemWriteState(el, meta.n.id);
|
|
3386
3442
|
const time = el.querySelector(":scope .tnc-item-time");
|
|
3387
3443
|
if (time) this.fillTime(time, meta.n, meta.variant, meta.day);
|
|
3388
3444
|
el.classList.toggle("is-dragging", this.draggingId === meta.n.id);
|
|
@@ -3565,6 +3621,7 @@ var Calendar = class {
|
|
|
3565
3621
|
this.current.scrollToTime(this.slot.scroll);
|
|
3566
3622
|
this.current.revealDay(this.anchor);
|
|
3567
3623
|
} else if (this.current instanceof TimelineView) this.current.scrollToDay(this.anchor);
|
|
3624
|
+
else if (this.current instanceof YearView) this.current.revealDay(this.anchor);
|
|
3568
3625
|
if (rangeChanged) this.opts.onRangeChange?.(this.view);
|
|
3569
3626
|
}
|
|
3570
3627
|
/** Sets the visible days and view info from the anchor. */
|
|
@@ -3590,9 +3647,11 @@ var Calendar = class {
|
|
|
3590
3647
|
}
|
|
3591
3648
|
/** The range, run on to the end of the strip's days so their dots are right. */
|
|
3592
3649
|
dataRangeFor(range) {
|
|
3593
|
-
const
|
|
3594
|
-
|
|
3595
|
-
|
|
3650
|
+
const window = this.strip?.window();
|
|
3651
|
+
const start = window ? Math.min(range.startDay, window.start) : range.startDay;
|
|
3652
|
+
const end = window ? Math.max(range.endDay, window.end) : range.endDay;
|
|
3653
|
+
if (start === range.startDay && end === range.endDay) return range;
|
|
3654
|
+
return { ...range, startDay: start, start: new Date(toInstant(start, 0, this.zone)), endDay: end, end: new Date(toInstant(end, 0, this.zone)) };
|
|
3596
3655
|
}
|
|
3597
3656
|
/** Adds, updates or removes the date strip for the current view. */
|
|
3598
3657
|
syncStrip(navigated) {
|
|
@@ -3639,20 +3698,24 @@ var Calendar = class {
|
|
|
3639
3698
|
stripShown() {
|
|
3640
3699
|
if (!this.strip || this.rebuilding || !this.view) return;
|
|
3641
3700
|
const next = this.dataRangeFor(this.view.range);
|
|
3642
|
-
if (next.endDay === this.view.dataRange.endDay) return;
|
|
3701
|
+
if (next.startDay === this.view.dataRange.startDay && next.endDay === this.view.dataRange.endDay) return;
|
|
3643
3702
|
this.view = { ...this.view, dataRange: next };
|
|
3644
3703
|
this.opts.onRangeChange?.(this.view);
|
|
3645
3704
|
}
|
|
3646
3705
|
/** What is under a point, the date strip included. */
|
|
3647
3706
|
hitAt(x, y) {
|
|
3707
|
+
const target = this.doc.elementFromPoint(x, y);
|
|
3708
|
+
if (!target || !this.root.contains(target)) {
|
|
3709
|
+
this.strip?.markTarget(null);
|
|
3710
|
+
return null;
|
|
3711
|
+
}
|
|
3648
3712
|
const strip = this.strip;
|
|
3649
3713
|
if (strip) {
|
|
3650
|
-
const
|
|
3651
|
-
const day = el ? strip.dayAt(el) : null;
|
|
3714
|
+
const day = strip.dayAt(target);
|
|
3652
3715
|
strip.markTarget(day !== null && this.draggingId ? day : null);
|
|
3653
3716
|
if (day !== null) return { kind: "day", day };
|
|
3654
3717
|
}
|
|
3655
|
-
return this.current?.hit(x, y)
|
|
3718
|
+
return this.current?.el.contains(target) ? this.current.hit(x, y) : null;
|
|
3656
3719
|
}
|
|
3657
3720
|
agendaList() {
|
|
3658
3721
|
return this.opts.view === "list" && this.opts.listAgenda && this.current instanceof ListView ? this.current : null;
|
|
@@ -3766,11 +3829,13 @@ var Calendar = class {
|
|
|
3766
3829
|
buttons.style.display = "flex";
|
|
3767
3830
|
select.style.display = "none";
|
|
3768
3831
|
const startWidth = Array.from(start.children).reduce((width, child) => width + child.scrollWidth, 0);
|
|
3769
|
-
const
|
|
3832
|
+
const availableWidth = Math.min(this.root.clientWidth, this.toolbarEl.clientWidth);
|
|
3833
|
+
const compact = mode === "select" || mode === "auto" && startWidth + buttons.scrollWidth + 32 > availableWidth;
|
|
3770
3834
|
buttons.hidden = compact;
|
|
3771
3835
|
select.hidden = !compact;
|
|
3772
3836
|
buttons.style.display = compact ? "none" : "flex";
|
|
3773
3837
|
select.style.display = compact ? "" : "none";
|
|
3838
|
+
select.parentElement?.classList.toggle("tnc-toolbar-end--compact", compact);
|
|
3774
3839
|
}
|
|
3775
3840
|
applyChange(change) {
|
|
3776
3841
|
if (!change.added.length && !change.updated.length && !change.removed.length && !change.days.size && !change.spans) return;
|
|
@@ -3835,7 +3900,7 @@ var Calendar = class {
|
|
|
3835
3900
|
const s = wallTime(n.startMs, this.zone);
|
|
3836
3901
|
const start = this.fmt.time(s.minute, true);
|
|
3837
3902
|
if (variant === "dot" || variant === "bar" || variant === "indicator") return { start: s.day === day ? start : "", end: "" };
|
|
3838
|
-
if (n.startMs === n.endMs) return { start, end: "" };
|
|
3903
|
+
if (n.startMs === n.endMs || n.item.timeDisplay === "start") return { start, end: "" };
|
|
3839
3904
|
return { start, end: this.fmt.time(wallTime(n.endMs, this.zone).minute, true) };
|
|
3840
3905
|
}
|
|
3841
3906
|
fillTime(el, n, variant, day) {
|
|
@@ -3851,7 +3916,8 @@ var Calendar = class {
|
|
|
3851
3916
|
}
|
|
3852
3917
|
const s = wallTime(n.startMs, this.zone);
|
|
3853
3918
|
const e = wallTime(n.endMs, this.zone);
|
|
3854
|
-
|
|
3919
|
+
const start = `${n.item.title}, ${this.fmt.longDate(s.day)} ${this.fmt.time(s.minute)}`;
|
|
3920
|
+
return n.item.timeDisplay === "start" || n.startMs === n.endMs ? start : `${start} \u2013 ${this.fmt.time(e.minute)}`;
|
|
3855
3921
|
}
|
|
3856
3922
|
defaultContent(meta) {
|
|
3857
3923
|
const { n, variant, day } = meta;
|
|
@@ -3879,7 +3945,7 @@ var Calendar = class {
|
|
|
3879
3945
|
addHandles(el, meta) {
|
|
3880
3946
|
const { n, variant } = meta;
|
|
3881
3947
|
const ports = variant === "timeline" && !meta.mirror && n.id !== EXTERNAL_ID && !!this.opts.timeline?.onLink;
|
|
3882
|
-
if (variant === "dot" || !this.isEditable(n, "duration")) {
|
|
3948
|
+
if (variant === "dot" || !this.isEditable(n, "duration", true)) {
|
|
3883
3949
|
if (ports) this.addPorts(el, n);
|
|
3884
3950
|
return;
|
|
3885
3951
|
}
|
|
@@ -4007,6 +4073,10 @@ var Calendar = class {
|
|
|
4007
4073
|
return el && this.root.contains(el) && this.meta.has(el) && !this.meta.get(el)?.n.item.preview ? el : null;
|
|
4008
4074
|
}
|
|
4009
4075
|
onDocPointerDown = (ev) => {
|
|
4076
|
+
if (this.cancelledPointerId !== null) {
|
|
4077
|
+
this.cancelledPointerId = null;
|
|
4078
|
+
this.listenDoc(false);
|
|
4079
|
+
}
|
|
4010
4080
|
const t = ev.target;
|
|
4011
4081
|
if (this.popover && !this.popover.el.contains(t) && !this.popover.anchor.contains(t)) this.closeMore();
|
|
4012
4082
|
if (this.selection && !this.root.contains(t)) this.unselect();
|
|
@@ -4014,6 +4084,7 @@ var Calendar = class {
|
|
|
4014
4084
|
onPointerDown = (ev) => {
|
|
4015
4085
|
if (ev.button !== 0 || this.session) return;
|
|
4016
4086
|
const target = ev.target;
|
|
4087
|
+
if (target.closest(".tnc-dg--compact .tnc-dg-day")) return;
|
|
4017
4088
|
if (target.closest("button, a, input, select, textarea, .tnc-toolbar, .tnc-port, [data-tnc-no-drag]")) {
|
|
4018
4089
|
if (!target.closest(".tnc-item")) return;
|
|
4019
4090
|
if (target.closest(".tnc-port, [data-tnc-no-drag], input, select, textarea")) return;
|
|
@@ -4046,7 +4117,7 @@ var Calendar = class {
|
|
|
4046
4117
|
y0: ev.clientY,
|
|
4047
4118
|
active: false,
|
|
4048
4119
|
origin,
|
|
4049
|
-
grab: overflowOrigin
|
|
4120
|
+
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,
|
|
4050
4121
|
proposal: null,
|
|
4051
4122
|
denied: false,
|
|
4052
4123
|
timer: null,
|
|
@@ -4071,16 +4142,79 @@ var Calendar = class {
|
|
|
4071
4142
|
};
|
|
4072
4143
|
activate(s) {
|
|
4073
4144
|
s.active = true;
|
|
4145
|
+
if (s.lastEvent) this.leaveHover(s.lastEvent);
|
|
4074
4146
|
if (s.timer !== null) this.win.clearTimeout(s.timer);
|
|
4075
4147
|
s.timer = null;
|
|
4076
4148
|
if (s.origin) {
|
|
4077
4149
|
this.draggingId = s.origin.id;
|
|
4078
|
-
for (const el of this.elementsFor(s.origin.id))
|
|
4150
|
+
for (const el of this.elementsFor(s.origin.id)) {
|
|
4151
|
+
if (this.opts.view !== "list" && s.mode === "move") {
|
|
4152
|
+
const source = el.cloneNode(true);
|
|
4153
|
+
source.classList.remove("is-selected");
|
|
4154
|
+
source.classList.add("tnc-drag-source");
|
|
4155
|
+
source.setAttribute("aria-hidden", "true");
|
|
4156
|
+
source.inert = true;
|
|
4157
|
+
for (const node of [source, ...source.querySelectorAll("[id], [data-id], [data-task-path]")]) {
|
|
4158
|
+
node.removeAttribute("id");
|
|
4159
|
+
node.removeAttribute("data-id");
|
|
4160
|
+
node.removeAttribute("data-task-path");
|
|
4161
|
+
}
|
|
4162
|
+
el.before(source);
|
|
4163
|
+
this.dragSources.push(source);
|
|
4164
|
+
}
|
|
4165
|
+
if (this.opts.view === "list" && !this.listDragPreview && s.mode === "move") {
|
|
4166
|
+
const bounds = el.getBoundingClientRect();
|
|
4167
|
+
const preview = el.cloneNode(true);
|
|
4168
|
+
preview.classList.add("tnc-drag-preview", "is-dragging");
|
|
4169
|
+
preview.removeAttribute("data-id");
|
|
4170
|
+
preview.removeAttribute("data-task-path");
|
|
4171
|
+
preview.setAttribute("aria-hidden", "true");
|
|
4172
|
+
preview.inert = true;
|
|
4173
|
+
preview.style.width = `${bounds.width}px`;
|
|
4174
|
+
this.root.append(preview);
|
|
4175
|
+
this.listDragPreview = { element: preview, offsetX: s.x0 - bounds.left, offsetY: s.y0 - bounds.top, width: bounds.width, height: bounds.height };
|
|
4176
|
+
}
|
|
4177
|
+
el.classList.add("is-dragging");
|
|
4178
|
+
}
|
|
4079
4179
|
}
|
|
4080
4180
|
this.closeMore();
|
|
4081
4181
|
if (s.mode !== "select") this.unselectSilently();
|
|
4082
4182
|
this.root.classList.add("tnc-dragging", `tnc-dragging-${s.mode}`);
|
|
4083
4183
|
if (s.lastEvent) this.track(s, s.lastEvent);
|
|
4184
|
+
this.startDragScroll();
|
|
4185
|
+
}
|
|
4186
|
+
startDragScroll() {
|
|
4187
|
+
if (this.dragScrollFrame !== null) return;
|
|
4188
|
+
const tick = () => {
|
|
4189
|
+
this.dragScrollFrame = null;
|
|
4190
|
+
const session = this.session;
|
|
4191
|
+
const pointer = session?.lastEvent;
|
|
4192
|
+
if (!session?.active || !pointer) return;
|
|
4193
|
+
const origin = session.origin ? this.elementsFor(session.origin.id)[0] : this.viewHost;
|
|
4194
|
+
const underPointer = this.doc.elementFromPoint(pointer.clientX, pointer.clientY);
|
|
4195
|
+
let moved = false;
|
|
4196
|
+
if (origin && underPointer && this.root.contains(underPointer)) {
|
|
4197
|
+
for (const axis of ["x", "y"]) {
|
|
4198
|
+
const scroller = scrollerOf(origin, axis);
|
|
4199
|
+
if (!scroller) continue;
|
|
4200
|
+
const viewport = scroller === this.doc.scrollingElement ? { left: 0, top: 0, right: this.win.innerWidth, bottom: this.win.innerHeight } : scroller.getBoundingClientRect();
|
|
4201
|
+
const coordinate = axis === "x" ? pointer.clientX : pointer.clientY;
|
|
4202
|
+
const lower = Math.max(0, axis === "x" ? viewport.left : viewport.top);
|
|
4203
|
+
const upper = Math.min(axis === "x" ? this.win.innerWidth : this.win.innerHeight, axis === "x" ? viewport.right : viewport.bottom);
|
|
4204
|
+
if (coordinate < lower || coordinate > upper) continue;
|
|
4205
|
+
const delta = coordinate < lower + 32 ? -Math.min(12, (lower + 32 - coordinate) / 2) : coordinate > upper - 32 ? Math.min(12, (coordinate - upper + 32) / 2) : 0;
|
|
4206
|
+
if (!delta) continue;
|
|
4207
|
+
if (!this.dragScrollOrigins.has(scroller)) this.dragScrollOrigins.set(scroller, { top: scroller.scrollTop, left: scroller.scrollLeft });
|
|
4208
|
+
const before = axis === "x" ? scroller.scrollLeft : scroller.scrollTop;
|
|
4209
|
+
if (axis === "x") scroller.scrollLeft += delta;
|
|
4210
|
+
else scroller.scrollTop += delta;
|
|
4211
|
+
moved ||= before !== (axis === "x" ? scroller.scrollLeft : scroller.scrollTop);
|
|
4212
|
+
}
|
|
4213
|
+
}
|
|
4214
|
+
if (moved) this.track(session, pointer);
|
|
4215
|
+
this.dragScrollFrame = this.win.requestAnimationFrame(tick);
|
|
4216
|
+
};
|
|
4217
|
+
this.dragScrollFrame = this.win.requestAnimationFrame(tick);
|
|
4084
4218
|
}
|
|
4085
4219
|
onTouchMove = (ev) => {
|
|
4086
4220
|
if (this.session?.active) ev.preventDefault();
|
|
@@ -4110,6 +4244,12 @@ var Calendar = class {
|
|
|
4110
4244
|
this.track(s, ev);
|
|
4111
4245
|
};
|
|
4112
4246
|
onPointerUp = (ev) => {
|
|
4247
|
+
if (ev.pointerId === this.cancelledPointerId) {
|
|
4248
|
+
this.cancelledPointerId = null;
|
|
4249
|
+
this.suppressNextClick();
|
|
4250
|
+
this.listenDoc(false);
|
|
4251
|
+
return;
|
|
4252
|
+
}
|
|
4113
4253
|
const s = this.session;
|
|
4114
4254
|
if (!s || ev.pointerId !== s.pointerId) return;
|
|
4115
4255
|
if (!s.active) {
|
|
@@ -4122,28 +4262,49 @@ var Calendar = class {
|
|
|
4122
4262
|
return;
|
|
4123
4263
|
}
|
|
4124
4264
|
this.suppressNextClick();
|
|
4265
|
+
this.track(s, ev);
|
|
4125
4266
|
this.endSession(ev, false);
|
|
4126
4267
|
};
|
|
4127
4268
|
onPointerCancel = (ev) => {
|
|
4269
|
+
if (ev.pointerId === this.cancelledPointerId) {
|
|
4270
|
+
this.cancelledPointerId = null;
|
|
4271
|
+
this.listenDoc(false);
|
|
4272
|
+
}
|
|
4128
4273
|
if (this.session && ev.pointerId === this.session.pointerId) this.endSession(null, true);
|
|
4129
4274
|
};
|
|
4130
4275
|
onDocKeyDown = (ev) => {
|
|
4131
4276
|
if (ev.key === "Escape" && this.session) {
|
|
4132
4277
|
ev.preventDefault();
|
|
4133
4278
|
ev.stopPropagation();
|
|
4279
|
+
const pointerId = this.session.active ? this.session.pointerId : null;
|
|
4134
4280
|
this.endSession(null, true);
|
|
4281
|
+
if (pointerId !== null) {
|
|
4282
|
+
this.cancelledPointerId = pointerId;
|
|
4283
|
+
this.listenDoc(true);
|
|
4284
|
+
}
|
|
4135
4285
|
}
|
|
4136
4286
|
};
|
|
4137
4287
|
/** Proposal for the current pointer position. */
|
|
4138
4288
|
track(s, ev) {
|
|
4289
|
+
if (this.listDragPreview) {
|
|
4290
|
+
const preview = this.listDragPreview;
|
|
4291
|
+
const bounds = this.root.getBoundingClientRect();
|
|
4292
|
+
preview.element.style.left = `${Math.max(8, Math.min(this.win.innerWidth - preview.width - 8, ev.clientX - preview.offsetX)) - bounds.left}px`;
|
|
4293
|
+
preview.element.style.top = `${Math.max(8, Math.min(this.win.innerHeight - preview.height - 8, ev.clientY - preview.offsetY)) - bounds.top}px`;
|
|
4294
|
+
}
|
|
4139
4295
|
const hit = this.hitAt(ev.clientX, ev.clientY);
|
|
4140
4296
|
if (s.mode === "external") {
|
|
4141
4297
|
this.trackExternal(s, hit);
|
|
4142
4298
|
return;
|
|
4143
4299
|
}
|
|
4144
4300
|
if (!s.grab) s.grab = hit;
|
|
4145
|
-
if (!hit || !s.grab)
|
|
4301
|
+
if (!hit || !s.grab) {
|
|
4302
|
+
this.invalidateProposal(s);
|
|
4303
|
+
return;
|
|
4304
|
+
}
|
|
4146
4305
|
if (s.mode === "select") {
|
|
4306
|
+
s.denied = false;
|
|
4307
|
+
this.root.classList.remove("tnc-drop-denied");
|
|
4147
4308
|
const sel = this.selectionFor(s.grab, hit);
|
|
4148
4309
|
if (!sel) return;
|
|
4149
4310
|
this.selection = sel;
|
|
@@ -4152,25 +4313,40 @@ var Calendar = class {
|
|
|
4152
4313
|
}
|
|
4153
4314
|
const origin = s.origin;
|
|
4154
4315
|
const p = s.mode === "move" ? this.moveProposal(origin, s.grab, hit) : this.resizeProposal(origin, hit, s.mode === "resize-start");
|
|
4155
|
-
if (!p)
|
|
4316
|
+
if (!p) {
|
|
4317
|
+
this.invalidateProposal(s);
|
|
4318
|
+
return;
|
|
4319
|
+
}
|
|
4156
4320
|
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;
|
|
4157
4321
|
s.denied = !allowed;
|
|
4158
4322
|
this.root.classList.toggle("tnc-drop-denied", !allowed);
|
|
4159
|
-
if (!allowed
|
|
4323
|
+
if (!allowed) {
|
|
4324
|
+
this.invalidateProposal(s);
|
|
4325
|
+
return;
|
|
4326
|
+
}
|
|
4327
|
+
if (sameProposal(p, s.proposal)) return;
|
|
4160
4328
|
s.proposal = p;
|
|
4161
4329
|
this.dragRow = p.rowId !== void 0 ? { id: origin.id, rowId: p.rowId } : null;
|
|
4162
|
-
this.applyChange(this.store.upsert([this.withProposal(origin, p)]));
|
|
4330
|
+
if (this.opts.view !== "list") this.applyChange(this.store.upsert([this.withProposal(origin, p)]));
|
|
4331
|
+
}
|
|
4332
|
+
invalidateProposal(s) {
|
|
4333
|
+
const hadProposal = s.proposal !== null;
|
|
4334
|
+
s.proposal = null;
|
|
4335
|
+
s.hit = null;
|
|
4336
|
+
s.denied = true;
|
|
4337
|
+
this.dragRow = null;
|
|
4338
|
+
this.root.classList.add("tnc-drop-denied");
|
|
4339
|
+
this.strip?.markTarget(null);
|
|
4340
|
+
this.unselectSilently();
|
|
4341
|
+
if (s.mode === "external") this.applyChange(this.store.remove([EXTERNAL_ID]));
|
|
4342
|
+
else if (hadProposal && s.origin) this.applyChange(this.store.upsert([s.origin.item]));
|
|
4163
4343
|
}
|
|
4164
4344
|
trackExternal(s, raw) {
|
|
4165
4345
|
const src = s.source;
|
|
4166
4346
|
const hit = raw?.kind === "timeline" && raw.area !== "track" && raw.area !== "header" ? null : raw;
|
|
4167
4347
|
s.hit = hit;
|
|
4168
4348
|
if (!hit) {
|
|
4169
|
-
|
|
4170
|
-
s.proposal = null;
|
|
4171
|
-
this.applyChange(this.store.remove([EXTERNAL_ID]));
|
|
4172
|
-
}
|
|
4173
|
-
this.unselectSilently();
|
|
4349
|
+
this.invalidateProposal(s);
|
|
4174
4350
|
return;
|
|
4175
4351
|
}
|
|
4176
4352
|
const dur = src.durationMinutes ?? this.opts.defaultTimedMinutes;
|
|
@@ -4189,6 +4365,10 @@ var Calendar = class {
|
|
|
4189
4365
|
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;
|
|
4190
4366
|
s.denied = !allowed;
|
|
4191
4367
|
this.root.classList.toggle("tnc-drop-denied", !allowed);
|
|
4368
|
+
if (!allowed) {
|
|
4369
|
+
this.invalidateProposal(s);
|
|
4370
|
+
return;
|
|
4371
|
+
}
|
|
4192
4372
|
if (sameProposal(p, s.proposal)) return;
|
|
4193
4373
|
s.proposal = p;
|
|
4194
4374
|
if (hit.kind === "timeline" && p.rowId === void 0) {
|
|
@@ -4381,7 +4561,18 @@ var Calendar = class {
|
|
|
4381
4561
|
endSession(ev, cancel) {
|
|
4382
4562
|
const s = this.session;
|
|
4383
4563
|
if (!s) return;
|
|
4564
|
+
if (this.dragScrollFrame !== null) this.win.cancelAnimationFrame(this.dragScrollFrame);
|
|
4565
|
+
this.dragScrollFrame = null;
|
|
4566
|
+
if (cancel || s.denied) for (const [scroller, position] of this.dragScrollOrigins) {
|
|
4567
|
+
scroller.scrollTop = position.top;
|
|
4568
|
+
scroller.scrollLeft = position.left;
|
|
4569
|
+
}
|
|
4570
|
+
this.dragScrollOrigins.clear();
|
|
4384
4571
|
this.session = null;
|
|
4572
|
+
this.listDragPreview?.element.remove();
|
|
4573
|
+
this.listDragPreview = null;
|
|
4574
|
+
for (const source of this.dragSources) source.remove();
|
|
4575
|
+
this.dragSources = [];
|
|
4385
4576
|
if (s.timer !== null) this.win.clearTimeout(s.timer);
|
|
4386
4577
|
this.listenDoc(false);
|
|
4387
4578
|
this.root.classList.remove(
|
|
@@ -4450,10 +4641,16 @@ var Calendar = class {
|
|
|
4450
4641
|
revert();
|
|
4451
4642
|
return;
|
|
4452
4643
|
}
|
|
4644
|
+
if (this.opts.view === "list") this.applyChange(this.store.upsert([this.withProposal(origin, p)]));
|
|
4453
4645
|
this.flush();
|
|
4454
4646
|
this.commit(s.mode === "move" ? "drop" : "resize", origin, p, ev, revert);
|
|
4455
4647
|
}
|
|
4456
4648
|
commit(kind, origin, p, ev, revert) {
|
|
4649
|
+
let reverted = false;
|
|
4650
|
+
const mark = (state) => {
|
|
4651
|
+
this.itemWriteStates.set(origin.id, state);
|
|
4652
|
+
for (const element of this.elementsFor(origin.id)) this.applyItemWriteState(element, origin.id);
|
|
4653
|
+
};
|
|
4457
4654
|
const arg = {
|
|
4458
4655
|
item: origin.item,
|
|
4459
4656
|
start: new Date(p.startMs),
|
|
@@ -4469,19 +4666,32 @@ var Calendar = class {
|
|
|
4469
4666
|
jsEvent: ev,
|
|
4470
4667
|
source: ev && "key" in ev ? "keyboard" : "pointer",
|
|
4471
4668
|
view: this.view,
|
|
4472
|
-
revert
|
|
4669
|
+
revert: () => {
|
|
4670
|
+
reverted = true;
|
|
4671
|
+
revert();
|
|
4672
|
+
mark("failed");
|
|
4673
|
+
}
|
|
4473
4674
|
};
|
|
4474
4675
|
const handler = kind === "drop" ? this.opts.onItemDrop : this.opts.onItemResize;
|
|
4475
4676
|
try {
|
|
4677
|
+
mark("pending");
|
|
4476
4678
|
const res = handler?.(arg);
|
|
4477
4679
|
if (res && typeof res.then === "function") {
|
|
4478
|
-
Promise.resolve(res).
|
|
4479
|
-
|
|
4680
|
+
void Promise.resolve(res).then(() => {
|
|
4681
|
+
if (!reverted) mark("changed");
|
|
4682
|
+
}, () => arg.revert());
|
|
4683
|
+
} else if (!reverted) mark("changed");
|
|
4480
4684
|
} catch (err) {
|
|
4481
|
-
revert();
|
|
4685
|
+
arg.revert();
|
|
4482
4686
|
throw err;
|
|
4483
4687
|
}
|
|
4484
4688
|
}
|
|
4689
|
+
applyItemWriteState(element, id) {
|
|
4690
|
+
const state = this.itemWriteStates.get(id);
|
|
4691
|
+
for (const name of ["pending", "failed", "changed"]) element.classList.toggle(`is-write-${name}`, state === name);
|
|
4692
|
+
if (state === "pending") element.setAttribute("aria-busy", "true");
|
|
4693
|
+
else element.removeAttribute("aria-busy");
|
|
4694
|
+
}
|
|
4485
4695
|
/* --------------------------------------------------------- click / keys */
|
|
4486
4696
|
/** Runs in the capture phase so the click ending a drag never reaches content inside the calendar, React portals included. */
|
|
4487
4697
|
onClickCapture = (ev) => {
|
|
@@ -4491,6 +4701,12 @@ var Calendar = class {
|
|
|
4491
4701
|
ev.preventDefault();
|
|
4492
4702
|
};
|
|
4493
4703
|
onClick = (ev) => {
|
|
4704
|
+
const compactDay = ev.target.closest?.(".tnc-dg--compact .tnc-dg-day");
|
|
4705
|
+
if (compactDay && this.root.contains(compactDay) && !ev.target.closest(".tnc-navlink")) {
|
|
4706
|
+
const day = parseDay(compactDay.dataset.date ?? "");
|
|
4707
|
+
if (day !== null) this.openMore(day, compactDay, ev);
|
|
4708
|
+
return;
|
|
4709
|
+
}
|
|
4494
4710
|
const yearDay = ev.target.closest?.(".tnc-ym-day");
|
|
4495
4711
|
if (yearDay && this.root.contains(yearDay)) {
|
|
4496
4712
|
const day = parseDay(yearDay.dataset.date ?? "");
|
|
@@ -4579,7 +4795,8 @@ var Calendar = class {
|
|
|
4579
4795
|
const day = parseDay(target.dataset.date ?? "");
|
|
4580
4796
|
if (day !== null) {
|
|
4581
4797
|
ev.preventDefault();
|
|
4582
|
-
|
|
4798
|
+
if (target.closest(".tnc-dg--compact")) this.openMore(day, target, ev);
|
|
4799
|
+
else this.clickSlot({ kind: "day", day }, ev, true);
|
|
4583
4800
|
}
|
|
4584
4801
|
return;
|
|
4585
4802
|
}
|
|
@@ -4667,9 +4884,13 @@ var Calendar = class {
|
|
|
4667
4884
|
const dt = ev.dataTransfer;
|
|
4668
4885
|
if (!dt || !this.opts.acceptNativeDrop?.(dt) || !this.current) return;
|
|
4669
4886
|
ev.preventDefault();
|
|
4887
|
+
const hit = this.hitAt(ev.clientX, ev.clientY);
|
|
4888
|
+
if (!hit || hit.kind === "timeline" && hit.area !== "track" && hit.area !== "header") {
|
|
4889
|
+
dt.dropEffect = "none";
|
|
4890
|
+
this.unselectSilently();
|
|
4891
|
+
return;
|
|
4892
|
+
}
|
|
4670
4893
|
dt.dropEffect = "copy";
|
|
4671
|
-
const hit = this.current.hit(ev.clientX, ev.clientY);
|
|
4672
|
-
if (!hit || hit.kind === "timeline" && hit.area !== "track" && hit.area !== "header") return;
|
|
4673
4894
|
const sel = this.selectionFor(hit, hit);
|
|
4674
4895
|
if (!sel) return;
|
|
4675
4896
|
this.selection = sel;
|
|
@@ -4683,7 +4904,7 @@ var Calendar = class {
|
|
|
4683
4904
|
const dt = ev.dataTransfer;
|
|
4684
4905
|
if (!dt || !this.opts.acceptNativeDrop?.(dt) || !this.current) return;
|
|
4685
4906
|
ev.preventDefault();
|
|
4686
|
-
const hit = this.
|
|
4907
|
+
const hit = this.hitAt(ev.clientX, ev.clientY);
|
|
4687
4908
|
this.unselectSilently();
|
|
4688
4909
|
if (!hit || hit.kind === "timeline" && hit.area !== "track" && hit.area !== "header") return;
|
|
4689
4910
|
const sel = this.selectionFor(hit, hit);
|
|
@@ -4714,7 +4935,7 @@ function scrollerOf(el, axis) {
|
|
|
4714
4935
|
return doc.scrollingElement;
|
|
4715
4936
|
}
|
|
4716
4937
|
function rangeMoved(prev, next) {
|
|
4717
|
-
return !prev || prev.type !== next.type || prev.range.startDay !== next.range.startDay || prev.range.endDay !== next.range.endDay || prev.dataRange.endDay !== next.dataRange.endDay;
|
|
4938
|
+
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;
|
|
4718
4939
|
}
|
|
4719
4940
|
|
|
4720
4941
|
// src/react/index.tsx
|