collabmd 0.1.47 → 0.1.49

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 (305) hide show
  1. package/README.md +70 -11
  2. package/bin/collabmd.js +3 -0
  3. package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-C-nmgL5g.js +1 -0
  4. package/dist/client/assets/JetBrainsMono-Regular-BQaDgvhP.woff2 +0 -0
  5. package/dist/client/assets/abnfDiagram-VCTEODGH-CdVZqicp.js +1 -0
  6. package/dist/client/assets/{architectureDiagram-5GKGNRK7-I39sYjHI.js → architectureDiagram-5GKGNRK7-wUo0bXif.js} +3 -3
  7. package/dist/client/assets/babel-CY5KOv-I.js +16 -0
  8. package/dist/client/assets/{blockDiagram-NRAW4CY4-C6DtJy5Y.js → blockDiagram-I7D4REHJ-BRSK3m49.js} +4 -4
  9. package/dist/client/assets/browser-utils-DbXSMI-6.js +1 -0
  10. package/dist/client/assets/{c4Diagram-UCG6FXSJ-CtWtxS9_.js → c4Diagram-7LVT6UL2-yD2poxqw.js} +1 -1
  11. package/dist/client/assets/channel-Fa4GS_-F.js +1 -0
  12. package/dist/client/assets/chunk-2E4U76K2-BPnTT-J3.js +2 -0
  13. package/dist/client/assets/{chunk-TEH6E4GO-DVayPj-q.js → chunk-4HAMMTFA-DStbIfJ1.js} +20 -20
  14. package/dist/client/assets/{chunk-75Z2AOVW-CdFSaPjz.js → chunk-75Z2AOVW-C5pGd3W9.js} +1 -1
  15. package/dist/client/assets/{chunk-CLGD4ZFX-DQLgbQrv.js → chunk-CLGD4ZFX-BMeArk03.js} +1 -1
  16. package/dist/client/assets/chunk-DU6HZSFF-Zkp69c6c.js +127 -0
  17. package/dist/client/assets/{chunk-F27PBJKO-CNHIFhjo.js → chunk-F27PBJKO-D4xNct1r.js} +1 -1
  18. package/dist/client/assets/{chunk-GMAD6QVW-CbcBqPM5.js → chunk-GMAD6QVW-NZ6WpDb8.js} +1 -1
  19. package/dist/client/assets/{chunk-OBVCFTLP-BJR7u1jh.js → chunk-GVQU2GXP-D8SDprfX.js} +1 -1
  20. package/dist/client/assets/{chunk-G27WJ6UU-D9-eg537.js → chunk-IMKFNOWR-D8jEuU3Q.js} +2 -2
  21. package/dist/client/assets/{chunk-JQ64N6SF-DSFNH4bh.js → chunk-L3NEJ4N5-aijKP-eh.js} +1 -1
  22. package/dist/client/assets/chunk-OSK3NFVY-CCbLQAMa.js +10 -0
  23. package/dist/client/assets/{chunk-P2QGCYS3-BRpqY32H.js → chunk-P2QGCYS3-Oag_FdCq.js} +1 -1
  24. package/dist/client/assets/{chunk-POPQ4Y6H-Cb4SlVZF.js → chunk-POPQ4Y6H-CYnpIgXT.js} +1 -1
  25. package/dist/client/assets/{chunk-PWAF6VOD-Cz8IwBB5.js → chunk-PWAF6VOD-JSNrcBmP.js} +1 -1
  26. package/dist/client/assets/{chunk-RM4UPSZO-CWRwxNWJ.js → chunk-RM4UPSZO-DOWllDY8.js} +4 -4
  27. package/dist/client/assets/{chunk-RHFEMEQ7-CWY8cf4H.js → chunk-SHT3W25Y-BiQGljao.js} +5 -5
  28. package/dist/client/assets/{chunk-SVP7TREG-CyHOmcac.js → chunk-SVP7TREG-DB485R5x.js} +1 -1
  29. package/dist/client/assets/{chunk-LCL6LL3I-DmDkVukh.js → chunk-TICWLB2K-8rAVvoS3.js} +4 -4
  30. package/dist/client/assets/{chunk-CKBBP62Z-DG26UiBv.js → chunk-TLUHSLCS-DTY5v0aj.js} +2 -2
  31. package/dist/client/assets/classDiagram-ZZMXUADV-BsQWoR3Q.js +1 -0
  32. package/dist/client/assets/classDiagram-v2-VYDZK3BY-BsQWoR3Q.js +1 -0
  33. package/dist/client/assets/{comment-thread-store-CdcwrObc.js → comment-thread-store-CX98zR6q.js} +1 -1
  34. package/dist/client/assets/comment-threads-BnRwo5B9.js +4 -0
  35. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CdTPi2yO.js → cynefinDiagram-5FMLGOSQ-rTz9RhFH.js} +1 -1
  36. package/dist/client/assets/{dagre-3AP2YEHR-5gtJtd0O.js → dagre-GXQ25YYZ-Cr67wLpQ.js} +2 -2
  37. package/dist/client/assets/{diagram-S7CK7UJ4-BudWz9WU.js → diagram-S7CK7UJ4-DywERe__.js} +2 -2
  38. package/dist/client/assets/{diagram-UQ7AKVKN-3v4rbH-s.js → diagram-UQ7AKVKN-CNYlXtu4.js} +1 -1
  39. package/dist/client/assets/diagram-VSXAHHWV-0H1a61Bn.js +3 -0
  40. package/dist/client/assets/{diagram-VX7I27RA-C_-rj0sw.js → diagram-VX7I27RA-CsJbsx5F.js} +1 -1
  41. package/dist/client/assets/{diagram-Z3DM3KII-B4yxavgj.js → diagram-Z3DM3KII-D0mLxEgI.js} +1 -1
  42. package/dist/client/assets/dist--hk9I5HQ.js +1 -0
  43. package/dist/client/assets/{dist-DutPuFmC.js → dist-B1XEa-Zs.js} +1 -1
  44. package/dist/client/assets/dist-Bd1JucQF.js +1 -0
  45. package/dist/client/assets/{dist-DZAAWTG-.js → dist-C0G3AaXG.js} +1 -1
  46. package/dist/client/assets/dist-ChRoo3IB.js +9 -0
  47. package/dist/client/assets/dist-Dm4w5UId.js +1 -0
  48. package/dist/client/assets/{dist-B_yQaEv_.js → dist-DpYDHR9p.js} +1 -1
  49. package/dist/client/assets/{dist-CietwTVS.js → dist-DzNmC81X.js} +1 -1
  50. package/dist/client/assets/{dist-DDUn5zTz.js → dist-GvvCNBe4.js} +1 -1
  51. package/dist/client/assets/dist-JaU3aRlD.js +19 -0
  52. package/dist/client/assets/{dist-Bw3VIE_v.js → dist-TW8iFRyW.js} +1 -1
  53. package/dist/client/assets/{dist-Dir5dDKZ.js → dist-jVU5Be5P.js} +1 -1
  54. package/dist/client/assets/document-formatter-rDDjRfZ2.js +2 -0
  55. package/dist/client/assets/drawioEditor-JubEEha7.js +9 -0
  56. package/dist/client/assets/ebnfDiagram-PWID7BFC-HeTxHpCU.js +1 -0
  57. package/dist/client/assets/editor-session-Bk6oIvSr.js +54 -0
  58. package/dist/client/assets/embedded-editor-base-BlCgz6mw.css +1 -0
  59. package/dist/client/assets/{erDiagram-SSCWMZ5O-C-iy6VkX.js → erDiagram-RLTQ6QDP-CbrDdd5P.js} +2 -2
  60. package/dist/client/assets/{es-CAsWR6hG.js → es-Bfdp096f.js} +13 -13
  61. package/dist/client/assets/estree-CuT_pB8K.js +44 -0
  62. package/dist/client/assets/excalidraw-element-link-YLIaTnVF.js +7 -0
  63. package/dist/client/assets/{excalidraw-scene-BOben2gr.js → excalidraw-scene-6uROebca.js} +1 -1
  64. package/dist/client/assets/{excalidraw-editor-BlcN6umJ.css → excalidrawEditor-BbSbI80a.css} +1 -1
  65. package/dist/client/assets/excalidrawEditor-dBMbRX_S.js +9 -0
  66. package/dist/client/assets/export-page-CRRQ2NEl.js +57 -0
  67. package/dist/client/assets/exportDocument-BlQRd9_m.js +2 -0
  68. package/dist/client/assets/exportDocument-CNSbjZwu.css +1 -0
  69. package/dist/client/assets/{file-icon-svg-CQAjlWjK.js → file-icon-svg-Y_kpF957.js} +1 -1
  70. package/dist/client/assets/file-kind-BwMIcZbi.js +1 -0
  71. package/dist/client/assets/file-search-DDLyyLDU.js +1 -0
  72. package/dist/client/assets/flowDiagram-HODETNUW-D5Gy0wmg.js +1 -0
  73. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-DtKHAbez.js → ganttDiagram-EL5Y4UJY-BHgOYiZz.js} +1 -1
  74. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-oue8fQ5o.js → gitGraphDiagram-WWUBYQGX-Dl__X3Sk.js} +1 -1
  75. package/dist/client/assets/html-Cdnr2qzU.js +25 -0
  76. package/dist/client/assets/image-ZVKINSPA-DgzW5zAy.js +1 -0
  77. package/dist/client/assets/index-D3RER1SZ.js +1023 -0
  78. package/dist/client/assets/index-DREVKl_K.css +1 -0
  79. package/dist/client/assets/{infoDiagram-RXCK75RN-BMzo6KIn.js → infoDiagram-27XIBGKW-DBpoANC9.js} +1 -1
  80. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BIM3h287.js → ishikawaDiagram-5VMMS53U-BMPC6hfp.js} +1 -1
  81. package/dist/client/assets/{journeyDiagram-EYS64GPL-mF6Lh8O-.js → journeyDiagram-3NMN7TZE-B1sApUmM.js} +2 -2
  82. package/dist/client/assets/{kanban-definition-3QL26DDD-DLN2NyoR.js → kanban-definition-UXKFOSKX-C9yP4td1.js} +4 -4
  83. package/dist/client/assets/{line-BfTWJmgf.js → line-BFl3ujec.js} +1 -1
  84. package/dist/client/assets/markdown-CByV-4CU.js +70 -0
  85. package/dist/client/assets/{mermaid.core-CLZBlpIW.js → mermaid.core-BrY09czX.js} +5 -5
  86. package/dist/client/assets/mermaid.core-DfcNfOTv.js +1 -0
  87. package/dist/client/assets/{mindmap-definition-FBJOCRG2-CRyHaHTk.js → mindmap-definition-YA3MSWOX-BUQHcYbK.js} +8 -8
  88. package/dist/client/assets/pegDiagram-XKGWAZYB-Bi2Iml7Z.js +1 -0
  89. package/dist/client/assets/{pieDiagram-E7YTZNPT-B5OZPb88.js → pieDiagram-E7YTZNPT-_gYXnMoi.js} +1 -1
  90. package/dist/client/assets/preview-render-compiler-CfxJYldJ.js +41 -0
  91. package/dist/client/assets/preview-render-compiler-Cu8_i9iS.js +1 -0
  92. package/dist/client/assets/{preview-render-worker-BmN79bVc.js → preview-render-worker-c4Yi93qW.js} +41 -35
  93. package/dist/client/assets/prod-BiJL30sl.js +1 -0
  94. package/dist/client/assets/prod-qAk7rHa4.js +177 -0
  95. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-Drrw14YH.js → quadrantDiagram-AXDQQJYC-DwexhEhd.js} +1 -1
  96. package/dist/client/assets/quick-switcher-controller-BoIK_wuG.js +1 -0
  97. package/dist/client/assets/railroadDiagram-O6MQD6OU-BVA5UbMu.js +1 -0
  98. package/dist/client/assets/{requirementDiagram-EFPCY7ZU-CRZG6mRB.js → requirementDiagram-BXWQKSXE-C4cKwiIw.js} +2 -2
  99. package/dist/client/assets/runtime-config-DcmnGcXU.js +1 -0
  100. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-DvarEJpo.js → sankeyDiagram-P5KCCOFB-B5HHkRT2.js} +1 -1
  101. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-B4oWlb-w.js → sequenceDiagram-WJ2MYXX4-BX6jqJFD.js} +6 -6
  102. package/dist/client/assets/standalone-6z5x8CWe.js +29 -0
  103. package/dist/client/assets/{stateDiagram-HBIQ2CUA-qbHIIqRZ.js → stateDiagram-D77RDMKH-CmqxyRGx.js} +1 -1
  104. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-zoLLQVyh.js +1 -0
  105. package/dist/client/assets/{swimlanes-XN3QIQJK-xB6CtUGj.js → swimlanes-42K2YHIH-Bmgb9Zld.js} +1 -1
  106. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DS-KQN37.js +8 -0
  107. package/dist/client/assets/{timeline-definition-24CTP7MA-Lj_yTNlY.js → timeline-definition-24CTP7MA-BA-lVH6P.js} +1 -1
  108. package/dist/client/assets/vault-api-client-iZLhMJKe.js +6 -0
  109. package/dist/client/assets/{vennDiagram-4TSXK5OY-BekRp5Y0.js → vennDiagram-4TSXK5OY-DNdUC_Xj.js} +1 -1
  110. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-kdnV_Hdm.js → wardleyDiagram-VM6X3IG4-C2oY-YbF.js} +1 -1
  111. package/dist/client/assets/wiki-link-resolver-DFIwErjc.js +1 -0
  112. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DufGwNSB.js → xychartDiagram-S5SC5T6Z-CoIR8CBX.js} +1 -1
  113. package/dist/client/assets/yaml-9ltHPDNO.js +154 -0
  114. package/dist/client/assets/{yjs-provider-reset-guard-DE0vINDP.js → yjs-provider-reset-guard-9ul1qF6k.js} +1 -1
  115. package/dist/client/drawio-editor.html +11 -3
  116. package/dist/client/excalidraw-editor.html +45 -2
  117. package/dist/client/export-document.html +3 -3
  118. package/dist/client/index.html +106 -52
  119. package/integrations/pi/index.ts +94 -0
  120. package/package.json +41 -29
  121. package/src/client/app/drawio-editor.html +2 -2
  122. package/src/client/app/excalidraw-editor.html +2 -2
  123. package/src/client/app/export-document.html +1 -1
  124. package/src/client/app/index.html +88 -50
  125. package/src/client/app/main-entry.js +15 -1
  126. package/src/client/application/app-shell/chat-feature.js +7 -22
  127. package/src/client/application/app-shell/export-feature.js +17 -1
  128. package/src/client/application/app-shell/git-feature.js +51 -14
  129. package/src/client/application/app-shell/presence-feature.js +8 -25
  130. package/src/client/application/app-shell/ui-feature-identity.js +13 -0
  131. package/src/client/application/app-shell/ui-feature-shell.js +199 -99
  132. package/src/client/application/app-shell/ui-feature-sidebar.js +43 -7
  133. package/src/client/application/app-shell/ui-feature-tab-activity.js +19 -6
  134. package/src/client/application/app-shell/ui-feature-toolbar.js +16 -129
  135. package/src/client/application/app-shell-elements.js +8 -0
  136. package/src/client/application/preview-render-compiler.js +1 -87
  137. package/src/client/application/preview-render-scheduler.js +8 -24
  138. package/src/client/application/preview-renderer.js +2 -2
  139. package/src/client/application/webmcp-diagram-renderer.js +47 -0
  140. package/src/client/application/workspace-coordinator.js +23 -4
  141. package/src/client/application/workspace-preview-controller.js +120 -2
  142. package/src/client/application/workspace-route-controller.js +11 -1
  143. package/src/client/assets/vendor/jetbrains-mono/JetBrainsMono-Regular.woff2 +0 -0
  144. package/src/client/assets/vendor/jetbrains-mono/OFL.txt +93 -0
  145. package/src/client/bootstrap/collabmd-app-shell.js +99 -6
  146. package/src/client/domain/document-formatter.js +193 -0
  147. package/src/client/domain/excalidraw-element-link.js +73 -0
  148. package/src/client/domain/excalidraw-scene.js +21 -0
  149. package/src/client/domain/file-search.js +73 -0
  150. package/src/client/domain/git-labels.js +5 -0
  151. package/src/client/domain/hash-routes.js +8 -0
  152. package/src/client/domain/room.js +1 -5
  153. package/src/client/domain/runtime-paths.js +5 -0
  154. package/src/client/domain/vault-paths.js +6 -4
  155. package/src/client/domain/wiki-link-completions.js +20 -20
  156. package/src/client/drawio-editor.js +8 -3
  157. package/src/client/excalidraw-editor.js +287 -16
  158. package/src/client/export/export-host.js +59 -36
  159. package/src/client/export/export-page.js +14 -4
  160. package/src/client/export/export-pipeline.js +270 -42
  161. package/src/client/infrastructure/agent-connection-api-client.js +23 -0
  162. package/src/client/infrastructure/auth-client.js +3 -13
  163. package/src/client/infrastructure/editor-session.js +15 -0
  164. package/src/client/infrastructure/editor-view-adapter.js +73 -14
  165. package/src/client/infrastructure/excalidraw-room-client.js +80 -1
  166. package/src/client/infrastructure/git-api-client.js +39 -33
  167. package/src/client/infrastructure/lobby-presence.js +2 -5
  168. package/src/client/infrastructure/runtime-config.js +11 -1
  169. package/src/client/infrastructure/tab-activity-lock.js +2 -5
  170. package/src/client/infrastructure/vault-api-client.js +33 -26
  171. package/src/client/infrastructure/webmcp-tool-registry.js +283 -0
  172. package/src/client/infrastructure/workspace-sync-client.js +6 -4
  173. package/src/client/presentation/agent-connection-controller.js +255 -0
  174. package/src/client/presentation/backlinks-panel.js +3 -0
  175. package/src/client/presentation/bases-preview-controller.js +59 -26
  176. package/src/client/presentation/comment-ui/comment-ui-card.js +4 -2
  177. package/src/client/presentation/create-menu-presenter.js +19 -16
  178. package/src/client/presentation/excalidraw-embed-controller.js +164 -4
  179. package/src/client/presentation/file-action-controller.js +15 -2
  180. package/src/client/presentation/file-explorer-controller.js +3 -0
  181. package/src/client/presentation/file-explorer-view.js +71 -12
  182. package/src/client/presentation/file-history-view-controller.js +19 -12
  183. package/src/client/presentation/file-tree-state.js +1 -11
  184. package/src/client/presentation/git-diff-view-controller.js +70 -53
  185. package/src/client/presentation/git-panel-controller.js +86 -32
  186. package/src/client/presentation/image-lightbox-controller.js +20 -16
  187. package/src/client/presentation/layout-controller.js +3 -1
  188. package/src/client/presentation/quick-switcher-controller.js +74 -232
  189. package/src/client/presentation/quick-switcher-text-search.js +10 -14
  190. package/src/client/styles/components/navigation.css +1 -2
  191. package/src/client/styles/components/scrollbars.css +10 -0
  192. package/src/client/styles/export-document.css +44 -29
  193. package/src/client/styles/features/agent-connection.css +202 -0
  194. package/src/client/styles/features/collaboration-chat.css +8 -1
  195. package/src/client/styles/features/collaboration-dialogs.css +16 -1
  196. package/src/client/styles/features/collaboration-presence.css +30 -5
  197. package/src/client/styles/features/diff-toolbar.css +1 -1
  198. package/src/client/styles/features/media-lightbox.css +12 -3
  199. package/src/client/styles/features/preview-markdown.css +54 -0
  200. package/src/client/styles/features/quick-switcher.css +20 -11
  201. package/src/client/styles/foundation/themes.css +2 -0
  202. package/src/client/styles/foundation/tokens.css +8 -0
  203. package/src/client/styles/layout/editor-page.css +25 -11
  204. package/src/client/styles/layout/responsive.css +2 -20
  205. package/src/client/styles/layout/shell.css +77 -24
  206. package/src/client/styles/layout/sidebar.css +7 -4
  207. package/src/client/styles/layout/view-modes.css +2 -0
  208. package/src/client/styles/overrides/codemirror.css +31 -19
  209. package/src/client/styles/primitives/controls.css +21 -54
  210. package/src/client/styles/style.css +1 -0
  211. package/src/client/styles/surfaces/excalidraw-editor.css +42 -0
  212. package/src/domain/agent-tool-definitions.js +796 -0
  213. package/src/domain/collabmd-content-capabilities.js +149 -0
  214. package/src/domain/collaboration-protocol.js +2 -0
  215. package/src/domain/comment-threads.js +3 -5
  216. package/src/domain/diagram-source.js +50 -0
  217. package/src/domain/editable-content-revision.js +10 -0
  218. package/src/domain/editable-text.js +3 -0
  219. package/src/domain/exact-text-edits.js +69 -0
  220. package/src/domain/excalidraw-agent-scene.js +522 -0
  221. package/src/domain/excalidraw-agent-verification.js +460 -0
  222. package/src/domain/excalidraw-room-codec.js +1 -5
  223. package/src/domain/file-kind.js +12 -1
  224. package/src/domain/video-embed.js +76 -0
  225. package/src/server/application/agent-connection-service.js +178 -0
  226. package/src/server/application/agent-content-service.js +773 -0
  227. package/src/server/application/workspace-reconciliation.js +5 -7
  228. package/src/server/config/env.js +51 -1
  229. package/src/server/create-app-server.js +36 -0
  230. package/src/server/domain/bases/base-query-service.js +1 -5
  231. package/src/server/domain/collaboration/collaboration-room.js +121 -25
  232. package/src/server/domain/collaboration/protocol.js +4 -0
  233. package/src/server/domain/hosted-workspace.js +21 -0
  234. package/src/server/domain/markdown-reference-extractor.js +15 -1
  235. package/src/server/domain/ripgrep-search-service.js +110 -37
  236. package/src/server/infrastructure/git/git-service.js +19 -1
  237. package/src/server/infrastructure/git/history-service.js +1 -1
  238. package/src/server/infrastructure/git/local-exclude.js +25 -0
  239. package/src/server/infrastructure/git/parsers.js +19 -17
  240. package/src/server/infrastructure/git/path-utils.js +0 -16
  241. package/src/server/infrastructure/git/status-service.js +1 -1
  242. package/src/server/infrastructure/git/untracked-files.js +12 -21
  243. package/src/server/infrastructure/http/create-agent-api-handler.js +171 -0
  244. package/src/server/infrastructure/http/create-git-api-command-handler.js +32 -0
  245. package/src/server/infrastructure/http/create-request-handler.js +28 -0
  246. package/src/server/infrastructure/http/create-static-handler.js +6 -0
  247. package/src/server/infrastructure/mcp/create-agent-mcp-handler.js +199 -0
  248. package/src/server/infrastructure/persistence/agent-connection-store.js +120 -0
  249. package/src/server/infrastructure/persistence/path-utils.js +10 -4
  250. package/src/server/infrastructure/persistence/pull-backup-store.js +2 -27
  251. package/src/server/infrastructure/persistence/vault-file-store.js +11 -2
  252. package/src/server/shared/agent-tool-image.js +22 -0
  253. package/src/server/shared/agent-tool-rate-limiter.js +20 -0
  254. package/src/server/startup/git-remote-bootstrap.js +5 -33
  255. package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-BPH4FJkv.js +0 -1
  256. package/dist/client/assets/abnfDiagram-VCTEODGH-BNDLzJ7L.js +0 -1
  257. package/dist/client/assets/browser-utils--H_DkyEF.js +0 -1
  258. package/dist/client/assets/channel-CaoKA_We.js +0 -1
  259. package/dist/client/assets/chunk-DSNCTWBM-8xkug7fQ.js +0 -2
  260. package/dist/client/assets/chunk-DU6HZSFF-COXDzJK1.js +0 -127
  261. package/dist/client/assets/chunk-R7TYR2AO-CTd0Yj98.js +0 -10
  262. package/dist/client/assets/classDiagram-DTDB5LWJ-7fEmn0zV.js +0 -1
  263. package/dist/client/assets/classDiagram-v2-JRS7N3AN-7fEmn0zV.js +0 -1
  264. package/dist/client/assets/comment-threads-9J6Em-_y.js +0 -4
  265. package/dist/client/assets/comment-ui-shared-DWkk9Vh3.js +0 -7
  266. package/dist/client/assets/diagram-VSXAHHWV-CQRVEZR7.js +0 -3
  267. package/dist/client/assets/dist-73RPdcyU.js +0 -1
  268. package/dist/client/assets/dist-CH-sQu3r.js +0 -1
  269. package/dist/client/assets/drawio-editor-BjrxTe3l.js +0 -9
  270. package/dist/client/assets/drawioEditor-DUVZjSSr.js +0 -2
  271. package/dist/client/assets/ebnfDiagram-PWID7BFC-OXa8VEp1.js +0 -1
  272. package/dist/client/assets/editor-session-DfZuRgB_.js +0 -54
  273. package/dist/client/assets/embedded-editor-base-DvMynhKu.css +0 -1
  274. package/dist/client/assets/excalidraw-editor-D7pnUCLH.js +0 -9
  275. package/dist/client/assets/excalidraw-mermaid-stub-BNckbX2n.js +0 -1
  276. package/dist/client/assets/excalidraw-mermaid-stub-DE5FTiZB.js +0 -1
  277. package/dist/client/assets/excalidrawEditor-B0jOK3lv.js +0 -2
  278. package/dist/client/assets/export-page-Bs3xE1fg.js +0 -57
  279. package/dist/client/assets/exportDocument-Dg9MjkIk.js +0 -2
  280. package/dist/client/assets/exportDocument-PnYU3v1s.css +0 -1
  281. package/dist/client/assets/file-kind-BbqgGzpc.js +0 -1
  282. package/dist/client/assets/flowDiagram-A5DVABFB-CiW1eN8C.js +0 -1
  283. package/dist/client/assets/image-ZVKINSPA-0zXSnE7M.js +0 -1
  284. package/dist/client/assets/index-BIpgxyGZ.css +0 -1
  285. package/dist/client/assets/index-Z5sI0Bj-.js +0 -2
  286. package/dist/client/assets/main-Dwnj9Gaq.js +0 -903
  287. package/dist/client/assets/pegDiagram-XKGWAZYB-B31fKPR2.js +0 -1
  288. package/dist/client/assets/preview-render-compiler-BApvlLLo.js +0 -35
  289. package/dist/client/assets/preview-render-compiler-BQ_3h9vD.js +0 -1
  290. package/dist/client/assets/preview-render-profile-CE-5rVTC.js +0 -1
  291. package/dist/client/assets/prod-BiYPMR1i.js +0 -177
  292. package/dist/client/assets/prod-VxdGZ5Ly.js +0 -1
  293. package/dist/client/assets/quick-switcher-controller-ButWPmCI.js +0 -12
  294. package/dist/client/assets/railroadDiagram-O6MQD6OU-BPifP0MB.js +0 -1
  295. package/dist/client/assets/runtime-config-BLrEKVO1.js +0 -1
  296. package/dist/client/assets/stateDiagram-v2-4QOOHH4V-B--gjrit.js +0 -1
  297. package/dist/client/assets/swimlanesDiagram-VK2B7HYN-DO8XNXEg.js +0 -8
  298. package/dist/client/assets/vault-api-client-_LpV1aIn.js +0 -6
  299. package/dist/client/assets/vault-utils-wdQ0RNR9.js +0 -1
  300. package/src/client/app/drawio-editor-entry.js +0 -1
  301. package/src/client/app/excalidraw-editor-entry.js +0 -1
  302. package/src/client/excalidraw-mermaid-stub.js +0 -7
  303. package/src/client/main.js +0 -16
  304. /package/dist/client/assets/{drawio-editor-UQQ8XHou.css → drawioEditor-UQQ8XHou.css} +0 -0
  305. /package/dist/client/assets/{sizeCapture-X5ZJPWSS-B0uUizjq.js → sizeCapture-INFHLROL-B0uUizjq.js} +0 -0
