@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/index.cjs
CHANGED
|
@@ -1074,8 +1074,9 @@ var DayGridView = class {
|
|
|
1074
1074
|
constructor(ctx) {
|
|
1075
1075
|
this.ctx = ctx;
|
|
1076
1076
|
const { doc, opts, days } = ctx;
|
|
1077
|
-
this.dotsMode = opts.monthDisplay === "dots";
|
|
1077
|
+
this.dotsMode = opts.monthDisplay === "dots" || opts.monthDisplay === "chips";
|
|
1078
1078
|
this.el = h(doc, "div", this.dotsMode ? "tnc-dg tnc-dg--dots" : "tnc-dg");
|
|
1079
|
+
this.el.classList.toggle("tnc-dg--chips", opts.monthDisplay === "chips");
|
|
1079
1080
|
this.scroller = h(doc, "div", "tnc-dg-scroll");
|
|
1080
1081
|
this.grid = h(doc, "div", "tnc-dg-grid", { role: "grid", "aria-label": ctx.view.title });
|
|
1081
1082
|
const perWeek = this.daysPerWeek();
|
|
@@ -1105,14 +1106,14 @@ var DayGridView = class {
|
|
|
1105
1106
|
const cell = h(doc, "div", cls.join(" "), { role: "gridcell", "aria-label": ctx.fmt.longDate(d), "data-date": arg.dateStr });
|
|
1106
1107
|
if (this.dotsMode) cell.tabIndex = 0;
|
|
1107
1108
|
const num2 = ctx.fmt.dayNumber(d);
|
|
1108
|
-
const label = ymdOfDay(d).day === 1 ? `${ctx.fmt.monthShort(d)} ${num2}` : num2;
|
|
1109
|
+
const label = !this.dotsMode && ymdOfDay(d).day === 1 ? `${ctx.fmt.monthShort(d)} ${num2}` : num2;
|
|
1109
1110
|
cell.append(
|
|
1110
1111
|
h(
|
|
1111
1112
|
doc,
|
|
1112
1113
|
"div",
|
|
1113
1114
|
"tnc-dg-top",
|
|
1114
1115
|
null,
|
|
1115
|
-
opts.navLinks ? ctx.navLink(d, label, "tnc-dg-num") : h(doc, "span", "tnc-dg-num", null, label)
|
|
1116
|
+
opts.navLinks && !this.dotsMode ? ctx.navLink(d, label, "tnc-dg-num") : h(doc, "span", "tnc-dg-num", null, label)
|
|
1116
1117
|
)
|
|
1117
1118
|
);
|
|
1118
1119
|
dates.append(cell);
|
|
@@ -1126,20 +1127,20 @@ var DayGridView = class {
|
|
|
1126
1127
|
layer.append(content);
|
|
1127
1128
|
row.append(dates, layer);
|
|
1128
1129
|
this.grid.append(row);
|
|
1129
|
-
const dots =
|
|
1130
|
+
const dots = cells.map((cell) => {
|
|
1130
1131
|
const box = h(doc, "div", "tnc-dg-dots", { "aria-hidden": "true" });
|
|
1131
1132
|
if (opts.dayMaxEvents === false) box.classList.add("is-unlimited");
|
|
1132
1133
|
const count = h(doc, "span", "tnc-dg-dots-more");
|
|
1133
1134
|
cell.append(box);
|
|
1134
1135
|
return { box, pool: new ItemPool(ctx, box), count };
|
|
1135
|
-
})
|
|
1136
|
+
});
|
|
1136
1137
|
this.weeks.push({ days: wdays, row, cells, layer, sel, more, pool: new ItemPool(ctx, content), dots });
|
|
1137
1138
|
}
|
|
1138
1139
|
this.scroller.append(this.grid);
|
|
1139
1140
|
this.el.append(this.scroller);
|
|
1140
1141
|
this.el.classList.toggle("tnc-dg--auto", opts.height === "auto");
|
|
1141
1142
|
const RO = ctx.win.ResizeObserver;
|
|
1142
|
-
if (RO
|
|
1143
|
+
if (RO) {
|
|
1143
1144
|
this.resizeObs = new RO(() => {
|
|
1144
1145
|
if (this.sizeKey() !== this.lastHeights) this.render(null);
|
|
1145
1146
|
});
|
|
@@ -1170,14 +1171,35 @@ var DayGridView = class {
|
|
|
1170
1171
|
}
|
|
1171
1172
|
render(_change) {
|
|
1172
1173
|
const { ctx } = this;
|
|
1174
|
+
this.dotsMode = ctx.opts.monthDisplay !== "full" || this.grid.clientWidth / this.daysPerWeek() < 72;
|
|
1175
|
+
this.el.classList.toggle("tnc-dg--dots", this.dotsMode);
|
|
1176
|
+
this.el.classList.toggle("tnc-dg--compact", this.dotsMode && ctx.opts.monthDisplay === "full");
|
|
1177
|
+
this.el.classList.toggle("tnc-dg--chips", ctx.opts.monthDisplay === "chips" && this.weeks[0].dots[0].box.clientHeight >= 44);
|
|
1173
1178
|
const cs = ctx.win.getComputedStyle(this.el);
|
|
1174
1179
|
this.barPx = px(cs, "--tnc-bar-h", 20);
|
|
1175
1180
|
this.topPx = this.weeks[0]?.cells[0]?.querySelector(".tnc-dg-top")?.offsetHeight || px(cs, "--tnc-dg-top-h", 24);
|
|
1176
1181
|
this.morePx = this.measureMore(cs);
|
|
1177
1182
|
this.lastHeights = this.sizeKey();
|
|
1178
1183
|
for (const w of this.weeks) {
|
|
1179
|
-
|
|
1180
|
-
|
|
1184
|
+
for (const cell of w.cells) {
|
|
1185
|
+
if (this.dotsMode) cell.tabIndex = 0;
|
|
1186
|
+
else cell.removeAttribute("tabindex");
|
|
1187
|
+
if (this.dotsMode && ctx.opts.monthDisplay === "full") cell.setAttribute("aria-haspopup", "dialog");
|
|
1188
|
+
else cell.removeAttribute("aria-haspopup");
|
|
1189
|
+
}
|
|
1190
|
+
for (const cell of w.dots) cell.box.hidden = !this.dotsMode;
|
|
1191
|
+
if (this.dotsMode) {
|
|
1192
|
+
w.pool.begin();
|
|
1193
|
+
w.pool.end();
|
|
1194
|
+
w.more.replaceChildren();
|
|
1195
|
+
this.renderDots(w);
|
|
1196
|
+
} else {
|
|
1197
|
+
for (const cell of w.dots) {
|
|
1198
|
+
cell.pool.begin();
|
|
1199
|
+
cell.pool.end();
|
|
1200
|
+
}
|
|
1201
|
+
this.renderWeek(w);
|
|
1202
|
+
}
|
|
1181
1203
|
}
|
|
1182
1204
|
}
|
|
1183
1205
|
/** Height of a "+N more" link as the host styles it (`--tnc-more-h`, or a taller min-height). */
|
|
@@ -1276,7 +1298,8 @@ var DayGridView = class {
|
|
|
1276
1298
|
w.more.append(link);
|
|
1277
1299
|
}
|
|
1278
1300
|
existing.delete(key);
|
|
1279
|
-
link.
|
|
1301
|
+
link.setAttribute("aria-label", ctx.text.more(items.length));
|
|
1302
|
+
link.textContent = w.row.clientWidth / n < 72 ? `+${new Intl.NumberFormat(ctx.opts.locale).format(items.length)}` : ctx.text.more(items.length);
|
|
1280
1303
|
setStyle(link, {
|
|
1281
1304
|
left: `calc(${pct(col / n)} + 2px)`,
|
|
1282
1305
|
width: `calc(${pct(1 / n)} - 4px)`,
|
|
@@ -1306,10 +1329,11 @@ var DayGridView = class {
|
|
|
1306
1329
|
const { dayMaxEvents } = ctx.opts;
|
|
1307
1330
|
const first = w.dots[0].box;
|
|
1308
1331
|
const cs = ctx.win.getComputedStyle(first);
|
|
1309
|
-
const
|
|
1332
|
+
const chips = this.el.classList.contains("tnc-dg--chips");
|
|
1333
|
+
const size = chips ? px(cs, "--tnc-chip-h", 14) : px(cs, "--tnc-dot-size", 8);
|
|
1310
1334
|
const gap = px(cs, "--tnc-dot-gap", 3);
|
|
1311
1335
|
const step = size + gap;
|
|
1312
|
-
const perRow = Math.max(1, Math.floor((first.clientWidth + gap) / step));
|
|
1336
|
+
const perRow = chips ? 1 : Math.max(1, Math.floor((first.clientWidth + gap) / step));
|
|
1313
1337
|
const rows = Math.max(1, Math.floor((first.clientHeight + gap) / step));
|
|
1314
1338
|
const fits = dayMaxEvents === false ? Infinity : perRow * rows;
|
|
1315
1339
|
const cap = typeof dayMaxEvents === "number" && dayMaxEvents > 0 ? Math.min(dayMaxEvents, fits) : fits;
|
|
@@ -1318,7 +1342,7 @@ var DayGridView = class {
|
|
|
1318
1342
|
w.days.forEach((day, i) => {
|
|
1319
1343
|
const cell = w.dots[i];
|
|
1320
1344
|
const items = this.itemsOn(day);
|
|
1321
|
-
const shown = items.length <= cap ? items.length : cap >= fits ? Math.max(
|
|
1345
|
+
const shown = items.length <= cap ? items.length : cap >= fits ? Math.max(1, cap - (chips ? 1 : 2)) : Math.max(1, cap);
|
|
1322
1346
|
cell.pool.begin();
|
|
1323
1347
|
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 }));
|
|
1324
1348
|
cell.pool.end();
|
|
@@ -1435,6 +1459,7 @@ var ListView = class {
|
|
|
1435
1459
|
const leadItems = [];
|
|
1436
1460
|
const inLead = /* @__PURE__ */ new Set();
|
|
1437
1461
|
const keep = /* @__PURE__ */ new Set();
|
|
1462
|
+
let itemCount = 0;
|
|
1438
1463
|
let prev = null;
|
|
1439
1464
|
for (const day of days) {
|
|
1440
1465
|
let items = this.itemsOn(day);
|
|
@@ -1448,7 +1473,7 @@ var ListView = class {
|
|
|
1448
1473
|
return false;
|
|
1449
1474
|
});
|
|
1450
1475
|
}
|
|
1451
|
-
if (!items.length && !agenda) continue;
|
|
1476
|
+
if (!items.length && !agenda && opts.listDayCount !== 1) continue;
|
|
1452
1477
|
keep.add(day);
|
|
1453
1478
|
let section = this.sections.get(day);
|
|
1454
1479
|
let pool = this.pools.get(day);
|
|
@@ -1467,6 +1492,7 @@ var ListView = class {
|
|
|
1467
1492
|
this.pools.set(day, pool);
|
|
1468
1493
|
}
|
|
1469
1494
|
section.classList.toggle("is-empty", !items.length);
|
|
1495
|
+
itemCount += items.length;
|
|
1470
1496
|
this.fill(pool, items, () => day);
|
|
1471
1497
|
if (prev ? prev.nextSibling !== section : this.body.firstChild !== section) {
|
|
1472
1498
|
if (prev) prev.after(section);
|
|
@@ -1482,13 +1508,14 @@ var ListView = class {
|
|
|
1482
1508
|
this.sections.delete(day);
|
|
1483
1509
|
}
|
|
1484
1510
|
this.renderLead(leadItems);
|
|
1485
|
-
let empty = this.body.querySelector("
|
|
1486
|
-
if (!
|
|
1511
|
+
let empty = this.body.querySelector(".tnc-list-empty");
|
|
1512
|
+
if (!itemCount && !leadItems.length && (!agenda || opts.listEmptyContent)) {
|
|
1487
1513
|
if (!empty) {
|
|
1488
1514
|
empty = h(doc, "div", "tnc-list-empty", { role: "listitem" }, ctx.text.noItems);
|
|
1489
1515
|
const content = ctx.opts.listEmptyContent?.();
|
|
1490
1516
|
if (content) empty.replaceChildren(content);
|
|
1491
|
-
this.
|
|
1517
|
+
if (this.sections.size === 1) this.sections.values().next().value.append(empty);
|
|
1518
|
+
else this.body.prepend(empty);
|
|
1492
1519
|
}
|
|
1493
1520
|
} else empty?.remove();
|
|
1494
1521
|
this.ctx.strip?.draw();
|
|
@@ -1546,7 +1573,7 @@ var ListView = class {
|
|
|
1546
1573
|
const section = day === this.ctx.days[0] && this.lead ? this.lead.section : this.sections.get(day);
|
|
1547
1574
|
if (!section) return;
|
|
1548
1575
|
this.ctx.strip?.measure();
|
|
1549
|
-
section.
|
|
1576
|
+
this.scroller.scrollTop += section.getBoundingClientRect().top - this.scroller.getBoundingClientRect().top;
|
|
1550
1577
|
this.ctx.strip?.setFocus(day);
|
|
1551
1578
|
this.pinned = true;
|
|
1552
1579
|
}
|
|
@@ -1635,8 +1662,7 @@ var DateStrip = class {
|
|
|
1635
1662
|
head.append(this.title, this.todayBtn, prev, next, this.slot);
|
|
1636
1663
|
this.dows = h(doc, "div", "tnc-strip-dows", { "aria-hidden": "true" });
|
|
1637
1664
|
this.grid = h(doc, "div", "tnc-strip-grid", { role: "group" });
|
|
1638
|
-
const handle = h(doc, "
|
|
1639
|
-
handle.addEventListener("click", () => this.setExpanded(!this.expanded));
|
|
1665
|
+
const handle = h(doc, "div", "tnc-strip-handle", { "aria-hidden": "true" });
|
|
1640
1666
|
this.el.append(head, this.dows, this.grid, handle);
|
|
1641
1667
|
this.grid.addEventListener("click", this.onClick);
|
|
1642
1668
|
this.grid.addEventListener("keydown", this.onKeyDown);
|
|
@@ -2215,8 +2241,15 @@ var TimeGridView = class {
|
|
|
2215
2241
|
link.classList.toggle("tnc-more--collision", collapse);
|
|
2216
2242
|
link.textContent = `+${rec.count}`;
|
|
2217
2243
|
if (collapse) {
|
|
2218
|
-
|
|
2219
|
-
|
|
2244
|
+
const items = placements.filter((placement) => placement.cluster === cluster).map((placement) => placement.item.item.title);
|
|
2245
|
+
const count = ctx.text.appointments(rec.count);
|
|
2246
|
+
const interval = `${ctx.fmt.time(rec.start)} \u2013 ${ctx.fmt.time(rec.end)}`;
|
|
2247
|
+
link.replaceChildren(
|
|
2248
|
+
h(ctx.doc, "span", "tnc-collision-count", null, String(rec.count)),
|
|
2249
|
+
h(ctx.doc, "span", "tnc-collision-range", null, interval),
|
|
2250
|
+
h(ctx.doc, "span", "tnc-collision-title", { "aria-hidden": "true" }, items.join(" \xB7 "))
|
|
2251
|
+
);
|
|
2252
|
+
link.setAttribute("aria-label", `${count}, ${interval}: ${items.join(", ")}`);
|
|
2220
2253
|
link.title = link.getAttribute("aria-label");
|
|
2221
2254
|
} else {
|
|
2222
2255
|
link.removeAttribute("aria-label");
|
|
@@ -2225,6 +2258,7 @@ var TimeGridView = class {
|
|
|
2225
2258
|
const cols = maxStack;
|
|
2226
2259
|
setStyle(link, {
|
|
2227
2260
|
top: top(rec.start),
|
|
2261
|
+
height: collapse ? pct((rec.end - rec.start) / this.minutes) : "",
|
|
2228
2262
|
...inLane(lane, rec.split, (cols - 1) / cols, 1 / cols)
|
|
2229
2263
|
});
|
|
2230
2264
|
}
|
|
@@ -2291,12 +2325,10 @@ var TimeGridView = class {
|
|
|
2291
2325
|
const r2 = cells[i2].getBoundingClientRect();
|
|
2292
2326
|
if (x >= r2.left && x < r2.right) return i2;
|
|
2293
2327
|
}
|
|
2294
|
-
const firstR = cells[0]?.getBoundingClientRect();
|
|
2295
|
-
const lastR = cells[cells.length - 1]?.getBoundingClientRect();
|
|
2296
|
-
if (firstR && x < firstR.left) return 0;
|
|
2297
|
-
if (lastR && x >= lastR.right) return cells.length - 1;
|
|
2298
2328
|
return -1;
|
|
2299
2329
|
};
|
|
2330
|
+
const bounds = this.scroller.getBoundingClientRect();
|
|
2331
|
+
if (x < bounds.left || x >= bounds.right || y < bounds.top || y >= bounds.bottom) return null;
|
|
2300
2332
|
if (this.allDayRow) {
|
|
2301
2333
|
const r2 = this.allDayRow.getBoundingClientRect();
|
|
2302
2334
|
if (y >= r2.top && y < r2.bottom || !this.body && y >= r2.top) {
|
|
@@ -3019,6 +3051,14 @@ ${this.ctx.text.more(items.length - 8)}` : ""}` : label;
|
|
|
3019
3051
|
setScroll(s) {
|
|
3020
3052
|
this.scroller.scrollTop = s.top;
|
|
3021
3053
|
}
|
|
3054
|
+
revealDay(day) {
|
|
3055
|
+
const month = this.cells.find((cell) => cell.day === day)?.el.closest(".tnc-ym");
|
|
3056
|
+
if (!month) return;
|
|
3057
|
+
const bounds = month.getBoundingClientRect();
|
|
3058
|
+
const viewport = this.scroller.getBoundingClientRect();
|
|
3059
|
+
if (bounds.top < viewport.top) this.scroller.scrollTop += bounds.top - viewport.top;
|
|
3060
|
+
else if (bounds.bottom > viewport.bottom) this.scroller.scrollTop += bounds.bottom - viewport.bottom;
|
|
3061
|
+
}
|
|
3022
3062
|
elementsFor(_id) {
|
|
3023
3063
|
return [];
|
|
3024
3064
|
}
|
|
@@ -3098,6 +3138,11 @@ var Calendar = class {
|
|
|
3098
3138
|
conflicts = /* @__PURE__ */ new Map();
|
|
3099
3139
|
slot = { min: 0, max: MINUTES_PER_DAY, duration: 30, snap: 30, scroll: 480 };
|
|
3100
3140
|
draggingId = null;
|
|
3141
|
+
listDragPreview = null;
|
|
3142
|
+
dragSources = [];
|
|
3143
|
+
dragScrollFrame = null;
|
|
3144
|
+
dragScrollOrigins = /* @__PURE__ */ new Map();
|
|
3145
|
+
itemWriteStates = /* @__PURE__ */ new Map();
|
|
3101
3146
|
dragRow = null;
|
|
3102
3147
|
strip = null;
|
|
3103
3148
|
stripSize = null;
|
|
@@ -3111,6 +3156,7 @@ var Calendar = class {
|
|
|
3111
3156
|
session = null;
|
|
3112
3157
|
selection = null;
|
|
3113
3158
|
suppressClick = false;
|
|
3159
|
+
cancelledPointerId = null;
|
|
3114
3160
|
selectedIds = /* @__PURE__ */ new Set();
|
|
3115
3161
|
popover = null;
|
|
3116
3162
|
timer = null;
|
|
@@ -3128,6 +3174,7 @@ var Calendar = class {
|
|
|
3128
3174
|
this.positionMore();
|
|
3129
3175
|
});
|
|
3130
3176
|
this.resizeObs.observe(this.root);
|
|
3177
|
+
this.resizeObs.observe(this.toolbarEl);
|
|
3131
3178
|
}
|
|
3132
3179
|
}
|
|
3133
3180
|
onAdoptCheck = () => {
|
|
@@ -3254,7 +3301,12 @@ var Calendar = class {
|
|
|
3254
3301
|
gotoDate(date) {
|
|
3255
3302
|
const day = this.toDay(date);
|
|
3256
3303
|
if (day === null) return;
|
|
3304
|
+
const sameMonth = this.opts.view === "month" && startOfMonth(day) === startOfMonth(this.anchor);
|
|
3257
3305
|
this.anchor = day;
|
|
3306
|
+
if (sameMonth) {
|
|
3307
|
+
this.view = { ...this.view, anchor: day };
|
|
3308
|
+
return;
|
|
3309
|
+
}
|
|
3258
3310
|
this.rebuild(true);
|
|
3259
3311
|
}
|
|
3260
3312
|
prev() {
|
|
@@ -3400,7 +3452,8 @@ var Calendar = class {
|
|
|
3400
3452
|
out.push(...classList(this.opts.dayClassNames?.(this.dayArg(day))));
|
|
3401
3453
|
return out;
|
|
3402
3454
|
}
|
|
3403
|
-
isEditable(n, what) {
|
|
3455
|
+
isEditable(n, what, presentation = false) {
|
|
3456
|
+
if (!presentation && this.itemWriteStates.get(n.id) === "pending") return false;
|
|
3404
3457
|
if (n.id === EXTERNAL_ID || n.item.preview || this.opts.view === "year") return false;
|
|
3405
3458
|
if (this.opts.view === "list" && (!this.opts.listAgenda || what === "duration")) return false;
|
|
3406
3459
|
const it = n.item;
|
|
@@ -3440,13 +3493,14 @@ var Calendar = class {
|
|
|
3440
3493
|
if (preview || n.id === EXTERNAL_ID) el.classList.add("is-mirror");
|
|
3441
3494
|
if (this.conflicts.has(n.id)) el.classList.add("is-conflict");
|
|
3442
3495
|
const indicator = variant === "indicator";
|
|
3443
|
-
if (!preview && !indicator && (this.isEditable(n, "start") || this.isEditable(n, "duration"))) el.classList.add("is-draggable");
|
|
3496
|
+
if (!preview && !indicator && (this.isEditable(n, "start", true) || this.isEditable(n, "duration", true))) el.classList.add("is-draggable");
|
|
3444
3497
|
if (this.draggingId === n.id) el.classList.add("is-dragging");
|
|
3445
3498
|
if (this.selectedIds.has(n.id) && !preview) el.classList.add("is-selected");
|
|
3446
3499
|
el.classList.add(...classList(it.className));
|
|
3447
3500
|
const arg = this.itemArg(el, meta);
|
|
3448
3501
|
el.classList.add(...classList(this.opts.itemClassNames?.(arg)));
|
|
3449
3502
|
el.dataset.id = n.id;
|
|
3503
|
+
this.applyItemWriteState(el, n.id);
|
|
3450
3504
|
if (it.kind) el.dataset.kind = it.kind;
|
|
3451
3505
|
const color = it.color ?? it.borderColor;
|
|
3452
3506
|
if (color) el.style.setProperty("--tnc-c", color);
|
|
@@ -3463,6 +3517,7 @@ var Calendar = class {
|
|
|
3463
3517
|
const custom = variant === "list" ? this.opts.listItemContent?.(arg) : null;
|
|
3464
3518
|
const content = indicator ? null : custom ?? this.opts.itemContent?.(arg);
|
|
3465
3519
|
if (indicator) {
|
|
3520
|
+
if (this.opts.monthDisplay === "chips") el.append(h(this.doc, "span", "tnc-item-title", null, it.title));
|
|
3466
3521
|
} else if (content != null) {
|
|
3467
3522
|
const wrap = h(this.doc, "div", "tnc-item-main");
|
|
3468
3523
|
wrap.append(content);
|
|
@@ -3475,6 +3530,7 @@ var Calendar = class {
|
|
|
3475
3530
|
return el;
|
|
3476
3531
|
}
|
|
3477
3532
|
refreshItemEl(el, meta) {
|
|
3533
|
+
this.applyItemWriteState(el, meta.n.id);
|
|
3478
3534
|
const time = el.querySelector(":scope .tnc-item-time");
|
|
3479
3535
|
if (time) this.fillTime(time, meta.n, meta.variant, meta.day);
|
|
3480
3536
|
el.classList.toggle("is-dragging", this.draggingId === meta.n.id);
|
|
@@ -3657,6 +3713,7 @@ var Calendar = class {
|
|
|
3657
3713
|
this.current.scrollToTime(this.slot.scroll);
|
|
3658
3714
|
this.current.revealDay(this.anchor);
|
|
3659
3715
|
} else if (this.current instanceof TimelineView) this.current.scrollToDay(this.anchor);
|
|
3716
|
+
else if (this.current instanceof YearView) this.current.revealDay(this.anchor);
|
|
3660
3717
|
if (rangeChanged) this.opts.onRangeChange?.(this.view);
|
|
3661
3718
|
}
|
|
3662
3719
|
/** Sets the visible days and view info from the anchor. */
|
|
@@ -3682,9 +3739,11 @@ var Calendar = class {
|
|
|
3682
3739
|
}
|
|
3683
3740
|
/** The range, run on to the end of the strip's days so their dots are right. */
|
|
3684
3741
|
dataRangeFor(range) {
|
|
3685
|
-
const
|
|
3686
|
-
|
|
3687
|
-
|
|
3742
|
+
const window = this.strip?.window();
|
|
3743
|
+
const start = window ? Math.min(range.startDay, window.start) : range.startDay;
|
|
3744
|
+
const end = window ? Math.max(range.endDay, window.end) : range.endDay;
|
|
3745
|
+
if (start === range.startDay && end === range.endDay) return range;
|
|
3746
|
+
return { ...range, startDay: start, start: new Date(toInstant(start, 0, this.zone)), endDay: end, end: new Date(toInstant(end, 0, this.zone)) };
|
|
3688
3747
|
}
|
|
3689
3748
|
/** Adds, updates or removes the date strip for the current view. */
|
|
3690
3749
|
syncStrip(navigated) {
|
|
@@ -3731,20 +3790,24 @@ var Calendar = class {
|
|
|
3731
3790
|
stripShown() {
|
|
3732
3791
|
if (!this.strip || this.rebuilding || !this.view) return;
|
|
3733
3792
|
const next = this.dataRangeFor(this.view.range);
|
|
3734
|
-
if (next.endDay === this.view.dataRange.endDay) return;
|
|
3793
|
+
if (next.startDay === this.view.dataRange.startDay && next.endDay === this.view.dataRange.endDay) return;
|
|
3735
3794
|
this.view = { ...this.view, dataRange: next };
|
|
3736
3795
|
this.opts.onRangeChange?.(this.view);
|
|
3737
3796
|
}
|
|
3738
3797
|
/** What is under a point, the date strip included. */
|
|
3739
3798
|
hitAt(x, y) {
|
|
3799
|
+
const target = this.doc.elementFromPoint(x, y);
|
|
3800
|
+
if (!target || !this.root.contains(target)) {
|
|
3801
|
+
this.strip?.markTarget(null);
|
|
3802
|
+
return null;
|
|
3803
|
+
}
|
|
3740
3804
|
const strip = this.strip;
|
|
3741
3805
|
if (strip) {
|
|
3742
|
-
const
|
|
3743
|
-
const day = el ? strip.dayAt(el) : null;
|
|
3806
|
+
const day = strip.dayAt(target);
|
|
3744
3807
|
strip.markTarget(day !== null && this.draggingId ? day : null);
|
|
3745
3808
|
if (day !== null) return { kind: "day", day };
|
|
3746
3809
|
}
|
|
3747
|
-
return this.current?.hit(x, y)
|
|
3810
|
+
return this.current?.el.contains(target) ? this.current.hit(x, y) : null;
|
|
3748
3811
|
}
|
|
3749
3812
|
agendaList() {
|
|
3750
3813
|
return this.opts.view === "list" && this.opts.listAgenda && this.current instanceof ListView ? this.current : null;
|
|
@@ -3858,11 +3921,13 @@ var Calendar = class {
|
|
|
3858
3921
|
buttons.style.display = "flex";
|
|
3859
3922
|
select.style.display = "none";
|
|
3860
3923
|
const startWidth = Array.from(start.children).reduce((width, child) => width + child.scrollWidth, 0);
|
|
3861
|
-
const
|
|
3924
|
+
const availableWidth = Math.min(this.root.clientWidth, this.toolbarEl.clientWidth);
|
|
3925
|
+
const compact = mode === "select" || mode === "auto" && startWidth + buttons.scrollWidth + 32 > availableWidth;
|
|
3862
3926
|
buttons.hidden = compact;
|
|
3863
3927
|
select.hidden = !compact;
|
|
3864
3928
|
buttons.style.display = compact ? "none" : "flex";
|
|
3865
3929
|
select.style.display = compact ? "" : "none";
|
|
3930
|
+
select.parentElement?.classList.toggle("tnc-toolbar-end--compact", compact);
|
|
3866
3931
|
}
|
|
3867
3932
|
applyChange(change) {
|
|
3868
3933
|
if (!change.added.length && !change.updated.length && !change.removed.length && !change.days.size && !change.spans) return;
|
|
@@ -3927,7 +3992,7 @@ var Calendar = class {
|
|
|
3927
3992
|
const s = wallTime(n.startMs, this.zone);
|
|
3928
3993
|
const start = this.fmt.time(s.minute, true);
|
|
3929
3994
|
if (variant === "dot" || variant === "bar" || variant === "indicator") return { start: s.day === day ? start : "", end: "" };
|
|
3930
|
-
if (n.startMs === n.endMs) return { start, end: "" };
|
|
3995
|
+
if (n.startMs === n.endMs || n.item.timeDisplay === "start") return { start, end: "" };
|
|
3931
3996
|
return { start, end: this.fmt.time(wallTime(n.endMs, this.zone).minute, true) };
|
|
3932
3997
|
}
|
|
3933
3998
|
fillTime(el, n, variant, day) {
|
|
@@ -3943,7 +4008,8 @@ var Calendar = class {
|
|
|
3943
4008
|
}
|
|
3944
4009
|
const s = wallTime(n.startMs, this.zone);
|
|
3945
4010
|
const e = wallTime(n.endMs, this.zone);
|
|
3946
|
-
|
|
4011
|
+
const start = `${n.item.title}, ${this.fmt.longDate(s.day)} ${this.fmt.time(s.minute)}`;
|
|
4012
|
+
return n.item.timeDisplay === "start" || n.startMs === n.endMs ? start : `${start} \u2013 ${this.fmt.time(e.minute)}`;
|
|
3947
4013
|
}
|
|
3948
4014
|
defaultContent(meta) {
|
|
3949
4015
|
const { n, variant, day } = meta;
|
|
@@ -3971,7 +4037,7 @@ var Calendar = class {
|
|
|
3971
4037
|
addHandles(el, meta) {
|
|
3972
4038
|
const { n, variant } = meta;
|
|
3973
4039
|
const ports = variant === "timeline" && !meta.mirror && n.id !== EXTERNAL_ID && !!this.opts.timeline?.onLink;
|
|
3974
|
-
if (variant === "dot" || !this.isEditable(n, "duration")) {
|
|
4040
|
+
if (variant === "dot" || !this.isEditable(n, "duration", true)) {
|
|
3975
4041
|
if (ports) this.addPorts(el, n);
|
|
3976
4042
|
return;
|
|
3977
4043
|
}
|
|
@@ -4099,6 +4165,10 @@ var Calendar = class {
|
|
|
4099
4165
|
return el && this.root.contains(el) && this.meta.has(el) && !this.meta.get(el)?.n.item.preview ? el : null;
|
|
4100
4166
|
}
|
|
4101
4167
|
onDocPointerDown = (ev) => {
|
|
4168
|
+
if (this.cancelledPointerId !== null) {
|
|
4169
|
+
this.cancelledPointerId = null;
|
|
4170
|
+
this.listenDoc(false);
|
|
4171
|
+
}
|
|
4102
4172
|
const t = ev.target;
|
|
4103
4173
|
if (this.popover && !this.popover.el.contains(t) && !this.popover.anchor.contains(t)) this.closeMore();
|
|
4104
4174
|
if (this.selection && !this.root.contains(t)) this.unselect();
|
|
@@ -4106,6 +4176,7 @@ var Calendar = class {
|
|
|
4106
4176
|
onPointerDown = (ev) => {
|
|
4107
4177
|
if (ev.button !== 0 || this.session) return;
|
|
4108
4178
|
const target = ev.target;
|
|
4179
|
+
if (target.closest(".tnc-dg--compact .tnc-dg-day")) return;
|
|
4109
4180
|
if (target.closest("button, a, input, select, textarea, .tnc-toolbar, .tnc-port, [data-tnc-no-drag]")) {
|
|
4110
4181
|
if (!target.closest(".tnc-item")) return;
|
|
4111
4182
|
if (target.closest(".tnc-port, [data-tnc-no-drag], input, select, textarea")) return;
|
|
@@ -4138,7 +4209,7 @@ var Calendar = class {
|
|
|
4138
4209
|
y0: ev.clientY,
|
|
4139
4210
|
active: false,
|
|
4140
4211
|
origin,
|
|
4141
|
-
grab: overflowOrigin
|
|
4212
|
+
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,
|
|
4142
4213
|
proposal: null,
|
|
4143
4214
|
denied: false,
|
|
4144
4215
|
timer: null,
|
|
@@ -4163,16 +4234,79 @@ var Calendar = class {
|
|
|
4163
4234
|
};
|
|
4164
4235
|
activate(s) {
|
|
4165
4236
|
s.active = true;
|
|
4237
|
+
if (s.lastEvent) this.leaveHover(s.lastEvent);
|
|
4166
4238
|
if (s.timer !== null) this.win.clearTimeout(s.timer);
|
|
4167
4239
|
s.timer = null;
|
|
4168
4240
|
if (s.origin) {
|
|
4169
4241
|
this.draggingId = s.origin.id;
|
|
4170
|
-
for (const el of this.elementsFor(s.origin.id))
|
|
4242
|
+
for (const el of this.elementsFor(s.origin.id)) {
|
|
4243
|
+
if (this.opts.view !== "list" && s.mode === "move") {
|
|
4244
|
+
const source = el.cloneNode(true);
|
|
4245
|
+
source.classList.remove("is-selected");
|
|
4246
|
+
source.classList.add("tnc-drag-source");
|
|
4247
|
+
source.setAttribute("aria-hidden", "true");
|
|
4248
|
+
source.inert = true;
|
|
4249
|
+
for (const node of [source, ...source.querySelectorAll("[id], [data-id], [data-task-path]")]) {
|
|
4250
|
+
node.removeAttribute("id");
|
|
4251
|
+
node.removeAttribute("data-id");
|
|
4252
|
+
node.removeAttribute("data-task-path");
|
|
4253
|
+
}
|
|
4254
|
+
el.before(source);
|
|
4255
|
+
this.dragSources.push(source);
|
|
4256
|
+
}
|
|
4257
|
+
if (this.opts.view === "list" && !this.listDragPreview && s.mode === "move") {
|
|
4258
|
+
const bounds = el.getBoundingClientRect();
|
|
4259
|
+
const preview = el.cloneNode(true);
|
|
4260
|
+
preview.classList.add("tnc-drag-preview", "is-dragging");
|
|
4261
|
+
preview.removeAttribute("data-id");
|
|
4262
|
+
preview.removeAttribute("data-task-path");
|
|
4263
|
+
preview.setAttribute("aria-hidden", "true");
|
|
4264
|
+
preview.inert = true;
|
|
4265
|
+
preview.style.width = `${bounds.width}px`;
|
|
4266
|
+
this.root.append(preview);
|
|
4267
|
+
this.listDragPreview = { element: preview, offsetX: s.x0 - bounds.left, offsetY: s.y0 - bounds.top, width: bounds.width, height: bounds.height };
|
|
4268
|
+
}
|
|
4269
|
+
el.classList.add("is-dragging");
|
|
4270
|
+
}
|
|
4171
4271
|
}
|
|
4172
4272
|
this.closeMore();
|
|
4173
4273
|
if (s.mode !== "select") this.unselectSilently();
|
|
4174
4274
|
this.root.classList.add("tnc-dragging", `tnc-dragging-${s.mode}`);
|
|
4175
4275
|
if (s.lastEvent) this.track(s, s.lastEvent);
|
|
4276
|
+
this.startDragScroll();
|
|
4277
|
+
}
|
|
4278
|
+
startDragScroll() {
|
|
4279
|
+
if (this.dragScrollFrame !== null) return;
|
|
4280
|
+
const tick = () => {
|
|
4281
|
+
this.dragScrollFrame = null;
|
|
4282
|
+
const session = this.session;
|
|
4283
|
+
const pointer = session?.lastEvent;
|
|
4284
|
+
if (!session?.active || !pointer) return;
|
|
4285
|
+
const origin = session.origin ? this.elementsFor(session.origin.id)[0] : this.viewHost;
|
|
4286
|
+
const underPointer = this.doc.elementFromPoint(pointer.clientX, pointer.clientY);
|
|
4287
|
+
let moved = false;
|
|
4288
|
+
if (origin && underPointer && this.root.contains(underPointer)) {
|
|
4289
|
+
for (const axis of ["x", "y"]) {
|
|
4290
|
+
const scroller = scrollerOf(origin, axis);
|
|
4291
|
+
if (!scroller) continue;
|
|
4292
|
+
const viewport = scroller === this.doc.scrollingElement ? { left: 0, top: 0, right: this.win.innerWidth, bottom: this.win.innerHeight } : scroller.getBoundingClientRect();
|
|
4293
|
+
const coordinate = axis === "x" ? pointer.clientX : pointer.clientY;
|
|
4294
|
+
const lower = Math.max(0, axis === "x" ? viewport.left : viewport.top);
|
|
4295
|
+
const upper = Math.min(axis === "x" ? this.win.innerWidth : this.win.innerHeight, axis === "x" ? viewport.right : viewport.bottom);
|
|
4296
|
+
if (coordinate < lower || coordinate > upper) continue;
|
|
4297
|
+
const delta = coordinate < lower + 32 ? -Math.min(12, (lower + 32 - coordinate) / 2) : coordinate > upper - 32 ? Math.min(12, (coordinate - upper + 32) / 2) : 0;
|
|
4298
|
+
if (!delta) continue;
|
|
4299
|
+
if (!this.dragScrollOrigins.has(scroller)) this.dragScrollOrigins.set(scroller, { top: scroller.scrollTop, left: scroller.scrollLeft });
|
|
4300
|
+
const before = axis === "x" ? scroller.scrollLeft : scroller.scrollTop;
|
|
4301
|
+
if (axis === "x") scroller.scrollLeft += delta;
|
|
4302
|
+
else scroller.scrollTop += delta;
|
|
4303
|
+
moved ||= before !== (axis === "x" ? scroller.scrollLeft : scroller.scrollTop);
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
if (moved) this.track(session, pointer);
|
|
4307
|
+
this.dragScrollFrame = this.win.requestAnimationFrame(tick);
|
|
4308
|
+
};
|
|
4309
|
+
this.dragScrollFrame = this.win.requestAnimationFrame(tick);
|
|
4176
4310
|
}
|
|
4177
4311
|
onTouchMove = (ev) => {
|
|
4178
4312
|
if (this.session?.active) ev.preventDefault();
|
|
@@ -4202,6 +4336,12 @@ var Calendar = class {
|
|
|
4202
4336
|
this.track(s, ev);
|
|
4203
4337
|
};
|
|
4204
4338
|
onPointerUp = (ev) => {
|
|
4339
|
+
if (ev.pointerId === this.cancelledPointerId) {
|
|
4340
|
+
this.cancelledPointerId = null;
|
|
4341
|
+
this.suppressNextClick();
|
|
4342
|
+
this.listenDoc(false);
|
|
4343
|
+
return;
|
|
4344
|
+
}
|
|
4205
4345
|
const s = this.session;
|
|
4206
4346
|
if (!s || ev.pointerId !== s.pointerId) return;
|
|
4207
4347
|
if (!s.active) {
|
|
@@ -4214,28 +4354,49 @@ var Calendar = class {
|
|
|
4214
4354
|
return;
|
|
4215
4355
|
}
|
|
4216
4356
|
this.suppressNextClick();
|
|
4357
|
+
this.track(s, ev);
|
|
4217
4358
|
this.endSession(ev, false);
|
|
4218
4359
|
};
|
|
4219
4360
|
onPointerCancel = (ev) => {
|
|
4361
|
+
if (ev.pointerId === this.cancelledPointerId) {
|
|
4362
|
+
this.cancelledPointerId = null;
|
|
4363
|
+
this.listenDoc(false);
|
|
4364
|
+
}
|
|
4220
4365
|
if (this.session && ev.pointerId === this.session.pointerId) this.endSession(null, true);
|
|
4221
4366
|
};
|
|
4222
4367
|
onDocKeyDown = (ev) => {
|
|
4223
4368
|
if (ev.key === "Escape" && this.session) {
|
|
4224
4369
|
ev.preventDefault();
|
|
4225
4370
|
ev.stopPropagation();
|
|
4371
|
+
const pointerId = this.session.active ? this.session.pointerId : null;
|
|
4226
4372
|
this.endSession(null, true);
|
|
4373
|
+
if (pointerId !== null) {
|
|
4374
|
+
this.cancelledPointerId = pointerId;
|
|
4375
|
+
this.listenDoc(true);
|
|
4376
|
+
}
|
|
4227
4377
|
}
|
|
4228
4378
|
};
|
|
4229
4379
|
/** Proposal for the current pointer position. */
|
|
4230
4380
|
track(s, ev) {
|
|
4381
|
+
if (this.listDragPreview) {
|
|
4382
|
+
const preview = this.listDragPreview;
|
|
4383
|
+
const bounds = this.root.getBoundingClientRect();
|
|
4384
|
+
preview.element.style.left = `${Math.max(8, Math.min(this.win.innerWidth - preview.width - 8, ev.clientX - preview.offsetX)) - bounds.left}px`;
|
|
4385
|
+
preview.element.style.top = `${Math.max(8, Math.min(this.win.innerHeight - preview.height - 8, ev.clientY - preview.offsetY)) - bounds.top}px`;
|
|
4386
|
+
}
|
|
4231
4387
|
const hit = this.hitAt(ev.clientX, ev.clientY);
|
|
4232
4388
|
if (s.mode === "external") {
|
|
4233
4389
|
this.trackExternal(s, hit);
|
|
4234
4390
|
return;
|
|
4235
4391
|
}
|
|
4236
4392
|
if (!s.grab) s.grab = hit;
|
|
4237
|
-
if (!hit || !s.grab)
|
|
4393
|
+
if (!hit || !s.grab) {
|
|
4394
|
+
this.invalidateProposal(s);
|
|
4395
|
+
return;
|
|
4396
|
+
}
|
|
4238
4397
|
if (s.mode === "select") {
|
|
4398
|
+
s.denied = false;
|
|
4399
|
+
this.root.classList.remove("tnc-drop-denied");
|
|
4239
4400
|
const sel = this.selectionFor(s.grab, hit);
|
|
4240
4401
|
if (!sel) return;
|
|
4241
4402
|
this.selection = sel;
|
|
@@ -4244,25 +4405,40 @@ var Calendar = class {
|
|
|
4244
4405
|
}
|
|
4245
4406
|
const origin = s.origin;
|
|
4246
4407
|
const p = s.mode === "move" ? this.moveProposal(origin, s.grab, hit) : this.resizeProposal(origin, hit, s.mode === "resize-start");
|
|
4247
|
-
if (!p)
|
|
4408
|
+
if (!p) {
|
|
4409
|
+
this.invalidateProposal(s);
|
|
4410
|
+
return;
|
|
4411
|
+
}
|
|
4248
4412
|
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;
|
|
4249
4413
|
s.denied = !allowed;
|
|
4250
4414
|
this.root.classList.toggle("tnc-drop-denied", !allowed);
|
|
4251
|
-
if (!allowed
|
|
4415
|
+
if (!allowed) {
|
|
4416
|
+
this.invalidateProposal(s);
|
|
4417
|
+
return;
|
|
4418
|
+
}
|
|
4419
|
+
if (sameProposal(p, s.proposal)) return;
|
|
4252
4420
|
s.proposal = p;
|
|
4253
4421
|
this.dragRow = p.rowId !== void 0 ? { id: origin.id, rowId: p.rowId } : null;
|
|
4254
|
-
this.applyChange(this.store.upsert([this.withProposal(origin, p)]));
|
|
4422
|
+
if (this.opts.view !== "list") this.applyChange(this.store.upsert([this.withProposal(origin, p)]));
|
|
4423
|
+
}
|
|
4424
|
+
invalidateProposal(s) {
|
|
4425
|
+
const hadProposal = s.proposal !== null;
|
|
4426
|
+
s.proposal = null;
|
|
4427
|
+
s.hit = null;
|
|
4428
|
+
s.denied = true;
|
|
4429
|
+
this.dragRow = null;
|
|
4430
|
+
this.root.classList.add("tnc-drop-denied");
|
|
4431
|
+
this.strip?.markTarget(null);
|
|
4432
|
+
this.unselectSilently();
|
|
4433
|
+
if (s.mode === "external") this.applyChange(this.store.remove([EXTERNAL_ID]));
|
|
4434
|
+
else if (hadProposal && s.origin) this.applyChange(this.store.upsert([s.origin.item]));
|
|
4255
4435
|
}
|
|
4256
4436
|
trackExternal(s, raw) {
|
|
4257
4437
|
const src = s.source;
|
|
4258
4438
|
const hit = raw?.kind === "timeline" && raw.area !== "track" && raw.area !== "header" ? null : raw;
|
|
4259
4439
|
s.hit = hit;
|
|
4260
4440
|
if (!hit) {
|
|
4261
|
-
|
|
4262
|
-
s.proposal = null;
|
|
4263
|
-
this.applyChange(this.store.remove([EXTERNAL_ID]));
|
|
4264
|
-
}
|
|
4265
|
-
this.unselectSilently();
|
|
4441
|
+
this.invalidateProposal(s);
|
|
4266
4442
|
return;
|
|
4267
4443
|
}
|
|
4268
4444
|
const dur = src.durationMinutes ?? this.opts.defaultTimedMinutes;
|
|
@@ -4281,6 +4457,10 @@ var Calendar = class {
|
|
|
4281
4457
|
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;
|
|
4282
4458
|
s.denied = !allowed;
|
|
4283
4459
|
this.root.classList.toggle("tnc-drop-denied", !allowed);
|
|
4460
|
+
if (!allowed) {
|
|
4461
|
+
this.invalidateProposal(s);
|
|
4462
|
+
return;
|
|
4463
|
+
}
|
|
4284
4464
|
if (sameProposal(p, s.proposal)) return;
|
|
4285
4465
|
s.proposal = p;
|
|
4286
4466
|
if (hit.kind === "timeline" && p.rowId === void 0) {
|
|
@@ -4473,7 +4653,18 @@ var Calendar = class {
|
|
|
4473
4653
|
endSession(ev, cancel) {
|
|
4474
4654
|
const s = this.session;
|
|
4475
4655
|
if (!s) return;
|
|
4656
|
+
if (this.dragScrollFrame !== null) this.win.cancelAnimationFrame(this.dragScrollFrame);
|
|
4657
|
+
this.dragScrollFrame = null;
|
|
4658
|
+
if (cancel || s.denied) for (const [scroller, position] of this.dragScrollOrigins) {
|
|
4659
|
+
scroller.scrollTop = position.top;
|
|
4660
|
+
scroller.scrollLeft = position.left;
|
|
4661
|
+
}
|
|
4662
|
+
this.dragScrollOrigins.clear();
|
|
4476
4663
|
this.session = null;
|
|
4664
|
+
this.listDragPreview?.element.remove();
|
|
4665
|
+
this.listDragPreview = null;
|
|
4666
|
+
for (const source of this.dragSources) source.remove();
|
|
4667
|
+
this.dragSources = [];
|
|
4477
4668
|
if (s.timer !== null) this.win.clearTimeout(s.timer);
|
|
4478
4669
|
this.listenDoc(false);
|
|
4479
4670
|
this.root.classList.remove(
|
|
@@ -4542,10 +4733,16 @@ var Calendar = class {
|
|
|
4542
4733
|
revert();
|
|
4543
4734
|
return;
|
|
4544
4735
|
}
|
|
4736
|
+
if (this.opts.view === "list") this.applyChange(this.store.upsert([this.withProposal(origin, p)]));
|
|
4545
4737
|
this.flush();
|
|
4546
4738
|
this.commit(s.mode === "move" ? "drop" : "resize", origin, p, ev, revert);
|
|
4547
4739
|
}
|
|
4548
4740
|
commit(kind, origin, p, ev, revert) {
|
|
4741
|
+
let reverted = false;
|
|
4742
|
+
const mark = (state) => {
|
|
4743
|
+
this.itemWriteStates.set(origin.id, state);
|
|
4744
|
+
for (const element of this.elementsFor(origin.id)) this.applyItemWriteState(element, origin.id);
|
|
4745
|
+
};
|
|
4549
4746
|
const arg = {
|
|
4550
4747
|
item: origin.item,
|
|
4551
4748
|
start: new Date(p.startMs),
|
|
@@ -4561,19 +4758,32 @@ var Calendar = class {
|
|
|
4561
4758
|
jsEvent: ev,
|
|
4562
4759
|
source: ev && "key" in ev ? "keyboard" : "pointer",
|
|
4563
4760
|
view: this.view,
|
|
4564
|
-
revert
|
|
4761
|
+
revert: () => {
|
|
4762
|
+
reverted = true;
|
|
4763
|
+
revert();
|
|
4764
|
+
mark("failed");
|
|
4765
|
+
}
|
|
4565
4766
|
};
|
|
4566
4767
|
const handler = kind === "drop" ? this.opts.onItemDrop : this.opts.onItemResize;
|
|
4567
4768
|
try {
|
|
4769
|
+
mark("pending");
|
|
4568
4770
|
const res = handler?.(arg);
|
|
4569
4771
|
if (res && typeof res.then === "function") {
|
|
4570
|
-
Promise.resolve(res).
|
|
4571
|
-
|
|
4772
|
+
void Promise.resolve(res).then(() => {
|
|
4773
|
+
if (!reverted) mark("changed");
|
|
4774
|
+
}, () => arg.revert());
|
|
4775
|
+
} else if (!reverted) mark("changed");
|
|
4572
4776
|
} catch (err) {
|
|
4573
|
-
revert();
|
|
4777
|
+
arg.revert();
|
|
4574
4778
|
throw err;
|
|
4575
4779
|
}
|
|
4576
4780
|
}
|
|
4781
|
+
applyItemWriteState(element, id) {
|
|
4782
|
+
const state = this.itemWriteStates.get(id);
|
|
4783
|
+
for (const name of ["pending", "failed", "changed"]) element.classList.toggle(`is-write-${name}`, state === name);
|
|
4784
|
+
if (state === "pending") element.setAttribute("aria-busy", "true");
|
|
4785
|
+
else element.removeAttribute("aria-busy");
|
|
4786
|
+
}
|
|
4577
4787
|
/* --------------------------------------------------------- click / keys */
|
|
4578
4788
|
/** Runs in the capture phase so the click ending a drag never reaches content inside the calendar, React portals included. */
|
|
4579
4789
|
onClickCapture = (ev) => {
|
|
@@ -4583,6 +4793,12 @@ var Calendar = class {
|
|
|
4583
4793
|
ev.preventDefault();
|
|
4584
4794
|
};
|
|
4585
4795
|
onClick = (ev) => {
|
|
4796
|
+
const compactDay = ev.target.closest?.(".tnc-dg--compact .tnc-dg-day");
|
|
4797
|
+
if (compactDay && this.root.contains(compactDay) && !ev.target.closest(".tnc-navlink")) {
|
|
4798
|
+
const day = parseDay(compactDay.dataset.date ?? "");
|
|
4799
|
+
if (day !== null) this.openMore(day, compactDay, ev);
|
|
4800
|
+
return;
|
|
4801
|
+
}
|
|
4586
4802
|
const yearDay = ev.target.closest?.(".tnc-ym-day");
|
|
4587
4803
|
if (yearDay && this.root.contains(yearDay)) {
|
|
4588
4804
|
const day = parseDay(yearDay.dataset.date ?? "");
|
|
@@ -4671,7 +4887,8 @@ var Calendar = class {
|
|
|
4671
4887
|
const day = parseDay(target.dataset.date ?? "");
|
|
4672
4888
|
if (day !== null) {
|
|
4673
4889
|
ev.preventDefault();
|
|
4674
|
-
|
|
4890
|
+
if (target.closest(".tnc-dg--compact")) this.openMore(day, target, ev);
|
|
4891
|
+
else this.clickSlot({ kind: "day", day }, ev, true);
|
|
4675
4892
|
}
|
|
4676
4893
|
return;
|
|
4677
4894
|
}
|
|
@@ -4759,9 +4976,13 @@ var Calendar = class {
|
|
|
4759
4976
|
const dt = ev.dataTransfer;
|
|
4760
4977
|
if (!dt || !this.opts.acceptNativeDrop?.(dt) || !this.current) return;
|
|
4761
4978
|
ev.preventDefault();
|
|
4979
|
+
const hit = this.hitAt(ev.clientX, ev.clientY);
|
|
4980
|
+
if (!hit || hit.kind === "timeline" && hit.area !== "track" && hit.area !== "header") {
|
|
4981
|
+
dt.dropEffect = "none";
|
|
4982
|
+
this.unselectSilently();
|
|
4983
|
+
return;
|
|
4984
|
+
}
|
|
4762
4985
|
dt.dropEffect = "copy";
|
|
4763
|
-
const hit = this.current.hit(ev.clientX, ev.clientY);
|
|
4764
|
-
if (!hit || hit.kind === "timeline" && hit.area !== "track" && hit.area !== "header") return;
|
|
4765
4986
|
const sel = this.selectionFor(hit, hit);
|
|
4766
4987
|
if (!sel) return;
|
|
4767
4988
|
this.selection = sel;
|
|
@@ -4775,7 +4996,7 @@ var Calendar = class {
|
|
|
4775
4996
|
const dt = ev.dataTransfer;
|
|
4776
4997
|
if (!dt || !this.opts.acceptNativeDrop?.(dt) || !this.current) return;
|
|
4777
4998
|
ev.preventDefault();
|
|
4778
|
-
const hit = this.
|
|
4999
|
+
const hit = this.hitAt(ev.clientX, ev.clientY);
|
|
4779
5000
|
this.unselectSilently();
|
|
4780
5001
|
if (!hit || hit.kind === "timeline" && hit.area !== "track" && hit.area !== "header") return;
|
|
4781
5002
|
const sel = this.selectionFor(hit, hit);
|
|
@@ -4806,7 +5027,7 @@ function scrollerOf(el, axis) {
|
|
|
4806
5027
|
return doc.scrollingElement;
|
|
4807
5028
|
}
|
|
4808
5029
|
function rangeMoved(prev, next) {
|
|
4809
|
-
return !prev || prev.type !== next.type || prev.range.startDay !== next.range.startDay || prev.range.endDay !== next.range.endDay || prev.dataRange.endDay !== next.dataRange.endDay;
|
|
5030
|
+
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;
|
|
4810
5031
|
}
|
|
4811
5032
|
|
|
4812
5033
|
// src/tasknotes/bases.ts
|