@tutti-os/ui-rich-text 0.0.12 → 0.0.14

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.
@@ -0,0 +1,1165 @@
1
+ import {
2
+ DEFAULT_RICH_TEXT_AT_PANEL_PAGE_SIZE,
3
+ RICH_TEXT_AT_ALL_FILTER_ID,
4
+ activityMentionStatusBadgeClassName,
5
+ activityMentionStatusTone,
6
+ buildDefaultRichTextTriggerProviderGroups,
7
+ buildMentionPaletteState,
8
+ buildRichTextAtFilterTabs,
9
+ findRichTextTriggerProviderGroup,
10
+ flattenMentionPaletteEntries,
11
+ groupRichTextAtMatches,
12
+ issueMentionStatusBadgeClassName,
13
+ issueMentionStatusTone,
14
+ mentionStatusBadgeClassName,
15
+ normalizeAtPanelQuery,
16
+ resolveMentionFileThumbnailUrl,
17
+ resolveMentionFileVisualKind,
18
+ richTextAtGroupExpandCount
19
+ } from "../chunk-E4PWFY3N.js";
20
+
21
+ // src/at-panel/MentionPalette.tsx
22
+ import {
23
+ useEffect as useEffect2,
24
+ useRef as useRef2,
25
+ useState as useState2
26
+ } from "react";
27
+ import {
28
+ FolderFailedFilledIcon,
29
+ KeyboardFilledIcon
30
+ } from "@tutti-os/ui-system/icons";
31
+ import { Spinner, UnderlineTabs } from "@tutti-os/ui-system/components";
32
+ import { cn as cn2 } from "@tutti-os/ui-system/utils";
33
+
34
+ // src/at-panel/mentionPaletteScrollbar.tsx
35
+ import {
36
+ useCallback,
37
+ useEffect,
38
+ useRef,
39
+ useState
40
+ } from "react";
41
+ import { cn } from "@tutti-os/ui-system/utils";
42
+ import { jsx } from "react/jsx-runtime";
43
+ var MENTION_PALETTE_SCROLLBAR_MIN_THUMB_HEIGHT = 24;
44
+ var MENTION_PALETTE_SCROLLBAR_HIDDEN_STATE = {
45
+ scrollable: false,
46
+ thumbHeight: 0,
47
+ thumbTop: 0
48
+ };
49
+ function MentionPaletteScrollbar({
50
+ scrollBodyRef,
51
+ className,
52
+ thumbClassName,
53
+ testId
54
+ }) {
55
+ "use memo";
56
+ const trackRef = useRef(null);
57
+ const dragStateRef = useRef(null);
58
+ const [scrollbarState, setScrollbarState] = useState({
59
+ scrollable: false,
60
+ thumbHeight: 0,
61
+ thumbTop: 0
62
+ });
63
+ const [dragging, setDragging] = useState(false);
64
+ const hideScrollbar = useCallback(() => {
65
+ setScrollbarState(
66
+ (previous) => previous.scrollable || previous.thumbHeight !== 0 || previous.thumbTop !== 0 ? MENTION_PALETTE_SCROLLBAR_HIDDEN_STATE : previous
67
+ );
68
+ }, []);
69
+ const syncScrollbarState = useCallback(() => {
70
+ const contentElement = scrollBodyRef.current;
71
+ if (!contentElement) {
72
+ hideScrollbar();
73
+ return;
74
+ }
75
+ const { scrollHeight, scrollTop, clientHeight } = contentElement;
76
+ const measuredTrackHeight = trackRef.current?.clientHeight ?? 0;
77
+ const trackHeight = measuredTrackHeight > 0 ? measuredTrackHeight : clientHeight;
78
+ const maxScrollTop = Math.max(0, scrollHeight - clientHeight);
79
+ if (clientHeight <= 0 || trackHeight <= 0 || maxScrollTop <= 0) {
80
+ hideScrollbar();
81
+ return;
82
+ }
83
+ const thumbHeight = Math.max(
84
+ MENTION_PALETTE_SCROLLBAR_MIN_THUMB_HEIGHT,
85
+ Math.round(clientHeight / scrollHeight * trackHeight)
86
+ );
87
+ const maxThumbTop = Math.max(0, trackHeight - thumbHeight);
88
+ const thumbTop = Math.round(scrollTop / maxScrollTop * maxThumbTop);
89
+ setScrollbarState(
90
+ (previous) => previous.scrollable && previous.thumbHeight === thumbHeight && previous.thumbTop === thumbTop ? previous : { scrollable: true, thumbHeight, thumbTop }
91
+ );
92
+ }, [hideScrollbar, scrollBodyRef]);
93
+ useEffect(() => {
94
+ const contentElement = scrollBodyRef.current;
95
+ if (!contentElement) {
96
+ hideScrollbar();
97
+ return;
98
+ }
99
+ syncScrollbarState();
100
+ contentElement.addEventListener("scroll", syncScrollbarState, {
101
+ passive: true
102
+ });
103
+ const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(syncScrollbarState) : null;
104
+ resizeObserver?.observe(contentElement);
105
+ if (trackRef.current) {
106
+ resizeObserver?.observe(trackRef.current);
107
+ }
108
+ const animationFrameId = window.requestAnimationFrame(syncScrollbarState);
109
+ return () => {
110
+ contentElement.removeEventListener("scroll", syncScrollbarState);
111
+ resizeObserver?.disconnect();
112
+ window.cancelAnimationFrame(animationFrameId);
113
+ };
114
+ }, [hideScrollbar, scrollBodyRef, syncScrollbarState]);
115
+ useEffect(() => {
116
+ if (!dragging) {
117
+ return;
118
+ }
119
+ const handleMouseMove = (event) => {
120
+ const contentElement = scrollBodyRef.current;
121
+ const dragState = dragStateRef.current;
122
+ if (!contentElement || !dragState || dragState.maxThumbTop <= 0) {
123
+ return;
124
+ }
125
+ const delta = event.clientY - dragState.startClientY;
126
+ const nextThumbTop = dragState.startScrollTop / dragState.maxScrollTop * dragState.maxThumbTop + delta;
127
+ contentElement.scrollTop = Math.min(Math.max(0, nextThumbTop), dragState.maxThumbTop) / dragState.maxThumbTop * dragState.maxScrollTop;
128
+ syncScrollbarState();
129
+ };
130
+ const handleMouseUp = () => {
131
+ dragStateRef.current = null;
132
+ setDragging(false);
133
+ };
134
+ window.addEventListener("mousemove", handleMouseMove);
135
+ window.addEventListener("mouseup", handleMouseUp);
136
+ return () => {
137
+ window.removeEventListener("mousemove", handleMouseMove);
138
+ window.removeEventListener("mouseup", handleMouseUp);
139
+ };
140
+ }, [dragging, scrollBodyRef, syncScrollbarState]);
141
+ const scrollContentToThumbTop = (thumbTop) => {
142
+ const contentElement = scrollBodyRef.current;
143
+ const trackElement = trackRef.current;
144
+ if (!contentElement || !trackElement) {
145
+ return;
146
+ }
147
+ const maxScrollTop = Math.max(
148
+ 0,
149
+ contentElement.scrollHeight - contentElement.clientHeight
150
+ );
151
+ const maxThumbTop = Math.max(
152
+ 0,
153
+ trackElement.clientHeight - scrollbarState.thumbHeight
154
+ );
155
+ if (maxScrollTop <= 0 || maxThumbTop <= 0) {
156
+ return;
157
+ }
158
+ contentElement.scrollTop = Math.min(Math.max(0, thumbTop), maxThumbTop) / maxThumbTop * maxScrollTop;
159
+ syncScrollbarState();
160
+ };
161
+ const handleTrackMouseDown = (event) => {
162
+ if (event.button !== 0 || !scrollbarState.scrollable || event.target !== event.currentTarget) {
163
+ return;
164
+ }
165
+ event.preventDefault();
166
+ const trackRect = event.currentTarget.getBoundingClientRect();
167
+ scrollContentToThumbTop(
168
+ event.clientY - trackRect.top - scrollbarState.thumbHeight / 2
169
+ );
170
+ };
171
+ const handleThumbMouseDown = (event) => {
172
+ if (event.button !== 0 || !scrollbarState.scrollable) {
173
+ return;
174
+ }
175
+ const contentElement = scrollBodyRef.current;
176
+ const trackElement = trackRef.current;
177
+ if (!contentElement || !trackElement) {
178
+ return;
179
+ }
180
+ event.preventDefault();
181
+ event.stopPropagation();
182
+ dragStateRef.current = {
183
+ maxScrollTop: Math.max(
184
+ 0,
185
+ contentElement.scrollHeight - contentElement.clientHeight
186
+ ),
187
+ maxThumbTop: Math.max(
188
+ 0,
189
+ trackElement.clientHeight - scrollbarState.thumbHeight
190
+ ),
191
+ startClientY: event.clientY,
192
+ startScrollTop: contentElement.scrollTop
193
+ };
194
+ setDragging(true);
195
+ };
196
+ if (!scrollbarState.scrollable && !dragging) {
197
+ return /* @__PURE__ */ jsx("div", { ref: trackRef, className: "hidden", "aria-hidden": "true" });
198
+ }
199
+ return /* @__PURE__ */ jsx(
200
+ "div",
201
+ {
202
+ ref: trackRef,
203
+ className: cn("group/status-scrollbar", className),
204
+ "data-scrollable": scrollbarState.scrollable ? "true" : "false",
205
+ "data-dragging": dragging ? "true" : "false",
206
+ "data-testid": testId,
207
+ "aria-hidden": "true",
208
+ onMouseDown: handleTrackMouseDown,
209
+ children: /* @__PURE__ */ jsx(
210
+ "div",
211
+ {
212
+ className: thumbClassName,
213
+ onMouseDown: handleThumbMouseDown,
214
+ style: {
215
+ height: `${scrollbarState.thumbHeight}px`,
216
+ transform: `translateY(${scrollbarState.thumbTop}px)`
217
+ }
218
+ }
219
+ )
220
+ }
221
+ );
222
+ }
223
+
224
+ // src/at-panel/MentionPalette.tsx
225
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
226
+ var DEFAULT_THEME = {
227
+ classNames: {
228
+ palette: "rich-text-at-mention-palette",
229
+ header: "rich-text-at-mention-palette-header",
230
+ footer: "rich-text-at-mention-palette-footer",
231
+ tabs: "rich-text-at-mention-palette-tabs",
232
+ scrollRegion: "rich-text-at-mention-palette-scroll-region",
233
+ scrollbar: "rich-text-at-mention-palette-scrollbar",
234
+ scrollbarThumb: "rich-text-at-mention-palette-scrollbar-thumb",
235
+ hint: "rich-text-at-mention-palette-hint",
236
+ hintItem: "rich-text-at-mention-palette-hint-item",
237
+ hintButton: "rich-text-at-mention-palette-hint-button",
238
+ hintSeparator: "rich-text-at-mention-palette-hint-separator",
239
+ shortcut: "rich-text-at-mention-palette-shortcut",
240
+ shortcutArrow: "rich-text-at-mention-palette-shortcut--arrow",
241
+ shortcutButton: "rich-text-at-mention-palette-shortcut-button",
242
+ shortcutGroup: "rich-text-at-mention-palette-shortcut-group"
243
+ },
244
+ testIds: {
245
+ emptyState: "rich-text-at-mention-palette-empty-state",
246
+ hint: "rich-text-at-mention-palette-hint",
247
+ scrollbar: "rich-text-at-mention-palette-scrollbar",
248
+ loadingSpinner: "rich-text-at-mention-loading-spinner"
249
+ },
250
+ groupDividerAttribute: "data-rich-text-at-mention-group-divider"
251
+ };
252
+ function resolveMentionPaletteTheme(theme) {
253
+ return {
254
+ classNames: { ...DEFAULT_THEME.classNames, ...theme?.classNames },
255
+ testIds: { ...DEFAULT_THEME.testIds, ...theme?.testIds },
256
+ groupDividerAttribute: theme?.groupDividerAttribute ?? DEFAULT_THEME.groupDividerAttribute
257
+ };
258
+ }
259
+ var paletteStyles = {
260
+ palette: "nodrag grid h-full max-h-[320px] min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden text-[13px] [-webkit-app-region:no-drag]",
261
+ header: "relative z-10 shrink-0",
262
+ footer: "shrink-0",
263
+ scrollShell: "relative min-h-0 overflow-hidden",
264
+ scrollBody: "h-full min-h-0 overflow-y-auto overscroll-contain px-1 pb-1 pt-2",
265
+ rowButton: "nodrag relative flex min-h-9 w-full min-w-0 cursor-pointer select-none items-center gap-1.5 overflow-hidden rounded-[6px] border-0 bg-transparent px-2.5 py-2 text-left text-[13px] text-[var(--text-primary)] outline-hidden transition-colors duration-200 [-webkit-app-region:no-drag] active:bg-[var(--transparency-active)] data-[highlighted]:bg-[var(--transparency-block)] data-[highlighted]:text-[var(--text-primary)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:min-w-0 *:[span]:last:flex-1 *:[span]:last:items-center *:[span]:last:gap-2",
266
+ categoryButton: "nodrag flex min-h-[72px] w-full items-center gap-3.5 rounded-[6px] border-0 bg-transparent px-2.5 py-2.5 text-left text-[var(--text-primary)] transition-[background-color,color] hover:bg-[var(--transparency-block)] focus-visible:bg-[var(--transparency-block)] focus-visible:outline-none active:bg-[var(--transparency-active)]",
267
+ expandButton: "nodrag flex w-full items-center justify-center rounded-[6px] px-3 py-2 text-[13px] font-medium text-[var(--text-secondary)] transition focus-visible:outline-none active:bg-[var(--transparency-active)] data-[highlighted]:bg-[var(--transparency-block)] data-[highlighted]:text-[var(--text-primary)]"
268
+ };
269
+ var MENTION_PALETTE_LOADING_MIN_VISIBLE_MS = 320;
270
+ function MentionPalette(props) {
271
+ "use memo";
272
+ const {
273
+ state,
274
+ highlightedKey,
275
+ getItemKey,
276
+ renderItem,
277
+ labels,
278
+ hintLabels,
279
+ maxHeightPx,
280
+ onHighlightChange,
281
+ onSelectItem,
282
+ onSelectCategory,
283
+ onSelectFilter,
284
+ onExpandGroup,
285
+ onCycleFilter,
286
+ onMoveSelection,
287
+ renderListFooter,
288
+ loadingBanner,
289
+ scrollHighlightedIntoViewCentered = false,
290
+ theme: themeProp
291
+ } = props;
292
+ const theme = resolveMentionPaletteTheme(themeProp);
293
+ const highlightedOptionRef = useRef2(null);
294
+ const scrollBodyRef = useRef2(null);
295
+ const loadingVisibleUntilRef = useRef2(0);
296
+ const loadingHideTimerRef = useRef2(
297
+ null
298
+ );
299
+ const [loadingIndicatorVisible, setLoadingIndicatorVisible] = useState2(
300
+ state.status === "loading"
301
+ );
302
+ const interactiveEntries = flattenMentionPaletteEntries(
303
+ state,
304
+ (item, groupId) => getItemKey(item, findGroup(state.groups, groupId))
305
+ );
306
+ const hasInteractiveEntries = interactiveEntries.some(
307
+ (entry) => entry.type === "item" || entry.type === "expand"
308
+ );
309
+ const showLoadingState = loadingIndicatorVisible && (!hasInteractiveEntries || state.mode === "browse");
310
+ const showLoadingBanner = Boolean(loadingBanner) && loadingIndicatorVisible && hasInteractiveEntries && state.mode === "results";
311
+ useEffect2(() => {
312
+ const highlightedElement = highlightedOptionRef.current;
313
+ if (!highlightedElement) {
314
+ return;
315
+ }
316
+ const scrollContainer = scrollBodyRef.current;
317
+ if (!scrollContainer || !scrollContainer.contains(highlightedElement)) {
318
+ highlightedElement.scrollIntoView({ block: "nearest" });
319
+ return;
320
+ }
321
+ if (!scrollHighlightedIntoViewCentered) {
322
+ return;
323
+ }
324
+ centerElementInScrollContainer(scrollContainer, highlightedElement);
325
+ }, [highlightedKey, scrollHighlightedIntoViewCentered]);
326
+ useEffect2(() => {
327
+ if (loadingHideTimerRef.current !== null) {
328
+ clearTimeout(loadingHideTimerRef.current);
329
+ loadingHideTimerRef.current = null;
330
+ }
331
+ if (state.status === "loading") {
332
+ loadingVisibleUntilRef.current = Date.now() + MENTION_PALETTE_LOADING_MIN_VISIBLE_MS;
333
+ setLoadingIndicatorVisible(true);
334
+ return;
335
+ }
336
+ const remainingMs = loadingVisibleUntilRef.current - Date.now();
337
+ if (remainingMs <= 0) {
338
+ setLoadingIndicatorVisible(false);
339
+ return;
340
+ }
341
+ loadingHideTimerRef.current = setTimeout(() => {
342
+ loadingHideTimerRef.current = null;
343
+ setLoadingIndicatorVisible(false);
344
+ }, remainingMs);
345
+ return () => {
346
+ if (loadingHideTimerRef.current !== null) {
347
+ clearTimeout(loadingHideTimerRef.current);
348
+ loadingHideTimerRef.current = null;
349
+ }
350
+ };
351
+ }, [state.status]);
352
+ const paletteMaxHeightStyle = maxHeightPx > 0 ? { maxHeight: `${maxHeightPx}px` } : void 0;
353
+ if (state.status === "error") {
354
+ return /* @__PURE__ */ jsx2(
355
+ "div",
356
+ {
357
+ className: cn2(theme.classNames.palette, paletteStyles.palette),
358
+ style: paletteMaxHeightStyle,
359
+ role: "listbox",
360
+ "aria-label": labels.listbox ?? labels.tabHint,
361
+ children: /* @__PURE__ */ jsx2(
362
+ MentionPaletteEmptyState,
363
+ {
364
+ icon: "folder-failed",
365
+ label: labels.error,
366
+ testId: theme.testIds.emptyState
367
+ }
368
+ )
369
+ }
370
+ );
371
+ }
372
+ const isBrowse = state.mode === "browse";
373
+ let body;
374
+ if (showLoadingState) {
375
+ body = /* @__PURE__ */ jsx2(
376
+ MentionPaletteLoading,
377
+ {
378
+ label: labels.loading,
379
+ spinnerTestId: theme.testIds.loadingSpinner
380
+ }
381
+ );
382
+ } else if (state.groups.length === 0) {
383
+ body = /* @__PURE__ */ jsx2(
384
+ MentionPaletteEmptyState,
385
+ {
386
+ icon: isBrowse ? "keyboard" : "folder-failed",
387
+ label: labels.empty,
388
+ testId: theme.testIds.emptyState
389
+ }
390
+ );
391
+ } else {
392
+ body = /* @__PURE__ */ jsx2(
393
+ MentionPaletteGroups,
394
+ {
395
+ state,
396
+ highlightedKey,
397
+ highlightedOptionRef,
398
+ getItemKey,
399
+ renderItem,
400
+ onHighlightChange,
401
+ onSelectItem,
402
+ onExpandGroup,
403
+ renderListFooter,
404
+ groupDividerAttribute: theme.groupDividerAttribute
405
+ }
406
+ );
407
+ }
408
+ return /* @__PURE__ */ jsxs(
409
+ "div",
410
+ {
411
+ className: cn2(theme.classNames.palette, paletteStyles.palette),
412
+ style: paletteMaxHeightStyle,
413
+ role: "listbox",
414
+ "aria-label": labels.listbox ?? labels.tabHint,
415
+ children: [
416
+ /* @__PURE__ */ jsxs("div", { className: cn2(theme.classNames.header, paletteStyles.header), children: [
417
+ /* @__PURE__ */ jsx2(
418
+ UnderlineTabs,
419
+ {
420
+ tabs: state.categories.map((category) => ({
421
+ value: category.id,
422
+ label: category.label
423
+ })),
424
+ value: state.filter,
425
+ onValueChange: isBrowse ? onSelectCategory : onSelectFilter,
426
+ className: theme.classNames.tabs,
427
+ preventMouseDownDefault: true
428
+ }
429
+ ),
430
+ showLoadingBanner ? loadingBanner : null
431
+ ] }),
432
+ /* @__PURE__ */ jsxs("div", { className: paletteStyles.scrollShell, children: [
433
+ /* @__PURE__ */ jsx2(
434
+ "div",
435
+ {
436
+ ref: scrollBodyRef,
437
+ className: cn2(
438
+ theme.classNames.scrollRegion,
439
+ paletteStyles.scrollBody
440
+ ),
441
+ children: body
442
+ }
443
+ ),
444
+ /* @__PURE__ */ jsx2(
445
+ MentionPaletteScrollbar,
446
+ {
447
+ scrollBodyRef,
448
+ className: theme.classNames.scrollbar,
449
+ thumbClassName: theme.classNames.scrollbarThumb,
450
+ testId: theme.testIds.scrollbar
451
+ }
452
+ )
453
+ ] }),
454
+ /* @__PURE__ */ jsx2("div", { className: cn2(theme.classNames.footer, paletteStyles.footer), children: /* @__PURE__ */ jsx2(
455
+ MentionPaletteHint,
456
+ {
457
+ ariaLabel: labels.tabHint,
458
+ cycleFilterLabel: hintLabels.cycleFilter,
459
+ moveSelectionLabel: hintLabels.moveSelection,
460
+ onCycleFilter,
461
+ onMoveSelection,
462
+ classNames: theme.classNames,
463
+ testId: theme.testIds.hint
464
+ }
465
+ ) })
466
+ ]
467
+ }
468
+ );
469
+ }
470
+ function centerElementInScrollContainer(container, element) {
471
+ const containerRect = container.getBoundingClientRect();
472
+ const elementRect = element.getBoundingClientRect();
473
+ const currentScrollTop = container.scrollTop;
474
+ const elementTop = elementRect.top - containerRect.top + currentScrollTop;
475
+ const centeredScrollTop = elementTop - (container.clientHeight - elementRect.height) / 2;
476
+ const maxScrollTop = Math.max(
477
+ 0,
478
+ container.scrollHeight - container.clientHeight
479
+ );
480
+ const nextScrollTop = Math.min(Math.max(0, centeredScrollTop), maxScrollTop);
481
+ container.scrollTo({ top: nextScrollTop, behavior: "auto" });
482
+ }
483
+ function findGroup(groups, groupId) {
484
+ const group = groups.find((candidate) => candidate.id === groupId);
485
+ if (!group) {
486
+ throw new Error(`MentionPalette: unknown group id "${groupId}"`);
487
+ }
488
+ return group;
489
+ }
490
+ function MentionPaletteGroups({
491
+ state,
492
+ highlightedKey,
493
+ highlightedOptionRef,
494
+ getItemKey,
495
+ renderItem,
496
+ onHighlightChange,
497
+ onSelectItem,
498
+ onExpandGroup,
499
+ renderListFooter,
500
+ groupDividerAttribute
501
+ }) {
502
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
503
+ state.groups.map((group, index) => {
504
+ const showGroupDivider = index > 0 && !group.hideTopDivider;
505
+ return /* @__PURE__ */ jsxs(
506
+ "section",
507
+ {
508
+ className: cn2("grid gap-1", group.sectionClassName),
509
+ children: [
510
+ showGroupDivider ? /* @__PURE__ */ jsx2(
511
+ "div",
512
+ {
513
+ className: "mx-3 mb-2 border-t border-[var(--line-1)]",
514
+ ...{ [groupDividerAttribute]: "true" },
515
+ "aria-hidden": "true"
516
+ }
517
+ ) : null,
518
+ group.label ? /* @__PURE__ */ jsx2("div", { className: "px-3 text-[13px] font-normal text-[var(--text-secondary)]", children: group.label }) : null,
519
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-1", children: [
520
+ group.items.length === 0 && group.emptyLabel ? /* @__PURE__ */ jsx2("div", { className: "px-3 py-1 text-[13px] font-normal text-[var(--text-tertiary)]", children: group.emptyLabel }) : null,
521
+ group.items.map((item) => {
522
+ const entryKey = `${group.id}:${getItemKey(item, group)}`;
523
+ const isHighlighted = entryKey === highlightedKey;
524
+ return /* @__PURE__ */ jsx2(
525
+ "button",
526
+ {
527
+ ref: isHighlighted ? highlightedOptionRef : null,
528
+ type: "button",
529
+ className: cn2(
530
+ paletteStyles.rowButton,
531
+ isHighlighted && "bg-[var(--transparency-block)]"
532
+ ),
533
+ role: "option",
534
+ "aria-selected": isHighlighted,
535
+ "data-highlighted": isHighlighted ? "" : void 0,
536
+ onMouseEnter: () => onHighlightChange(entryKey),
537
+ onMouseDown: (event) => event.preventDefault(),
538
+ onClick: () => onSelectItem(item, group),
539
+ children: renderItem(item, { active: isHighlighted })
540
+ },
541
+ entryKey
542
+ );
543
+ }),
544
+ group.hasMore ? /* @__PURE__ */ jsx2(
545
+ "button",
546
+ {
547
+ ref: `expand:${group.id}` === highlightedKey ? highlightedOptionRef : null,
548
+ type: "button",
549
+ className: cn2(
550
+ paletteStyles.expandButton,
551
+ `expand:${group.id}` === highlightedKey && "bg-[var(--transparency-block)] text-[var(--text-primary)]"
552
+ ),
553
+ "data-highlighted": `expand:${group.id}` === highlightedKey ? "" : void 0,
554
+ onMouseEnter: () => onHighlightChange(`expand:${group.id}`),
555
+ onMouseDown: (event) => event.preventDefault(),
556
+ onClick: () => onExpandGroup(group.id),
557
+ children: group.expandLabel ?? `+${Math.max(0, group.totalCount - group.visibleCount)}`
558
+ },
559
+ `expand:${group.id}`
560
+ ) : null
561
+ ] })
562
+ ]
563
+ },
564
+ group.id
565
+ );
566
+ }),
567
+ renderListFooter?.()
568
+ ] });
569
+ }
570
+ function MentionPaletteEmptyState({
571
+ icon = "folder-failed",
572
+ label,
573
+ testId
574
+ }) {
575
+ "use memo";
576
+ const EmptyStateIcon = icon === "keyboard" ? KeyboardFilledIcon : FolderFailedFilledIcon;
577
+ return /* @__PURE__ */ jsx2(
578
+ "div",
579
+ {
580
+ className: "flex h-full min-h-0 flex-1 items-center justify-center px-4 py-6 text-center text-[13px] text-[var(--text-tertiary)]",
581
+ "data-empty-state-icon": icon,
582
+ "data-testid": testId,
583
+ children: /* @__PURE__ */ jsxs("div", { className: "flex max-w-[28ch] flex-col items-center justify-center gap-3", children: [
584
+ /* @__PURE__ */ jsx2(
585
+ EmptyStateIcon,
586
+ {
587
+ className: "h-6 w-6 text-[var(--text-tertiary)]",
588
+ "aria-hidden": "true"
589
+ }
590
+ ),
591
+ /* @__PURE__ */ jsx2("span", { className: "leading-5 text-[var(--text-tertiary)]", children: label })
592
+ ] })
593
+ }
594
+ );
595
+ }
596
+ function MentionPaletteLoading({
597
+ label,
598
+ spinnerTestId
599
+ }) {
600
+ "use memo";
601
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-[52px] items-center gap-2 rounded-xl px-3 text-[13px] text-[var(--text-secondary)]", children: [
602
+ /* @__PURE__ */ jsx2(
603
+ Spinner,
604
+ {
605
+ size: 16,
606
+ className: "text-[var(--text-secondary)]",
607
+ testId: spinnerTestId
608
+ }
609
+ ),
610
+ /* @__PURE__ */ jsx2("span", { children: label })
611
+ ] });
612
+ }
613
+ function MentionPaletteHint({
614
+ ariaLabel,
615
+ cycleFilterLabel,
616
+ moveSelectionLabel,
617
+ onCycleFilter,
618
+ onMoveSelection,
619
+ classNames,
620
+ testId
621
+ }) {
622
+ "use memo";
623
+ return /* @__PURE__ */ jsxs(
624
+ "div",
625
+ {
626
+ className: classNames.hint,
627
+ "aria-label": ariaLabel,
628
+ "data-testid": testId,
629
+ children: [
630
+ /* @__PURE__ */ jsxs(
631
+ "button",
632
+ {
633
+ className: cn2(classNames.hintItem, classNames.hintButton),
634
+ type: "button",
635
+ "aria-label": cycleFilterLabel,
636
+ onMouseDown: (event) => event.preventDefault(),
637
+ onClick: () => onCycleFilter(1),
638
+ children: [
639
+ /* @__PURE__ */ jsx2("kbd", { className: classNames.shortcut, children: "Tab" }),
640
+ /* @__PURE__ */ jsx2("span", { children: cycleFilterLabel })
641
+ ]
642
+ }
643
+ ),
644
+ /* @__PURE__ */ jsx2("span", { className: classNames.hintSeparator, "aria-hidden": "true", children: "\uFF5C" }),
645
+ /* @__PURE__ */ jsxs("span", { className: classNames.hintItem, children: [
646
+ /* @__PURE__ */ jsxs("span", { className: classNames.shortcutGroup, children: [
647
+ /* @__PURE__ */ jsx2(
648
+ "button",
649
+ {
650
+ className: cn2(
651
+ classNames.shortcut,
652
+ classNames.shortcutArrow,
653
+ classNames.shortcutButton
654
+ ),
655
+ type: "button",
656
+ "aria-label": `\u2191 ${moveSelectionLabel}`,
657
+ onMouseDown: (event) => event.preventDefault(),
658
+ onClick: () => onMoveSelection(-1),
659
+ children: "\u2191"
660
+ }
661
+ ),
662
+ /* @__PURE__ */ jsx2(
663
+ "button",
664
+ {
665
+ className: cn2(
666
+ classNames.shortcut,
667
+ classNames.shortcutArrow,
668
+ classNames.shortcutButton
669
+ ),
670
+ type: "button",
671
+ "aria-label": `\u2193 ${moveSelectionLabel}`,
672
+ onMouseDown: (event) => event.preventDefault(),
673
+ onClick: () => onMoveSelection(1),
674
+ children: "\u2193"
675
+ }
676
+ )
677
+ ] }),
678
+ /* @__PURE__ */ jsx2("span", { children: moveSelectionLabel })
679
+ ] })
680
+ ]
681
+ }
682
+ );
683
+ }
684
+
685
+ // src/at-panel/MentionRow.tsx
686
+ import {
687
+ ArrowLeftIcon,
688
+ Badge,
689
+ FileCodeIcon,
690
+ FileTextIcon,
691
+ FolderIcon,
692
+ ImageFileIcon,
693
+ ProductIcon,
694
+ StatusDot,
695
+ VideoFileIcon,
696
+ cn as cn3
697
+ } from "@tutti-os/ui-system";
698
+
699
+ // src/at-panel/mentionRowDataAttributes.ts
700
+ var MENTION_ROW_DATA_ATTRIBUTES = {
701
+ shared: {
702
+ agentAvatar: "data-rich-text-at-mention-agent-avatar",
703
+ appIcon: "data-rich-text-at-mention-app-icon",
704
+ fileEntryKind: "data-rich-text-at-mention-file-entry-kind",
705
+ fileThumb: "data-rich-text-at-mention-file-thumb",
706
+ fileVisualKind: "data-rich-text-at-mention-file-visual-kind",
707
+ navigation: "data-rich-text-at-mention-navigation",
708
+ statusTag: "data-rich-text-at-mention-status-tag",
709
+ userAvatar: "data-rich-text-at-mention-user-avatar"
710
+ },
711
+ agent: {
712
+ agentAvatar: "data-agent-mention-agent-avatar",
713
+ appIcon: "data-agent-mention-app-icon",
714
+ fileEntryKind: "data-agent-file-entry-kind",
715
+ fileThumb: "data-agent-mention-file-thumb",
716
+ fileVisualKind: "data-agent-file-visual-kind",
717
+ navigation: "data-agent-mention-navigation",
718
+ statusTag: "data-agent-mention-status-tag",
719
+ userAvatar: "data-agent-mention-user-avatar"
720
+ }
721
+ };
722
+ function mentionRowRootDataAttributes(mode, kind) {
723
+ return mode === "agent" ? {
724
+ "data-agent-file-mention": "true",
725
+ "data-agent-mention-kind": kind
726
+ } : {
727
+ "data-rich-text-at-mention-row": "true",
728
+ "data-rich-text-at-mention-kind": kind
729
+ };
730
+ }
731
+ function mentionRowDataAttribute(mode, key, value) {
732
+ return {
733
+ [MENTION_ROW_DATA_ATTRIBUTES[mode][key]]: value
734
+ };
735
+ }
736
+
737
+ // src/at-panel/MentionRow.tsx
738
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
739
+ var MENTION_FILE_VISUAL_KIND_ICON = {
740
+ back: ArrowLeftIcon,
741
+ folder: FolderIcon,
742
+ document: FileTextIcon,
743
+ // The agent maps markdown to `product-filled.svg`; ProductIcon is the
744
+ // matching boundary-safe ui-system glyph.
745
+ markdown: ProductIcon,
746
+ code: FileCodeIcon,
747
+ image: ImageFileIcon,
748
+ video: VideoFileIcon
749
+ };
750
+ var DEFAULT_MENTION_ROW_CLASS_NAMES = {
751
+ fileIcon: "rich-text-at-mention-file-icon",
752
+ fileThumb: "rich-text-at-mention-file-thumb",
753
+ kindIcon: "rich-text-at-mention-kind-icon",
754
+ avatarImgUserPlaceholder: "rich-text-at-mention-avatar-img--user-placeholder"
755
+ };
756
+ function resolveMentionRowClassNames(classNames) {
757
+ return {
758
+ fileIcon: classNames?.fileIcon ?? DEFAULT_MENTION_ROW_CLASS_NAMES.fileIcon,
759
+ fileThumb: classNames?.fileThumb ?? DEFAULT_MENTION_ROW_CLASS_NAMES.fileThumb,
760
+ kindIcon: classNames?.kindIcon ?? DEFAULT_MENTION_ROW_CLASS_NAMES.kindIcon,
761
+ avatarImgUserPlaceholder: classNames?.avatarImgUserPlaceholder ?? DEFAULT_MENTION_ROW_CLASS_NAMES.avatarImgUserPlaceholder
762
+ };
763
+ }
764
+ function resolveMentionRowRenderOptions(options) {
765
+ if (isMentionRowRenderOptions(options)) {
766
+ return {
767
+ classNames: options.classNames,
768
+ dataAttributeMode: options.dataAttributeMode ?? "shared"
769
+ };
770
+ }
771
+ return {
772
+ classNames: options,
773
+ dataAttributeMode: "shared"
774
+ };
775
+ }
776
+ function isMentionRowRenderOptions(options) {
777
+ return options !== void 0 && ("classNames" in options || "dataAttributeMode" in options);
778
+ }
779
+ function renderMentionRow(item, options) {
780
+ const { classNames, dataAttributeMode } = resolveMentionRowRenderOptions(options);
781
+ const resolved = resolveMentionRowClassNames(classNames);
782
+ if (item.kind === "file") {
783
+ return /* @__PURE__ */ jsx3(
784
+ MentionFileRow,
785
+ {
786
+ item,
787
+ classNames: resolved,
788
+ dataAttributeMode
789
+ }
790
+ );
791
+ }
792
+ if (item.kind === "session") {
793
+ return /* @__PURE__ */ jsxs2("span", { className: "grid w-full min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-3", children: [
794
+ /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-2 overflow-hidden", children: [
795
+ /* @__PURE__ */ jsx3(
796
+ MentionSessionAvatarStack,
797
+ {
798
+ item,
799
+ classNames: resolved,
800
+ dataAttributeMode
801
+ }
802
+ ),
803
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate text-[13px] font-semibold leading-[16px] text-[var(--text-primary)]", children: /* @__PURE__ */ jsx3(MentionSessionTitle, { item }) })
804
+ ] }),
805
+ item.statusTag ? /* @__PURE__ */ jsx3(
806
+ MentionStatusBadge,
807
+ {
808
+ statusTag: item.statusTag,
809
+ dataAttributeMode
810
+ }
811
+ ) : null
812
+ ] });
813
+ }
814
+ if (item.kind === "app") {
815
+ return /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-2 overflow-hidden", children: [
816
+ /* @__PURE__ */ jsx3(
817
+ MentionWorkspaceAppIcon,
818
+ {
819
+ iconUrl: item.iconUrl,
820
+ kindIconClassName: resolved.kindIcon,
821
+ dataAttributeMode
822
+ }
823
+ ),
824
+ /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 flex-1 items-baseline gap-1 overflow-hidden", children: [
825
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 max-w-[40%] shrink-0 truncate text-[13px] font-semibold text-[var(--text-primary)]", children: item.name }),
826
+ item.description ? /* @__PURE__ */ jsx3("span", { className: "min-w-0 flex-1 truncate text-[13px] font-normal text-[var(--text-secondary)]", children: item.description }) : null
827
+ ] })
828
+ ] });
829
+ }
830
+ if (item.kind === "app-factory") {
831
+ return /* @__PURE__ */ jsx3("span", { className: "grid min-w-0 overflow-hidden gap-1", children: /* @__PURE__ */ jsx3("span", { className: "min-w-0 flex-1 truncate text-[13px] font-semibold text-[var(--text-primary)]", children: item.name }) });
832
+ }
833
+ return /* @__PURE__ */ jsxs2("span", { className: "grid min-w-0 overflow-hidden gap-1", children: [
834
+ /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-2 overflow-hidden", children: [
835
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate text-[13px] font-semibold text-[var(--text-primary)]", children: item.title }),
836
+ item.statusTag ? /* @__PURE__ */ jsx3(
837
+ MentionStatusBadge,
838
+ {
839
+ statusTag: item.statusTag,
840
+ dataAttributeMode
841
+ }
842
+ ) : null
843
+ ] }),
844
+ item.creatorName ? /* @__PURE__ */ jsx3("span", { className: "truncate text-[13px] font-normal text-[var(--text-secondary)]", children: item.creatorName }) : null
845
+ ] });
846
+ }
847
+ function MentionFileRow({
848
+ item,
849
+ classNames,
850
+ dataAttributeMode
851
+ }) {
852
+ return /* @__PURE__ */ jsxs2(
853
+ "span",
854
+ {
855
+ className: "flex min-w-0 items-center gap-2",
856
+ ...mentionRowRootDataAttributes(dataAttributeMode, "file"),
857
+ ...item.entryKind ? mentionRowDataAttribute(
858
+ dataAttributeMode,
859
+ "fileEntryKind",
860
+ item.entryKind
861
+ ) : {},
862
+ ...mentionRowDataAttribute(
863
+ dataAttributeMode,
864
+ "fileVisualKind",
865
+ item.visualKind
866
+ ),
867
+ ...item.mentionNavigation ? mentionRowDataAttribute(
868
+ dataAttributeMode,
869
+ "navigation",
870
+ item.mentionNavigation
871
+ ) : {},
872
+ children: [
873
+ /* @__PURE__ */ jsx3(
874
+ MentionFileIcon,
875
+ {
876
+ item,
877
+ classNames,
878
+ dataAttributeMode
879
+ }
880
+ ),
881
+ /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-baseline gap-1 overflow-hidden", children: [
882
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate text-[13px] font-semibold text-[var(--text-primary)]", children: item.name }),
883
+ item.childCountLabel ? /* @__PURE__ */ jsx3("span", { className: "shrink-0 text-[13px] font-normal text-[var(--text-secondary)]", children: item.childCountLabel }) : null
884
+ ] })
885
+ ]
886
+ }
887
+ );
888
+ }
889
+ function MentionFileIcon({
890
+ item,
891
+ classNames,
892
+ dataAttributeMode
893
+ }) {
894
+ const thumbnailUrl = item.visualKind === "image" ? item.thumbnailUrl?.trim() || "" : "";
895
+ if (thumbnailUrl) {
896
+ return /* @__PURE__ */ jsx3(
897
+ "span",
898
+ {
899
+ className: classNames.fileThumb,
900
+ ...mentionRowDataAttribute(dataAttributeMode, "fileThumb", "true"),
901
+ "aria-hidden": "true",
902
+ children: /* @__PURE__ */ jsx3(
903
+ "img",
904
+ {
905
+ src: thumbnailUrl,
906
+ alt: "",
907
+ className: "h-full w-full object-cover",
908
+ decoding: "async",
909
+ loading: "lazy",
910
+ draggable: false
911
+ }
912
+ )
913
+ }
914
+ );
915
+ }
916
+ const usesDefaultFileIcon = classNames.fileIcon === DEFAULT_MENTION_ROW_CLASS_NAMES.fileIcon;
917
+ if (usesDefaultFileIcon) {
918
+ const Icon = MENTION_FILE_VISUAL_KIND_ICON[item.visualKind];
919
+ return /* @__PURE__ */ jsx3(
920
+ "span",
921
+ {
922
+ className: cn3(
923
+ classNames.fileIcon,
924
+ "grid h-4 w-4 shrink-0 place-items-center text-[var(--text-secondary)]"
925
+ ),
926
+ ...mentionRowDataAttribute(
927
+ dataAttributeMode,
928
+ "fileVisualKind",
929
+ item.visualKind
930
+ ),
931
+ "aria-hidden": "true",
932
+ children: /* @__PURE__ */ jsx3(Icon, { size: 16 })
933
+ }
934
+ );
935
+ }
936
+ return /* @__PURE__ */ jsx3(
937
+ "span",
938
+ {
939
+ className: classNames.fileIcon,
940
+ ...mentionRowDataAttribute(
941
+ dataAttributeMode,
942
+ "fileVisualKind",
943
+ item.visualKind
944
+ ),
945
+ "aria-hidden": "true"
946
+ }
947
+ );
948
+ }
949
+ function MentionWorkspaceAppIcon({
950
+ iconUrl,
951
+ kindIconClassName,
952
+ dataAttributeMode
953
+ }) {
954
+ const normalizedIconUrl = iconUrl?.trim() ?? "";
955
+ return /* @__PURE__ */ jsx3(
956
+ "span",
957
+ {
958
+ className: "grid h-5 w-5 shrink-0 place-items-center overflow-hidden rounded-[5px] bg-block text-[var(--text-secondary)]",
959
+ ...mentionRowDataAttribute(dataAttributeMode, "appIcon", "true"),
960
+ "data-workspace-app-icon": "true",
961
+ "aria-hidden": "true",
962
+ children: normalizedIconUrl ? /* @__PURE__ */ jsx3(
963
+ "img",
964
+ {
965
+ src: normalizedIconUrl,
966
+ alt: "",
967
+ className: "h-full w-full object-cover",
968
+ decoding: "async",
969
+ loading: "lazy",
970
+ draggable: false
971
+ }
972
+ ) : /* @__PURE__ */ jsx3("span", { className: cn3(kindIconClassName, "h-4 w-4") })
973
+ }
974
+ );
975
+ }
976
+ function MentionSessionAvatarStack({
977
+ item,
978
+ classNames,
979
+ dataAttributeMode
980
+ }) {
981
+ const userAvatarUrl = item.userAvatarUrl?.trim() ?? "";
982
+ const placeholderUrl = item.userAvatarPlaceholderUrl;
983
+ const userImageUrl = userAvatarUrl || placeholderUrl;
984
+ return /* @__PURE__ */ jsxs2(
985
+ "span",
986
+ {
987
+ className: "relative isolate block h-5 w-9 shrink-0",
988
+ "aria-hidden": "true",
989
+ children: [
990
+ /* @__PURE__ */ jsx3(
991
+ "span",
992
+ {
993
+ className: "absolute left-0 top-0 z-0 grid h-5 w-5 overflow-hidden rounded-full bg-block",
994
+ ...mentionRowDataAttribute(dataAttributeMode, "userAvatar", "true"),
995
+ children: /* @__PURE__ */ jsx3(
996
+ "img",
997
+ {
998
+ src: userImageUrl,
999
+ alt: "",
1000
+ className: cn3(
1001
+ "h-full w-full object-cover",
1002
+ !userAvatarUrl && classNames.avatarImgUserPlaceholder
1003
+ ),
1004
+ decoding: "async",
1005
+ loading: "lazy",
1006
+ referrerPolicy: "no-referrer",
1007
+ draggable: false,
1008
+ onError: (event) => {
1009
+ if (event.currentTarget.dataset.fallbackAvatarApplied === "true") {
1010
+ return;
1011
+ }
1012
+ event.currentTarget.dataset.fallbackAvatarApplied = "true";
1013
+ event.currentTarget.src = placeholderUrl;
1014
+ event.currentTarget.classList.add(
1015
+ classNames.avatarImgUserPlaceholder
1016
+ );
1017
+ }
1018
+ }
1019
+ )
1020
+ }
1021
+ ),
1022
+ /* @__PURE__ */ jsx3(
1023
+ "span",
1024
+ {
1025
+ className: "absolute left-4 top-0 z-10 grid h-5 w-5 overflow-hidden rounded-full bg-block",
1026
+ ...mentionRowDataAttribute(dataAttributeMode, "agentAvatar", "true"),
1027
+ children: /* @__PURE__ */ jsx3(
1028
+ "img",
1029
+ {
1030
+ src: item.agentIconUrl,
1031
+ alt: "",
1032
+ className: "h-full w-full object-cover",
1033
+ decoding: "async",
1034
+ loading: "lazy",
1035
+ draggable: false
1036
+ }
1037
+ )
1038
+ }
1039
+ )
1040
+ ]
1041
+ }
1042
+ );
1043
+ }
1044
+ function MentionSessionTitle({
1045
+ item
1046
+ }) {
1047
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
1048
+ /* @__PURE__ */ jsx3("span", { className: "text-[13px] leading-[16px]", children: item.participant }),
1049
+ /* @__PURE__ */ jsxs2("span", { className: "text-[13px] font-normal leading-[16px] text-[var(--text-secondary)]", children: [
1050
+ " ",
1051
+ item.summary ?? ""
1052
+ ] })
1053
+ ] });
1054
+ }
1055
+ function MentionStatusBadge({
1056
+ statusTag,
1057
+ dataAttributeMode
1058
+ }) {
1059
+ if (statusTag.variant === "issue") {
1060
+ return /* @__PURE__ */ jsx3(
1061
+ Badge,
1062
+ {
1063
+ variant: "secondary",
1064
+ className: cn3(
1065
+ "shrink-0 text-[13px]",
1066
+ mentionStatusBadgeClassName({
1067
+ tone: statusTag.tone,
1068
+ variant: "issue"
1069
+ })
1070
+ ),
1071
+ ...mentionRowDataAttribute(dataAttributeMode, "statusTag", "true"),
1072
+ ...statusTag.dataStatus ? { "data-status": statusTag.dataStatus } : {},
1073
+ children: statusTag.label
1074
+ }
1075
+ );
1076
+ }
1077
+ return /* @__PURE__ */ jsxs2(
1078
+ Badge,
1079
+ {
1080
+ variant: "secondary",
1081
+ className: cn3(
1082
+ "inline-flex h-5 shrink-0 items-center gap-1.5 rounded-[4px] px-2 text-[11px] font-semibold leading-none",
1083
+ mentionStatusBadgeClassName({
1084
+ tone: statusTag.tone,
1085
+ variant: "activity"
1086
+ })
1087
+ ),
1088
+ ...mentionRowDataAttribute(dataAttributeMode, "statusTag", "true"),
1089
+ ...statusTag.dataStatus ? { "data-status": statusTag.dataStatus } : {},
1090
+ "data-tone": statusTag.tone,
1091
+ title: statusTag.label,
1092
+ children: [
1093
+ /* @__PURE__ */ jsx3(
1094
+ StatusDot,
1095
+ {
1096
+ tone: statusTag.tone,
1097
+ pulse: statusTag.pulse ?? false,
1098
+ size: "xs",
1099
+ title: statusTag.label
1100
+ }
1101
+ ),
1102
+ /* @__PURE__ */ jsx3("span", { children: statusTag.label })
1103
+ ]
1104
+ }
1105
+ );
1106
+ }
1107
+
1108
+ // src/at-panel/useAtPanelKeyboard.ts
1109
+ function makeAtPanelKeyDown(actions) {
1110
+ return (event) => {
1111
+ if (event.key === "ArrowDown") {
1112
+ event.preventDefault();
1113
+ actions.moveSelection(1);
1114
+ return true;
1115
+ }
1116
+ if (event.key === "ArrowUp") {
1117
+ event.preventDefault();
1118
+ actions.moveSelection(-1);
1119
+ return true;
1120
+ }
1121
+ if (event.key === "Escape") {
1122
+ event.preventDefault();
1123
+ actions.close();
1124
+ return true;
1125
+ }
1126
+ if (event.key === "Tab" && actions.cycleFilter) {
1127
+ event.preventDefault();
1128
+ actions.cycleFilter(event.shiftKey ? -1 : 1);
1129
+ return true;
1130
+ }
1131
+ if (event.key === "Enter") {
1132
+ event.preventDefault();
1133
+ actions.commitSelection();
1134
+ return true;
1135
+ }
1136
+ return false;
1137
+ };
1138
+ }
1139
+ function useAtPanelKeyboard(actions) {
1140
+ return makeAtPanelKeyDown(actions);
1141
+ }
1142
+ export {
1143
+ DEFAULT_RICH_TEXT_AT_PANEL_PAGE_SIZE,
1144
+ MentionPalette,
1145
+ RICH_TEXT_AT_ALL_FILTER_ID,
1146
+ activityMentionStatusBadgeClassName,
1147
+ activityMentionStatusTone,
1148
+ buildDefaultRichTextTriggerProviderGroups,
1149
+ buildMentionPaletteState,
1150
+ buildRichTextAtFilterTabs,
1151
+ findRichTextTriggerProviderGroup,
1152
+ flattenMentionPaletteEntries,
1153
+ groupRichTextAtMatches,
1154
+ issueMentionStatusBadgeClassName,
1155
+ issueMentionStatusTone,
1156
+ makeAtPanelKeyDown,
1157
+ mentionStatusBadgeClassName,
1158
+ normalizeAtPanelQuery,
1159
+ renderMentionRow,
1160
+ resolveMentionFileThumbnailUrl,
1161
+ resolveMentionFileVisualKind,
1162
+ richTextAtGroupExpandCount,
1163
+ useAtPanelKeyboard
1164
+ };
1165
+ //# sourceMappingURL=index.js.map