@dxos/plugin-thread 0.6.11-staging.e6894a4 → 0.6.12-main.15a606f

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 (83) hide show
  1. package/dist/lib/browser/{ThreadArticle-O64ZECMF.mjs → ThreadArticle-4VU752F4.mjs} +3 -3
  2. package/dist/lib/browser/{ThreadMain-ZDCRC6RG.mjs → ThreadMain-ML3P4XSD.mjs} +3 -3
  3. package/dist/lib/browser/{chunk-5IBJO53M.mjs → chunk-7NUYW5IW.mjs} +2 -5
  4. package/dist/lib/browser/chunk-7NUYW5IW.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-GKPZHUT3.mjs → chunk-GJRBBPXI.mjs} +2 -2
  6. package/dist/lib/browser/{chunk-GKPZHUT3.mjs.map → chunk-GJRBBPXI.mjs.map} +1 -1
  7. package/dist/lib/browser/{chunk-P7ZE5N5M.mjs → chunk-XF5QKI75.mjs} +13 -11
  8. package/dist/lib/browser/chunk-XF5QKI75.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +237 -210
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/meta.mjs +1 -1
  13. package/dist/lib/browser/types.mjs +2 -2
  14. package/dist/lib/node/{ThreadArticle-DO56JXBU.cjs → ThreadArticle-ERUHPHVT.cjs} +7 -7
  15. package/dist/lib/node/{ThreadMain-XJX75GHG.cjs → ThreadMain-6DN7FDNB.cjs} +7 -7
  16. package/dist/lib/node/{chunk-BWBONZGU.cjs → chunk-6EVXCSDS.cjs} +5 -18
  17. package/dist/lib/node/chunk-6EVXCSDS.cjs.map +7 -0
  18. package/dist/lib/node/{chunk-D5GOVXHS.cjs → chunk-FXD3DYMO.cjs} +6 -6
  19. package/dist/lib/node/{chunk-D5GOVXHS.cjs.map → chunk-FXD3DYMO.cjs.map} +1 -1
  20. package/dist/lib/node/{chunk-5PZNPPQF.cjs → chunk-PZVUW4W2.cjs} +65 -63
  21. package/dist/lib/node/chunk-PZVUW4W2.cjs.map +7 -0
  22. package/dist/lib/node/index.cjs +324 -299
  23. package/dist/lib/node/index.cjs.map +4 -4
  24. package/dist/lib/node/meta.cjs +4 -4
  25. package/dist/lib/node/meta.cjs.map +1 -1
  26. package/dist/lib/node/meta.json +1 -1
  27. package/dist/lib/node/types.cjs +3 -3
  28. package/dist/lib/node/types.cjs.map +1 -1
  29. package/dist/lib/node-esm/ThreadArticle-NKI5F4W5.mjs +19 -0
  30. package/dist/lib/node-esm/ThreadArticle-NKI5F4W5.mjs.map +7 -0
  31. package/dist/lib/node-esm/ThreadMain-2A3VQLCW.mjs +27 -0
  32. package/dist/lib/node-esm/ThreadMain-2A3VQLCW.mjs.map +7 -0
  33. package/dist/lib/node-esm/chunk-A44C4MTQ.mjs +413 -0
  34. package/dist/lib/node-esm/chunk-A44C4MTQ.mjs.map +7 -0
  35. package/dist/lib/node-esm/chunk-Y475KZTX.mjs +20 -0
  36. package/dist/lib/node-esm/chunk-Y475KZTX.mjs.map +7 -0
  37. package/dist/lib/node-esm/chunk-YO46JGAE.mjs +21 -0
  38. package/dist/lib/node-esm/chunk-YO46JGAE.mjs.map +7 -0
  39. package/dist/lib/node-esm/index.mjs +1133 -0
  40. package/dist/lib/node-esm/index.mjs.map +7 -0
  41. package/dist/lib/node-esm/meta.json +1 -0
  42. package/dist/lib/node-esm/meta.mjs +12 -0
  43. package/dist/lib/node-esm/meta.mjs.map +7 -0
  44. package/dist/lib/node-esm/types.mjs +9 -0
  45. package/dist/lib/node-esm/types.mjs.map +7 -0
  46. package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
  47. package/dist/types/src/components/Chat.stories.d.ts +0 -1
  48. package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
  49. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  50. package/dist/types/src/components/CommentContainer.d.ts.map +1 -1
  51. package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
  52. package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
  53. package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
  54. package/dist/types/src/components/ThreadComplementary.d.ts +11 -0
  55. package/dist/types/src/components/ThreadComplementary.d.ts.map +1 -0
  56. package/dist/types/src/components/testing.d.ts +2 -0
  57. package/dist/types/src/components/testing.d.ts.map +1 -1
  58. package/dist/types/src/meta.d.ts +1 -4
  59. package/dist/types/src/meta.d.ts.map +1 -1
  60. package/dist/types/src/types.d.ts +1 -1
  61. package/dist/types/src/types.d.ts.map +1 -1
  62. package/package.json +37 -34
  63. package/src/ThreadPlugin.tsx +70 -190
  64. package/src/components/Chat.stories.tsx +3 -3
  65. package/src/components/ChatContainer.tsx +7 -8
  66. package/src/components/CommentContainer.tsx +10 -7
  67. package/src/components/Comments.stories.tsx +10 -15
  68. package/src/components/CommentsContainer.tsx +22 -18
  69. package/src/components/MessageContainer.tsx +2 -1
  70. package/src/components/ThreadComplementary.tsx +120 -0
  71. package/src/meta.tsx +1 -5
  72. package/src/types.ts +1 -1
  73. package/dist/lib/browser/chunk-5IBJO53M.mjs.map +0 -7
  74. package/dist/lib/browser/chunk-P7ZE5N5M.mjs.map +0 -7
  75. package/dist/lib/node/chunk-5PZNPPQF.cjs.map +0 -7
  76. package/dist/lib/node/chunk-BWBONZGU.cjs.map +0 -7
  77. package/dist/types/src/types.test.d.ts +0 -2
  78. package/dist/types/src/types.test.d.ts.map +0 -1
  79. package/src/types.test.ts +0 -13
  80. /package/dist/lib/browser/{ThreadArticle-O64ZECMF.mjs.map → ThreadArticle-4VU752F4.mjs.map} +0 -0
  81. /package/dist/lib/browser/{ThreadMain-ZDCRC6RG.mjs.map → ThreadMain-ML3P4XSD.mjs.map} +0 -0
  82. /package/dist/lib/node/{ThreadArticle-DO56JXBU.cjs.map → ThreadArticle-ERUHPHVT.cjs.map} +0 -0
  83. /package/dist/lib/node/{ThreadMain-XJX75GHG.cjs.map → ThreadMain-6DN7FDNB.cjs.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ThreadAction
3
- } from "./chunk-GKPZHUT3.mjs";
3
+ } from "./chunk-GJRBBPXI.mjs";
4
4
  import {
5
5
  ChatContainer,
6
6
  ChatHeading,
@@ -10,34 +10,30 @@ import {
10
10
  useAnalyticsCallback,
11
11
  useOnEditAnalytics,
12
12
  useStatus
13
- } from "./chunk-P7ZE5N5M.mjs";
13
+ } from "./chunk-XF5QKI75.mjs";
14
14
  import {
15
15
  THREAD_ITEM,
16
16
  THREAD_PLUGIN,
17
17
  meta_default
18
- } from "./chunk-5IBJO53M.mjs";
18
+ } from "./chunk-7NUYW5IW.mjs";
19
19
 
