@k2b/ui 0.46.0 → 0.48.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 (103) hide show
  1. package/dist/browser/chat/ChatComposer.js +244 -193
  2. package/dist/browser/chat/ChatComposer.js.map +1 -1
  3. package/dist/browser/chat/ChatDecision.js +10 -6
  4. package/dist/browser/chat/ChatDecision.js.map +1 -1
  5. package/dist/browser/chat/chat-messages.js +6 -0
  6. package/dist/browser/chat/chat-messages.js.map +1 -1
  7. package/dist/browser/chat/types.js.map +1 -1
  8. package/dist/browser/content/Calendar.js +40 -5
  9. package/dist/browser/content/Calendar.js.map +1 -1
  10. package/dist/browser/content/VirtualFeed.js +26 -21
  11. package/dist/browser/content/VirtualFeed.js.map +1 -1
  12. package/dist/browser/content/calendar-event-detail.js +328 -0
  13. package/dist/browser/content/calendar-event-detail.js.map +1 -0
  14. package/dist/browser/content/calendar-messages.js +34 -2
  15. package/dist/browser/content/calendar-messages.js.map +1 -1
  16. package/dist/browser/content/calendar-shared.js +189 -82
  17. package/dist/browser/content/calendar-shared.js.map +1 -1
  18. package/dist/browser/content/calendar-time-view.js +101 -96
  19. package/dist/browser/content/calendar-time-view.js.map +1 -1
  20. package/dist/browser/content/index.js.map +1 -1
  21. package/dist/browser/inputs/Combobox.js +14 -6
  22. package/dist/browser/inputs/Combobox.js.map +1 -1
  23. package/dist/browser/inputs/dictation/Dictation.js +114 -108
  24. package/dist/browser/inputs/dictation/Dictation.js.map +1 -1
  25. package/dist/browser/inputs/dictation/dictation-messages.js +2 -0
  26. package/dist/browser/inputs/dictation/dictation-messages.js.map +1 -1
  27. package/dist/browser/layout/AnchoredPopover.js +2 -1
  28. package/dist/browser/layout/AnchoredPopover.js.map +1 -1
  29. package/dist/browser/layout/AppWorkspace.js +340 -440
  30. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  31. package/dist/browser/layout/AppWorkspaceSidebarItemStatus.js +113 -0
  32. package/dist/browser/layout/AppWorkspaceSidebarItemStatus.js.map +1 -0
  33. package/dist/browser/layout/DetailPanel.js +1 -1
  34. package/dist/browser/layout/DetailPanel.js.map +1 -1
  35. package/dist/browser/layout/DetailSections.js +236 -132
  36. package/dist/browser/layout/DetailSections.js.map +1 -1
  37. package/dist/browser/layout/MobileShell.js +30 -13
  38. package/dist/browser/layout/MobileShell.js.map +1 -1
  39. package/dist/browser/layout/detail-sections-messages.js +4 -0
  40. package/dist/browser/layout/detail-sections-messages.js.map +1 -1
  41. package/dist/browser/layout/index.js +1 -0
  42. package/dist/browser/layout/index.js.map +1 -1
  43. package/dist/ssr/chat/ChatComposer.js +53 -30
  44. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  45. package/dist/ssr/chat/ChatDecision.js +10 -6
  46. package/dist/ssr/chat/ChatDecision.js.map +1 -1
  47. package/dist/ssr/chat/chat-messages.js +6 -0
  48. package/dist/ssr/chat/chat-messages.js.map +1 -1
  49. package/dist/ssr/chat/types.js.map +1 -1
  50. package/dist/ssr/content/Calendar.js +36 -4
  51. package/dist/ssr/content/Calendar.js.map +1 -1
  52. package/dist/ssr/content/VirtualFeed.js +26 -21
  53. package/dist/ssr/content/VirtualFeed.js.map +1 -1
  54. package/dist/ssr/content/calendar-event-detail.js +212 -0
  55. package/dist/ssr/content/calendar-event-detail.js.map +1 -0
  56. package/dist/ssr/content/calendar-messages.js +34 -2
  57. package/dist/ssr/content/calendar-messages.js.map +1 -1
  58. package/dist/ssr/content/calendar-shared.js +117 -36
  59. package/dist/ssr/content/calendar-shared.js.map +1 -1
  60. package/dist/ssr/content/calendar-time-view.js +6 -4
  61. package/dist/ssr/content/calendar-time-view.js.map +1 -1
  62. package/dist/ssr/content/index.js.map +1 -1
  63. package/dist/ssr/inputs/Combobox.js +6 -3
  64. package/dist/ssr/inputs/Combobox.js.map +1 -1
  65. package/dist/ssr/inputs/dictation/Dictation.js +3 -1
  66. package/dist/ssr/inputs/dictation/Dictation.js.map +1 -1
  67. package/dist/ssr/inputs/dictation/dictation-messages.js +2 -0
  68. package/dist/ssr/inputs/dictation/dictation-messages.js.map +1 -1
  69. package/dist/ssr/layout/AnchoredPopover.js +2 -1
  70. package/dist/ssr/layout/AnchoredPopover.js.map +1 -1
  71. package/dist/ssr/layout/AppWorkspace.js +61 -127
  72. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  73. package/dist/ssr/layout/AppWorkspaceSidebarItemStatus.js +76 -0
  74. package/dist/ssr/layout/AppWorkspaceSidebarItemStatus.js.map +1 -0
  75. package/dist/ssr/layout/DetailPanel.js +1 -1
  76. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  77. package/dist/ssr/layout/DetailSections.js +126 -50
  78. package/dist/ssr/layout/DetailSections.js.map +1 -1
  79. package/dist/ssr/layout/MobileShell.js +16 -2
  80. package/dist/ssr/layout/MobileShell.js.map +1 -1
  81. package/dist/ssr/layout/detail-sections-messages.js +4 -0
  82. package/dist/ssr/layout/detail-sections-messages.js.map +1 -1
  83. package/dist/ssr/layout/index.js +1 -0
  84. package/dist/ssr/layout/index.js.map +1 -1
  85. package/dist/styles.css +1 -1
  86. package/dist/types/chat/ChatDecision.d.ts +5 -0
  87. package/dist/types/chat/chat-messages.d.ts +3 -0
  88. package/dist/types/chat/types.d.ts +5 -0
  89. package/dist/types/content/Calendar.d.ts +29 -5
  90. package/dist/types/content/calendar-event-detail.d.ts +21 -0
  91. package/dist/types/content/calendar-messages.d.ts +16 -0
  92. package/dist/types/content/calendar-shared.d.ts +16 -1
  93. package/dist/types/content/calendar-time-view.d.ts +1 -1
  94. package/dist/types/content/index.d.ts +1 -1
  95. package/dist/types/inputs/Combobox.d.ts +2 -0
  96. package/dist/types/inputs/dictation/dictation-messages.d.ts +1 -0
  97. package/dist/types/layout/AppWorkspace.d.ts +2 -28
  98. package/dist/types/layout/AppWorkspaceSidebarItemStatus.d.ts +30 -0
  99. package/dist/types/layout/DetailSections.d.ts +32 -2
  100. package/dist/types/layout/MobileShell.d.ts +12 -0
  101. package/dist/types/layout/detail-sections-messages.d.ts +2 -0
  102. package/dist/types/layout/index.d.ts +1 -0
  103. package/package.json +1 -1
