@arbidocs/blocks 0.5.1 → 0.5.2

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 (35) hide show
  1. package/dist/{ConnectedCallDock-7O6VPYVI.cjs → ConnectedCallDock-NNX5PEPK.cjs} +3 -3
  2. package/dist/{ConnectedCallDock-7O6VPYVI.cjs.map → ConnectedCallDock-NNX5PEPK.cjs.map} +1 -1
  3. package/dist/{ConnectedCallDock-74BBCKXO.js → ConnectedCallDock-UGGY6YUK.js} +3 -3
  4. package/dist/{ConnectedCallDock-74BBCKXO.js.map → ConnectedCallDock-UGGY6YUK.js.map} +1 -1
  5. package/dist/{ConnectedCallRoom-2HCE5YD2.cjs → ConnectedCallRoom-B7SZHQNV.cjs} +3 -3
  6. package/dist/{ConnectedCallRoom-2HCE5YD2.cjs.map → ConnectedCallRoom-B7SZHQNV.cjs.map} +1 -1
  7. package/dist/{ConnectedCallRoom-KAHBN5KO.js → ConnectedCallRoom-I4HPWMK2.js} +3 -3
  8. package/dist/{ConnectedCallRoom-KAHBN5KO.js.map → ConnectedCallRoom-I4HPWMK2.js.map} +1 -1
  9. package/dist/calls/index.cjs +2 -2
  10. package/dist/calls/index.js +2 -2
  11. package/dist/chat/index.cjs +4 -4
  12. package/dist/chat/index.js +1 -1
  13. package/dist/{chunk-KJXJRX33.js → chunk-DDCMLHXF.js} +4 -4
  14. package/dist/chunk-DDCMLHXF.js.map +1 -0
  15. package/dist/{chunk-LDRHUYRE.cjs → chunk-EBRYYVNH.cjs} +7 -7
  16. package/dist/{chunk-LDRHUYRE.cjs.map → chunk-EBRYYVNH.cjs.map} +1 -1
  17. package/dist/{chunk-26EQQQBX.js → chunk-PY5D6HBD.js} +5 -5
  18. package/dist/{chunk-26EQQQBX.js.map → chunk-PY5D6HBD.js.map} +1 -1
  19. package/dist/{chunk-OK3UJMO4.cjs → chunk-Z2XZ2D4N.cjs} +4 -4
  20. package/dist/chunk-Z2XZ2D4N.cjs.map +1 -0
  21. package/dist/connect/index.cjs +193 -109
  22. package/dist/connect/index.cjs.map +1 -1
  23. package/dist/connect/index.js +173 -89
  24. package/dist/connect/index.js.map +1 -1
  25. package/dist/connect/viewer.cjs +13 -13
  26. package/dist/connect/viewer.js +3 -3
  27. package/dist/connection/files/grid/documentGridBus.d.ts +12 -10
  28. package/dist/connection/messenger/ConnectedChatThread.d.ts +3 -1
  29. package/dist/connection/messenger/ConnectedMessenger.d.ts +21 -3
  30. package/dist/index.cjs +4 -4
  31. package/dist/index.js +1 -1
  32. package/node_modules/@arbidocs/coedit/package.json +1 -1
  33. package/package.json +5 -5
  34. package/dist/chunk-KJXJRX33.js.map +0 -1
  35. package/dist/chunk-OK3UJMO4.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkLDRHUYRE_cjs = require('../chunk-LDRHUYRE.cjs');
4
+ var chunkEBRYYVNH_cjs = require('../chunk-EBRYYVNH.cjs');
5
5
  var chunkIFAIUKQQ_cjs = require('../chunk-IFAIUKQQ.cjs');
6
6
  require('../chunk-2WLXQGWC.cjs');
7
7
  require('../chunk-223D4727.cjs');
@@ -35,7 +35,7 @@ require('../chunk-ZW6FPIFC.cjs');
35
35
  var chunk25YFJLFP_cjs = require('../chunk-25YFJLFP.cjs');
36
36
  require('../chunk-ULWRNGGE.cjs');
37
37
  require('../chunk-5UHAWSEX.cjs');
38
- require('../chunk-OK3UJMO4.cjs');
38
+ require('../chunk-Z2XZ2D4N.cjs');
39
39
  require('../chunk-B6MVQCXW.cjs');
40
40
  require('../chunk-32HW2Q33.cjs');
41
41
  var chunkFX3K6LNZ_cjs = require('../chunk-FX3K6LNZ.cjs');
