@arbidocs/blocks 0.5.115 → 0.5.117

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 (147) hide show
  1. package/dist/{ConnectedCallDock-WER7R222.cjs → ConnectedCallDock-OZBTU3IT.cjs} +20 -20
  2. package/dist/{ConnectedCallDock-WER7R222.cjs.map → ConnectedCallDock-OZBTU3IT.cjs.map} +1 -1
  3. package/dist/{ConnectedCallRoom-T7OBQTYP.cjs → ConnectedCallRoom-VMZE2NFP.cjs} +13 -13
  4. package/dist/{ConnectedCallRoom-T7OBQTYP.cjs.map → ConnectedCallRoom-VMZE2NFP.cjs.map} +1 -1
  5. package/dist/{ConnectedNativeDocxComparison-YXMYJWXY.cjs → ConnectedNativeDocxComparison-7OUKTKYP.cjs} +20 -20
  6. package/dist/{ConnectedNativeDocxComparison-YXMYJWXY.cjs.map → ConnectedNativeDocxComparison-7OUKTKYP.cjs.map} +1 -1
  7. package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs → ConnectedProductionSetDialog-4EAY6KAZ.cjs} +3 -3
  8. package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs.map → ConnectedProductionSetDialog-4EAY6KAZ.cjs.map} +1 -1
  9. package/dist/{ConnectedStreamedWordArtifact-2RTCHVPI.cjs → ConnectedStreamedWordArtifact-7V24ZDAC.cjs} +20 -20
  10. package/dist/{ConnectedStreamedWordArtifact-2RTCHVPI.cjs.map → ConnectedStreamedWordArtifact-7V24ZDAC.cjs.map} +1 -1
  11. package/dist/{DocumentReviewCard-ZSBZBGFK.cjs → DocumentReviewCard-OCPFVMLD.cjs} +15 -15
  12. package/dist/{DocumentReviewCard-ZSBZBGFK.cjs.map → DocumentReviewCard-OCPFVMLD.cjs.map} +1 -1
  13. package/dist/{FilesViewerDialog-I5QIHQZT.cjs → FilesViewerDialog-KLRDIYEH.cjs} +45 -45
  14. package/dist/{FilesViewerDialog-I5QIHQZT.cjs.map → FilesViewerDialog-KLRDIYEH.cjs.map} +1 -1
  15. package/dist/{NativeDocxEditor-H6TAEVGY.cjs → NativeDocxEditor-2LQY2CTV.cjs} +6 -6
  16. package/dist/{NativeDocxEditor-H6TAEVGY.cjs.map → NativeDocxEditor-2LQY2CTV.cjs.map} +1 -1
  17. package/dist/{WorkspaceTableView-J3C6VH4T.cjs → WorkspaceTableView-IMAZICIZ.cjs} +8 -8
  18. package/dist/{WorkspaceTableView-J3C6VH4T.cjs.map → WorkspaceTableView-IMAZICIZ.cjs.map} +1 -1
  19. package/dist/agents/index.cjs +297 -297
  20. package/dist/{ai-IM4A23YT.cjs → ai-7U4B4CVF.cjs} +24 -24
  21. package/dist/ai-7U4B4CVF.cjs.map +1 -0
  22. package/dist/calls/index.cjs +121 -121
  23. package/dist/chat/index.cjs +1 -1
  24. package/dist/{chunk-M6IKVKU5.cjs → chunk-2CSLFAGF.cjs} +392 -149
  25. package/dist/chunk-2CSLFAGF.cjs.map +1 -0
  26. package/dist/{chunk-SGYSDABK.cjs → chunk-2W5E62EY.cjs} +6 -6
  27. package/dist/{chunk-SGYSDABK.cjs.map → chunk-2W5E62EY.cjs.map} +1 -1
  28. package/dist/{chunk-P77YTTJ3.cjs → chunk-3ODEWSRO.cjs} +4 -4
  29. package/dist/{chunk-P77YTTJ3.cjs.map → chunk-3ODEWSRO.cjs.map} +1 -1
  30. package/dist/{chunk-DDIW4HLU.cjs → chunk-3U36VYMD.cjs} +27 -27
  31. package/dist/{chunk-DDIW4HLU.cjs.map → chunk-3U36VYMD.cjs.map} +1 -1
  32. package/dist/{chunk-TP5PGWIO.cjs → chunk-4IOYQLKG.cjs} +3 -3
  33. package/dist/{chunk-TP5PGWIO.cjs.map → chunk-4IOYQLKG.cjs.map} +1 -1
  34. package/dist/{chunk-NY3YUCOW.cjs → chunk-4NPCDS2X.cjs} +3 -3
  35. package/dist/{chunk-NY3YUCOW.cjs.map → chunk-4NPCDS2X.cjs.map} +1 -1
  36. package/dist/{chunk-BQ5RIWWT.cjs → chunk-4VZZWYEC.cjs} +3 -3
  37. package/dist/{chunk-BQ5RIWWT.cjs.map → chunk-4VZZWYEC.cjs.map} +1 -1
  38. package/dist/{chunk-Y24V6HPR.cjs → chunk-57EE6CMW.cjs} +15 -15
  39. package/dist/{chunk-Y24V6HPR.cjs.map → chunk-57EE6CMW.cjs.map} +1 -1
  40. package/dist/{chunk-NNUK5ZM7.cjs → chunk-5QUL5BZO.cjs} +4 -4
  41. package/dist/{chunk-NNUK5ZM7.cjs.map → chunk-5QUL5BZO.cjs.map} +1 -1
  42. package/dist/{chunk-OEREKAAP.cjs → chunk-6DCIZA3X.cjs} +75 -75
  43. package/dist/{chunk-OEREKAAP.cjs.map → chunk-6DCIZA3X.cjs.map} +1 -1
  44. package/dist/{chunk-YGXOKB5Z.cjs → chunk-7TEUGFIL.cjs} +4 -4
  45. package/dist/{chunk-YGXOKB5Z.cjs.map → chunk-7TEUGFIL.cjs.map} +1 -1
  46. package/dist/{chunk-TT4IF52H.cjs → chunk-7X3FS5HQ.cjs} +35 -35
  47. package/dist/{chunk-TT4IF52H.cjs.map → chunk-7X3FS5HQ.cjs.map} +1 -1
  48. package/dist/{chunk-CPR6EHG7.cjs → chunk-7XT5B2DZ.cjs} +47 -47
  49. package/dist/{chunk-CPR6EHG7.cjs.map → chunk-7XT5B2DZ.cjs.map} +1 -1
  50. package/dist/chunk-BKY2LAV2.cjs +18 -0
  51. package/dist/{chunk-CIHERNDO.cjs.map → chunk-BKY2LAV2.cjs.map} +1 -1
  52. package/dist/{chunk-XKVPSOKP.cjs → chunk-BW5MF464.cjs} +4 -4
  53. package/dist/{chunk-XKVPSOKP.cjs.map → chunk-BW5MF464.cjs.map} +1 -1
  54. package/dist/{chunk-IW7CDJTA.cjs → chunk-COD5ENHK.cjs} +4 -4
  55. package/dist/{chunk-IW7CDJTA.cjs.map → chunk-COD5ENHK.cjs.map} +1 -1
  56. package/dist/{chunk-A3T3IC3K.cjs → chunk-D7ICHGWM.cjs} +239 -85
  57. package/dist/chunk-D7ICHGWM.cjs.map +1 -0
  58. package/dist/{chunk-TDO5UWXF.cjs → chunk-E4BLRF2L.cjs} +5 -5
  59. package/dist/{chunk-TDO5UWXF.cjs.map → chunk-E4BLRF2L.cjs.map} +1 -1
  60. package/dist/{chunk-WR2SF44W.cjs → chunk-E4DUXU5K.cjs} +9 -9
  61. package/dist/{chunk-WR2SF44W.cjs.map → chunk-E4DUXU5K.cjs.map} +1 -1
  62. package/dist/{chunk-WAV762GP.cjs → chunk-GQXPNIRE.cjs} +6 -6
  63. package/dist/{chunk-WAV762GP.cjs.map → chunk-GQXPNIRE.cjs.map} +1 -1
  64. package/dist/{chunk-7OPOPYV6.cjs → chunk-H5OLHP2U.cjs} +3 -3
  65. package/dist/{chunk-7OPOPYV6.cjs.map → chunk-H5OLHP2U.cjs.map} +1 -1
  66. package/dist/{chunk-6UTKM5AB.cjs → chunk-JSQQV23D.cjs} +3 -3
  67. package/dist/{chunk-6UTKM5AB.cjs.map → chunk-JSQQV23D.cjs.map} +1 -1
  68. package/dist/{chunk-557MJ4IH.cjs → chunk-LFRNBT2I.cjs} +20 -20
  69. package/dist/{chunk-557MJ4IH.cjs.map → chunk-LFRNBT2I.cjs.map} +1 -1
  70. package/dist/{chunk-R7CJEIA5.cjs → chunk-LYTIQQQ2.cjs} +3 -3
  71. package/dist/{chunk-R7CJEIA5.cjs.map → chunk-LYTIQQQ2.cjs.map} +1 -1
  72. package/dist/{chunk-CPG7II4E.cjs → chunk-MC4F2URI.cjs} +28 -28
  73. package/dist/{chunk-CPG7II4E.cjs.map → chunk-MC4F2URI.cjs.map} +1 -1
  74. package/dist/{chunk-WXUU3COI.cjs → chunk-MZ2KZXNU.cjs} +3 -3
  75. package/dist/{chunk-WXUU3COI.cjs.map → chunk-MZ2KZXNU.cjs.map} +1 -1
  76. package/dist/{chunk-ZTXQIIFV.cjs → chunk-OZVDOAXG.cjs} +6 -6
  77. package/dist/{chunk-ZTXQIIFV.cjs.map → chunk-OZVDOAXG.cjs.map} +1 -1
  78. package/dist/{chunk-325GVZE6.cjs → chunk-Q6DQGGP4.cjs} +3 -3
  79. package/dist/{chunk-325GVZE6.cjs.map → chunk-Q6DQGGP4.cjs.map} +1 -1
  80. package/dist/{chunk-KTQOGT2L.cjs → chunk-TDN33HSK.cjs} +6 -6
  81. package/dist/{chunk-KTQOGT2L.cjs.map → chunk-TDN33HSK.cjs.map} +1 -1
  82. package/dist/{chunk-T23UTIRI.cjs → chunk-UNDQYTRF.cjs} +6 -6
  83. package/dist/{chunk-T23UTIRI.cjs.map → chunk-UNDQYTRF.cjs.map} +1 -1
  84. package/dist/{chunk-KXIRVKCJ.cjs → chunk-UUENH4BJ.cjs} +3 -3
  85. package/dist/{chunk-KXIRVKCJ.cjs.map → chunk-UUENH4BJ.cjs.map} +1 -1
  86. package/dist/{chunk-24EDG4PC.cjs → chunk-VBL3SHWX.cjs} +50 -50
  87. package/dist/{chunk-24EDG4PC.cjs.map → chunk-VBL3SHWX.cjs.map} +1 -1
  88. package/dist/{chunk-3A7QWUAW.cjs → chunk-VKH3BEZE.cjs} +3 -3
  89. package/dist/{chunk-3A7QWUAW.cjs.map → chunk-VKH3BEZE.cjs.map} +1 -1
  90. package/dist/{chunk-X5LANJDZ.cjs → chunk-VTYJAZDU.cjs} +23 -15
  91. package/dist/chunk-VTYJAZDU.cjs.map +1 -0
  92. package/dist/{chunk-B3LZITVF.cjs → chunk-WW6LXQY6.cjs} +12 -12
  93. package/dist/{chunk-B3LZITVF.cjs.map → chunk-WW6LXQY6.cjs.map} +1 -1
  94. package/dist/{chunk-NJCK6V6U.cjs → chunk-XKDUPU7B.cjs} +4 -4
  95. package/dist/{chunk-NJCK6V6U.cjs.map → chunk-XKDUPU7B.cjs.map} +1 -1
  96. package/dist/{chunk-42TURFHF.cjs → chunk-YGBHY67W.cjs} +5 -5
  97. package/dist/{chunk-42TURFHF.cjs.map → chunk-YGBHY67W.cjs.map} +1 -1
  98. package/dist/connect/docx.cjs +24 -24
  99. package/dist/connect/index.cjs +983 -983
  100. package/dist/connect/viewer.cjs +34 -34
  101. package/dist/connection/docx/ConnectedNativeDocxEditor.js +10 -2
  102. package/dist/connection/docx/ConnectedNativeDocxEditor.js.map +2 -2
  103. package/dist/connection/viewer/ConnectedDocumentViewer.js +124 -21
  104. package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
  105. package/dist/connection/viewer/VersionDropdown.d.ts +9 -0
  106. package/dist/connection/viewer/VersionDropdown.js +39 -0
  107. package/dist/connection/viewer/VersionDropdown.js.map +7 -0
  108. package/dist/connection/viewer/ViewerPdfPane.js +4 -1
  109. package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
  110. package/dist/connection/viewer/useViewerBlobs.d.ts +3 -1
  111. package/dist/connection/viewer/useViewerBlobs.js +14 -8
  112. package/dist/connection/viewer/useViewerBlobs.js.map +2 -2
  113. package/dist/connection/viewer/useViewerTabs.js +10 -0
  114. package/dist/connection/viewer/useViewerTabs.js.map +2 -2
  115. package/dist/dashboards/index.cjs +1 -1
  116. package/dist/docx/DocxCommandMenu.d.ts +8 -0
  117. package/dist/docx/DocxCommandMenu.js +202 -0
  118. package/dist/docx/DocxCommandMenu.js.map +7 -0
  119. package/dist/docx/NativeDocxEditor.d.ts +4 -2
  120. package/dist/docx/NativeDocxEditor.js +51 -12
  121. package/dist/docx/NativeDocxEditor.js.map +2 -2
  122. package/dist/docx/RibbonMenu.d.ts +3 -1
  123. package/dist/docx/RibbonMenu.js +10 -3
  124. package/dist/docx/RibbonMenu.js.map +2 -2
  125. package/dist/docx/RibbonOverflow.d.ts +3 -0
  126. package/dist/docx/RibbonOverflow.js +24 -1
  127. package/dist/docx/RibbonOverflow.js.map +2 -2
  128. package/dist/docx/index.cjs +38 -38
  129. package/dist/docx/signatures/SignatureFields.d.ts +3 -1
  130. package/dist/docx/signatures/SignatureFields.js +17 -8
  131. package/dist/docx/signatures/SignatureFields.js.map +2 -2
  132. package/dist/embed/index.cjs +38 -38
  133. package/dist/files/index.cjs +224 -224
  134. package/dist/index.cjs +1590 -1590
  135. package/dist/settings/index.cjs +147 -147
  136. package/dist/shell/index.cjs +90 -90
  137. package/dist/studio/index.cjs +26 -26
  138. package/dist/styles.css +1 -1
  139. package/dist/workflow-canvas/index.cjs +55 -55
  140. package/node_modules/@arbidocs/coedit/package.json +1 -1
  141. package/package.json +5 -5
  142. package/src/docx/styles.css +94 -0
  143. package/dist/ai-IM4A23YT.cjs.map +0 -1
  144. package/dist/chunk-A3T3IC3K.cjs.map +0 -1
  145. package/dist/chunk-CIHERNDO.cjs +0 -18
  146. package/dist/chunk-M6IKVKU5.cjs.map +0 -1
  147. package/dist/chunk-X5LANJDZ.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/viewer/useViewerTabs.tsx"],