@@ -4,17 +4,20 @@ import { memo as _$memo } from "solid-js/web";
4
4
  import { createComponent as _$createComponent } from "solid-js/web";
5
5
  import { ssr as _$ssr } from "solid-js/web";
6
6
  import { escape as _$escape } from "solid-js/web";
7
- var _tmpl$ = ["<span class=\"k2b-calendar-event__time\">", "</span>"],
8
- _tmpl$2 = "<span class=\"k2b-calendar-event__marker\" aria-hidden=\"true\"></span>",
9
- _tmpl$3 = ["<span class=\"k2b-calendar-event__title\">", "", "</span>"],
10
- _tmpl$4 = ["<span class=\"k2b-calendar-event__remaining\">", "</span>"],
11
- _tmpl$5 = ["<span class=\"k2b-calendar-event__meta\">", "", "</span>"],
12
- _tmpl$6 = ["<span class=\"k2b-calendar-event__meta\">", "</span>"],
13
- _tmpl$7 = ["<span class=\"k2b-calendar-event__description\">", "</span>"],
14
- _tmpl$8 = ["<span class=\"k2b-calendar-event__hint\" data-edge=\"start\" aria-hidden=\"true\">", "</span>"],
15
- _tmpl$9 = ["<span class=\"k2b-calendar-event__hint\" data-edge=\"end\" aria-hidden=\"true\">", "</span>"];
7
+ var _tmpl$ = ["<i class=\"", "\" aria-hidden=\"true\"></i>"],
8
+ _tmpl$2 = ["<span class=\"k2b-calendar-event__remaining\">", "</span>"],
9
+ _tmpl$3 = ["<span class=\"k2b-calendar-event__links\"><i class=\"ti ti-link\"></i>", "</span>"],
10
+ _tmpl$4 = ["<span class=\"k2b-calendar-event__extras\" aria-hidden=\"true\">", "", "</span>"],
11
+ _tmpl$5 = ["<span class=\"k2b-calendar-event__time\">", "</span>"],
12
+ _tmpl$6 = ["<span class=\"k2b-calendar-event__title\">", "", "</span>"],
13
+ _tmpl$7 = ["<span class=\"k2b-calendar-event__meta\">", "</span>"],
14
+ _tmpl$8 = ["<span class=\"k2b-calendar-event__row\">", "", "</span>"],
15
+ _tmpl$9 = ["<span class=\"k2b-calendar-event__description\">", "</span>"],
16
+ _tmpl$0 = ["<span class=\"k2b-calendar-event__hint\" data-edge=\"start\" aria-hidden=\"true\">", "</span>"],
17
+ _tmpl$1 = ["<span class=\"k2b-calendar-event__hint\" data-edge=\"end\" aria-hidden=\"true\">", "</span>"];
16
18
  import { dates as calendar } from "@k2b/stdlib";
17
19
  import { createMemo, Show } from "solid-js";
20
+ import { AvatarFaces } from "../surfaces/AvatarStack";
18
21
  import { useCalendarMessages } from "./calendar-messages";
19
22
 
20
23
  /** One piece of an event in one day, with the times of the whole event. */
@@ -23,6 +26,24 @@ import { useCalendarMessages } from "./calendar-messages";
23
26
 
24
27
  /** What the built-in views read from the props: they only ever link to built-in views. */
25
28
 
