@formicoidea/labre-core 0.41.0 → 0.42.0

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 (252) hide show
  1. package/LICENSE +384 -0
  2. package/dist/_pkgs/affine-block-bookmark/bookmark-block.js +2 -2
  3. package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/config.js +7 -1
  4. package/dist/_pkgs/affine-block-embed/embed-figma-block/embed-figma-block.js +2 -1
  5. package/dist/_pkgs/affine-block-embed/embed-github-block/embed-github-block.js +2 -1
  6. package/dist/_pkgs/affine-block-embed/embed-iframe-block/consts.d.ts +2 -0
  7. package/dist/_pkgs/affine-block-embed/embed-iframe-block/consts.js +5 -0
  8. package/dist/_pkgs/affine-block-embed/embed-iframe-block/embed-iframe-block.d.ts +1 -0
  9. package/dist/_pkgs/affine-block-embed/embed-iframe-block/embed-iframe-block.js +30 -8
  10. package/dist/_pkgs/affine-block-embed/embed-iframe-block/utils.d.ts +8 -0
  11. package/dist/_pkgs/affine-block-embed/embed-iframe-block/utils.js +19 -0
  12. package/dist/_pkgs/affine-block-embed/embed-loom-block/embed-loom-block.js +2 -1
  13. package/dist/_pkgs/affine-block-embed/embed-youtube-block/embed-youtube-block.js +2 -1
  14. package/dist/_pkgs/affine-block-frame/frame-manager.js +1 -1
  15. package/dist/_pkgs/affine-block-frame/frame-tool.js +1 -1
  16. package/dist/_pkgs/affine-block-frame/frame-toolbar.js +6 -1
  17. package/dist/_pkgs/affine-block-list/list-keymap.js +7 -0
  18. package/dist/_pkgs/affine-block-note/note-keymap.js +7 -1
  19. package/dist/_pkgs/affine-block-paragraph/paragraph-keymap.js +7 -1
  20. package/dist/_pkgs/affine-block-root/commands/pivot-commands.js +1 -8
  21. package/dist/_pkgs/affine-block-root/commands/tag-commands.js +1 -8
  22. package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.d.ts +9 -0
  23. package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.js +51 -0
  24. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.d.ts +22 -0
  25. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.js +46 -0
  26. package/dist/_pkgs/affine-block-root/edgeless/utils/pinch-zoom.d.ts +21 -0
  27. package/dist/_pkgs/affine-block-root/edgeless/utils/pinch-zoom.js +24 -0
  28. package/dist/_pkgs/affine-block-root/edgeless/utils/query.js +8 -0
  29. package/dist/_pkgs/affine-block-root/keyboard/keymap.js +1 -16
  30. package/dist/_pkgs/affine-block-surface/element-model/index.d.ts +21 -3
  31. package/dist/_pkgs/affine-block-surface/element-model/index.js +14 -2
  32. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.d.ts +23 -0
  33. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.js +89 -0
  34. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.d.ts +7 -0
  35. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.js +5 -0
  36. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.d.ts +41 -0
  37. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +70 -0
  38. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.d.ts +49 -0
  39. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.js +257 -0
  40. package/dist/_pkgs/affine-block-surface/extensions/export-svg/tagged-path.d.ts +16 -0
  41. package/dist/_pkgs/affine-block-surface/extensions/export-svg/tagged-path.js +24 -0
  42. package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.d.ts +24 -0
  43. package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.js +66 -0
  44. package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +4 -0
  45. package/dist/_pkgs/affine-block-surface/extensions/index.js +4 -0
  46. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.d.ts +66 -4
  47. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.js +241 -11
  48. package/dist/_pkgs/affine-block-surface/extensions/interchange.d.ts +18 -0
  49. package/dist/_pkgs/affine-block-surface/extensions/legend-toolbar.d.ts +81 -0
  50. package/dist/_pkgs/affine-block-surface/extensions/legend-toolbar.js +81 -0
  51. package/dist/_pkgs/affine-block-surface/extensions/legend.d.ts +136 -0
  52. package/dist/_pkgs/affine-block-surface/extensions/legend.js +439 -0
  53. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.d.ts +17 -3
  54. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.js +35 -13
  55. package/dist/_pkgs/affine-block-surface/extensions/reading.d.ts +61 -1
  56. package/dist/_pkgs/affine-block-surface/extensions/reading.js +85 -39
  57. package/dist/_pkgs/affine-block-surface/extensions/record-action.d.ts +66 -0
  58. package/dist/_pkgs/affine-block-surface/extensions/record-action.js +145 -0
  59. package/dist/_pkgs/affine-block-surface/extensions/validation.d.ts +253 -28
  60. package/dist/_pkgs/affine-block-surface/extensions/validation.js +489 -41
  61. package/dist/_pkgs/affine-block-surface/framework-background/background-view.d.ts +115 -0
  62. package/dist/_pkgs/affine-block-surface/framework-background/background-view.js +185 -0
  63. package/dist/_pkgs/affine-block-surface/framework-background/index.d.ts +1 -0
  64. package/dist/_pkgs/affine-block-surface/framework-background/index.js +1 -0
  65. package/dist/_pkgs/affine-block-surface/framework-background/labels.d.ts +16 -1
  66. package/dist/_pkgs/affine-block-surface/framework-background/labels.js +31 -21
  67. package/dist/_pkgs/affine-block-surface/framework-background/renderer.js +29 -5
  68. package/dist/_pkgs/affine-block-surface/framework-background/stacking.d.ts +6 -4
  69. package/dist/_pkgs/affine-block-surface/framework-background/stacking.js +56 -8
  70. package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.d.ts +12 -0
  71. package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.js +15 -0
  72. package/dist/_pkgs/affine-block-surface/view.js +8 -1
  73. package/dist/_pkgs/affine-block-surface-ref/configs/slash-menu.js +1 -1
  74. package/dist/_pkgs/affine-components/color-picker/button.d.ts +56 -1
  75. package/dist/_pkgs/affine-components/color-picker/button.js +168 -23
  76. package/dist/_pkgs/affine-components/color-picker/framework-palette.d.ts +106 -0
  77. package/dist/_pkgs/affine-components/color-picker/framework-palette.js +177 -0
  78. package/dist/_pkgs/affine-components/color-picker/index.d.ts +2 -0
  79. package/dist/_pkgs/affine-components/color-picker/index.js +2 -0
  80. package/dist/_pkgs/affine-components/color-picker/palette-carousel.d.ts +85 -0
  81. package/dist/_pkgs/affine-components/color-picker/palette-carousel.js +440 -0
  82. package/dist/_pkgs/affine-components/edgeless-shape-color-picker/color-picker.d.ts +31 -1
  83. package/dist/_pkgs/affine-components/edgeless-shape-color-picker/color-picker.js +189 -63
  84. package/dist/_pkgs/affine-components/resource/resource.js +29 -16
  85. package/dist/_pkgs/affine-components/translations.d.ts +8 -0
  86. package/dist/_pkgs/affine-components/translations.js +17 -0
  87. package/dist/_pkgs/affine-foundation/view.js +2 -1
  88. package/dist/_pkgs/affine-gfx-brush/element-renderer.js +2 -2
  89. package/dist/_pkgs/affine-gfx-brush/toolbar/configs/brush.js +6 -1
  90. package/dist/_pkgs/affine-gfx-brush/toolbar/configs/highlighter.js +6 -1
  91. package/dist/_pkgs/affine-gfx-connector/connector-manager.d.ts +9 -1
  92. package/dist/_pkgs/affine-gfx-connector/connector-manager.js +61 -0
  93. package/dist/_pkgs/affine-gfx-connector/element-renderer/connector-dom/index.d.ts +7 -1
  94. package/dist/_pkgs/affine-gfx-connector/element-renderer/connector-dom/index.js +87 -17
  95. package/dist/_pkgs/affine-gfx-connector/element-renderer/index.js +78 -17
  96. package/dist/_pkgs/affine-gfx-connector/element-renderer/utils.d.ts +24 -2
  97. package/dist/_pkgs/affine-gfx-connector/element-renderer/utils.js +31 -8
  98. package/dist/_pkgs/affine-gfx-connector/text/edgeless-connector-label-editor.d.ts +124 -3
  99. package/dist/_pkgs/affine-gfx-connector/text/edgeless-connector-label-editor.js +216 -54
  100. package/dist/_pkgs/affine-gfx-connector/text/text.d.ts +13 -4
  101. package/dist/_pkgs/affine-gfx-connector/text/text.js +13 -44
  102. package/dist/_pkgs/affine-gfx-connector/toolbar/config.d.ts +56 -0
  103. package/dist/_pkgs/affine-gfx-connector/toolbar/config.js +72 -4
  104. package/dist/_pkgs/affine-gfx-connector/toolbar/hollow-endpoint-icons.d.ts +8 -0
  105. package/dist/_pkgs/affine-gfx-connector/toolbar/hollow-endpoint-icons.js +118 -0
  106. package/dist/_pkgs/affine-gfx-connector/view/view.d.ts +37 -1
  107. package/dist/_pkgs/affine-gfx-connector/view/view.js +97 -8
  108. package/dist/_pkgs/affine-gfx-group/command/group-api.js +1 -1
  109. package/dist/_pkgs/affine-gfx-group/store.js +0 -2
  110. package/dist/_pkgs/affine-gfx-group/translations.d.ts +9 -10
  111. package/dist/_pkgs/affine-gfx-group/translations.js +9 -13
  112. package/dist/_pkgs/affine-gfx-mindmap/templates/index.js +1 -1
  113. package/dist/_pkgs/affine-gfx-mindmap/toolbar/basket-elements.js +1 -1
  114. package/dist/_pkgs/affine-gfx-mindmap/toolbar/utils/import-mindmap.js +2 -2
  115. package/dist/_pkgs/affine-gfx-mindmap/translations.d.ts +1 -1
  116. package/dist/_pkgs/affine-gfx-mindmap/translations.js +1 -1
  117. package/dist/_pkgs/affine-gfx-shape/element-renderer/highlighter.js +2 -2
  118. package/dist/_pkgs/affine-gfx-shape/overlay/polygon-drawing-overlay.d.ts +6 -0
  119. package/dist/_pkgs/affine-gfx-shape/overlay/polygon-drawing-overlay.js +30 -1
  120. package/dist/_pkgs/affine-gfx-shape/polygon-tool.d.ts +20 -1
  121. package/dist/_pkgs/affine-gfx-shape/polygon-tool.js +9 -1
  122. package/dist/_pkgs/affine-gfx-shape/toolbar/config.js +6 -1
  123. package/dist/_pkgs/affine-gfx-shape/toolbar/palette-color-action.js +11 -1
  124. package/dist/_pkgs/affine-gfx-template/builtin/other.js +1 -1
  125. package/dist/_pkgs/affine-gfx-template/snapshot-from-action.js +32 -119
  126. package/dist/_pkgs/affine-gfx-template/toolbar/template-type.d.ts +1 -1
  127. package/dist/_pkgs/affine-gfx-text/dblclick-add-edgeless-text.d.ts +13 -1
  128. package/dist/_pkgs/affine-gfx-text/dblclick-add-edgeless-text.js +19 -4
  129. package/dist/_pkgs/affine-gfx-text/edgeless-text-editor.d.ts +41 -0
  130. package/dist/_pkgs/affine-gfx-text/edgeless-text-editor.js +57 -2
  131. package/dist/_pkgs/affine-gfx-text/toolbar/actions.d.ts +8 -1
  132. package/dist/_pkgs/affine-gfx-text/toolbar/actions.js +12 -2
  133. package/dist/_pkgs/affine-gfx-text/translations.d.ts +1 -0
  134. package/dist/_pkgs/affine-gfx-text/translations.js +2 -1
  135. package/dist/_pkgs/affine-inline-preset/markdown.js +5 -1
  136. package/dist/_pkgs/affine-model/consts/connector.d.ts +28 -2
  137. package/dist/_pkgs/affine-model/consts/connector.js +26 -0
  138. package/dist/_pkgs/affine-model/elements/bpmn/pool.js +1 -1
  139. package/dist/_pkgs/affine-model/elements/brush/brush.js +1 -1
  140. package/dist/_pkgs/affine-model/elements/c4/board.js +1 -1
  141. package/dist/_pkgs/affine-model/elements/c4/boundary.js +1 -1
  142. package/dist/_pkgs/affine-model/elements/connector/connector.d.ts +135 -0
  143. package/dist/_pkgs/affine-model/elements/connector/connector.js +246 -5
  144. package/dist/_pkgs/affine-model/elements/connector/end-label.d.ts +83 -0
  145. package/dist/_pkgs/affine-model/elements/connector/end-label.js +119 -0
  146. package/dist/_pkgs/affine-model/elements/connector/index.d.ts +1 -0
  147. package/dist/_pkgs/affine-model/elements/connector/index.js +1 -0
  148. package/dist/_pkgs/affine-model/elements/context-map/context-map.js +1 -1
  149. package/dist/_pkgs/affine-model/elements/core-domain/core-domain.d.ts +28 -0
  150. package/dist/_pkgs/affine-model/elements/core-domain/core-domain.js +129 -2
  151. package/dist/_pkgs/affine-model/elements/cynefin/cynefin.d.ts +8 -0
  152. package/dist/_pkgs/affine-model/elements/cynefin/cynefin.js +45 -2
  153. package/dist/_pkgs/affine-model/elements/edgy/board.js +1 -1
  154. package/dist/_pkgs/affine-model/elements/edgy/facets.js +1 -1
  155. package/dist/_pkgs/affine-model/elements/estuarine/estuarine.d.ts +6 -0
  156. package/dist/_pkgs/affine-model/elements/estuarine/estuarine.js +36 -2
  157. package/dist/_pkgs/affine-model/elements/event-storming/event-storming.d.ts +18 -7
  158. package/dist/_pkgs/affine-model/elements/event-storming/event-storming.js +23 -8
  159. package/dist/_pkgs/affine-model/elements/framework-background/background.d.ts +16 -0
  160. package/dist/_pkgs/affine-model/elements/framework-background/background.js +18 -0
  161. package/dist/_pkgs/affine-model/elements/highlighter/highlighter.js +1 -1
  162. package/dist/_pkgs/affine-model/elements/index.d.ts +8 -0
  163. package/dist/_pkgs/affine-model/elements/index.js +1 -0
  164. package/dist/_pkgs/affine-model/elements/shape/shape.js +1 -1
  165. package/dist/_pkgs/affine-model/elements/text/text.js +1 -1
  166. package/dist/_pkgs/affine-model/elements/uml/band.d.ts +39 -0
  167. package/dist/_pkgs/affine-model/elements/uml/band.js +31 -0
  168. package/dist/_pkgs/affine-model/elements/uml/diagram.d.ts +158 -0
  169. package/dist/_pkgs/affine-model/elements/uml/diagram.js +229 -0
  170. package/dist/_pkgs/affine-model/elements/uml/fragment.d.ts +161 -0
  171. package/dist/_pkgs/affine-model/elements/uml/fragment.js +205 -0
  172. package/dist/_pkgs/affine-model/elements/uml/index.d.ts +8 -0
  173. package/dist/_pkgs/affine-model/elements/uml/index.js +8 -0
  174. package/dist/_pkgs/affine-model/elements/uml/lifeline.d.ts +77 -0
  175. package/dist/_pkgs/affine-model/elements/uml/lifeline.js +89 -0
  176. package/dist/_pkgs/affine-model/elements/uml/node.d.ts +142 -0
  177. package/dist/_pkgs/affine-model/elements/uml/node.js +190 -0
  178. package/dist/_pkgs/affine-model/elements/uml/partition.d.ts +106 -0
  179. package/dist/_pkgs/affine-model/elements/uml/partition.js +172 -0
  180. package/dist/_pkgs/affine-model/elements/uml/region.d.ts +75 -0
  181. package/dist/_pkgs/affine-model/elements/uml/region.js +150 -0
  182. package/dist/_pkgs/affine-model/elements/uml/subject.d.ts +37 -0
  183. package/dist/_pkgs/affine-model/elements/uml/subject.js +108 -0
  184. package/dist/_pkgs/affine-model/elements/wardley/wardley.js +1 -1
  185. package/dist/_pkgs/affine-shared/services/embed-iframe/embed-iframe-config.d.ts +1 -0
  186. package/dist/_pkgs/affine-shared/services/font-loader/config.d.ts +7 -0
  187. package/dist/_pkgs/affine-shared/services/font-loader/config.js +43 -0
  188. package/dist/_pkgs/affine-shared/services/pivot-materiality-publisher.js +1 -9
  189. package/dist/_pkgs/affine-shared/services/telemetry-service/document-damage-watcher.d.ts +53 -0
  190. package/dist/_pkgs/affine-shared/services/telemetry-service/document-damage-watcher.js +95 -0
  191. package/dist/_pkgs/affine-shared/services/telemetry-service/index.d.ts +1 -0
  192. package/dist/_pkgs/affine-shared/services/telemetry-service/index.js +1 -0
  193. package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +26 -1
  194. package/dist/_pkgs/affine-shared/services/telemetry-service/telemetry-service.d.ts +2 -2
  195. package/dist/_pkgs/affine-shared/services/toolbar-service/command-action.d.ts +34 -0
  196. package/dist/_pkgs/affine-shared/services/toolbar-service/command-action.js +63 -0
  197. package/dist/_pkgs/affine-shared/services/toolbar-service/index.d.ts +1 -0
  198. package/dist/_pkgs/affine-shared/services/toolbar-service/index.js +1 -0
  199. package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +77 -7
  200. package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +97 -7
  201. package/dist/_pkgs/affine-shared/styles/index.d.ts +1 -0
  202. package/dist/_pkgs/affine-shared/styles/index.js +1 -0
  203. package/dist/_pkgs/affine-shared/styles/motion.d.ts +14 -0
  204. package/dist/_pkgs/affine-shared/styles/motion.js +38 -0
  205. package/dist/_pkgs/affine-shared/utils/event.d.ts +10 -0
  206. package/dist/_pkgs/affine-shared/utils/event.js +20 -0
  207. package/dist/_pkgs/affine-shared/utils/file/filesys.d.ts +16 -0
  208. package/dist/_pkgs/affine-shared/utils/file/filesys.js +25 -0
  209. package/dist/_pkgs/affine-shared/utils/index.d.ts +1 -0
  210. package/dist/_pkgs/affine-shared/utils/index.js +1 -0
  211. package/dist/_pkgs/affine-shared/utils/link-preview-refresh.d.ts +12 -0
  212. package/dist/_pkgs/affine-shared/utils/link-preview-refresh.js +13 -0
  213. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.d.ts +12 -4
  214. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.js +27 -4
  215. package/dist/_pkgs/affine-widget-edgeless-toolbar/create-popper.js +13 -0
  216. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.d.ts +2 -0
  217. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.js +2 -0
  218. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.d.ts +80 -0
  219. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.js +270 -81
  220. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/senior-menu-selection.d.ts +15 -0
  221. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/senior-menu-selection.js +15 -0
  222. package/dist/_pkgs/affine-widget-edgeless-toolbar/panel/font-weight-and-style-panel.js +8 -1
  223. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-ghost-overlay.d.ts +42 -0
  224. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-ghost-overlay.js +100 -0
  225. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-placement-tool.d.ts +100 -0
  226. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-placement-tool.js +274 -0
  227. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/index.d.ts +3 -0
  228. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/index.js +3 -0
  229. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/translate-created.d.ts +25 -0
  230. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/translate-created.js +67 -0
  231. package/dist/_pkgs/affine-widget-edgeless-toolbar/view.js +5 -0
  232. package/dist/_pkgs/global/gfx/xywh.js +7 -0
  233. package/dist/_pkgs/std/extension/command-registry.d.ts +158 -1
  234. package/dist/_pkgs/std/extension/command-registry.js +22 -0
  235. package/dist/_pkgs/std/gfx/index.d.ts +1 -1
  236. package/dist/_pkgs/std/gfx/interactivity/gfx-view-event-handler.d.ts +12 -0
  237. package/dist/_pkgs/std/gfx/interactivity/gfx-view-event-handler.js +20 -1
  238. package/dist/_pkgs/std/gfx/interactivity/manager.d.ts +10 -0
  239. package/dist/_pkgs/std/gfx/interactivity/manager.js +12 -0
  240. package/dist/_pkgs/std/gfx/model/surface/element-model.js +12 -7
  241. package/dist/_pkgs/std/gfx/model/surface/surface-model.d.ts +56 -0
  242. package/dist/_pkgs/std/gfx/model/surface/surface-model.js +84 -3
  243. package/dist/_pkgs/std/gfx/view/view.d.ts +11 -2
  244. package/dist/_pkgs/std/gfx/view/view.js +16 -2
  245. package/dist/commands.d.ts +6 -0
  246. package/dist/commands.js +8 -1
  247. package/dist/frameworks.d.ts +9 -0
  248. package/dist/frameworks.js +19 -0
  249. package/dist/translations.js +16 -0
  250. package/package.json +9 -4
  251. package/dist/_pkgs/affine-gfx-group/group-watcher.d.ts +0 -1
  252. package/dist/_pkgs/affine-gfx-group/group-watcher.js +0 -20