@@ -150,9 +150,9 @@ function fileExtension(fileName) {
150
150
  function useViewedDocument(documentId) {
151
151
  const [webmHasVideoTrack, setWebmHasVideoTrack] = React.useState(null);
152
152
  React.useEffect(() => setWebmHasVideoTrack(null), [documentId]);
153
- const streamingDoc = chunkLDRHUYRE_cjs.useViewerStreamingDocument(documentId);
153
+ const streamingDoc = chunkEBRYYVNH_cjs.useViewerStreamingDocument(documentId);
154
154
  const isStreaming = !!streamingDoc && !streamingDoc.isComplete;
155
- const draftDoc = chunkLDRHUYRE_cjs.useViewerDraftDocument(documentId);
155
+ const draftDoc = chunkEBRYYVNH_cjs.useViewerDraftDocument(documentId);
156
156
  const isDraft = !!draftDoc;
157
157
  const isCaptureDraft = draftDoc?.kind === "audio" || draftDoc?.kind === "photo" || draftDoc?.kind === "video";
158
158
  const isTextDraft = draftDoc?.kind === "text";
@@ -233,7 +233,7 @@ function useViewerBlobs(documentId, doc) {
233
233
  const { setWebmHasVideoTrack } = doc;
234
234
  const { client, saveFile } = documentTools.useDocumentTools();
235
235
  const { notify } = chunk25YFJLFP_cjs.useBlocksEnvironment();
236
- const { loadOfflineCopy } = chunkLDRHUYRE_cjs.useDocumentViewerSupport();
236
+ const { loadOfflineCopy } = chunkEBRYYVNH_cjs.useDocumentViewerSupport();
237
237
  const currentVersion = documentData?.current_version ?? 1;
238
238
  const name = documentData?.file_name;
239
239
  const original = ui.isImageFile(name) || ui.isVideoFile(name) || ui.isAudioFile(name);
@@ -593,7 +593,7 @@ function PassageTagPanel({
593
593
  onClose,
594
594
  onViewTaggedChunks
595
595
  }) {
596
- const { createTag } = chunkLDRHUYRE_cjs.useDocumentViewerSupport();
596
+ const { createTag } = chunkEBRYYVNH_cjs.useDocumentViewerSupport();
597
597
  const [editingNoteTagId, setEditingNoteTagId] = React.useState(null);
598
598
  const [noteValue, setNoteValue] = React.useState("");
599
599
  const { data: allTags } = chunk5DXTO7CE_cjs.useConnectedTags();
@@ -837,7 +837,7 @@ var ParsedPassage = React.memo(function ParsedPassage2({
837
837
  items: passageItems
838
838
  }
839
839
  ) : void 0,
840
- children: /* @__PURE__ */ jsxRuntime.jsx(chunkLDRHUYRE_cjs.ConnectedMarkdown, { children: chunk.content })
840
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkEBRYYVNH_cjs.ConnectedMarkdown, { children: chunk.content })
841
841
  }
842
842
  );
843
843
  });