29
+ /** `data` keys the calendar writes as `data-*` attributes: camelCase letters and digits, none of the calendar's own. */
30
+ const DATA_KEY = /^[a-z][a-zA-Z0-9]*$/;
31
+ export const eventDataAttributes = data => {
32
+ const attributes = {};
33
+ for (const [key, value] of Object.entries(data ?? {})) {
34
+ if (!DATA_KEY.test(key) || key.startsWith("calendar") || typeof value !== "string") continue;
35
+ attributes[`data-${key.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)}`] = value;
36
+ }
37
+ return attributes;
38
+ };
39
+
40
+ /** An open to-do or deadline whose time has passed. */
41
+ export const isOverdue = (event, now) => {
42
+ if (event.checked !== false || !now) return false;
43
+ const start = event.sourceStartDate?.getTime() ?? Number.NaN;
44
+ const end = event.sourceEndDate?.getTime() ?? start;
45
+ return Math.max(start, end) <= now.getTime();
46
+ };
26
47
  export const ownerDateConfig = owner => ({
27
48
  ...owner.dateConfig,
28
49
  timeZone: owner.timeZone ?? owner.dateConfig?.timeZone,
@@ -69,7 +90,15 @@ export const EventChip = props => {
69
90
  const style = () => props.event.colorHex ? {
70
91
  "--k2b-calendar-accent": props.event.colorHex
71
92
  } : undefined;
72
- const isInteractive = () => Boolean(props.owner.onEventActivate);
93
+ const activate = anchor => {
94
+ if (props.owner.onEventActivate) props.owner.onEventActivate(props.event);else props.owner.openEventDetail?.(props.event, anchor);
95
+ };
96
+ const isInteractive = () => Boolean(props.owner.onEventActivate ?? props.owner.openEventDetail);
97
+ const done = () => props.event.checked === true;
98
+ const overdue = () => isOverdue(props.event, props.owner.calendarNow?.());
99
+ const attendees = () => props.event.attendees ?? [];
100
+ const links = () => props.event.links ?? [];
101
+ const shownFaces = () => props.faces ? attendees().slice(0, props.faces) : [];
73
102
  const durationHours = () => (props.event.endDate.getTime() - props.event.startDate.getTime()) / 3_600_000;
74
103
  const short = () => Boolean(props.fill && !props.event.allDay && durationHours() < 0.75);
75
104
  const showTime = () => props.timeLabel ? !props.event.allDay : !props.event.allDay && !props.compact && durationHours() >= 0.75;
@@ -84,7 +113,11 @@ export const EventChip = props => {
84
113
  start: formatTime(props.event.startDate, dateConfig()),
85
114
  end: formatTime(props.event.endDate, dateConfig())
86
115
  });
87
- return [label, props.remaining, props.event.accessibleDetail].filter(Boolean).join(", ");
116
+ return [label, props.remaining, done() ? messages().calendarStateDone : overdue() ? messages().calendarStateOverdue : undefined, attendees().length ? messages().calendarPeopleCount({
117
+ count: attendees().length
118
+ }) : undefined, links().length ? messages().calendarLinkCount({
119
+ count: links().length
120
+ }) : undefined, props.event.accessibleDetail].filter(Boolean).join(", ");
88
121
  };
89
122
  const renderedEvent = () => props.owner.renderEvent?.(props.event, {
90
123
  compact: props.compact ?? false,
@@ -99,54 +132,100 @@ export const EventChip = props => {
99
132
  checkbox: props.checkbox ?? false,
100
133
  timeline: props.timeline ?? false
101
134
  });
135
+ // Faces and the link count only take room the title and time leave; they carry no text of their own.
136
+ const icon = () => props.event.icon ? _$ssr(_tmpl$, `k2b-calendar-event__icon ${_$escape(props.event.icon, true)}`) : undefined;
137
+ const metaText = () => [_$createComponent(Show, {
138
+ get when() {
139
+ return showTime();
140
+ },
141
+ get children() {
142
+ return timeLabel();
143
+ }
144
+ }), _$createComponent(Show, {
145
+ get when() {
146
+ return props.remaining;
147
+ },
148
+ get children() {
149
+ return _$ssr(_tmpl$2, showTime() ? ` · ${_$escape(props.remaining)}` : _$escape(props.remaining));
150
+ }
151
+ })];
152
+ const hasExtras = () => shownFaces().length > 0 || Boolean(props.linkCount && links().length > 0);
153
+ const extras = () => hasExtras() ? _$ssr(_tmpl$4, _$escape(_$createComponent(Show, {
154
+ get when() {
155
+ return shownFaces().length > 0;
156
+ },
157
+ get children() {
158
+ return _$createComponent(AvatarFaces, {
159
+ get people() {
160
+ return shownFaces();
161
+ },
162
+ get total() {
163
+ return _$memo(() => (props.faces ?? 0) > 1)() ? attendees().length : undefined;
164
+ },
165
+ get max() {
166
+ return props.faces;
167
+ }
168
+ });
169
+ }
170
+ })), _$escape(_$createComponent(Show, {
171
+ get when() {
172
+ return _$memo(() => !!props.linkCount)() && links().length > 0;
173
+ },
174
+ get children() {
175
+ return _$ssr(_tmpl$3, _$escape(links().length));
176
+ }
177
+ }))) : undefined;
102
178
  const defaultContent = [_$createComponent(Show, {
103
179
  get when() {
104
180
  return props.leadingTime;
105
181
  },
106
182
  get children() {
107
- return _$ssr(_tmpl$, _$escape(props.leadingTime));
183
+ return [icon(), _$ssr(_tmpl$5, _$escape(props.leadingTime))];
108
184
  }
109
- }), _$ssr(_tmpl$3, _$escape(_$createComponent(Show, {
185
+ }), _$ssr(_tmpl$6, _$escape(_$createComponent(Show, {
110
186
  get when() {
111
- return _$memo(() => props.event.display === "marker")() && !props.checkbox;
187
+ return !props.leadingTime;
112
188
  },
113
189
  get children() {
114
- return _$ssr(_tmpl$2);
190
+ return icon();
115
191
  }
116
192
  })), _$escape(props.event.title)), _$createComponent(Show, {
117
193
  get when() {
118
- return showTime() || props.remaining;
194
+ return hasExtras();
119
195
  },
120
- get children() {
121
- return _$ssr(_tmpl$5, _$escape(_$createComponent(Show, {
196
+ get fallback() {
197
+ return _$createComponent(Show, {
122
198
  get when() {
123
- return showTime();
199
+ return showTime() || props.remaining;
124
200
  },
125
201
  get children() {
126
- return timeLabel();
202
+ return _$ssr(_tmpl$7, _$escape(metaText()));
127
203
  }
128
- })), _$escape(_$createComponent(Show, {
204
+ });
205
+ },
206
+ get children() {
207
+ return _$ssr(_tmpl$8, _$escape(_$createComponent(Show, {
129
208
  get when() {
130
- return props.remaining;
209
+ return showTime() || props.remaining;
131
210
  },
132
211
  get children() {
133
- return _$ssr(_tmpl$4, showTime() ? ` · ${_$escape(props.remaining)}` : _$escape(props.remaining));
212
+ return _$ssr(_tmpl$7, _$escape(metaText()));
134
213
  }
135
- })));
214
+ })), _$escape(extras()));
136
215
  }
137
216
  }), _$createComponent(Show, {
138
217
  get when() {
139
218
  return showLocation();
140
219
  },
141
220
  get children() {
142
- return _$ssr(_tmpl$6, _$escape(props.event.location));
221
+ return _$ssr(_tmpl$7, _$escape(props.event.location));
143
222
  }
144
223
  }), _$createComponent(Show, {
145
224
  get when() {
146
225
  return showDescription();
147
226
  },
148
227
  get children() {
149
- return _$ssr(_tmpl$7, _$escape(props.event.description));
228
+ return _$ssr(_tmpl$9, _$escape(props.event.description));
150
229
  }
151
230
  })];
152
231
  const content = () => [_$createComponent(Show, {
@@ -154,14 +233,14 @@ export const EventChip = props => {
154
233
  return props.hintStart;
155
234
  },
156
235
  get children() {
157
- return _$ssr(_tmpl$8, _$escape(props.hintStart));
236
+ return _$ssr(_tmpl$0, _$escape(props.hintStart));
158
237
  }
159
238
  }), renderedEvent() ?? defaultContent, _$createComponent(Show, {
160
239
  get when() {
161
240
  return props.hintEnd;
162
241
  },
163
242
  get children() {
164
- return _$ssr(_tmpl$9, _$escape(props.hintEnd));
243
+ return _$ssr(_tmpl$1, _$escape(props.hintEnd));
165
244
  }
166
245
  }), props.trailing];
167
246
  const isActionable = () => isInteractive() || Boolean(props.onMovePointerDown);
@@ -172,16 +251,18 @@ export const EventChip = props => {
172
251
  event.stopPropagation();
173
252
  return;
174
253
  }
175
- if (!props.owner.onEventActivate || props.owner.eventActivation === "double") return;
254
+ if (!isInteractive() || props.owner.eventActivation === "double") return;
255
+ // A link with a modifier or another button still opens where the reader asked, such as in a new tab.
256
+ if (props.href && (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)) return;
176
257
  event.preventDefault();
177
258
  event.stopPropagation();
178
- props.owner.onEventActivate(props.event);
259
+ activate(event.currentTarget);
179
260
  };
180
261
  const onDoubleClick = event => {
181
- if (!props.owner.onEventActivate || props.owner.eventActivation !== "double") return;
262
+ if (!isInteractive() || props.owner.eventActivation !== "double") return;
182
263
  event.preventDefault();
183
264
  event.stopPropagation();
184
- props.owner.onEventActivate(props.event);
265
+ activate(event.currentTarget);
185
266
  };
186
267
  /** Space on an entry with a box checks it; Enter still opens the entry. */
187
268
  const onCheckKeyDown = event => {
@@ -193,7 +274,7 @@ export const EventChip = props => {
193
274
  const onButtonKeyDown = event => {
194
275
  if (onCheckKeyDown(event) || !isInteractive() || event.key !== "Enter" && event.key !== " ") return;
195
276
  event.preventDefault();
196
- props.owner.onEventActivate?.(props.event);
277
+ activate(event.currentTarget);
197
278
  };
198
279
  const onPointerDown = event => {
199
280
  if (event.pointerType === "touch") return;
@@ -215,6 +296,9 @@ export const EventChip = props => {
215
296
  "data-continues-after": props.continuesAfter ? "true" : undefined,
216
297
  "data-bar": props.bar ? "true" : undefined,
217
298
  "data-display": props.event.display,
299
+ "data-done": done() ? "true" : undefined,
300
+ "data-overdue": overdue() ? "true" : undefined,
301
+ ...eventDataAttributes(props.event.data),
218
302
  "data-stop": props.stop?.id,
219
303
  "data-col": props.stop?.column,
220
304
  "data-minute": props.stop?.minute,
@@ -228,9 +312,6 @@ export const EventChip = props => {
228
312
  get ["data-interactive"]() {
229
313
  return isInteractive() ? "true" : undefined;
230
314
  },
231
- get ["data-space-item-id"]() {
232
- return props.event.dataSpaceItemId;
233
- },
234
315
  get tabIndex() {
235
316
  return props.tabIndex;
236
317
  },
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["content/calendar-shared.tsx"],"sourcesContent":["import { dates as calendar, type DateContext } from \"@k2b/stdlib\";\nimport type { JSX } from \"solid-js\";\nimport { createMemo, Show } from \"solid-js\";\nimport type { CalendarEvent, CalendarProps } from \"./Calendar\";\nimport { useCalendarMessages } from \"./calendar-messages\";\n\n/** One piece of an event in one day, with the times of the whole event. */\nexport type NormalizedEvent = CalendarEvent & {\n startDate: Date;\n endDate: Date;\n dayKey: string;\n sourceStartDate: Date;\n sourceEndDate: Date;\n};\n\n/** A keyboard stop of the week grid. */\nexport type CalendarStop = { id: string; column: number; minute: number };\n\n/** What the built-in views read from the props: they only ever link to built-in views. */\nexport type CalendarOwner = Omit<CalendarProps, \"view\" | \"customViews\" | \"children\">;\n\nexport const ownerDateConfig = (owner: CalendarOwner): DateContext => ({\n ...owner.dateConfig,\n timeZone: owner.timeZone ?? owner.dateConfig?.timeZone,\n firstDayOfWeek: owner.firstDayOfWeek ?? owner.dateConfig?.firstDayOfWeek ?? owner.dateConfig?.weekStartsOn ?? 1,\n});\n\nconst dateOnlyPattern = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport const parseDate = (value: Date | string, context?: DateContext): Date => {\n if (value instanceof Date) return new Date(value);\n if (dateOnlyPattern.test(value)) return calendar.parseCalendarDate(value, context);\n const normalized = value.includes(\"T\") ? value : value.replace(\" \", \"T\");\n const parsed = new Date(normalized);\n if (!Number.isNaN(parsed.getTime())) return parsed;\n const [year, month = \"1\", day = \"1\"] = value.split(\"-\");\n return new Date(Number(year), Number(month) - 1, Number(day), 12);\n};\n\nexport const validDate = (value: Date): boolean => !Number.isNaN(value.getTime());\n\nexport const formatTime = (date: Date, context?: DateContext): string => calendar.formatTime(date, context);\n\nexport const eventHref = (props: CalendarOwner, event: CalendarEvent): string | undefined => props.getEventHref?.(event) ?? event.href;\n\n/** Places a calendar popover below its anchor when there is room and above it otherwise, inside the viewport. */\nexport const placeCalendarPopover = (anchor: Element | DOMRect, popover: HTMLElement): void => {\n const margin = 8;\n const gap = 4;\n const rect = anchor instanceof Element ? anchor.getBoundingClientRect() : anchor;\n const width = Math.min(popover.offsetWidth || 288, window.innerWidth - margin * 2);\n const height = popover.offsetHeight;\n const left = Math.max(margin, Math.min(rect.left, window.innerWidth - width - margin));\n const roomBelow = window.innerHeight - rect.bottom - gap - margin;\n const above = height > roomBelow && rect.top - gap - margin > roomBelow;\n const top = above ? Math.max(margin, rect.top - height - gap) : Math.min(rect.bottom + gap, window.innerHeight - height - margin);\n popover.style.left = `${left}px`;\n popover.style.top = `${Math.max(margin, top)}px`;\n};\n\n/** Follows a calendar link the way the calendar's own links do: through the host's navigation when it has one. */\nexport const followCalendarHref = (owner: CalendarOwner, href: string): void => {\n if (owner.onNavigateHref) owner.onNavigateHref(href);\n else window.location.assign(href);\n};\n\nexport const EventChip = (props: {\n event: NormalizedEvent;\n owner: CalendarOwner;\n href?: string;\n compact?: boolean;\n fill?: boolean;\n moving?: boolean;\n /** Replaces the title and time at the start of the accessible name, for example with the dates a long event spans. */\n label?: string;\n /** A bar of a long event that goes on before or after the week row it sits in. */\n continuesBefore?: boolean;\n continuesAfter?: boolean;\n /** Month view: an all-day or multi-day entry drawn as a bar. */\n bar?: boolean;\n /** Short dates at the torn ends of a bar, where it continues in another week row. */\n hintStart?: string;\n hintEnd?: string;\n /** Month view: the start time before the title. */\n leadingTime?: string;\n /** Day and week views: what is left of a running event, such as \"27 min left\". */\n remaining?: string;\n /** Day and week views: the calendar draws the event's checkbox beside the chip. */\n checkbox?: boolean;\n /** Day and week views with `dayHours`: the chip is a band, a deadline, or an all-day entry of a timeline. */\n timeline?: boolean;\n /** Text after the content, such as the time of a deadline. */\n trailing?: JSX.Element;\n /** Day and week views: the time as they write it, such as \"10:30–11:15\", shown whatever the length. */\n timeLabel?: string;\n /** Day view: a band tall enough shows its place below the time. */\n showLocation?: boolean;\n /** Week view: the grid's one tab stop decides which chip takes Tab. */\n tabIndex?: number;\n /** A keyboard stop of the week grid: its id, its day column, and its minute for moving between columns. */\n stop?: CalendarStop;\n /** Day and week views: Space on the chip checks the box the calendar draws beside it, as on the box itself. */\n onCheck?: () => void;\n onMovePointerDown?: (event: PointerEvent, onActivate: () => void) => void;\n}): JSX.Element => {\n const messages = useCalendarMessages();\n const dateConfig = createMemo(() => ownerDateConfig(props.owner));\n const color = () => props.event.color ?? \"blue\";\n const selected = () => Boolean(props.owner.selectedEventId) && props.owner.selectedEventId === props.event.id;\n const style = () => (props.event.colorHex ? { \"--k2b-calendar-accent\": props.event.colorHex } : undefined);\n const isInteractive = () => Boolean(props.owner.onEventActivate);\n const durationHours = () => (props.event.endDate.getTime() - props.event.startDate.getTime()) / 3_600_000;\n const short = () => Boolean(props.fill && !props.event.allDay && durationHours() < 0.75);\n const showTime = () => (props.timeLabel ? !props.event.allDay : !props.event.allDay && !props.compact && durationHours() >= 0.75);\n const showLocation = () =>\n Boolean(props.event.location && (props.showLocation ?? (!props.compact && !props.timeLabel && durationHours() >= 1.25)));\n const showDescription = () =>\n Boolean(\n props.event.description?.trim() && props.fill && !props.timeLabel && !props.event.allDay && !props.compact && durationHours() >= 1.5,\n );\n const timeLabel = () =>\n props.timeLabel ?? `${formatTime(props.event.startDate, dateConfig())} - ${formatTime(props.event.endDate, dateConfig())}`;\n const ariaLabel = () => {\n const label = props.label\n ? props.label\n : props.event.allDay\n ? props.event.title\n : props.event.endDate.getTime() <= props.event.startDate.getTime()\n ? // A deadline is a moment, not a span: it names one time.\n `${props.event.title}, ${formatTime(props.event.startDate, dateConfig())}`\n : messages().calendarEventTime({\n title: props.event.title,\n start: formatTime(props.event.startDate, dateConfig()),\n end: formatTime(props.event.endDate, dateConfig()),\n });\n return [label, props.remaining, props.event.accessibleDetail].filter(Boolean).join(\", \");\n };\n const renderedEvent = () =>\n props.owner.renderEvent?.(props.event, {\n compact: props.compact ?? false,\n fill: props.fill ?? false,\n start: props.event.startDate,\n end: props.event.endDate,\n allDay: props.event.allDay ?? false,\n durationHours: durationHours(),\n timeLabel: timeLabel(),\n leadingTime: props.leadingTime,\n remaining: props.remaining,\n checkbox: props.checkbox ?? false,\n timeline: props.timeline ?? false,\n });\n const defaultContent = (\n <>\n <Show when={props.leadingTime}>\n <span class=\"k2b-calendar-event__time\">{props.leadingTime}</span>\n </Show>\n <span class=\"k2b-calendar-event__title\">\n <Show when={props.event.display === \"marker\" && !props.checkbox}>\n <span class=\"k2b-calendar-event__marker\" aria-hidden=\"true\" />\n </Show>\n {props.event.title}\n </span>\n <Show when={showTime() || props.remaining}>\n <span class=\"k2b-calendar-event__meta\">\n <Show when={showTime()}>{timeLabel()}</Show>\n <Show when={props.remaining}>\n <span class=\"k2b-calendar-event__remaining\">{showTime() ? ` · ${props.remaining}` : props.remaining}</span>\n </Show>\n </span>\n </Show>\n <Show when={showLocation()}>\n <span class=\"k2b-calendar-event__meta\">{props.event.location}</span>\n </Show>\n <Show when={showDescription()}>\n <span class=\"k2b-calendar-event__description\">{props.event.description}</span>\n </Show>\n </>\n );\n const content = () => (\n <>\n <Show when={props.hintStart}>\n <span class=\"k2b-calendar-event__hint\" data-edge=\"start\" aria-hidden=\"true\">\n {props.hintStart}\n </span>\n </Show>\n {renderedEvent() ?? defaultContent}\n <Show when={props.hintEnd}>\n <span class=\"k2b-calendar-event__hint\" data-edge=\"end\" aria-hidden=\"true\">\n {props.hintEnd}\n </span>\n </Show>\n {props.trailing}\n </>\n );\n const isActionable = () => isInteractive() || Boolean(props.onMovePointerDown);\n let suppressClickUntil = 0;\n const onClick = (event: MouseEvent) => {\n if (performance.now() < suppressClickUntil) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n if (!props.owner.onEventActivate || props.owner.eventActivation === \"double\") return;\n event.preventDefault();\n event.stopPropagation();\n props.owner.onEventActivate(props.event);\n };\n const onDoubleClick = (event: MouseEvent) => {\n if (!props.owner.onEventActivate || props.owner.eventActivation !== \"double\") return;\n event.preventDefault();\n event.stopPropagation();\n props.owner.onEventActivate(props.event);\n };\n /** Space on an entry with a box checks it; Enter still opens the entry. */\n const onCheckKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \" \" || !props.onCheck || event.altKey || event.ctrlKey || event.metaKey) return false;\n event.preventDefault();\n props.onCheck();\n return true;\n };\n const onButtonKeyDown = (event: KeyboardEvent) => {\n if (onCheckKeyDown(event) || !isInteractive() || (event.key !== \"Enter\" && event.key !== \" \")) return;\n event.preventDefault();\n props.owner.onEventActivate?.(props.event);\n };\n const onPointerDown = (event: PointerEvent) => {\n if (event.pointerType === \"touch\") return;\n if (props.onMovePointerDown) event.stopPropagation();\n props.onMovePointerDown?.(event, () => {\n suppressClickUntil = performance.now() + 400;\n });\n };\n const attributes = () => ({\n class: \"k2b-calendar-event\",\n \"data-calendar-event\": \"\",\n \"data-color\": props.event.colorHex ? undefined : color(),\n \"data-selected\": selected() ? \"true\" : undefined,\n \"data-compact\": props.compact ? \"true\" : undefined,\n \"data-fill\": props.fill ? \"true\" : undefined,\n \"data-short\": short() ? \"true\" : undefined,\n \"data-moving\": props.moving ? \"true\" : undefined,\n \"data-continues-before\": props.continuesBefore ? \"true\" : undefined,\n \"data-continues-after\": props.continuesAfter ? \"true\" : undefined,\n \"data-bar\": props.bar ? \"true\" : undefined,\n \"data-display\": props.event.display,\n \"data-stop\": props.stop?.id,\n \"data-col\": props.stop?.column,\n \"data-minute\": props.stop?.minute,\n style: style(),\n \"aria-label\": ariaLabel(),\n });\n\n return props.href ? (\n <a\n {...attributes()}\n href={props.href}\n data-interactive={isInteractive() ? \"true\" : undefined}\n data-space-item-id={props.event.dataSpaceItemId}\n tabIndex={props.tabIndex}\n draggable={props.onMovePointerDown ? false : undefined}\n onClick={onClick}\n onDblClick={onDoubleClick}\n onDragStart={props.onMovePointerDown ? (event) => event.preventDefault() : undefined}\n onPointerDown={onPointerDown}\n onKeyDown={onCheckKeyDown}\n >\n {content()}\n </a>\n ) : isActionable() ? (\n <button\n {...attributes()}\n type=\"button\"\n data-interactive=\"true\"\n tabIndex={props.tabIndex}\n onClick={onClick}\n onDblClick={onDoubleClick}\n onPointerDown={onPointerDown}\n onKeyDown={onButtonKeyDown}\n >\n {content()}\n </button>\n ) : (\n <div {...attributes()} role=\"group\" tabIndex={props.tabIndex} onKeyDown={onCheckKeyDown}>\n {content()}\n </div>\n );\n};\n\nlet measureContext: CanvasRenderingContext2D | null | undefined;\n/** The width of a text in a font, from a canvas, so a bar can tell whether its title leaves room for a date hint. */\nexport const textWidth = (text: string, font: string): number => {\n measureContext ??= typeof document === \"undefined\" ? null : document.createElement(\"canvas\").getContext(\"2d\");\n if (!measureContext) return Number.POSITIVE_INFINITY;\n measureContext.font = font;\n return measureContext.measureText(text).width;\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["content/calendar-shared.tsx"],"sourcesContent":["import { dates as calendar, type DateContext } from \"@k2b/stdlib\";\nimport type { JSX } from \"solid-js\";\nimport { createMemo, Show } from \"solid-js\";\nimport { AvatarFaces } from \"../surfaces/AvatarStack\";\nimport type { CalendarEvent, CalendarProps } from \"./Calendar\";\nimport { useCalendarMessages } from \"./calendar-messages\";\n\n/** One piece of an event in one day, with the times of the whole event. */\nexport type NormalizedEvent = CalendarEvent & {\n startDate: Date;\n endDate: Date;\n dayKey: string;\n sourceStartDate: Date;\n sourceEndDate: Date;\n};\n\n/** A keyboard stop of the week grid. */\nexport type CalendarStop = { id: string; column: number; minute: number };\n\n/** What the built-in views read from the props: they only ever link to built-in views. */\nexport type CalendarOwner = Omit<CalendarProps, \"view\" | \"customViews\" | \"children\"> & {\n /** The calendar's clock, which ticks every minute; an open entry in the past is overdue. */\n calendarNow?: () => Date;\n /** Without `onEventActivate`: opens the calendar's own detail of an entry beside the element that opened it. */\n openEventDetail?: (event: CalendarEvent, anchor: HTMLElement) => void;\n};\n\n/** `data` keys the calendar writes as `data-*` attributes: camelCase letters and digits, none of the calendar's own. */\nconst DATA_KEY = /^[a-z][a-zA-Z0-9]*$/;\nexport const eventDataAttributes = (data: CalendarEvent[\"data\"]): Record<string, string> => {\n const attributes: Record<string, string> = {};\n for (const [key, value] of Object.entries(data ?? {})) {\n if (!DATA_KEY.test(key) || key.startsWith(\"calendar\") || typeof value !== \"string\") continue;\n attributes[`data-${key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}`] = value;\n }\n return attributes;\n};\n\n/** An open to-do or deadline whose time has passed. */\nexport const isOverdue = (event: CalendarEvent & { sourceStartDate?: Date; sourceEndDate?: Date }, now: Date | undefined): boolean => {\n if (event.checked !== false || !now) return false;\n const start = event.sourceStartDate?.getTime() ?? Number.NaN;\n const end = event.sourceEndDate?.getTime() ?? start;\n return Math.max(start, end) <= now.getTime();\n};\n\nexport const ownerDateConfig = (owner: CalendarOwner): DateContext => ({\n ...owner.dateConfig,\n timeZone: owner.timeZone ?? owner.dateConfig?.timeZone,\n firstDayOfWeek: owner.firstDayOfWeek ?? owner.dateConfig?.firstDayOfWeek ?? owner.dateConfig?.weekStartsOn ?? 1,\n});\n\nconst dateOnlyPattern = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport const parseDate = (value: Date | string, context?: DateContext): Date => {\n if (value instanceof Date) return new Date(value);\n if (dateOnlyPattern.test(value)) return calendar.parseCalendarDate(value, context);\n const normalized = value.includes(\"T\") ? value : value.replace(\" \", \"T\");\n const parsed = new Date(normalized);\n if (!Number.isNaN(parsed.getTime())) return parsed;\n const [year, month = \"1\", day = \"1\"] = value.split(\"-\");\n return new Date(Number(year), Number(month) - 1, Number(day), 12);\n};\n\nexport const validDate = (value: Date): boolean => !Number.isNaN(value.getTime());\n\nexport const formatTime = (date: Date, context?: DateContext): string => calendar.formatTime(date, context);\n\nexport const eventHref = (props: CalendarOwner, event: CalendarEvent): string | undefined => props.getEventHref?.(event) ?? event.href;\n\n/** Places a calendar popover below its anchor when there is room and above it otherwise, inside the viewport. */\nexport const placeCalendarPopover = (anchor: Element | DOMRect, popover: HTMLElement): void => {\n const margin = 8;\n const gap = 4;\n const rect = anchor instanceof Element ? anchor.getBoundingClientRect() : anchor;\n const width = Math.min(popover.offsetWidth || 288, window.innerWidth - margin * 2);\n const height = popover.offsetHeight;\n const left = Math.max(margin, Math.min(rect.left, window.innerWidth - width - margin));\n const roomBelow = window.innerHeight - rect.bottom - gap - margin;\n const above = height > roomBelow && rect.top - gap - margin > roomBelow;\n const top = above ? Math.max(margin, rect.top - height - gap) : Math.min(rect.bottom + gap, window.innerHeight - height - margin);\n popover.style.left = `${left}px`;\n popover.style.top = `${Math.max(margin, top)}px`;\n};\n\n/** Follows a calendar link the way the calendar's own links do: through the host's navigation when it has one. */\nexport const followCalendarHref = (owner: CalendarOwner, href: string): void => {\n if (owner.onNavigateHref) owner.onNavigateHref(href);\n else window.location.assign(href);\n};\n\nexport const EventChip = (props: {\n event: NormalizedEvent;\n owner: CalendarOwner;\n href?: string;\n compact?: boolean;\n fill?: boolean;\n moving?: boolean;\n /** Replaces the title and time at the start of the accessible name, for example with the dates a long event spans. */\n label?: string;\n /** A bar of a long event that goes on before or after the week row it sits in. */\n continuesBefore?: boolean;\n continuesAfter?: boolean;\n /** Month view: an all-day or multi-day entry drawn as a bar. */\n bar?: boolean;\n /** Short dates at the torn ends of a bar, where it continues in another week row. */\n hintStart?: string;\n hintEnd?: string;\n /** Month view: the start time before the title. */\n leadingTime?: string;\n /** Day and week views: what is left of a running event, such as \"27 min left\". */\n remaining?: string;\n /** Day and week views: the calendar draws the event's checkbox beside the chip. */\n checkbox?: boolean;\n /** Day and week views with `dayHours`: the chip is a band, a deadline, or an all-day entry of a timeline. */\n timeline?: boolean;\n /** Text after the content, such as the time of a deadline. */\n trailing?: JSX.Element;\n /** Day and week views: the time as they write it, such as \"10:30–11:15\", shown whatever the length. */\n timeLabel?: string;\n /** Day view: a band tall enough shows its place below the time. */\n showLocation?: boolean;\n /** Week view: the grid's one tab stop decides which chip takes Tab. */\n tabIndex?: number;\n /** A keyboard stop of the week grid: its id, its day column, and its minute for moving between columns. */\n stop?: CalendarStop;\n /** Day and week views: Space on the chip checks the box the calendar draws beside it, as on the box itself. */\n onCheck?: () => void;\n onMovePointerDown?: (event: PointerEvent, onActivate: () => void) => void;\n /** How many faces of the attendees fit: up to three in a band, one in the day list, none by default. */\n faces?: number;\n /** Shows how many links the entry has, where there is room beside the title or time. */\n linkCount?: boolean;\n}): JSX.Element => {\n const messages = useCalendarMessages();\n const dateConfig = createMemo(() => ownerDateConfig(props.owner));\n const color = () => props.event.color ?? \"blue\";\n const selected = () => Boolean(props.owner.selectedEventId) && props.owner.selectedEventId === props.event.id;\n const style = () => (props.event.colorHex ? { \"--k2b-calendar-accent\": props.event.colorHex } : undefined);\n const activate = (anchor: HTMLElement) => {\n if (props.owner.onEventActivate) props.owner.onEventActivate(props.event);\n else props.owner.openEventDetail?.(props.event, anchor);\n };\n const isInteractive = () => Boolean(props.owner.onEventActivate ?? props.owner.openEventDetail);\n const done = () => props.event.checked === true;\n const overdue = () => isOverdue(props.event, props.owner.calendarNow?.());\n const attendees = () => props.event.attendees ?? [];\n const links = () => props.event.links ?? [];\n const shownFaces = () => (props.faces ? attendees().slice(0, props.faces) : []);\n const durationHours = () => (props.event.endDate.getTime() - props.event.startDate.getTime()) / 3_600_000;\n const short = () => Boolean(props.fill && !props.event.allDay && durationHours() < 0.75);\n const showTime = () => (props.timeLabel ? !props.event.allDay : !props.event.allDay && !props.compact && durationHours() >= 0.75);\n const showLocation = () =>\n Boolean(props.event.location && (props.showLocation ?? (!props.compact && !props.timeLabel && durationHours() >= 1.25)));\n const showDescription = () =>\n Boolean(\n props.event.description?.trim() && props.fill && !props.timeLabel && !props.event.allDay && !props.compact && durationHours() >= 1.5,\n );\n const timeLabel = () =>\n props.timeLabel ?? `${formatTime(props.event.startDate, dateConfig())} - ${formatTime(props.event.endDate, dateConfig())}`;\n const ariaLabel = () => {\n const label = props.label\n ? props.label\n : props.event.allDay\n ? props.event.title\n : props.event.endDate.getTime() <= props.event.startDate.getTime()\n ? // A deadline is a moment, not a span: it names one time.\n `${props.event.title}, ${formatTime(props.event.startDate, dateConfig())}`\n : messages().calendarEventTime({\n title: props.event.title,\n start: formatTime(props.event.startDate, dateConfig()),\n end: formatTime(props.event.endDate, dateConfig()),\n });\n return [\n label,\n props.remaining,\n done() ? messages().calendarStateDone : overdue() ? messages().calendarStateOverdue : undefined,\n attendees().length ? messages().calendarPeopleCount({ count: attendees().length }) : undefined,\n links().length ? messages().calendarLinkCount({ count: links().length }) : undefined,\n props.event.accessibleDetail,\n ]\n .filter(Boolean)\n .join(\", \");\n };\n const renderedEvent = () =>\n props.owner.renderEvent?.(props.event, {\n compact: props.compact ?? false,\n fill: props.fill ?? false,\n start: props.event.startDate,\n end: props.event.endDate,\n allDay: props.event.allDay ?? false,\n durationHours: durationHours(),\n timeLabel: timeLabel(),\n leadingTime: props.leadingTime,\n remaining: props.remaining,\n checkbox: props.checkbox ?? false,\n timeline: props.timeline ?? false,\n });\n // Faces and the link count only take room the title and time leave; they carry no text of their own.\n const icon = () => (props.event.icon ? <i class={`k2b-calendar-event__icon ${props.event.icon}`} aria-hidden=\"true\" /> : undefined);\n const metaText = () => (\n <>\n <Show when={showTime()}>{timeLabel()}</Show>\n <Show when={props.remaining}>\n <span class=\"k2b-calendar-event__remaining\">{showTime() ? ` · ${props.remaining}` : props.remaining}</span>\n </Show>\n </>\n );\n const hasExtras = () => shownFaces().length > 0 || Boolean(props.linkCount && links().length > 0);\n const extras = () =>\n hasExtras() ? (\n <span class=\"k2b-calendar-event__extras\" aria-hidden=\"true\">\n <Show when={shownFaces().length > 0}>\n <AvatarFaces people={shownFaces()} total={(props.faces ?? 0) > 1 ? attendees().length : undefined} max={props.faces} />\n </Show>\n <Show when={props.linkCount && links().length > 0}>\n <span class=\"k2b-calendar-event__links\">\n <i class=\"ti ti-link\" />\n {links().length}\n </span>\n </Show>\n </span>\n ) : undefined;\n const defaultContent = (\n <>\n {/* The icon leads the entry: before the month view's start time, else inside the title, which a band wraps. */}\n <Show when={props.leadingTime}>\n {icon()}\n <span class=\"k2b-calendar-event__time\">{props.leadingTime}</span>\n </Show>\n <span class=\"k2b-calendar-event__title\">\n <Show when={!props.leadingTime}>{icon()}</Show>\n {props.event.title}\n </span>\n <Show\n when={hasExtras()}\n fallback={\n <Show when={showTime() || props.remaining}>\n <span class=\"k2b-calendar-event__meta\">{metaText()}</span>\n </Show>\n }\n >\n <span class=\"k2b-calendar-event__row\">\n <Show when={showTime() || props.remaining}>\n <span class=\"k2b-calendar-event__meta\">{metaText()}</span>\n </Show>\n {extras()}\n </span>\n </Show>\n <Show when={showLocation()}>\n <span class=\"k2b-calendar-event__meta\">{props.event.location}</span>\n </Show>\n <Show when={showDescription()}>\n <span class=\"k2b-calendar-event__description\">{props.event.description}</span>\n </Show>\n </>\n );\n const content = () => (\n <>\n <Show when={props.hintStart}>\n <span class=\"k2b-calendar-event__hint\" data-edge=\"start\" aria-hidden=\"true\">\n {props.hintStart}\n </span>\n </Show>\n {renderedEvent() ?? defaultContent}\n <Show when={props.hintEnd}>\n <span class=\"k2b-calendar-event__hint\" data-edge=\"end\" aria-hidden=\"true\">\n {props.hintEnd}\n </span>\n </Show>\n {props.trailing}\n </>\n );\n const isActionable = () => isInteractive() || Boolean(props.onMovePointerDown);\n let suppressClickUntil = 0;\n const onClick = (event: MouseEvent) => {\n if (performance.now() < suppressClickUntil) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n if (!isInteractive() || props.owner.eventActivation === \"double\") return;\n // A link with a modifier or another button still opens where the reader asked, such as in a new tab.\n if (props.href && (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)) return;\n event.preventDefault();\n event.stopPropagation();\n activate(event.currentTarget as HTMLElement);\n };\n const onDoubleClick = (event: MouseEvent) => {\n if (!isInteractive() || props.owner.eventActivation !== \"double\") return;\n event.preventDefault();\n event.stopPropagation();\n activate(event.currentTarget as HTMLElement);\n };\n /** Space on an entry with a box checks it; Enter still opens the entry. */\n const onCheckKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \" \" || !props.onCheck || event.altKey || event.ctrlKey || event.metaKey) return false;\n event.preventDefault();\n props.onCheck();\n return true;\n };\n const onButtonKeyDown = (event: KeyboardEvent) => {\n if (onCheckKeyDown(event) || !isInteractive() || (event.key !== \"Enter\" && event.key !== \" \")) return;\n event.preventDefault();\n activate(event.currentTarget as HTMLElement);\n };\n const onPointerDown = (event: PointerEvent) => {\n if (event.pointerType === \"touch\") return;\n if (props.onMovePointerDown) event.stopPropagation();\n props.onMovePointerDown?.(event, () => {\n suppressClickUntil = performance.now() + 400;\n });\n };\n const attributes = () => ({\n class: \"k2b-calendar-event\",\n \"data-calendar-event\": \"\",\n \"data-color\": props.event.colorHex ? undefined : color(),\n \"data-selected\": selected() ? \"true\" : undefined,\n \"data-compact\": props.compact ? \"true\" : undefined,\n \"data-fill\": props.fill ? \"true\" : undefined,\n \"data-short\": short() ? \"true\" : undefined,\n \"data-moving\": props.moving ? \"true\" : undefined,\n \"data-continues-before\": props.continuesBefore ? \"true\" : undefined,\n \"data-continues-after\": props.continuesAfter ? \"true\" : undefined,\n \"data-bar\": props.bar ? \"true\" : undefined,\n \"data-display\": props.event.display,\n \"data-done\": done() ? \"true\" : undefined,\n \"data-overdue\": overdue() ? \"true\" : undefined,\n ...eventDataAttributes(props.event.data),\n \"data-stop\": props.stop?.id,\n \"data-col\": props.stop?.column,\n \"data-minute\": props.stop?.minute,\n style: style(),\n \"aria-label\": ariaLabel(),\n });\n\n return props.href ? (\n <a\n {...attributes()}\n href={props.href}\n data-interactive={isInteractive() ? \"true\" : undefined}\n tabIndex={props.tabIndex}\n draggable={props.onMovePointerDown ? false : undefined}\n onClick={onClick}\n onDblClick={onDoubleClick}\n onDragStart={props.onMovePointerDown ? (event) => event.preventDefault() : undefined}\n onPointerDown={onPointerDown}\n onKeyDown={onCheckKeyDown}\n >\n {content()}\n </a>\n ) : isActionable() ? (\n <button\n {...attributes()}\n type=\"button\"\n data-interactive=\"true\"\n tabIndex={props.tabIndex}\n onClick={onClick}\n onDblClick={onDoubleClick}\n onPointerDown={onPointerDown}\n onKeyDown={onButtonKeyDown}\n >\n {content()}\n </button>\n ) : (\n <div {...attributes()} role=\"group\" tabIndex={props.tabIndex} onKeyDown={onCheckKeyDown}>\n {content()}\n </div>\n );\n};\n\nlet measureContext: CanvasRenderingContext2D | null | undefined;\n/** The width of a text in a font, from a canvas, so a bar can tell whether its title leaves room for a date hint. */\nexport const textWidth = (text: string, font: string): number => {\n measureContext ??= typeof document === \"undefined\" ? null : document.createElement(\"canvas\").getContext(\"2d\");\n if (!measureContext) return Number.POSITIVE_INFINITY;\n measureContext.font = font;\n return measureContext.measureText(text).width;\n};\n"],"mappings":"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","ignoreList":[]}
@@ -5,7 +5,7 @@ import { createComponent as _$createComponent } from "solid-js/web";
5
5
  import { escape as _$escape } from "solid-js/web";
6
6
  import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
7
7
  import { ssr as _$ssr } from "solid-js/web";
8
- var _tmpl$ = "<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\"><rect x=\"1.75\" y=\"1.75\" width=\"12.5\" height=\"12.5\" rx=\"3.5\"></rect><path d=\"M4.6 8.3l2.3 2.3 4.6-4.9\"></path></svg>",
8
+ var _tmpl$ = "<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\"><circle cx=\"8\" cy=\"8\" r=\"5.75\"></circle><path d=\"M5.4 8.2l1.8 1.8 3.5-3.8\"></path></svg>",
9
9
  _tmpl$2 = ["<button type=\"button\" class=\"k2b-calendar-check\" role=\"checkbox\"", ">", "</button>"],
10
10
  _tmpl$3 = ["<span class=\"k2b-calendar-check\"", " aria-hidden=\"true\">", "</span>"],
11
11
  _tmpl$4 = "<span class=\"k2b-calendar-band__fill\" aria-hidden=\"true\"></span>",
@@ -816,9 +816,9 @@ export const longDay = (view, key) => view.parseKey(key).toLocaleDateString(view
816
816
  } : {}),
817
817
  timeZone: view.dateConfig().timeZone
818
818
  });
819
- const CHECK_PATH = "M4.6 8.3l2.3 2.3 4.6-4.9";
819
+ const CHECK_PATH = "M5.4 8.2l1.8 1.8 3.5-3.8";
820
820
 
821
- /** A to-do's checkbox: it draws its check, and the title beside it strikes through. */
821
+ /** A to-do's check: a small ring in the entry's color before its title that fills when done; the title strikes through. */
822
822
  export const TimeCheck = props => {
823
823
  const checked = () => props.view.checkedOf(props.event) ?? false;
824
824
  const box = _$ssr(_tmpl$);
@@ -858,7 +858,7 @@ export const TimeBand = props => {
858
858
  duration: view.duration(props.band.end - now())
859
859
  }) : undefined;
860
860
  const lines = () => Math.max(1, Math.floor((pixels() - 24) / 15));
861
- return _$ssr(_tmpl$7, _$ssrAttribute("data-calendar-entry", _$escape(event().id, true), false) + _$ssrAttribute("data-size", _$escape(size(), true), false) + _$ssrAttribute("data-past", past() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-running", running() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-checked", checked() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-checkbox", checked() !== undefined ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-just-checked", view.justChecked().has(event().id) ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-cut-bottom", props.band.end > limit() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-moving", view.movingId() === event().id ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-display", _$escape(event().display, true), false), _$ssrStyleProperty("--k2b-calendar-accent:", _$escape(eventAccent(event()), true)) + _$ssrStyleProperty(";--k2b-calendar-lane:", _$escape(String(props.band.lane), true)) + _$ssrStyleProperty(";--k2b-calendar-lanes:", _$escape(String(props.band.lanes), true)) + _$ssrStyleProperty(";--k2b-calendar-lines:", _$escape(String(lines()), true)) + _$ssrStyleProperty(";--k2b-calendar-progress:", running() ? `${_$escape(((now() - props.band.start) / length() * 100).toFixed(1), true)}%` : _$escape(undefined, true)) + _$ssrStyleProperty(";top:", `calc(${_$escape(termsCss(top()), true)} + 1px)`) + _$ssrStyleProperty(";height:", `max(var(--k2b-calendar-band-min), calc(${_$escape(termsCss(subtractTerms(bottom(), top())), true)} - 2px))`), _$escape(_$createComponent(Show, {
861
+ return _$ssr(_tmpl$7, _$ssrAttribute("data-calendar-entry", _$escape(event().id, true), false) + _$ssrAttribute("data-size", _$escape(size(), true), false) + _$ssrAttribute("data-past", past() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-running", running() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-checked", checked() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-overdue", past() && checked() === false ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-checkbox", checked() !== undefined ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-just-checked", view.justChecked().has(event().id) ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-cut-bottom", props.band.end > limit() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-moving", view.movingId() === event().id ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-display", _$escape(event().display, true), false), _$ssrStyleProperty("--k2b-calendar-accent:", _$escape(eventAccent(event()), true)) + _$ssrStyleProperty(";--k2b-calendar-lane:", _$escape(String(props.band.lane), true)) + _$ssrStyleProperty(";--k2b-calendar-lanes:", _$escape(String(props.band.lanes), true)) + _$ssrStyleProperty(";--k2b-calendar-lines:", _$escape(String(lines()), true)) + _$ssrStyleProperty(";--k2b-calendar-progress:", running() ? `${_$escape(((now() - props.band.start) / length() * 100).toFixed(1), true)}%` : _$escape(undefined, true)) + _$ssrStyleProperty(";top:", `calc(${_$escape(termsCss(top()), true)} + 1px)`) + _$ssrStyleProperty(";height:", `max(var(--k2b-calendar-band-min), calc(${_$escape(termsCss(subtractTerms(bottom(), top())), true)} - 2px))`), _$escape(_$createComponent(Show, {
862
862
  get when() {
863
863
  return running();
864
864
  },
@@ -892,6 +892,8 @@ export const TimeBand = props => {
892
892
  },
893
893
  fill: true,
894
894
  timeline: true,
895
+ faces: 3,
896
+ linkCount: true,
895
897
  get compact() {
896
898
  return props.compact;
897
899
  },