@tensor_1/react 2.31.0 → 2.33.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 (117) hide show
  1. package/README.md +367 -0
  2. package/dist/SchedulingCalendar-C4XVbqZr.d.ts +339 -0
  3. package/dist/attachment-labels.d.ts +16 -0
  4. package/dist/attachment-labels.js +9 -0
  5. package/dist/calendar-model.d.ts +141 -1
  6. package/dist/calendar-model.js +200 -11
  7. package/dist/chart-preset.cjs +127 -7
  8. package/dist/chart-preset.d.cts +2 -2
  9. package/dist/chart-preset.d.ts +1 -0
  10. package/dist/chart-preset.js +6 -1
  11. package/dist/chart-theme-Cl0IrkKQ.d.cts +112 -0
  12. package/dist/chart-theme.d.ts +51 -0
  13. package/dist/chart-theme.js +99 -0
  14. package/dist/chart.cjs +127 -7
  15. package/dist/chart.d.cts +2 -2
  16. package/dist/chart.d.ts +1 -0
  17. package/dist/chart.js +6 -2
  18. package/dist/components/Alert.d.ts +17 -1
  19. package/dist/components/Alert.js +9 -4
  20. package/dist/components/AlertDismiss.d.ts +14 -0
  21. package/dist/components/AlertDismiss.js +11 -0
  22. package/dist/components/Attachment.d.ts +15 -12
  23. package/dist/components/Attachment.js +17 -17
  24. package/dist/components/AttachmentParts.d.ts +24 -0
  25. package/dist/components/AttachmentParts.js +20 -0
  26. package/dist/components/Chart.d.ts +1 -0
  27. package/dist/components/Chart.js +6 -1
  28. package/dist/components/ChartCore.d.ts +6 -1
  29. package/dist/components/ChartCore.js +23 -5
  30. package/dist/components/Chip.d.ts +17 -2
  31. package/dist/components/Chip.js +35 -11
  32. package/dist/components/ChipRemove.d.ts +17 -0
  33. package/dist/components/ChipRemove.js +13 -0
  34. package/dist/components/CollapsibleParts.d.ts +29 -0
  35. package/dist/components/CollapsibleParts.js +20 -0
  36. package/dist/components/CollapsibleSection.d.ts +30 -3
  37. package/dist/components/CollapsibleSection.js +7 -11
  38. package/dist/components/CollapsibleSectionState.d.ts +1 -1
  39. package/dist/components/CollapsibleSectionState.js +54 -27
  40. package/dist/components/DashboardGrid.d.ts +60 -0
  41. package/dist/components/DashboardGrid.js +40 -0
  42. package/dist/components/DateRangePicker.d.ts +7 -1
  43. package/dist/components/DateRangePicker.js +5 -1
  44. package/dist/components/DescriptionList.d.ts +12 -1
  45. package/dist/components/DescriptionList.js +5 -5
  46. package/dist/components/Dialogs.d.ts +24 -3
  47. package/dist/components/Dialogs.js +74 -16
  48. package/dist/components/FileUpload.d.ts +10 -2
  49. package/dist/components/FileUpload.js +10 -4
  50. package/dist/components/FilterEditor.d.ts +4 -0
  51. package/dist/components/FilterEditor.js +13 -2
  52. package/dist/components/Heartbeat.d.ts +31 -0
  53. package/dist/components/Heartbeat.js +28 -0
  54. package/dist/components/Menu.d.ts +53 -5
  55. package/dist/components/Menu.js +104 -4
  56. package/dist/components/Meter.d.ts +7 -3
  57. package/dist/components/Meter.js +2 -1
  58. package/dist/components/Popover.d.ts +21 -2
  59. package/dist/components/Popover.js +94 -17
  60. package/dist/components/Prose.d.ts +6 -2
  61. package/dist/components/Prose.js +1 -1
  62. package/dist/components/RuleBuilder.d.ts +52 -4
  63. package/dist/components/RuleBuilder.js +109 -24
  64. package/dist/components/SchedulingCalendar.d.ts +4 -110
  65. package/dist/components/SchedulingCalendar.js +299 -63
  66. package/dist/components/SchedulingTimeGrid.d.ts +4 -0
  67. package/dist/components/SchedulingTimeGrid.js +521 -0
  68. package/dist/components/SchedulingTimeline.d.ts +2 -1
  69. package/dist/components/Segmented.d.ts +17 -3
  70. package/dist/components/Segmented.js +59 -5
  71. package/dist/components/Select.d.ts +66 -2
  72. package/dist/components/Select.js +800 -10
  73. package/dist/components/Spinner.d.ts +2 -1
  74. package/dist/components/Spinner.js +1 -1
  75. package/dist/components/StatusPill.d.ts +8 -2
  76. package/dist/components/StatusPill.js +2 -2
  77. package/dist/components/Steps.d.ts +28 -4
  78. package/dist/components/Steps.js +46 -16
  79. package/dist/components/TableControls.js +4 -3
  80. package/dist/components/Tabs.d.ts +7 -2
  81. package/dist/components/Tabs.js +14 -1
  82. package/dist/components/TextDiff.d.ts +49 -0
  83. package/dist/components/TextDiff.js +124 -0
  84. package/dist/{emoji-image-6mPZ15Zy.d.cts → emoji-image-DjCKpdwE.d.cts} +1 -1
  85. package/dist/emoji.cjs +169 -27
  86. package/dist/emoji.d.cts +3 -3
  87. package/dist/file-model.d.ts +22 -3
  88. package/dist/file-model.js +6 -4
  89. package/dist/filter-model.d.ts +26 -2
  90. package/dist/filter-model.js +13 -1
  91. package/dist/hooks/useAnchoredPosition.d.ts +24 -1
  92. package/dist/hooks/useAnchoredPosition.js +58 -8
  93. package/dist/hooks/useVirtualRows.d.ts +17 -2
  94. package/dist/hooks/useVirtualRows.js +6 -5
  95. package/dist/icons/Icon.d.ts +14 -14
  96. package/dist/index.cjs +4888 -1714
  97. package/dist/index.d.cts +1871 -658
  98. package/dist/index.d.ts +16 -9
  99. package/dist/index.js +67 -4
  100. package/dist/labels-context.d.ts +29 -1
  101. package/dist/{overlay-position-Cjv5E7mn.d.cts → overlay-position-2Afke51l.d.cts} +20 -0
  102. package/dist/overlay-position.d.ts +20 -0
  103. package/dist/overlay-position.js +17 -2
  104. package/dist/rich-text.cjs +169 -27
  105. package/dist/rich-text.d.cts +3 -3
  106. package/dist/rule-builder-model.d.ts +34 -2
  107. package/dist/rule-builder-model.js +48 -12
  108. package/dist/scheduling-calendar-model.d.ts +169 -0
  109. package/dist/scheduling-calendar-model.js +176 -0
  110. package/dist/select-model.d.ts +80 -0
  111. package/dist/select-model.js +109 -0
  112. package/dist/table-engine.d.ts +7 -0
  113. package/dist/table-engine.js +2 -1
  114. package/dist/text-diff-model.d.ts +71 -0
  115. package/dist/text-diff-model.js +261 -0
  116. package/package.json +1 -1
  117. package/dist/ChartCore-DzWe10bN.d.cts +0 -59