@@ -6,9 +6,12 @@ export * from './edit-props-middleware-builder.js';
6
6
  export * from './editor-anchored-panel.js';
7
7
  export * from './element-renderer.js';
8
8
  export * from './export-manager/index.js';
9
+ export * from './export-svg/index.js';
9
10
  export * from './interchange.js';
10
11
  export * from './interchange-import.js';
11
12
  export * from './legacy-slot-extension.js';
13
+ export * from './legend.js';
14
+ export * from './legend-toolbar.js';
12
15
  export * from './map-quality.js';
13
16
  export * from './map-quality-widget.js';
14
17
  export * from './morph-toolbar.js';
@@ -16,6 +19,7 @@ export * from './query.js';
16
19
  export * from './reading.js';
17
20
  export * from './reading-toolbar.js';
18
21
  export * from './reading-widget.js';
22
+ export * from './record-action.js';
19
23
  export * from './spotlight.js';
20
24
  export * from './surface-middleware.js';
21
25
  export * from './svg-sketch.js';
@@ -6,9 +6,12 @@ export * from './edit-props-middleware-builder.js';
6
6
  export * from './editor-anchored-panel.js';
7
7
  export * from './element-renderer.js';
8
8
  export * from './export-manager/index.js';
9
+ export * from './export-svg/index.js';
9
10
  export * from './interchange.js';
