hs-uix 2.1.0 → 2.2.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.
Files changed (49) hide show
  1. package/README.md +3 -1
  2. package/common-components.d.ts +319 -68
  3. package/dist/calendar.js +397 -119
  4. package/dist/calendar.mjs +399 -119
  5. package/dist/common-components.js +3546 -88
  6. package/dist/common-components.mjs +3530 -84
  7. package/dist/datatable.js +108 -18
  8. package/dist/datatable.mjs +108 -18
  9. package/dist/experimental.js +2876 -0
  10. package/dist/experimental.mjs +2883 -0
  11. package/dist/feed.js +267 -38
  12. package/dist/feed.mjs +260 -37
  13. package/dist/filter.js +1379 -0
  14. package/dist/filter.mjs +1334 -0
  15. package/dist/form.js +222 -26
  16. package/dist/form.mjs +227 -27
  17. package/dist/index.js +3255 -353
  18. package/dist/index.mjs +3199 -344
  19. package/dist/kanban.js +282 -62
  20. package/dist/kanban.mjs +273 -61
  21. package/dist/safe.js +9207 -0
  22. package/dist/safe.mjs +9298 -0
  23. package/dist/utils.js +491 -75
  24. package/dist/utils.mjs +491 -75
  25. package/experimental.d.ts +1 -0
  26. package/filter.d.ts +1 -0
  27. package/index.d.ts +45 -3
  28. package/package.json +19 -1
  29. package/safe.d.ts +1 -0
  30. package/src/calendar/README.md +76 -5
  31. package/src/calendar/index.d.ts +108 -1
  32. package/src/common-components/README.md +140 -1
  33. package/src/datatable/README.md +0 -2
  34. package/src/experimental/README.md +126 -0
  35. package/src/experimental/index.d.ts +346 -0
  36. package/src/feed/README.md +69 -0
  37. package/src/feed/index.d.ts +103 -0
  38. package/src/filter/README.md +148 -0
  39. package/src/filter/index.d.ts +221 -0
  40. package/src/form/README.md +132 -4
  41. package/src/form/index.d.ts +82 -1
  42. package/src/kanban/README.md +119 -6
  43. package/src/kanban/index.d.ts +153 -2
  44. package/src/safe/README.md +108 -0
  45. package/src/safe/index.d.ts +158 -0
  46. package/src/utils/README.md +39 -0
  47. package/src/wizard/README.md +158 -0
  48. package/src/wizard/index.d.ts +138 -0
  49. package/utils.d.ts +17 -0
package/dist/calendar.mjs CHANGED
@@ -2,8 +2,10 @@
2
2
  import React5, { useCallback, useEffect, useMemo, useState as useState2 } from "react";
3
3
  import {
4
4
  Alert,
5
+ AutoGrid,
5
6
  Box as Box2,
6
7
  Button as Button3,
8
+ DateInput as DateInput2,
7
9
  Divider,
8
10
  EmptyState,
9
11
  Flex as Flex4,
@@ -91,7 +93,6 @@ import React2 from "react";
91
93
  import { Image, Icon as HsIcon, Link } from "@hubspot/ui-extensions";
92
94
 
93
95
  // src/common-components/svgDefaults.js
94
- var HS_FONT_FAMILY = '"Lexend Deca", Helvetica, Arial, sans-serif';
95
96
  var HS_TEXT_COLOR = "#33475b";
96
97
 
97
98
  // src/common-components/icons.generated.js
@@ -346,7 +347,7 @@ var GENERATED_ICONS = {
346
347
  "ZoomOut": { "viewBox": "0 0 32 32", "paths": ["M14.42 26.75c2.85 0 5.47-.97 7.56-2.6l-.03.02 5.28 5.34a1.619 1.619 0 0 0 2.76-1.15c0-.45-.18-.85-.47-1.14l-5.33-5.33c1.59-2.06 2.55-4.68 2.55-7.52C26.74 7.54 21.2 2 14.37 2S2 7.55 2 14.38s5.54 12.37 12.37 12.37h.05m0-21.55c5.06 0 9.16 4.1 9.16 9.16s-4.1 9.16-9.16 9.16-9.16-4.1-9.16-9.16c.01-5.05 4.11-9.14 9.16-9.15Zm-4.31 10.78h8.62c.89 0 1.62-.72 1.62-1.62s-.72-1.62-1.62-1.62h-8.62c-.89 0-1.62.72-1.62 1.62s.72 1.62 1.62 1.62"] }
347
348
  };
348
349
 
349
- // src/common-components/Icon.js
350
+ // src/common-components/nativeIconNames.js
350
351
  var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
351
352
  "add",
352
353
  "appointment",
@@ -358,12 +359,12 @@ var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
358
359
  "block",
359
360
  "book",
360
361
  "bulb",
362
+ "callTranscript",
361
363
  "calling",
362
364
  "callingHangup",
363
365
  "callingMade",
364
366
  "callingMissed",
365
367
  "callingVoicemail",
366
- "callTranscript",
367
368
  "campaigns",
368
369
  "cap",
369
370
  "checkCircle",
@@ -392,13 +393,13 @@ var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
392
393
  "enroll",
393
394
  "exclamation",
394
395
  "exclamationCircle",
395
- "facebook",
396
396
  "faceHappy",
397
397
  "faceHappyFilled",
398
398
  "faceNeutral",
399
399
  "faceNeutralFilled",
400
400
  "faceSad",
401
401
  "faceSadFilled",
402
+ "facebook",
402
403
  "favoriteHollow",
403
404
  "file",
404
405
  "filledXCircleIcon",
@@ -539,6 +540,8 @@ var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
539
540
  "zoomIn",
540
541
  "zoomOut"
541
542
  ]);
543
+
544
+ // src/common-components/Icon.js
542
545
  var NATIVE_COLORS = /* @__PURE__ */ new Set(["inherit", "alert", "warning", "success"]);
