@formicoidea/labre-core 0.32.0 → 0.34.1

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 (308) hide show
  1. package/dist/_pkgs/affine-block-attachment/attachment-block.js +3 -3
  2. package/dist/_pkgs/affine-block-attachment/configs/toolbar.d.ts +2 -2
  3. package/dist/_pkgs/affine-block-attachment/configs/toolbar.js +9 -7
  4. package/dist/_pkgs/affine-block-bookmark/configs/toolbar.js +12 -12
  5. package/dist/_pkgs/affine-block-callout/callout-block.js +1 -1
  6. package/dist/_pkgs/affine-block-code/code-block-inline.js +1 -1
  7. package/dist/_pkgs/affine-block-code/code-block.js +2 -2
  8. package/dist/_pkgs/affine-block-code/code-toolbar/config.js +9 -1
  9. package/dist/_pkgs/affine-block-code/code-toolbar/index.js +1 -1
  10. package/dist/_pkgs/affine-block-database/data-source.js +1 -2
  11. package/dist/_pkgs/affine-block-database/database-block.js +2 -2
  12. package/dist/_pkgs/affine-block-database/external-data-source.js +1 -1
  13. package/dist/_pkgs/affine-block-edgeless-text/edgeless-text-block.js +1 -1
  14. package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/config.js +1 -1
  15. package/dist/_pkgs/affine-block-embed/common/render-linked-doc.js +3 -3
  16. package/dist/_pkgs/affine-block-embed/configs/toolbar.js +11 -11
  17. package/dist/_pkgs/affine-block-embed/embed-figma-block/embed-figma-service.js +1 -1
  18. package/dist/_pkgs/affine-block-embed/embed-html-block/configs/toolbar.js +5 -5
  19. package/dist/_pkgs/affine-block-embed/embed-iframe-block/configs/toolbar.d.ts +7 -7
  20. package/dist/_pkgs/affine-block-embed/embed-iframe-block/configs/toolbar.js +14 -14
  21. package/dist/_pkgs/affine-block-embed/embed-iframe-block/embed-iframe-block.js +2 -2
  22. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/configs/toolbar.js +10 -10
  23. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/embed-linked-doc-block.js +4 -4
  24. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/utils.js +1 -1
  25. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/components/embed-synced-doc-card.js +5 -4
  26. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/configs/toolbar.js +10 -10
  27. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/embed-synced-doc-block.js +1 -1
  28. package/dist/_pkgs/affine-block-frame/frame-manager.js +3 -1
  29. package/dist/_pkgs/affine-block-frame/frame-tool.js +1 -1
  30. package/dist/_pkgs/affine-block-frame/frame-toolbar.js +2 -2
  31. package/dist/_pkgs/affine-block-image/components/page-image-block.js +1 -1
  32. package/dist/_pkgs/affine-block-image/configs/toolbar.js +4 -4
  33. package/dist/_pkgs/affine-block-image/image-edgeless-block.js +1 -1
  34. package/dist/_pkgs/affine-block-list/utils/forward-delete.js +1 -1
  35. package/dist/_pkgs/affine-block-note/commands/select-block.js +1 -1
  36. package/dist/_pkgs/affine-block-note/commands/select-blocks-between.js +1 -1
  37. package/dist/_pkgs/affine-block-note/configs/toolbar.js +2 -2
  38. package/dist/_pkgs/affine-block-note/move-block.js +1 -1
  39. package/dist/_pkgs/affine-block-paragraph/utils/forward-delete.js +2 -2
  40. package/dist/_pkgs/affine-block-paragraph/utils/merge-with-prev.js +1 -1
  41. package/dist/_pkgs/affine-block-root/configs/toolbar.d.ts +6 -4
  42. package/dist/_pkgs/affine-block-root/configs/toolbar.js +6 -6
  43. package/dist/_pkgs/affine-block-root/edgeless/configs/toolbar/misc.d.ts +10 -10
  44. package/dist/_pkgs/affine-block-root/edgeless/configs/toolbar/misc.js +4 -4
  45. package/dist/_pkgs/affine-block-root/edgeless/configs/toolbar/more.d.ts +7 -7
  46. package/dist/_pkgs/affine-block-root/edgeless/configs/toolbar/more.js +9 -9
  47. package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.js +1 -1
  48. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.js +3 -1
  49. package/dist/_pkgs/affine-block-root/edgeless/utils/clipboard-utils.js +1 -1
  50. package/dist/_pkgs/affine-block-surface/adapters/markdown/element-adapter/type.js +1 -1
  51. package/dist/_pkgs/affine-block-surface/adapters/plain-text/element-adapter/type.js +1 -1
  52. package/dist/_pkgs/affine-block-surface/element-model/index.d.ts +18 -3
  53. package/dist/_pkgs/affine-block-surface/element-model/index.js +12 -2
  54. package/dist/_pkgs/affine-block-surface/extensions/audit.js +23 -6
  55. package/dist/_pkgs/affine-block-surface/extensions/crud-extension.js +10 -5
  56. package/dist/_pkgs/affine-block-surface/extensions/editor-anchored-panel.js +2 -1
  57. package/dist/_pkgs/affine-block-surface/extensions/element-renderer.js +1 -1
  58. package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +1 -1
  59. package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +4 -0
  60. package/dist/_pkgs/affine-block-surface/extensions/index.js +4 -0
  61. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.d.ts +172 -0
  62. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.js +404 -0
  63. package/dist/_pkgs/affine-block-surface/extensions/interchange.d.ts +323 -0
  64. package/dist/_pkgs/affine-block-surface/extensions/interchange.js +64 -0
  65. package/dist/_pkgs/affine-block-surface/extensions/map-quality-widget.js +61 -61
  66. package/dist/_pkgs/affine-block-surface/extensions/morph-toolbar.d.ts +248 -0
  67. package/dist/_pkgs/affine-block-surface/extensions/morph-toolbar.js +248 -0
  68. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.js +78 -80
  69. package/dist/_pkgs/affine-block-surface/extensions/reading.js +2 -2
  70. package/dist/_pkgs/affine-block-surface/extensions/spotlight.d.ts +21 -0
  71. package/dist/_pkgs/affine-block-surface/extensions/spotlight.js +17 -3
  72. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.d.ts +107 -0
  73. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.js +958 -0
  74. package/dist/_pkgs/affine-block-surface/extensions/validation.d.ts +809 -20
  75. package/dist/_pkgs/affine-block-surface/extensions/validation.js +1661 -50
  76. package/dist/_pkgs/affine-block-surface/extensions/violation-detail-widget.d.ts +50 -6
  77. package/dist/_pkgs/affine-block-surface/extensions/violation-detail-widget.js +129 -32
  78. package/dist/_pkgs/affine-block-surface/framework-background/def.d.ts +289 -0
  79. package/dist/_pkgs/affine-block-surface/framework-background/def.js +126 -1
  80. package/dist/_pkgs/affine-block-surface/framework-background/labels.d.ts +42 -2
  81. package/dist/_pkgs/affine-block-surface/framework-background/labels.js +80 -4
  82. package/dist/_pkgs/affine-block-surface/framework-background/renderer.js +172 -11
  83. package/dist/_pkgs/affine-block-surface/index.d.ts +1 -0
  84. package/dist/_pkgs/affine-block-surface/index.js +1 -0
  85. package/dist/_pkgs/affine-block-surface/renderer/element-highlight-overlay.d.ts +17 -0
  86. package/dist/_pkgs/affine-block-surface/renderer/element-highlight-overlay.js +66 -0
  87. package/dist/_pkgs/affine-block-surface/renderer/overlay.js +1 -1
  88. package/dist/_pkgs/affine-block-surface/view.js +5 -0
  89. package/dist/_pkgs/affine-block-surface-ref/configs/toolbar.js +4 -4
  90. package/dist/_pkgs/affine-block-surface-ref/portal/note.js +2 -2
  91. package/dist/_pkgs/affine-block-table/commands.js +1 -1
  92. package/dist/_pkgs/affine-components/edgeless-shape-color-picker/color-picker.js +1 -1
  93. package/dist/_pkgs/affine-components/embed-card-modal/embed-card-edit-modal.js +1 -1
  94. package/dist/_pkgs/affine-components/filterable-list/styles.js +1 -1
  95. package/dist/_pkgs/affine-components/highlight-dropdown-menu/highlight-duotone-icon.js +8 -8
  96. package/dist/_pkgs/affine-components/highlight-dropdown-menu/text-duotone-icon.js +11 -11
  97. package/dist/_pkgs/affine-components/icons/text.js +426 -426
  98. package/dist/_pkgs/affine-components/open-doc-dropdown-menu/dropdown-menu.d.ts +2 -0
  99. package/dist/_pkgs/affine-components/peek/peekable.js +1 -1
  100. package/dist/_pkgs/affine-components/resource/resource.js +2 -0
  101. package/dist/_pkgs/affine-components/toolbar/index.d.ts +1 -0
  102. package/dist/_pkgs/affine-components/toolbar/index.js +1 -0
  103. package/dist/_pkgs/affine-components/toolbar/menu-button.js +1 -1
  104. package/dist/_pkgs/affine-components/toolbar/picker-menu.d.ts +55 -0
  105. package/dist/_pkgs/affine-components/toolbar/picker-menu.js +47 -0
  106. package/dist/_pkgs/affine-components/view-dropdown-menu/dropdown-menu.js +27 -14
  107. package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.js +2 -2
  108. package/dist/_pkgs/affine-fragment-frame-panel/header/frame-panel-header.js +2 -2
  109. package/dist/_pkgs/affine-fragment-frame-panel/header/frames-setting-menu.js +1 -1
  110. package/dist/_pkgs/affine-fragment-outline/mobile-outline-panel.js +1 -1
  111. package/dist/_pkgs/affine-gfx-brush/toolbar/components/pen/pen-tool-button.js +1 -1
  112. package/dist/_pkgs/affine-gfx-connector/connector-manager.js +7 -10
  113. package/dist/_pkgs/affine-gfx-connector/connector-tool.d.ts +19 -1
  114. package/dist/_pkgs/affine-gfx-connector/connector-tool.js +10 -2
  115. package/dist/_pkgs/affine-gfx-connector/connector-watcher.js +1 -4
  116. package/dist/_pkgs/affine-gfx-connector/direction/direction-reveal.js +2 -1
  117. package/dist/_pkgs/affine-gfx-connector/direction/invert-direction.js +1 -3
  118. package/dist/_pkgs/affine-gfx-connector/element-renderer/index.js +1 -1
  119. package/dist/_pkgs/affine-gfx-connector/element-renderer/utils.js +1 -1
  120. package/dist/_pkgs/affine-gfx-connector/toolbar/config.js +1 -1
  121. package/dist/_pkgs/affine-gfx-mindmap/adapter/markdown/index.js +1 -1
  122. package/dist/_pkgs/affine-gfx-mindmap/adapter/utils.js +1 -1
  123. package/dist/_pkgs/affine-gfx-mindmap/templates/index.js +583 -4
  124. package/dist/_pkgs/affine-gfx-mindmap/toolbar/mindmap-menu.js +23 -23
  125. package/dist/_pkgs/affine-gfx-mindmap/toolbar/mindmap-tool-button.js +5 -1
  126. package/dist/_pkgs/affine-gfx-mindmap/view/utils.js +1 -1
  127. package/dist/_pkgs/affine-gfx-note/overlay/overlay.js +1 -1
  128. package/dist/_pkgs/affine-gfx-note/toolbar/note-senior-button.js +1 -1
  129. package/dist/_pkgs/affine-gfx-shape/consts.js +1 -1
  130. package/dist/_pkgs/affine-gfx-shape/draggable/shape-draggable.js +1 -1
  131. package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/polygon.js +17 -9
  132. package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/utils.js +8 -3
  133. package/dist/_pkgs/affine-gfx-shape/element-view.js +19 -12
  134. package/dist/_pkgs/affine-gfx-shape/overlay/polygon-drawing-overlay.js +1 -1
  135. package/dist/_pkgs/affine-gfx-shape/overlay/polygon-vertex-editing-overlay.js +12 -7
  136. package/dist/_pkgs/affine-gfx-shape/overlay/shape-overlay.js +1 -1
  137. package/dist/_pkgs/affine-gfx-shape/polygon-tool.js +4 -2
  138. package/dist/_pkgs/affine-gfx-shape/shape-tool.js +1 -1
  139. package/dist/_pkgs/affine-gfx-shape/text/edgeless-shape-text-editor.js +1 -3
  140. package/dist/_pkgs/affine-gfx-template/builtin/other.js +66 -17
  141. package/dist/_pkgs/affine-gfx-template/toolbar/overlay-scrollbar.js +1 -1
  142. package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.js +1 -1
  143. package/dist/_pkgs/affine-gfx-text/toolbar/actions.js +1 -1
  144. package/dist/_pkgs/affine-inline-link/command.js +1 -1
  145. package/dist/_pkgs/affine-inline-link/link-node/configs/toolbar.d.ts +4 -4
  146. package/dist/_pkgs/affine-inline-link/link-node/configs/toolbar.js +6 -6
  147. package/dist/_pkgs/affine-inline-preset/command/format-block.js +1 -1
  148. package/dist/_pkgs/affine-inline-preset/command/format-native.js +2 -2
  149. package/dist/_pkgs/affine-inline-preset/command/format-text.js +1 -1
  150. package/dist/_pkgs/affine-inline-preset/inline-spec.js +1 -1
  151. package/dist/_pkgs/affine-inline-reference/reference-node/configs/toolbar.d.ts +4 -4
  152. package/dist/_pkgs/affine-inline-reference/reference-node/configs/toolbar.js +6 -6
  153. package/dist/_pkgs/affine-inline-reference/reference-node/reference-node.js +1 -1
  154. package/dist/_pkgs/affine-model/elements/bpmn/node.d.ts +40 -7
  155. package/dist/_pkgs/affine-model/elements/bpmn/node.js +4 -2
  156. package/dist/_pkgs/affine-model/elements/bpmn/pool.d.ts +135 -17
  157. package/dist/_pkgs/affine-model/elements/bpmn/pool.js +148 -26
  158. package/dist/_pkgs/affine-model/elements/c4/board.d.ts +88 -0
  159. package/dist/_pkgs/affine-model/elements/c4/board.js +128 -0
  160. package/dist/_pkgs/affine-model/elements/c4/boundary.d.ts +63 -0
  161. package/dist/_pkgs/affine-model/elements/c4/boundary.js +134 -0
  162. package/dist/_pkgs/affine-model/elements/c4/index.d.ts +3 -0
  163. package/dist/_pkgs/affine-model/elements/c4/index.js +3 -0
  164. package/dist/_pkgs/affine-model/elements/c4/node.d.ts +97 -0
  165. package/dist/_pkgs/affine-model/elements/c4/node.js +130 -0
  166. package/dist/_pkgs/affine-model/elements/connector/connector.js +1 -1
  167. package/dist/_pkgs/affine-model/elements/context-map/context-map.d.ts +27 -0
  168. package/dist/_pkgs/affine-model/elements/context-map/context-map.js +94 -0
  169. package/dist/_pkgs/affine-model/elements/context-map/index.d.ts +1 -0
  170. package/dist/_pkgs/affine-model/elements/context-map/index.js +1 -0
  171. package/dist/_pkgs/affine-model/elements/core-domain/core-domain.d.ts +34 -17
  172. package/dist/_pkgs/affine-model/elements/core-domain/core-domain.js +28 -26
  173. package/dist/_pkgs/affine-model/elements/cynefin/cynefin.d.ts +7 -2
  174. package/dist/_pkgs/affine-model/elements/cynefin/cynefin.js +9 -4
  175. package/dist/_pkgs/affine-model/elements/edgy/board.d.ts +7 -2
  176. package/dist/_pkgs/affine-model/elements/edgy/board.js +9 -4
  177. package/dist/_pkgs/affine-model/elements/edgy/facets.d.ts +20 -3
  178. package/dist/_pkgs/affine-model/elements/edgy/facets.js +13 -4
  179. package/dist/_pkgs/affine-model/elements/estuarine/estuarine.d.ts +7 -2
  180. package/dist/_pkgs/affine-model/elements/estuarine/estuarine.js +9 -4
  181. package/dist/_pkgs/affine-model/elements/event-storming/event-storming.d.ts +36 -0
  182. package/dist/_pkgs/affine-model/elements/event-storming/event-storming.js +103 -0
  183. package/dist/_pkgs/affine-model/elements/event-storming/index.d.ts +1 -0
  184. package/dist/_pkgs/affine-model/elements/event-storming/index.js +1 -0
  185. package/dist/_pkgs/affine-model/elements/framework-background/background.d.ts +7 -2
  186. package/dist/_pkgs/affine-model/elements/framework-background/background.js +9 -4
  187. package/dist/_pkgs/affine-model/elements/framework-background/hit-test.d.ts +48 -0
  188. package/dist/_pkgs/affine-model/elements/framework-background/hit-test.js +55 -0
  189. package/dist/_pkgs/affine-model/elements/framework-background/index.d.ts +1 -0
  190. package/dist/_pkgs/affine-model/elements/framework-background/index.js +1 -0
  191. package/dist/_pkgs/affine-model/elements/index.d.ts +11 -0
  192. package/dist/_pkgs/affine-model/elements/index.js +3 -0
  193. package/dist/_pkgs/affine-model/elements/shape/api/polygon.js +2 -8
  194. package/dist/_pkgs/affine-shared/adapters/html/block-adapter.js +1 -1
  195. package/dist/_pkgs/affine-shared/adapters/markdown/block-adapter.js +1 -1
  196. package/dist/_pkgs/affine-shared/adapters/markdown/delta-converter.js +1 -1
  197. package/dist/_pkgs/affine-shared/adapters/notion-html/block-adapter.js +1 -1
  198. package/dist/_pkgs/affine-shared/adapters/notion-html/delta-converter.js +1 -1
  199. package/dist/_pkgs/affine-shared/adapters/plain-text/block-adapter.js +1 -1
  200. package/dist/_pkgs/affine-shared/adapters/plain-text/delta-converter.js +1 -1
  201. package/dist/_pkgs/affine-shared/adapters/utils/color.js +5 -2
  202. package/dist/_pkgs/affine-shared/commands/model-crud/draft-selected-models.js +1 -1
  203. package/dist/_pkgs/affine-shared/commands/selection/focus-block-end.js +1 -1
  204. package/dist/_pkgs/affine-shared/commands/selection/focus-block-start.js +1 -1
  205. package/dist/_pkgs/affine-shared/consts/index.d.ts +10 -0
  206. package/dist/_pkgs/affine-shared/consts/index.js +10 -0
  207. package/dist/_pkgs/affine-shared/services/artefact-catalogue-service.d.ts +55 -0
  208. package/dist/_pkgs/affine-shared/services/artefact-catalogue-service.js +35 -0
  209. package/dist/_pkgs/affine-shared/services/audit-service.d.ts +11 -0
  210. package/dist/_pkgs/affine-shared/services/command-usage-service.d.ts +31 -0
  211. package/dist/_pkgs/affine-shared/services/command-usage-service.js +109 -0
  212. package/dist/_pkgs/affine-shared/services/comment-service/block-comment-manager.js +1 -1
  213. package/dist/_pkgs/affine-shared/services/doc-display-meta-service.js +1 -1
  214. package/dist/_pkgs/affine-shared/services/edit-props-store.d.ts +11 -0
  215. package/dist/_pkgs/affine-shared/services/edit-props-store.js +15 -0
  216. package/dist/_pkgs/affine-shared/services/embed-iframe/embed-iframe-config.js +1 -1
  217. package/dist/_pkgs/affine-shared/services/index.d.ts +2 -0
  218. package/dist/_pkgs/affine-shared/services/index.js +2 -0
  219. package/dist/_pkgs/affine-shared/services/pivot-materiality-publisher.js +2 -1
  220. package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +73 -1
  221. package/dist/_pkgs/affine-shared/services/toolbar-service/action.d.ts +32 -0
  222. package/dist/_pkgs/affine-shared/services/toolbar-service/action.js +16 -0
  223. package/dist/_pkgs/affine-shared/services/toolbar-service/flags.d.ts +10 -0
  224. package/dist/_pkgs/affine-shared/services/toolbar-service/flags.js +32 -1
  225. package/dist/_pkgs/affine-shared/services/toolbar-service/registry.d.ts +44 -0
  226. package/dist/_pkgs/affine-shared/services/toolbar-service/registry.js +161 -3
  227. package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +106 -0
  228. package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +201 -0
  229. package/dist/_pkgs/affine-shared/services/translation-service/index.d.ts +1 -0
  230. package/dist/_pkgs/affine-shared/services/translation-service/index.js +1 -0
  231. package/dist/_pkgs/affine-shared/services/universe-tag-defs-service.js +5 -3
  232. package/dist/_pkgs/affine-shared/test-utils/affine-template.js +1 -1
  233. package/dist/_pkgs/affine-shared/utils/edgeless.js +1 -1
  234. package/dist/_pkgs/affine-shared/utils/file/filesys.d.ts +34 -0
  235. package/dist/_pkgs/affine-shared/utils/file/filesys.js +48 -7
  236. package/dist/_pkgs/affine-shared/utils/zod-schema.js +1 -3
  237. package/dist/_pkgs/affine-widget-drag-handle/utils.js +1 -1
  238. package/dist/_pkgs/affine-widget-edgeless-auto-connect/index.js +1 -1
  239. package/dist/_pkgs/affine-widget-edgeless-dragging-area/edgeless-dragging-area-rect.js +1 -1
  240. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-default.d.ts +14 -0
  241. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-default.js +40 -0
  242. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.d.ts +158 -0
  243. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.js +572 -0
  244. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/catalogue-groups.d.ts +41 -0
  245. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/catalogue-groups.js +49 -0
  246. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/chord-format.d.ts +13 -0
  247. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/chord-format.js +50 -0
  248. package/dist/_pkgs/affine-widget-edgeless-toolbar/edgeless-toolbar.d.ts +6 -0
  249. package/dist/_pkgs/affine-widget-edgeless-toolbar/edgeless-toolbar.js +15 -5
  250. package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.d.ts +2 -0
  251. package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.js +2 -0
  252. package/dist/_pkgs/affine-widget-edgeless-toolbar/extension/index.d.ts +7 -0
  253. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.d.ts +4 -0
  254. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.js +4 -0
  255. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.d.ts +19 -0
  256. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.js +51 -10
  257. package/dist/_pkgs/affine-widget-edgeless-toolbar/view.js +9 -0
  258. package/dist/_pkgs/affine-widget-keyboard-toolbar/config.js +2 -1
  259. package/dist/_pkgs/affine-widget-keyboard-toolbar/icons.js +98 -98
  260. package/dist/_pkgs/affine-widget-keyboard-toolbar/keyboard-tool-panel.js +1 -1
  261. package/dist/_pkgs/affine-widget-linked-doc/import-doc/import-doc.js +1 -1
  262. package/dist/_pkgs/affine-widget-linked-doc/linked-doc-popover.js +1 -1
  263. package/dist/_pkgs/affine-widget-page-dragging-area/index.js +1 -1
  264. package/dist/_pkgs/affine-widget-remote-selection/doc/doc-remote-selection.js +1 -1
  265. package/dist/_pkgs/affine-widget-slash-menu/config.js +2 -1
  266. package/dist/_pkgs/affine-widget-toolbar/toolbar.js +11 -2
  267. package/dist/_pkgs/affine-widget-toolbar/utils.d.ts +19 -2
  268. package/dist/_pkgs/affine-widget-toolbar/utils.js +28 -9
  269. package/dist/_pkgs/data-view/core/group-by/renderer/boolean-group.js +11 -11
  270. package/dist/_pkgs/data-view/core/utils/menu-title.js +17 -17
  271. package/dist/_pkgs/data-view/view-presets/calendar/pc/actions.js +8 -12
  272. package/dist/_pkgs/data-view/view-presets/calendar/pc/view.js +52 -40
  273. package/dist/_pkgs/data-view/view-presets/table/mobile/group.js +3 -1
  274. package/dist/_pkgs/data-view/view-presets/table/pc/group.js +3 -1
  275. package/dist/_pkgs/data-view/view-presets/table/pc-virtual/group/top/group-title.js +18 -18
  276. package/dist/_pkgs/std/clipboard/utils.js +4 -1
  277. package/dist/_pkgs/std/extension/command-registry.d.ts +195 -5
  278. package/dist/_pkgs/std/extension/command-registry.js +218 -4
  279. package/dist/_pkgs/std/extension/shortcut.js +2 -1
  280. package/dist/_pkgs/std/extension/translation-manifest.d.ts +46 -1
  281. package/dist/_pkgs/std/extension/translation-manifest.js +58 -0
  282. package/dist/_pkgs/std/gfx/grid.js +1 -1
  283. package/dist/_pkgs/std/gfx/highlight.d.ts +84 -0
  284. package/dist/_pkgs/std/gfx/highlight.js +112 -0
  285. package/dist/_pkgs/std/gfx/index.d.ts +2 -1
  286. package/dist/_pkgs/std/gfx/index.js +1 -0
  287. package/dist/_pkgs/std/gfx/interactivity/gfx-view-event-handler.js +17 -3
  288. package/dist/_pkgs/std/gfx/model/surface/element-model.d.ts +160 -0
  289. package/dist/_pkgs/std/gfx/model/surface/element-model.js +75 -1
  290. package/dist/_pkgs/std/gfx/model/surface/role.js +5 -3
  291. package/dist/_pkgs/std/gfx/model/surface/surface-model.js +2 -1
  292. package/dist/_pkgs/std/gfx/selection.js +1 -1
  293. package/dist/_pkgs/std/gfx/viewport.js +1 -1
  294. package/dist/_pkgs/std/inline/extensions/inline-manager.js +1 -1
  295. package/dist/_pkgs/std/inline/extensions/markdown-matcher.js +1 -1
  296. package/dist/_pkgs/std/scope/std-scope.d.ts +2 -1
  297. package/dist/_pkgs/std/scope/std-scope.js +2 -0
  298. package/dist/_pkgs/std/utils/gfx.js +2 -0
  299. package/dist/_pkgs/store/model/store/crud.js +4 -1
  300. package/dist/commands.js +1 -1
  301. package/dist/extensions/command-usage.d.ts +23 -0
  302. package/dist/extensions/command-usage.js +37 -0
  303. package/dist/extensions/view.js +12 -0
  304. package/dist/frameworks.js +32 -0
  305. package/dist/shortcuts.d.ts +20 -6
  306. package/dist/shortcuts.js +7 -9
  307. package/dist/translations.js +98 -3
  308. package/package.json +13 -1