10
11
  export * from './interchange-import.js';
11
12
  export * from './legacy-slot-extension.js';
13
+ export * from './legend.js';
14
+ export * from './legend-toolbar.js';
12
15
  export * from './map-quality.js';
13
16
  export * from './map-quality-widget.js';
14
17
  export * from './morph-toolbar.js';
@@ -16,6 +19,7 @@ export * from './query.js';
16
19
  export * from './reading.js';
17
20
  export * from './reading-toolbar.js';
18
21
  export * from './reading-widget.js';
22
+ export * from './record-action.js';
19
23
  export * from './spotlight.js';
20
24
  export * from './surface-middleware.js';
21
25
  export * from './svg-sketch.js';
@@ -1,6 +1,6 @@
1
1
  import type { ServiceProvider } from '../../global/di/index.js';
2
2
  import type { BlockStdScope } from '../../std/index.js';
3
- import { type InterchangeFormat, type InterchangeImportCapability, type InterchangeReport, type SerializedElementProps } from './interchange.js';
3
+ import { type InterchangeFormat, type InterchangeImportCapability, type InterchangeNote, type InterchangeReport, type SerializedElementProps } from './interchange.js';
4
4
  /**
5
5
  * **The public import API** — what an editor, a host application or a plugin
6
6
  * calls to turn a foreign file into a board (`docs/adr/0012`).
@@ -50,11 +50,49 @@ import { type InterchangeFormat, type InterchangeImportCapability, type Intercha
50
50
  * whole blob and `addElement` writes it with everything else, which is the
51
51
  * whole-record LWW the field's own contract asks for (D2).
52
52
  *
53
+ * ## The reader's OWN names, and why there is a second map
54
+ *
55
+ * A source id is the file's, and there are two things a reader has to point at
56
+ * that the file never named: an element it MINTED (a framework artefact is
57
+ * routinely several elements — a shape, its compartments, and the group that
58
+ * makes them one thing), and the group membership between them. So a reader may
59
+ * also hand each element a provisional `id` of its own. `surface.addElement`
60
+ * overwrites it with a nanoid and is documented to, which is precisely what
61
+ * makes it safe to use as a local name: it reaches no document, and it is read
62
+ * here and nowhere else.
63
+ *
64
+ * A GROUP's `children` are therefore rewritten BEFORE the group is created, out
65
+ * of the map built so far — which costs nothing and asks the reader for the one
66
+ * thing it can always give: emit an element before the group that holds it. A
67
+ * connector is the opposite case (a flow may be written before either of its
68
+ * ends) and keeps its second pass.
69
+ *
70
+ * Source ids win over provisional ones wherever both could answer, so a reader
71
+ * that mints no local name behaves exactly as it did before this was here.
72
+ *
73
+ * ## Beside what is already drawn
74
+ *
75
+ * A reader writes the coordinates its FILE gave it, so importing the same file
76
+ * twice put the second board exactly on top of the first. The offset is applied
77
+ * here, once, for every framework, because the only thing that knows what the
78
+ * canvas already holds is the function doing the writing — see
79
+ * {@link importOffset}, and note that an empty surface is left alone.
80
+ *
81
+ * ## A read-only document is answered, not thrown at
82
+ *
83
+ * This is a public API — a host (labre-mcp) writes through it with no command
84
+ * in front of it — so the guard belongs here too and not only at the callers:
85
+ * a readonly document answers the empty array, which is the same "nothing was
86
+ * minted" every other refusal of this function returns, rather than an
87
+ * exception a caller would have to know to catch.
88
+ *
53
89
  * @param formatId the format whose payload key carries the source ids — the
54
90
  * `id` of the capability's {@link InterchangeFormat}, and the ONLY thing this
55
91
  * function ever knew about BPMN.
56
92
  */