@@ -1065,7 +1065,7 @@ function useCitationSelection({
1065
1065
  orderedChunkIds,
1066
1066
  pageOf
1067
1067
  }) {
1068
- const passageCitation = chunkLDRHUYRE_cjs.useViewerPassageCitation();
1068
+ const passageCitation = chunkEBRYYVNH_cjs.useViewerPassageCitation();
1069
1069
  const activeCitationContext = passageCitation?.active ?? null;
1070
1070
  const setPendingPassagesForCitation = passageCitation?.pick ?? noop;
1071
1071
  const setUnselectedPassagesForCitation = passageCitation?.unpick ?? noop;
@@ -1422,7 +1422,7 @@ function ParsedTextView({
1422
1422
  onZoomChange
1423
1423
  }) {
1424
1424
  const { workspaceId } = chunkLMXMUWPA_cjs.useConnectedWorkspace();
1425
- const { openInNavigator } = chunkLDRHUYRE_cjs.useDocumentViewerSupport();
1425
+ const { openInNavigator } = chunkEBRYYVNH_cjs.useDocumentViewerSupport();
1426
1426
  const containerRef = React.useRef(null);
1427
1427
  const { data: documentRecord } = react.useDocument(artifacts.parseVersionRef(documentId).docId, {
1428
1428
  enabled: !!documentId && !!workspaceId
@@ -1585,7 +1585,7 @@ var GuidedSigningViewer = React.lazy(
1585
1585
  function SessionPdfViewer(props) {
1586
1586
  const session = react.useArbiSessionStore();
1587
1587
  const viewingId = react.useArbiSessionState((s) => s.viewingDocument?.id);
1588
- const isDetached = chunkLDRHUYRE_cjs.useViewerIsDetached();
1588
+ const isDetached = chunkEBRYYVNH_cjs.useViewerIsDetached();
1589
1589
  const onPageChange = React.useCallback(
1590
1590
  (page) => {
1591
1591
  if (viewingId) session.setViewingDocument({ id: viewingId, page });
@@ -1742,7 +1742,7 @@ function ConnectedDocumentViewer(props) {
1742
1742
  resetKey: openedId,
1743
1743
  labels: { title: "This document couldn't be displayed" },
1744
1744
  testId: "document-viewer-error",
1745
- children: /* @__PURE__ */ jsxRuntime.jsx(chunkLDRHUYRE_cjs.ConnectedDocumentToolsProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(DocumentViewerContent, { ...props, openedId }) })
1745
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkEBRYYVNH_cjs.ConnectedDocumentToolsProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(DocumentViewerContent, { ...props, openedId }) })
1746
1746
  }
1747
1747
  );
1748
1748
  }
@@ -1753,7 +1753,7 @@ function DocumentViewerContent({
1753
1753
  }) {
1754
1754
  const arbi = react.useArbi();
1755
1755
  const session = react.useArbiSessionStore();
1756
- const support = chunkLDRHUYRE_cjs.useDocumentViewerSupport();
1756
+ const support = chunkEBRYYVNH_cjs.useDocumentViewerSupport();
1757
1757
  const formatDate = support.formatDate ?? chunkKDG6FER6_cjs.fmtDate;
1758
1758
  const tools = documentTools.useDocumentTools();
1759
1759
  const { openConversation, notify } = chunk25YFJLFP_cjs.useBlocksEnvironment();
@@ -2323,7 +2323,7 @@ function DocumentViewerContent({
2323
2323
 
2324
2324
  Object.defineProperty(exports, "ConnectedDocumentToolsProvider", {
2325
2325
  enumerable: true,
2326
- get: function () { return chunkLDRHUYRE_cjs.ConnectedDocumentToolsProvider; }
2326
+ get: function () { return chunkEBRYYVNH_cjs.ConnectedDocumentToolsProvider; }
2327
2327
  });
2328
2328
  exports.ConnectedDocumentViewer = ConnectedDocumentViewer;
2329
2329
  //# sourceMappingURL=viewer.cjs.map
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { ConnectedMarkdown, ConnectedDocumentToolsProvider, useDocumentViewerSupport, useViewerStreamingDocument, useViewerDraftDocument, useViewerIsDetached, useViewerPassageCitation } from '../chunk-26EQQQBX.js';
3
- export { ConnectedDocumentToolsProvider } from '../chunk-26EQQQBX.js';
2
+ import { ConnectedMarkdown, ConnectedDocumentToolsProvider, useDocumentViewerSupport, useViewerStreamingDocument, useViewerDraftDocument, useViewerIsDetached, useViewerPassageCitation } from '../chunk-PY5D6HBD.js';
3
+ export { ConnectedDocumentToolsProvider } from '../chunk-PY5D6HBD.js';
4
4
  import { HtmlPassage, ViewerTitle, ViewerTabBar, ViewerImageActions, canChangeVisibility, ViewerFrame, ViewerMessage, DocumentLabelBar, ViewerControlBar, ViewerZoomControl, PdfPageNav, ViewerPageCounter, summariseDocTags, isDocumentLabel, ViewerPreviewUnavailable, ViewerLoadError, HtmlViewerRoot, CitedRunNav, HtmlViewerSurface, HtmlPage, HtmlViewerEmpty, TagPassagePanel } from '../chunk-QE7MS7NA.js';
5
5
  import '../chunk-JJA6GQKH.js';
6
6
  import '../chunk-RC6VTY2H.js';
@@ -34,7 +34,7 @@ import '../chunk-P6GHJSLR.js';
34
34
  import { useBlocksEnvironment } from '../chunk-GKM4EOH7.js';
35
35
  import '../chunk-TX2ZICS7.js';
36
36
  import '../chunk-OKERRHLH.js';
37
- import '../chunk-KJXJRX33.js';
37
+ import '../chunk-DDCMLHXF.js';
38
38
  import '../chunk-7XF5SFJ2.js';
39
39
  import '../chunk-AUS3KBHJ.js';
40
40
  import { useIsPhone } from '../chunk-SLSBJRWW.js';
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Document Grid Bus
3
3
  *
4
- * Applies the row changes of every write to the documents list (`@arbidocs/react`
4
+ * Applies the row updates of every write to the documents list (`@arbidocs/react`
5
5
  * `subscribeDocumentRows`) to the Files AG Grid as `applyTransactionAsync` transactions.
6
6
  *
7
7
  * Why a bus:
@@ -29,18 +29,20 @@ export declare function registerDocumentGridApi(api: GridApi<Doc>): void;
29
29
  */
30
30
  export declare function unregisterDocumentGridApi(api: GridApi<Doc>): void;
31
31
  /**
32
- * Apply one write's row changes to the grid as a single transaction.
32
+ * Apply one write's row updates to the grid as a single transaction.
33
33
  *
34
- * Adds are not sent: AG Grid's React integration, with `rowData` AND `getRowId` set (the Files grid
35
- * sets both), diffs every `rowData` change and queues its OWN add transactions. An add queued here
36
- * would collide with AG Grid's for the same id in the same flush window ("Duplicate node id", a
37
- * phantom second row), so the `rowData` diff carries adds. An add whose id the grid already holds
38
- * (a sibling path raced ahead) is sent as an update so the cell still refreshes.
34
+ * Adds and removes are not sent: AG Grid's React integration, with `rowData` AND `getRowId` set
35
+ * (the Files grid sets both), diffs every `rowData` change and queues its OWN add and remove
36
+ * transactions. An add queued here would collide with AG Grid's for the same id in the same flush
37
+ * window ("Duplicate node id", a phantom second row); a remove queued here reaches a grid the diff
38
+ * has already taken the row out of, and AG Grid logs `error #4: Could not find row id=…` for it
39
+ * (every delete). An add whose id the grid already holds (a sibling path raced ahead) is sent as an
40
+ * update so the cell still refreshes.
39
41
  *
40
- * Updates are filtered to ids the grid holds: AG Grid logs `error #4: Could not find row id=…` for
41
- * every unmatched id (processing events for rows the `rowData` diff has not flushed yet).
42
+ * Updates are filtered to ids the grid holds: AG Grid logs error #4 for every unmatched id
43
+ * (processing events for rows the `rowData` diff has not flushed yet).
42
44
  */
43
- export declare function applyDocumentRowChange({ add, update, remove }: DocumentRowChange): void;
45
+ export declare function applyDocumentRowChange({ add, update }: DocumentRowChange): void;
44
46
  /**
45
47
  * Test-only: reset module state between tests.
46
48
  * @internal
@@ -17,5 +17,7 @@ export interface ConnectedChatThreadProps {
17
17
  host?: MessengerHost;
18
18
  /** Called after a message is sent. */
19
19
  onMessageSent?: () => void;
20
+ /** The composer's placeholder. Default: "Type a message…". */
21
+ placeholder?: string;
20
22
  }
21
- export declare function ConnectedChatThread({ chat, peer, host, onMessageSent, }: ConnectedChatThreadProps): import("react").JSX.Element;
23
+ export declare function ConnectedChatThread({ chat, peer, host, onMessageSent, placeholder, }: ConnectedChatThreadProps): import("react").JSX.Element;
@@ -1,15 +1,21 @@
1
1
  /**
2
- * The chats messenger for a side panel: the list of chats OR one thread, never both.
2
+ * The chats messenger. `layout="panel"` (default, a side panel): the list of chats OR one thread.
3
3
  *
4
4
  * - nothing open → the chat rows fill the panel, "+ Invite", "New group" (and the host's
5
5
  * list actions, e.g. "New call") first
6
6
  * - one open → the thread fills it under a static identity header
7
7
  *
8
+ * `layout="split"` (a messages page): one card with the "Conversations · N colleagues" rail
9
+ * (the invite chips pinned under its heading, unread counts, the open row highlighted) beside the
10
+ * open thread (its contact header, the messages and a "Message <name>…" composer), or
11
+ * `emptyThread` while nothing is open. On a phone it is one or the other, with a way back to the
12
+ * list (`onBack`). Every colour is a theme token, so each site looks like itself.
13
+ *
8
14
  * A row is a direct chat (a person, myself, or my agent), a group or a meeting chat, plus the
9
15
  * people I can message and have no chat with yet. Rows are the shared <ConversationList>; the
10
16
  * thread is <ConnectedChatThread>. Which conversation is open is the host's (its tabs).
11
17
  */
12
- import { type ReactNode } from 'react';
18
+ import { type CSSProperties, type ReactNode } from 'react';
13
19
  import { type ChatResponse, type DmConversation, type DmUser } from '@arbidocs/react';
14
20
  import type { MessengerHost } from './types';
15
21
  /** Tri-state filters (a host's filter menu), keyed by what they select for. */
@@ -47,6 +53,18 @@ export interface ConnectedMessengerProps {
47
53
  /** Controls in a group's header, before the members button. */
48
54
  groupActions?: (chat: ChatResponse, title: string | null) => ReactNode;
49
55
  host?: MessengerHost;
56
+ /**
57
+ * `panel` (default): the list or the open thread, for a side panel. `split`: the messages page,
58
+ * the list beside the open thread with the open row highlighted (one or the other on a phone).
59
+ */
60
+ layout?: 'panel' | 'split';
61
+ /** `split`: what the thread side shows while nothing is open. Default: "No conversation selected". */
62
+ emptyThread?: ReactNode;
63
+ /** `split` on a phone: go back from the open thread to the list (absent: no back button). */
64
+ onBack?: () => void;
65
+ /** `split`: the card's classes and size. Default height: the viewport less a page header. */
66
+ className?: string;
67
+ style?: CSSProperties;
50
68
  }
51
- export declare function ConnectedMessenger({ activeId, onOpen, onClose, people, extraRows, filters, rowFilters, onInvite, listActions, directActions, groupActions, host, }: ConnectedMessengerProps): import("react").JSX.Element;
69
+ export declare function ConnectedMessenger({ activeId, onOpen, onClose, people, extraRows, filters, rowFilters, onInvite, listActions, directActions, groupActions, host, layout, emptyThread, onBack, className, style, }: ConnectedMessengerProps): import("react").JSX.Element | null;
52
70
  export {};
package/dist/index.cjs CHANGED
@@ -53,7 +53,7 @@ var chunk4KMYUM7Q_cjs = require('./chunk-4KMYUM7Q.cjs');
53
53
  var chunkF66OH26L_cjs = require('./chunk-F66OH26L.cjs');
54
54
  var chunkLHWKA2XI_cjs = require('./chunk-LHWKA2XI.cjs');
55
55
  var chunk5UHAWSEX_cjs = require('./chunk-5UHAWSEX.cjs');
56
- var chunkOK3UJMO4_cjs = require('./chunk-OK3UJMO4.cjs');
56
+ var chunkZ2XZ2D4N_cjs = require('./chunk-Z2XZ2D4N.cjs');
57
57
  var chunkB6MVQCXW_cjs = require('./chunk-B6MVQCXW.cjs');
58
58
  var chunkDHOIO3B7_cjs = require('./chunk-DHOIO3B7.cjs');
59
59
  var chunk76L6LOP3_cjs = require('./chunk-76L6LOP3.cjs');
@@ -3801,15 +3801,15 @@ Object.defineProperty(exports, "Toaster", {
3801
3801
  });
3802
3802
  Object.defineProperty(exports, "DOC_ID_IN_HREF", {
3803
3803
  enumerable: true,
3804
- get: function () { return chunkOK3UJMO4_cjs.DOC_ID_IN_HREF; }
3804
+ get: function () { return chunkZ2XZ2D4N_cjs.DOC_ID_IN_HREF; }
3805
3805
  });
3806
3806
  Object.defineProperty(exports, "rehypeDocEntityPills", {
3807
3807
  enumerable: true,
3808
- get: function () { return chunkOK3UJMO4_cjs.rehypeDocEntityPills; }
3808
+ get: function () { return chunkZ2XZ2D4N_cjs.rehypeDocEntityPills; }
3809
3809
  });
3810
3810
  Object.defineProperty(exports, "workspaceDocIdFromHref", {
3811
3811
  enumerable: true,
3812
- get: function () { return chunkOK3UJMO4_cjs.workspaceDocIdFromHref; }
3812
+ get: function () { return chunkZ2XZ2D4N_cjs.workspaceDocIdFromHref; }
3813
3813
  });
3814
3814
  Object.defineProperty(exports, "BlocksTooltipProvider", {
3815
3815
  enumerable: true,
package/dist/index.js CHANGED
@@ -51,7 +51,7 @@ export { AssistantToaster, ContextActionButton, ContextCheckRow, ContextPanelCon
51
51
  export { BranchControls, ComposerAccessories, ComposerTools, ContextUsageBar, Conversation, ConversationBody, ConversationHeader, ConversationHeaderActions, ConversationHistoryPane, ConversationLoading, ConversationMain, ConversationRoot, ConversationSettingsButton, DEFAULT_BRANCH_CONTROLS_LABELS, DEFAULT_CONVERSATION_LAYOUT_LABELS, DEFAULT_CONVERSATION_PARTS_LABELS, DEFAULT_DRAFTING_DOC_CHIP_LABELS, DEFAULT_MODEL_PRICING_TIP_LABELS, DEFAULT_PENDING_ANSWER_BAR_LABELS, DEFAULT_SLASH_MENU_LABELS, DEFAULT_THREAD_MAP_LABELS, DEFAULT_THREAD_VISUALIZER_LABELS, DraftingDocChip, ModelAutoIcon, ModelConfigureButton, ModelDot, ModelMenuDivider, ModelMenuMessage, ModelOption, ModelOptionLabel, ModelPickerPopover, ModelPickerTrigger, ModelPricingTip, ModelTierIcon, ModelTierOption, ModelTriggerContent, NewChatButton, NewPaChatButton, PaModeBadge, PendingAnswerBar, SlashMenu, ThreadMap, ThreadMapDiagram, ThreadMapError, ThreadMapLoading, ThreadVisualizer, buildMessageLink, buildSlashItems, buildThreadDiagram, copyMessageToClipboard, downloadTableAsCsv, filterSlashItems, findMessageDocument, flashMessage, getParticipantTints, groupOutputsByConversation, isLongPastedText, latestThreadVersionMessage, parseSlashTokenInProgress as parseSlashToken, threadForNode, useLongPaste, useRecipientDraft } from './chunk-ULQV2NJT.js';
52
52
  export { AssistantDock, AssistantDockToggle, AssistantModeToggle, ChatDocuments, ChatMessageContent, ChatPage, ChatThreadList, ChatThreadSelect, CitationMark, Composer, ComposerBranchingNotice, ComposerContainer, ComposerDock, ComposerFrame, ComposerInput, ComposerRoot, ComposerSend, ComposerToolbar, ComposerVoiceButton, ContextChip, ConversationEmpty, DEFAULT_ASSISTANT_MODE_TOGGLE_LABELS, DEFAULT_CHAT_PAGE_LABELS, DEFAULT_COMPOSER_LABELS, DEFAULT_CONVERSATION_EMPTY_LABELS, DEFAULT_MESSAGE_ALERT_LABELS, DEFAULT_MESSAGE_LABELS, DEFAULT_MESSAGE_LIST_LABELS, DEFAULT_WORKFLOW_STEP_CHIP_LABELS, Message, MessageActionButton, MessageActionMenu, MessageAlert, MessageAuthor, MessageBody, MessageBubble, MessageByline, MessageContent, MessageFooter, MessageList, MessageListBanner, MessageListEmpty, MessageListRoot, MessageListRow, MessageListRows, MessageListStatus, MessageListTail, MessageNarration, MessageRoot, MessageSources, MessageSubagentBadge, ScrollToBottom, SourceChip, WorkflowStepChip, toSpeakableText, useAssistantDock, useChatSurface, useRegisterEmbeddedChat, useStreamAnnouncement } from './chunk-BKNHCORH.js';
53
53
  export { DEFAULT_DOCK_WIDTH, Toaster } from './chunk-OKERRHLH.js';
54
- export { DOC_ID_IN_HREF, rehypeDocEntityPills, workspaceDocIdFromHref } from './chunk-KJXJRX33.js';
54
+ export { DOC_ID_IN_HREF, rehypeDocEntityPills, workspaceDocIdFromHref } from './chunk-DDCMLHXF.js';
55
55
  export { BlocksTooltipProvider, DEFAULT_OVERLAY_ZONE_ID, DEFAULT_PAGE_CONTAINER_PADDING, DEFAULT_SIDEBAR_TOGGLE_BUTTON_LABELS, PageContainer, SHELL_BOTTOM_INSET_VAR, Shell, SidebarToggleButton, ToolButton, useDrawerBehavior, useOverlayZoneId, useShellBottomInset } from './chunk-7XF5SFJ2.js';
56
56
  export { DEFAULT_ASSIGNEE_WORDING, DEFAULT_STEP_DOCUMENT_LABELS, DEFAULT_STEP_KIND_LABELS, DEFAULT_STEP_RECORD_LABELS, STEP_KIND_ICONS, StepDocumentButton, StepDocumentCards, StepRecord, WORKFLOW_STEP_KINDS, assigneeName, canAssign, composeStepPrompt, dependsOn, fillRunText, fillStepInputs, initialRunInputs, isPersonAction, isPersonStep, isRunFinished, isSteppedWorkflow, nextAction, orderSteps, reviewInstructions, runFields, runFieldsOf, runThreadTitle, sendBackTargets, splitDocRef, stepConfigProblems, stepDependencies, stepDocuments, stepFields, stepKindOf, stepLevels, stepPhase, stepStatesFromActivity, upstreamSteps, useMentionAutocomplete, validateStep, validateWorkflowGraph, workflowSteps } from './chunk-3KZWRDPY.js';
57
57
  export { EMPTY_WORKFLOW_SCOPE, SKILL_PROMPT_FALLBACK_PLACEHOLDER, SKILL_PROMPT_LABEL, buildLaunch, composeWorkflowPrompt, defaultInputs, fieldToFrontmatter, inputsFromContext, isEmptyWorkflowScope, isWorkflowScope, mergeSkillWorkflows, promptFieldName, skillTitle, skillToWorkflow, validateInputs, workflowAccepts, workflowFromFrontmatter, workflowsAccepting, workflowsForHost } from './chunk-TZGBRLPK.js';
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arbidocs/coedit",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Real-time collaboration for the ARBI native DOCX editor: a Yjs mirror of the canonical OOXML package, session, and server runtime",
5
5
  "type": "module",
6
6
  "sideEffects": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arbidocs/blocks",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Composable, domain-neutral UI blocks for ARBI apps, organised by capability (retrieval, facts, agents, workspaces, citations, collaboration) plus shell, theme and site primitives, on top of @arbidocs/react.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -296,9 +296,9 @@
296
296
  "example:test:e2e": "playwright test -c examples/custom-ui/playwright.config.ts"
297
297
  },
298
298
  "dependencies": {
299
- "@arbidocs/client": "0.5.1",
300
- "@arbidocs/coedit": "0.5.1",
301
- "@arbidocs/sdk": "0.5.1",
299
+ "@arbidocs/client": "0.5.2",
300
+ "@arbidocs/coedit": "0.5.2",
301
+ "@arbidocs/sdk": "0.5.2",
302
302
  "@auth0/auth0-react": "^2.19.0",
303
303
  "@dnd-kit/core": "^6.3.1",
304
304
  "@dnd-kit/sortable": "^10.0.0",
@@ -345,7 +345,7 @@
345
345
  "y-protocols": "^1.0.6"
346
346
  },
347
347
  "peerDependencies": {
348
- "@arbidocs/react": "0.5.1",
348
+ "@arbidocs/react": "0.5.2",
349
349
  "@lexical/html": "0.35.0",
350
350
  "@lexical/link": "0.35.0",
351
351
  "@lexical/list": "0.35.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/chat/doc-links.ts","../src/chat/rehype-doc-entity-pills.ts"],"names":[],"mappings":"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","file":"chunk-KJXJRX33.js","sourcesContent":["/**\n * Recognising workspace-document links inside rendered markdown hrefs.\n */\n\n/**\n * A workspace document id in an href — `doc-` plus EXACTLY eight alphanumerics,\n * the format every model in the backend pins (`^doc-[a-zA-Z0-9]{8}$`).\n *\n * `{8,}` would swallow an unrelated external URL that merely contains a `doc-…`\n * segment (`https://example.com/doc-download1234`) and route it to a viewer that\n * has nothing to show.\n */\nexport const DOC_ID_IN_HREF = /\\b(doc-[a-zA-Z0-9]{8})\\b/\n\n/**\n * The document id an href points at, or null if it does not address one of OURS.\n *\n * Absolute URLs qualify only for this origin or the deployment (`deploymentDomain`, the blocks\n * environment's `runtimeConfig.deploymentDomain`).\n * Development UI and API hosts can differ. Unrelated origins remain external. The\n * observed shape is the bare id (`[title](doc-35ce54e8)`), which is relative.\n */\nexport function workspaceDocIdFromHref(\n href: string | undefined,\n deploymentDomain?: string | null\n): string | null {\n if (!href) return null\n const match = DOC_ID_IN_HREF.exec(href)\n if (!match) return null\n if (/^[a-z][a-z0-9+.-]*:/i.test(href)) {\n try {\n const target = new URL(href)\n const isDeployment =\n !!deploymentDomain && target.protocol === 'https:' && target.hostname === deploymentDomain\n if (target.origin !== window.location.origin && !isDeployment) return null\n } catch {\n return null\n }\n }\n return match[1]\n}\n","// A document (doc-…) or an email of the person's own mailbox (eml-…): both render as entity pills.\nconst DOC_ID_PATTERN = /\\b((?:doc|eml)-[a-zA-Z0-9]+)\\b/\n\n/**\n * Per-text-node transform cache.\n *\n * Keyed by the raw text-node value. For the vast majority of text nodes — those\n * without any `doc-…` substring — we memoize the \"no match\" decision so a repeat\n * render of an unchanged message skips the regex entirely. When a node does\n * contain doc IDs we also cache the pre-built replacement children, so repeated\n * renders of a finished message don't re-scan or re-allocate.\n *\n * Uses a bounded LRU-ish Map — oldest entries are evicted when we exceed the\n * cap. This is a module singleton; across the app the hottest entries (tool\n * responses, common answer fragments) end up cached permanently for the session.\n */\nconst MAX_CACHE_ENTRIES = 512\nconst textCache = new Map<string, ReadonlyArray<unknown> | null>()\n\nfunction cacheGet(key: string): ReadonlyArray<unknown> | null | undefined {\n if (!textCache.has(key)) return undefined\n const value = textCache.get(key)\n // Touch to move it to the end of the insertion order (LRU).\n textCache.delete(key)\n textCache.set(key, value as ReadonlyArray<unknown> | null)\n return value\n}\n\nfunction cacheSet(key: string, value: ReadonlyArray<unknown> | null): void {\n if (textCache.size >= MAX_CACHE_ENTRIES) {\n const oldest = textCache.keys().next().value\n if (oldest !== undefined) textCache.delete(oldest)\n }\n textCache.set(key, value)\n}\n\n/**\n * Test-only helper to reset the memoization cache.\n * @internal\n */\nexport function __resetDocEntityPillCache(): void {\n textCache.clear()\n}\n\nfunction buildReplacementNodes(text: string): ReadonlyArray<unknown> | null {\n if (!DOC_ID_PATTERN.test(text)) return null\n\n const globalPattern = /\\b((?:doc|eml)-[a-zA-Z0-9]+)\\b/g\n const newNodes: unknown[] = []\n let lastIndex = 0\n let m: RegExpExecArray | null\n\n while ((m = globalPattern.exec(text)) !== null) {\n if (m.index > lastIndex) {\n newNodes.push({ type: 'text', value: text.slice(lastIndex, m.index) })\n }\n newNodes.push({\n type: 'element',\n tagName: 'span',\n properties: m[1].startsWith('eml-') ? { dataMailId: m[1] } : { dataDocId: m[1] },\n children: [],\n })\n lastIndex = m.index + m[0].length\n }\n\n if (lastIndex < text.length) {\n newNodes.push({ type: 'text', value: text.slice(lastIndex) })\n }\n\n return newNodes\n}\n\n/**\n * Rehype plugin that detects doc external IDs in text nodes and converts them to\n * <span data-doc-id=\"...\"> elements for rendering as entity pills in MarkdownRenderer.\n *\n * Skips text inside code/pre elements so IDs in code blocks are left as plain text.\n *\n * Results are memoized per text-node value — stable messages re-use the cached\n * decision instead of re-running the regex on every render.\n */\n/** A node of the HTML tree (hast), as far as the transform reads it. */\ninterface TreeNode {\n type: string\n tagName?: string\n value?: string\n children?: unknown[]\n}\n\n/** Replace the doc/mail ids in the text nodes under `parent` (code and pre are left alone). */\nfunction transformChildren(parent: TreeNode): void {\n const children = parent.children\n if (!children) return\n const inCode = parent.tagName === 'code' || parent.tagName === 'pre'\n for (let index = 0; index < children.length; index++) {\n const node = children[index] as TreeNode\n if (node.type !== 'text') {\n transformChildren(node)\n continue\n }\n if (inCode) continue\n const text = node.value ?? ''\n let replacement = cacheGet(text)\n if (replacement === undefined) {\n replacement = buildReplacementNodes(text)\n cacheSet(text, replacement)\n }\n if (replacement === null) continue\n // Clone cached nodes so each tree gets its own object identity. AST transforms by other\n // plugins may otherwise mutate shared references.\n const cloned = replacement.map((n) =>\n typeof n === 'object' && n !== null ? { ...(n as object) } : n\n )\n children.splice(index, 1, ...cloned)\n index += cloned.length - 1\n }\n}\n\nexport function rehypeDocEntityPills() {\n return (tree: TreeNode) => {\n transformChildren(tree)\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/chat/doc-links.ts","../src/chat/rehype-doc-entity-pills.ts"],"names":[],"mappings":"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","file":"chunk-OK3UJMO4.cjs","sourcesContent":["/**\n * Recognising workspace-document links inside rendered markdown hrefs.\n */\n\n/**\n * A workspace document id in an href — `doc-` plus EXACTLY eight alphanumerics,\n * the format every model in the backend pins (`^doc-[a-zA-Z0-9]{8}$`).\n *\n * `{8,}` would swallow an unrelated external URL that merely contains a `doc-…`\n * segment (`https://example.com/doc-download1234`) and route it to a viewer that\n * has nothing to show.\n */\nexport const DOC_ID_IN_HREF = /\\b(doc-[a-zA-Z0-9]{8})\\b/\n\n/**\n * The document id an href points at, or null if it does not address one of OURS.\n *\n * Absolute URLs qualify only for this origin or the deployment (`deploymentDomain`, the blocks\n * environment's `runtimeConfig.deploymentDomain`).\n * Development UI and API hosts can differ. Unrelated origins remain external. The\n * observed shape is the bare id (`[title](doc-35ce54e8)`), which is relative.\n */\nexport function workspaceDocIdFromHref(\n href: string | undefined,\n deploymentDomain?: string | null\n): string | null {\n if (!href) return null\n const match = DOC_ID_IN_HREF.exec(href)\n if (!match) return null\n if (/^[a-z][a-z0-9+.-]*:/i.test(href)) {\n try {\n const target = new URL(href)\n const isDeployment =\n !!deploymentDomain && target.protocol === 'https:' && target.hostname === deploymentDomain\n if (target.origin !== window.location.origin && !isDeployment) return null\n } catch {\n return null\n }\n }\n return match[1]\n}\n","// A document (doc-…) or an email of the person's own mailbox (eml-…): both render as entity pills.\nconst DOC_ID_PATTERN = /\\b((?:doc|eml)-[a-zA-Z0-9]+)\\b/\n\n/**\n * Per-text-node transform cache.\n *\n * Keyed by the raw text-node value. For the vast majority of text nodes — those\n * without any `doc-…` substring — we memoize the \"no match\" decision so a repeat\n * render of an unchanged message skips the regex entirely. When a node does\n * contain doc IDs we also cache the pre-built replacement children, so repeated\n * renders of a finished message don't re-scan or re-allocate.\n *\n * Uses a bounded LRU-ish Map — oldest entries are evicted when we exceed the\n * cap. This is a module singleton; across the app the hottest entries (tool\n * responses, common answer fragments) end up cached permanently for the session.\n */\nconst MAX_CACHE_ENTRIES = 512\nconst textCache = new Map<string, ReadonlyArray<unknown> | null>()\n\nfunction cacheGet(key: string): ReadonlyArray<unknown> | null | undefined {\n if (!textCache.has(key)) return undefined\n const value = textCache.get(key)\n // Touch to move it to the end of the insertion order (LRU).\n textCache.delete(key)\n textCache.set(key, value as ReadonlyArray<unknown> | null)\n return value\n}\n\nfunction cacheSet(key: string, value: ReadonlyArray<unknown> | null): void {\n if (textCache.size >= MAX_CACHE_ENTRIES) {\n const oldest = textCache.keys().next().value\n if (oldest !== undefined) textCache.delete(oldest)\n }\n textCache.set(key, value)\n}\n\n/**\n * Test-only helper to reset the memoization cache.\n * @internal\n */\nexport function __resetDocEntityPillCache(): void {\n textCache.clear()\n}\n\nfunction buildReplacementNodes(text: string): ReadonlyArray<unknown> | null {\n if (!DOC_ID_PATTERN.test(text)) return null\n\n const globalPattern = /\\b((?:doc|eml)-[a-zA-Z0-9]+)\\b/g\n const newNodes: unknown[] = []\n let lastIndex = 0\n let m: RegExpExecArray | null\n\n while ((m = globalPattern.exec(text)) !== null) {\n if (m.index > lastIndex) {\n newNodes.push({ type: 'text', value: text.slice(lastIndex, m.index) })\n }\n newNodes.push({\n type: 'element',\n tagName: 'span',\n properties: m[1].startsWith('eml-') ? { dataMailId: m[1] } : { dataDocId: m[1] },\n children: [],\n })\n lastIndex = m.index + m[0].length\n }\n\n if (lastIndex < text.length) {\n newNodes.push({ type: 'text', value: text.slice(lastIndex) })\n }\n\n return newNodes\n}\n\n/**\n * Rehype plugin that detects doc external IDs in text nodes and converts them to\n * <span data-doc-id=\"...\"> elements for rendering as entity pills in MarkdownRenderer.\n *\n * Skips text inside code/pre elements so IDs in code blocks are left as plain text.\n *\n * Results are memoized per text-node value — stable messages re-use the cached\n * decision instead of re-running the regex on every render.\n */\n/** A node of the HTML tree (hast), as far as the transform reads it. */\ninterface TreeNode {\n type: string\n tagName?: string\n value?: string\n children?: unknown[]\n}\n\n/** Replace the doc/mail ids in the text nodes under `parent` (code and pre are left alone). */\nfunction transformChildren(parent: TreeNode): void {\n const children = parent.children\n if (!children) return\n const inCode = parent.tagName === 'code' || parent.tagName === 'pre'\n for (let index = 0; index < children.length; index++) {\n const node = children[index] as TreeNode\n if (node.type !== 'text') {\n transformChildren(node)\n continue\n }\n if (inCode) continue\n const text = node.value ?? ''\n let replacement = cacheGet(text)\n if (replacement === undefined) {\n replacement = buildReplacementNodes(text)\n cacheSet(text, replacement)\n }\n if (replacement === null) continue\n // Clone cached nodes so each tree gets its own object identity. AST transforms by other\n // plugins may otherwise mutate shared references.\n const cloned = replacement.map((n) =>\n typeof n === 'object' && n !== null ? { ...(n as object) } : n\n )\n children.splice(index, 1, ...cloned)\n index += cloned.length - 1\n }\n}\n\nexport function rehypeDocEntityPills() {\n return (tree: TreeNode) => {\n transformChildren(tree)\n }\n}\n"]}