4
- "sourcesContent": ["/**\n * Tabs of the document viewer: which tabs a document has, the automatic switches when the\n * document's type or parsed content changes, and switching (which ends a comparison when leaving\n * the tab that hosts it). The open tab is the session state's, so whatever opens a document can\n * open it on a tab.\n */\n\nimport { useEffect, useRef } from 'react'\nimport { Code, FileText, History, MonitorPlay } from 'lucide-react'\nimport { friendlyFileType } from '@arbidocs/react/ui'\nimport {\n AudIcon,\n DocIcon,\n EmlIcon,\n HtmlIcon,\n ImgIcon,\n PdfIcon,\n VidIcon,\n XlsIcon,\n useArbiSessionState,\n useArbiSessionStore,\n type ArbiViewerTab,\n} from '@arbidocs/react'\nimport type { ViewerTab } from '../../files/ViewerParts'\nimport { useIsPhone } from '../../lib/use-media-query'\nimport type { ViewedDocument } from './useViewedDocument'\n\n/**\n * @param hasHistory The document has earlier versions (a signed copy, a re-upload): PDF and text\n * documents then get a Versions tab too. Artifacts and Word documents always have one.\n */\nexport function useViewerTabs(doc: ViewedDocument, isCompact: boolean, hasHistory = false) {\n const {\n documentData,\n isArtifact,\n isDocx,\n isXlsx,\n isEmail,\n isVideo,\n isAudio,\n isImage,\n liveKind,\n hasParsedContent,\n isParsedDocLoading,\n } = doc\n const session = useArbiSessionStore()\n const {\n tab: activeTab,\n compareId,\n tabRequest,\n phonePdfChosen,\n } = useArbiSessionState((s) => s.documentViewer)\n const setActiveTab = (tab: ArbiViewerTab) => session.setDocumentViewer({ tab })\n // A plain-text file is still shown as a generated PDF, but the tab names the file the user\n // opened (\"Text\", as the Fields panel does), not the rendering format.\n const isTextFile = friendlyFileType(documentData?.file_type, documentData?.file_name) === 'Text'\n const isPhone = useIsPhone()\n const phoneDefaultDecidedFor = useRef<string | null>(null)\n\n // Switch to the tab that fits the document type. Only on type changes: never over the user's own\n // choice. Keyed on the document and its kind, not on the record: a refreshed record (a new\n // version finishing processing) must not send a user on the PDF tab of a Word document back to\n // the editor.\n const hasDocumentData = !!documentData\n const documentKey = documentData?.external_id\n useEffect(() => {\n // A Word artifact (an AI draft, stored as .docx) has one Word tab, 'edit', not a DOCX tab.\n if (isArtifact && (activeTab === 'pdf' || (!liveKind && activeTab === 'docx'))) {\n setActiveTab(liveKind ? 'preview' : 'edit')\n } else if (isDocx && activeTab === 'pdf') {\n setActiveTab('docx')\n } else if (!liveKind && activeTab === 'preview') {\n setActiveTab(isArtifact ? 'edit' : 'pdf')\n } else if (!isArtifact && documentData && activeTab === 'edit') {\n setActiveTab(isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n } else if (\n !isArtifact &&\n !isDocx &&\n !isXlsx &&\n documentData &&\n (activeTab === 'docx' || activeTab === 'xlsx')\n ) {\n setActiveTab('pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hasDocumentData, documentKey, isArtifact, isDocx, isXlsx, liveKind])\n\n // A tab asked for when the document was opened (a signature request opens on the PDF, where it\n // is signed) wins over the type's own tab once that document has loaded, and over the phone's\n // text default. Declared after the type switch above so it has the last word.\n useEffect(() => {\n if (!tabRequest || !documentKey || tabRequest.documentId !== documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n session.setDocumentViewer({ tabRequest: null, tab: tabRequest.tab })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [documentKey, tabRequest])\n\n // Versions of a PDF or text document exist only with history: leave the tab when there is none\n // (another document opened while it was active).\n const hasVersionsTab = isArtifact || isDocx || hasHistory\n useEffect(() => {\n if (activeTab === 'versions' && documentData && !hasVersionsTab) {\n setActiveTab(isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTab, documentData, hasVersionsTab])\n\n // The text tab exists only with parsed content. When it is open without any (a recording with\n // no transcript, a failed parse), fall back to the natural default once the parsed query\n // settles. Not during a comparison, which uses the text tab. Waits for the record: until it is\n // here the parsed query has not started, so it is not loading yet.\n useEffect(() => {\n if (\n activeTab === 'html' &&\n documentData !== undefined &&\n !isParsedDocLoading &&\n !hasParsedContent &&\n !compareId\n ) {\n setActiveTab(isArtifact ? 'edit' : isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n activeTab,\n documentData,\n isParsedDocLoading,\n hasParsedContent,\n compareId,\n isArtifact,\n isDocx,\n isXlsx,\n ])\n\n // Phones open a document on the readable reflowed (text) view: a fit-width PDF on a 390px\n // screen is footnote-sized. Decided once per document, after the parsed query settles, and only\n // over the PDF default (Word, sheets, artifacts and media keep their own tab). A PDF the user\n // picked by hand this session wins.\n useEffect(() => {\n if (!isPhone || !documentKey || isParsedDocLoading) return\n if (phoneDefaultDecidedFor.current === documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n const opensOnPdf =\n !isArtifact && !isDocx && !isXlsx && !isVideo && !isAudio && !isImage && !isEmail\n if (opensOnPdf && hasParsedContent && !compareId && !phonePdfChosen && activeTab === 'pdf') {\n setActiveTab('html')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isPhone, documentKey, isParsedDocLoading, hasParsedContent])\n\n const handleTabChange = (tabId: string) => {\n // A comparison is shown on the text tab: leaving it ends the comparison.\n const change: Parameters<typeof session.setDocumentViewer>[0] = { tab: tabId as ArbiViewerTab }\n if (tabId !== 'html' && compareId) change.compareId = null\n // A phone user who goes back to the PDF wants it: stop opening documents on the text view\n // until they pick it again.\n if (isPhone && (tabId === 'pdf' || tabId === 'html')) change.phonePdfChosen = tabId === 'pdf'\n session.setDocumentViewer(change)\n }\n\n const mediaTab = isVideo\n ? { icon: <VidIcon size={20} />, tooltip: 'Video' }\n : isAudio\n ? { icon: <AudIcon size={20} />, tooltip: 'Audio' }\n : isImage\n ? { icon: <ImgIcon size={20} />, tooltip: 'Image' }\n : isEmail\n ? { icon: <EmlIcon size={20} />, tooltip: 'Email' }\n : isTextFile\n ? { icon: <FileText className=\"size-5\" />, tooltip: 'Text' }\n : documentData\n ? { icon: <PdfIcon size={20} />, tooltip: 'PDF' }\n : // The file type is unknown until the record loads: name no guess (a text file\n // would flip from PDF to Text once it arrives).\n { icon: <FileText className=\"size-5\" />, tooltip: 'Document' }\n // Tabs say what they are: in a narrow panel or on a phone only the open tab keeps its name, plus\n // the text view, whose icon is not recognisable. Labelling every tab there would crowd the header.\n const tabLabel = (id: string, label: string) =>\n !isCompact || activeTab === id || id === 'html' ? label : undefined\n\n const versionsTab: ViewerTab = {\n id: 'versions',\n icon: <History className=\"size-5\" />,\n tooltip: 'Versions',\n label: tabLabel('versions', 'Versions'),\n }\n const viewerTabs: ViewerTab[] = [\n ...(isArtifact\n ? [\n ...(liveKind\n ? [\n {\n id: 'preview',\n icon: <MonitorPlay className=\"size-5\" />,\n tooltip: 'Preview',\n label: tabLabel('preview', 'Preview'),\n },\n ]\n : []),\n {\n id: 'edit',\n icon: liveKind ? <Code className=\"size-5\" /> : <FileText className=\"size-5\" />,\n tooltip: liveKind ? 'Code' : 'Editor',\n label: tabLabel('edit', liveKind ? 'Code' : 'Document'),\n },\n versionsTab,\n ]\n : [\n ...(isDocx\n ? [\n {\n id: 'docx',\n icon: <DocIcon size={20} />,\n tooltip: 'DOCX (with track changes & comments)',\n label: tabLabel('docx', 'DOCX'),\n },\n ]\n : []),\n ...(isXlsx\n ? [\n {\n id: 'xlsx',\n icon: <XlsIcon size={20} />,\n tooltip: 'Spreadsheet',\n label: tabLabel('xlsx', 'Sheet'),\n },\n ]\n : []),\n { id: 'pdf', ...mediaTab, label: tabLabel('pdf', mediaTab.tooltip) },\n ...(hasVersionsTab ? [versionsTab] : []),\n ]),\n ...((hasParsedContent || compareId) && !liveKind\n ? [\n {\n id: 'html',\n icon: compareId ? <FileText className=\"size-5\" /> : <HtmlIcon size={20} />,\n tooltip: compareId ? 'Word redline' : 'HTML',\n label: tabLabel('html', compareId ? 'Compare' : 'HTML'),\n },\n ]\n : []),\n ]\n\n return { activeTab, handleTabChange, viewerTabs }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Tabs of the document viewer: which tabs a document has, the automatic switches when the\n * document's type or parsed content changes, and switching (which ends a comparison when leaving\n * the tab that hosts it). The open tab is the session state's, so whatever opens a document can\n * open it on a tab.\n */\n\nimport { useEffect, useRef } from 'react'\nimport { Code, FileText, History, MonitorPlay } from 'lucide-react'\nimport { friendlyFileType } from '@arbidocs/react/ui'\nimport {\n AudIcon,\n DocIcon,\n EmlIcon,\n HtmlIcon,\n ImgIcon,\n PdfIcon,\n VidIcon,\n XlsIcon,\n useArbiSessionState,\n useArbiSessionStore,\n type ArbiViewerTab,\n} from '@arbidocs/react'\nimport type { ViewerTab } from '../../files/ViewerParts'\nimport { useIsPhone } from '../../lib/use-media-query'\nimport type { ViewedDocument } from './useViewedDocument'\n\n/**\n * @param hasHistory The document has earlier versions (a signed copy, a re-upload): PDF and text\n * documents then get a Versions tab too. Artifacts and Word documents always have one.\n */\nexport function useViewerTabs(doc: ViewedDocument, isCompact: boolean, hasHistory = false) {\n const {\n documentData,\n isArtifact,\n isDraft,\n isStreaming,\n isDocx,\n isXlsx,\n isEmail,\n isVideo,\n isAudio,\n isImage,\n liveKind,\n hasParsedContent,\n isParsedDocLoading,\n } = doc\n const session = useArbiSessionStore()\n const {\n tab: activeTab,\n compareId,\n tabRequest,\n phonePdfChosen,\n } = useArbiSessionState((s) => s.documentViewer)\n const setActiveTab = (tab: ArbiViewerTab) => session.setDocumentViewer({ tab })\n // A plain-text file is still shown as a generated PDF, but the tab names the file the user\n // opened (\"Text\", as the Fields panel does), not the rendering format.\n const isTextFile = friendlyFileType(documentData?.file_type, documentData?.file_name) === 'Text'\n const isPhone = useIsPhone()\n const phoneDefaultDecidedFor = useRef<string | null>(null)\n\n // Switch to the tab that fits the document type. Only on type changes: never over the user's own\n // choice. Keyed on the document and its kind, not on the record: a refreshed record (a new\n // version finishing processing) must not send a user on the PDF tab of a Word document back to\n // the editor.\n const hasDocumentData = !!documentData\n const documentKey = documentData?.external_id\n useEffect(() => {\n // A Word artifact (an AI draft, stored as .docx) has one Word tab, 'edit', not a DOCX tab.\n if (isArtifact && (activeTab === 'pdf' || (!liveKind && activeTab === 'docx'))) {\n setActiveTab(liveKind ? 'preview' : 'edit')\n } else if (isDocx && activeTab === 'pdf') {\n setActiveTab('docx')\n } else if (!liveKind && activeTab === 'preview') {\n setActiveTab(isArtifact ? 'edit' : 'pdf')\n } else if (!isArtifact && documentData && activeTab === 'edit') {\n setActiveTab(isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n } else if (\n !isArtifact &&\n !isDocx &&\n !isXlsx &&\n documentData &&\n (activeTab === 'docx' || activeTab === 'xlsx')\n ) {\n setActiveTab('pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hasDocumentData, documentKey, isArtifact, isDocx, isXlsx, liveKind])\n\n // A tab asked for when the document was opened (a signature request opens on the PDF, where it\n // is signed) wins over the type's own tab once that document has loaded, and over the phone's\n // text default. Declared after the type switch above so it has the last word.\n useEffect(() => {\n if (!tabRequest || !documentKey || tabRequest.documentId !== documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n session.setDocumentViewer({ tabRequest: null, tab: tabRequest.tab })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [documentKey, tabRequest])\n\n // Versions of a PDF or text document exist only with history: leave the tab when there is none\n // (another document opened while it was active).\n const hasVersionsTab = isArtifact || isDocx || hasHistory\n useEffect(() => {\n if (activeTab === 'versions' && documentData && !hasVersionsTab) {\n setActiveTab(isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTab, documentData, hasVersionsTab])\n\n // The text tab exists only with parsed content. When it is open without any (a recording with\n // no transcript, a failed parse), fall back to the natural default once the parsed query\n // settles. Not during a comparison, which uses the text tab. Waits for the record: until it is\n // here the parsed query has not started, so it is not loading yet.\n useEffect(() => {\n if (\n activeTab === 'html' &&\n documentData !== undefined &&\n !isParsedDocLoading &&\n !hasParsedContent &&\n !compareId\n ) {\n setActiveTab(isArtifact ? 'edit' : isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n activeTab,\n documentData,\n isParsedDocLoading,\n hasParsedContent,\n compareId,\n isArtifact,\n isDocx,\n isXlsx,\n ])\n\n // Phones open a document on the readable reflowed (text) view: a fit-width PDF on a 390px\n // screen is footnote-sized. Decided once per document, after the parsed query settles, and only\n // over the PDF default (Word, sheets, artifacts and media keep their own tab). A PDF the user\n // picked by hand this session wins.\n useEffect(() => {\n if (!isPhone || !documentKey || isParsedDocLoading) return\n if (phoneDefaultDecidedFor.current === documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n const opensOnPdf =\n !isArtifact && !isDocx && !isXlsx && !isVideo && !isAudio && !isImage && !isEmail\n if (opensOnPdf && hasParsedContent && !compareId && !phonePdfChosen && activeTab === 'pdf') {\n setActiveTab('html')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isPhone, documentKey, isParsedDocLoading, hasParsedContent])\n\n const handleTabChange = (tabId: string) => {\n // A comparison is shown on the text tab: leaving it ends the comparison.\n const change: Parameters<typeof session.setDocumentViewer>[0] = { tab: tabId as ArbiViewerTab }\n if (tabId !== 'html' && compareId) change.compareId = null\n // A phone user who goes back to the PDF wants it: stop opening documents on the text view\n // until they pick it again.\n if (isPhone && (tabId === 'pdf' || tabId === 'html')) change.phonePdfChosen = tabId === 'pdf'\n session.setDocumentViewer(change)\n }\n\n const mediaTab = isVideo\n ? { icon: <VidIcon size={20} />, tooltip: 'Video' }\n : isAudio\n ? { icon: <AudIcon size={20} />, tooltip: 'Audio' }\n : isImage\n ? { icon: <ImgIcon size={20} />, tooltip: 'Image' }\n : isEmail\n ? { icon: <EmlIcon size={20} />, tooltip: 'Email' }\n : isTextFile\n ? { icon: <FileText className=\"size-5\" />, tooltip: 'Text' }\n : documentData\n ? { icon: <PdfIcon size={20} />, tooltip: 'PDF' }\n : // The file type is unknown until the record loads: name no guess (a text file\n // would flip from PDF to Text once it arrives).\n { icon: <FileText className=\"size-5\" />, tooltip: 'Document' }\n // Tabs say what they are: in a narrow panel or on a phone only the open tab keeps its name, plus\n // the text view, whose icon is not recognisable. Labelling every tab there would crowd the header.\n const tabLabel = (id: string, label: string) =>\n !isCompact || activeTab === id || id === 'html' ? label : undefined\n\n const versionsTab: ViewerTab = {\n id: 'versions',\n icon: <History className=\"size-5\" />,\n tooltip: 'Versions',\n label: tabLabel('versions', 'Versions'),\n }\n const viewerTabs: ViewerTab[] = [\n ...(isArtifact\n ? [\n ...(liveKind\n ? [\n {\n id: 'preview',\n icon: <MonitorPlay className=\"size-5\" />,\n tooltip: 'Preview',\n label: tabLabel('preview', 'Preview'),\n },\n ]\n : []),\n {\n id: 'edit',\n icon: liveKind ? <Code className=\"size-5\" /> : <FileText className=\"size-5\" />,\n tooltip: liveKind ? 'Code' : 'Editor',\n label: tabLabel('edit', liveKind ? 'Code' : 'Document'),\n },\n ...(!liveKind && !isDraft && !isStreaming && isDocx\n ? [\n {\n id: 'pdf',\n icon: <PdfIcon size={20} />,\n tooltip: 'PDF',\n label: tabLabel('pdf', 'PDF'),\n },\n ]\n : []),\n versionsTab,\n ]\n : [\n ...(isDocx\n ? [\n {\n id: 'docx',\n icon: <DocIcon size={20} />,\n tooltip: 'DOCX (with track changes & comments)',\n label: tabLabel('docx', 'DOCX'),\n },\n ]\n : []),\n ...(isXlsx\n ? [\n {\n id: 'xlsx',\n icon: <XlsIcon size={20} />,\n tooltip: 'Spreadsheet',\n label: tabLabel('xlsx', 'Sheet'),\n },\n ]\n : []),\n { id: 'pdf', ...mediaTab, label: tabLabel('pdf', mediaTab.tooltip) },\n ...(hasVersionsTab ? [versionsTab] : []),\n ]),\n ...((hasParsedContent || compareId) && !liveKind\n ? [\n {\n id: 'html',\n icon: compareId ? <FileText className=\"size-5\" /> : <HtmlIcon size={20} />,\n tooltip: compareId ? 'Word redline' : 'HTML',\n label: tabLabel('html', compareId ? 'Compare' : 'HTML'),\n },\n ]\n : []),\n ]\n\n return { activeTab, handleTabChange, viewerTabs }\n}\n"],
5
+ "mappings": ";AAkKc;AA3Jd,SAAS,WAAW,cAAc;AAClC,SAAS,MAAM,UAAU,SAAS,mBAAmB;AACrD,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,SAAS,kBAAkB;AAOpB,SAAS,cAAc,KAAqB,WAAoB,aAAa,OAAO;AACzF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,UAAU,oBAAoB;AACpC,QAAM;AAAA,IACJ,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,oBAAoB,CAAC,MAAM,EAAE,cAAc;AAC/C,QAAM,eAAe,CAAC,QAAuB,QAAQ,kBAAkB,EAAE,IAAI,CAAC;AAG9E,QAAM,aAAa,iBAAiB,cAAc,WAAW,cAAc,SAAS,MAAM;AAC1F,QAAM,UAAU,WAAW;AAC3B,QAAM,yBAAyB,OAAsB,IAAI;AAMzD,QAAM,kBAAkB,CAAC,CAAC;AAC1B,QAAM,cAAc,cAAc;AAClC,YAAU,MAAM;AAEd,QAAI,eAAe,cAAc,SAAU,CAAC,YAAY,cAAc,SAAU;AAC9E,mBAAa,WAAW,YAAY,MAAM;AAAA,IAC5C,WAAW,UAAU,cAAc,OAAO;AACxC,mBAAa,MAAM;AAAA,IACrB,WAAW,CAAC,YAAY,cAAc,WAAW;AAC/C,mBAAa,aAAa,SAAS,KAAK;AAAA,IAC1C,WAAW,CAAC,cAAc,gBAAgB,cAAc,QAAQ;AAC9D,mBAAa,SAAS,SAAS,SAAS,SAAS,KAAK;AAAA,IACxD,WACE,CAAC,cACD,CAAC,UACD,CAAC,UACD,iBACC,cAAc,UAAU,cAAc,SACvC;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EAEF,GAAG,CAAC,iBAAiB,aAAa,YAAY,QAAQ,QAAQ,QAAQ,CAAC;AAKvE,YAAU,MAAM;AACd,QAAI,CAAC,cAAc,CAAC,eAAe,WAAW,eAAe,YAAa;AAC1E,2BAAuB,UAAU;AACjC,YAAQ,kBAAkB,EAAE,YAAY,MAAM,KAAK,WAAW,IAAI,CAAC;AAAA,EAErE,GAAG,CAAC,aAAa,UAAU,CAAC;AAI5B,QAAM,iBAAiB,cAAc,UAAU;AAC/C,YAAU,MAAM;AACd,QAAI,cAAc,cAAc,gBAAgB,CAAC,gBAAgB;AAC/D,mBAAa,SAAS,SAAS,KAAK;AAAA,IACtC;AAAA,EAEF,GAAG,CAAC,WAAW,cAAc,cAAc,CAAC;AAM5C,YAAU,MAAM;AACd,QACE,cAAc,UACd,iBAAiB,UACjB,CAAC,sBACD,CAAC,oBACD,CAAC,WACD;AACA,mBAAa,aAAa,SAAS,SAAS,SAAS,SAAS,SAAS,KAAK;AAAA,IAC9E;AAAA,EAEF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAMD,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,eAAe,mBAAoB;AACpD,QAAI,uBAAuB,YAAY,YAAa;AACpD,2BAAuB,UAAU;AACjC,UAAM,aACJ,CAAC,cAAc,CAAC,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC;AAC5E,QAAI,cAAc,oBAAoB,CAAC,aAAa,CAAC,kBAAkB,cAAc,OAAO;AAC1F,mBAAa,MAAM;AAAA,IACrB;AAAA,EAEF,GAAG,CAAC,SAAS,aAAa,oBAAoB,gBAAgB,CAAC;AAE/D,QAAM,kBAAkB,CAAC,UAAkB;AAEzC,UAAM,SAA0D,EAAE,KAAK,MAAuB;AAC9F,QAAI,UAAU,UAAU,UAAW,QAAO,YAAY;AAGtD,QAAI,YAAY,UAAU,SAAS,UAAU,QAAS,QAAO,iBAAiB,UAAU;AACxF,YAAQ,kBAAkB,MAAM;AAAA,EAClC;AAEA,QAAM,WAAW,UACb,EAAE,MAAM,oBAAC,WAAQ,MAAM,IAAI,GAAI,SAAS,QAAQ,IAChD,UACE,EAAE,MAAM,oBAAC,WAAQ,MAAM,IAAI,GAAI,SAAS,QAAQ,IAChD,UACE,EAAE,MAAM,oBAAC,WAAQ,MAAM,IAAI,GAAI,SAAS,QAAQ,IAChD,UACE,EAAE,MAAM,oBAAC,WAAQ,MAAM,IAAI,GAAI,SAAS,QAAQ,IAChD,aACE,EAAE,MAAM,oBAAC,YAAS,WAAU,UAAS,GAAI,SAAS,OAAO,IACzD,eACE,EAAE,MAAM,oBAAC,WAAQ,MAAM,IAAI,GAAI,SAAS,MAAM;AAAA;AAAA;AAAA,IAG9C,EAAE,MAAM,oBAAC,YAAS,WAAU,UAAS,GAAI,SAAS,WAAW;AAAA;AAG3E,QAAM,WAAW,CAAC,IAAY,UAC5B,CAAC,aAAa,cAAc,MAAM,OAAO,SAAS,QAAQ;AAE5D,QAAM,cAAyB;AAAA,IAC7B,IAAI;AAAA,IACJ,MAAM,oBAAC,WAAQ,WAAU,UAAS;AAAA,IAClC,SAAS;AAAA,IACT,OAAO,SAAS,YAAY,UAAU;AAAA,EACxC;AACA,QAAM,aAA0B;AAAA,IAC9B,GAAI,aACA;AAAA,MACE,GAAI,WACA;AAAA,QACE;AAAA,UACE,IAAI;AAAA,UACJ,MAAM,oBAAC,eAAY,WAAU,UAAS;AAAA,UACtC,SAAS;AAAA,UACT,OAAO,SAAS,WAAW,SAAS;AAAA,QACtC;AAAA,MACF,IACA,CAAC;AAAA,MACL;AAAA,QACE,IAAI;AAAA,QACJ,MAAM,WAAW,oBAAC,QAAK,WAAU,UAAS,IAAK,oBAAC,YAAS,WAAU,UAAS;AAAA,QAC5E,SAAS,WAAW,SAAS;AAAA,QAC7B,OAAO,SAAS,QAAQ,WAAW,SAAS,UAAU;AAAA,MACxD;AAAA,MACA,GAAI,CAAC,YAAY,CAAC,WAAW,CAAC,eAAe,SACzC;AAAA,QACE;AAAA,UACE,IAAI;AAAA,UACJ,MAAM,oBAAC,WAAQ,MAAM,IAAI;AAAA,UACzB,SAAS;AAAA,UACT,OAAO,SAAS,OAAO,KAAK;AAAA,QAC9B;AAAA,MACF,IACA,CAAC;AAAA,MACL;AAAA,IACF,IACA;AAAA,MACE,GAAI,SACA;AAAA,QACE;AAAA,UACE,IAAI;AAAA,UACJ,MAAM,oBAAC,WAAQ,MAAM,IAAI;AAAA,UACzB,SAAS;AAAA,UACT,OAAO,SAAS,QAAQ,MAAM;AAAA,QAChC;AAAA,MACF,IACA,CAAC;AAAA,MACL,GAAI,SACA;AAAA,QACE;AAAA,UACE,IAAI;AAAA,UACJ,MAAM,oBAAC,WAAQ,MAAM,IAAI;AAAA,UACzB,SAAS;AAAA,UACT,OAAO,SAAS,QAAQ,OAAO;AAAA,QACjC;AAAA,MACF,IACA,CAAC;AAAA,MACL,EAAE,IAAI,OAAO,GAAG,UAAU,OAAO,SAAS,OAAO,SAAS,OAAO,EAAE;AAAA,MACnE,GAAI,iBAAiB,CAAC,WAAW,IAAI,CAAC;AAAA,IACxC;AAAA,IACJ,IAAK,oBAAoB,cAAc,CAAC,WACpC;AAAA,MACE;AAAA,QACE,IAAI;AAAA,QACJ,MAAM,YAAY,oBAAC,YAAS,WAAU,UAAS,IAAK,oBAAC,YAAS,MAAM,IAAI;AAAA,QACxE,SAAS,YAAY,iBAAiB;AAAA,QACtC,OAAO,SAAS,QAAQ,YAAY,YAAY,MAAM;AAAA,MACxD;AAAA,IACF,IACA,CAAC;AAAA,EACP;AAEA,SAAO,EAAE,WAAW,iBAAiB,WAAW;AAClD;",
6
6
  "names": []