@@ -1,7 +1,9 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useMemo, useRef, useState } from "react";
4
- import { addCalendarDays, addCalendarMonths, buildMonthGrid, startOfMonth, zonedDateSpan } from "../calendar-model.js";
4
+ import { addCalendarDays, addCalendarMonths, buildMonthGrid, cachedDateTimeFormat, startOfMonth, zonedDateKey, zonedTimeOfDay } from "../calendar-model.js";
5
+ import { TOP_LANE_CROSS_MIDNIGHT_MINUTES, itemDaySpan, layoutMonthSpans } from "../scheduling-calendar-model.js";
6
+ import { SchedulingTimeGrid } from "./SchedulingTimeGrid.js";
5
7
  import { cx } from "../cx.js";
6
8
  import { useUixLabels } from "../labels-context.js";
7
9
  import { StatusPill } from "./StatusPill.js";
@@ -10,9 +12,16 @@ const DEFAULT_SCHEDULING_CALENDAR_LABELS = {
10
12
  region: "Scheduling calendar in {timeZone}",
11
13
  previous: "Previous",
12
14
  next: "Next",
15
+ previousMonth: "Previous month",
16
+ nextMonth: "Next month",
17
+ previousWeek: "Previous week",
18
+ nextWeek: "Next week",
19
+ previousDay: "Previous day",
20
+ nextDay: "Next day",
13
21
  viewGroup: "Calendar view",
14
22
  viewMonth: "Month",
15
23
  viewWeek: "Week",
24
+ viewDay: "Day",
16
25
  viewAgenda: "Agenda",
17
26
  loading: "Loading schedule\u2026",
18
27
  retry: "Try again",
@@ -20,21 +29,54 @@ const DEFAULT_SCHEDULING_CALENDAR_LABELS = {
20
29
  agendaEmpty: "No scheduled entries match the current filters.",
21
30
  grid: "{view} schedule",
22
31
  entry: "{title}, {state}, {start} to {end}",
32
+ overlay: "{title}, {start} to {end}",
23
33
  legend: "Schedule state legend",
24
34
  moreEntries: "+{count} more",
25
35
  moreEntriesLabel: "{count} more entries on {date}",
26
36
  fewerEntries: "Show fewer",
27
- states: { scheduled: "Scheduled", conflicted: "Conflicted", "in-progress": "In progress", "blackout-violation": "Blackout violation" }
37
+ moreSpans: "+{count}",
38
+ moreSpansLabel: "{count} more spanning this week, from {date}",
39
+ dayCount: "{count} entries",
40
+ states: { scheduled: "Scheduled", conflicted: "Conflicted", "in-progress": "In progress", "blackout-violation": "Blackout violation" },
41
+ statuses: { tentative: "Tentative", committed: "Scheduled", live: "In progress", done: "Done", dead: "Cancelled" },
42
+ timeZone: "{timeZone}",
43
+ windows: "Windows",
44
+ moreWindows: "+{count} windows",
45
+ moreWindowsLabel: "{count} more windows, from {date}",
46
+ topLane: "All-day and longer entries",
47
+ continuesFrom: "from {time}",
48
+ moveHint: "Hold Shift and press an arrow key to move it. Enter confirms, Escape cancels.",
49
+ moveProposed: "Move to {start} \u2013 {end}. Enter confirms, Escape cancels.",
50
+ moveCancelled: "Move cancelled.",
51
+ gapForward: "That time does not exist on this day. Moved forward to {time}."
28
52
  };
29
53
  const stateTone = (state) => state === "scheduled" ? "info" : state === "in-progress" ? "success" : "danger";
30
54
  const utcDate = (date) => /* @__PURE__ */ new Date(`${date}T00:00:00Z`);
31
55
  const INTL_PARTS = {
32
56
  day: { dateStyle: "full", timeZone: "UTC" },
33
57
  weekday: { weekday: "short", timeZone: "UTC" },
34
- month: { month: "long", year: "numeric", timeZone: "UTC" }
58
+ month: { month: "long", year: "numeric", timeZone: "UTC" },
59
+ column: { weekday: "short", day: "2-digit", month: "2-digit", timeZone: "UTC" }
35
60
  };
36
- const intlDate = (date, part, locale) => new Intl.DateTimeFormat(locale, INTL_PARTS[part]).format(utcDate(date));
37
61
  const EMPTY_OVERLAYS = [];
62
+ const EMPTY_ENTRIES = [];
63
+ const DEFAULT_LANE_CAP = 2;
64
+ const DEFAULT_CHIP_ROWS = 3;
65
+ function coveredDays(start, end, timeZone) {
66
+ try {
67
+ return itemDaySpan(start, end, timeZone);
68
+ } catch {
69
+ return itemDaySpan(start, start, timeZone);
70
+ }
71
+ }
72
+ function Marker({ marker, showLabel }) {
73
+ const emphasis = marker.emphasis ?? "neutral";
74
+ return /* @__PURE__ */ jsxs("span", { className: "uix-scheduling-calendar__marker", "data-emphasis": emphasis, "data-glyph": marker.icon == null ? emphasis : void 0, children: [
75
+ marker.icon != null && /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__marker-icon", "aria-hidden": "true", children: marker.icon }),
76
+ /* @__PURE__ */ jsx("span", { className: showLabel ? "uix-scheduling-calendar__marker-label" : "uix-visually-hidden", children: marker.label })
77
+ ] });
78
+ }
79
+ const renderMarker = (marker, showLabel) => /* @__PURE__ */ jsx(Marker, { marker, showLabel });
38
80
  function SchedulingCalendar({
39
81
  entries,
40
82
  anchorDate,
@@ -44,6 +86,7 @@ function SchedulingCalendar({
44
86
  onAnchorDateChange,
45
87
  onSelectEntry,
46
88
  overlays = EMPTY_OVERLAYS,
89
+ onSelectOverlay,
47
90
  filter,
48
91
  renderEntry,
49
92
  locale,
@@ -53,6 +96,25 @@ function SchedulingCalendar({
53
96
  maxEntriesPerDay,
54
97
  onShowMore,
55
98
  renderDayBadge,
99
+ days: dayInfo,
100
+ dayEntries,
101
+ spanLayout,
102
+ windowLaneCap,
103
+ spanLaneCap,
104
+ legend,
105
+ legendCaption,
106
+ showHeader = true,
107
+ notice,
108
+ emptyNote,
109
+ onSelectDate,
110
+ timeGrid = false,
111
+ now,
112
+ canMove = false,
113
+ step = 15,
114
+ onProposeMove,
115
+ topLaneCrossMidnightMinutes = TOP_LANE_CROSS_MIDNIGHT_MINUTES,
116
+ topLaneCap = 3,
117
+ maxLanes = 4,
56
118
  loading,
57
119
  error,
58
120
  onRetry,
@@ -60,28 +122,80 @@ function SchedulingCalendar({
60
122
  labels: labelOverrides
61
123
  }) {
62
124
  const uixLabels = useUixLabels();
125
+ const overrides = { ...uixLabels.schedulingCalendar, ...labelOverrides };
63
126
  const labels = {
64
127
  ...DEFAULT_SCHEDULING_CALENDAR_LABELS,
65
- ...uixLabels.schedulingCalendar,
66
- ...labelOverrides,
67
- states: { ...DEFAULT_SCHEDULING_CALENDAR_LABELS.states, ...uixLabels.schedulingCalendar?.states, ...labelOverrides?.states }
128
+ ...overrides,
129
+ states: { ...DEFAULT_SCHEDULING_CALENDAR_LABELS.states, ...uixLabels.schedulingCalendar?.states, ...labelOverrides?.states },
130
+ statuses: { ...DEFAULT_SCHEDULING_CALENDAR_LABELS.statuses, ...uixLabels.schedulingCalendar?.statuses, ...labelOverrides?.statuses }
68
131
  };
69
132
  const stateLabel = labels.states;
70
- const viewLabel = { month: labels.viewMonth, week: labels.viewWeek, agenda: labels.viewAgenda };
133
+ const viewLabel = { month: labels.viewMonth, week: labels.viewWeek, day: labels.viewDay, agenda: labels.viewAgenda };
71
134
  const [internalView, setInternalView] = useState("month");
72
135
  const view = controlledView ?? internalView;
73
136
  const [activeDate, setActiveDate] = useState(anchorDate);
74
137
  const [expandedDates, setExpandedDates] = useState(() => /* @__PURE__ */ new Set());
75
- const dateText = (date, part) => formatDate?.(date, part) ?? intlDate(date, part, locale);
138
+ const dateText = (date, part) => formatDate?.(date, part) ?? cachedDateTimeFormat(locale, INTL_PARTS[part]).format(utcDate(date));
139
+ const formatInstant = (instant) => formatInstantProp?.(instant) ?? `${dateText(zonedDateKey(instant, timeZone), "day")} ${zonedTimeOfDay(instant, timeZone)}`;
76
140
  const gridRef = useRef(null);
141
+ const picksGiven = dayEntries !== void 0;
142
+ const controlled = picksGiven || dayInfo !== void 0;
143
+ const fixed = controlled || maxEntriesPerDay !== void 0 && onShowMore !== void 0;
144
+ const windowCap = Math.max(0, windowLaneCap ?? (fixed ? DEFAULT_LANE_CAP : Infinity));
145
+ const spanCap = Math.max(0, spanLaneCap ?? (fixed ? DEFAULT_LANE_CAP : Infinity));
77
146
  const visibleEntries = useMemo(() => entries.filter((entry) => filter?.(entry) ?? true), [entries, filter]);
78
- const entrySpans = useMemo(() => new Map(visibleEntries.map((entry) => [entry.id, zonedDateSpan(entry.start, entry.end, timeZone)])), [visibleEntries, timeZone]);
79
- const overlaySpans = useMemo(() => new Map(overlays.map((overlay) => [overlay.id, { start: overlay.start.slice(0, 10), end: overlay.end.slice(0, 10) }])), [overlays]);
80
147
  const monthDays = useMemo(() => buildMonthGrid(startOfMonth(anchorDate), weekStartsOn), [anchorDate, weekStartsOn]);
81
148
  const weekday = (utcDate(anchorDate).getUTCDay() - weekStartsOn + 7) % 7;
82
149
  const weekStart = addCalendarDays(anchorDate, -weekday);
83
150
  const weekDays = useMemo(() => Array.from({ length: 7 }, (_, index) => addCalendarDays(weekStart, index)), [weekStart]);
84
- const days = useMemo(() => view === "month" ? monthDays.map((day) => day.date) : weekDays, [view, monthDays, weekDays]);
151
+ const days = useMemo(() => view === "month" ? monthDays.map((day) => day.date) : view === "day" ? [anchorDate] : weekDays, [view, monthDays, weekDays, anchorDate]);
152
+ const timeGridView = view === "day" || view === "week" && timeGrid;
153
+ const { singles, multiDay, coverage } = useMemo(() => {
154
+ const byDay = /* @__PURE__ */ new Map();
155
+ const spans = [];
156
+ const every = [];
157
+ for (const entry of visibleEntries) {
158
+ const covered = coveredDays(entry.start, entry.end, timeZone);
159
+ every.push({ entry, ...covered });
160
+ if (addCalendarDays(covered.start, 1) === covered.end) {
161
+ const list = byDay.get(covered.start);
162
+ if (list) list.push(entry);
163
+ else byDay.set(covered.start, [entry]);
164
+ } else spans.push({ entry, ...covered });
165
+ }
166
+ return { singles: byDay, multiDay: spans, coverage: every };
167
+ }, [visibleEntries, timeZone]);
168
+ const entryById = useMemo(() => new Map([...multiDay].reverse().map(({ entry }) => [entry.id, entry])), [multiDay]);
169
+ const overlayById = useMemo(() => new Map([...overlays].reverse().map((overlay) => [overlay.id, overlay])), [overlays]);
170
+ const layout = useMemo(() => {
171
+ if (spanLayout) return spanLayout;
172
+ if (view === "agenda" || timeGridView) return { placed: [], hiddenByRow: {}, firstHiddenDayByRow: {} };
173
+ const inputs = [];
174
+ const windowIds = /* @__PURE__ */ new Set();
175
+ const itemIds = /* @__PURE__ */ new Set();
176
+ for (const overlay of overlays) {
177
+ if (windowIds.has(overlay.id) || !(new Date(overlay.end).getTime() >= new Date(overlay.start).getTime())) continue;
178
+ windowIds.add(overlay.id);
179
+ inputs.push({ id: overlay.id, start: overlay.start, end: overlay.end, group: "window" });
180
+ }
181
+ for (const { entry } of multiDay) {
182
+ if (itemIds.has(entry.id)) continue;
183
+ itemIds.add(entry.id);
184
+ inputs.push({ id: entry.id, start: entry.start, end: entry.end, group: "item" });
185
+ }
186
+ return layoutMonthSpans(inputs, days, { timeZone, laneCap: { window: windowCap, item: spanCap } });
187
+ }, [spanLayout, view, timeGridView, overlays, multiDay, days, timeZone, windowCap, spanCap]);
188
+ const placedByRow = useMemo(() => {
189
+ const rows = /* @__PURE__ */ new Map();
190
+ for (const placed of layout.placed) {
191
+ const row = rows.get(placed.weekRow);
192
+ if (row) row.push(placed);
193
+ else rows.set(placed.weekRow, [placed]);
194
+ }
195
+ return rows;
196
+ }, [layout]);
197
+ const lanesUsed = (row, group) => (placedByRow.get(row) ?? []).reduce((max, placed) => placed.group === group ? Math.max(max, placed.lane + 1) : max, 0);
198
+ const lanesUsedAnywhere = (group) => layout.placed.reduce((max, placed) => placed.group === group ? Math.max(max, placed.lane + 1) : max, 0);
85
199
  useEffect(() => {
86
200
  if (view !== "agenda" && !days.includes(activeDate)) setActiveDate(days[0]);
87
201
  }, [activeDate, days, view]);
@@ -89,7 +203,11 @@ function SchedulingCalendar({
89
203
  if (controlledView === void 0) setInternalView(next);
90
204
  onViewChange?.(next);
91
205
  };
92
- const movePeriod = (direction) => onAnchorDateChange?.(view === "month" ? addCalendarMonths(anchorDate, direction) : addCalendarDays(anchorDate, direction * 7));
206
+ const movePeriod = (direction) => onAnchorDateChange?.(view === "month" ? addCalendarMonths(anchorDate, direction) : addCalendarDays(anchorDate, view === "day" ? direction : direction * 7));
207
+ const periodLabel = (direction) => {
208
+ const key = `${direction}${view === "month" ? "Month" : view === "day" ? "Day" : "Week"}`;
209
+ return overrides[key] ?? overrides[direction] ?? labels[key];
210
+ };
93
211
  const focusDate = (date) => {
94
212
  setActiveDate(date);
95
213
  requestAnimationFrame(() => gridRef.current?.querySelector(`[data-calendar-date="${date}"]`)?.focus());
@@ -107,18 +225,10 @@ function SchedulingCalendar({
107
225
  focusDate(days[days.length - 1]);
108
226
  }
109
227
  };
110
- const entriesFor = (date) => visibleEntries.filter((entry) => {
111
- const span = entrySpans.get(entry.id);
112
- return date >= span.start && date <= span.end;
113
- });
114
- const overlaysFor = (date) => overlays.filter((overlay) => {
115
- const span = overlaySpans.get(overlay.id);
116
- return date >= span.start && date <= span.end;
117
- });
118
- const formatInstant = (instant) => formatInstantProp?.(instant) ?? new Intl.DateTimeFormat(locale, { timeZone, dateStyle: "medium", timeStyle: "short" }).format(new Date(instant));
119
- const toggleMore = (date, dayEntries) => {
228
+ const entriesOn = (date) => coverage.filter((covered) => date >= covered.start && date < covered.end).map((covered) => covered.entry);
229
+ const toggleMore = (date, all) => {
120
230
  if (onShowMore) {
121
- onShowMore(date, dayEntries);
231
+ onShowMore(date, all);
122
232
  return;
123
233
  }
124
234
  setExpandedDates((current) => {
@@ -128,21 +238,129 @@ function SchedulingCalendar({
128
238
  return next;
129
239
  });
130
240
  };
241
+ const statusOf = (entry) => entry.status ?? (entry.state === "in-progress" ? "live" : "committed");
242
+ const markersOf = (entry) => {
243
+ const flagged = entry.state === "conflicted" || entry.state === "blackout-violation";
244
+ return flagged ? [...entry.markers ?? [], { id: "state", label: stateLabel[entry.state], emphasis: "warning" }] : entry.markers ?? [];
245
+ };
246
+ const stateText = (entry) => entry.state ? stateLabel[entry.state] : entry.status ? labels.statuses[entry.status] : stateLabel.scheduled;
247
+ const entryName = (entry) => entry.accessibleName ?? [fillLabel(labels.entry, { title: entry.title, state: stateText(entry), start: formatInstant(entry.start), end: formatInstant(entry.end) }), ...(entry.markers ?? []).map((marker) => marker.label)].join(", ");
248
+ const overlayName = (overlay) => overlay.accessibleName ?? fillLabel(labels.overlay, { title: [overlay.kindLabel, overlay.label, overlay.scopeLabel].filter(Boolean).join(", "), start: formatInstant(overlay.start), end: formatInstant(overlay.end) });
249
+ const entryProps = (entry) => ({
250
+ type: "button",
251
+ "data-item-id": entry.id,
252
+ "data-band": entry.band ?? "none",
253
+ "data-status": statusOf(entry),
254
+ "data-state": entry.state,
255
+ onClick: () => onSelectEntry?.(entry),
256
+ "aria-label": entryName(entry)
257
+ });
258
+ const entryContent = (entry, withTime = true) => {
259
+ const markers = markersOf(entry);
260
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
261
+ /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__entry-text", children: renderEntry?.(entry) ?? /* @__PURE__ */ jsxs(Fragment, { children: [
262
+ withTime && /* @__PURE__ */ jsxs(Fragment, { children: [
263
+ /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__time", children: zonedTimeOfDay(entry.start, timeZone) }),
264
+ " "
265
+ ] }),
266
+ /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__title", children: entry.title })
267
+ ] }) }),
268
+ markers.length > 0 && /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__markers", children: markers.map((marker) => /* @__PURE__ */ jsx(Marker, { marker }, marker.id)) })
269
+ ] });
270
+ };
271
+ const laneStyle = (placed, windowLanes) => ({
272
+ gridColumn: `${placed.startCol + 1} / ${placed.endCol + 2}`,
273
+ ["--uix-scheduling-calendar-lane"]: placed.group === "window" ? placed.lane : windowLanes + placed.lane
274
+ });
275
+ const nothingToShow = visibleEntries.length === 0 && !Object.values(dayEntries ?? {}).some((list) => list.length > 0) && !Object.values(dayInfo ?? {}).some((day) => day.count > 0);
276
+ const chipRows = Math.max(0, maxEntriesPerDay ?? DEFAULT_CHIP_ROWS, ...Object.values(dayEntries ?? {}).map((list) => list.length));
277
+ const renderDay = (date, index) => {
278
+ const info = dayInfo?.[date];
279
+ const all = picksGiven ? dayEntries[date] ?? EMPTY_ENTRIES : singles.get(date) ?? EMPTY_ENTRIES;
280
+ const overflowing = !picksGiven && maxEntriesPerDay !== void 0 && all.length > maxEntriesPerDay;
281
+ const collapsed = overflowing && (controlled || onShowMore !== void 0 || !expandedDates.has(date));
282
+ const shown = collapsed ? all.slice(0, Math.max(0, maxEntriesPerDay)) : all;
283
+ const hiddenCount = info ? info.overflowCount : picksGiven ? 0 : all.length - shown.length;
284
+ const onDay = picksGiven ? all : entriesOn(date);
285
+ const badge = renderDayBadge?.(date, onDay);
286
+ const hasBadge = badge != null && badge !== false;
287
+ const dateButton = /* @__PURE__ */ jsx("button", { type: "button", className: "uix-scheduling-calendar__date", "data-calendar-date": date, tabIndex: activeDate === date ? 0 : -1, onFocus: () => setActiveDate(date), onKeyDown: (event) => onDayKeyDown(event, date), onClick: onSelectDate ? () => onSelectDate(date) : void 0, "aria-label": dateText(date, "day"), children: Number(date.slice(-2)) });
288
+ const moreText = fillLabel(labels.moreEntries, { count: hiddenCount });
289
+ const moreName = fillLabel(labels.moreEntriesLabel, { count: hiddenCount, date: dateText(date, "day") });
290
+ return /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__day", "data-outside": view === "month" && !monthDays[index].inMonth || void 0, children: [
291
+ hasBadge || info ? /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__dayhead", children: [
292
+ hasBadge && /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__badge", children: badge }),
293
+ info && /* @__PURE__ */ jsxs("span", { className: "uix-scheduling-calendar__count", children: [
294
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: info.count }),
295
+ /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: info.label ?? fillLabel(labels.dayCount, { count: info.count }) })
296
+ ] }),
297
+ info?.markers && info.markers.length > 0 && /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__markers", children: info.markers.map((marker) => /* @__PURE__ */ jsx(Marker, { marker }, marker.id)) }),
298
+ dateButton
299
+ ] }) : dateButton,
300
+ /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__entries", children: [
301
+ shown.map((entry) => /* @__PURE__ */ jsx("button", { className: "uix-scheduling-calendar__entry", ...entryProps(entry), children: entryContent(entry) }, entry.id)),
302
+ controlled ? hiddenCount > 0 && (onShowMore ? /* @__PURE__ */ jsx("button", { type: "button", className: "uix-scheduling-calendar__more", "aria-label": moreName, onClick: () => onShowMore(date, onDay), children: moreText }) : /* @__PURE__ */ jsxs("span", { className: "uix-scheduling-calendar__more", children: [
303
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: moreText }),
304
+ /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: moreName })
305
+ ] })) : overflowing && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-scheduling-calendar__more", "aria-expanded": onShowMore ? void 0 : !collapsed, "aria-label": collapsed ? moreName : void 0, onClick: () => toggleMore(date, onDay), children: collapsed ? moreText : labels.fewerEntries })
306
+ ] })
307
+ ] }, date);
308
+ };
309
+ const renderWeek = (row) => {
310
+ const rowDays = days.slice(row * 7, row * 7 + 7);
311
+ const windowLanes = lanesUsed(row, "window");
312
+ const spanLanes = lanesUsed(row, "item");
313
+ const hidden = layout.hiddenByRow?.[row]?.length ?? 0;
314
+ const firstHiddenDay = layout.firstHiddenDayByRow?.[row] ?? rowDays[0];
315
+ const moreText = fillLabel(labels.moreSpans, { count: hidden });
316
+ const moreName = fillLabel(labels.moreSpansLabel, { count: hidden, date: dateText(firstHiddenDay, "day") });
317
+ const style = { ["--uix-scheduling-calendar-lanes"]: Math.max(windowLanes + spanLanes, hidden > 0 ? 1 : 0) };
318
+ return /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__week", style, children: [
319
+ rowDays.map((date, column) => renderDay(date, row * 7 + column)),
320
+ (placedByRow.get(row) ?? []).map((placed) => {
321
+ const continues = { "data-continues-before": placed.continuesBefore || void 0, "data-continues-after": placed.continuesAfter || void 0 };
322
+ if (placed.group === "window") {
323
+ const overlay = overlayById.get(placed.id);
324
+ if (!overlay) return null;
325
+ return /* @__PURE__ */ jsx("button", { type: "button", className: "uix-scheduling-calendar__window", "data-overlay-id": overlay.id, "data-pattern": overlay.pattern ?? "solid", "data-global": overlay.global || void 0, "data-kind": overlay.kind, ...continues, style: laneStyle(placed, windowLanes), onClick: () => onSelectOverlay?.(overlay), "aria-label": overlayName(overlay), children: /* @__PURE__ */ jsxs("span", { className: "uix-scheduling-calendar__window-text", children: [
326
+ overlay.kindLabel && /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__window-kind", children: overlay.kindLabel }),
327
+ /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__window-name", children: overlay.label }),
328
+ overlay.scopeLabel && /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__window-scope", children: overlay.scopeLabel })
329
+ ] }) }, `window-${placed.id}`);
330
+ }
331
+ const entry = entryById.get(placed.id);
332
+ if (!entry) return null;
333
+ return /* @__PURE__ */ jsx("button", { className: "uix-scheduling-calendar__entry uix-scheduling-calendar__span", ...entryProps(entry), ...continues, style: laneStyle(placed, windowLanes), children: entryContent(entry, !placed.continuesBefore) }, `span-${placed.id}`);
334
+ }),
335
+ hidden > 0 && (onShowMore ? /* @__PURE__ */ jsx("button", { type: "button", className: "uix-scheduling-calendar__rowmore", "aria-label": moreName, onClick: () => onShowMore(firstHiddenDay, picksGiven ? dayEntries[firstHiddenDay] ?? EMPTY_ENTRIES : entriesOn(firstHiddenDay)), children: moreText }) : /* @__PURE__ */ jsxs("span", { className: "uix-scheduling-calendar__rowmore", children: [
336
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: moreText }),
337
+ /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: moreName })
338
+ ] }))
339
+ ] }, rowDays[0]);
340
+ };
341
+ const gridStyle = fixed ? {
342
+ ["--uix-scheduling-calendar-chips"]: chipRows,
343
+ ["--uix-scheduling-calendar-lane-cap"]: Math.max(
344
+ Math.max(Number.isFinite(windowCap) ? windowCap : 0, lanesUsedAnywhere("window")) + Math.max(Number.isFinite(spanCap) ? spanCap : 0, lanesUsedAnywhere("item")),
345
+ Object.keys(layout.hiddenByRow ?? {}).length > 0 ? 1 : 0
346
+ )
347
+ } : void 0;
131
348
  return /* @__PURE__ */ jsxs("section", { className: cx("uix-scheduling-calendar", className), "aria-label": fillLabel(labels.region, { timeZone }), children: [
132
- /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__header", children: [
349
+ showHeader && /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__header", children: [
133
350
  /* @__PURE__ */ jsxs("div", { children: [
134
- /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(-1), disabled: !onAnchorDateChange, children: labels.previous }),
135
- /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(1), disabled: !onAnchorDateChange, children: labels.next })
351
+ /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(-1), disabled: !onAnchorDateChange, children: periodLabel("previous") }),
352
+ /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(1), disabled: !onAnchorDateChange, children: periodLabel("next") })
136
353
  ] }),