57
- export declare function materializeInterchangeImport(std: BlockStdScope, formatId: string, elements: readonly SerializedElementProps[]): string[];
93
+ export declare function materializeInterchangeImport(std: BlockStdScope, formatId: string, elements: readonly SerializedElementProps[], options?: {
94
+ onNote?: (note: InterchangeNote) => void;
95
+ }): string[];
58
96
  /**
59
97
  * Say what the import did — the summary, and the remarks.
60
98
  *
@@ -109,7 +147,31 @@ export declare function reportInterchangeImport(std: BlockStdScope, format: Inte
109
147
  * deliberately so: a dialog a document cannot honour should never open in the
110
148
  * first place.
111
149
  */
112
- export declare function runInterchangeImportFile(std: BlockStdScope, capability: InterchangeImportCapability): Promise<void>;
150
+ export declare function runInterchangeImportFile(std: BlockStdScope, capability: InterchangeImportCapability, options?: InterchangeImportOptions): Promise<void>;
151
+ /** What a caller can put between the file's bytes and the declared reader. */
152
+ export interface InterchangeImportOptions {
153
+ /**
154
+ * Turn the file's text into the text the reader takes — the seam for a
155
+ * format whose container is not the document.
156
+ *
157
+ * A reader is a PURE, synchronous function of text (`docs/adr/0012` P3), and
158
+ * that is not negotiable: it is what lets labre-mcp call the same function
159
+ * the command calls. Some containers put an asynchronous platform API between
160
+ * the bytes and the document all the same — a `.drawio` file holds its
161
+ * `<mxGraphModel>` as base64 of a raw deflate, and inflating it needs
162
+ * `DecompressionStream` (`gfx/uml/src/drawio-decode.ts`, `docs/adr/0019`);
163
+ * a zipped container would be the next one.
164
+ *
165
+ * So the unwrapping happens HERE, where a caller already has an editor and an
166
+ * `await`, and the reader keeps its purity. Anything this throws is shown as
167
+ * the import's failure notification, exactly as a reader's own refusal is —
168
+ * so the sentence it throws should name what is wrong with the file.
169
+ *
170
+ * Absent for every format whose file IS its document, which is all of them
171
+ * bar one.
172
+ */
173
+ decode?: (text: string, file: File) => string | Promise<string>;
174
+ }
113
175
  /**
114
176
  * The import itself, over a file the caller ALREADY HAS: run the declared
115
177
  * capability (`docs/adr/0012`), write what it returned, bring it into view, and
@@ -147,7 +209,7 @@ export declare function runInterchangeImportFile(std: BlockStdScope, capability:
147
209
  * its refusals it was, so it is shown as it is rather than replaced with a
148
210
  * wording of our own that knows less.
149
211
  */