20
20
  // packages/plugins/plugin-thread/src/ThreadPlugin.tsx
21
- import { Chat } from "@phosphor-icons/react";
22
21
  import { computed, effect } from "@preact/signals-core";
23
- import React5, { useCallback as useCallback2 } from "react";
24
- import { LayoutAction, NavigationAction, parseIntentPlugin, parseNavigationPlugin, resolvePlugin, parseGraphPlugin, SLUG_PATH_SEPARATOR, SLUG_COLLECTION_INDICATOR, isLayoutParts, parseMetadataResolverPlugin, useResolvePlugins } from "@dxos/app-framework";
22
+ import React6 from "react";
23
+ import { LayoutAction as LayoutAction2, NavigationAction, parseIntentPlugin, parseNavigationPlugin, resolvePlugin, isLayoutParts, parseMetadataResolverPlugin } from "@dxos/app-framework";
25
24
  import { getTypename } from "@dxos/echo-schema";
26
25
  import { create as create2 } from "@dxos/echo-schema";
27
26
  import { LocalStorageStore } from "@dxos/local-storage";
28
- import { parseAttentionPlugin } from "@dxos/plugin-attention";
27
+ import { log } from "@dxos/log";
29
28
  import { parseClientPlugin } from "@dxos/plugin-client";
30
- import { createExtension, isActionGroup } from "@dxos/plugin-graph";
31
- import { DocumentType } from "@dxos/plugin-markdown/types";
29
+ import { createExtension, isActionGroup, toSignal } from "@dxos/plugin-graph";
32
30
  import { ObservabilityAction } from "@dxos/plugin-observability/meta";
33
31
  import { SpaceAction } from "@dxos/plugin-space";
34
32
  import { ThreadType, MessageType as MessageType2, ChannelType } from "@dxos/plugin-space/types";
35
- import { getSpace as getSpace2, getTextInRange, Filter, createDocAccessor, fullyQualifiedId, loadObjectReferences } from "@dxos/react-client/echo";
36
- import { ScrollArea } from "@dxos/react-ui";
37
- import { createAttendableAttributes } from "@dxos/react-ui-attention";
33
+ import { getSpace as getSpace2, getTextInRange, createDocAccessor, fullyQualifiedId as fullyQualifiedId4, loadObjectReferences } from "@dxos/react-client/echo";
38
34
  import { comments, createExternalCommentSync, listener as listener2 } from "@dxos/react-ui-editor";
39
35
  import { translations as threadTranslations } from "@dxos/react-ui-thread";
40
- import { nonNullable as nonNullable2 } from "@dxos/util";
36
+ import { nonNullable as nonNullable3 } from "@dxos/util";
41
37
 
42
38
  // packages/plugins/plugin-thread/src/components/index.ts
43
39
  import React4 from "react";
@@ -61,7 +57,7 @@ import { CheckCircle, X } from "@phosphor-icons/react";
61
57
  import React2, { useCallback, useEffect, useMemo, useRef, useState } from "react";
62
58
  import { create } from "@dxos/echo-schema";
63
59
  import { MessageType } from "@dxos/plugin-space/types";
64
- import { getSpace, useMembers } from "@dxos/react-client/echo";
60
+ import { fullyQualifiedId, getSpace, useMembers } from "@dxos/react-client/echo";
65
61
  import { useIdentity } from "@dxos/react-client/halo";
66
62
  import { Button, Tag, Tooltip, useThemeContext, useTranslation as useTranslation2 } from "@dxos/react-ui";
67
63
  import { createBasicExtensions, createThemeExtensions, listener } from "@dxos/react-ui-editor";