@@ -0,0 +1,172 @@
1
+ import type { ServiceProvider } from '../../global/di/index.js';
2
+ import type { BlockStdScope } from '../../std/index.js';
3
+ import { type InterchangeFormat, type InterchangeImportCapability, type InterchangeReport, type SerializedElementProps } from './interchange.js';
4
+ /**
5
+ * **The public import API** — what an editor, a host application or a plugin
6
+ * calls to turn a foreign file into a board (`docs/adr/0012`).
7
+ *
8
+ * The registry next door declares WHAT Labre can read; a reader is a pure
9
+ * function of text (P3), and it deliberately stops short of the four things
10
+ * only a caller with an editor in its hands can do: pick the file, mint surface
11
+ * ids and repair the references that named the file's, bring the drawing into
12
+ * view, and say what the import cost. Those four were written once, for BPMN,
13
+ * inside `gfx/bpmn/src/actions.ts`. They are here now because not one line of
14
+ * them was about BPMN: an OWM sketch, a mermaid diagram and an SVG all need the
15
+ * same four, and a second copy of them would be a second set of bugs and a
16
+ * second wording of the same report.
17
+ *
18
+ * Three audiences, and they take different doors:
19
+ *
20
+ * - a **framework command** calls {@link runInterchangeImportFile} with its own
21
+ * capability, and that is the whole of its import glue;
22
+ * - a **host** (labreapp) builds its own import surface — a drop zone, a
23
+ * sidepanel, a menu of everything readable — on
24
+ * {@link interchangeImportersByExtension} to decide WHAT can read the file it
25
+ * was handed, and {@link importInterchangeFile} to run it: a drop zone
26
+ * already holds the `File` and must not be answered with a dialog;
27
+ * - **labre-mcp** calls no function here at all. It has no editor, so it calls
28
+ * `capability.run` directly and writes the props itself, which is exactly the
29
+ * purity P3 buys.
30
+ */
31
+ /**
32
+ * Write an imported board onto the surface, and give back the ids it minted.
33
+ *
34
+ * ## The one thing the caller of an importer owes (`docs/adr/0012`, D3)
35
+ *
36
+ * `surface.addElement` mints its own nanoid and ignores any id it is handed —
37
+ * surface identity is Labre's and never the file's — so a connector arrives
38
+ * with `source` / `target` naming the SOURCE FILE's ids. Every element carries
39
+ * its own source id under `interchange[formatId].id`, so the map from file id to
40
+ * surface id is a fold over the very array the reader returned; the second pass
41
+ * rewrites the two endpoints from it. Nothing else is needed, and nothing else
42
+ * is done: an end the map cannot resolve is left exactly as the file wrote it.
43
+ * That keeps the DOCUMENT honest, not the drawing — a connector naming an id no
44
+ * element has routes to an empty path and is invisible on the canvas (it does
45
+ * not crash; `connector-manager.ts` handles the missing connectable) — and an
46
+ * unresolvable name a reader can go and look up in the source file beats one
47
+ * this function quietly invented.
48
+ *
49
+ * The `interchange` payload needs no second pass: it rides in the props as one
50
+ * whole blob and `addElement` writes it with everything else, which is the
51
+ * whole-record LWW the field's own contract asks for (D2).
52
+ *
53
+ * @param formatId the format whose payload key carries the source ids — the
54
+ * `id` of the capability's {@link InterchangeFormat}, and the ONLY thing this
55
+ * function ever knew about BPMN.
56
+ */
57
+ export declare function materializeInterchangeImport(std: BlockStdScope, formatId: string, elements: readonly SerializedElementProps[]): string[];
58
+ /**
59
+ * Say what the import did — the summary, and the remarks.
60
+ *
61
+ * ## v1 of ADR 0012's open question 4 ("where does the report live?")
62
+ *
63
+ * The architect's v1: a NOTIFICATION for the summary, and the full notes on a
64
+ * surface that is reachable and honest. Reachable rules out a toast that names
65
+ * a count and drops the list; honest rules out the two things that look easier
66
+ * — writing the notes into the document as a text annotation (which pollutes a
67
+ * board the user did not ask us to draw on, and which the next export would
68
+ * have to explain) and dropping them (the notes are not derivable by re-running
69
+ * anything: the file is gone the moment the picker closes).
70
+ *
71
+ * So: one notification with the counts and the format version, a second with
72
+ * the remarks when there are few enough to read, and `console.table` with all
73
+ * of them, always, whenever there is one. The console is a poor product
74
+ * surface and it is named as one — the deliberate TARGET is the conformity
75
+ * panel, which is where a reader already goes to ask what is wrong with this
76
+ * board, and where an import remark belongs beside a validation finding. This
77
+ * is a stopgap that tells the truth, not the destination.
78
+ *
79
+ * ## The format is a word in the sentence, not a sentence per format
80
+ *
81
+ * The wordings are one set of keys for every format, and the format's own name
82
+ * is composed into them ({@link formatLabel}). The translation seam has no
83
+ * interpolation and no pluralisation — both are the host's — so a countable
84
+ * noun and a proper noun are the largest units this library can hand over
85
+ * without inventing grammar, which is the same argument the three count labels
86
+ * already ran on. The alternative, a key per format, would ask a host to
87
+ * translate "BPMN file imported" and "SVG file imported" as unrelated
88
+ * sentences and would leave every new format silently untranslated.
89
+ */
90
+ export declare function reportInterchangeImport(std: BlockStdScope, format: InterchangeFormat, report: InterchangeReport): void;
91
+ /**
92
+ * Read a file the user picks with one declared capability, draw it, and say
93
+ * what it cost.
94
+ *
95
+ * Two steps, and neither is re-implemented anywhere: ask for a file, then hand
96
+ * it to {@link importInterchangeFile}, which is the rest of the gesture.
97
+ *
98
+ * ## The picker filter is the FORMAT's, not a table's
99
+ *
100
+ * `{ [mime]: extensions }` straight off the declaration, so a framework that
101
+ * adds a format adds its dialog filter with it and no second file has to agree.
102
+ * A format that declares no mime is offered as `text/plain`, which is what a
103
+ * DSL is — the extensions are the half that matters anyway, and the fallback
104
+ * branch of the picker (`showOpenFilePicker` is absent in Firefox and Safari)
105
+ * puts both halves into `input.accept` precisely because extensions like
106
+ * `.bpmn` are registered with no operating system on earth.
107
+ *
108
+ * The read-only guard is here as well as inside `importInterchangeFile`, and
109
+ * deliberately so: a dialog a document cannot honour should never open in the
110
+ * first place.
111
+ */
112
+ export declare function runInterchangeImportFile(std: BlockStdScope, capability: InterchangeImportCapability): Promise<void>;
113
+ /**
114
+ * The import itself, over a file the caller ALREADY HAS: run the declared
115
+ * capability (`docs/adr/0012`), write what it returned, bring it into view, and
116
+ * say what it cost.
117
+ *
118
+ * ## Why this is separate from the picker
119
+ *
120
+ * Because a picker is one way to be handed a file and not the only one. A host
121
+ * drop zone has the `File` the moment somebody lets go of it; so does a paste,
122
+ * an "open with", and a fetch from a document store. Every one of those wants
123
+ * the four steps below and none of them wants a dialog — and a seam that only
124
+ * exists behind `showOpenFilePicker` forces each of them to re-implement the id
125
+ * remapping and the viewport fit, which is the duplication this whole file was
126
+ * written to end.
127
+ *
128
+ * It is also the honest testing seam. A test that has to intercept a MODULE to
129
+ * reach this code is a test coupled to the bundler; passing the file in is one
130
+ * argument, and it means the pipeline is proven the same way in every
131
+ * environment the library runs in. `capability.run` is the same function
132
+ * labre-mcp calls, so a command, a drop zone and the registry cannot read the
133
+ * same file differently — one door, and the registry is the label on it.
134
+ *
135
+ * ## What arrives is a NEW board, never a merge
136
+ *
137
+ * The elements are added beside whatever is already on the surface. That is the
138
+ * bottom row of a reader's own loss table — surface identity across a
139
+ * re-import is lost — and it is the honest behaviour: two boards the user can
140
+ * see and delete beats a merge that silently rewrote artefacts they had edited.
141
+ *
142
+ * ## Failure is an exception, and it says which one
143
+ *
144
+ * A reader THROWS on a file it cannot read, because the five note kinds cannot
145
+ * say "this is not a file I can read" and a report of three zeroes would claim
146
+ * an empty document where there was none. The sentence it throws names which of
147
+ * its refusals it was, so it is shown as it is rather than replaced with a
148
+ * wording of our own that knows less.
149
+ */
150
+ export declare function importInterchangeFile(std: BlockStdScope, capability: InterchangeImportCapability, file: File): Promise<void>;
151
+ /**
152
+ * Every registered importer, indexed by the extensions it declares.
153
+ *
154
+ * A LIST per extension, and that is the whole design: `.svg` will be claimed by
155
+ * several frameworks at once, because an SVG is a picture and which framework's
156
+ * vocabulary it is a picture OF is not a fact about the filename. ADR 0012 is
157
+ * explicit that a visual import is heuristic recognition and that the surface
158
+ * must name what it is about to do before the file is read — so this answers
159
+ * "what could read this file", and a UI (or a user) chooses. Anything that
160
+ * silently picked one would be guessing on the user's behalf about the one
161
+ * question they are the only one able to answer.
162
+ *
163
+ * Keys keep their leading dot and are lower-cased, because a file called
164
+ * `Order.BPMN` is the same kind of file as `order.bpmn` and nobody should have
165
+ * to know which. Capabilities keep the registry's own order — sorted by
166
+ * capability id — so a menu built from this map reads the same on every boot.
167
+ *
168
+ * Registration is flag-gated tooling (`docs/adr/0009`), so a framework whose
169
+ * flag is off contributes no row here, and a document a past import wrote keeps
170
+ * every byte it was given.
171
+ */
172
+ export declare function interchangeImportersByExtension(provider: ServiceProvider): Map<string, InterchangeImportCapability[]>;
@@ -0,0 +1,404 @@
1
+ import { ConnectorElementModel } from '../../affine-model/index.js';
2
+ import { NotificationProvider, translateKey, } from '../../affine-shared/services/index.js';
3
+ import { openSingleFileWithSpec } from '../../affine-shared/utils/index.js';
4
+ import { getCommonBound } from '../../global/gfx/index.js';
5
+ import { GfxControllerIdentifier } from '../../std/gfx/index.js';
6
+ import { DefaultTool } from '../tool/default-tool.js';
7
+ import { interchangeCapabilities, } from './interchange.js';
8
+ /**
9
+ * **The public import API** — what an editor, a host application or a plugin
10
+ * calls to turn a foreign file into a board (`docs/adr/0012`).
11
+ *
12
+ * The registry next door declares WHAT Labre can read; a reader is a pure
13
+ * function of text (P3), and it deliberately stops short of the four things
14
+ * only a caller with an editor in its hands can do: pick the file, mint surface
15
+ * ids and repair the references that named the file's, bring the drawing into
16
+ * view, and say what the import cost. Those four were written once, for BPMN,
17
+ * inside `gfx/bpmn/src/actions.ts`. They are here now because not one line of
18
+ * them was about BPMN: an OWM sketch, a mermaid diagram and an SVG all need the
19
+ * same four, and a second copy of them would be a second set of bugs and a
20
+ * second wording of the same report.
21
+ *
22
+ * Three audiences, and they take different doors:
23
+ *
24
+ * - a **framework command** calls {@link runInterchangeImportFile} with its own
25
+ * capability, and that is the whole of its import glue;
26
+ * - a **host** (labreapp) builds its own import surface — a drop zone, a
27
+ * sidepanel, a menu of everything readable — on
28
+ * {@link interchangeImportersByExtension} to decide WHAT can read the file it
29
+ * was handed, and {@link importInterchangeFile} to run it: a drop zone
30
+ * already holds the `File` and must not be answered with a dialog;
31
+ * - **labre-mcp** calls no function here at all. It has no editor, so it calls
32
+ * `capability.run` directly and writes the props itself, which is exactly the
33
+ * purity P3 buys.
34
+ */
35
+ /* ── Writing what a reader returned ───────────────────────────────────── */
36
+ /**
37
+ * Write an imported board onto the surface, and give back the ids it minted.
38
+ *
39
+ * ## The one thing the caller of an importer owes (`docs/adr/0012`, D3)
40
+ *
41
+ * `surface.addElement` mints its own nanoid and ignores any id it is handed —
42
+ * surface identity is Labre's and never the file's — so a connector arrives
43
+ * with `source` / `target` naming the SOURCE FILE's ids. Every element carries
44
+ * its own source id under `interchange[formatId].id`, so the map from file id to
45
+ * surface id is a fold over the very array the reader returned; the second pass
46
+ * rewrites the two endpoints from it. Nothing else is needed, and nothing else
47
+ * is done: an end the map cannot resolve is left exactly as the file wrote it.
48
+ * That keeps the DOCUMENT honest, not the drawing — a connector naming an id no
49
+ * element has routes to an empty path and is invisible on the canvas (it does
50
+ * not crash; `connector-manager.ts` handles the missing connectable) — and an
51
+ * unresolvable name a reader can go and look up in the source file beats one
52
+ * this function quietly invented.
53
+ *
54
+ * The `interchange` payload needs no second pass: it rides in the props as one
55
+ * whole blob and `addElement` writes it with everything else, which is the
56
+ * whole-record LWW the field's own contract asks for (D2).
57
+ *
58
+ * @param formatId the format whose payload key carries the source ids — the
59
+ * `id` of the capability's {@link InterchangeFormat}, and the ONLY thing this
60
+ * function ever knew about BPMN.
61
+ */
62
+ export function materializeInterchangeImport(std, formatId, elements) {
63
+ const surface = std.get(GfxControllerIdentifier).surface;
64
+ if (!surface)
65
+ return [];
66
+ const bySource = new Map();
67
+ const created = elements.map(props => {
68
+ const id = surface.addElement({ ...props });
69
+ const carried = props.interchange;
70
+ const source = carried?.[formatId]?.id;
71
+ // FIRST wins, matching a reader's own answer to a file that used one id
72
+ // twice: it imports both and says so in a `substituted-id` note, and a flow
73
+ // naming that id means the first of them.
74
+ if (source !== undefined && !bySource.has(source))
75
+ bySource.set(source, id);
76
+ return id;
77
+ });
78
+ for (const id of created) {
79
+ const model = surface.getElementById(id);
80
+ if (!(model instanceof ConnectorElementModel))
81
+ continue;
82
+ for (const side of ['source', 'target']) {
83
+ const end = model[side];
84
+ if (end?.id === undefined)
85
+ continue;
86
+ model[side] = { ...end, id: bySource.get(end.id) ?? end.id };
87
+ }
88
+ }
89
+ return created;
90
+ }
91
+ /* ── Saying what it cost ──────────────────────────────────────────────── */
92
+ const IMPORT_DONE_KEY = 'com.labre.interchange.import.done';
93
+ const IMPORT_DONE_FALLBACK = 'file imported';
94
+ const IMPORT_FAILED_KEY = 'com.labre.interchange.import.failed';
95
+ const IMPORT_FAILED_FALLBACK = 'This file could not be imported';
96
+ const IMPORT_REMARKS_KEY = 'com.labre.interchange.import.remarks';
97
+ const IMPORT_REMARKS_FALLBACK = 'What the import could not keep as it was';
98
+ const IMPORT_CONSOLE_KEY = 'com.labre.interchange.import.console';
99
+ const IMPORT_CONSOLE_FALLBACK = 'remarks — the full report is in the browser console.';
100
+ const IMPORT_DRAWN_KEY = 'com.labre.interchange.import.drawn';
101
+ const IMPORT_DRAWN_FALLBACK = 'drawn';
102
+ const IMPORT_CARRIED_KEY = 'com.labre.interchange.import.carried';
103
+ const IMPORT_CARRIED_FALLBACK = 'carried';
104
+ const IMPORT_QUARANTINED_KEY = 'com.labre.interchange.import.quarantined';
105
+ const IMPORT_QUARANTINED_FALLBACK = 'quarantined';
106
+ /**
107
+ * How many remarks the second notification spells out before it hands the
108
+ * reader to the console.
109
+ *
110
+ * A toast is a headline surface: past five lines it stops being read and starts
111
+ * being dismissed, and a report nobody reads is a report that was not written.
112
+ * See {@link reportInterchangeImport} for what the number is a compromise
113
+ * about.
114
+ */
115
+ const REMARKS_IN_A_NOTIFICATION = 5;
116
+ /**
117
+ * How the format names itself in a sentence: `bpmn` → `BPMN`.
118
+ *
119
+ * A format id is a lower-case key in the document (D2) and a proper noun in the
120
+ * chrome, and the chrome is where a user reads it — "BPMN 2.0", "SVG", "OWM".
121
+ * Upper-casing the declared id rather than adding a `label` field keeps the
122
+ * registry a table of facts about files: there is no second name to keep in
123
+ * step, and no format can be called one thing in its payload and another in the
124
+ * toast. The names this library actually ships are acronyms, which is why the
125
+ * rule is this simple one and not a title-casing.
126
+ */
127
+ const formatLabel = (format) => format.id.toUpperCase();
128
+ /**
129
+ * One remark, as the line a reader sees.
130
+ *
131
+ * The reader that produced it had no `std` and could not translate it (P3), so
132
+ * this is where a remark that declared a key gets its wording — with its own
133
+ * `message` as the English default, exactly like every other `translateKey`
134
+ * call site. A remark with no key is one that names something out of the file
135
+ * and is shown as the reader wrote it (see `InterchangeNote.messageKey`).
136
+ */
137
+ function remarkLine(std, note) {
138
+ const message = note.messageKey
139
+ ? translateKey(std, note.messageKey, note.message)
140
+ : note.message;
141
+ const subject = note.sourceId ?? note.element;
142
+ return subject ? `${subject}: ${message}` : message;
143
+ }
144
+ /**
145
+ * The notification seam, or silence.
146
+ *
147
+ * `getOptional`, like every other call site in the library: the host injects a
148
+ * `NotificationService` (labreapp does, the standalone playground does not), and
149
+ * an import that assumed one would be an import the playground cannot run.
150
+ * Nothing here decides that an import failed to happen because nobody was
151
+ * listening — the elements are on the surface either way.
152
+ */
153
+ function notifyImport(std, options) {
154
+ std.getOptional(NotificationProvider)?.notify({
155
+ title: options.title,
156
+ message: options.message,
157
+ accent: options.accent,
158
+ // Long enough to read a paragraph of remarks, and still self-dismissing:
159
+ // an import report is not a modal, and a toast the user has to close is a
160
+ // toast that interrupts the next thing they were doing.
161
+ duration: 8000,
162
+ });
163
+ }
164
+ /**
165
+ * Say what the import did — the summary, and the remarks.
166
+ *
167
+ * ## v1 of ADR 0012's open question 4 ("where does the report live?")
168
+ *
169
+ * The architect's v1: a NOTIFICATION for the summary, and the full notes on a
170
+ * surface that is reachable and honest. Reachable rules out a toast that names
171
+ * a count and drops the list; honest rules out the two things that look easier
172
+ * — writing the notes into the document as a text annotation (which pollutes a
173
+ * board the user did not ask us to draw on, and which the next export would
174
+ * have to explain) and dropping them (the notes are not derivable by re-running
175
+ * anything: the file is gone the moment the picker closes).
176
+ *
177
+ * So: one notification with the counts and the format version, a second with
178
+ * the remarks when there are few enough to read, and `console.table` with all
179
+ * of them, always, whenever there is one. The console is a poor product
180
+ * surface and it is named as one — the deliberate TARGET is the conformity
181
+ * panel, which is where a reader already goes to ask what is wrong with this
182
+ * board, and where an import remark belongs beside a validation finding. This
183
+ * is a stopgap that tells the truth, not the destination.
184
+ *
185
+ * ## The format is a word in the sentence, not a sentence per format
186
+ *
187
+ * The wordings are one set of keys for every format, and the format's own name
188
+ * is composed into them ({@link formatLabel}). The translation seam has no
189
+ * interpolation and no pluralisation — both are the host's — so a countable
190
+ * noun and a proper noun are the largest units this library can hand over
191
+ * without inventing grammar, which is the same argument the three count labels
192
+ * already ran on. The alternative, a key per format, would ask a host to
193
+ * translate "BPMN file imported" and "SVG file imported" as unrelated
194
+ * sentences and would leave every new format silently untranslated.
195
+ */
196
+ export function reportInterchangeImport(std, format, report) {
197
+ const label = formatLabel(format);
198
+ const counts = [
199
+ `${report.mapped} ${translateKey(std, IMPORT_DRAWN_KEY, IMPORT_DRAWN_FALLBACK)}`,
200
+ `${report.carried} ${translateKey(std, IMPORT_CARRIED_KEY, IMPORT_CARRIED_FALLBACK)}`,
201
+ `${report.quarantined} ${translateKey(std, IMPORT_QUARANTINED_KEY, IMPORT_QUARANTINED_FALLBACK)}`,
202
+ ].join(' · ');
203
+ // The version the reader actually READ, which is a fact about the file and
204
+ // not about this library — an `exporter` attribute is how a support thread
205
+ // about "bpmn.io drew it differently" gets answered in one line.
206
+ const version = report.sourceVersion;
207
+ notifyImport(std, {
208
+ title: `${label} ${translateKey(std, IMPORT_DONE_KEY, IMPORT_DONE_FALLBACK)}`,
209
+ message: version ? `${counts} — ${label} ${version}` : counts,
210
+ accent: 'info',
211
+ });
212
+ const notes = report.notes;
213
+ if (notes.length === 0)
214
+ return;
215
+ // Always, and before the second toast: the console line is the one that is
216
+ // still there in ten minutes, and the only place the WHOLE list lands when
217
+ // there are forty of them.
218
+ console.info(`[${format.id}] import report — ${counts}${version ? ` — ${label} ${version}` : ''}`);
219
+ console.table(notes.map(note => ({
220
+ kind: note.kind,
221
+ source: note.sourceId ?? '',
222
+ element: note.element ?? '',
223
+ message: note.message,
224
+ })));
225
+ notifyImport(std, {
226
+ title: translateKey(std, IMPORT_REMARKS_KEY, IMPORT_REMARKS_FALLBACK),
227
+ message: notes.length <= REMARKS_IN_A_NOTIFICATION
228
+ ? notes.map(note => remarkLine(std, note)).join('\n')
229
+ : `${notes.length} ${translateKey(std, IMPORT_CONSOLE_KEY, IMPORT_CONSOLE_FALLBACK)}`,
230
+ // Not `error`, and not `info`: nothing failed — every one of these is
231
+ // something the document KEPT — but each one is a difference between the
232
+ // file the user handed over and the board they are looking at.
233
+ accent: 'warning',
234
+ });
235
+ }
236
+ /* ── The whole gesture ────────────────────────────────────────────────── */
237
+ /**
238
+ * Read a file the user picks with one declared capability, draw it, and say
239
+ * what it cost.
240
+ *
241
+ * Two steps, and neither is re-implemented anywhere: ask for a file, then hand
242
+ * it to {@link importInterchangeFile}, which is the rest of the gesture.
243
+ *
244
+ * ## The picker filter is the FORMAT's, not a table's
245
+ *
246
+ * `{ [mime]: extensions }` straight off the declaration, so a framework that
247
+ * adds a format adds its dialog filter with it and no second file has to agree.
248
+ * A format that declares no mime is offered as `text/plain`, which is what a
249
+ * DSL is — the extensions are the half that matters anyway, and the fallback
250
+ * branch of the picker (`showOpenFilePicker` is absent in Firefox and Safari)
251
+ * puts both halves into `input.accept` precisely because extensions like
252
+ * `.bpmn` are registered with no operating system on earth.
253
+ *
254
+ * The read-only guard is here as well as inside `importInterchangeFile`, and
255
+ * deliberately so: a dialog a document cannot honour should never open in the
256
+ * first place.
257
+ */
258
+ export async function runInterchangeImportFile(std, capability) {
259
+ const gfx = std.get(GfxControllerIdentifier);
260
+ if (!gfx.surface || std.store.readonly)
261
+ return;
262
+ const { format } = capability;
263
+ const file = await openSingleFileWithSpec({
264
+ description: formatLabel(format),
265
+ accept: { [format.mime ?? 'text/plain']: [...format.extensions] },
266
+ });
267
+ // The user closed the picker. Not a failure, and not a notification: they
268
+ // know what they just did.
269
+ if (!file)
270
+ return;
271
+ await importInterchangeFile(std, capability, file);
272
+ }
273
+ /**
274
+ * The import itself, over a file the caller ALREADY HAS: run the declared
275
+ * capability (`docs/adr/0012`), write what it returned, bring it into view, and
276
+ * say what it cost.
277
+ *
278
+ * ## Why this is separate from the picker
279
+ *
280
+ * Because a picker is one way to be handed a file and not the only one. A host
281
+ * drop zone has the `File` the moment somebody lets go of it; so does a paste,
282
+ * an "open with", and a fetch from a document store. Every one of those wants
283
+ * the four steps below and none of them wants a dialog — and a seam that only
284
+ * exists behind `showOpenFilePicker` forces each of them to re-implement the id
285
+ * remapping and the viewport fit, which is the duplication this whole file was
286
+ * written to end.
287
+ *
288
+ * It is also the honest testing seam. A test that has to intercept a MODULE to
289
+ * reach this code is a test coupled to the bundler; passing the file in is one
290
+ * argument, and it means the pipeline is proven the same way in every
291
+ * environment the library runs in. `capability.run` is the same function
292
+ * labre-mcp calls, so a command, a drop zone and the registry cannot read the
293
+ * same file differently — one door, and the registry is the label on it.
294
+ *
295
+ * ## What arrives is a NEW board, never a merge
296
+ *
297
+ * The elements are added beside whatever is already on the surface. That is the
298
+ * bottom row of a reader's own loss table — surface identity across a
299
+ * re-import is lost — and it is the honest behaviour: two boards the user can
300
+ * see and delete beats a merge that silently rewrote artefacts they had edited.
301
+ *
302
+ * ## Failure is an exception, and it says which one
303
+ *
304
+ * A reader THROWS on a file it cannot read, because the five note kinds cannot
305
+ * say "this is not a file I can read" and a report of three zeroes would claim
306
+ * an empty document where there was none. The sentence it throws names which of
307
+ * its refusals it was, so it is shown as it is rather than replaced with a
308
+ * wording of our own that knows less.
309
+ */
310
+ export async function importInterchangeFile(std, capability, file) {
311
+ const gfx = std.get(GfxControllerIdentifier);
312
+ if (!gfx.surface || std.store.readonly)
313
+ return;
314
+ const { format } = capability;
315
+ let result;
316
+ try {
317
+ result = capability.run(await file.text(), { name: file.name });
318
+ }
319
+ catch (error) {
320
+ notifyImport(std, {
321
+ title: translateKey(std, IMPORT_FAILED_KEY, IMPORT_FAILED_FALLBACK),
322
+ message: error instanceof Error ? error.message : String(error),
323
+ accent: 'error',
324
+ });
325
+ return;
326
+ }
327
+ // One undo step for the whole file, the way one lane gesture is one step:
328
+ // `captureSync` before opens a boundary, the writes land inside it, and the
329
+ // second one closes it. An import a user has to undo forty times is an import
330
+ // they cannot undo.
331
+ std.store.captureSync();
332
+ const created = materializeInterchangeImport(std, format.id, result.elements);
333
+ std.store.captureSync();
334
+ // …and then bring it into view, which is what template insertion does for
335
+ // the same reason: a board that landed off-screen looks like a command that
336
+ // did nothing. The padding is in MODEL units, so it is divided by the zoom to
337
+ // stay a constant margin on screen — the template panel's own arithmetic.
338
+ //
339
+ // ## Why the empty boxes are dropped, and it is not defensive
340
+ //
341
+ // A connector has no geometry of its own: its bound is derived from the path
342
+ // the connector manager routes between its two ends, and that path is
343
+ // computed on a LATER tick than the `addElement` that created it. Read
344
+ // synchronously here — which is the only moment this function has — every
345
+ // freshly imported connector answers `[0, 0, 0, 0]`, and a common bound that
346
+ // includes the origin stretches from (0, 0) to the far corner of the drawing.
347
+ // A file drawn at x ≈ 100000 (bpmn.io hands those out the moment somebody
348
+ // drags a process across the canvas) then fits a 100000-wide box, and the
349
+ // process the user just imported is a speck in the corner.
350
+ //
351
+ // Dropping zero-area boxes costs nothing and loses nothing: a connector runs
352
+ // BETWEEN two nodes, so once its path settles its bound is already inside
353
+ // theirs, and every artefact a framework pack draws has a positive size by
354
+ // construction. What is left is exactly the shaped elements, which is what
355
+ // "fit the imported board" means.
356
+ const boxes = created
357
+ .map(id => gfx.surface?.getElementById(id)?.elementBound)
358
+ .filter((bound) => bound !== undefined && bound.w > 0 && bound.h > 0);
359
+ const bound = getCommonBound(boxes);
360
+ if (bound) {
361
+ const padding = 20 / gfx.viewport.zoom;
362
+ gfx.viewport.setViewportByBound(bound, [padding, padding, padding, padding], true);
363
+ }
364
+ gfx.tool.setTool(DefaultTool);
365
+ reportInterchangeImport(std, format, result.report);
366
+ }
367
+ /* ── What can read a file called this ─────────────────────────────────── */
368
+ /**
369
+ * Every registered importer, indexed by the extensions it declares.
370
+ *
371
+ * A LIST per extension, and that is the whole design: `.svg` will be claimed by
372
+ * several frameworks at once, because an SVG is a picture and which framework's
373
+ * vocabulary it is a picture OF is not a fact about the filename. ADR 0012 is
374
+ * explicit that a visual import is heuristic recognition and that the surface
375
+ * must name what it is about to do before the file is read — so this answers
376
+ * "what could read this file", and a UI (or a user) chooses. Anything that
377
+ * silently picked one would be guessing on the user's behalf about the one
378
+ * question they are the only one able to answer.
379
+ *
380
+ * Keys keep their leading dot and are lower-cased, because a file called
381
+ * `Order.BPMN` is the same kind of file as `order.bpmn` and nobody should have
382
+ * to know which. Capabilities keep the registry's own order — sorted by
383
+ * capability id — so a menu built from this map reads the same on every boot.
384
+ *
385
+ * Registration is flag-gated tooling (`docs/adr/0009`), so a framework whose
386
+ * flag is off contributes no row here, and a document a past import wrote keeps
387
+ * every byte it was given.
388
+ */
389
+ export function interchangeImportersByExtension(provider) {
390
+ const byExtension = new Map();
391
+ for (const capability of interchangeCapabilities(provider, {
392
+ direction: 'import',
393
+ })) {
394
+ for (const extension of capability.format.extensions) {
395
+ const key = extension.toLowerCase();
396
+ const capabilities = byExtension.get(key);
397
+ if (capabilities)
398
+ capabilities.push(capability);
399
+ else
400
+ byExtension.set(key, [capability]);
401
+ }
402
+ }
403
+ return byExtension;
404
+ }