@@ -76,6 +76,8 @@ export class ImageLightboxController {
76
76
  this.pinchStartCenter = { x: 0, y: 0 };
77
77
  this.didDrag = false;
78
78
  this.resetButton = null;
79
+ this.previouslyFocusedElement = null;
80
+ this.blockingModalHandler = () => this.close();
79
81
 
80
82
  this.handlePreviewClick = (event) => {
81
83
  const target = event.target;
@@ -102,12 +104,6 @@ export class ImageLightboxController {
102
104
  return;
103
105
  }
104
106
 
105
- if (event.key === 'Escape') {
106
- event.preventDefault();
107
- this.close();
108
- return;
109
- }
110
-
111
107
  if (event.key === '+' || event.key === '=') {
112
108
  event.preventDefault();
113
109
  this.zoomBy(ZOOM_STEP);
@@ -161,15 +157,19 @@ export class ImageLightboxController {
161
157
  }
162
158
 
163
159
  this.ensureOverlayRoot();
160
+ this.previouslyFocusedElement = this.document.activeElement instanceof this.window.HTMLElement
161
+ ? this.document.activeElement
162
+ : null;
164
163
  this.resetView();
165
164
  this.titleElement.textContent = image.getAttribute('alt') || 'Image preview';
166
165
  this.imageElement.src = src;
167
166
  this.imageElement.alt = image.getAttribute('alt') || '';
168
- this.overlayRoot.hidden = false;
167
+ this.overlayRoot.showModal();
169
168
  this.isOpen = true;
170
169
  this.document.body.classList.add('image-lightbox-open');
170
+ this.document.addEventListener('collabmd:close-custom-modals', this.blockingModalHandler);
171
171
  this.syncTransform();
172
- this.overlayRoot.focus?.();
172
+ this.overlayRoot.querySelector('button:not(:disabled)')?.focus();
173
173
  return true;
174
174
  }
175
175
 
@@ -184,11 +184,14 @@ export class ImageLightboxController {
184
184
  this.pinchStartDistance = 0;
185
185
  this.didDrag = false;
186
186
  this.viewport?.classList?.remove('is-dragging');
187
- if (this.overlayRoot) {
188
- this.overlayRoot.hidden = true;
187
+ if (this.overlayRoot?.open) {
188
+ this.overlayRoot.close();
189
189
  }
190
190
  this.isOpen = false;
191
191
  this.document.body.classList.remove('image-lightbox-open');
192
+ this.document.removeEventListener('collabmd:close-custom-modals', this.blockingModalHandler);
193
+ this.previouslyFocusedElement?.focus?.();
194
+ this.previouslyFocusedElement = null;
192
195
  }
193
196
 
194
197
  resetView() {
@@ -442,11 +445,14 @@ export class ImageLightboxController {
442
445
  return this.overlayRoot;
443
446
  }
444
447
 
445
- const overlayRoot = this.document.createElement('div');
448
+ const overlayRoot = this.document.createElement('dialog');
446
449
  overlayRoot.className = 'image-lightbox-root';
447
450
  overlayRoot.dataset.imageLightboxRoot = 'true';
448
- overlayRoot.hidden = true;
449
- overlayRoot.tabIndex = -1;
451
+ overlayRoot.setAttribute('aria-labelledby', 'imageLightboxTitle');
452
+ overlayRoot.addEventListener('cancel', (event) => {
453
+ event.preventDefault();
454
+ this.close();
455
+ });
450
456
 
451
457
  const backdrop = this.document.createElement('button');
452
458
  backdrop.className = 'image-lightbox-backdrop';
@@ -460,9 +466,6 @@ export class ImageLightboxController {
460
466
 
461
467
  const shell = this.document.createElement('div');
462
468
  shell.className = 'image-lightbox-shell';
463
- shell.setAttribute('role', 'dialog');
464
- shell.setAttribute('aria-modal', 'true');
465
- shell.setAttribute('aria-label', 'Image preview');
466
469
  shell.addEventListener('click', (event) => event.stopPropagation());
467
470
  shell.addEventListener('pointerdown', (event) => event.stopPropagation());
468
471
 
@@ -471,6 +474,7 @@ export class ImageLightboxController {
471
474
 
472
475
  const title = this.document.createElement('div');
473
476
  title.className = 'image-lightbox-title';
477
+ title.id = 'imageLightboxTitle';
474
478
  title.textContent = 'Image preview';
475
479
 
476
480
  const controls = this.document.createElement('div');
@@ -15,7 +15,7 @@ export class LayoutController {
15
15
  this.previewPane = document.getElementById('previewPane');
16
16
  this.mobileToggleButton = document.getElementById('mobileViewToggle');
17
17
  this.resizer = document.getElementById('resizer');
18
- this.viewButtons = Array.from(document.querySelectorAll('.view-btn'));
18
+ this.viewButtons = Array.from(document.querySelectorAll('#toolbarViewToggle [data-view]'));
19
19
  }
20
20
 
21
21
  isMobileViewport() {
@@ -128,6 +128,8 @@ export class LayoutController {
128
128
  const previewIcon = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>';
129
129
  const editorIcon = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="8" y1="8" x2="16" y2="8"/><line x1="8" y1="12" x2="14" y2="12"/><line x1="8" y1="16" x2="12" y2="16"/></svg>';
130
130
 
131
+ // Icons and labels are fixed application-owned markup.
132
+ // pi-lens-ignore: no-inner-html-js
131
133
  this.mobileToggleButton.innerHTML = `${label === 'Editor' ? editorIcon : previewIcon}<span class="ui-toolbar-button-label">${label}</span>`;
132
134
  }
133
135
 
@@ -1,5 +1,4 @@
1
- import { stripVaultFileExtension } from '../../domain/file-kind.js';
2
- import { escapeHtml } from '../domain/vault-utils.js';
1
+ import { createFileSearchEntry, findFileSearchMatch } from '../domain/file-search.js';
3
2
  import { getVaultFileIconSvg } from './file-icon-svg.js';
4
3
  import {
5
4
  DEFAULT_SEARCH_DEBOUNCE_MS,
@@ -17,117 +16,15 @@ function getRawFileName(filePath) {
17
16
  return String(filePath ?? '').split('/').pop() || String(filePath ?? '');
18
17
  }
19
18
 
20
- function createCorpusEntry(filePath) {
21
- const displayName = stripVaultFileExtension(filePath);
22
- const fileName = displayName.split('/').pop() || displayName;
23
- const rawFileName = getRawFileName(filePath);
24
-
25
- return {
26
- displayName,
27
- fileName,
28
- filePath,
29
- lowerDisplayName: displayName.toLowerCase(),
30
- lowerFileName: fileName.toLowerCase(),
31
- lowerPath: String(filePath).toLowerCase(),
32
- lowerRawFileName: rawFileName.toLowerCase(),
33
- };
34
- }
35
-
36
19
  function getFileName(filePath) {
37
- const displayName = stripVaultFileExtension(filePath);
38
- return displayName.split('/').pop() || displayName;
20
+ return createFileSearchEntry(filePath).fileName;
39
21
  }
40
22
 
41
23
  function getDirPath(filePath) {
42
- const displayName = stripVaultFileExtension(filePath);
24
+ const displayName = createFileSearchEntry(filePath).displayName;
43
25
  return displayName.includes('/') ? displayName.substring(0, displayName.lastIndexOf('/')) : '';
44
26
  }
45
27
 
46
- function createRangeIndices(start, length) {
47
- return Array.from({ length }, (_, index) => start + index);
48
- }
49
-
50
- function findFuzzyMatch(text, query) {
51
- const indices = [];
52
- let queryIndex = 0;
53
- let score = 0;
54
- let consecutiveBonus = 0;
55
-
56
- for (let index = 0; index < text.length && queryIndex < query.length; index += 1) {
57
- if (/\s/u.test(query[queryIndex]) && /[\s/\\_-]/u.test(text[index])) {
58
- queryIndex += 1;
59
- consecutiveBonus = 0;
60
- continue;
61
- }
62
-
63
- if (text[index] !== query[queryIndex]) {
64
- if (queryIndex > 0) {
65
- score -= 0.25;
66
- }
67
- consecutiveBonus = 0;
68
- continue;
69
- }
70
-
71
- queryIndex += 1;
72
- indices.push(index);
73
- consecutiveBonus += 1;
74
- score += consecutiveBonus;
75
-
76
- if (
77
- index === 0
78
- || text[index - 1] === '/'
79
- || text[index - 1] === '-'
80
- || text[index - 1] === '_'
81
- || text[index - 1] === ' '
82
- ) {
83
- score += 5;
84
- }
85
- }
86
-
87
- return queryIndex === query.length && score > 0
88
- ? { indices, score }
89
- : null;
90
- }
91
-
92
- function findCorpusMatch(entry, query) {
93
- const fileIndex = entry.lowerFileName.indexOf(query);
94
- if (fileIndex >= 0) {
95
- return {
96
- indices: createRangeIndices(fileIndex + (entry.displayName.length - entry.fileName.length), query.length),
97
- score: 100 + (1 / entry.fileName.length),
98
- };
99
- }
100
-
101
- const pathIndex = entry.lowerDisplayName.indexOf(query);
102
- if (pathIndex >= 0) {
103
- return {
104
- indices: createRangeIndices(pathIndex, query.length),
105
- score: 50 + (1 / entry.displayName.length),
106
- };
107
- }
108
-
109
- const rawFileIndex = entry.lowerRawFileName.indexOf(query);
110
- if (rawFileIndex >= 0) {
111
- return {
112
- indices: createRangeIndices(
113
- rawFileIndex + (entry.displayName.length - entry.fileName.length),
114
- query.length,
115
- ),
116
- score: 40 + (1 / entry.lowerRawFileName.length),
117
- };
118
- }
119
-
120
- const rawPathIndex = entry.lowerPath.indexOf(query);
121
- if (rawPathIndex >= 0) {
122
- return {
123
- indices: createRangeIndices(rawPathIndex, query.length),
124
- score: 25 + (1 / entry.lowerPath.length),
125
- };
126
- }
127
-
128
- return findFuzzyMatch(entry.lowerDisplayName, query);
129
- }
130
-
131
28
  function splitMatchIndices(entry, indices = []) {
132
29
  const fileNameStart = entry.displayName.length - entry.fileName.length;
133
30
  return {
@@ -138,42 +35,25 @@ function splitMatchIndices(entry, indices = []) {
138
35
  };
139
36
  }
140
37
 
141
- function highlightText(text, indices = []) {
142
- if (indices.length === 0) {
143
- return escapeHtml(text);
144
- }
145
-
38
+ function appendHighlightedText(element, text, indices = []) {
146
39
  const matchedIndices = new Set(indices);
147
- let result = '';
148
- let runStart = null;
149
40
  let cursor = 0;
150
41
 
151
- const appendRun = (runEnd) => {
152
- result += escapeHtml(text.slice(cursor, runStart));
153
- result += `<mark>${escapeHtml(text.slice(runStart, runEnd + 1))}</mark>`;
154
- cursor = runEnd + 1;
155
- runStart = null;
156
- };
42
+ while (cursor < text.length) {
43
+ const matched = matchedIndices.has(cursor);
44
+ let end = cursor + 1;
45
+ while (end < text.length && matchedIndices.has(end) === matched) end += 1;
157
46
 
158
- for (let index = 0; index < text.length; index += 1) {
159
- if (!matchedIndices.has(index)) {
160
- if (runStart !== null) {
161
- appendRun(index - 1);
162
- }
163
- continue;
164
- }
165
-
166
- if (runStart === null) {
167
- runStart = index;
47
+ const value = text.slice(cursor, end);
48
+ if (matched) {
49
+ const mark = document.createElement('mark');
50
+ mark.textContent = value;
51
+ element.append(mark);
52
+ } else {
53
+ element.append(value);
168
54
  }
55
+ cursor = end;
169
56
  }
170
-
171
- if (runStart !== null) {
172
- appendRun(text.length - 1);
173
- }
174
-
175
- result += escapeHtml(text.slice(cursor));
176
- return result;
177
57
  }
178
58
 
179
59
  export class QuickSwitcherController {
@@ -218,28 +98,20 @@ export class QuickSwitcherController {
218
98
  this.selectedIndex = 0;
219
99
  this.selectedTextIndex = 0;
220
100
  this.isOpen = false;
221
- this.previousActiveElement = null;
222
101
  this.mode = 'files';
223
102
  this.textResults = null;
224
103
  this.textResultItems = [];
225
104
  this.textSearchRunner = new QuickSwitcherTextSearchRunner({
226
105
  debounceMs: this.searchDebounceMs,
227
106
  });
107
+ this.blockingModalHandler = () => this.close();
228
108
 
229
109
  this.bindEvents();
230
110
  }
231
111
 
232
112
  bindEvents() {
233
- this.overlay?.addEventListener('mousedown', (e) => {
234
- if (e.target === this.overlay) this.close();
235
- });
236
-
237
- this.overlay?.addEventListener('keydown', (e) => {
238
- if (e.key === 'Escape') {
239
- e.preventDefault();
240
- this.close();
241
- }
242
- });
113
+ document.addEventListener?.('collabmd:close-custom-modals', this.blockingModalHandler);
114
+ this.overlay?.addEventListener('close', () => this.handleClose());
243
115
 
244
116
  this.modeTabs.forEach((tab, index) => {
245
117
  tab.addEventListener('click', () => {
@@ -293,86 +165,36 @@ export class QuickSwitcherController {
293
165
  });
294
166
  }
295
167
 
168
+ handleClose() {
169
+ this.abortTextSearch();
170
+ this.isOpen = false;
171
+ this.input?.setAttribute('aria-expanded', 'false');
172
+ this.input.value = '';
173
+ this.resultsList.innerHTML = '';
174
+ this.setActiveDescendant('');
175
+ }
176
+
296
177
  open() {
297
- if (!this.overlay) return;
178
+ if (!this.overlay || this.overlay.open) return;
298
179
 
299
- this.previousActiveElement = document.activeElement;
300
180
  this.isOpen = true;
301
181
  this.input.value = '';
302
182
  this.selectedIndex = 0;
303
183
  this.selectedTextIndex = 0;
304
- this.overlay.classList.add('visible');
305
- this.overlay.setAttribute('aria-hidden', 'false');
306
- this.input?.setAttribute('aria-expanded', 'true');
307
184
  this.setMode('files', { preserveInput: true });
308
-
309
- // The overlay transitions visibility hidden→visible over 120ms.
310
- // Browsers ignore .focus() while the element is still visibility:hidden,
311
- // so we must wait for the transition to complete.
312
- this._focusAfterTransition();
313
- }
314
-
315
- /** Focus the input once the overlay visibility transition finishes. */
316
- _focusAfterTransition() {
317
- this._cancelPendingFocus();
318
-
319
- const tryFocus = () => {
320
- this._focusCleanup = null;
321
- this.input?.focus();
322
- if (this.isOpen && this.input && document.activeElement !== this.input) {
323
- setTimeout(() => this.input?.focus(), 50);
324
- }
325
- };
326
-
327
- const onEnd = (e) => {
328
- if (e.propertyName === 'visibility' || e.propertyName === 'opacity') {
329
- this.overlay.removeEventListener('transitionend', onEnd);
330
- clearTimeout(fallbackTimer);
331
- tryFocus();
332
- }
333
- };
334
- this.overlay.addEventListener('transitionend', onEnd);
335
-
336
- const fallbackTimer = setTimeout(() => {
337
- this.overlay.removeEventListener('transitionend', onEnd);
338
- tryFocus();
339
- }, 160);
340
-
341
- this._focusCleanup = () => {
342
- this.overlay.removeEventListener('transitionend', onEnd);
343
- clearTimeout(fallbackTimer);
344
- };
185
+ this.overlay.showModal();
186
+ this.input?.setAttribute('aria-expanded', 'true');
345
187
  }
346
188
 
347
- _cancelPendingFocus() {
348
- if (this._focusCleanup) {
349
- this._focusCleanup();
350
- this._focusCleanup = null;
351
- }
352
- }
353
-
354
- close({ restoreFocus = true } = {}) {
355
- if (!this.overlay) return;
356
-
357
- const previousActiveElement = this.previousActiveElement;
358
- this._cancelPendingFocus();
359
- this.abortTextSearch();
360
- this.isOpen = false;
361
- this.overlay.classList.remove('visible');
362
- this.overlay.setAttribute('aria-hidden', 'true');
363
- this.input?.setAttribute('aria-expanded', 'false');
364
- this.input.value = '';
365
- this.resultsList.innerHTML = '';
366
- this.setActiveDescendant('');
367
- this.previousActiveElement = null;
368
-
369
- if (restoreFocus) {
370
- previousActiveElement?.focus?.();
189
+ close() {
190
+ this.handleClose();
191
+ if (this.overlay?.open) {
192
+ this.overlay.close();
371
193
  }
372
194
  }
373
195
 
374
196
  toggle() {
375
- if (this.isOpen) {
197
+ if (this.overlay?.open) {
376
198
  this.close();
377
199
  } else {
378
200
  this.open();
@@ -429,7 +251,7 @@ export class QuickSwitcherController {
429
251
  const allFiles = this.getFileList?.() ?? [];
430
252
  if (allFiles !== this.lastFileListRef) {
431
253
  this.lastFileListRef = allFiles;
432
- this.fileCorpus = allFiles.map((filePath) => createCorpusEntry(filePath));
254
+ this.fileCorpus = allFiles.map((filePath) => createFileSearchEntry(filePath));
433
255
  }
434
256
 
435
257
  this.fileMatches.clear();
@@ -462,7 +284,7 @@ export class QuickSwitcherController {
462
284
  const ranked = [];
463
285
  let fileMatchCount = 0;
464
286
  this.fileCorpus.forEach((entry) => {
465
- const match = findCorpusMatch(entry, query);
287
+ const match = findFileSearchMatch(entry, query);
466
288
  if (!match) {
467
289
  return;
468
290
  }
@@ -556,11 +378,20 @@ export class QuickSwitcherController {
556
378
  const corpusEntry = this.fileCorpus.find((entry) => entry.filePath === filePath);
557
379
  const matchIndices = corpusEntry ? splitMatchIndices(corpusEntry, match?.indices) : { dirPath: [], fileName: [] };
558
380
 
559
- item.innerHTML = `
560
- ${getVaultFileIconSvg(filePath, { className: 'qs-result-icon' })}
561
- <span class="qs-result-name">${highlightText(fileName, matchIndices.fileName)}</span>
562
- ${dirPath ? `<span class="qs-result-path" title="${escapeHtml(dirPath)}">${highlightText(dirPath, matchIndices.dirPath)}</span>` : ''}
563
- `;
381
+ const svg = getVaultFileIconSvg(filePath, { className: 'qs-result-icon' });
382
+ item.append(document.createRange().createContextualFragment(svg));
383
+ const name = document.createElement('span');
384
+ name.className = 'qs-result-name';
385
+ appendHighlightedText(name, fileName, matchIndices.fileName);
386
+ item.append(name);
387
+
388
+ if (dirPath) {
389
+ const path = document.createElement('span');
390
+ path.className = 'qs-result-path';
391
+ path.title = dirPath;
392
+ appendHighlightedText(path, dirPath, matchIndices.dirPath);
393
+ item.append(path);
394
+ }
564
395
 
565
396
  item.addEventListener('click', () => {
566
397
  this.selectedIndex = index;
@@ -645,11 +476,16 @@ export class QuickSwitcherController {
645
476
 
646
477
  const header = document.createElement('div');
647
478
  header.className = 'qs-text-group-header';
648
- header.innerHTML = `
649
- <span class="qs-text-file-name">${escapeHtml(getFileName(fileGroup.file))}</span>
650
- <span class="qs-text-file-meta">${escapeHtml(getDirPath(fileGroup.file))}</span>
651
- <span class="qs-text-count">${escapeHtml(formatMatchCount(fileGroup.matchCount, { truncated: fileGroup.truncated }))}</span>
652
- `;
479
+ [
480
+ ['qs-text-file-name', getFileName(fileGroup.file)],
481
+ ['qs-text-file-meta', getDirPath(fileGroup.file)],
482
+ ['qs-text-count', formatMatchCount(fileGroup.matchCount, { truncated: fileGroup.truncated })],
483
+ ].forEach(([className, text]) => {
484
+ const span = document.createElement('span');
485
+ span.className = className;
486
+ span.textContent = text;
487
+ header.append(span);
488
+ });
653
489
  group.appendChild(header);
654
490
 
655
491
  (fileGroup.snippets ?? []).forEach((snippet) => {
@@ -664,10 +500,13 @@ export class QuickSwitcherController {
664
500
  item.setAttribute('role', 'option');
665
501
  item.setAttribute('aria-selected', itemIndex === this.selectedTextIndex ? 'true' : 'false');
666
502
  item.dataset.textIndex = String(itemIndex);
667
- item.innerHTML = `
668
- <span class="qs-text-line">L${escapeHtml(String(snippet.line ?? 1))}</span>
669
- <span class="qs-text-snippet">${this.highlightSnippet(snippet)}</span>
670
- `;
503
+ const line = document.createElement('span');
504
+ line.className = 'qs-text-line';
505
+ line.textContent = `L${snippet.line ?? 1}`;
506
+ const snippetText = document.createElement('span');
507
+ snippetText.className = 'qs-text-snippet';
508
+ this.appendHighlightedSnippet(snippetText, snippet);
509
+ item.append(line, snippetText);
671
510
  item.addEventListener('click', () => {
672
511
  this.selectedTextIndex = itemIndex;
673
512
  this.confirmSelection();
@@ -687,11 +526,14 @@ export class QuickSwitcherController {
687
526
  this.updateSelection();
688
527
  }
689
528
 
690
- highlightSnippet(snippet = {}) {
529
+ appendHighlightedSnippet(element, snippet = {}) {
691
530
  const text = String(snippet.text ?? '');
692
531
  const start = Math.min(Math.max(Number(snippet.matchStart) || 0, 0), text.length);
693
532
  const end = Math.min(Math.max(Number(snippet.matchEnd) || start, start), text.length);
694
- return `${escapeHtml(text.slice(0, start))}<mark>${escapeHtml(text.slice(start, end))}</mark>${escapeHtml(text.slice(end))}`;
533
+ element.append(text.slice(0, start));
534
+ const mark = document.createElement('mark');
535
+ mark.textContent = text.slice(start, end);
536
+ element.append(mark, text.slice(end));
695
537
  }
696
538
 
697
539
  moveSelection(delta) {
@@ -7,20 +7,16 @@ export function formatMatchCount(count = 0, { truncated = false } = {}) {
7
7
  }
8
8
 
9
9
  export function flattenTextResults(payload = {}) {
10
- const flattened = [];
11
- (payload.files ?? []).forEach((fileGroup) => {
12
- (fileGroup.snippets ?? []).forEach((snippet) => {
13
- flattened.push({
14
- column: snippet.column,
15
- file: fileGroup.file,
16
- kind: fileGroup.kind,
17
- line: snippet.line,
18
- matchLength: Math.max((snippet.matchEnd ?? 0) - (snippet.matchStart ?? 0), 0),
19
- snippet,
20
- });
21
- });
22
- });
23
- return flattened;
10
+ return (payload.files ?? []).flatMap((fileGroup) => (
11
+ (fileGroup.snippets ?? []).map((snippet) => ({
12
+ column: snippet.column,
13
+ file: fileGroup.file,
14
+ kind: fileGroup.kind,
15
+ line: snippet.line,
16
+ matchLength: Math.max((snippet.matchEnd ?? 0) - (snippet.matchStart ?? 0), 0),
17
+ snippet,
18
+ }))
19
+ ));
24
20
  }
25
21
 
26
22
  export class QuickSwitcherTextSearchRunner {
@@ -1,7 +1,6 @@
1
1
  /* ===== COMPONENTS / NAVIGATION ===== */
2
2
 
3
- .ui-button--toolbar,
4
- .ui-toolbar-button {
3
+ .ui-button--toolbar {
5
4
  display: flex;
6
5
  align-items: center;
7
6
  gap: var(--space-1);
@@ -2,6 +2,8 @@
2
2
 
3
3
  .preview-container,
4
4
  .cm-scroller,
5
+ .cm-tooltip-autocomplete > ul,
6
+ .presence-panel-list,
5
7
  .file-tree,
6
8
  .git-panel,
7
9
  .diff-scroll,
@@ -25,6 +27,8 @@
25
27
 
26
28
  .preview-container::-webkit-scrollbar,
27
29
  .cm-scroller::-webkit-scrollbar,
30
+ .cm-tooltip-autocomplete > ul::-webkit-scrollbar,
31
+ .presence-panel-list::-webkit-scrollbar,
28
32
  .file-tree::-webkit-scrollbar,
29
33
  .git-panel::-webkit-scrollbar,
30
34
  .diff-scroll::-webkit-scrollbar,
@@ -48,6 +52,8 @@
48
52
 
49
53
  .preview-container::-webkit-scrollbar-track,
50
54
  .cm-scroller::-webkit-scrollbar-track,
55
+ .cm-tooltip-autocomplete > ul::-webkit-scrollbar-track,
56
+ .presence-panel-list::-webkit-scrollbar-track,
51
57
  .file-tree::-webkit-scrollbar-track,
52
58
  .git-panel::-webkit-scrollbar-track,
53
59
  .diff-scroll::-webkit-scrollbar-track,
@@ -70,6 +76,8 @@
70
76
 
71
77
  .preview-container::-webkit-scrollbar-thumb,
72
78
  .cm-scroller::-webkit-scrollbar-thumb,
79
+ .cm-tooltip-autocomplete > ul::-webkit-scrollbar-thumb,
80
+ .presence-panel-list::-webkit-scrollbar-thumb,
73
81
  .file-tree::-webkit-scrollbar-thumb,
74
82
  .git-panel::-webkit-scrollbar-thumb,
75
83
  .diff-scroll::-webkit-scrollbar-thumb,
@@ -93,6 +101,8 @@
93
101
 
94
102
  .preview-container::-webkit-scrollbar-thumb:hover,
95
103
  .cm-scroller::-webkit-scrollbar-thumb:hover,
104
+ .cm-tooltip-autocomplete > ul::-webkit-scrollbar-thumb:hover,
105
+ .presence-panel-list::-webkit-scrollbar-thumb:hover,
96
106
  .file-tree::-webkit-scrollbar-thumb:hover,
97
107
  .git-panel::-webkit-scrollbar-thumb:hover,
98
108
  .diff-scroll::-webkit-scrollbar-thumb:hover,