137
- /* @__PURE__ */ jsx("strong", { children: view === "month" ? dateText(startOfMonth(anchorDate), "month") : `${dateText(weekStart, "day")} \u2013 ${dateText(weekDays[weekDays.length - 1], "day")}` }),
138
- /* @__PURE__ */ jsx("div", { className: "uix-segmented", role: "group", "aria-label": labels.viewGroup, children: ["month", "week", "agenda"].map((option) => /* @__PURE__ */ jsx("button", { type: "button", className: "uix-segmented__option", "aria-pressed": view === option, "data-selected": view === option || void 0, onClick: () => setView(option), children: viewLabel[option] }, option)) })
354
+ /* @__PURE__ */ jsx("strong", { children: view === "month" ? dateText(startOfMonth(anchorDate), "month") : view === "day" ? dateText(anchorDate, "day") : `${dateText(weekStart, "day")} \u2013 ${dateText(weekDays[weekDays.length - 1], "day")}` }),
355
+ /* @__PURE__ */ jsx("div", { className: "uix-segmented", role: "group", "aria-label": labels.viewGroup, children: (timeGrid || view === "day" ? ["month", "week", "day", "agenda"] : ["month", "week", "agenda"]).map((option) => /* @__PURE__ */ jsx("button", { type: "button", className: "uix-segmented__option", "aria-pressed": view === option, "data-selected": view === option || void 0, onClick: () => setView(option), children: viewLabel[option] }, option)) })
139
356
  ] }),