150
- export declare function importInterchangeFile(std: BlockStdScope, capability: InterchangeImportCapability, file: File): Promise<void>;
212
+ export declare function importInterchangeFile(std: BlockStdScope, capability: InterchangeImportCapability, file: File, options?: InterchangeImportOptions): Promise<void>;
151
213
  /**
152
214
  * Every registered importer, indexed by the extensions it declares.
153
215
  *
@@ -1,7 +1,7 @@
1
1
  import { ConnectorElementModel } from '../../affine-model/index.js';
2
- import { NotificationProvider, translateKey, } from '../../affine-shared/services/index.js';
2
+ import { fillPlaceholders, NotificationProvider, translateKey, } from '../../affine-shared/services/index.js';
3
3
  import { openSingleFileWithSpec } from '../../affine-shared/utils/index.js';
4
- import { getCommonBound } from '../../global/gfx/index.js';
4
+ import { Bound, getCommonBound } from '../../global/gfx/index.js';
5
5
  import { GfxControllerIdentifier } from '../../std/gfx/index.js';
6
6
  import { DefaultTool } from '../tool/default-tool.js';
7
7
  import { InterchangeImportError, interchangeCapabilities, } from './interchange.js';
@@ -55,17 +55,70 @@ import { InterchangeImportError, interchangeCapabilities, } from './interchange.
55
55
  * whole blob and `addElement` writes it with everything else, which is the
56
56
  * whole-record LWW the field's own contract asks for (D2).
57
57
  *
58
+ * ## The reader's OWN names, and why there is a second map
59
+ *
60
+ * A source id is the file's, and there are two things a reader has to point at
61
+ * that the file never named: an element it MINTED (a framework artefact is
62
+ * routinely several elements — a shape, its compartments, and the group that
63
+ * makes them one thing), and the group membership between them. So a reader may
64
+ * also hand each element a provisional `id` of its own. `surface.addElement`
65
+ * overwrites it with a nanoid and is documented to, which is precisely what
66
+ * makes it safe to use as a local name: it reaches no document, and it is read
67
+ * here and nowhere else.
68
+ *
69
+ * A GROUP's `children` are therefore rewritten BEFORE the group is created, out
70
+ * of the map built so far — which costs nothing and asks the reader for the one
71
+ * thing it can always give: emit an element before the group that holds it. A
72
+ * connector is the opposite case (a flow may be written before either of its
73
+ * ends) and keeps its second pass.
74
+ *
75
+ * Source ids win over provisional ones wherever both could answer, so a reader
76
+ * that mints no local name behaves exactly as it did before this was here.
77
+ *
78
+ * ## Beside what is already drawn
79
+ *
80
+ * A reader writes the coordinates its FILE gave it, so importing the same file
81
+ * twice put the second board exactly on top of the first. The offset is applied
82
+ * here, once, for every framework, because the only thing that knows what the
83
+ * canvas already holds is the function doing the writing — see
84
+ * {@link importOffset}, and note that an empty surface is left alone.
85
+ *
86
+ * ## A read-only document is answered, not thrown at
87
+ *
88
+ * This is a public API — a host (labre-mcp) writes through it with no command
89
+ * in front of it — so the guard belongs here too and not only at the callers:
90
+ * a readonly document answers the empty array, which is the same "nothing was
91
+ * minted" every other refusal of this function returns, rather than an
92
+ * exception a caller would have to know to catch.
93
+ *
58
94
  * @param formatId the format whose payload key carries the source ids — the
59
95
  * `id` of the capability's {@link InterchangeFormat}, and the ONLY thing this
60
96
  * function ever knew about BPMN.
61
97
  */