@@ -118,12 +114,12 @@ var CommentContainer = ({ thread, detached, context, current, autoFocusTextbox,
118
114
  const identity = useIdentity();
119
115
  const space = getSpace(thread);
120
116
  const members = useMembers(space?.key);
121
- const activity = useStatus(space, thread.id);
117
+ const activity = useStatus(space, fullyQualifiedId(thread));
122
118
  const { t } = useTranslation2(THREAD_PLUGIN);
123
119
  const threadScrollRef = useRef(null);
124
120
  const [autoFocus, setAutoFocus] = useState(!!autoFocusTextbox);
125
121
  const { themeMode } = useThemeContext();
126
- const textboxMetadata = getMessageMetadata(thread.id, identity);
122
+ const textboxMetadata = getMessageMetadata(fullyQualifiedId(thread), identity);
127
123
  const [_count, _setCount] = useState(0);
128
124
  const rerenderEditor = () => _setCount((count) => count + 1);
129
125
  const messageRef = useRef("");
@@ -172,12 +168,11 @@ var CommentContainer = ({ thread, detached, context, current, autoFocusTextbox,
172
168
  thread,
173
169
  identity
174
170
  ]);
175
- const handleDeleteMessage = (id) => onMessageDelete?.(id);
176
171
  return /* @__PURE__ */ React2.createElement(Thread, {
177
172
  onClickCapture: onAttend,
178
173
  onFocusCapture: onAttend,
179
174
  current,
180
- id: thread.id
175
+ id: fullyQualifiedId(thread)
181
176
  }, /* @__PURE__ */ React2.createElement("div", {
182
177
  role: "none",
183
178
  className: mx("col-span-2 grid grid-cols-[var(--rail-size)_1fr_min-content]", hoverableControls, hoverableFocusedWithinControls)
@@ -201,7 +196,7 @@ var CommentContainer = ({ thread, detached, context, current, autoFocusTextbox,
201
196
  key: message.id,
202
197
  message,
203
198
  members,
204
- onDelete: handleDeleteMessage
199
+ onDelete: (id) => onMessageDelete?.(id)
205
200
  })), /* @__PURE__ */ React2.createElement(MessageTextbox, {
206
201
  extensions,
207
202
  autoFocus,
@@ -217,10 +212,11 @@ var CommentContainer = ({ thread, detached, context, current, autoFocusTextbox,
217
212
  };
218
213
 
219
214
  // packages/plugins/plugin-thread/src/components/CommentsContainer.tsx
220
- import { ChatText, Quotes } from "@phosphor-icons/react";
215
+ import { ChatText } from "@phosphor-icons/react";
221
216
  import React3, { useEffect as useEffect2 } from "react";
222
- import { useTranslation as useTranslation3, Trans } from "@dxos/react-ui";
223
- import { PlankHeading, plankHeadingIconProps } from "@dxos/react-ui-deck";
217
+ import { fullyQualifiedId as fullyQualifiedId2 } from "@dxos/react-client/echo";
218
+ import { useTranslation as useTranslation3, Icon, Trans } from "@dxos/react-ui";
219
+ import { PlankHeading } from "@dxos/react-ui-deck";
224
220
  import { descriptionText, mx as mx2 } from "@dxos/react-ui-theme";
225
221
  var CommentsHeading = ({ attendableId }) => {
226
222
  const { t } = useTranslation3(THREAD_PLUGIN);
@@ -229,7 +225,10 @@ var CommentsHeading = ({ attendableId }) => {
229
225
  className: "flex items-center"
230
226
  }, /* @__PURE__ */ React3.createElement(PlankHeading.Button, {
231
227
  attendableId
232
- }, /* @__PURE__ */ React3.createElement(Quotes, plankHeadingIconProps)), /* @__PURE__ */ React3.createElement(PlankHeading.Label, {
228
+ }, /* @__PURE__ */ React3.createElement(Icon, {
229
+ icon: "ph--quotes--regular",
230
+ size: 5
231
+ })), /* @__PURE__ */ React3.createElement(PlankHeading.Label, {
233
232
  attendableId
234
233
  }, t("comments heading")));
235
234
  };
@@ -246,26 +245,29 @@ var CommentsContainer = ({ threads, detached = [], currentId, autoFocusCurrentTe
246
245
  }, [
247
246
  currentId
248
247
  ]);
249
- return /* @__PURE__ */ React3.createElement(React3.Fragment, null, filteredThreads.length > 0 ? filteredThreads.map((thread) => /* @__PURE__ */ React3.createElement(CommentContainer, {
250
- key: thread.id,
251
- thread,
252
- current: currentId === thread.id,
253
- detached: detached.includes(thread.id),
254
- autoFocusTextbox: autoFocusCurrentTextbox && currentId === thread.id,
255
- ...onThreadAttend && {
256
- onAttend: () => onThreadAttend(thread)
257
- },
258
- ...onThreadDelete && {
259
- onThreadDelete: () => onThreadDelete(thread)
260
- },
261
- ...onMessageDelete && {
262
- onMessageDelete: (messageId) => onMessageDelete(thread, messageId)
263
- },
264
- ...onThreadToggleResolved && {
265
- onResolve: () => onThreadToggleResolved(thread)
266
- },
267
- ...props
268
- })) : /* @__PURE__ */ React3.createElement("div", {
248
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, filteredThreads.length > 0 ? filteredThreads.map((thread) => {
249
+ const threadId = fullyQualifiedId2(thread);
250
+ return /* @__PURE__ */ React3.createElement(CommentContainer, {
251
+ key: threadId,
252
+ thread,
253
+ current: currentId === threadId,
254
+ detached: detached.includes(threadId),
255
+ autoFocusTextbox: autoFocusCurrentTextbox && currentId === threadId,
256
+ ...onThreadAttend && {
257
+ onAttend: () => onThreadAttend(thread)
258
+ },
259
+ ...onThreadDelete && {
260
+ onThreadDelete: () => onThreadDelete(thread)
261
+ },
262
+ ...onMessageDelete && {
263
+ onMessageDelete: (messageId) => onMessageDelete(thread, messageId)
264
+ },
265
+ ...onThreadToggleResolved && {
266
+ onResolve: () => onThreadToggleResolved(thread)
267
+ },
268
+ ...props
269
+ });
270
+ }) : /* @__PURE__ */ React3.createElement("div", {
269
271
  role: "alert",
270
272
  className: mx2(descriptionText, "place-self-center border border-dashed border-neutral-400/50 rounded-lg text-center p-4 m-4")
271
273
  }, /* @__PURE__ */ React3.createElement("h2", {
@@ -282,8 +284,124 @@ var CommentsContainer = ({ threads, detached = [], currentId, autoFocusCurrentTe
282
284
  };
283
285
 
284
286
  // packages/plugins/plugin-thread/src/components/index.ts
285
- var ThreadMain = React4.lazy(() => import("./ThreadMain-ZDCRC6RG.mjs"));
286
- var ThreadArticle = React4.lazy(() => import("./ThreadArticle-O64ZECMF.mjs"));
287
+ var ThreadMain = React4.lazy(() => import("./ThreadMain-ML3P4XSD.mjs"));
288
+ var ThreadArticle = React4.lazy(() => import("./ThreadArticle-4VU752F4.mjs"));
289
+
290
+ // packages/plugins/plugin-thread/src/components/ThreadComplementary.tsx
291
+ import React5, { useEffect as useEffect3, useMemo as useMemo2 } from "react";
292
+ import { LayoutAction, useIntentDispatcher, useResolvePlugins } from "@dxos/app-framework";
293
+ import { fullyQualifiedId as fullyQualifiedId3 } from "@dxos/react-client/echo";
294
+ import { ScrollArea } from "@dxos/react-ui";
295
+ import { createAttendableAttributes, useAttentionContext } from "@dxos/react-ui-attention";
296
+ import { nonNullable as nonNullable2 } from "@dxos/util";
297
+ var providesThreadsConfig = (plugin) => "thread" in plugin.provides ? plugin : void 0;
298
+ var ThreadComplementary = ({ role, subject, stagedThreads, current, focus, showResolvedThreads }) => {
299
+ const dispatch = useIntentDispatcher();
300
+ const threadsIntegrators = useResolvePlugins(providesThreadsConfig);
301
+ const threadProvides = useMemo2(() => threadsIntegrators.map((p) => p.provides.thread), [
302
+ threadsIntegrators
303
+ ]);
304
+ const createSort = useMemo2(() => threadProvides.find((p) => p.predicate(subject))?.createSort, [
305
+ threadProvides,
306
+ subject
307
+ ]);
308
+ const sort = useMemo2(() => createSort?.(subject), [
309
+ createSort,
310
+ subject
311
+ ]);
312
+ const threads = useMemo2(() => {
313
+ return subject.threads.concat(stagedThreads ?? []).filter(nonNullable2);
314
+ }, [
315
+ JSON.stringify(subject.threads),
316
+ JSON.stringify(stagedThreads)
317
+ ]);
318
+ const detachedIds = useMemo2(() => {
319
+ return threads.filter(({ anchor }) => !anchor).map((thread) => fullyQualifiedId3(thread));
320
+ }, [
321
+ threads
322
+ ]);
323
+ useEffect3(() => {
324
+ if (!sort) {
325
+ return;
326
+ }
327
+ threads.sort((a, b) => sort(a?.anchor, b?.anchor));
328
+ }, [
329
+ sort,
330
+ threads
331
+ ]);
332
+ const { attended } = useAttentionContext("Thread Complementary");
333
+ const qualifiedSubjectId = fullyQualifiedId3(subject);
334
+ const attendableAttrs = createAttendableAttributes(qualifiedSubjectId);
335
+ return /* @__PURE__ */ React5.createElement("div", {
336
+ role: "none",
337
+ className: "contents group/attention",
338
+ ...attendableAttrs
339
+ }, role === "complementary" && /* @__PURE__ */ React5.createElement(CommentsHeading, {
340
+ attendableId: qualifiedSubjectId
341
+ }), /* @__PURE__ */ React5.createElement(ScrollArea.Root, {
342
+ classNames: "row-span-2"
343
+ }, /* @__PURE__ */ React5.createElement(ScrollArea.Viewport, null, /* @__PURE__ */ React5.createElement(CommentsContainer, {
344
+ threads,
345
+ detached: detachedIds,
346
+ currentId: attended.has(qualifiedSubjectId) ? current : void 0,
347
+ autoFocusCurrentTextbox: focus,
348
+ showResolvedThreads,
349
+ onThreadAttend: (thread) => {
350
+ const threadId = fullyQualifiedId3(thread);
351
+ if (current !== threadId) {
352
+ current = threadId;
353
+ void dispatch?.([
354
+ {
355
+ action: LayoutAction.SCROLL_INTO_VIEW,
356
+ data: {
357
+ id: fullyQualifiedId3(subject),
358
+ thread: threadId,
359
+ cursor: thread.anchor
360
+ }
361
+ }
362
+ ]);
363
+ }
364
+ },
365
+ onThreadDelete: (thread) => {
366
+ return dispatch({
367
+ plugin: THREAD_PLUGIN,
368
+ action: ThreadAction.DELETE,
369
+ data: {
370
+ subject,
371
+ thread
372
+ }
373
+ });
374
+ },
375
+ onMessageDelete: (thread, messageId) => dispatch({
376
+ plugin: THREAD_PLUGIN,
377
+ action: ThreadAction.DELETE_MESSAGE,
378
+ data: {
379
+ subject,
380
+ thread,
381
+ messageId
382
+ }
383
+ }),
384
+ onThreadToggleResolved: (thread) => dispatch({
385
+ plugin: THREAD_PLUGIN,
386
+ action: ThreadAction.TOGGLE_RESOLVED,
387
+ data: {
388
+ thread
389
+ }
390
+ }),
391
+ onComment: (thread) => {
392
+ void dispatch({
393
+ action: ThreadAction.ON_MESSAGE_ADD,
394
+ data: {
395
+ thread,
396
+ subject
397
+ }
398
+ });
399
+ }
400
+ }), /* @__PURE__ */ React5.createElement("div", {
401
+ role: "none",
402
+ className: "bs-10"
403
+ }), /* @__PURE__ */ React5.createElement(ScrollArea.Scrollbar, null, /* @__PURE__ */ React5.createElement(ScrollArea.Thumb, null)))));
404
+ };
287
405
 
288
406
  // packages/plugins/plugin-thread/src/translations.ts
289
407
  var translations_default = [
@@ -322,6 +440,7 @@ var translations_default = [
322
440
  ];
323
441
 
324
442
  // packages/plugins/plugin-thread/src/ThreadPlugin.tsx
443
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-thread/src/ThreadPlugin.tsx";
325
444
  var initialViewState = {
326
445
  showResolvedThreads: false
327
446
  };
@@ -339,10 +458,8 @@ var ThreadPlugin = () => {
339
458
  }
340
459
  return viewStore[subjectId];
341
460
  };
342
- let attentionPlugin;
343
461
  let navigationPlugin;
344
462
  let intentPlugin;
345
- let dispatch;
346
463
  const unsubscribeCallbacks = [];
347
464
  return {
348
465
  meta: meta_default,
@@ -353,36 +470,8 @@ var ThreadPlugin = () => {
353
470
  allowUndefined: true
354
471
  })
355
472
  });
356
- attentionPlugin = resolvePlugin(plugins, parseAttentionPlugin);
357
473
  navigationPlugin = resolvePlugin(plugins, parseNavigationPlugin);
358
474
  intentPlugin = resolvePlugin(plugins, parseIntentPlugin);
359
- dispatch = intentPlugin?.provides.intent.dispatch;
360
- const graphPlugin = resolvePlugin(plugins, parseGraphPlugin);
361
- const client = resolvePlugin(plugins, parseClientPlugin)?.provides.client;
362
- if (!client) {
363
- return;
364
- }
365
- const channelsQuery = client.spaces.query(Filter.schema(ChannelType));
366
- const queryUnsubscribe = channelsQuery.subscribe();
367
- const unsubscribe = effect(() => {
368
- const attention = attentionPlugin?.provides.attention;
369
- if (!attention?.attended) {
370
- return;
371
- }
372
- const firstAttendedNodeWithComments = Array.from(attention.attended).map((id) => graphPlugin?.provides.graph.findNode(id)).find((node) => node?.data instanceof DocumentType && (node.data.threads?.length ?? 0) > 0);
373
- if (firstAttendedNodeWithComments) {
374
- void intentPlugin?.provides.intent.dispatch({
375
- action: NavigationAction.OPEN,
376
- data: {
377
- activeParts: {
378
- complementary: `${firstAttendedNodeWithComments.id}${SLUG_PATH_SEPARATOR}comments`
379
- }
380
- }
381
- });
382
- }
383
- });
384
- unsubscribeCallbacks.push(queryUnsubscribe);
385
- unsubscribeCallbacks.push(unsubscribe);
386
475
  },
387
476
  unload: async () => {
388
477
  unsubscribeCallbacks.forEach((unsubscribe) => unsubscribe());
@@ -398,8 +487,7 @@ var ThreadPlugin = () => {
398
487
  ns: THREAD_PLUGIN
399
488
  }
400
489
  ],
401
- icon: (props) => /* @__PURE__ */ React5.createElement(Chat, props),
402
- iconSymbol: "ph--chat--regular",
490
+ icon: "ph--chat--regular",
403
491
  // TODO(wittjosiah): Move out of metadata.
404
492
  loadReferences: (channel) => loadObjectReferences(channel, (channel2) => channel2.threads)
405
493
  },
@@ -446,9 +534,9 @@ var ThreadPlugin = () => {
446
534
  graph: {
447
535
  builder: (plugins) => {
448
536
  const client = resolvePlugin(plugins, parseClientPlugin)?.provides.client;
449
- const dispatch2 = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatch;
537
+ const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatch;
450
538
  const metadataResolver = resolvePlugin(plugins, parseMetadataResolverPlugin)?.provides.metadata.resolver;
451
- if (!client || !dispatch2 || !metadataResolver) {
539
+ if (!client || !dispatch || !metadataResolver) {
452
540
  return [];
453
541
  }
454
542
  return [
@@ -458,27 +546,33 @@ var ThreadPlugin = () => {
458
546
  if (!id.endsWith("~comments")) {
459
547
  return;
460
548
  }
461
- const docId = id.split("~").at(0);
462
- const [spaceId, objectId] = docId?.split(":") ?? [];
549
+ const subjectId = id.split("~").at(0);
550
+ const [spaceId, objectId] = subjectId?.split(":") ?? [];
463
551
  const space = client.spaces.get().find((space2) => space2.id === spaceId);
464
- const doc = space?.db.getObjectById(objectId);
465
- if (!doc || !docId) {
552
+ const object = toSignal((onChange) => {
553
+ const timeout = setTimeout(async () => {
554
+ await space?.db.loadObjectById(objectId);
555
+ onChange();
556
+ });
557
+ return () => clearTimeout(timeout);
558
+ }, () => space?.db.getObjectById(objectId));
559
+ if (!object || !subjectId) {
466
560
  return;
467
561
  }
468
- const docMeta = metadataResolver(getTypename(doc) ?? "");
469
- const label = docMeta.label?.(doc) || doc.name || docMeta.placeholder || [
562
+ const meta = metadataResolver(getTypename(object) ?? "");
563
+ const label = meta.label?.(object) || object.name || meta.placeholder || [
470
564
  "unnamed object threads label",
471
565
  {
472
566
  ns: THREAD_PLUGIN
473
567
  }
474
568
  ];
475
- const viewState = getViewState(docId);
569
+ const viewState = getViewState(subjectId);
476
570
  return {
477
571
  id,
478
572
  type: "orphan-comments-for-subject",
479
- data: doc,
573
+ data: object,
480
574
  properties: {
481
- icon: meta_default.iconComponent,
575
+ icon: meta.icon,
482
576
  label,
483
577
  showResolvedThreads: viewState.showResolvedThreads
484
578
  }
@@ -494,7 +588,7 @@ var ThreadPlugin = () => {
494
588
  const toggle = () => {
495
589
  const newToggleState = !viewState.showResolvedThreads;
496
590
  viewState.showResolvedThreads = newToggleState;
497
- void dispatch2({
591
+ void dispatch({
498
592
  action: ObservabilityAction.SEND_EVENT,
499
593
  data: {
500
594
  name: "threads.toggle-show-resolved",
@@ -519,7 +613,8 @@ var ThreadPlugin = () => {
519
613
  ],
520
614
  menuItemType: "toggle",
521
615
  isChecked: viewState.showResolvedThreads,
522
- testId: "threadPlugin.toggleShowResolved"
616
+ testId: "threadPlugin.toggleShowResolved",
617
+ icon: viewState.showResolvedThreads ? "ph--eye-slash--regular" : "ph--eye--regular"
523
618
  }
524
619
  }
525
620
  ];
@@ -541,7 +636,7 @@ var ThreadPlugin = () => {
541
636
  {
542
637
  id: `${THREAD_PLUGIN}/create/${node.id}`,
543
638
  data: async () => {
544
- await dispatch2([
639
+ await dispatch([
545
640
  {
546
641
  plugin: THREAD_PLUGIN,
547
642
  action: ThreadAction.CREATE
@@ -564,8 +659,7 @@ var ThreadPlugin = () => {
564
659
  ns: THREAD_PLUGIN
565
660
  }
566
661
  ],
567
- icon: (props) => /* @__PURE__ */ React5.createElement(Chat, props),
568
- iconSymbol: "ph--chat--regular",
662
+ icon: "ph--chat--regular",
569
663
  testId: "threadPlugin.createObject"
570
664
  }
571
665
  }
@@ -579,24 +673,18 @@ var ThreadPlugin = () => {
579
673
  component: ({ data, role }) => {
580
674
  switch (role) {
581
675
  case "main": {
582
- return data.active instanceof ChannelType && data.active.threads[0] ? /* @__PURE__ */ React5.createElement(ThreadMain, {
676
+ return data.active instanceof ChannelType && data.active.threads[0] ? /* @__PURE__ */ React6.createElement(ThreadMain, {
583
677
  thread: data.active.threads[0]
584
678
  }) : null;
585
679
  }
586
680
  case "settings": {
587
- return data.plugin === meta_default.id ? /* @__PURE__ */ React5.createElement(ThreadSettings, {
681
+ return data.plugin === meta_default.id ? /* @__PURE__ */ React6.createElement(ThreadSettings, {
588
682
  settings: settings.values
589
683
  }) : null;
590
684
  }
591
685
  case "article":
592
686
  case "complementary": {
593
687
  const location = navigationPlugin?.provides.location;
594
- const providesThreadsConfig = useCallback2((plugin) => (
595
- // TODO(Zan): More robust runtime check.
596
- "thread" in plugin.provides ? plugin : void 0
597
- ), []);
598
- const threadsIntegrators = useResolvePlugins(providesThreadsConfig);
599
- const threadProvides = threadsIntegrators.map((p) => p.provides.thread);
600
688
  if (data.object instanceof ChannelType && data.object.threads[0]) {
601
689
  const channel = data.object;
602
690
  if (isLayoutParts(location?.active) && location.active.main) {
@@ -605,101 +693,33 @@ var ThreadPlugin = () => {
605
693
  if (currentPosition > 0) {
606
694
  const objectToTheLeft = layoutEntries[currentPosition - 1];
607
695
  const context = getSpace2(data.object)?.db.getObjectById(objectToTheLeft.id);
608
- return /* @__PURE__ */ React5.createElement(ThreadArticle, {
696
+ return /* @__PURE__ */ React6.createElement(ThreadArticle, {
609
697
  thread: data.object.threads[0],
610
698
  context
611
699
  });
612
700
  }
613
701
  }
614
- return /* @__PURE__ */ React5.createElement(ThreadArticle, {
702
+ return /* @__PURE__ */ React6.createElement(ThreadArticle, {
615
703
  thread: data.object.threads[0]
616
704
  });
617
705
  }
618
706
  if (data.subject instanceof ThreadType) {
619
- return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(ChatHeading, {
707
+ return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(ChatHeading, {
620
708
  attendableId: data.subject.id
621
- }), /* @__PURE__ */ React5.createElement(ChatContainer, {
709
+ }), /* @__PURE__ */ React6.createElement(ChatContainer, {
622
710
  thread: data.subject
623
711
  }));
624
712
  }
625
713
  if (data.subject && typeof data.subject === "object" && "threads" in data.subject && Array.isArray(data.subject.threads)) {
626
- const threads = data.subject.threads.concat(state.staging[fullyQualifiedId(data.subject)]).filter(nonNullable2);
627
- const createSort = threadProvides.find((p) => p.predicate(data.subject))?.createSort;
628
- if (createSort) {
629
- const sort = createSort(data.subject);
630
- threads.sort((a, b) => sort(a.anchor, b.anchor));
631
- }
632
- const detached = data.subject.threads.filter(nonNullable2).filter(({ anchor }) => !anchor).map((thread) => thread.id);
633
- const qualifiedSubjectId = fullyQualifiedId(data.subject);
634
- const attention = attentionPlugin?.provides.attention?.attended ?? /* @__PURE__ */ new Set([
635
- qualifiedSubjectId
636
- ]);
637
- const attendableAttrs = createAttendableAttributes(qualifiedSubjectId);
638
- const { showResolvedThreads } = getViewState(qualifiedSubjectId);
639
- return /* @__PURE__ */ React5.createElement("div", {
640
- role: "none",
641
- className: "contents group/attention",
642
- ...attendableAttrs
643
- }, role === "complementary" && /* @__PURE__ */ React5.createElement(CommentsHeading, {
644
- attendableId: qualifiedSubjectId
645
- }), /* @__PURE__ */ React5.createElement(ScrollArea.Root, {
646
- classNames: "row-span-2"
647
- }, /* @__PURE__ */ React5.createElement(ScrollArea.Viewport, null, /* @__PURE__ */ React5.createElement(CommentsContainer, {
648
- threads,
649
- detached,
650
- currentId: attention.has(qualifiedSubjectId) ? state.current : void 0,
651
- autoFocusCurrentTextbox: state.focus,
652
- showResolvedThreads,
653
- onThreadAttend: (thread) => {
654
- if (state.current !== thread.id) {
655
- state.current = thread.id;
656
- void dispatch?.({
657
- action: LayoutAction.SCROLL_INTO_VIEW,
658
- data: {
659
- id: fullyQualifiedId(data.subject),
660
- thread: fullyQualifiedId(thread),
661
- cursor: thread.anchor
662
- }
663
- });
664
- }
665
- },
666
- onThreadDelete: (thread) => dispatch?.({
667
- plugin: THREAD_PLUGIN,
668
- action: ThreadAction.DELETE,
669
- data: {
670
- subject: data.subject,
671
- thread
672
- }
673
- }),
674
- onMessageDelete: (thread, messageId) => dispatch?.({
675
- plugin: THREAD_PLUGIN,
676
- action: ThreadAction.DELETE_MESSAGE,
677
- data: {
678
- subject: data.subject,
679
- thread,
680
- messageId
681
- }
682
- }),
683
- onThreadToggleResolved: (thread) => dispatch?.({
684
- plugin: THREAD_PLUGIN,
685
- action: ThreadAction.TOGGLE_RESOLVED,
686
- data: {
687
- thread
688
- }
689
- }),
690
- onComment: (thread) => {
691
- void intentPlugin?.provides.intent.dispatch({
692
- action: ThreadAction.ON_MESSAGE_ADD,
693
- data: {
694
- thread,
695
- subject: data.subject
696
- }
697
- });
698
- }
699
- }), /* @__PURE__ */ React5.createElement("div", {
700
- role: "none",
701
- className: "bs-10"
702
- }), /* @__PURE__ */ React5.createElement(ScrollArea.Scrollbar, null, /* @__PURE__ */ React5.createElement(ScrollArea.Thumb, null)))));
714
+ const { showResolvedThreads } = getViewState(fullyQualifiedId4(data.subject));
715
+ return /* @__PURE__ */ React6.createElement(ThreadComplementary, {
716
+ role,
717
+ subject: data.subject,
718
+ stagedThreads: state.staging[fullyQualifiedId4(data.subject)],
719
+ current: state.current,
720
+ focus: true,
721
+ showResolvedThreads
722
+ });
703
723
  }
704
724
  }
705
725
  }
@@ -712,7 +732,20 @@ var ThreadPlugin = () => {
712
732
  case ThreadAction.CREATE: {
713
733
  if (intent.data && intent.data.cursor !== void 0) {
714
734
  const { cursor, name, subject } = intent.data;
715
- const subjectId = fullyQualifiedId(subject);
735
+ if (subject?.threads === void 0) {
736
+ try {
737
+ subject.threads = [];
738
+ } catch (e) {
739
+ log.error("Subject does not support threads array", subject?.typename, {
740
+ F: __dxlog_file,
741
+ L: 331,
742
+ S: void 0,
743
+ C: (f, a) => f(...a)
744
+ });
745
+ return;
746
+ }
747
+ }
748
+ const subjectId = fullyQualifiedId4(subject);
716
749
  const thread = create2(ThreadType, {
717
750
  name,
718
751
  anchor: cursor,
@@ -731,23 +764,15 @@ var ThreadPlugin = () => {
731
764
  data: thread,
732
765
  intents: [
733
766
  [
734
- {
735
- action: NavigationAction.OPEN,
736
- data: {
737
- activeParts: {
738
- complementary: `${subjectId}${SLUG_PATH_SEPARATOR}comments${SLUG_COLLECTION_INDICATOR}`
739
- }
740
- }
741
- },
742
767
  {
743
768
  action: ThreadAction.SELECT,
744
769
  data: {
745
- current: thread.id,
770
+ current: fullyQualifiedId4(thread),
746
771
  focus: true
747
772
  }
748
773
  },
749
774
  {
750
- action: LayoutAction.SET_LAYOUT,
775
+ action: LayoutAction2.SET_LAYOUT,
751
776
  data: {
752
777
  element: "complementary",
753
778
  subject: subjectId,
@@ -807,16 +832,18 @@ var ThreadPlugin = () => {
807
832
  }
808
833
  case ThreadAction.DELETE: {
809
834
  const { subject, thread } = intent.data ?? {};
810
- if (!(subject instanceof DocumentType) || !(thread instanceof ThreadType)) {
835
+ if (!(thread instanceof ThreadType) || !(subject && typeof subject === "object" && "threads" in subject)) {
811
836
  return;
812
837
  }
813
- const subjectId = fullyQualifiedId(subject);
838
+ const subjectId = fullyQualifiedId4(subject);
814
839
  const stagingArea = state.staging[subjectId];
815
840
  if (stagingArea) {
816
841
  const index = stagingArea.findIndex((t) => t.id === thread.id);
817
842
  if (index !== -1) {
818
843
  stagingArea.splice(index, 1);
819
- return;
844
+ return {
845
+ data: true
846
+ };
820
847
  }
821
848
  }
822
849
  const space = getSpace2(thread);
@@ -877,10 +904,10 @@ var ThreadPlugin = () => {
877
904
  }
878
905
  case ThreadAction.ON_MESSAGE_ADD: {
879
906
  const { thread, subject } = intent.data ?? {};
880
- if (!(thread instanceof ThreadType) || !(subject && typeof subject === "object" && "threads" in subject)) {
907
+ if (!(thread instanceof ThreadType) || !(subject && typeof subject === "object" && "threads" in subject && Array.isArray(subject.threads))) {
881
908
  return;
882
909
  }
883
- const subjectId = fullyQualifiedId(subject);
910
+ const subjectId = fullyQualifiedId4(subject);
884
911
  const space = getSpace2(subject);
885
912
  const intents = [];
886
913
  const analyticsProperties = {
@@ -921,7 +948,7 @@ var ThreadPlugin = () => {
921
948
  case ThreadAction.DELETE_MESSAGE: {
922
949
  const { subject, thread, messageId } = intent.data ?? {};
923
950
  const space = getSpace2(subject);
924
- if (!(subject instanceof DocumentType) || !(thread instanceof ThreadType) || !space) {
951
+ if (!(thread instanceof ThreadType) || !(subject && typeof subject === "object" && "threads" in subject)) {
925
952
  return;
926
953
  }
927
954
  if (!intent.undo) {
@@ -963,7 +990,7 @@ var ThreadPlugin = () => {
963
990
  name: "threads.message.delete",
964
991
  properties: {
965
992
  threadId: thread.id,
966
- spaceId: space.id
993
+ spaceId: space?.id
967
994
  }
968
995
  }
969
996
  }
@@ -987,7 +1014,7 @@ var ThreadPlugin = () => {
987
1014
  name: "threads.message.undo-delete",
988
1015
  properties: {
989
1016
  threadId: thread.id,
990
- spaceId: space.id
1017
+ spaceId: space?.id
991
1018
  }
992
1019
  }
993
1020
  }
@@ -1009,8 +1036,8 @@ var ThreadPlugin = () => {
1009
1036
  ];
1010
1037
  }
1011
1038
  const threads = computed(() => [
1012
- ...doc.threads.filter(nonNullable2),
1013
- ...state.staging[fullyQualifiedId(doc)] ?? []
1039
+ ...doc.threads.filter(nonNullable3),
1040
+ ...state.staging[fullyQualifiedId4(doc)] ?? []
1014
1041
  ].filter((thread) => !(thread?.status === "resolved")));
1015
1042
  return [
1016
1043
  listener2({
@@ -1029,7 +1056,7 @@ var ThreadPlugin = () => {
1029
1056
  }
1030
1057
  }),
1031
1058
  createExternalCommentSync(doc.id, (sink) => effect(() => sink()), () => threads.value.filter((thread) => thread?.anchor).map((thread) => ({
1032
- id: thread.id,
1059
+ id: fullyQualifiedId4(thread),
1033
1060
  cursor: thread.anchor
1034
1061
  }))),
1035
1062
  comments({
@@ -1049,9 +1076,9 @@ var ThreadPlugin = () => {
1049
1076
  });
1050
1077
  },
1051
1078
  onDelete: ({ id }) => {
1052
- const stagingArea = state.staging[fullyQualifiedId(doc)];
1079
+ const stagingArea = state.staging[fullyQualifiedId4(doc)];
1053
1080
  if (stagingArea) {
1054
- const index = stagingArea.findIndex((thread2) => thread2.id === id);
1081
+ const index = stagingArea.findIndex((thread2) => fullyQualifiedId4(thread2) === id);
1055
1082
  if (index !== -1) {
1056
1083
  stagingArea.splice(index, 1);
1057
1084
  }
@@ -1062,7 +1089,7 @@ var ThreadPlugin = () => {
1062
1089
  }
1063
1090
  },
1064
1091
  onUpdate: ({ id, cursor }) => {
1065
- const thread = state.staging[fullyQualifiedId(doc)]?.find((thread2) => thread2.id === id) ?? doc.threads.find((thread2) => thread2?.id === id);
1092
+ const thread = state.staging[fullyQualifiedId4(doc)]?.find((thread2) => fullyQualifiedId4(thread2) === id) ?? doc.threads.find((thread2) => thread2?.id === id);
1066
1093
  if (thread instanceof ThreadType && thread.anchor) {
1067
1094
  const [start, end] = thread.anchor.split(":");
1068
1095
  thread.name = doc.content && getTextInRange(createDocAccessor(doc.content, [
@@ -1072,9 +1099,9 @@ var ThreadPlugin = () => {
1072
1099
  }
1073
1100
  },
1074
1101
  onSelect: ({ selection: { current, closest } }) => {
1075
- const dispatch2 = intentPlugin?.provides.intent.dispatch;
1076
- if (dispatch2) {
1077
- void dispatch2([
1102
+ const dispatch = intentPlugin?.provides.intent.dispatch;
1103
+ if (dispatch) {
1104
+ void dispatch([
1078
1105
  {
1079
1106
  action: ThreadAction.SELECT,
1080
1107
  data: {