357
+ notice != null && notice !== false && /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__notice", children: notice }),
140
358
  loading ? /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__state", role: "status", children: labels.loading }) : error ? /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__state", role: "alert", children: [
141
359
  /* @__PURE__ */ jsx("p", { children: error }),
142
360
  onRetry && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: labels.retry })
143
361
  ] }) : view === "agenda" ? /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__agenda", role: "region", "aria-label": labels.agenda, children: visibleEntries.length === 0 ? /* @__PURE__ */ jsx("p", { children: labels.agendaEmpty }) : /* @__PURE__ */ jsx("ol", { children: [...visibleEntries].sort((a, b) => a.start.localeCompare(b.start)).map((entry) => {
144
- const state = entry.state ?? "scheduled";
145
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => onSelectEntry?.(entry), children: [
362
+ const markers = markersOf(entry);
363
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("button", { type: "button", "data-item-id": entry.id, "data-band": entry.band ?? "none", "data-status": statusOf(entry), "data-state": entry.state, onClick: () => onSelectEntry?.(entry), children: [
146
364
  /* @__PURE__ */ jsxs("span", { children: [
147
365
  /* @__PURE__ */ jsx("strong", { children: renderEntry?.(entry) ?? entry.title }),
148
366
  /* @__PURE__ */ jsxs("span", { children: [
@@ -152,40 +370,58 @@ function SchedulingCalendar({
152
370
  ] }),
153
371
  entry.meta && /* @__PURE__ */ jsx("span", { children: entry.meta })
154
372
  ] }),
155
- /* @__PURE__ */ jsx(StatusPill, { tone: stateTone(state), children: stateLabel[state] })
373
+ markers.length > 0 && /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__markers", children: markers.map((marker) => /* @__PURE__ */ jsx(Marker, { marker }, marker.id)) }),
374
+ entry.state ? /* @__PURE__ */ jsx(StatusPill, { tone: stateTone(entry.state), children: stateLabel[entry.state] }) : /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__status", children: stateText(entry) })
156
375
  ] }) }, entry.id);
157
- }) }) }) : /* @__PURE__ */ jsxs("div", { ref: gridRef, className: cx("uix-scheduling-calendar__grid", view === "week" && "uix-scheduling-calendar__grid--week"), role: "group", "aria-label": fillLabel(labels.grid, { view: viewLabel[view] }), children: [
376
+ }) }) }) : timeGridView ? /* @__PURE__ */ jsx(
377
+ SchedulingTimeGrid,
378
+ {
379
+ view: view === "day" ? "day" : "week",
380
+ days,
381
+ timeZone,
382
+ entries: visibleEntries,
383
+ overlays,
384
+ dayInfo,
385
+ labels,
386
+ gridLabel: fillLabel(labels.grid, { view: viewLabel[view] }),
387
+ dateText,
388
+ formatInstant,
389
+ entryName,
390
+ entryStatus: statusOf,
391
+ entryMarkers: markersOf,
392
+ overlayName,
393
+ renderEntry,
394
+ renderMarker,
395
+ onSelectEntry,
396
+ onSelectOverlay,
397
+ onSelectDate,
398
+ onShowMore,
399
+ now,
400
+ canMove,
401
+ step,
402
+ onProposeMove,
403
+ topLaneCrossMidnightMinutes,
404
+ topLaneCap,
405
+ windowLaneCap: windowLaneCap ?? DEFAULT_LANE_CAP,
406
+ maxLanes,
407
+ emptyNote,
408
+ nothingToShow
409
+ }
410
+ ) : /* @__PURE__ */ jsxs("div", { ref: gridRef, className: cx("uix-scheduling-calendar__grid", view === "week" && "uix-scheduling-calendar__grid--week"), "data-fixed": fixed || void 0, style: gridStyle, role: "group", "aria-label": fillLabel(labels.grid, { view: viewLabel[view] }), children: [
158
411
  days.slice(0, 7).map((date) => /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__weekday", "aria-hidden": "true", children: dateText(date, "weekday") }, `weekday-${date}`)),
159
- days.map((date, index) => {
160
- const dayEntries = entriesFor(date);
161
- const dayOverlays = overlaysFor(date);
162
- const overflowing = maxEntriesPerDay !== void 0 && dayEntries.length > maxEntriesPerDay;
163
- const collapsed = overflowing && (onShowMore !== void 0 || !expandedDates.has(date));
164
- const shownEntries = collapsed ? dayEntries.slice(0, Math.max(0, maxEntriesPerDay)) : dayEntries;
165
- const hiddenCount = dayEntries.length - shownEntries.length;
166
- const badge = renderDayBadge?.(date, dayEntries);
167
- const dateButton = /* @__PURE__ */ jsx("button", { type: "button", className: "uix-scheduling-calendar__date", "data-calendar-date": date, tabIndex: activeDate === date ? 0 : -1, onFocus: () => setActiveDate(date), onKeyDown: (event) => onDayKeyDown(event, date), "aria-label": dateText(date, "day"), children: Number(date.slice(-2)) });
168
- return /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__day", "data-outside": view === "month" && !monthDays[index].inMonth || void 0, children: [
169
- badge == null || badge === false ? dateButton : /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__dayhead", children: [
170
- /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__badge", children: badge }),
171
- dateButton
172
- ] }),
173
- dayOverlays.map((overlay) => /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__overlay", "data-kind": overlay.kind, children: overlay.label }, overlay.id)),
174
- /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__entries", children: [
175
- shownEntries.map((entry) => {
176
- const span = entrySpans.get(entry.id);
177
- const state = entry.state ?? "scheduled";
178
- return /* @__PURE__ */ jsxs("button", { type: "button", className: "uix-scheduling-calendar__entry", "data-state": state, "data-range-start": date === span.start || void 0, "data-range-end": date === span.end || void 0, onClick: () => onSelectEntry?.(entry), "aria-label": fillLabel(labels.entry, { title: entry.title, state: stateLabel[state], start: formatInstant(entry.start), end: formatInstant(entry.end) }), children: [
179
- /* @__PURE__ */ jsx("span", { children: renderEntry?.(entry) ?? entry.title }),
180
- /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: stateLabel[state] })
181
- ] }, entry.id);
182
- }),
183
- overflowing && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-scheduling-calendar__more", "aria-expanded": onShowMore ? void 0 : !collapsed, "aria-label": collapsed ? fillLabel(labels.moreEntriesLabel, { count: hiddenCount, date: dateText(date, "day") }) : void 0, onClick: () => toggleMore(date, dayEntries), children: collapsed ? fillLabel(labels.moreEntries, { count: hiddenCount }) : labels.fewerEntries })
184
- ] })
185
- ] }, date);
186
- })
412
+ Array.from({ length: days.length / 7 }, (_, row) => renderWeek(row)),
413
+ emptyNote != null && emptyNote !== false && nothingToShow && /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__empty", children: emptyNote })
187
414
  ] }),
