@dxos/plugin-thread 0.6.12-main.f9d0246 → 0.6.12-staging.0b4bb48

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