7
7
  }
@@ -10,8 +10,8 @@ require('../chunk-ZU2B2RZK.cjs');
10
10
  var chunkNSD37OF5_cjs = require('../chunk-NSD37OF5.cjs');
11
11
  var chunkOEJQFPWO_cjs = require('../chunk-OEJQFPWO.cjs');
12
12
  require('../chunk-JV5TVUOU.cjs');
13
- var chunkZW6FPIFC_cjs = require('../chunk-ZW6FPIFC.cjs');
14
13
  require('../chunk-IPSHAMO2.cjs');
14
+ var chunkZW6FPIFC_cjs = require('../chunk-ZW6FPIFC.cjs');
15
15
  var chunkTKHCIHE2_cjs = require('../chunk-TKHCIHE2.cjs');
16
16
  require('../chunk-JDFBEGQO.cjs');
17
17
  require('../chunk-ULWRNGGE.cjs');
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { type DocxImageGeneration } from './layout/GenerateImage';
3
+ /** One editing menu, with named categories and the existing editor commands. */
4
+ export declare function DocxCommandMenu({ onSave, badge, imageGeneration, }: {
5
+ onSave: () => void;
6
+ badge?: React.ReactNode;
7
+ imageGeneration?: DocxImageGeneration;
8
+ }): React.JSX.Element;
@@ -0,0 +1,202 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { DocxEditor, useChromeTranslate } from "@docx-editor.dev/react";
5
+ import {
6
+ BookA,
7
+ ChevronDown,
8
+ FilePenLine,
9
+ Home,
10
+ Image,
11
+ LayoutGrid,
12
+ ListChecks,
13
+ Menu,
14
+ Plus,
15
+ Table,
16
+ UsersRound
17
+ } from "lucide-react";
18
+ import { useDefinedTerms } from "./definitions/DefinedTerms.js";
19
+ import { RibbonMenu } from "./RibbonMenu.js";
20
+ import { NamedCommandList, RibbonItem } from "./RibbonOverflow.js";
21
+ import { StyleGallery } from "./StyleGallery.js";
22
+ import { NoteButtons } from "./WordReferences.js";
23
+ import { CrossReferenceButton, UpdateCrossReferencesButton } from "./references/EditorMenus.js";
24
+ import { LayoutTabContent, LAYOUT_TAB, useContextualTabs } from "./layout/LayoutTabs.js";
25
+ import {
26
+ GenerateImageButton,
27
+ useGenerateImageTarget
28
+ } from "./layout/GenerateImage.js";
29
+ import { QuickParts } from "./template/QuickParts.js";
30
+ import { HouseTemplatePanel } from "./template/HouseTemplatePanel.js";
31
+ import { MySignatureMenu, SignatureFieldMenu } from "./signatures/SignatureFields.js";
32
+ function DefinedTermButton() {
33
+ const terms = useDefinedTerms();
34
+ if (!terms) return null;
35
+ return /* @__PURE__ */ jsx(
36
+ "button",
37
+ {
38
+ type: "button",
39
+ className: "native-docx-ribbon-trigger",
40
+ "aria-label": terms.labels.insert,
41
+ title: `${terms.labels.insert} (type @@)`,
42
+ "data-testid": "docx-insert-defined-term",
43
+ onMouseDown: (event) => event.preventDefault(),
44
+ onClick: (event) => terms.openPicker(event.currentTarget),
45
+ children: /* @__PURE__ */ jsx(BookA, { size: 16 })
46
+ }
47
+ );
48
+ }
49
+ const categories = [
50
+ { name: "Home", icon: Home },
51
+ { name: "Insert", icon: Plus },
52
+ { name: "Design", icon: FilePenLine },
53
+ { name: LAYOUT_TAB, icon: LayoutGrid },
54
+ { name: "References", icon: BookA },
55
+ { name: "Review", icon: ListChecks }
56
+ ];
57
+ function DocxCommandMenu({
58
+ onSave,
59
+ badge,
60
+ imageGeneration
61
+ }) {
62
+ const [selected, setSelected] = useState("Home");
63
+ const contextual = useContextualTabs(selected);
64
+ const tab = contextual.shown;
65
+ const t = useChromeTranslate();
66
+ useGenerateImageTarget();
67
+ const allCategories = [
68
+ ...categories,
69
+ ...contextual.tabs.map((name) => ({ name, icon: name === "Table" ? Table : Image }))
70
+ ];
71
+ return /* @__PURE__ */ jsxs("div", { className: "native-docx-ribbon native-docx-command-menu", children: [
72
+ /* @__PURE__ */ jsxs(DocxEditor.Toolbar, { t, preset: false, onSave, children: [
73
+ /* @__PURE__ */ jsx(
74
+ RibbonMenu,
75
+ {
76
+ label: "Editing tools",
77
+ icon: /* @__PURE__ */ jsxs(Fragment, { children: [
78
+ /* @__PURE__ */ jsx(Menu, { size: 16 }),
79
+ /* @__PURE__ */ jsx("span", { children: "Editing tools" }),
80
+ /* @__PURE__ */ jsx(ChevronDown, { size: 14 })
81
+ ] }),
82
+ className: "native-docx-command-trigger",
83
+ popoverClassName: "native-docx-command-panel",
84
+ keepMounted: true,
85
+ restoreFocus: true,
86
+ children: (close) => /* @__PURE__ */ jsxs("div", { className: "native-docx-command-layout", children: [
87
+ /* @__PURE__ */ jsx("nav", { className: "native-docx-command-categories", "aria-label": "Editing tool categories", children: allCategories.map(({ name, icon: Icon }) => /* @__PURE__ */ jsxs(
88
+ "button",
89
+ {
90
+ type: "button",
91
+ "aria-pressed": tab === name,
92
+ onClick: () => setSelected(name),
93
+ children: [
94
+ /* @__PURE__ */ jsx(Icon, { size: 16, "aria-hidden": "true" }),
95
+ /* @__PURE__ */ jsx("span", { children: name })
96
+ ]
97
+ },
98
+ name
99
+ )) }),
100
+ /* @__PURE__ */ jsx(
101
+ "div",
102
+ {
103
+ className: "native-docx-command-list",
104
+ role: "group",
105
+ "aria-label": `${tab} commands`,
106
+ onClick: (event) => {
107
+ const target = event.target;
108
+ const button = target.closest("button");
109
+ const item = target.closest("[data-ribbon-item]")?.dataset.ribbonItem;
110
+ const direct = /* @__PURE__ */ new Set([
111
+ "home-undo",
112
+ "home-redo",
113
+ "home-save",
114
+ "home-bold",
115
+ "home-italic",
116
+ "home-underline",
117
+ "home-bullets",
118
+ "home-numbers",
119
+ "home-indent",
120
+ "home-outdent",
121
+ "home-strike",
122
+ "home-clear",
123
+ "references-footnote",
124
+ "references-endnote",
125
+ "references-update-cross-references",
126
+ "table-row-above",
127
+ "table-row-below",
128
+ "table-column-left",
129
+ "table-column-right"
130
+ ]);
131
+ if ((!button || !button.disabled) && target.closest('[aria-disabled="true"]') === null && (button && item && direct.has(item) || target.closest('[role="gridcell"]') || target.closest('[role="menuitemradio"]') || target.closest('[data-testid="docx-insert-my-signature"]') || target.closest('[data-testid="docx-insert-my-initials"]') || target.closest('.native-docx-style-gallery [role="option"]') || button && button.closest(".native-docx-style-gallery"))) {
132
+ close();
133
+ }
134
+ },
135
+ children: /* @__PURE__ */ jsxs(NamedCommandList, { children: [
136
+ tab === "Home" && /* @__PURE__ */ jsxs(Fragment, { children: [
137
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-undo", label: "Undo", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Undo, {}) }),
138
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-redo", label: "Redo", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Redo, {}) }),
139
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-save", label: "Save", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Save, {}) }),
140
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-style", label: "Styles", children: /* @__PURE__ */ jsx(StyleGallery, {}) }),
141
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-bold", label: "Bold", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Bold, {}) }),
142
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-italic", label: "Italic", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Italic, {}) }),
143
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-underline", label: "Underline", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Underline, {}) }),
144
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-font-family", label: "Font family", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.FontFamily, {}) }),
145
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-font-size", label: "Font size", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.FontSize, {}) }),
146
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-font-color", label: "Font color", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.FontColor, {}) }),
147
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-highlight", label: "Highlight", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Highlight, {}) }),
148
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-alignment", label: "Alignment", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Alignment, {}) }),
149
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-bullets", label: "Bulleted list", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.BulletList, {}) }),
150
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-numbers", label: "Numbered list", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.NumberedList, {}) }),
151
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-line-spacing", label: "Line spacing", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.LineSpacing, {}) }),
152
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-indent", label: "Increase indent", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Indent, {}) }),
153
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-outdent", label: "Decrease indent", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Outdent, {}) }),
154
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-strike", label: "Strikethrough", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Strike, {}) }),
155
+ /* @__PURE__ */ jsx(RibbonItem, { id: "home-clear", label: "Clear formatting", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.ClearFormatting, {}) })
156
+ ] }),
157
+ tab === "Insert" && /* @__PURE__ */ jsxs(Fragment, { children: [
158
+ /* @__PURE__ */ jsx(RibbonItem, { id: "insert-table", label: "Table", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.TableInsert, {}) }),
159
+ /* @__PURE__ */ jsx(RibbonItem, { id: "insert-picture", label: "Picture", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.ImageInsert, {}) }),
160
+ imageGeneration && /* @__PURE__ */ jsx(RibbonItem, { id: "insert-generate-image", label: "Generate image", children: /* @__PURE__ */ jsx(GenerateImageButton, { generation: imageGeneration }) }),
161
+ /* @__PURE__ */ jsx(RibbonItem, { id: "insert-page-break", label: "Page break", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Button, { slotId: "insert.pageBreak" }) }),
162
+ /* @__PURE__ */ jsx(RibbonItem, { id: "insert-link", label: "Link", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Link, {}) }),
163
+ /* @__PURE__ */ jsx(RibbonItem, { id: "insert-defined-term", label: "Defined term", children: /* @__PURE__ */ jsx(DefinedTermButton, {}) }),
164
+ /* @__PURE__ */ jsx(RibbonItem, { id: "insert-quick-parts", label: "Quick Parts", children: /* @__PURE__ */ jsx(QuickParts, {}) }),
165
+ /* @__PURE__ */ jsx(RibbonItem, { id: "insert-signature-field", label: "Signature field", children: /* @__PURE__ */ jsx(SignatureFieldMenu, { onInserted: close }) }),
166
+ /* @__PURE__ */ jsx(RibbonItem, { id: "insert-my-signature", label: "My signature", children: /* @__PURE__ */ jsx(MySignatureMenu, {}) }),
167
+ /* @__PURE__ */ jsx(RibbonItem, { id: "insert-cross-reference", label: "Cross-reference", children: /* @__PURE__ */ jsx(CrossReferenceButton, {}) })
168
+ ] }),
169
+ /* @__PURE__ */ jsx(LayoutTabContent, { tab }),
170
+ tab === "Design" && /* @__PURE__ */ jsx(RibbonItem, { id: "design-house-template", label: "House template", children: /* @__PURE__ */ jsx(HouseTemplatePanel, {}) }),
171
+ tab === "References" && /* @__PURE__ */ jsxs(Fragment, { children: [
172
+ /* @__PURE__ */ jsx(NoteButtons, {}),
173
+ /* @__PURE__ */ jsx(RibbonItem, { id: "references-cross-reference", label: "Cross-reference", children: /* @__PURE__ */ jsx(CrossReferenceButton, {}) }),
174
+ /* @__PURE__ */ jsx(
175
+ RibbonItem,
176
+ {
177
+ id: "references-update-cross-references",
178
+ label: "Update cross-references",
179
+ children: /* @__PURE__ */ jsx(UpdateCrossReferencesButton, {})
180
+ }
181
+ )
182
+ ] }),
183
+ tab === "Review" && /* @__PURE__ */ jsxs(Fragment, { children: [
184
+ /* @__PURE__ */ jsx(RibbonItem, { id: "review-editing-mode", label: "Editing mode", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.EditingMode, {}) }),
185
+ /* @__PURE__ */ jsx(RibbonItem, { id: "review-comments", label: "Comments", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Comments, {}) }),
186
+ /* @__PURE__ */ jsx(RibbonItem, { id: "review-options", label: "Review options", children: /* @__PURE__ */ jsx(RibbonMenu, { label: "Review options", icon: /* @__PURE__ */ jsx(UsersRound, { size: 16 }), children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Reviewers, {}) }) })
187
+ ] })
188
+ ] })
189
+ }
190
+ )
191
+ ] })
192
+ }
193
+ ),
194
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.TableCellFill, { hidden: true })
195
+ ] }),
196
+ badge && /* @__PURE__ */ jsx("span", { className: "native-docx-ribbon-badge", "data-testid": "docx-ribbon-badge", children: badge })
197
+ ] });
198
+ }
199
+ export {
200
+ DocxCommandMenu
201
+ };
202
+ //# sourceMappingURL=DocxCommandMenu.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/docx/DocxCommandMenu.tsx"],
4
+ "sourcesContent": ["import React, { useState } from 'react'\nimport { DocxEditor, useChromeTranslate } from '@docx-editor.dev/react'\nimport {\n BookA,\n ChevronDown,\n FilePenLine,\n Home,\n Image,\n LayoutGrid,\n ListChecks,\n Menu,\n Plus,\n Table,\n UsersRound,\n} from 'lucide-react'\nimport { useDefinedTerms } from './definitions/DefinedTerms'\nimport { RibbonMenu } from './RibbonMenu'\nimport { NamedCommandList, RibbonItem } from './RibbonOverflow'\nimport { StyleGallery } from './StyleGallery'\nimport { NoteButtons } from './WordReferences'\nimport { CrossReferenceButton, UpdateCrossReferencesButton } from './references/EditorMenus'\nimport { LayoutTabContent, LAYOUT_TAB, useContextualTabs } from './layout/LayoutTabs'\nimport {\n GenerateImageButton,\n useGenerateImageTarget,\n type DocxImageGeneration,\n} from './layout/GenerateImage'\nimport { QuickParts } from './template/QuickParts'\nimport { HouseTemplatePanel } from './template/HouseTemplatePanel'\nimport { MySignatureMenu, SignatureFieldMenu } from './signatures/SignatureFields'\n\nfunction DefinedTermButton() {\n const terms = useDefinedTerms()\n if (!terms) return null\n return (\n <button\n type=\"button\"\n className=\"native-docx-ribbon-trigger\"\n aria-label={terms.labels.insert}\n title={`${terms.labels.insert} (type @@)`}\n data-testid=\"docx-insert-defined-term\"\n onMouseDown={(event) => event.preventDefault()}\n onClick={(event) => terms.openPicker(event.currentTarget)}\n >\n <BookA size={16} />\n </button>\n )\n}\n\nconst categories = [\n { name: 'Home', icon: Home },\n { name: 'Insert', icon: Plus },\n { name: 'Design', icon: FilePenLine },\n { name: LAYOUT_TAB, icon: LayoutGrid },\n { name: 'References', icon: BookA },\n { name: 'Review', icon: ListChecks },\n] as const\n\n/** One editing menu, with named categories and the existing editor commands. */\nexport function DocxCommandMenu({\n onSave,\n badge,\n imageGeneration,\n}: {\n onSave: () => void\n badge?: React.ReactNode\n imageGeneration?: DocxImageGeneration\n}) {\n const [selected, setSelected] = useState('Home')\n const contextual = useContextualTabs(selected)\n const tab = contextual.shown\n const t = useChromeTranslate()\n useGenerateImageTarget()\n const allCategories = [\n ...categories,\n ...contextual.tabs.map((name) => ({ name, icon: name === 'Table' ? Table : Image })),\n ]\n return (\n <div className=\"native-docx-ribbon native-docx-command-menu\">\n <DocxEditor.Toolbar t={t} preset={false} onSave={onSave}>\n <RibbonMenu\n label=\"Editing tools\"\n icon={\n <>\n <Menu size={16} />\n <span>Editing tools</span>\n <ChevronDown size={14} />\n </>\n }\n className=\"native-docx-command-trigger\"\n popoverClassName=\"native-docx-command-panel\"\n keepMounted\n restoreFocus\n >\n {(close) => (\n <div className=\"native-docx-command-layout\">\n <nav className=\"native-docx-command-categories\" aria-label=\"Editing tool categories\">\n {allCategories.map(({ name, icon: Icon }) => (\n <button\n type=\"button\"\n key={name}\n aria-pressed={tab === name}\n onClick={() => setSelected(name)}\n >\n <Icon size={16} aria-hidden=\"true\" />\n <span>{name}</span>\n </button>\n ))}\n </nav>\n <div\n className=\"native-docx-command-list\"\n role=\"group\"\n aria-label={`${tab} commands`}\n onClick={(event) => {\n const target = event.target as HTMLElement\n const button = target.closest<HTMLButtonElement>('button')\n const item = target.closest<HTMLElement>('[data-ribbon-item]')?.dataset.ribbonItem\n const direct = new Set([\n 'home-undo',\n 'home-redo',\n 'home-save',\n 'home-bold',\n 'home-italic',\n 'home-underline',\n 'home-bullets',\n 'home-numbers',\n 'home-indent',\n 'home-outdent',\n 'home-strike',\n 'home-clear',\n 'references-footnote',\n 'references-endnote',\n 'references-update-cross-references',\n 'table-row-above',\n 'table-row-below',\n 'table-column-left',\n 'table-column-right',\n ])\n if (\n (!button || !button.disabled) &&\n target.closest('[aria-disabled=\"true\"]') === null &&\n ((button && item && direct.has(item)) ||\n target.closest('[role=\"gridcell\"]') ||\n target.closest('[role=\"menuitemradio\"]') ||\n target.closest('[data-testid=\"docx-insert-my-signature\"]') ||\n target.closest('[data-testid=\"docx-insert-my-initials\"]') ||\n target.closest('.native-docx-style-gallery [role=\"option\"]') ||\n (button && button.closest('.native-docx-style-gallery')))\n ) {\n close()\n }\n }}\n >\n <NamedCommandList>\n {tab === 'Home' && (\n <>\n <RibbonItem id=\"home-undo\" label=\"Undo\">\n <DocxEditor.Toolbar.Undo />\n </RibbonItem>\n <RibbonItem id=\"home-redo\" label=\"Redo\">\n <DocxEditor.Toolbar.Redo />\n </RibbonItem>\n <RibbonItem id=\"home-save\" label=\"Save\">\n <DocxEditor.Toolbar.Save />\n </RibbonItem>\n <RibbonItem id=\"home-style\" label=\"Styles\">\n <StyleGallery />\n </RibbonItem>\n <RibbonItem id=\"home-bold\" label=\"Bold\">\n <DocxEditor.Toolbar.Bold />\n </RibbonItem>\n <RibbonItem id=\"home-italic\" label=\"Italic\">\n <DocxEditor.Toolbar.Italic />\n </RibbonItem>\n <RibbonItem id=\"home-underline\" label=\"Underline\">\n <DocxEditor.Toolbar.Underline />\n </RibbonItem>\n <RibbonItem id=\"home-font-family\" label=\"Font family\">\n <DocxEditor.Toolbar.FontFamily />\n </RibbonItem>\n <RibbonItem id=\"home-font-size\" label=\"Font size\">\n <DocxEditor.Toolbar.FontSize />\n </RibbonItem>\n <RibbonItem id=\"home-font-color\" label=\"Font color\">\n <DocxEditor.Toolbar.FontColor />\n </RibbonItem>\n <RibbonItem id=\"home-highlight\" label=\"Highlight\">\n <DocxEditor.Toolbar.Highlight />\n </RibbonItem>\n <RibbonItem id=\"home-alignment\" label=\"Alignment\">\n <DocxEditor.Toolbar.Alignment />\n </RibbonItem>\n <RibbonItem id=\"home-bullets\" label=\"Bulleted list\">\n <DocxEditor.Toolbar.BulletList />\n </RibbonItem>\n <RibbonItem id=\"home-numbers\" label=\"Numbered list\">\n <DocxEditor.Toolbar.NumberedList />\n </RibbonItem>\n <RibbonItem id=\"home-line-spacing\" label=\"Line spacing\">\n <DocxEditor.Toolbar.LineSpacing />\n </RibbonItem>\n <RibbonItem id=\"home-indent\" label=\"Increase indent\">\n <DocxEditor.Toolbar.Indent />\n </RibbonItem>\n <RibbonItem id=\"home-outdent\" label=\"Decrease indent\">\n <DocxEditor.Toolbar.Outdent />\n </RibbonItem>\n <RibbonItem id=\"home-strike\" label=\"Strikethrough\">\n <DocxEditor.Toolbar.Strike />\n </RibbonItem>\n <RibbonItem id=\"home-clear\" label=\"Clear formatting\">\n <DocxEditor.Toolbar.ClearFormatting />\n </RibbonItem>\n </>\n )}\n {tab === 'Insert' && (\n <>\n <RibbonItem id=\"insert-table\" label=\"Table\">\n <DocxEditor.Toolbar.TableInsert />\n </RibbonItem>\n <RibbonItem id=\"insert-picture\" label=\"Picture\">\n <DocxEditor.Toolbar.ImageInsert />\n </RibbonItem>\n {imageGeneration && (\n <RibbonItem id=\"insert-generate-image\" label=\"Generate image\">\n <GenerateImageButton generation={imageGeneration} />\n </RibbonItem>\n )}\n <RibbonItem id=\"insert-page-break\" label=\"Page break\">\n <DocxEditor.Toolbar.Button slotId=\"insert.pageBreak\" />\n </RibbonItem>\n <RibbonItem id=\"insert-link\" label=\"Link\">\n <DocxEditor.Toolbar.Link />\n </RibbonItem>\n <RibbonItem id=\"insert-defined-term\" label=\"Defined term\">\n <DefinedTermButton />\n </RibbonItem>\n <RibbonItem id=\"insert-quick-parts\" label=\"Quick Parts\">\n <QuickParts />\n </RibbonItem>\n <RibbonItem id=\"insert-signature-field\" label=\"Signature field\">\n <SignatureFieldMenu onInserted={close} />\n </RibbonItem>\n <RibbonItem id=\"insert-my-signature\" label=\"My signature\">\n <MySignatureMenu />\n </RibbonItem>\n <RibbonItem id=\"insert-cross-reference\" label=\"Cross-reference\">\n <CrossReferenceButton />\n </RibbonItem>\n </>\n )}\n <LayoutTabContent tab={tab} />\n {tab === 'Design' && (\n <RibbonItem id=\"design-house-template\" label=\"House template\">\n <HouseTemplatePanel />\n </RibbonItem>\n )}\n {tab === 'References' && (\n <>\n <NoteButtons />\n <RibbonItem id=\"references-cross-reference\" label=\"Cross-reference\">\n <CrossReferenceButton />\n </RibbonItem>\n <RibbonItem\n id=\"references-update-cross-references\"\n label=\"Update cross-references\"\n >\n <UpdateCrossReferencesButton />\n </RibbonItem>\n </>\n )}\n {tab === 'Review' && (\n <>\n <RibbonItem id=\"review-editing-mode\" label=\"Editing mode\">\n <DocxEditor.Toolbar.EditingMode />\n </RibbonItem>\n <RibbonItem id=\"review-comments\" label=\"Comments\">\n <DocxEditor.Toolbar.Comments />\n </RibbonItem>\n <RibbonItem id=\"review-options\" label=\"Review options\">\n <RibbonMenu label=\"Review options\" icon={<UsersRound size={16} />}>\n <DocxEditor.Toolbar.Reviewers />\n </RibbonMenu>\n </RibbonItem>\n </>\n )}\n </NamedCommandList>\n </div>\n </div>\n )}\n </RibbonMenu>\n <DocxEditor.Toolbar.TableCellFill hidden />\n </DocxEditor.Toolbar>\n {badge && (\n <span className=\"native-docx-ribbon-badge\" data-testid=\"docx-ribbon-badge\">\n {badge}\n </span>\n )}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -35,7 +35,7 @@ export interface NativeDocxAdapter {
35
35
  author?: string;
36
36
  subscribeTokenChanges?: (listener: () => void) => () => void;
37
37
  onDirtyChange?: (dirty: boolean) => void;
38
- onVersionSaved?: (documentId: string) => void | Promise<void>;
38
+ onVersionSaved?: (documentId: string, version?: number) => void | Promise<void>;
39
39
  notify?: (message: string, kind: 'success' | 'error') => void;
40
40
  mentions?: readonly DocxMention[];
41
41
  requestAgent?: (documentId: string, request: DocxAgentCommentRequest) => Promise<DocxMentionDelivery | void>;
@@ -89,6 +89,8 @@ export interface NativeDocxEditorProps {
89
89
  compact?: boolean;
90
90
  /** Receives a reader of the live room's state, so the host's save can include the latest keystrokes. */
91
91
  stateRef?: React.MutableRefObject<(() => string | undefined) | null>;
92
+ /** Save the current live room before leaving the editor; false means the caller must stay. */
93
+ saveRef?: React.MutableRefObject<(() => Promise<boolean | number>) | null>;
92
94
  }
93
95
  export declare function DocxParticipants({ session }: {
94
96
  session?: DocxCollaborationSession;
@@ -100,4 +102,4 @@ export declare function DocxRibbon({ onSave, badge, imageGeneration, }: {
100
102
  /** A short state label at the end of the row, such as "Co-editing". */
101
103
  badge?: React.ReactNode;
102
104
  }): React.JSX.Element;
103
- export declare function NativeDocxEditor({ documentId, title, draftContent, initialCommentId, snapshot, onSaved, stream, adapter, compact, stateRef, }: NativeDocxEditorProps): React.JSX.Element;
105
+ export declare function NativeDocxEditor({ documentId, title, draftContent, initialCommentId, snapshot, onSaved, stream, adapter, compact, stateRef, saveRef, }: NativeDocxEditorProps): React.JSX.Element;
@@ -33,6 +33,7 @@ import {
33
33
  } from "lucide-react";
34
34
  import { DefinedTermsProvider, useDefinedTerms } from "./definitions/DefinedTerms.js";
35
35
  import { RibbonMenu } from "./RibbonMenu.js";
36
+ import { DocxCommandMenu } from "./DocxCommandMenu.js";
36
37
  import { RibbonItem, RibbonOverflow } from "./RibbonOverflow.js";
37
38
  import { StyleGallery } from "./StyleGallery.js";
38
39
  import { NoteButtons, WordShortcuts } from "./WordReferences.js";
@@ -100,12 +101,21 @@ class EditorBoundary extends React.Component {
100
101
  ] }) : this.props.children;
101
102
  }