188
- /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__legend", "aria-label": labels.legend, children: ["scheduled", "conflicted", "in-progress", "blackout-violation"].map((state) => /* @__PURE__ */ jsx("span", { "data-state": state, children: stateLabel[state] }, state)) })
415
+ legend ? (legend.length > 0 || legendCaption != null && legendCaption !== false) && /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__legend", role: "group", "aria-label": labels.legend, children: [
416
+ legend.length > 0 && /* @__PURE__ */ jsx("ul", { className: "uix-scheduling-calendar__legend-list", children: legend.map((item) => /* @__PURE__ */ jsxs("li", { "data-legend-id": item.id, children: [
417
+ /* @__PURE__ */ jsx("span", { className: "uix-scheduling-calendar__swatch", "aria-hidden": "true", "data-band": item.swatch.band, "data-status": item.swatch.status, "data-pattern": item.swatch.pattern, children: item.swatch.icon }),
418
+ item.label
419
+ ] }, item.id)) }),
420
+ legendCaption != null && legendCaption !== false && /* @__PURE__ */ jsx("p", { className: "uix-scheduling-calendar__legend-caption", children: legendCaption })
421
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__legend", role: "group", "aria-label": labels.legend, children: [
422
+ ["scheduled", "conflicted", "in-progress", "blackout-violation"].map((state) => /* @__PURE__ */ jsx("span", { "data-state": state, children: stateLabel[state] }, state)),
423
+ legendCaption != null && legendCaption !== false && /* @__PURE__ */ jsx("p", { className: "uix-scheduling-calendar__legend-caption", children: legendCaption })
424
+ ] })
189
425
  ] });
190
426
  }
191
427
  export {
@@ -0,0 +1,4 @@
1
+ import 'react';
2
+ import '../scheduling-calendar-model.js';
3
+ export { p as SchedulingTimeGrid, q as SchedulingTimeGridProps, T as TimeGridEntryContext } from '../SchedulingCalendar-C4XVbqZr.js';
4
+ import '../calendar-model.js';