62
- export function materializeInterchangeImport(std, formatId, elements) {
98
+ export function materializeInterchangeImport(std, formatId, elements, options = {}) {
63
99
  const surface = std.get(GfxControllerIdentifier).surface;
64
100
  if (!surface)
65
101
  return [];
102
+ if (std.store.readonly)
103
+ return [];
104
+ const shift = importOffset(surface.elementModels, elements);
66
105
  const bySource = new Map();
106
+ const byLocal = new Map();
107
+ const resolve = (name) => bySource.get(name) ?? byLocal.get(name);
67
108
  const created = elements.map(props => {
68
- const id = surface.addElement({ ...props });
109
+ const written = shift
110
+ ? translateProps(props, shift)
111
+ : { ...props };
112
+ const children = written.children;
113
+ if (written.type === 'group' &&
114
+ children !== null &&
115
+ typeof children === 'object') {
116
+ written.children = Object.fromEntries(Object.keys(children).map(child => [
117
+ resolve(child) ?? child,
118
+ true,
119
+ ]));
120
+ }
121
+ const id = surface.addElement(written);
69
122
  const carried = props.interchange;
70
123
  const source = carried?.[formatId]?.id;
71
124
  // FIRST wins, matching a reader's own answer to a file that used one id
@@ -73,6 +126,31 @@ export function materializeInterchangeImport(std, formatId, elements) {
73
126
  // naming that id means the first of them.
74
127
  if (source !== undefined && !bySource.has(source))
75
128
  bySource.set(source, id);
129
+ const local = props.id;
130
+ if (typeof local === 'string') {
131
+ // FIRST wins here too, and for the same reason — but where a duplicated
132
+ // SOURCE id is the FILE's mistake and the reader has already reported it,
133
+ // a duplicated provisional name is the READER's, and nothing else in the
134
+ // pipeline is in a position to notice. So it is named: every element is
135
+ // still imported, and the remark says which of the two a group or a
136
+ // connector naming it will have landed on.
137
+ if (byLocal.has(local)) {
138
+ // The English is FILLED from the wording rather than restated beside
139
+ // it, so the sentence a host translates and the sentence a playground
140
+ // with no catalogue reads cannot drift apart.
141
+ const messageParams = { name: local };
142
+ options.onNote?.({
143
+ kind: 'substituted-id',
144
+ elementId: id,
145
+ messageKey: IMPORT_DUPLICATE_NAME_KEY,
146
+ message: fillPlaceholders(IMPORT_DUPLICATE_NAME_FALLBACK, messageParams),
147
+ messageParams,
148
+ });
149
+ }
150
+ else {
151
+ byLocal.set(local, id);
152
+ }
153
+ }
76
154
  return id;
77
155
  });
78
156
  for (const id of created) {
@@ -83,16 +161,129 @@ export function materializeInterchangeImport(std, formatId, elements) {
83
161
  const end = model[side];
84
162
  if (end?.id === undefined)
85
163
  continue;
86
- model[side] = { ...end, id: bySource.get(end.id) ?? end.id };
164
+ model[side] = { ...end, id: resolve(end.id) ?? end.id };
87
165
  }
88
166
  }
89
167
  return created;
90
168
  }
169
+ /* ── Beside what is already there ─────────────────────────────────────── */
170
+ /**
171
+ * The space left between a board that is already drawn and one just imported.
172
+ *
173
+ * Wide enough that the two read as two documents rather than as one crowded
174
+ * sheet, and narrow enough that the viewport fit which follows still shows the
175
+ * new one at a useful zoom.
176
+ */
177
+ const IMPORT_BESIDE_GAP = 200;
178
+ /** A box off one element's props, or nothing — `[x,y,w,h]`, as the store holds it. */
179
+ function propsBound(props) {
180
+ const xywh = props.xywh;
181
+ if (typeof xywh !== 'string')
182
+ return undefined;
183
+ try {
184
+ return Bound.deserialize(xywh);
185
+ }
186
+ catch {
187
+ return undefined;
188
+ }
189
+ }
190
+ /**
191
+ * How far to move an imported board so it lands BESIDE what is already drawn.
192
+ *
193
+ * ## Why this is the seam's job and not each reader's
194
+ *
195
+ * "What arrives is a NEW board, never a merge" is already this file's rule
196
+ * ({@link importInterchangeFile}) — but a reader has no surface to look at, so
197
+ * it writes the coordinates the FILE gave it, and a second import of the same
198
+ * file therefore landed exactly on top of the first. Every framework had the
199
+ * bug and none of them could fix it: the only thing that knows what the canvas
200
+ * already holds is the function doing the writing.
201
+ *
202
+ * `undefined` on an EMPTY surface, and deliberately: with nothing to avoid, the
203
+ * board keeps the file's own coordinates, which is what every golden and every
204
+ * round-trip assertion is written against. Only a second import moves, which is
205
+ * exactly the case that was wrong.
206
+ *
207
+ * Connectors are excluded from the measurement for the reason
208
+ * {@link importInterchangeFile} excludes them from the viewport fit: a
209
+ * connector's bound is derived from a path the router has not computed yet, and
210
+ * it answers `[0, 0, 0, 0]` — which would anchor every offset to the origin.
211
+ *
212
+ * The list is read defensively because a SURFACE is not the only thing that ever
213
+ * reaches this function: several framework specs drive the pipeline through a
214
+ * hand-built stub that answers `addElement` and little else. A stub with no
215
+ * elements is an empty canvas, which is the one case that must not move.
216
+ */
217
+ function importOffset(drawn, arriving) {
218
+ const occupied = getCommonBound((drawn ?? [])
219
+ .map(model => model.elementBound)
220
+ .filter((bound) => !!bound && bound.w > 0 && bound.h > 0));
221
+ if (!occupied)
222
+ return undefined;
223
+ const boxes = arriving
224
+ .map(propsBound)
225
+ .filter((bound) => bound !== undefined);
226
+ const incoming = getCommonBound(boxes);
227
+ if (!incoming)
228
+ return undefined;
229
+ return {
230
+ x: occupied.x + occupied.w + IMPORT_BESIDE_GAP - incoming.x,
231
+ y: occupied.y - incoming.y,
232
+ };
233
+ }
234
+ /**
235
+ * One element's props, moved.
236
+ *
237
+ * `xywh` and the label boxes, with one exception: a connector end that names no
238
+ * element carries an ABSOLUTE position rather than an anchor within a shape, and
239
+ * an end left behind would stretch the line back to where the file drew it. An
240
+ * end WITH an id carries a fraction of its shape's box and must not be touched.
241
+ *
242
+ * A connector's three label boxes (`labelXYWH`, and ADR 0020's two per-end
243
+ * siblings) are absolute `[x, y, w, h]` in the same space as `xywh`, so they
244
+ * move with everything else. A reader that creates a connector with an end label
245
+ * already positioned — `gfx/uml`'s materializer does — would otherwise drop the
246
+ * text at the origin of a board it was not imported onto.
247
+ */
248
+ function translateProps(props, shift) {
249
+ const moved = { ...props };
250
+ const bound = propsBound(props);
251
+ if (bound) {
252
+ moved.xywh = new Bound(bound.x + shift.x, bound.y + shift.y, bound.w, bound.h).serialize();
253
+ }
254
+ for (const key of ['labelXYWH', 'sourceLabelXYWH', 'targetLabelXYWH']) {
255
+ const box = props[key];
256
+ if (!Array.isArray(box) || box.length !== 4)
257
+ continue;
258
+ if (!box.every(each => typeof each === 'number'))
259
+ continue;
260
+ const [x, y, w, h] = box;
261
+ moved[key] = [x + shift.x, y + shift.y, w, h];
262
+ }
263
+ for (const side of ['source', 'target']) {
264
+ const end = props[side];
265
+ if (!end || end.id !== undefined || !Array.isArray(end.position))
266
+ continue;
267
+ moved[side] = {
268
+ ...end,
269
+ position: [end.position[0] + shift.x, end.position[1] + shift.y],
270
+ };
271
+ }
272
+ return moved;
273
+ }
91
274
  /* ── Saying what it cost ──────────────────────────────────────────────── */
92
275
  const IMPORT_DONE_KEY = 'com.labre.interchange.import.done';
93
276
  const IMPORT_DONE_FALLBACK = 'file imported';
94
277
  const IMPORT_FAILED_KEY = 'com.labre.interchange.import.failed';
95
278
  const IMPORT_FAILED_FALLBACK = 'This file could not be imported';
279
+ /**
280
+ * The document went read-only between the moment the file was accepted and the
281
+ * moment its board was about to be written — see the second guard in
282
+ * {@link importInterchangeFile}. Its own sentence rather than the reader's,
283
+ * because nothing is wrong with the FILE.
284
+ */
285
+ const IMPORT_READONLY_KEY = 'com.labre.interchange.import.readonly';
286
+ const IMPORT_READONLY_FALLBACK = 'This document became read-only while the file was being read, so nothing was imported.';
96
287
  const IMPORT_REMARKS_KEY = 'com.labre.interchange.import.remarks';
97
288
  const IMPORT_REMARKS_FALLBACK = 'What the import could not keep as it was';
98
289
  const IMPORT_CONSOLE_KEY = 'com.labre.interchange.import.console';
@@ -103,6 +294,16 @@ const IMPORT_CARRIED_KEY = 'com.labre.interchange.import.carried';
103
294
  const IMPORT_CARRIED_FALLBACK = 'carried';
104
295
  const IMPORT_QUARANTINED_KEY = 'com.labre.interchange.import.quarantined';
105
296
  const IMPORT_QUARANTINED_FALLBACK = 'quarantined';
297
+ /**
298
+ * The one remark the MATERIALIZER raises itself (see the provisional-name note
299
+ * on `SerializedElementProps`) — this pipeline's own words about its own
300
+ * substitution, not a reader's, so it is keyed here with the rest of the
301
+ * pipeline's chrome rather than in any one format's table. `{{name}}` is the
302
+ * provisional name the reader minted, filled from `messageParams` by
303
+ * `resolveNoteMessage` exactly as a reader's own remark is.
304
+ */
305
+ const IMPORT_DUPLICATE_NAME_KEY = 'com.labre.interchange.import.duplicate-provisional-name';
306
+ const IMPORT_DUPLICATE_NAME_FALLBACK = 'Two imported elements were handed the same provisional name "{{name}}". Both are on the board; anything referring to that name points at the first of them.';
106
307
  /**
107
308
  * How many remarks the second notification spells out before it hands the
108
309
  * reader to the console.
@@ -265,7 +466,7 @@ export function reportInterchangeImport(std, format, report) {
265
466
  * deliberately so: a dialog a document cannot honour should never open in the
266
467
  * first place.
267
468
  */
268
- export async function runInterchangeImportFile(std, capability) {
469
+ export async function runInterchangeImportFile(std, capability, options = {}) {
269
470
  const gfx = std.get(GfxControllerIdentifier);
270
471
  if (!gfx.surface || std.store.readonly)
271
472
  return;
@@ -278,7 +479,7 @@ export async function runInterchangeImportFile(std, capability) {
278
479
  // know what they just did.
279
480
  if (!file)
280
481
  return;
281
- await importInterchangeFile(std, capability, file);
482
+ await importInterchangeFile(std, capability, file, options);
282
483
  }
283
484
  /**
284
485
  * The import itself, over a file the caller ALREADY HAS: run the declared
@@ -317,14 +518,20 @@ export async function runInterchangeImportFile(std, capability) {
317
518
  * its refusals it was, so it is shown as it is rather than replaced with a
318
519
  * wording of our own that knows less.
319
520
  */
320
- export async function importInterchangeFile(std, capability, file) {
521
+ export async function importInterchangeFile(std, capability, file, options = {}) {
321
522
  const gfx = std.get(GfxControllerIdentifier);
322
523
  if (!gfx.surface || std.store.readonly)
323
524
  return;
324
525
  const { format } = capability;
325
526
  let result;
326
527
  try {
327
- result = capability.run(await file.text(), { name: file.name });
528
+ const text = await file.text();
529
+ // The container, opened — see {@link InterchangeImportOptions.decode}. Inside
530
+ // the same `try` as the reader, deliberately: "this .drawio could not be
531
+ // inflated" and "this is not a BPMN document" are the same event to the
532
+ // person who picked the file, and they take the same notification.
533
+ const source = options.decode ? await options.decode(text, file) : text;
534
+ result = capability.run(source, { name: file.name });
328
535
  }
329
536
  catch (error) {
330
537
  // `InterchangeImportError` checked FIRST: a reader that throws it declared
@@ -343,12 +550,33 @@ export async function importInterchangeFile(std, capability, file) {
343
550
  });
344
551
  return;
345
552
  }
553
+ // The guard at the top was a decision taken BEFORE two `await`s, and rights
554
+ // can be lost while they run: a remote cascade turning the store read-only
555
+ // between the picker and this line is the same class of defect as issue #324
556
+ // ("Cannot remove element in readonly mode"). Writing anyway rejects a
557
+ // promise nobody awaits, and returning in silence loses a file the user
558
+ // chose — so it is said, through the channel every other import failure uses.
559
+ if (std.store.readonly) {
560
+ notifyImport(std, {
561
+ title: translateKey(std, IMPORT_FAILED_KEY, IMPORT_FAILED_FALLBACK),
562
+ message: translateKey(std, IMPORT_READONLY_KEY, IMPORT_READONLY_FALLBACK),
563
+ accent: 'error',
564
+ });
565
+ return;
566
+ }
346
567
  // One undo step for the whole file, the way one lane gesture is one step:
347
568
  // `captureSync` before opens a boundary, the writes land inside it, and the
348
569
  // second one closes it. An import a user has to undo forty times is an import
349
570
  // they cannot undo.
571
+ // What the WRITING found that the reading could not: a provisional name the
572
+ // reader handed out twice. Collected here rather than pushed into the
573
+ // reader's own array, which is `readonly` and is the reader's statement about
574
+ // the file — this is a statement about the import.
575
+ const written = [];
350
576
  std.store.captureSync();
351
- const created = materializeInterchangeImport(std, format.id, result.elements);
577
+ const created = materializeInterchangeImport(std, format.id, result.elements, {
578
+ onNote: note => written.push(note),
579
+ });
352
580
  std.store.captureSync();
353
581
  // …and then bring it into view, which is what template insertion does for
354
582
  // the same reason: a board that landed off-screen looks like a command that
@@ -381,7 +609,9 @@ export async function importInterchangeFile(std, capability, file) {
381
609
  gfx.viewport.setViewportByBound(bound, [padding, padding, padding, padding], true);
382
610
  }
383
611
  gfx.tool.setTool(DefaultTool);
384
- reportInterchangeImport(std, format, result.report);
612
+ reportInterchangeImport(std, format, written.length === 0
613
+ ? result.report
614
+ : { ...result.report, notes: [...result.report.notes, ...written] });
385
615
  }
386
616
  /* ── What can read a file called this ─────────────────────────────────── */
387
617
  /**
@@ -69,6 +69,24 @@ export type InterchangeDirection = 'import' | 'export';
69
69
  * One element as it is handed to `surface.addElement` — the exact shape the
70
70
  * store already takes, so an importer's output is written with no translation
71
71
  * step in between and no live model in sight.
72
+ *
73
+ * ## The provisional `id`, and how a reader points at itself
74
+ *
75
+ * A reader names things the FILE named through `interchange[formatId].id`, and
76
+ * that is the identity `materializeInterchangeImport` remaps endpoints from. It
77
+ * is not enough on its own: a framework artefact is routinely several elements
78
+ * the file never mentioned — a shape, its compartment texts, and the group that
79
+ * makes them one thing — so a reader may also put an `id` of its own on each
80
+ * element. `surface.addElement` OVERWRITES it with a nanoid and is documented
81
+ * to, which is exactly what makes it safe as a local name: it reaches no
82
+ * document, it is read by the materializer and nowhere else, and it cannot
83
+ * collide with a real surface id. Two rules make it work — a reader emits an
84
+ * element BEFORE any group that holds it (a group's `children` are rewritten
85
+ * from the map built so far, in one pass, rather than deferred like a
86
+ * connector's two ends), and a SOURCE id wins wherever both could answer, so a
87
+ * reader that mints no local name behaves exactly as it did before this
88
+ * existed. A provisional name used twice resolves to the FIRST element that
89
+ * claimed it, and the import says so in a `substituted-id` note.
72
90
  */
73
91
  export type SerializedElementProps = Record<string, unknown> & {
74
92
  type: string;
@@ -0,0 +1,81 @@
1
+ import { type ChromeWording, type FrameworkElementEvent, type ToolbarAction } from '../../affine-shared/services/index.js';
2
+ import type { BlockStdScope, CommandOwner } from '../../std/index.js';
3
+ import { type TemplateResult } from 'lit';
4
+ /**
5
+ * The legend BUTTON — one factory and one emitter for every framework that has
6
+ * a legend, where there were seven copies of the same twenty lines.
7
+ *
8
+ * The legend deliberately stays a BUTTON and never becomes a command (PO
9
+ * arbitration of 27/08/2026, R6 of `docs/add-a-framework/02-framework-rules.md`):
10
+ * generating one belongs to a board you have SELECTED and to nothing else, so
11
+ * it is absent from the catalogue, the palette and Settings › Shortcuts — and
12
+ * the command registry's per-framework counts must not move because of it.
13
+ *
14
+ * The cost of staying outside `runCommand` is that the telemetry it owes is
15
+ * emitted by hand. {@link trackLegendCreated} is where, once, so the wire
16
+ * values cannot drift apart across seven files again.
17
+ */
18
+ /**
19
+ * The HISTORICAL PostHog value of the `framework` dimension — `context-map`,
20
+ * not `ddd-context-map`, and `event-storming`, not `ddd-event-storming`. Taken
21
+ * from the event's own closed union rather than restated, so a framework that
22
+ * never joined the taxonomy cannot be passed here by mistake.
23
+ */
24
+ export type LegendFramework = FrameworkElementEvent['framework'];
25
+ /**
26
+ * Contextual-toolbar glyph — "generate the legend of what is on this board".
27
+ * One icon because it is one gesture; the Core Domain chart has drawn this exact
28
+ * box-and-rows since its legend button shipped and the others borrowed it.
29
+ *
30
+ * `html` rather than `svg`: a toolbar action's `icon` is rendered as a
31
+ * standalone template, unlike the senior-button glyphs that are interpolated
32
+ * into an outer `<svg>`.
33
+ */
34
+ export declare const legendIcon: TemplateResult<1>;
35
+ /**
36
+ * The ONE `FrameworkLegendCreated` emission, with the wire values every
37
+ * framework's own button has been sending.
38
+ *
39
+ * `framework` is the HISTORICAL PostHog value (`FrameworkDescriptor.
40
+ * telemetryKey`): `context-map`, not `ddd-context-map`. It is a parameter and
41
+ * not derived from anything, because the two spellings differ for three of the
42
+ * eight frameworks and a prefix rule would quietly rename a metric.
43
+ */
44
+ export declare function trackLegendCreated(std: BlockStdScope, framework: LegendFramework, module: string): void;
45
+ export interface LegendToolbarActionOptions<M extends {
46
+ xywh: string;
47
+ }> {
48
+ /**
49
+ * Sort key inside the row, and NOT a constant across frameworks: the toolbar
50
+ * orders lexicographically by id, so a legend that must land after "remove a
51
+ * lane" is `c.legend` while C4's is `b.legend` and Wardley's `d.legend`.
52
+ * Defaults to `b.legend`, the commonest.
53
+ */
54
+ id?: string;
55
+ /** The board element this button documents — how it finds it in the selection. */
56
+ Model: abstract new (...args: any[]) => M;
57
+ /** Whose commands the rows are derived from. See {@link createBoardLegend}. */
58
+ owner: CommandOwner;
59
+ /** The HISTORICAL telemetry value. See {@link trackLegendCreated}. */
60
+ framework: LegendFramework;
61
+ /**
62
+ * The `module` dimension. Defaults to `` `${framework} toolbar` ``, which is
63
+ * what six of the seven buttons send; UML's is `uml toolbox` and says so.
64
+ */
65
+ module?: string;
66
+ tooltipWording?: ChromeWording;
67
+ icon?: TemplateResult;
68
+ }
69
+ /**
70
+ * The shared legend entry of a board's contextual toolbar.
71
+ *
72
+ * Registered by each framework in its OWN flag-gated module
73
+ * (`custom:affine:surface:<board>`), merged with `validationToolbarConfig`'s
74
+ * actions: a flavour may carry exactly one toolbar module, and generating a
75
+ * legend is tooling a flag may take away. What the gesture already WROTE is
76
+ * document content and keeps being painted with the flag off — the box is made
77
+ * of plain shapes, text and the framework's own always-on renderers.
78
+ */
79
+ export declare function legendToolbarAction<M extends {
80
+ xywh: string;
81
+ }>({ id, Model, owner, framework, module, tooltipWording, icon, }: LegendToolbarActionOptions<M>): ToolbarAction;