102
103
  }
103
- function RoomInputBinding({ session }) {
104
+ function RoomInputBinding({
105
+ session,
106
+ flushRef
107
+ }) {
104
108
  const editor = useDocxEditor();
105
109
  useEffect(() => {
106
- if (!editor || !session) return;
107
- return session.bindEditorInput(() => editor.surface?.flushPendingInput());
108
- }, [editor, session]);
110
+ if (!editor) return;
111
+ const flush = () => editor.surface?.flushPendingInput();
112
+ flushRef.current = flush;
113
+ const unbind = session?.bindEditorInput(flush);
114
+ return () => {
115
+ if (flushRef.current === flush) flushRef.current = null;
116
+ unbind?.();
117
+ };
118
+ }, [editor, session, flushRef]);
109
119
  return null;
110
120
  }
111
121
  function DocxParticipants({ session }) {
@@ -252,11 +262,14 @@ function NativeDocxEditor({
252
262
  stream,
253
263
  adapter,
254
264
  compact = false,
255
- stateRef
265
+ stateRef,
266
+ saveRef
256
267
  }) {
257
268
  const [ready, setReady] = useState(), [error, setError] = useState(""), [retry, setRetry] = useState(0);
258
269
  const [status, setStatus] = useState("Connecting\u2026"), [dirty, setDirty] = useState(false), [saving, setSaving] = useState(false), [offline, setOffline] = useState(false);
259
270
  const revision = useRef(0);
271
+ const savingRef = useRef(false);
272
+ const flushInputRef = useRef(null);
260
273
  const stageRef = useRef(null), fitCleanup = useRef(void 0), refit = useRef(void 0);
261
274
  const fitting = useRef(true), fitted = useRef(void 0);
262
275
  const [fitWidth, setFitWidth] = useState(true), [zoomPercent, setZoomPercent] = useState(100);
@@ -480,11 +493,16 @@ function NativeDocxEditor({
480
493
  };
481
494
  }, [documentId, isDraft, ready]);
482
495
  async function saveVersion() {
483
- if (!ready || saving || stream) return;
496
+ if (!ready || savingRef.current || stream) return false;
497
+ if (snapshot || !ready.canEdit) return true;
498
+ if (offline) return false;
499
+ savingRef.current = true;
484
500
  setSaving(true);
485
- runBeforeSave(ref.current);
486
- const atRevision = revision.current;
487
501
  try {
502
+ if (!flushInputRef.current) throw new Error("The editor is not ready to save yet.");
503
+ flushInputRef.current();
504
+ runBeforeSave(ref.current);
505
+ const atRevision = revision.current;
488
506
  const result = isDraft ? await (async () => {
489
507
  const bytes = await ref.current?.save();
490
508
  if (!bytes) throw new Error("The editor is not ready.");
@@ -501,17 +519,32 @@ function NativeDocxEditor({
501
519
  setDirty(false);
502
520
  drafts.delete(documentId);
503
521
  }
504
- await Promise.resolve(adapter.onVersionSaved?.(result.document_ext_id)).catch(() => {
505
- });
522
+ const savedVersion = "version" in result && typeof result.version === "number" ? result.version : void 0;
523
+ if (!isDraft && !savedVersion) throw new Error("Could not confirm the saved version.");
524
+ await adapter.onVersionSaved?.(result.document_ext_id, savedVersion);
506
525
  onSaved?.(result.document_ext_id);
526
+ if (revision.current !== atRevision) {
527
+ adapter.notify?.("The document changed while saving. Please try again.", "error");
528
+ return false;
529
+ }
507
530
  adapter.notify?.(isDraft ? "Word note saved" : "DOCX version saved", "success");
531
+ return savedVersion ?? true;
508
532
  } catch (e) {
509
533
  adapter.notify?.(e instanceof Error ? e.message : "Could not save this document.", "error");
510
534
  setStatus("Save failed \xB7 your draft is retained");
535
+ return false;
511
536
  } finally {
537
+ savingRef.current = false;
512
538
  setSaving(false);
513
539
  }
514
540
  }
541
+ useEffect(() => {
542
+ if (!saveRef) return;
543
+ saveRef.current = saveVersion;
544
+ return () => {
545
+ saveRef.current = null;
546
+ };
547
+ });
515
548
  function editorReady(editor) {
516
549
  ref.current = editor;
517
550
  if (streamRef.current) {
@@ -672,7 +705,7 @@ function NativeDocxEditor({
672
705
  ),
673
706
  compact && !stream && /* @__PURE__ */ jsx(CompactToolbar, {}),
674
707
  !compact && !stream && /* @__PURE__ */ jsx(
675
- DocxRibbon,
708
+ DocxCommandMenu,
676
709
  {
677
710
  onSave: () => void saveVersion(),
678
711
  imageGeneration: adapter.imageGeneration && {
@@ -713,7 +746,13 @@ function NativeDocxEditor({
713
746
  getAgentStatus: adapter.getAgentStatus,
714
747
  requestAgent: adapter.requestAgent ? (request) => adapter.requestAgent(documentId, request) : void 0,
715
748
  children: [
716
- /* @__PURE__ */ jsx(RoomInputBinding, { session: ready.room?.session }),
749
+ /* @__PURE__ */ jsx(
750
+ RoomInputBinding,
751
+ {
752
+ session: ready.room?.session,
753
+ flushRef: flushInputRef
754
+ }
755
+ ),
717
756
  /* @__PURE__ */ jsx(AgentUndoRoom.Provider, { value: ready.room?.ydoc ?? null, children: /* @__PURE__ */ jsx(DocxEditorReview, { children: () => /* @__PURE__ */ jsxs(DocxEditorReview.Card, { children: [
718
757
  /* @__PURE__ */ jsx(DocxCommentActivity, {}),
719
758
  /* @__PURE__ */ jsx(AgentUndo, {})