@edux-design/comments 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,579 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/index.js
30
+ var index_exports = {};
31
+ __export(index_exports, {
32
+ Comment: () => Comment,
33
+ CommentComposer: () => CommentComposer,
34
+ CommentMention: () => CommentMention
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+
38
+ // src/elements/Comment.jsx
39
+ var import_react = __toESM(require("react"));
40
+ var import_utils = require("@edux-design/utils");
41
+ var import_avatars = require("@edux-design/avatars");
42
+ var import_jsx_runtime = require("react/jsx-runtime");
43
+ var VARIANT_STYLES = {
44
+ default: "border-border-minimal bg-bg-base",
45
+ resolved: "border-border-success-base bg-bg-success-subtle"
46
+ };
47
+ var CommentContext = (0, import_react.createContext)({
48
+ editable: true,
49
+ onResolve: void 0
50
+ });
51
+ var useCommentContext = () => (0, import_react.useContext)(CommentContext);
52
+ var Comment = (0, import_react.forwardRef)(function Comment2({
53
+ author = "Author",
54
+ timestamp,
55
+ avatar,
56
+ avatarName,
57
+ avatarProps,
58
+ body,
59
+ replies,
60
+ variant = "default",
61
+ resolved = false,
62
+ onResolve,
63
+ editable = true,
64
+ children,
65
+ className,
66
+ ...props
67
+ }, ref) {
68
+ const childArray = import_react.default.Children.toArray(children);
69
+ const actionsSlot = childArray.find(
70
+ (child) => {
71
+ var _a;
72
+ return (0, import_react.isValidElement)(child) && (child.type === CommentActions || ((_a = child.type) == null ? void 0 : _a.displayName) === "Comment.Actions");
73
+ }
74
+ );
75
+ const bodyNodes = childArray.filter((child) => child !== actionsSlot);
76
+ const bodyContent = body ?? bodyNodes;
77
+ const hasBodyContent = body !== void 0 ? Boolean(body) : bodyNodes.length > 0;
78
+ const isResolved = resolved || variant === "resolved";
79
+ const resolvedVariant = VARIANT_STYLES[isResolved ? "resolved" : variant] ?? VARIANT_STYLES.default;
80
+ const resolvedAvatarName = avatarName ?? (typeof author === "string" ? author : void 0);
81
+ const shouldRenderAvatar = Boolean(avatar || avatarProps || resolvedAvatarName);
82
+ const replyItems = (0, import_react.useMemo)(
83
+ () => import_react.default.Children.toArray(replies).filter(
84
+ (reply) => reply !== null && reply !== void 0 && reply !== false
85
+ ),
86
+ [replies]
87
+ );
88
+ const replyCount = replyItems.length;
89
+ const shouldCollapseReplies = replyCount > 2;
90
+ const [showAllReplies, setShowAllReplies] = (0, import_react.useState)(!shouldCollapseReplies);
91
+ (0, import_react.useEffect)(() => {
92
+ setShowAllReplies(!shouldCollapseReplies);
93
+ }, [shouldCollapseReplies]);
94
+ const visibleReplies = shouldCollapseReplies && !showAllReplies ? [replyItems[replyCount - 1]] : replyItems;
95
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommentContext.Provider, { value: { editable, onResolve }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
96
+ "div",
97
+ {
98
+ ref,
99
+ className: (0, import_utils.cx)(
100
+ "flex gap-12 rounded-default border p-12",
101
+ resolvedVariant,
102
+ className
103
+ ),
104
+ "data-variant": variant,
105
+ ...props,
106
+ children: [
107
+ shouldRenderAvatar && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "shrink-0", children: avatar ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_avatars.Avatar, { name: resolvedAvatarName, size: "small", ...avatarProps }) }),
108
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
109
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-center gap-6", children: [
110
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate text-sm font-semibold text-fg-base", children: author }),
111
+ timestamp && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-fg-subtle", children: timestamp })
112
+ ] }),
113
+ hasBodyContent && !isResolved ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-6 text-sm leading-relaxed text-fg-base", children: bodyContent }) : null,
114
+ isResolved ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-6 text-xs font-semibold uppercase tracking-wide text-fg-success-base", children: "Resolved" }) : null,
115
+ actionsSlot ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-8", children: actionsSlot }) : null,
116
+ replies && !isResolved ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-10 border-l border-border-minimal pl-12", children: [
117
+ shouldCollapseReplies && !showAllReplies && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
118
+ "button",
119
+ {
120
+ type: "button",
121
+ className: "mb-8 text-xs font-semibold text-fg-info-base",
122
+ onClick: () => setShowAllReplies(true),
123
+ "aria-expanded": showAllReplies,
124
+ children: [
125
+ "Show all ",
126
+ replyCount,
127
+ " replies"
128
+ ]
129
+ }
130
+ ),
131
+ visibleReplies
132
+ ] }) : null
133
+ ] })
134
+ ]
135
+ }
136
+ ) });
137
+ });
138
+ var CommentActions = ({ children, className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
139
+ "div",
140
+ {
141
+ className: (0, import_utils.cx)(
142
+ "flex flex-wrap items-center gap-8 text-xs text-fg-subtle",
143
+ className
144
+ ),
145
+ ...props,
146
+ children
147
+ }
148
+ );
149
+ var CommentReply = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
150
+ "button",
151
+ {
152
+ type: "button",
153
+ className: (0, import_utils.cx)("text-xs text-fg-info-base cursor-pointer", className),
154
+ ...props,
155
+ children: "Reply"
156
+ }
157
+ );
158
+ var CommentEdit = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
159
+ "button",
160
+ {
161
+ type: "button",
162
+ className: (0, import_utils.cx)("text-xs text-fg-info-base cursor-pointer", className),
163
+ ...props,
164
+ children: "Edit"
165
+ }
166
+ );
167
+ var CommentResolve = ({
168
+ className,
169
+ disabled,
170
+ onClick,
171
+ ...props
172
+ }) => {
173
+ const { editable, onResolve } = useCommentContext();
174
+ const isDisabled = disabled || !editable;
175
+ const handleClick = onClick ?? onResolve;
176
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
177
+ "button",
178
+ {
179
+ type: "button",
180
+ className: (0, import_utils.cx)(
181
+ "text-xs font-semibold text-fg-success-base cursor-pointer",
182
+ className
183
+ ),
184
+ onClick: handleClick,
185
+ disabled: isDisabled,
186
+ "aria-disabled": isDisabled,
187
+ ...props,
188
+ children: "Resolve"
189
+ }
190
+ );
191
+ };
192
+ Comment.Actions = CommentActions;
193
+ Comment.Reply = CommentReply;
194
+ Comment.Edit = CommentEdit;
195
+ Comment.Resolve = CommentResolve;
196
+ CommentActions.displayName = "Comment.Actions";
197
+ CommentReply.displayName = "Comment.Reply";
198
+ CommentEdit.displayName = "Comment.Edit";
199
+ CommentResolve.displayName = "Comment.Resolve";
200
+
201
+ // src/elements/CommentComposer.jsx
202
+ var import_react4 = __toESM(require("react"));
203
+ var import_utils2 = require("@edux-design/utils");
204
+ var import_avatars2 = require("@edux-design/avatars");
205
+ var import_buttons = require("@edux-design/buttons");
206
+ var import_react5 = require("@tiptap/react");
207
+ var import_starter_kit = __toESM(require("@tiptap/starter-kit"));
208
+ var import_extension_placeholder = __toESM(require("@tiptap/extension-placeholder"));
209
+
210
+ // src/elements/CommentMentionExtension.jsx
211
+ var import_react2 = __toESM(require("react"));
212
+ var import_core = require("@tiptap/core");
213
+ var import_react3 = require("@tiptap/react");
214
+ var import_mentions = require("@edux-design/mentions");
215
+ var import_jsx_runtime2 = require("react/jsx-runtime");
216
+ var MentionNodeView = ({ node }) => {
217
+ var _a, _b;
218
+ const handle = ((_a = node.attrs) == null ? void 0 : _a.handle) ?? "";
219
+ const label = ((_b = node.attrs) == null ? void 0 : _b.label) ?? "";
220
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
221
+ import_react3.NodeViewWrapper,
222
+ {
223
+ as: "span",
224
+ className: "inline-flex items-center align-middle -translate-y-2",
225
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_mentions.Mention, { handle, size: "small", children: [
226
+ "@",
227
+ handle,
228
+ " \xB7 ",
229
+ label
230
+ ] })
231
+ }
232
+ );
233
+ };
234
+ var CommentMentionExtension = import_core.Node.create({
235
+ name: "commentMention",
236
+ group: "inline",
237
+ inline: true,
238
+ atom: true,
239
+ selectable: false,
240
+ addAttributes() {
241
+ return {
242
+ id: { default: null },
243
+ handle: { default: "" },
244
+ label: { default: "" }
245
+ };
246
+ },
247
+ parseHTML() {
248
+ return [{ tag: "span[data-comment-mention]" }];
249
+ },
250
+ renderHTML({ HTMLAttributes }) {
251
+ const handle = HTMLAttributes.handle || "";
252
+ const label = HTMLAttributes.label || `@${handle}`;
253
+ return [
254
+ "span",
255
+ (0, import_core.mergeAttributes)(HTMLAttributes, {
256
+ "data-comment-mention": "true",
257
+ "data-handle": handle
258
+ }),
259
+ label
260
+ ];
261
+ },
262
+ addNodeView() {
263
+ return (0, import_react3.ReactNodeViewRenderer)(MentionNodeView);
264
+ }
265
+ });
266
+
267
+ // src/elements/CommentComposer.jsx
268
+ var import_jsx_runtime3 = require("react/jsx-runtime");
269
+ var CommentComposerContext = (0, import_react4.createContext)(null);
270
+ var useCommentComposer = () => {
271
+ const context = (0, import_react4.useContext)(CommentComposerContext);
272
+ if (!context) {
273
+ throw new Error(
274
+ "CommentComposer components must be used within a <CommentComposer />."
275
+ );
276
+ }
277
+ return context;
278
+ };
279
+ var CommentComposer = (0, import_react4.forwardRef)(function CommentComposer2({
280
+ value,
281
+ onChange,
282
+ onSubmit,
283
+ onCancel,
284
+ placeholder = "Write a comment...",
285
+ rows = 4,
286
+ disabled = false,
287
+ isSubmitting = false,
288
+ submitLabel = "Post",
289
+ cancelLabel = "Cancel",
290
+ avatar,
291
+ avatarProps,
292
+ actions,
293
+ className,
294
+ children,
295
+ ...props
296
+ }, ref) {
297
+ const hasValue = value === void 0 ? true : Boolean(value && value.trim().length);
298
+ const isSubmitDisabled = disabled || isSubmitting || !hasValue;
299
+ const editor = (0, import_react5.useEditor)({
300
+ extensions: [
301
+ import_starter_kit.default,
302
+ CommentMentionExtension,
303
+ import_extension_placeholder.default.configure({
304
+ placeholder
305
+ })
306
+ ],
307
+ content: value ?? "",
308
+ editable: !disabled,
309
+ editorProps: {
310
+ attributes: {
311
+ class: (0, import_utils2.cx)(
312
+ "w-full bg-white border-2 rounded-md border-border-base",
313
+ "outline-none transition-all duration-300 ease-in-out",
314
+ "pl-5 py-3 font-normal text-base leading-relaxed",
315
+ "h-[120px] overflow-y-auto",
316
+ "focus:shadow-focus focus-visible:shadow-focus",
317
+ disabled && "bg-bg-subtle border-border-subtle text-fg-inactive"
318
+ )
319
+ }
320
+ },
321
+ onUpdate: ({ editor: editor2 }) => {
322
+ onChange == null ? void 0 : onChange({ target: { value: editor2.getText() } });
323
+ }
324
+ });
325
+ const containerRef = (0, import_react4.useRef)(null);
326
+ (0, import_react4.useEffect)(() => {
327
+ if (typeof ref === "function") {
328
+ ref(containerRef.current);
329
+ } else if (ref) {
330
+ ref.current = containerRef.current;
331
+ }
332
+ }, [ref]);
333
+ (0, import_react4.useEffect)(() => {
334
+ if (!editor) return;
335
+ if (value === "") {
336
+ editor.commands.clearContent();
337
+ }
338
+ }, [editor, value]);
339
+ const contextValue = (0, import_react4.useMemo)(
340
+ () => ({
341
+ editor,
342
+ placeholder,
343
+ editorContainerRef: containerRef
344
+ }),
345
+ [editor, placeholder]
346
+ );
347
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CommentComposerContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
348
+ "form",
349
+ {
350
+ className: (0, import_utils2.cx)(
351
+ "relative flex gap-12 rounded-default border border-border-minimal bg-bg-base p-12",
352
+ className
353
+ ),
354
+ onSubmit: (event) => {
355
+ event.preventDefault();
356
+ if (isSubmitDisabled) return;
357
+ onSubmit == null ? void 0 : onSubmit(event);
358
+ },
359
+ ...props,
360
+ children: [
361
+ (avatar || avatarProps) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "shrink-0", children: avatar ?? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_avatars2.Avatar, { size: "small", ...avatarProps }) }),
362
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "min-w-0 flex-1", children: [
363
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: containerRef, className: "relative", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react5.EditorContent, { editor }) }),
364
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mt-8 flex flex-wrap items-center justify-between gap-8", children: [
365
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex flex-wrap items-center gap-8 text-xs text-fg-subtle", children: actions }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", {}),
366
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-8", children: [
367
+ onCancel && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
368
+ import_buttons.Button,
369
+ {
370
+ type: "button",
371
+ size: "small",
372
+ isSecondary: true,
373
+ onClick: onCancel,
374
+ disabled: disabled || isSubmitting,
375
+ children: cancelLabel
376
+ }
377
+ ),
378
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_buttons.Button, { type: "submit", size: "small", disabled: isSubmitDisabled, children: isSubmitting ? "Posting..." : submitLabel })
379
+ ] })
380
+ ] })
381
+ ] }),
382
+ children
383
+ ]
384
+ }
385
+ ) });
386
+ });
387
+
388
+ // src/elements/CommentMention.jsx
389
+ var import_react6 = __toESM(require("react"));
390
+ var import_menus = require("@edux-design/menus");
391
+ var import_avatars3 = require("@edux-design/avatars");
392
+ var import_jsx_runtime4 = require("react/jsx-runtime");
393
+ var CommentMention = ({
394
+ peopleList = []
395
+ }) => {
396
+ const { editor, editorContainerRef } = useCommentComposer();
397
+ const [menuOpen, setMenuOpen] = (0, import_react6.useState)(false);
398
+ const [query, setQuery] = (0, import_react6.useState)("");
399
+ const [range, setRange] = (0, import_react6.useState)(null);
400
+ const [anchorStyle, setAnchorStyle] = (0, import_react6.useState)({ left: 0, top: 0 });
401
+ const menuListRef = (0, import_react6.useRef)(null);
402
+ const rangeRef = (0, import_react6.useRef)(null);
403
+ const peopleByHandle = (0, import_react6.useMemo)(
404
+ () => new Map(peopleList.map((person) => [person.handle.toLowerCase(), person])),
405
+ [peopleList]
406
+ );
407
+ const filteredPeople = (0, import_react6.useMemo)(() => {
408
+ if (!query) return peopleList;
409
+ const lowered = query.toLowerCase();
410
+ return peopleList.filter(
411
+ (person) => person.handle.toLowerCase().startsWith(lowered)
412
+ );
413
+ }, [peopleList, query]);
414
+ const updateMenuState = (0, import_react6.useCallback)(() => {
415
+ var _a, _b;
416
+ if (!editor) return;
417
+ const { from } = editor.state.selection;
418
+ const { parent, parentOffset, pos } = editor.state.selection.$from;
419
+ if (!parent.isTextblock) {
420
+ setMenuOpen(false);
421
+ setQuery("");
422
+ setRange(null);
423
+ return;
424
+ }
425
+ const textBefore = parent.textBetween(0, parentOffset, "\n", "\0");
426
+ const match = textBefore.match(/@([\w-]*)$/);
427
+ if (match) {
428
+ const handleQuery = match[1] ?? "";
429
+ setQuery(handleQuery);
430
+ setMenuOpen(true);
431
+ const fromPos = pos - match[0].length;
432
+ const nextRange = { from: fromPos, to: pos };
433
+ setRange(nextRange);
434
+ rangeRef.current = nextRange;
435
+ const coords = editor.view.coordsAtPos(fromPos);
436
+ const containerRect = (_b = (_a = editorContainerRef == null ? void 0 : editorContainerRef.current) == null ? void 0 : _a.getBoundingClientRect) == null ? void 0 : _b.call(_a);
437
+ if (containerRect) {
438
+ setAnchorStyle({
439
+ left: coords.left - containerRect.left + 12,
440
+ top: coords.bottom - containerRect.top + 4
441
+ });
442
+ }
443
+ return;
444
+ }
445
+ setMenuOpen(false);
446
+ setQuery("");
447
+ setRange(null);
448
+ rangeRef.current = null;
449
+ }, [editor]);
450
+ const handleSelectPerson = (0, import_react6.useCallback)(
451
+ (person) => {
452
+ if (!editor || !rangeRef.current) return;
453
+ const selectionRange = rangeRef.current;
454
+ editor.commands.focus();
455
+ editor.commands.setTextSelection(selectionRange);
456
+ editor.commands.insertContentAt(
457
+ selectionRange,
458
+ [
459
+ {
460
+ type: "commentMention",
461
+ attrs: {
462
+ id: person.id,
463
+ handle: person.handle,
464
+ label: person.name
465
+ }
466
+ },
467
+ { type: "text", text: " " }
468
+ ],
469
+ { updateSelection: false }
470
+ );
471
+ const nextPos = selectionRange.from + 2;
472
+ requestAnimationFrame(() => {
473
+ editor.commands.setTextSelection(nextPos);
474
+ editor.view.focus();
475
+ setTimeout(() => editor.view.focus(), 0);
476
+ });
477
+ setMenuOpen(false);
478
+ setQuery("");
479
+ setRange(null);
480
+ rangeRef.current = null;
481
+ },
482
+ [editor]
483
+ );
484
+ (0, import_react6.useEffect)(() => {
485
+ if (!editor) return;
486
+ updateMenuState();
487
+ editor.on("transaction", updateMenuState);
488
+ editor.on("selectionUpdate", updateMenuState);
489
+ return () => {
490
+ editor.off("transaction", updateMenuState);
491
+ editor.off("selectionUpdate", updateMenuState);
492
+ };
493
+ }, [editor, updateMenuState]);
494
+ (0, import_react6.useEffect)(() => {
495
+ var _a;
496
+ if (!editor) return;
497
+ const handleKeyDown = (event) => {
498
+ var _a2;
499
+ if (!menuOpen) return;
500
+ if (event.key !== "ArrowDown" && event.key !== "ArrowUp") return;
501
+ event.preventDefault();
502
+ const list = menuListRef.current;
503
+ const items = list == null ? void 0 : list.querySelectorAll("[data-menu-item]");
504
+ if (!list || !(items == null ? void 0 : items.length)) return;
505
+ list.focus();
506
+ const direction = event.key === "ArrowDown" ? 1 : -1;
507
+ const targetIndex = direction === 1 ? 0 : items.length - 1;
508
+ (_a2 = items[targetIndex]) == null ? void 0 : _a2.focus();
509
+ };
510
+ const dom = (_a = editor.view) == null ? void 0 : _a.dom;
511
+ dom == null ? void 0 : dom.addEventListener("keydown", handleKeyDown);
512
+ return () => dom == null ? void 0 : dom.removeEventListener("keydown", handleKeyDown);
513
+ }, [editor, menuOpen]);
514
+ const menuContent = (0, import_react6.useMemo)(
515
+ () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
516
+ import_menus.Menu,
517
+ {
518
+ open: menuOpen && filteredPeople.length > 0,
519
+ onOpenChange: setMenuOpen,
520
+ button: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
521
+ "button",
522
+ {
523
+ type: "button",
524
+ "aria-hidden": true,
525
+ className: "absolute h-1 w-1 opacity-0",
526
+ style: {
527
+ left: `${anchorStyle.left}px`,
528
+ top: `${anchorStyle.top}px`,
529
+ pointerEvents: "none"
530
+ }
531
+ }
532
+ ),
533
+ align: "start",
534
+ side: "bottom",
535
+ trapFocus: false,
536
+ disableOutsidePointerEvents: false,
537
+ onOpenAutoFocus: (event) => event.preventDefault(),
538
+ contentProps: {
539
+ sideOffset: 4,
540
+ avoidCollisions: true,
541
+ collisionPadding: 12,
542
+ onCloseAutoFocus: (event) => event.preventDefault()
543
+ },
544
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_menus.MenuList, { ref: menuListRef, className: "min-w-[220px]", children: filteredPeople.map((person) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
545
+ import_menus.MenuItem,
546
+ {
547
+ onMouseDown: (event) => {
548
+ event.preventDefault();
549
+ event.stopPropagation();
550
+ handleSelectPerson(person);
551
+ },
552
+ onClick: () => handleSelectPerson(person),
553
+ onPointerDown: (event) => event.preventDefault(),
554
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "flex items-center gap-8", children: [
555
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_avatars3.Avatar, { size: "small", ...person.avatarProps }),
556
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "flex flex-col", children: [
557
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-sm text-fg-base", children: person.name }),
558
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "text-xs text-fg-subtle", children: [
559
+ "@",
560
+ person.handle
561
+ ] })
562
+ ] })
563
+ ] })
564
+ },
565
+ person.id
566
+ )) })
567
+ }
568
+ ),
569
+ [filteredPeople, handleSelectPerson, menuOpen]
570
+ );
571
+ if (!editor) return null;
572
+ return menuContent;
573
+ };
574
+ // Annotate the CommonJS export names for ESM import in node:
575
+ 0 && (module.exports = {
576
+ Comment,
577
+ CommentComposer,
578
+ CommentMention
579
+ });