543
546
  var NATIVE_SIZE_TOKENS = {
544
547
  sm: "sm",
@@ -751,6 +754,7 @@ var CollectionFilterControl = ({
751
754
  { key: name, direction: "row", align: "center", gap: "xs" },
752
755
  h2(DateInput, {
753
756
  name: `${controlName}-from`,
757
+ label: filter.fromLabel ?? labels.dateFrom,
754
758
  placeholder: filter.fromLabel ?? labels.dateFrom,
755
759
  format: "medium",
756
760
  value: rangeValue.from ?? null,
@@ -759,6 +763,7 @@ var CollectionFilterControl = ({
759
763
  h2(Icon, { name: "right", size: "sm" }),
760
764
  h2(DateInput, {
761
765
  name: `${controlName}-to`,
766
+ label: filter.toLabel ?? labels.dateTo,
762
767
  placeholder: filter.toLabel ?? labels.dateTo,
763
768
  format: "medium",
764
769
  value: rangeValue.to ?? null,
@@ -1213,21 +1218,6 @@ var formatTimeZoneLabel = (tz, atDate = /* @__PURE__ */ new Date()) => {
1213
1218
 
1214
1219
  // src/calendar/svgChips.js
1215
1220
  var toDataUri = (svg) => `data:image/svg+xml,${encodeURIComponent(svg)}`;
1216
- var escapeXml = (s) => String(s == null ? "" : s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1217
- var truncateLabel = (value, max) => {
1218
- const s = String(value == null ? "" : value);
1219
- if (!max || s.length <= max) return s;
1220
- return s.slice(0, Math.max(1, max - 1)).trimEnd() + "\u2026";
1221
- };
1222
- var CHIP_PALETTE = {
1223
- default: { fill: "#7FD1DE", text: HS_TEXT_COLOR },
1224
- info: { fill: "#00A4BD", text: "#FFFFFF" },
1225
- success: { fill: "#00BDA5", text: "#FFFFFF" },
1226
- warning: { fill: "#F5C26B", text: HS_TEXT_COLOR },
1227
- error: { fill: "#F2545B", text: "#FFFFFF" },
1228
- danger: { fill: "#F2545B", text: "#FFFFFF" }
1229
- // StatusTag spells red "danger"; accept both
1230
- };
1231
1221
  var DOT_FILL = {
1232
1222
  default: "#7C98B6",
1233
1223
  info: "#00A4BD",
@@ -1242,31 +1232,177 @@ var makeDotDataUri = (variant = "default", size = 8) => {
1242
1232
  const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><circle cx="${r}" cy="${r}" r="${r}" fill="${fill}" /></svg>`;
1243
1233
  return { src: toDataUri(svg), width: size, height: size };
1244
1234
  };
1245
- var makeEventChipDataUri = (opts) => {
1246
- const { label, width, height = 24, variant = "default" } = opts;
1247
- const palette = CHIP_PALETTE[variant] || CHIP_PALETTE.default;
1248
- const accentX = 5;
1249
- const accentW = 3;
1250
- const textX = accentX + accentW + 6;
1251
- const rightPad = 8;
1252
- const maxChars = Math.max(1, Math.floor((width - textX - rightPad) / 6));
1253
- const text = truncateLabel(label, maxChars);
1254
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><rect x="0.5" y="0.5" width="${width - 1}" height="${height - 1}" rx="4" ry="4" fill="#FFFFFF" stroke="#CBD6E2" stroke-width="1" /><rect x="${accentX}" y="5" width="${accentW}" height="${height - 10}" rx="1.5" ry="1.5" fill="${palette.fill}" /><text x="${textX}" y="${height / 2}" font-family='${HS_FONT_FAMILY}' font-size="12" font-weight="500" fill="${HS_TEXT_COLOR}" text-anchor="start" dominant-baseline="central">${escapeXml(text)}</text></svg>`;
1255
- return { src: toDataUri(svg), width, height };
1256
- };
1257
- var makeMoreDataUri = (opts) => {
1258
- const { label, width, height = 24 } = opts;
1259
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><text x="3" y="${height / 2}" font-family='${HS_FONT_FAMILY}' font-size="13" font-weight="700" fill="#0091AE" text-anchor="start" dominant-baseline="central">${escapeXml(label)}</text></svg>`;
1260
- return { src: toDataUri(svg), width, height };
1261
- };
1262
1235
  var makeSpacerDataUri = (height = 24, width = 4) => {
1263
1236
  const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><rect x="0" y="0" width="${width}" height="${height}" fill="#FFFFFF" fill-opacity="0" /></svg>`;
1264
1237
  return { src: toDataUri(svg), width, height };
1265
1238
  };
1266
1239
 
1240
+ // src/calendar/rescheduleUtils.js
1241
+ var shiftDate = (date, shift) => {
1242
+ const d = toDate(date);
1243
+ if (!d) return null;
1244
+ if (!shift || typeof shift !== "object") return new Date(d);
1245
+ const days = (shift.days || 0) + (shift.weeks || 0) * 7;
1246
+ let next = days ? addDays(d, days) : new Date(d);
1247
+ const ms = (shift.hours || 0) * 36e5 + (shift.minutes || 0) * 6e4;
1248
+ if (ms) next = new Date(next.getTime() + ms);
1249
+ return next;
1250
+ };
1251
+ var shiftEvent = (range, shift) => {
1252
+ const start = toDate(range && range.start);
1253
+ if (!start) return null;
1254
+ const end = toDate(range && range.end) || start;
1255
+ return { start: shiftDate(start, shift), end: shiftDate(end, shift) };
1256
+ };
1257
+ var calendarDayDelta = (a, b) => Math.round((startOfDay(b).getTime() - startOfDay(a).getTime()) / MS_PER_DAY);
1258
+ var msIntoDay = (d) => ((d.getHours() * 60 + d.getMinutes()) * 60 + d.getSeconds()) * 1e3 + d.getMilliseconds();
1259
+ var rescheduleToStart = (range, newStart) => {
1260
+ const start = toDate(range && range.start);
1261
+ const target = toDate(newStart);
1262
+ if (!start || !target) return null;
1263
+ const end = toDate(range && range.end) || start;
1264
+ const dayDelta = calendarDayDelta(start, target);
1265
+ const timeDelta = msIntoDay(target) - msIntoDay(start);
1266
+ const endOnDay = addDays(end, dayDelta);
1267
+ if (!timeDelta) return { start: target, end: endOnDay };
1268
+ return {
1269
+ start: target,
1270
+ end: new Date(
1271
+ endOnDay.getFullYear(),
1272
+ endOnDay.getMonth(),
1273
+ endOnDay.getDate(),
1274
+ 0,
1275
+ 0,
1276
+ 0,
1277
+ msIntoDay(endOnDay) + timeDelta
1278
+ )
1279
+ };
1280
+ };
1281
+ var applyDatePick = (start, value) => {
1282
+ if (!isDateValueObject(value)) return null;
1283
+ const s = toDate(start);
1284
+ return new Date(
1285
+ value.year,
1286
+ value.month,
1287
+ value.date,
1288
+ s ? s.getHours() : 0,
1289
+ s ? s.getMinutes() : 0,
1290
+ s ? s.getSeconds() : 0,
1291
+ s ? s.getMilliseconds() : 0
1292
+ );
1293
+ };
1294
+ var DEFAULT_RESCHEDULE_PRESETS = [
1295
+ { label: "+1 hour", shift: { hours: 1 } },
1296
+ { label: "+1 day", shift: { days: 1 } },
1297
+ { label: "Next week", shift: { weeks: 1 } }
1298
+ ];
1299
+ var normalizeRescheduleOptions = (options) => {
1300
+ if (!options) return [];
1301
+ if (options === true) return DEFAULT_RESCHEDULE_PRESETS;
1302
+ if (!Array.isArray(options)) return [];
1303
+ const out = [];
1304
+ for (const opt of options) {
1305
+ if (typeof opt === "function") {
1306
+ out.push({ label: opt.label || opt.name || "Reschedule", getStart: opt });
1307
+ } else if (opt && typeof opt === "object" && opt.label != null) {
1308
+ if (typeof opt.shift === "function") {
1309
+ out.push({ label: opt.label, getStart: opt.shift });
1310
+ } else if (typeof opt.getStart === "function") {
1311
+ out.push({ label: opt.label, getStart: opt.getStart });
1312
+ } else if (opt.shift && typeof opt.shift === "object") {
1313
+ out.push({ label: opt.label, shift: opt.shift });
1314
+ }
1315
+ }
1316
+ }
1317
+ return out;
1318
+ };
1319
+ var resolveRescheduleTarget = (range, option, fnArg) => {
1320
+ if (!range || !toDate(range.start) || !option) return null;
1321
+ if (typeof option.getStart === "function") {
1322
+ const next = toDate(option.getStart(fnArg !== void 0 ? fnArg : range));
1323
+ return next ? rescheduleToStart(range, next) : null;
1324
+ }
1325
+ if (option.shift && typeof option.shift === "object") {
1326
+ return shiftEvent(range, option.shift);
1327
+ }
1328
+ return null;
1329
+ };
1330
+
1331
+ // src/calendar/resourceLanes.js
1332
+ var resolveResourceId = (record, spec) => {
1333
+ if (record == null || spec == null) return null;
1334
+ const value = typeof spec === "function" ? spec(record) : record[spec];
1335
+ if (value == null || value === "") return null;
1336
+ return value;
1337
+ };
1338
+ var buildResourceLanes = (events, options = {}) => {
1339
+ const {
1340
+ resources,
1341
+ resourceLabels,
1342
+ getId,
1343
+ showUnassignedLane = true,
1344
+ unassignedLabel = "Unassigned"
1345
+ } = options;
1346
+ const labelFor = (id) => {
1347
+ if (resourceLabels && resourceLabels[id] != null) return resourceLabels[id];
1348
+ return String(id);
1349
+ };
1350
+ const lanes = [];
1351
+ const byKey = /* @__PURE__ */ new Map();
1352
+ const addLane = (id, label, declared) => {
1353
+ const key = String(id);
1354
+ if (byKey.has(key)) return byKey.get(key);
1355
+ const lane = { id, key, label, events: [], unassigned: false, declared };
1356
+ byKey.set(key, lane);
1357
+ lanes.push(lane);
1358
+ return lane;
1359
+ };
1360
+ (resources || []).forEach((resource) => {
1361
+ if (resource == null) return;
1362
+ if (typeof resource === "object") {
1363
+ addLane(resource.id, resource.label != null ? resource.label : labelFor(resource.id), true);
1364
+ } else {
1365
+ addLane(resource, labelFor(resource), true);
1366
+ }
1367
+ });
1368
+ const unassigned = {
1369
+ id: null,
1370
+ key: "__unassigned__",
1371
+ label: unassignedLabel,
1372
+ events: [],
1373
+ unassigned: true,
1374
+ declared: false
1375
+ };
1376
+ (events || []).forEach((event) => {
1377
+ const id = getId ? getId(event) : null;
1378
+ if (id == null || id === "") {
1379
+ unassigned.events.push(event);
1380
+ return;
1381
+ }
1382
+ const lane = byKey.get(String(id)) || addLane(id, labelFor(id), false);
1383
+ lane.events.push(event);
1384
+ });
1385
+ if (showUnassignedLane && unassigned.events.length > 0) lanes.push(unassigned);
1386
+ return lanes;
1387
+ };
1388
+ var eventsIntersectingRange = (events, rangeStart, rangeEnd) => {
1389
+ const rs = rangeStart.getTime();
1390
+ const re = rangeEnd.getTime();
1391
+ return (events || []).filter((event) => {
1392
+ if (!event || !event.start) return false;
1393
+ const es = event.start.getTime();
1394
+ const ee = (event.end || event.start).getTime();
1395
+ return es <= re && ee >= rs;
1396
+ });
1397
+ };
1398
+ var laneEventsForDay = (events, day) => eventsIntersectingRange(events, startOfDay(day), endOfDay(day)).sort(
1399
+ (a, b) => a.start.getTime() - b.start.getTime()
1400
+ );
1401
+
1267
1402
  // src/calendar/Calendar.jsx
1268
1403
  var DEFAULT_MAX_EVENTS_PER_DAY = 3;
1269
1404
  var ALL_VIEWS = ["month", "week", "day", "agenda"];
1405
+ var ALL_VIEWS_WITH_RESOURCE = ["month", "week", "day", "resource", "agenda"];
1270
1406
  var DEFAULT_DAY_START_HOUR = 8;
1271
1407
  var DEFAULT_DAY_END_HOUR = 20;
1272
1408
  var DEFAULT_TIME_ZONES = [
@@ -1302,7 +1438,8 @@ var VIEW_LABELS = {
1302
1438
  month: "Month",
1303
1439
  week: "Week",
1304
1440
  day: "Day",
1305
- agenda: "Agenda"
1441
+ agenda: "Agenda",
1442
+ resource: "Resource"
1306
1443
  };
1307
1444
  var DEFAULT_LABELS3 = {
1308
1445
  today: "Today",
@@ -1319,7 +1456,11 @@ var DEFAULT_LABELS3 = {
1319
1456
  errorMessage: "An error occurred while loading events.",
1320
1457
  dayDetailTitle: (label) => label,
1321
1458
  open: "Open",
1322
- allDay: "All day"
1459
+ allDay: "All day",
1460
+ reschedule: "Reschedule",
1461
+ pickDate: "Pick date",
1462
+ unassigned: "Unassigned",
1463
+ resource: "Resource"
1323
1464
  };
1324
1465
  var DEFAULT_EVENT_FIELDS = {
1325
1466
  id: "id",
@@ -1354,11 +1495,30 @@ var STATUS_VARIANT = {
1354
1495
  error: "danger",
1355
1496
  danger: "danger"
1356
1497
  };
1498
+ var TAG_VARIANT = {
1499
+ default: "default",
1500
+ info: "info",
1501
+ success: "success",
1502
+ warning: "warning",
1503
+ error: "error",
1504
+ danger: "error"
1505
+ };
1506
+ var MONTH_EVENT_STYLES = /* @__PURE__ */ new Set(["statusTag", "tag"]);
1507
+ var monthLabelMaxChars = (style) => {
1508
+ const overhead = style === "tag" ? 34 : 46;
1509
+ return Math.max(6, Math.floor((MONTH_COL_WIDTH - overhead) / 6.6));
1510
+ };
1511
+ var truncateMonthLabel = (value, max) => {
1512
+ const s = String(value == null ? "" : value);
1513
+ if (!max || s.length <= max) return s;
1514
+ return s.slice(0, max).trimEnd();
1515
+ };
1357
1516
  var MONTH_COL_WIDTH = 160;
1358
1517
  var TIMEGRID_DAY_COL = 150;
1359
1518
  var TIMEGRID_DAY_COL_SINGLE = 560;
1519
+ var RESOURCE_LABEL_COL_WIDTH = "min";
1360
1520
  var HOUR_SLOT_HEIGHT = 64;
1361
- var EventDetail = ({ event, labels }) => {
1521
+ var EventDetail = ({ event, labels, reschedule, idSuffix = "" }) => {
1362
1522
  const { start, end, title, subtitle, href } = event;
1363
1523
  let when = "";
1364
1524
  if (start) {
@@ -1372,11 +1532,27 @@ var EventDetail = ({ event, labels }) => {
1372
1532
  when = `${formatDayTitle(start)} \u2013 ${formatDayTitle(end)}`;
1373
1533
  }
1374
1534
  }
1375
- return /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "xs" }, /* @__PURE__ */ React5.createElement(Text, { format: { fontWeight: "demibold" } }, title || "--"), when ? /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy" }, when) : null, subtitle ? /* @__PURE__ */ React5.createElement(Text, null, subtitle) : null, href ? /* @__PURE__ */ React5.createElement(Link2, { href: href.url, external: href.external }, labels.open) : null);
1535
+ return /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "xs" }, /* @__PURE__ */ React5.createElement(Text, { format: { fontWeight: "demibold" }, truncate: true }, title || "--"), when ? /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy", truncate: true }, when) : null, subtitle ? /* @__PURE__ */ React5.createElement(Text, { truncate: true }, subtitle) : null, href ? /* @__PURE__ */ React5.createElement(Link2, { href: href.url, external: href.external }, labels.open) : null, reschedule ? /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Divider, null), /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy", format: { fontWeight: "demibold" } }, labels.reschedule), reschedule.options.length > 0 ? /* @__PURE__ */ React5.createElement(Flex4, { direction: "row", gap: "xs", wrap: "wrap" }, reschedule.options.map((option, i) => /* @__PURE__ */ React5.createElement(
1536
+ Button3,
1537
+ {
1538
+ key: `${option.label}-${i}`,
1539
+ size: "xs",
1540
+ variant: "secondary",
1541
+ onClick: () => reschedule.onPreset(event, option)
1542
+ },
1543
+ option.label
1544
+ ))) : null, /* @__PURE__ */ React5.createElement(
1545
+ DateInput2,
1546
+ {
1547
+ name: `cal-resched-${event.key}${idSuffix}`,
1548
+ label: labels.pickDate,
1549
+ onChange: (value) => reschedule.onPick(event, value)
1550
+ }
1551
+ )) : null);
1376
1552
  };
1377
- var buildOverlay = (event, mode, renderEventDetail, labels, idSuffix = "") => {
1553
+ var buildOverlay = (event, mode, renderEventDetail, labels, idSuffix = "", reschedule = null) => {
1378
1554
  if (mode === "none") return void 0;
1379
- const body = renderEventDetail ? renderEventDetail(event) : /* @__PURE__ */ React5.createElement(EventDetail, { event, labels });
1555
+ const body = renderEventDetail ? renderEventDetail(event) : /* @__PURE__ */ React5.createElement(EventDetail, { event, labels, reschedule, idSuffix });
1380
1556
  const id = `cal-evt-${event.key}${idSuffix}`;
1381
1557
  if (mode === "modal") {
1382
1558
  return /* @__PURE__ */ React5.createElement(Modal, { id, title: event.title || labels.open, width: "small" }, /* @__PURE__ */ React5.createElement(ModalBody, null, body));
@@ -1384,46 +1560,34 @@ var buildOverlay = (event, mode, renderEventDetail, labels, idSuffix = "") => {
1384
1560
  if (mode === "panel") {
1385
1561
  return /* @__PURE__ */ React5.createElement(Panel, { id, title: event.title || labels.open, width: "small", variant: "modal" }, /* @__PURE__ */ React5.createElement(PanelBody, null, body));
1386
1562
  }
1387
- return /* @__PURE__ */ React5.createElement(Popover, { id, placement: "bottom" }, /* @__PURE__ */ React5.createElement(Tile, { compact: true }, body));
1563
+ return /* @__PURE__ */ React5.createElement(Popover, { id, placement: "bottom", variant: "longform" }, /* @__PURE__ */ React5.createElement(Tile, { compact: true }, body));
1388
1564
  };
1389
- var AgendaEventRow = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels }) => {
1565
+ var AgendaEventRow = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels, reschedule }) => {
1390
1566
  const variant = VALID_VARIANTS.has(event.color) ? event.color : "default";
1391
- const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-ag${day.getTime()}` : "");
1567
+ const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-ag${day.getTime()}` : "", reschedule);
1392
1568
  const handleClick = onEventClick ? () => onEventClick(event.raw, event) : void 0;
1393
1569
  const timeLabel = isAllDayEvent(event) ? labels.allDay : formatTime(event.start);
1394
1570
  return /* @__PURE__ */ React5.createElement(Flex4, { direction: "row", align: "center", gap: "sm" }, /* @__PURE__ */ React5.createElement(Box2, { flex: 2 }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "row", align: "center" }, /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy", format: { fontWeight: "demibold" } }, timeLabel))), /* @__PURE__ */ React5.createElement(Box2, { flex: 11 }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "row", align: "center", gap: "xs" }, /* @__PURE__ */ React5.createElement(ColorDot, { variant }), /* @__PURE__ */ React5.createElement(Text, { truncate: true }, /* @__PURE__ */ React5.createElement(Link2, { overlay, onClick: handleClick }, event.title || "--")))), event.subtitle ? /* @__PURE__ */ React5.createElement(Box2, { flex: 4 }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "row", align: "center" }, /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy", truncate: true }, event.subtitle))) : null);
1395
1571
  };
1396
- var MONTH_CHIP_WIDTH = MONTH_COL_WIDTH - 8;
1397
- var MONTH_CHIP_HEIGHT = 24;
1398
- var MonthChip = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels }) => {
1572
+ var MONTH_SLOT_HEIGHT = 24;
1573
+ var MonthChip = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels, monthEventStyle, monthEventMaxChars, reschedule, idScope = "" }) => {
1399
1574
  const isStartDay = !day || !event.start || isSameDay(event.start, day);
1400
- const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-m${day.getTime()}` : "");
1575
+ const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-m${idScope}${day.getTime()}` : "", reschedule);
1401
1576
  const handleClick = onEventClick ? () => onEventClick(event.raw, event) : void 0;
1402
1577
  const variant = VALID_VARIANTS.has(event.color) ? event.color : "default";
1403
1578
  const startHasTime = event.start && (event.start.getHours() !== 0 || event.start.getMinutes() !== 0);
1404
1579
  const time = isStartDay && startHasTime ? `${formatTime(event.start)} ` : "";
1405
1580
  const prefix = isStartDay ? "" : "\u2192 ";
1406
- const chip = makeEventChipDataUri({
1407
- label: `${prefix}${time}${event.title || "--"}`,
1408
- width: MONTH_CHIP_WIDTH,
1409
- height: MONTH_CHIP_HEIGHT,
1410
- variant
1411
- });
1412
- return /* @__PURE__ */ React5.createElement(
1413
- Image2,
1414
- {
1415
- src: chip.src,
1416
- width: chip.width,
1417
- height: chip.height,
1418
- alt: event.title || "",
1419
- overlay,
1420
- onClick: handleClick
1421
- }
1422
- );
1581
+ const maxChars = monthEventMaxChars != null ? monthEventMaxChars : monthLabelMaxChars(monthEventStyle);
1582
+ const label = truncateMonthLabel(`${prefix}${time}${event.title || "--"}`, maxChars);
1583
+ if (monthEventStyle === "tag") {
1584
+ return /* @__PURE__ */ React5.createElement(Tag2, { variant: TAG_VARIANT[variant] || "default", overlay, onClick: handleClick }, label);
1585
+ }
1586
+ return /* @__PURE__ */ React5.createElement(Link2, { overlay, onClick: handleClick }, /* @__PURE__ */ React5.createElement(StatusTag, { variant: STATUS_VARIANT[variant] || "default" }, label));
1423
1587
  };
1424
- var DayListItem = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels }) => {
1588
+ var DayListItem = ({ event, day, overlayMode, renderEventDetail, onEventClick, labels, reschedule, idScope = "" }) => {
1425
1589
  const handleClick = onEventClick ? () => onEventClick(event.raw, event) : void 0;
1426
- const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-more${day.getTime()}` : "-more");
1590
+ const overlay = buildOverlay(event, overlayMode, renderEventDetail, labels, day ? `-more${idScope}${day.getTime()}` : "-more", reschedule);
1427
1591
  const href = event.href;
1428
1592
  return /* @__PURE__ */ React5.createElement(Button3, { variant: "transparent", size: "sm", href: href ? href.url : void 0, overlay, onClick: handleClick }, event.title || "--");
1429
1593
  };
@@ -1488,6 +1652,40 @@ var Toolbar = ({
1488
1652
  }
1489
1653
  ));
1490
1654
  };
1655
+ var DayChipStack = ({ day, events, maxEventsPerDay, chipProps, labels, idScope = "" }) => {
1656
+ const slotSpacer = makeSpacerDataUri(MONTH_SLOT_HEIGHT, 1);
1657
+ const shown = events.slice(0, maxEventsPerDay);
1658
+ const hasOverflow = events.length > maxEventsPerDay;
1659
+ const heightSpacer = /* @__PURE__ */ React5.createElement(Image2, { src: slotSpacer.src, width: slotSpacer.width, height: slotSpacer.height, alt: "" });
1660
+ const slotRow = (key, content) => /* @__PURE__ */ React5.createElement(Flex4, { key, direction: "row", align: "center", gap: "flush" }, heightSpacer, content);
1661
+ const slots = [];
1662
+ for (let i = 0; i < maxEventsPerDay; i++) {
1663
+ if (i < shown.length) {
1664
+ slots.push(slotRow(shown[i].key, /* @__PURE__ */ React5.createElement(MonthChip, { event: shown[i], day, idScope, ...chipProps })));
1665
+ } else {
1666
+ slots.push(/* @__PURE__ */ React5.createElement(Image2, { key: `sp-${i}`, src: slotSpacer.src, width: slotSpacer.width, height: slotSpacer.height, alt: "" }));
1667
+ }
1668
+ }
1669
+ if (hasOverflow) {
1670
+ slots.push(
1671
+ slotRow(
1672
+ "more",
1673
+ /* @__PURE__ */ React5.createElement(
1674
+ Link2,
1675
+ {
1676
+ overlay: /* @__PURE__ */ React5.createElement(Popover, { id: `cal-day-${idScope}${day.getTime()}`, placement: "top", variant: "longform" }, /* @__PURE__ */ React5.createElement(Tile, { compact: true }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "sm" }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "row", justify: "center", align: "center", gap: "xs" }, /* @__PURE__ */ React5.createElement(Text, { format: { fontWeight: "bold" } }, String(events.length)), /* @__PURE__ */ React5.createElement(Text, { format: { fontWeight: "demibold" } }, labels.onThisDate)), /* @__PURE__ */ React5.createElement(Divider, null), events.map((event, i) => /* @__PURE__ */ React5.createElement(React5.Fragment, { key: event.key }, /* @__PURE__ */ React5.createElement(DayListItem, { event, day, idScope, ...chipProps }), i < events.length - 1 ? /* @__PURE__ */ React5.createElement(Divider, null) : null)))))
1677
+ },
1678
+ labels.more(events.length - maxEventsPerDay)
1679
+ )
1680
+ )
1681
+ );
1682
+ } else {
1683
+ slots.push(
1684
+ /* @__PURE__ */ React5.createElement(Image2, { key: "more-sp", src: slotSpacer.src, width: slotSpacer.width, height: slotSpacer.height, alt: "" })
1685
+ );
1686
+ }
1687
+ return /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "xs" }, slots);
1688
+ };
1491
1689
  var MonthView = ({
1492
1690
  refDate,
1493
1691
  now,
@@ -1502,49 +1700,21 @@ var MonthView = ({
1502
1700
  }) => {
1503
1701
  const headers = weekdayLabels(weekStartsOn, hideWeekends, true);
1504
1702
  const today = now || /* @__PURE__ */ new Date();
1505
- const spacer24 = makeSpacerDataUri(MONTH_CHIP_HEIGHT, MONTH_COL_WIDTH);
1506
1703
  const renderCell = (day) => {
1507
1704
  const dayEvents = eventsForDay(day);
1508
1705
  const inMonth = isSameMonth(day, refDate);
1509
1706
  const isToday = isSameDay(day, today);
1510
1707
  if (renderDayCell) return renderDayCell(day, dayEvents);
1511
- const shown = dayEvents.slice(0, maxEventsPerDay);
1512
- const hasOverflow = dayEvents.length > maxEventsPerDay;
1513
- const slots = [];
1514
- for (let i = 0; i < maxEventsPerDay; i++) {
1515
- if (i < shown.length) {
1516
- slots.push(/* @__PURE__ */ React5.createElement(MonthChip, { key: shown[i].key, event: shown[i], day, ...chipProps }));
1517
- } else {
1518
- slots.push(
1519
- /* @__PURE__ */ React5.createElement(Image2, { key: `sp-${i}`, src: spacer24.src, width: spacer24.width, height: spacer24.height, alt: "" })
1520
- );
1708
+ return /* @__PURE__ */ React5.createElement(AutoGrid, { columnWidth: MONTH_COL_WIDTH, gap: "flush" }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "xs" }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "row", align: "center", gap: "xs" }, isToday ? /* @__PURE__ */ React5.createElement(ColorDot, { variant: "info" }) : null, /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy", format: { fontWeight: inMonth ? "demibold" : "regular" } }, String(day.getDate()))), /* @__PURE__ */ React5.createElement(
1709
+ DayChipStack,
1710
+ {
1711
+ day,
1712
+ events: dayEvents,
1713
+ maxEventsPerDay,
1714
+ chipProps,
1715
+ labels
1521
1716
  }
1522
- }
1523
- if (hasOverflow) {
1524
- const more = makeMoreDataUri({
1525
- label: labels.more(dayEvents.length - maxEventsPerDay),
1526
- width: MONTH_COL_WIDTH,
1527
- height: MONTH_CHIP_HEIGHT
1528
- });
1529
- slots.push(
1530
- /* @__PURE__ */ React5.createElement(
1531
- Image2,
1532
- {
1533
- key: "more",
1534
- src: more.src,
1535
- width: more.width,
1536
- height: more.height,
1537
- alt: labels.more(dayEvents.length - maxEventsPerDay),
1538
- overlay: /* @__PURE__ */ React5.createElement(Popover, { id: `cal-day-${day.getTime()}`, placement: "top", variant: "longform" }, /* @__PURE__ */ React5.createElement(Tile, { compact: true }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "sm" }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "row", align: "center", gap: "sm" }, /* @__PURE__ */ React5.createElement(Heading, null, String(dayEvents.length)), /* @__PURE__ */ React5.createElement(Text, { format: { fontWeight: "demibold" } }, labels.onThisDate)), /* @__PURE__ */ React5.createElement(Divider, null), dayEvents.map((event, i) => /* @__PURE__ */ React5.createElement(React5.Fragment, { key: event.key }, /* @__PURE__ */ React5.createElement(DayListItem, { event, day, ...chipProps }), i < dayEvents.length - 1 ? /* @__PURE__ */ React5.createElement(Divider, null) : null)))))
1539
- }
1540
- )
1541
- );
1542
- } else {
1543
- slots.push(
1544
- /* @__PURE__ */ React5.createElement(Image2, { key: "more-sp", src: spacer24.src, width: spacer24.width, height: spacer24.height, alt: "" })
1545
- );
1546
- }
1547
- return /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "xs" }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "row", align: "center", gap: "xs" }, isToday ? /* @__PURE__ */ React5.createElement(ColorDot, { variant: "info" }) : null, /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy", format: { fontWeight: inMonth ? "demibold" : "regular" } }, String(day.getDate()))), slots);
1717
+ )));
1548
1718
  };
1549
1719
  return /* @__PURE__ */ React5.createElement(Table, { bordered: true, flush: true }, /* @__PURE__ */ React5.createElement(TableHead, null, /* @__PURE__ */ React5.createElement(TableRow, null, headers.map((h4) => /* @__PURE__ */ React5.createElement(TableHeader, { key: h4, width: "min", align: "center" }, h4.toUpperCase())))), /* @__PURE__ */ React5.createElement(TableBody, null, weeks.map((week, wi) => {
1550
1720
  const days = hideWeekends ? week.filter((d) => d.getDay() !== 0 && d.getDay() !== 6) : week;
@@ -1566,6 +1736,33 @@ var AgendaView = ({ rangeStart, rangeEnd, eventsForDay, chipProps, labels, rende
1566
1736
  }
1567
1737
  return /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "lg" }, days.map(({ day, events }) => /* @__PURE__ */ React5.createElement(Flex4, { key: day.getTime(), direction: "column", gap: "sm" }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "row", justify: "between", align: "end" }, /* @__PURE__ */ React5.createElement(Text, { format: { fontWeight: "demibold" } }, formatDayTitle(day)), /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy" }, `${events.length} ${events.length === 1 ? "event" : "events"}`)), /* @__PURE__ */ React5.createElement(Divider, null), events.map((event) => /* @__PURE__ */ React5.createElement(AgendaEventRow, { key: event.key, event, day, ...chipProps })))));
1568
1738
  };
1739
+ var ResourceView = ({ days, now, lanes, maxEventsPerDay, chipProps, labels, renderEmptyState }) => {
1740
+ const today = now || /* @__PURE__ */ new Date();
1741
+ if (!lanes || lanes.length === 0) {
1742
+ if (renderEmptyState) return renderEmptyState({});
1743
+ return /* @__PURE__ */ React5.createElement(EmptyState, { title: labels.noEventsTitle }, /* @__PURE__ */ React5.createElement(Text, null, labels.noEventsMessage));
1744
+ }
1745
+ const rangeStart = startOfDay(days[0]);
1746
+ const rangeEnd = endOfDay(days[days.length - 1]);
1747
+ return /* @__PURE__ */ React5.createElement(Table, { bordered: true, flush: true }, /* @__PURE__ */ React5.createElement(TableHead, null, /* @__PURE__ */ React5.createElement(TableRow, null, /* @__PURE__ */ React5.createElement(TableHeader, { width: RESOURCE_LABEL_COL_WIDTH }, String(labels.resource).toUpperCase()), days.map((day) => {
1748
+ const isToday = isSameDay(day, today);
1749
+ const label = `${formatWeekdayShort(day)} ${formatMonthShort(day)} ${day.getDate()}`;
1750
+ return /* @__PURE__ */ React5.createElement(TableHeader, { key: day.getTime(), width: "min", align: "center" }, isToday ? `${label} \xB7 Today` : label);
1751
+ }))), /* @__PURE__ */ React5.createElement(TableBody, null, lanes.map((lane, laneIndex) => {
1752
+ const visible = eventsIntersectingRange(lane.events, rangeStart, rangeEnd);
1753
+ return /* @__PURE__ */ React5.createElement(TableRow, { key: lane.key }, /* @__PURE__ */ React5.createElement(TableCell, { width: RESOURCE_LABEL_COL_WIDTH }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "flush" }, /* @__PURE__ */ React5.createElement(Text, { format: { fontWeight: "demibold" } }, lane.label), /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy" }, `${visible.length} ${visible.length === 1 ? "event" : "events"}`))), days.map((day) => /* @__PURE__ */ React5.createElement(TableCell, { key: day.getTime(), width: "min" }, /* @__PURE__ */ React5.createElement(AutoGrid, { columnWidth: MONTH_COL_WIDTH, gap: "flush" }, /* @__PURE__ */ React5.createElement(
1754
+ DayChipStack,
1755
+ {
1756
+ day,
1757
+ events: laneEventsForDay(visible, day),
1758
+ maxEventsPerDay,
1759
+ chipProps,
1760
+ labels,
1761
+ idScope: `r${laneIndex}-`
1762
+ }
1763
+ )))));
1764
+ })));
1765
+ };
1569
1766
  var formatTimedDuration = (start, end) => {
1570
1767
  const mins = Math.max(0, Math.round(((end || start).getTime() - start.getTime()) / 6e4));
1571
1768
  const h4 = Math.floor(mins / 60);
@@ -1587,6 +1784,7 @@ var TimeGridView = ({ days, now, hours, dayStartHour, dayEndHour, eventsForDay,
1587
1784
  const today = now || /* @__PURE__ */ new Date();
1588
1785
  const centerDays = days.length === 1;
1589
1786
  const dayColWidth = days.length === 1 ? TIMEGRID_DAY_COL_SINGLE : TIMEGRID_DAY_COL;
1787
+ const weekTitleMaxChars = Math.max(6, Math.floor((TIMEGRID_DAY_COL - 46) / 6.6));
1590
1788
  const todayInView = days.some((d) => isSameDay(d, today));
1591
1789
  const nowHour = today.getHours();
1592
1790
  const dayData = days.map((day) => {
@@ -1612,7 +1810,8 @@ var TimeGridView = ({ days, now, hours, dayStartHour, dayEndHour, eventsForDay,
1612
1810
  chipProps.overlayMode,
1613
1811
  chipProps.renderEventDetail,
1614
1812
  chipProps.labels,
1615
- `-tg${mode}${hour}-${dayMs}`
1813
+ `-tg${mode}${hour}-${dayMs}`,
1814
+ chipProps.reschedule
1616
1815
  );
1617
1816
  const handleClick = chipProps.onEventClick ? () => chipProps.onEventClick(e.raw, e) : void 0;
1618
1817
  const variant = VALID_VARIANTS.has(e.color) ? e.color : "default";
@@ -1631,10 +1830,10 @@ var TimeGridView = ({ days, now, hours, dayStartHour, dayEndHour, eventsForDay,
1631
1830
  } else if (mode === "cont") {
1632
1831
  sub = `\u2191 cont. through ${endLabel}`;
1633
1832
  }
1634
- return /* @__PURE__ */ React5.createElement(Flex4, { key: `${e.key}-${mode}-${hour}`, direction: "column", gap: "flush" }, /* @__PURE__ */ React5.createElement(Link2, { overlay, onClick: handleClick }, /* @__PURE__ */ React5.createElement(StatusTag, { variant: STATUS_VARIANT[variant] || "default" }, e.title || "--")), sub ? /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy" }, sub) : null);
1833
+ const titleLabel = centerDays ? e.title || "--" : truncateMonthLabel(e.title || "--", weekTitleMaxChars);
1834
+ return /* @__PURE__ */ React5.createElement(Flex4, { key: `${e.key}-${mode}-${hour}`, direction: "column", gap: "flush" }, /* @__PURE__ */ React5.createElement(Link2, { overlay, onClick: handleClick }, /* @__PURE__ */ React5.createElement(StatusTag, { variant: STATUS_VARIANT[variant] || "default" }, titleLabel)), sub ? /* @__PURE__ */ React5.createElement(Text, { variant: "microcopy" }, sub) : null);
1635
1835
  };
1636
- const daySpacer = makeSpacerDataUri(1, dayColWidth);
1637
- const dayCell = (key, content) => /* @__PURE__ */ React5.createElement(TableCell, { key, width: centerDays ? "max" : "min", align: "left" }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "xs" }, content, centerDays ? null : /* @__PURE__ */ React5.createElement(Image2, { src: daySpacer.src, width: daySpacer.width, height: daySpacer.height, alt: "" })));
1836
+ const dayCell = (key, content) => /* @__PURE__ */ React5.createElement(TableCell, { key, width: centerDays ? "max" : "min", align: "left" }, centerDays ? /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "xs" }, content) : /* @__PURE__ */ React5.createElement(AutoGrid, { columnWidth: dayColWidth, gap: "flush" }, /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "xs" }, content)));
1638
1837
  const slotSpacer = makeSpacerDataUri(HOUR_SLOT_HEIGHT, 1);
1639
1838
  const emptyCell = null;
1640
1839
  return /* @__PURE__ */ React5.createElement(Table, { bordered: true, flush: true, density: "compact" }, /* @__PURE__ */ React5.createElement(TableHead, null, /* @__PURE__ */ React5.createElement(TableRow, null, /* @__PURE__ */ React5.createElement(TableHeader, { width: "min" }, "TIME"), dayData.map(({ day }) => {
@@ -1690,9 +1889,21 @@ var Calendar = (props) => {
1690
1889
  weekStartsOn = 0,
1691
1890
  hideWeekends = false,
1692
1891
  maxEventsPerDay = DEFAULT_MAX_EVENTS_PER_DAY,
1892
+ // month-grid event token style: "statusTag" (dot + text, default) | "tag" (pill)
1893
+ monthEventStyle = "statusTag",
1894
+ // max characters for a month-cell label before "…" (default derived per style)
1895
+ monthEventMaxChars,
1693
1896
  // time grid (week / day)
1694
1897
  dayStartHour = DEFAULT_DAY_START_HOUR,
1695
1898
  dayEndHour = DEFAULT_DAY_END_HOUR,
1899
+ // resource / lane view (rows = resources, columns = the focused week's days)
1900
+ resources,
1901
+ resourceField,
1902
+ resourceLabels,
1903
+ showUnassignedLane = true,
1904
+ // drag-free reschedule (presets + date picker in the event-detail overlay)
1905
+ rescheduleOptions,
1906
+ onEventReschedule,
1696
1907
  // timezone
1697
1908
  timeZone: controlledTimeZone,
1698
1909
  defaultTimeZone,
@@ -1731,10 +1942,12 @@ var Calendar = (props) => {
1731
1942
  const fields = useMemo(() => ({ ...DEFAULT_EVENT_FIELDS, ...eventFields || {} }), [eventFields]);
1732
1943
  const [internalView, setInternalView] = useState2(defaultView);
1733
1944
  const view = controlledView != null ? controlledView : internalView;
1945
+ const resourceEnabled = resources && resources.length > 0 || resourceField != null;
1734
1946
  const enabledViews = useMemo(() => {
1735
- const base = viewsProp && viewsProp.length > 0 ? viewsProp : ALL_VIEWS;
1736
- return base.filter((v) => ALL_VIEWS.includes(v));
1737
- }, [viewsProp]);
1947
+ const all = resourceEnabled ? ALL_VIEWS_WITH_RESOURCE : ALL_VIEWS;
1948
+ const base = viewsProp && viewsProp.length > 0 ? viewsProp : all;
1949
+ return base.filter((v) => all.includes(v));
1950
+ }, [viewsProp, resourceEnabled]);
1738
1951
  const setView = useCallback(
1739
1952
  (next) => {
1740
1953
  if (controlledView == null) setInternalView(next);
@@ -1759,7 +1972,9 @@ var Calendar = (props) => {
1759
1972
  const focusedDate = (controlledFocusedDate != null ? toDate(controlledFocusedDate) : internalDate) || startOfDay(nowWall);
1760
1973
  const stepFor = useCallback(
1761
1974
  (dir) => {
1762
- if (view === "week" || view === "agenda") return addDays(focusedDate, dir * 7);
1975
+ if (view === "week" || view === "agenda" || view === "resource") {
1976
+ return addDays(focusedDate, dir * 7);
1977
+ }
1763
1978
  if (view === "day") return addDays(focusedDate, dir);
1764
1979
  return addMonths(focusedDate, dir);
1765
1980
  },
@@ -1786,7 +2001,7 @@ var Calendar = (props) => {
1786
2001
  rangeEnd: endOfDay(flat[flat.length - 1])
1787
2002
  };
1788
2003
  }
1789
- if (view === "week") {
2004
+ if (view === "week" || view === "resource") {
1790
2005
  const days = buildWeekDays(focusedDate, weekStartsOn, hideWeekends);
1791
2006
  return {
1792
2007
  weeks: null,
@@ -1859,14 +2074,18 @@ var Calendar = (props) => {
1859
2074
  );
1860
2075
  const normalized = useMemo(
1861
2076
  () => (events || []).map((raw, index) => {
1862
- const start = toWallClock(toDate(resolveField(raw, fields.start)), timeZone);
1863
- const endRaw = toWallClock(toDate(resolveField(raw, fields.end)), timeZone);
2077
+ const sourceStart = toDate(resolveField(raw, fields.start));
2078
+ const sourceEnd = toDate(resolveField(raw, fields.end));
2079
+ const start = toWallClock(sourceStart, timeZone);
2080
+ const endRaw = toWallClock(sourceEnd, timeZone);
1864
2081
  const id = resolveField(raw, fields.id);
1865
2082
  return {
1866
2083
  key: id != null ? String(id) : `evt-${index}`,
1867
2084
  id,
1868
2085
  start,
1869
2086
  end: endRaw || start,
2087
+ sourceStart,
2088
+ sourceEnd: sourceEnd || sourceStart,
1870
2089
  title: resolveField(raw, fields.title),
1871
2090
  subtitle: resolveField(raw, fields.subtitle),
1872
2091
  color: resolveField(raw, fields.color),
@@ -1903,13 +2122,60 @@ var Calendar = (props) => {
1903
2122
  }, [rangeKey]);
1904
2123
  const title = useMemo(() => {
1905
2124
  if (view === "day") return formatDayTitle(focusedDate);
1906
- if (view === "week" || view === "agenda") {
1907
- const days = buildWeekDays(focusedDate, weekStartsOn, view === "week" && hideWeekends);
2125
+ if (view === "week" || view === "agenda" || view === "resource") {
2126
+ const days = buildWeekDays(focusedDate, weekStartsOn, view !== "agenda" && hideWeekends);
1908
2127
  return formatRangeTitle(days[0], days[days.length - 1]);
1909
2128
  }
1910
2129
  return formatMonthTitle(focusedDate);
1911
2130
  }, [view, focusedDate, weekStartsOn, hideWeekends]);
1912
- const chipProps = { overlayMode, renderEventDetail, onEventClick, labels };
2131
+ const handleReschedulePreset = useCallback(
2132
+ (event, option) => {
2133
+ const target = resolveRescheduleTarget(
2134
+ { start: event.sourceStart, end: event.sourceEnd },
2135
+ option,
2136
+ event
2137
+ );
2138
+ if (target && onEventReschedule) onEventReschedule(event.raw, target, event);
2139
+ },
2140
+ [onEventReschedule]
2141
+ );
2142
+ const handleReschedulePick = useCallback(
2143
+ (event, value) => {
2144
+ const newStart = applyDatePick(event.sourceStart, value);
2145
+ if (!newStart) return;
2146
+ const target = rescheduleToStart({ start: event.sourceStart, end: event.sourceEnd }, newStart);
2147
+ if (target && onEventReschedule) onEventReschedule(event.raw, target, event);
2148
+ },
2149
+ [onEventReschedule]
2150
+ );
2151
+ const reschedule = useMemo(() => {
2152
+ if (!rescheduleOptions) return null;
2153
+ return {
2154
+ options: normalizeRescheduleOptions(rescheduleOptions),
2155
+ onPreset: handleReschedulePreset,
2156
+ onPick: handleReschedulePick
2157
+ };
2158
+ }, [rescheduleOptions, handleReschedulePreset, handleReschedulePick]);
2159
+ const safeMonthEventStyle = MONTH_EVENT_STYLES.has(monthEventStyle) ? monthEventStyle : "statusTag";
2160
+ const chipProps = {
2161
+ overlayMode,
2162
+ renderEventDetail,
2163
+ onEventClick,
2164
+ labels,
2165
+ monthEventStyle: safeMonthEventStyle,
2166
+ monthEventMaxChars,
2167
+ reschedule
2168
+ };
2169
+ const resourceLaneData = useMemo(() => {
2170
+ if (view !== "resource") return null;
2171
+ return buildResourceLanes(queried, {
2172
+ resources,
2173
+ resourceLabels,
2174
+ getId: (e) => resolveResourceId(e.raw, resourceField),
2175
+ showUnassignedLane,
2176
+ unassignedLabel: labels.unassigned
2177
+ });
2178
+ }, [view, queried, resources, resourceLabels, resourceField, showUnassignedLane, labels]);
1913
2179
  const timeZoneOptions = useMemo(() => {
1914
2180
  if (!showTimeZoneSelect) return null;
1915
2181
  const base = (timeZoneOptionsProp && timeZoneOptionsProp.length ? timeZoneOptionsProp : DEFAULT_TIME_ZONES).map(
@@ -1970,6 +2236,19 @@ var Calendar = (props) => {
1970
2236
  labels
1971
2237
  }
1972
2238
  );
2239
+ } else if (view === "resource") {
2240
+ body = /* @__PURE__ */ React5.createElement(
2241
+ ResourceView,
2242
+ {
2243
+ days: gridDays,
2244
+ now: nowWall,
2245
+ lanes: resourceLaneData,
2246
+ maxEventsPerDay,
2247
+ chipProps,
2248
+ labels,
2249
+ renderEmptyState
2250
+ }
2251
+ );
1973
2252
  } else if (view === "week" || view === "day") {
1974
2253
  body = /* @__PURE__ */ React5.createElement(
1975
2254
  TimeGridView,
@@ -1999,6 +2278,7 @@ var Calendar = (props) => {
1999
2278
  }
2000
2279
  return /* @__PURE__ */ React5.createElement(Flex4, { direction: "column", gap: "sm" }, toolbar, body);
2001
2280
  };
2281
+ Calendar.displayName = "Calendar";
2002
2282
  export {
2003
2283
  Calendar
2004
2284
  };