@comty.io/core 0.1.2 → 0.1.4

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/src/comments.js CHANGED
@@ -3,7 +3,7 @@ export function createCommentThread(context) {
3
3
  const {
4
4
  root, apiUrl, projectKey, commentStatuses, selectedStatusFilters, placedPins,
5
5
  closeBubbles, getCommentStatus, updateCommentStatus, applyStatusDot,
6
- renderSidepanelComments, applyStatusFilters, loadComments, createThreadItem,
6
+ renderSidepanelComments, applyStatusFilters, createThreadItem, renderCommentContent,
7
7
  isOwnCommentEntry, updateCommentContent, deleteSdkComment, getCommentId,
8
8
  updateReplyContent, deleteSdkReply, createCommentAvatar, getSdkHeaders,
9
9
  showAuthPrompt,
@@ -31,14 +31,6 @@ export function createCommentThread(context) {
31
31
  const header = document.createElement("div");
32
32
  header.className = "comty-bubble-header";
33
33
 
34
- const title = document.createElement("h2");
35
- title.className = "comty-bubble-title";
36
- title.innerText = comment.kind === "agent" ? "Agent task" : "Comment";
37
- header.appendChild(title);
38
-
39
- const headerActions = document.createElement("div");
40
- headerActions.className = "comty-bubble-header-actions";
41
-
42
34
  const statusMenuButton = document.createElement("button");
43
35
  statusMenuButton.className = "comty-status-trigger";
44
36
  statusMenuButton.type = "button";
@@ -77,7 +69,7 @@ export function createCommentThread(context) {
77
69
  };
78
70
 
79
71
  const saveStatus = async (nextStatus, control) => {
80
- if (!context.canWrite && !comment.local_agent) return false;
72
+ if (!context.canManage) return false;
81
73
  control.disabled = true;
82
74
  const savedStatus = await updateCommentStatus(comment, nextStatus);
83
75
  control.disabled = false;
@@ -93,10 +85,6 @@ export function createCommentThread(context) {
93
85
  syncStatusTrigger();
94
86
  renderSidepanelComments();
95
87
  applyStatusFilters();
96
- if (comment.local_agent && savedStatus === "done") {
97
- closeBubbles();
98
- void loadComments({ force: true });
99
- }
100
88
  if (
101
89
  selectedStatusFilters.size > 0 &&
102
90
  !selectedStatusFilters.has(savedStatusOption.value)
@@ -106,7 +94,7 @@ export function createCommentThread(context) {
106
94
  return true;
107
95
  };
108
96
 
109
- statusMenuButton.disabled = comment.local_agent || !context.canWrite;
97
+ statusMenuButton.disabled = !context.canManage;
110
98
  statusMenuButton.onclick = (event) => {
111
99
  event.stopPropagation();
112
100
  const existingPopover = document.querySelector(
@@ -118,10 +106,11 @@ export function createCommentThread(context) {
118
106
  if (existingPopover) return;
119
107
 
120
108
  const popover = document.createElement("div");
121
- popover.className = "comty-popover comty-status-popover";
109
+ popover.className = "comty-popover comty-comment-popover comty-status-popover";
122
110
  const buttonRect = statusMenuButton.getBoundingClientRect();
123
111
  popover.style.top = `${buttonRect.bottom + 4}px`;
124
- popover.style.left = `${buttonRect.right - 140}px`;
112
+ popover.style.left = `${buttonRect.left}px`;
113
+ popover.style.transformOrigin = "top left";
125
114
 
126
115
  for (const status of commentStatuses) {
127
116
  const item = document.createElement("button");
@@ -159,6 +148,13 @@ export function createCommentThread(context) {
159
148
  }
160
149
 
161
150
  root.appendChild(popover);
151
+ const popoverWidth = popover.offsetWidth;
152
+ const popoverHeight = popover.offsetHeight;
153
+ popover.style.left = `${Math.max(8, Math.min(buttonRect.left, innerWidth - popoverWidth - 8))}px`;
154
+ if (buttonRect.bottom + 4 + popoverHeight > innerHeight - 8) {
155
+ popover.style.top = `${Math.max(8, buttonRect.top - popoverHeight - 4)}px`;
156
+ popover.style.transformOrigin = "bottom left";
157
+ }
162
158
 
163
159
  const closeStatusPopover = (closeEvent) => {
164
160
  if (
@@ -175,9 +171,7 @@ export function createCommentThread(context) {
175
171
  );
176
172
  };
177
173
 
178
- headerActions.appendChild(statusMenuButton);
179
- headerActions.appendChild(closeButton);
180
- header.appendChild(headerActions);
174
+ header.append(statusMenuButton, closeButton);
181
175
  bubble.appendChild(header);
182
176
 
183
177
  const thread = document.createElement("div");
@@ -196,7 +190,7 @@ export function createCommentThread(context) {
196
190
 
197
191
  const popover = document.createElement("div");
198
192
  popover.className =
199
- "comty-popover comty-entry-actions-popover";
193
+ "comty-popover comty-comment-popover comty-entry-actions-popover";
200
194
 
201
195
  const editItem = document.createElement("button");
202
196
  editItem.className = "comty-popover-item";
@@ -249,7 +243,7 @@ export function createCommentThread(context) {
249
243
  );
250
244
  };
251
245
 
252
- const mainItem = createThreadItem(comment, { showMore: !comment.local_agent && isOwnCommentEntry(comment) });
246
+ const mainItem = createThreadItem(comment, { showMore: isOwnCommentEntry(comment) });
253
247
 
254
248
  const startEditingEntry = (entry, item, persist) => {
255
249
  if (!isOwnCommentEntry(entry)) return;
@@ -282,7 +276,7 @@ export function createCommentThread(context) {
282
276
 
283
277
  const previousContent = entry.content;
284
278
  entry.content = nextContent;
285
- item.content.innerText = nextContent;
279
+ renderCommentContent(item.content, nextContent);
286
280
  editor.disabled = true;
287
281
  editor.replaceWith(item.content);
288
282
  renderSidepanelComments();
@@ -290,11 +284,11 @@ export function createCommentThread(context) {
290
284
  const savedContent = await persist(nextContent);
291
285
  if (!savedContent) {
292
286
  entry.content = previousContent;
293
- item.content.innerText = previousContent || "";
287
+ renderCommentContent(item.content, previousContent || "");
294
288
  renderSidepanelComments();
295
289
  return;
296
290
  }
297
- item.content.innerText = savedContent;
291
+ renderCommentContent(item.content, savedContent);
298
292
  renderSidepanelComments();
299
293
  };
300
294
 
@@ -396,13 +390,15 @@ export function createCommentThread(context) {
396
390
  const replyForm = document.createElement("div");
397
391
  replyForm.className = "comty-reply-form";
398
392
 
399
- if (context.canWrite && !comment.local_agent) {
393
+ if (context.canWrite) {
400
394
  replyForm.appendChild(createCommentAvatar(context.currentUser || { name: "You" }));
401
395
  const replyField = document.createElement("div");
402
396
  replyField.className = "comty-reply-field";
403
- const replyInput = document.createElement("input");
397
+ const replyInput = document.createElement("textarea");
404
398
  replyInput.className = "comty-reply-input";
405
399
  replyInput.placeholder = "Reply";
400
+ replyInput.rows = 1;
401
+ replyInput.setAttribute("aria-label", "Reply");
406
402
 
407
403
  const replyButton = document.createElement("button");
408
404
  replyButton.className = "comty-reply-button";
@@ -436,6 +432,7 @@ export function createCommentThread(context) {
436
432
  comment.replies = replies;
437
433
  appendReply(data.reply);
438
434
  replyInput.value = "";
435
+ syncReplySize();
439
436
  requestAnimationFrame(() => {
440
437
  threadList.scrollTop = threadList.scrollHeight;
441
438
  });
@@ -449,12 +446,28 @@ export function createCommentThread(context) {
449
446
  }
450
447
  };
451
448
 
449
+ const syncReplySize = () => {
450
+ const currentHeight = replyInput.getBoundingClientRect().height;
451
+ replyInput.style.transition = "none";
452
+ const lineHeight = parseFloat(getComputedStyle(replyInput).lineHeight);
453
+ replyInput.style.height = `${lineHeight}px`;
454
+ const contentHeight = replyInput.scrollHeight;
455
+ replyInput.style.height = `${currentHeight}px`;
456
+ replyInput.getBoundingClientRect();
457
+ replyInput.style.transition = "";
458
+ const nextHeight = Math.min(contentHeight, parseFloat(getComputedStyle(replyInput).maxHeight));
459
+ replyInput.style.height = `${nextHeight}px`;
460
+ if (contentHeight <= lineHeight + 1) replyInput.scrollTop = 0;
461
+ replyField.classList.toggle("comty-reply-expanded", contentHeight > lineHeight + 1);
462
+ };
463
+
452
464
  replyInput.oninput = () => {
465
+ syncReplySize();
453
466
  replyButton.disabled = replyInput.value.trim().length === 0;
454
467
  };
455
468
  replyInput.onkeydown = (event) => {
456
469
  event.stopPropagation();
457
- if (event.key === "Enter" && !event.shiftKey) {
470
+ if (event.key === "Enter" && !event.shiftKey && !event.isComposing) {
458
471
  event.preventDefault();
459
472
  void submitReply();
460
473
  }
@@ -467,20 +480,20 @@ export function createCommentThread(context) {
467
480
  replyField.appendChild(replyInput);
468
481
  replyField.appendChild(replyButton);
469
482
  replyForm.appendChild(replyField);
470
- } else if (!comment.local_agent) {
483
+ } else {
471
484
  replyForm.classList.add("comty-reply-form-guest");
472
485
  const signInButton = document.createElement("button");
473
486
  signInButton.className = "comty-sign-in-reply";
474
487
  signInButton.type = "button";
475
- signInButton.innerText = "Sign in to reply";
488
+ signInButton.innerText = context.allowGuestComments ? "Leave a reply" : "Sign in to reply";
476
489
  signInButton.onclick = (event) => {
477
490
  event.stopPropagation();
478
- showAuthPrompt();
491
+ showAuthPrompt(false, () => openCommentThread(comment, pin, pinStatusDot, x, y, removeHoverBubble));
479
492
  };
480
493
  replyForm.appendChild(signInButton);
481
494
  }
482
495
 
483
- if (!comment.local_agent) thread.appendChild(replyForm);
496
+ thread.appendChild(replyForm);
484
497
  bubble.appendChild(thread);
485
498
  root.appendChild(bubble);
486
499