@dataverse-kit/calendar-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -0
- package/dist/CalendarView-CShiWFsR.d.ts +104 -0
- package/dist/CalendarView-Dd8BHOLE.d.cts +104 -0
- package/dist/core.cjs +192 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +64 -0
- package/dist/core.d.ts +64 -0
- package/dist/core.mjs +151 -0
- package/dist/core.mjs.map +1 -0
- package/dist/dataverse.cjs +300 -0
- package/dist/dataverse.cjs.map +1 -0
- package/dist/dataverse.d.cts +121 -0
- package/dist/dataverse.d.ts +121 -0
- package/dist/dataverse.mjs +263 -0
- package/dist/dataverse.mjs.map +1 -0
- package/dist/fake.cjs +199 -0
- package/dist/fake.cjs.map +1 -0
- package/dist/fake.d.cts +29 -0
- package/dist/fake.d.ts +29 -0
- package/dist/fake.mjs +171 -0
- package/dist/fake.mjs.map +1 -0
- package/dist/index.cjs +568 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.mjs +515 -0
- package/dist/index.mjs.map +1 -0
- package/dist/pcf-dataset.cjs +328 -0
- package/dist/pcf-dataset.cjs.map +1 -0
- package/dist/pcf-dataset.d.cts +98 -0
- package/dist/pcf-dataset.d.ts +98 -0
- package/dist/pcf-dataset.mjs +296 -0
- package/dist/pcf-dataset.mjs.map +1 -0
- package/dist/types-u3Gpxk53.d.cts +108 -0
- package/dist/types-u3Gpxk53.d.ts +108 -0
- package/dist/v9.cjs +555 -0
- package/dist/v9.cjs.map +1 -0
- package/dist/v9.d.cts +18 -0
- package/dist/v9.d.ts +18 -0
- package/dist/v9.mjs +517 -0
- package/dist/v9.mjs.map +1 -0
- package/package.json +104 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
CalendarView: () => CalendarView,
|
|
34
|
+
GROUP_PALETTE: () => GROUP_PALETTE,
|
|
35
|
+
addDays: () => addDays,
|
|
36
|
+
browserZone: () => browserZone,
|
|
37
|
+
contrastRatio: () => contrastRatio,
|
|
38
|
+
fixedZone: () => fixedZone,
|
|
39
|
+
fromWall: () => fromWall,
|
|
40
|
+
groupColor: () => groupColor,
|
|
41
|
+
kindOf: () => kindOf,
|
|
42
|
+
normaliseFloating: () => normaliseFloating,
|
|
43
|
+
parseHex: () => parseHex,
|
|
44
|
+
readableTextOn: () => readableTextOn,
|
|
45
|
+
themeStyle: () => themeStyle,
|
|
46
|
+
toDate: () => toDate,
|
|
47
|
+
toInstant: () => toInstant,
|
|
48
|
+
toWall: () => toWall,
|
|
49
|
+
utcFieldsToWall: () => utcFieldsToWall
|
|
50
|
+
});
|
|
51
|
+
module.exports = __toCommonJS(src_exports);
|
|
52
|
+
|
|
53
|
+
// src/view/CalendarView.tsx
|
|
54
|
+
var React2 = __toESM(require("react"), 1);
|
|
55
|
+
var import_react = __toESM(require("@fullcalendar/react"), 1);
|
|
56
|
+
var import_daygrid = __toESM(require("@fullcalendar/react/daygrid"), 1);
|
|
57
|
+
var import_timegrid = __toESM(require("@fullcalendar/react/timegrid"), 1);
|
|
58
|
+
var import_list = __toESM(require("@fullcalendar/react/list"), 1);
|
|
59
|
+
var import_interaction = __toESM(require("@fullcalendar/react/interaction"), 1);
|
|
60
|
+
var import_classic = __toESM(require("@fullcalendar/react/themes/classic"), 1);
|
|
61
|
+
var import_skeleton = require("@fullcalendar/react/skeleton.css");
|
|
62
|
+
var import_theme = require("@fullcalendar/react/themes/classic/theme.css");
|
|
63
|
+
var import_palette = require("@fullcalendar/react/themes/classic/palette.css");
|
|
64
|
+
|
|
65
|
+
// src/core/datetime.ts
|
|
66
|
+
var DATE_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
67
|
+
var FLOATING_RE = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d{1,9})?)?$/;
|
|
68
|
+
var INSTANT_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})$/i;
|
|
69
|
+
var pad = (n, w = 2) => String(n).padStart(w, "0");
|
|
70
|
+
var browserZone = (instant) => -instant.getTimezoneOffset();
|
|
71
|
+
var fixedZone = (minutesEast) => () => minutesEast;
|
|
72
|
+
function kindOf(value) {
|
|
73
|
+
if (value instanceof Date) {
|
|
74
|
+
if (Number.isNaN(value.getTime())) throw new RangeError("Invalid Date");
|
|
75
|
+
return "instant";
|
|
76
|
+
}
|
|
77
|
+
const local = DATE_RE.test(value) ? "date" : FLOATING_RE.test(value) ? "floating" : null;
|
|
78
|
+
if (local) {
|
|
79
|
+
const m = FLOATING_RE.exec(value) ?? DATE_RE.exec(value);
|
|
80
|
+
const [, y, mo, d, h = "0", mi = "0", sec = "0"] = m;
|
|
81
|
+
const t = new Date(Date.UTC(+y, +mo - 1, +d, +h, +mi, +sec));
|
|
82
|
+
if (t.getUTCFullYear() !== +y || t.getUTCMonth() !== +mo - 1 || t.getUTCDate() !== +d || +h > 23 || +mi > 59 || +sec > 59) {
|
|
83
|
+
throw new RangeError(`Not a real calendar date or time: ${JSON.stringify(value)}`);
|
|
84
|
+
}
|
|
85
|
+
return local;
|
|
86
|
+
}
|
|
87
|
+
if (INSTANT_RE.test(value) && !Number.isNaN(new Date(value).getTime())) return "instant";
|
|
88
|
+
throw new RangeError(`Not an ISO-8601 date, wall-clock time or instant: ${JSON.stringify(value)}`);
|
|
89
|
+
}
|
|
90
|
+
function toInstant(value) {
|
|
91
|
+
if (value instanceof Date) return value.toISOString();
|
|
92
|
+
if (kindOf(value) !== "instant") throw new RangeError(`Not an instant: ${value}`);
|
|
93
|
+
return new Date(value).toISOString();
|
|
94
|
+
}
|
|
95
|
+
function wallMillis(wall) {
|
|
96
|
+
const m = FLOATING_RE.exec(wall) ?? DATE_RE.exec(wall);
|
|
97
|
+
if (!m) throw new RangeError(`Not a date or wall-clock time: ${wall}`);
|
|
98
|
+
const [, y, mo, d, h = "0", mi = "0", s = "0"] = m;
|
|
99
|
+
return Date.UTC(+y, +mo - 1, +d, +h, +mi, +s);
|
|
100
|
+
}
|
|
101
|
+
function formatWall(ms) {
|
|
102
|
+
const d = new Date(ms);
|
|
103
|
+
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}T${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}`;
|
|
104
|
+
}
|
|
105
|
+
function toWall(instant, zone) {
|
|
106
|
+
const at = instant instanceof Date ? instant : new Date(toInstant(instant));
|
|
107
|
+
return formatWall(at.getTime() + zone(at) * 6e4);
|
|
108
|
+
}
|
|
109
|
+
function fromWall(wall, zone) {
|
|
110
|
+
const w = wallMillis(wall);
|
|
111
|
+
const before = zone(new Date(w - 864e5));
|
|
112
|
+
const after = zone(new Date(w + 864e5));
|
|
113
|
+
const fits = (offset) => {
|
|
114
|
+
const t2 = w - offset * 6e4;
|
|
115
|
+
return zone(new Date(t2)) === offset ? t2 : null;
|
|
116
|
+
};
|
|
117
|
+
const candidates = [fits(before), fits(after)].filter((t2) => t2 !== null);
|
|
118
|
+
const t = candidates.length > 0 ? Math.min(...candidates) : w - before * 6e4;
|
|
119
|
+
return new Date(t).toISOString();
|
|
120
|
+
}
|
|
121
|
+
function toDate(value, zone) {
|
|
122
|
+
const k = kindOf(value);
|
|
123
|
+
if (k === "date") return value;
|
|
124
|
+
if (k === "floating") return value.slice(0, 10);
|
|
125
|
+
return toWall(value, zone).slice(0, 10);
|
|
126
|
+
}
|
|
127
|
+
function addDays(date, days) {
|
|
128
|
+
if (kindOf(date) !== "date") throw new RangeError(`addDays needs a date, got ${date}`);
|
|
129
|
+
return formatWall(wallMillis(date) + days * 864e5).slice(0, 10);
|
|
130
|
+
}
|
|
131
|
+
function utcFieldsToWall(d) {
|
|
132
|
+
return formatWall(d.getTime());
|
|
133
|
+
}
|
|
134
|
+
function normaliseFloating(value) {
|
|
135
|
+
return formatWall(wallMillis(value));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/core/colors.ts
|
|
139
|
+
var GROUP_PALETTE = [
|
|
140
|
+
"#0f6cbd",
|
|
141
|
+
// blue
|
|
142
|
+
"#107c10",
|
|
143
|
+
// green
|
|
144
|
+
"#c50f1f",
|
|
145
|
+
// red
|
|
146
|
+
"#8764b8",
|
|
147
|
+
// lavender
|
|
148
|
+
"#ae4b00",
|
|
149
|
+
// dark orange
|
|
150
|
+
"#03787c",
|
|
151
|
+
// teal
|
|
152
|
+
"#4f52b2",
|
|
153
|
+
// indigo
|
|
154
|
+
"#8a5b00",
|
|
155
|
+
// dark gold
|
|
156
|
+
"#c0077d",
|
|
157
|
+
// magenta
|
|
158
|
+
"#5c2e91"
|
|
159
|
+
// purple
|
|
160
|
+
];
|
|
161
|
+
function hash(key) {
|
|
162
|
+
let h = 2166136261;
|
|
163
|
+
for (let i = 0; i < key.length; i++) {
|
|
164
|
+
h ^= key.charCodeAt(i);
|
|
165
|
+
h = Math.imul(h, 16777619);
|
|
166
|
+
}
|
|
167
|
+
return h >>> 0;
|
|
168
|
+
}
|
|
169
|
+
function groupColor(key, palette = GROUP_PALETTE) {
|
|
170
|
+
return palette[hash(key) % palette.length];
|
|
171
|
+
}
|
|
172
|
+
function parseHex(color) {
|
|
173
|
+
const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color.trim());
|
|
174
|
+
if (!m) return null;
|
|
175
|
+
const h = m[1].length === 3 ? m[1].replace(/./g, (c) => c + c) : m[1];
|
|
176
|
+
return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
|
|
177
|
+
}
|
|
178
|
+
function luminance([r, g, b]) {
|
|
179
|
+
const lin = (c) => {
|
|
180
|
+
const s = c / 255;
|
|
181
|
+
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
182
|
+
};
|
|
183
|
+
return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
|
|
184
|
+
}
|
|
185
|
+
function contrastRatio(a, b) {
|
|
186
|
+
const pa = parseHex(a);
|
|
187
|
+
const pb = parseHex(b);
|
|
188
|
+
if (!pa || !pb) return null;
|
|
189
|
+
const [hi, lo] = [luminance(pa), luminance(pb)].sort((x, y) => y - x);
|
|
190
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
191
|
+
}
|
|
192
|
+
function readableTextOn(background) {
|
|
193
|
+
const onWhite = contrastRatio(background, "#ffffff");
|
|
194
|
+
const onBlack = contrastRatio(background, "#000000");
|
|
195
|
+
if (onWhite === null || onBlack === null) return void 0;
|
|
196
|
+
return onWhite >= onBlack ? "#ffffff" : "#000000";
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/view/fcBridge.ts
|
|
200
|
+
function toFcValue(value, zone) {
|
|
201
|
+
const k = kindOf(value);
|
|
202
|
+
if (k === "instant") return toWall(value, zone);
|
|
203
|
+
if (k === "floating") return normaliseFloating(value);
|
|
204
|
+
return value;
|
|
205
|
+
}
|
|
206
|
+
function exclusiveAllDayEnd(end, zone) {
|
|
207
|
+
const wall = toFcValue(end, zone);
|
|
208
|
+
if (wall.length === 10) return wall;
|
|
209
|
+
return wall.slice(11, 19) === "00:00:00" ? wall.slice(0, 10) : addDays(wall.slice(0, 10), 1);
|
|
210
|
+
}
|
|
211
|
+
function toFcEvent(event, zone) {
|
|
212
|
+
const originalKind = kindOf(event.start);
|
|
213
|
+
const allDay = event.allDay ?? originalKind === "date";
|
|
214
|
+
const start = allDay ? toFcValue(event.start, zone).slice(0, 10) : toFcValue(event.start, zone);
|
|
215
|
+
const out = {
|
|
216
|
+
id: event.id,
|
|
217
|
+
title: event.title,
|
|
218
|
+
start,
|
|
219
|
+
allDay,
|
|
220
|
+
extendedProps: { source: event, kind: allDay ? "date" : originalKind, originalKind }
|
|
221
|
+
};
|
|
222
|
+
if (event.end !== void 0) out.end = allDay ? exclusiveAllDayEnd(event.end, zone) : toFcValue(event.end, zone);
|
|
223
|
+
if (event.color) {
|
|
224
|
+
out.color = event.color;
|
|
225
|
+
const text = readableTextOn(event.color);
|
|
226
|
+
if (text) out.textColor = text;
|
|
227
|
+
}
|
|
228
|
+
if (event.readOnly) out.editable = false;
|
|
229
|
+
else if (event.end === void 0) out.durationEditable = false;
|
|
230
|
+
return out;
|
|
231
|
+
}
|
|
232
|
+
function fromFcDate(d, kind, zone) {
|
|
233
|
+
const wall = utcFieldsToWall(d);
|
|
234
|
+
if (kind === "date") return wall.slice(0, 10);
|
|
235
|
+
if (kind === "floating") return wall;
|
|
236
|
+
return fromWall(wall, zone);
|
|
237
|
+
}
|
|
238
|
+
function asKind(value, from, target, zone) {
|
|
239
|
+
if (from === target || from !== "date") return value;
|
|
240
|
+
return target === "instant" ? fromWall(`${value}T00:00:00`, zone) : `${value}T00:00:00`;
|
|
241
|
+
}
|
|
242
|
+
function canonical(value) {
|
|
243
|
+
const k = kindOf(value);
|
|
244
|
+
return k === "instant" ? toInstant(value) : k === "floating" ? normaliseFloating(value) : value;
|
|
245
|
+
}
|
|
246
|
+
function toChange(fcEvent, kind, zone) {
|
|
247
|
+
const { source, kind: valueKind, originalKind } = fcEvent.extendedProps;
|
|
248
|
+
if (!fcEvent.start) throw new Error(`FullCalendar returned no start for event ${source.id}`);
|
|
249
|
+
const back = (d) => asKind(fromFcDate(d, valueKind, zone), valueKind, originalKind ?? valueKind, zone);
|
|
250
|
+
return {
|
|
251
|
+
event: source,
|
|
252
|
+
kind,
|
|
253
|
+
// ★ A RESIZE never moves the start. Recomputing it from FullCalendar's wall-clock Date is
|
|
254
|
+
// lossy on the fall-back day (the second 01:30 reads back as the first), and toWebApiPatch
|
|
255
|
+
// writes `start` unconditionally — so resizing an end silently moved the start an hour.
|
|
256
|
+
start: kind === "resize" ? canonical(source.start) : back(fcEvent.start),
|
|
257
|
+
end: fcEvent.end ? back(fcEvent.end) : void 0,
|
|
258
|
+
allDay: fcEvent.allDay
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function toSelection(start, end, allDay, zone) {
|
|
262
|
+
const kind = allDay ? "date" : "instant";
|
|
263
|
+
return { start: fromFcDate(start, kind, zone), end: fromFcDate(end, kind, zone), allDay };
|
|
264
|
+
}
|
|
265
|
+
function toVisibleRange(start, end, view, zone) {
|
|
266
|
+
return {
|
|
267
|
+
start: fromFcDate(start, "instant", zone),
|
|
268
|
+
end: fromFcDate(end, "instant", zone),
|
|
269
|
+
view,
|
|
270
|
+
startDate: utcFieldsToWall(start).slice(0, 10),
|
|
271
|
+
endDate: utcFieldsToWall(end).slice(0, 10)
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
var nowWall = (zone) => toWall(/* @__PURE__ */ new Date(), zone);
|
|
275
|
+
var sameAllDayness = (spanAllDay, eventAllDay) => spanAllDay === eventAllDay;
|
|
276
|
+
var same = (a, b) => {
|
|
277
|
+
if (a === void 0 || b === void 0) return a === b;
|
|
278
|
+
const ka = kindOf(a);
|
|
279
|
+
if (ka !== kindOf(b)) return false;
|
|
280
|
+
if (ka === "instant") return new Date(a).getTime() === new Date(b).getTime();
|
|
281
|
+
return ka === "floating" ? normaliseFloating(a) === normaliseFloating(b) : a === b;
|
|
282
|
+
};
|
|
283
|
+
function applyPending(events, pending) {
|
|
284
|
+
if (pending.size === 0) return events;
|
|
285
|
+
return events.map((e) => {
|
|
286
|
+
const p = pending.get(e.id);
|
|
287
|
+
return p ? { ...e, start: p.start, end: p.end, allDay: p.allDay } : e;
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
function settledIds(events, pending) {
|
|
291
|
+
const byId = new Map(events.map((e) => [e.id, e]));
|
|
292
|
+
const done = [];
|
|
293
|
+
for (const [id, p] of pending) {
|
|
294
|
+
const e = byId.get(id);
|
|
295
|
+
if (!e || same(e.start, p.start) && same(e.end, p.end) || p.savedWith !== void 0 && p.savedWith !== events) done.push(id);
|
|
296
|
+
}
|
|
297
|
+
return done;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/view/useOptimisticChanges.ts
|
|
301
|
+
var React = __toESM(require("react"), 1);
|
|
302
|
+
function describe(error) {
|
|
303
|
+
const m = error?.message;
|
|
304
|
+
return typeof m === "string" && m ? m : String(error);
|
|
305
|
+
}
|
|
306
|
+
function useOptimisticChanges(events, onEventChange, onChangeError, zoneRef) {
|
|
307
|
+
const [pending, setPending] = React.useState(() => /* @__PURE__ */ new Map());
|
|
308
|
+
const [error, setError] = React.useState(null);
|
|
309
|
+
const eventsRef = React.useRef(events);
|
|
310
|
+
eventsRef.current = events;
|
|
311
|
+
const latest = React.useRef(/* @__PURE__ */ new Map());
|
|
312
|
+
const seq = React.useRef(0);
|
|
313
|
+
const mounted = React.useRef(true);
|
|
314
|
+
React.useEffect(() => {
|
|
315
|
+
mounted.current = true;
|
|
316
|
+
return () => {
|
|
317
|
+
mounted.current = false;
|
|
318
|
+
};
|
|
319
|
+
}, []);
|
|
320
|
+
React.useEffect(() => {
|
|
321
|
+
const done = settledIds(events, pending);
|
|
322
|
+
if (done.length === 0) return;
|
|
323
|
+
for (const id of done) if (latest.current.get(id) === pending.get(id)?.token) latest.current.delete(id);
|
|
324
|
+
setPending((prev) => {
|
|
325
|
+
const next = new Map(prev);
|
|
326
|
+
for (const id of done) next.delete(id);
|
|
327
|
+
return next;
|
|
328
|
+
});
|
|
329
|
+
}, [events, pending]);
|
|
330
|
+
const handleChange = React.useCallback(
|
|
331
|
+
(kind) => (info) => {
|
|
332
|
+
if (!onEventChange) {
|
|
333
|
+
info.revert();
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
let change;
|
|
337
|
+
try {
|
|
338
|
+
change = toChange(info.event, kind, zoneRef.current);
|
|
339
|
+
} catch (e) {
|
|
340
|
+
info.revert();
|
|
341
|
+
setError(describe(e));
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
setError(null);
|
|
345
|
+
const id = change.event.id;
|
|
346
|
+
const token = ++seq.current;
|
|
347
|
+
const fail = (err) => {
|
|
348
|
+
const current = latest.current.get(id) === token;
|
|
349
|
+
if (current) latest.current.delete(id);
|
|
350
|
+
onChangeError?.(err, change);
|
|
351
|
+
if (!mounted.current) return;
|
|
352
|
+
setError(`Could not save "${change.event.title}": ${describe(err)}`);
|
|
353
|
+
if (!current) return;
|
|
354
|
+
setPending((prev) => {
|
|
355
|
+
if (!prev.has(id)) return prev;
|
|
356
|
+
const next = new Map(prev);
|
|
357
|
+
next.delete(id);
|
|
358
|
+
return next;
|
|
359
|
+
});
|
|
360
|
+
try {
|
|
361
|
+
info.revert();
|
|
362
|
+
} catch {
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
latest.current.set(id, token);
|
|
366
|
+
let result;
|
|
367
|
+
try {
|
|
368
|
+
result = onEventChange(change);
|
|
369
|
+
} catch (err) {
|
|
370
|
+
fail(err);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (!result || typeof result.then !== "function") {
|
|
374
|
+
if (latest.current.get(id) === token) latest.current.delete(id);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
setPending((prev) => new Map(prev).set(id, { start: change.start, end: change.end, allDay: change.allDay, token }));
|
|
378
|
+
result.then(
|
|
379
|
+
() => {
|
|
380
|
+
if (!mounted.current || latest.current.get(id) !== token) return;
|
|
381
|
+
const savedWith = eventsRef.current;
|
|
382
|
+
setPending((prev) => {
|
|
383
|
+
const p = prev.get(id);
|
|
384
|
+
if (!p || p.token !== token) return prev;
|
|
385
|
+
return new Map(prev).set(id, { ...p, savedWith });
|
|
386
|
+
});
|
|
387
|
+
},
|
|
388
|
+
fail
|
|
389
|
+
);
|
|
390
|
+
},
|
|
391
|
+
[onEventChange, onChangeError, zoneRef]
|
|
392
|
+
);
|
|
393
|
+
return { pending, error, dismissError: React.useCallback(() => setError(null), []), handleChange };
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/view/theme.ts
|
|
397
|
+
var VAR = {
|
|
398
|
+
primary: "--fc-classic-primary",
|
|
399
|
+
primaryForeground: "--fc-classic-primary-foreground",
|
|
400
|
+
background: "--fc-classic-background",
|
|
401
|
+
foreground: "--fc-classic-foreground",
|
|
402
|
+
mutedForeground: "--fc-classic-muted-foreground",
|
|
403
|
+
faint: "--fc-classic-faint",
|
|
404
|
+
muted: "--fc-classic-muted",
|
|
405
|
+
strong: "--fc-classic-strong",
|
|
406
|
+
border: "--fc-classic-border",
|
|
407
|
+
strongBorder: "--fc-classic-strong-border",
|
|
408
|
+
today: "--fc-classic-today",
|
|
409
|
+
highlight: "--fc-classic-highlight",
|
|
410
|
+
now: "--fc-classic-now",
|
|
411
|
+
button: "--fc-classic-button",
|
|
412
|
+
buttonForeground: "--fc-classic-button-foreground",
|
|
413
|
+
buttonBorder: "--fc-classic-button-border",
|
|
414
|
+
buttonStrong: "--fc-classic-button-strong",
|
|
415
|
+
buttonStrongBorder: "--fc-classic-button-strong-border"
|
|
416
|
+
};
|
|
417
|
+
function themeStyle(theme) {
|
|
418
|
+
const style = {};
|
|
419
|
+
if (!theme) return style;
|
|
420
|
+
for (const [key, cssVar] of Object.entries(VAR)) {
|
|
421
|
+
const v = theme[key];
|
|
422
|
+
if (v) style[cssVar] = v;
|
|
423
|
+
}
|
|
424
|
+
if (theme.fontFamily) style.fontFamily = theme.fontFamily;
|
|
425
|
+
if (theme.fontSize) style.fontSize = theme.fontSize;
|
|
426
|
+
if (theme.background) style.background = theme.background;
|
|
427
|
+
if (theme.foreground) style.color = theme.foreground;
|
|
428
|
+
return style;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// src/view/CalendarView.tsx
|
|
432
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
433
|
+
var FC_VIEW = {
|
|
434
|
+
month: "dayGridMonth",
|
|
435
|
+
week: "timeGridWeek",
|
|
436
|
+
workWeek: "timeGridWorkWeek",
|
|
437
|
+
day: "timeGridDay",
|
|
438
|
+
list: "listWeek"
|
|
439
|
+
};
|
|
440
|
+
var VIEW_LABEL = {
|
|
441
|
+
month: "Month",
|
|
442
|
+
week: "Week",
|
|
443
|
+
workWeek: "Work week",
|
|
444
|
+
day: "Day",
|
|
445
|
+
list: "List"
|
|
446
|
+
};
|
|
447
|
+
var asChangeInfo = (info) => ({
|
|
448
|
+
event: {
|
|
449
|
+
start: info.event.start,
|
|
450
|
+
end: info.event.end,
|
|
451
|
+
allDay: info.event.allDay,
|
|
452
|
+
extendedProps: info.event.extendedProps
|
|
453
|
+
},
|
|
454
|
+
revert: () => info.revert()
|
|
455
|
+
});
|
|
456
|
+
var bannerStyle = {
|
|
457
|
+
display: "flex",
|
|
458
|
+
alignItems: "center",
|
|
459
|
+
gap: 8,
|
|
460
|
+
padding: "6px 10px",
|
|
461
|
+
marginBottom: 6,
|
|
462
|
+
borderRadius: 4,
|
|
463
|
+
border: "1px solid currentColor"
|
|
464
|
+
};
|
|
465
|
+
function CalendarView(props) {
|
|
466
|
+
const zone = props.zone ?? browserZone;
|
|
467
|
+
const zoneRef = React2.useRef(zone);
|
|
468
|
+
zoneRef.current = zone;
|
|
469
|
+
const { pending, error, dismissError, handleChange } = useOptimisticChanges(
|
|
470
|
+
props.events,
|
|
471
|
+
props.onEventChange,
|
|
472
|
+
props.onChangeError,
|
|
473
|
+
zoneRef
|
|
474
|
+
);
|
|
475
|
+
const fcEvents = React2.useMemo(
|
|
476
|
+
() => applyPending(props.events, pending).map((e) => toFcEvent(e, zone)),
|
|
477
|
+
[props.events, pending, zone]
|
|
478
|
+
);
|
|
479
|
+
const views = props.views ?? ["month", "week", "day", "list"];
|
|
480
|
+
const optional = {};
|
|
481
|
+
if (props.firstDay !== void 0) optional.firstDay = props.firstDay;
|
|
482
|
+
if (props.slotMinTime !== void 0) optional.slotMinTime = props.slotMinTime;
|
|
483
|
+
if (props.slotMaxTime !== void 0) optional.slotMaxTime = props.slotMaxTime;
|
|
484
|
+
if (props.initialDate !== void 0) optional.initialDate = props.initialDate;
|
|
485
|
+
if (props.classNames?.button) optional.buttonClass = props.classNames.button;
|
|
486
|
+
if (props.classNames?.toolbar) optional.headerToolbarClass = props.classNames.toolbar;
|
|
487
|
+
if (props.businessHours) optional.businessHours = props.businessHours.map((b) => ({ ...b, daysOfWeek: [...b.daysOfWeek] }));
|
|
488
|
+
const selectable = props.selectable ?? !!props.onSelectRange;
|
|
489
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
490
|
+
"div",
|
|
491
|
+
{
|
|
492
|
+
className: props.className,
|
|
493
|
+
style: themeStyle(props.theme),
|
|
494
|
+
role: "region",
|
|
495
|
+
"aria-label": props["aria-label"] ?? "Calendar",
|
|
496
|
+
"aria-busy": props.loading || void 0,
|
|
497
|
+
"data-calendar-kit": "",
|
|
498
|
+
children: [
|
|
499
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { role: "alert", style: { ...bannerStyle, color: props.theme?.error ?? "#a4262c" }, children: [
|
|
500
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1 }, children: error }),
|
|
501
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: dismissError, "aria-label": "Dismiss", style: { font: "inherit" }, children: "\xD7" })
|
|
502
|
+
] }),
|
|
503
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
504
|
+
import_react.default,
|
|
505
|
+
{
|
|
506
|
+
plugins: [import_daygrid.default, import_timegrid.default, import_list.default, import_interaction.default, import_classic.default],
|
|
507
|
+
timeZone: "UTC",
|
|
508
|
+
now: () => nowWall(zoneRef.current),
|
|
509
|
+
initialView: FC_VIEW[props.view ?? "week"],
|
|
510
|
+
views: { timeGridWorkWeek: { type: "timeGridWeek", hiddenDays: [0, 6] } },
|
|
511
|
+
headerToolbar: {
|
|
512
|
+
start: "today prev,next",
|
|
513
|
+
center: "title",
|
|
514
|
+
end: views.map((v) => FC_VIEW[v]).join(",")
|
|
515
|
+
},
|
|
516
|
+
buttons: {
|
|
517
|
+
today: { text: "Today" },
|
|
518
|
+
...Object.fromEntries(views.map((v) => [FC_VIEW[v], { text: VIEW_LABEL[v] }]))
|
|
519
|
+
},
|
|
520
|
+
height: props.height ?? "auto",
|
|
521
|
+
events: fcEvents,
|
|
522
|
+
editable: !!props.editable && !!props.onEventChange,
|
|
523
|
+
selectable,
|
|
524
|
+
selectMirror: true,
|
|
525
|
+
nowIndicator: true,
|
|
526
|
+
dayMaxEvents: true,
|
|
527
|
+
...optional,
|
|
528
|
+
scrollTime: props.scrollTime ?? "08:00:00",
|
|
529
|
+
eventAllow: (span, moving) => moving ? sameAllDayness(span.allDay, moving.allDay) : true,
|
|
530
|
+
datesSet: (info) => props.onRangeChange?.(toVisibleRange(info.start, info.end, info.view.type, zoneRef.current)),
|
|
531
|
+
eventClick: (info) => {
|
|
532
|
+
info.jsEvent.preventDefault();
|
|
533
|
+
const source = info.event.extendedProps.source;
|
|
534
|
+
if (source) props.onEventClick?.(source);
|
|
535
|
+
},
|
|
536
|
+
select: (info) => {
|
|
537
|
+
props.onSelectRange?.(toSelection(info.start, info.end, info.allDay, zoneRef.current));
|
|
538
|
+
info.view.calendar.unselect();
|
|
539
|
+
},
|
|
540
|
+
eventDrop: (info) => handleChange("move")(asChangeInfo(info)),
|
|
541
|
+
eventResize: (info) => handleChange("resize")(asChangeInfo(info))
|
|
542
|
+
}
|
|
543
|
+
)
|
|
544
|
+
]
|
|
545
|
+
}
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
549
|
+
0 && (module.exports = {
|
|
550
|
+
CalendarView,
|
|
551
|
+
GROUP_PALETTE,
|
|
552
|
+
addDays,
|
|
553
|
+
browserZone,
|
|
554
|
+
contrastRatio,
|
|
555
|
+
fixedZone,
|
|
556
|
+
fromWall,
|
|
557
|
+
groupColor,
|
|
558
|
+
kindOf,
|
|
559
|
+
normaliseFloating,
|
|
560
|
+
parseHex,
|
|
561
|
+
readableTextOn,
|
|
562
|
+
themeStyle,
|
|
563
|
+
toDate,
|
|
564
|
+
toInstant,
|
|
565
|
+
toWall,
|
|
566
|
+
utcFieldsToWall
|
|
567
|
+
});
|
|
568
|
+
//# sourceMappingURL=index.cjs.map
|