@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
@@ -34,16 +34,23 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
34
34
  };
35
35
  import { TextUtils } from '../../affine-block-surface/index.js';
36
36
  import { FontFamily, FontFamilyMap, FontStyle, FontWeight, } from '../../affine-model/index.js';
37
- import { FONT_STYLE_ITALIC, FONT_WEIGHT_LIGHT, FONT_WEIGHT_REGULAR, FONT_WEIGHT_SEMIBOLD, translateKey, } from '../../affine-shared/services/index.js';
37
+ import { FONT_STYLE_ITALIC, FONT_WEIGHT_BOLD, FONT_WEIGHT_LIGHT, FONT_WEIGHT_REGULAR, FONT_WEIGHT_SEMIBOLD, translateKey, } from '../../affine-shared/services/index.js';
38
38
  import { DoneIcon } from '@blocksuite/icons/lit';
39
39
  import { css, html, LitElement, nothing } from 'lit';
40
40
  import { property } from 'lit/decorators.js';
41
41
  import { join } from 'lit/directives/join.js';
42
42
  import { repeat } from 'lit/directives/repeat.js';
43
+ /**
44
+ * How each weight is named. The panel does not offer this list: it offers the
45
+ * faces the current family actually has loaded, and only borrows the wording
46
+ * from here — so a family that ships no 700 file simply never draws a Bold
47
+ * row.
48
+ */
43
49
  const FONT_WEIGHT_CHOOSE = [
44
50
  [FontWeight.Light, FONT_WEIGHT_LIGHT],
45
51
  [FontWeight.Regular, FONT_WEIGHT_REGULAR],
46
52
  [FontWeight.SemiBold, FONT_WEIGHT_SEMIBOLD],
53
+ [FontWeight.Bold, FONT_WEIGHT_BOLD],
47
54
  ];
48
55
  let EdgelessFontWeightAndStylePanel = (() => {
49
56
  let _classSuper = LitElement;
@@ -0,0 +1,42 @@
1
+ import { type RoughCanvas, ToolOverlay } from '../../affine-block-surface/index.js';
2
+ import type { Bound } from '../../global/gfx/index.js';
3
+ import type { GfxController, GfxPrimitiveElementModel } from '../../std/gfx/index.js';
4
+ /**
5
+ * The ghost an armed {@link ArtefactPlacementTool} leaves under the cursor: the
6
+ * artefact itself, painted by the very renderers that will paint it once it is
7
+ * placed, at full opacity (PO decision, 2026-09-16).
8
+ *
9
+ * The elements are DETACHED models (`createDetachedElement`), built once by the
10
+ * tool from the recording of the command — never per frame, and never in the
11
+ * document. Each frame only runs the renderers, in paint order.
12
+ *
13
+ * When nothing could be built — the recording threw, or recorded nothing the
14
+ * surface can build — the ghost falls back to what the tool can still promise:
15
+ * a dashed footprint and the command's label under it. A real preview carries
16
+ * its own words, so it gets no label.
17
+ *
18
+ * Like `ShapeOverlay`, everything is positioned from {@link ToolOverlay.x} /
19
+ * {@link ToolOverlay.y} — the cursor in model coordinates — and the recorded
20
+ * boxes are offsets around it, because the recording ran against a viewport
21
+ * whose centre was the origin. The same offset is what the placement re-applies
22
+ * for real.
23
+ */
24
+ export declare class ArtefactGhostOverlay extends ToolOverlay {
25
+ /** The footprint, relative to the cursor. */
26
+ bound: Bound;
27
+ /** What the command is called, in the reader's language. */
28
+ label: string;
29
+ /** The artefact's drawable elements, in paint order, with their renderer. */
30
+ private readonly _preview;
31
+ constructor(gfx: GfxController, bound: Bound, label: string, models?: GfxPrimitiveElementModel[]);
32
+ /** Whether the artefact itself is drawn, rather than the fallback box. */
33
+ get drawsArtefact(): boolean;
34
+ render(ctx: CanvasRenderingContext2D, rc: RoughCanvas): void;
35
+ /**
36
+ * What the surface's render loop does per element, with the cursor in place
37
+ * of the element's position: the context is already in model coordinates
38
+ * here, so the element's matrix is that transform moved to cursor + offset.
39
+ */
40
+ private _renderArtefact;
41
+ private _renderFootprint;
42
+ }
@@ -0,0 +1,100 @@
1
+ import { CanvasRenderer, ElementRendererIdentifier, ToolOverlay, } from '../../affine-block-surface/index.js';
2
+ import { ThemeProvider } from '../../affine-shared/services/index.js';
3
+ /** Gap between the bottom of the footprint and the baseline of the label. */
4
+ const LABEL_GAP = 16;
5
+ /** Label size in SCREEN pixels; divided by the zoom before it is drawn. */
6
+ const LABEL_SIZE = 12;
7
+ /**
8
+ * The ghost an armed {@link ArtefactPlacementTool} leaves under the cursor: the
9
+ * artefact itself, painted by the very renderers that will paint it once it is
10
+ * placed, at full opacity (PO decision, 2026-09-16).
11
+ *
12
+ * The elements are DETACHED models (`createDetachedElement`), built once by the
13
+ * tool from the recording of the command — never per frame, and never in the
14
+ * document. Each frame only runs the renderers, in paint order.
15
+ *
16
+ * When nothing could be built — the recording threw, or recorded nothing the
17
+ * surface can build — the ghost falls back to what the tool can still promise:
18
+ * a dashed footprint and the command's label under it. A real preview carries
19
+ * its own words, so it gets no label.
20
+ *
21
+ * Like `ShapeOverlay`, everything is positioned from {@link ToolOverlay.x} /
22
+ * {@link ToolOverlay.y} — the cursor in model coordinates — and the recorded
23
+ * boxes are offsets around it, because the recording ran against a viewport
24
+ * whose centre was the origin. The same offset is what the placement re-applies
25
+ * for real.
26
+ */
27
+ export class ArtefactGhostOverlay extends ToolOverlay {
28
+ constructor(gfx, bound, label, models = []) {
29
+ super(gfx);
30
+ this.bound = bound;
31
+ this.label = label;
32
+ // Resolved once: a type without a canvas renderer is skipped silently, as
33
+ // the surface's own render loop skips it.
34
+ this._preview = models.flatMap(model => {
35
+ const render = gfx.std.getOptional(ElementRendererIdentifier(model.type));
36
+ return render ? [{ model, render }] : [];
37
+ });
38
+ }
39
+ /** Whether the artefact itself is drawn, rather than the fallback box. */
40
+ get drawsArtefact() {
41
+ return this._preview.length > 0;
42
+ }
43
+ render(ctx, rc) {
44
+ ctx.globalAlpha = this.globalAlpha;
45
+ if (this.globalAlpha === 0)
46
+ return;
47
+ const renderer = this.gfx.surfaceComponent
48
+ ?.renderer;
49
+ if (this.drawsArtefact && renderer instanceof CanvasRenderer) {
50
+ this._renderArtefact(ctx, rc, renderer);
51
+ }
52
+ else {
53
+ this._renderFootprint(ctx);
54
+ }
55
+ }
56
+ /**
57
+ * What the surface's render loop does per element, with the cursor in place
58
+ * of the element's position: the context is already in model coordinates
59
+ * here, so the element's matrix is that transform moved to cursor + offset.
60
+ */
61
+ _renderArtefact(ctx, rc, renderer) {
62
+ const base = ctx.getTransform();
63
+ const viewportBound = this.gfx.viewport.viewportBounds;
64
+ for (const { model, render } of this._preview) {
65
+ const [x, y] = model.deserializedXYWH;
66
+ ctx.save();
67
+ ctx.globalAlpha = model.opacity ?? 1;
68
+ render(model, ctx, base.translate(this.x + x, this.y + y), renderer, rc, viewportBound);
69
+ ctx.restore();
70
+ }
71
+ }
72
+ _renderFootprint(ctx) {
73
+ const theme = this.gfx.std.get(ThemeProvider);
74
+ const stroke = theme.getCssVariableColor('--affine-primary-color');
75
+ const text = theme.getCssVariableColor('--affine-text-secondary-color');
76
+ // Chrome, not content: the outline and the label keep their size on screen
77
+ // whatever the zoom, the way the polygon tool's own indicators do.
78
+ const zoom = this.gfx.viewport.zoom;
79
+ const { bound } = this;
80
+ const x = this.x + bound.x;
81
+ const y = this.y + bound.y;
82
+ const radius = Math.min(8 / zoom, bound.w / 4, bound.h / 4);
83
+ ctx.save();
84
+ ctx.beginPath();
85
+ ctx.roundRect(x, y, bound.w, bound.h, radius);
86
+ ctx.strokeStyle = stroke;
87
+ ctx.lineWidth = 1.5 / zoom;
88
+ ctx.setLineDash([6 / zoom, 4 / zoom]);
89
+ ctx.stroke();
90
+ if (this.label) {
91
+ ctx.setLineDash([]);
92
+ ctx.font = `${LABEL_SIZE / zoom}px var(--affine-font-family, sans-serif)`;
93
+ ctx.fillStyle = text;
94
+ ctx.textAlign = 'center';
95
+ ctx.textBaseline = 'top';
96
+ ctx.fillText(this.label, x + bound.w / 2, y + bound.h + LABEL_GAP / zoom - LABEL_SIZE / zoom);
97
+ }
98
+ ctx.restore();
99
+ }
100
+ }
@@ -0,0 +1,100 @@
1
+ import { type AnyCommandDescriptor, type BlockStdScope, type CommandOwner, type PointerEventState } from '../../std/index.js';
2
+ import { BaseTool, type GfxController } from '../../std/gfx/index.js';
3
+ export type ArtefactPlacementOption = {
4
+ /** Whose senior menu armed this, and therefore whose row Shift+S walks. */
5
+ owner: CommandOwner;
6
+ command: AnyCommandDescriptor;
7
+ };
8
+ /**
9
+ * ONE tool for every framework's artefacts: pick one from a senior menu and it
10
+ * is not created, it is ARMED — a ghost follows the cursor and the click says
11
+ * where (PO decision, 2026-09-16).
12
+ *
13
+ * The shape tool has always worked this way, and a framework artefact is a
14
+ * shape the framework named. Before this, an artefact landed at the viewport
15
+ * centre whatever the author was looking at, and putting it where they meant it
16
+ * to go was a second gesture with a mouse held down.
17
+ *
18
+ * It is generic on purpose. Nothing here knows what a Wardley component or a
19
+ * BPMN gateway is: the armed {@link CommandDescriptor} carries its own label,
20
+ * its own creation body and its own telemetry, and the footprint is MEASURED by
21
+ * running that body against the recording fake (`recordAction`) rather than
22
+ * declared a second time. A ninth framework arms this tool by existing.
23
+ *
24
+ * What it deliberately does not do:
25
+ *
26
+ * - **Telemetry.** Arming and cycling emit nothing and record no usage, exactly
27
+ * as choosing a shape variant does. The one emission still happens where it
28
+ * always did — inside {@link runCommand}, at placement — so the numbers a
29
+ * framework already reports are unchanged, and a user who arms an artefact
30
+ * and changes their mind has not "used" it.
31
+ * - **Drag to size.** A framework artefact has a size its framework chose; the
32
+ * click places that size. Out of scope, deliberately.
33
+ */
34
+ export declare class ArtefactPlacementTool extends BaseTool<ArtefactPlacementOption> {
35
+ static toolName: string;
36
+ private _ghost;
37
+ private get _surfaceComponent();
38
+ activate(): void;
39
+ deactivate(): void;
40
+ clearOverlay(): void;
41
+ /**
42
+ * Record the armed command once, and hang its ghost off the cursor.
43
+ *
44
+ * Once per arming and per cycle, never per pointer move: the recording runs
45
+ * the command's whole creation body against a fake and the preview builds a
46
+ * model per element, which is cheap but not free — and neither can change
47
+ * between two mouse positions.
48
+ *
49
+ * An artefact made of connectors only gets no ghost at all: a connector is
50
+ * not previewed (PO decision, 2026-09-16), and the crosshair alone says the
51
+ * next click places something.
52
+ */
53
+ createOverlay(): void;
54
+ /**
55
+ * Place the artefact under the cursor.
56
+ *
57
+ * The command is not asked WHERE to create — every one of them creates around
58
+ * the viewport centre, and teaching eight frameworks' worth of actions to take
59
+ * a point would be the per-framework code this tool exists to avoid. So the
60
+ * command runs as it always has, and what it created is moved by the offset
61
+ * between the centre it aimed at and the point the user clicked. That offset
62
+ * is read BEFORE the run, because a command may move the viewport.
63
+ */
64
+ click(e: PointerEventState): void;
65
+ pointerMove(e: PointerEventState): void;
66
+ pointerOut(e: PointerEventState): void;
67
+ /** A framework artefact keeps the size its framework chose; a drag is a click. */
68
+ dragStart(_e: PointerEventState): void;
69
+ dragMove(_e: PointerEventState): void;
70
+ dragEnd(_e: PointerEventState): void;
71
+ }
72
+ /** The armed artefact, or `null` when the editor is on any other tool. */
73
+ export declare function armedArtefact(gfx: GfxController): ArtefactPlacementOption | null;
74
+ /** Arm `command`; the ghost appears with the next pointer move. */
75
+ export declare function armArtefact(gfx: GfxController, owner: CommandOwner, command: AnyCommandDescriptor): void;
76
+ /**
77
+ * The artefacts of one owner, in the order its senior menu shows them.
78
+ *
79
+ * The MENU's row and not the whole catalogue: cycling is a keyboard walk along
80
+ * a row of buttons the user is looking at, and a Shift+S that stepped onto an
81
+ * artefact filed away in the sidepanel would move the ghost with nothing on
82
+ * screen to explain it. An owner past the fourteen-slot cap therefore cycles
83
+ * through its thirteen ranked artefacts; the rest stay one catalogue away.
84
+ *
85
+ * `kind` is what decides, not the owner: an entry of kind `'tool'` — a link
86
+ * tool, the evolution arrow, the Wardley area polygon — arms a gesture of its
87
+ * own and has no footprint to ghost, so it is never armed here and never
88
+ * stepped onto.
89
+ */
90
+ export declare function artefactCommandsFor(std: BlockStdScope, owner: CommandOwner): AnyCommandDescriptor[];
91
+ /**
92
+ * Arm the artefact `dir` steps along the owner's row, wrapping at both ends.
93
+ * Returns false when nothing is armed, so a caller can fall through to whatever
94
+ * the keystroke means otherwise.
95
+ *
96
+ * An artefact armed from the catalogue is not in the row: a backwards step then
97
+ * enters on the row's last entry, a forwards one on its first — the same "enter
98
+ * from nothing" the open menu's highlight gives.
99
+ */
100
+ export declare function cycleArmedArtefact(gfx: GfxController, dir: 1 | -1): boolean;
@@ -0,0 +1,274 @@
1
+ import { DefaultTool, EXCLUDING_MOUSE_OUT_CLASS_LIST, recordAction, sortIndex, } from '../../affine-block-surface/index.js';
2
+ import { translateKey } from '../../affine-shared/services/index.js';
3
+ import { hasClassNameInList } from '../../affine-shared/utils/index.js';
4
+ import { Bound } from '../../global/gfx/index.js';
5
+ import { runCommand, } from '../../std/index.js';
6
+ import { BaseTool, GfxGroupLikeElementModel, } from '../../std/gfx/index.js';
7
+ import { seniorMenuSelection } from '../menu/senior-menu-selection.js';
8
+ import { ArtefactGhostOverlay } from './artefact-ghost-overlay.js';
9
+ import { collectCreated, translateCreated } from './translate-created.js';
10
+ /** The ghost of an artefact nobody could measure. */
11
+ const FALLBACK_FOOTPRINT = new Bound(-60, -30, 120, 60);
12
+ /**
13
+ * ONE tool for every framework's artefacts: pick one from a senior menu and it
14
+ * is not created, it is ARMED — a ghost follows the cursor and the click says
15
+ * where (PO decision, 2026-09-16).
16
+ *
17
+ * The shape tool has always worked this way, and a framework artefact is a
18
+ * shape the framework named. Before this, an artefact landed at the viewport
19
+ * centre whatever the author was looking at, and putting it where they meant it
20
+ * to go was a second gesture with a mouse held down.
21
+ *
22
+ * It is generic on purpose. Nothing here knows what a Wardley component or a
23
+ * BPMN gateway is: the armed {@link CommandDescriptor} carries its own label,
24
+ * its own creation body and its own telemetry, and the footprint is MEASURED by
25
+ * running that body against the recording fake (`recordAction`) rather than
26
+ * declared a second time. A ninth framework arms this tool by existing.
27
+ *
28
+ * What it deliberately does not do:
29
+ *
30
+ * - **Telemetry.** Arming and cycling emit nothing and record no usage, exactly
31
+ * as choosing a shape variant does. The one emission still happens where it
32
+ * always did — inside {@link runCommand}, at placement — so the numbers a
33
+ * framework already reports are unchanged, and a user who arms an artefact
34
+ * and changes their mind has not "used" it.
35
+ * - **Drag to size.** A framework artefact has a size its framework chose; the
36
+ * click places that size. Out of scope, deliberately.
37
+ */
38
+ export class ArtefactPlacementTool extends BaseTool {
39
+ constructor() {
40
+ super(...arguments);
41
+ this._ghost = null;
42
+ }
43
+ static { this.toolName = 'artefact-placement'; }
44
+ get _surfaceComponent() {
45
+ return this.gfx.surfaceComponent;
46
+ }
47
+ activate() {
48
+ this.createOverlay();
49
+ }
50
+ deactivate() {
51
+ this.clearOverlay();
52
+ }
53
+ clearOverlay() {
54
+ if (!this._ghost)
55
+ return;
56
+ this._ghost.dispose();
57
+ this._surfaceComponent?.renderer.removeOverlay(this._ghost);
58
+ this._ghost = null;
59
+ this._surfaceComponent?.renderer.refresh();
60
+ }
61
+ /**
62
+ * Record the armed command once, and hang its ghost off the cursor.
63
+ *
64
+ * Once per arming and per cycle, never per pointer move: the recording runs
65
+ * the command's whole creation body against a fake and the preview builds a
66
+ * model per element, which is cheap but not free — and neither can change
67
+ * between two mouse positions.
68
+ *
69
+ * An artefact made of connectors only gets no ghost at all: a connector is
70
+ * not previewed (PO decision, 2026-09-16), and the crosshair alone says the
71
+ * next click places something.
72
+ */
73
+ createOverlay() {
74
+ this.clearOverlay();
75
+ const { command } = this.activatedOption;
76
+ if (!command)
77
+ return;
78
+ const preview = previewOf(this.gfx, command);
79
+ if (!preview)
80
+ return;
81
+ this._ghost = new ArtefactGhostOverlay(this.gfx, preview.bound, translateKey(this.std, command.labelKey, command.labelFallback), preview.models);
82
+ this._surfaceComponent?.renderer.addOverlay(this._ghost);
83
+ }
84
+ /**
85
+ * Place the artefact under the cursor.
86
+ *
87
+ * The command is not asked WHERE to create — every one of them creates around
88
+ * the viewport centre, and teaching eight frameworks' worth of actions to take
89
+ * a point would be the per-framework code this tool exists to avoid. So the
90
+ * command runs as it always has, and what it created is moved by the offset
91
+ * between the centre it aimed at and the point the user clicked. That offset
92
+ * is read BEFORE the run, because a command may move the viewport.
93
+ */
94
+ click(e) {
95
+ const { command } = this.activatedOption;
96
+ this.clearOverlay();
97
+ if (!command)
98
+ return;
99
+ const { viewport } = this.gfx;
100
+ const [x, y] = viewport.toModelCoord(e.point.x, e.point.y);
101
+ const dx = x - viewport.centerX;
102
+ const dy = y - viewport.centerY;
103
+ this.doc.captureSync();
104
+ // THE bottleneck, not a shortcut past it: the placement is an invocation
105
+ // like any other, so `FrameworkElementAdded` and the usage measure are
106
+ // emitted exactly where they were before the tool existed.
107
+ const created = collectCreated(this.gfx, () => {
108
+ runCommand(this.std, command, {
109
+ surface: 'senior-menu',
110
+ source: 'toolbar:general',
111
+ });
112
+ });
113
+ const placed = translateCreated(this.gfx, created, dx, dy);
114
+ // `setTool` clears the selection, so the selection goes after it.
115
+ this.gfx.tool.setTool(DefaultTool);
116
+ if (placed.length) {
117
+ this.gfx.selection.set({ elements: placed, editing: false });
118
+ }
119
+ }
120
+ pointerMove(e) {
121
+ if (!this._ghost)
122
+ return;
123
+ if (this._ghost.globalAlpha === 0)
124
+ this._ghost.globalAlpha = 1;
125
+ const [x, y] = this.gfx.viewport.toModelCoord(e.x, e.y);
126
+ this._ghost.x = x;
127
+ this._ghost.y = y;
128
+ this._surfaceComponent?.refresh();
129
+ }
130
+ pointerOut(e) {
131
+ if (e.raw.relatedTarget &&
132
+ hasClassNameInList(e.raw.relatedTarget, EXCLUDING_MOUSE_OUT_CLASS_LIST))
133
+ return;
134
+ if (!this._ghost)
135
+ return;
136
+ this._ghost.globalAlpha = 0;
137
+ this._surfaceComponent?.refresh();
138
+ }
139
+ /** A framework artefact keeps the size its framework chose; a drag is a click. */
140
+ dragStart(_e) { }
141
+ dragMove(_e) { }
142
+ dragEnd(_e) { }
143
+ }
144
+ /**
145
+ * What the command would draw, recorded and BUILT by running it against
146
+ * nothing: its footprint, and a detached model per drawable element, in paint
147
+ * order. `null` when there is nothing to show but the crosshair.
148
+ *
149
+ * The recording's viewport centre is the origin, so every recorded box is
150
+ * already the offset around a real centre — and therefore around the cursor.
151
+ * The records go to `createDetachedElement` as they were handed to the CRUD,
152
+ * so a seed string becomes its `Y.Text` through the element's own `propsToY`,
153
+ * exactly as it will at insertion; the host's `TranslationProvider` makes the
154
+ * seeds come out in the author's language, as they will once placed.
155
+ *
156
+ * Skipped: connectors (never previewed) and group-likes, whose renderers draw
157
+ * selection chrome and look their children up in the document — the children
158
+ * are drawn on their own. A record the surface cannot build is skipped too.
159
+ *
160
+ * A command the fake cannot serve throws by design (it answers only the
161
+ * members creation actions touch); that is not an error worth a console line
162
+ * here, it just means the ghost falls back to a plain box rather than the tool
163
+ * refusing to arm. So does a recording in which nothing could be built.
164
+ */
165
+ function previewOf(gfx, command) {
166
+ let recorded;
167
+ try {
168
+ recorded = recordAction((std) => {
169
+ // An async body records nothing it does after its first `await`, and
170
+ // then fails on the fake: that late failure is the same "cannot
171
+ // preview", not an unhandled rejection in the console.
172
+ Promise.resolve(command.run(std, { surface: 'senior-menu', source: 'internal' })).catch(() => { });
173
+ }, { host: gfx.std });
174
+ }
175
+ catch {
176
+ return { bound: FALLBACK_FOOTPRINT, models: [] };
177
+ }
178
+ const { records } = recorded;
179
+ if (records.length > 0 && records.every(r => r['type'] === 'connector')) {
180
+ return null;
181
+ }
182
+ // Paint order as the surface derives it: a group's children sort under the
183
+ // group's own index, even though the group itself is not drawn.
184
+ const groupIndexMap = new Map();
185
+ for (const record of records) {
186
+ const children = record['children'];
187
+ if (record['type'] !== 'group' || typeof children !== 'object')
188
+ continue;
189
+ const group = { id: String(record['id']), index: String(record['index']) };
190
+ for (const childId of Object.keys(children ?? {})) {
191
+ groupIndexMap.set(childId, group);
192
+ }
193
+ }
194
+ const ordered = records
195
+ .map(record => ({
196
+ record,
197
+ id: String(record['id']),
198
+ index: String(record['index']),
199
+ }))
200
+ .sort((a, b) => sortIndex(a, b, groupIndexMap));
201
+ const { surface } = gfx;
202
+ const models = [];
203
+ for (const { record, id } of ordered) {
204
+ const type = String(record['type']);
205
+ const Ctor = surface?.getConstructor(type);
206
+ if (!surface ||
207
+ !Ctor ||
208
+ type === 'connector' ||
209
+ Ctor.prototype instanceof GfxGroupLikeElementModel) {
210
+ continue;
211
+ }
212
+ try {
213
+ models.push(surface.createDetachedElement({ ...record, type, id }));
214
+ }
215
+ catch {
216
+ // Unbuildable here means unpaintable here; the rest still draws.
217
+ }
218
+ }
219
+ return { bound: recorded.bound ?? FALLBACK_FOOTPRINT, models };
220
+ }
221
+ /** The armed artefact, or `null` when the editor is on any other tool. */
222
+ export function armedArtefact(gfx) {
223
+ const { toolType, options } = gfx.tool.currentToolOption$.value ?? {};
224
+ if (toolType?.toolName !== ArtefactPlacementTool.toolName)
225
+ return null;
226
+ const armed = options;
227
+ return armed?.command ? armed : null;
228
+ }
229
+ /** Arm `command`; the ghost appears with the next pointer move. */
230
+ export function armArtefact(gfx, owner, command) {
231
+ gfx.tool.setTool(ArtefactPlacementTool, { owner, command });
232
+ }
233
+ /**
234
+ * The artefacts of one owner, in the order its senior menu shows them.
235
+ *
236
+ * The MENU's row and not the whole catalogue: cycling is a keyboard walk along
237
+ * a row of buttons the user is looking at, and a Shift+S that stepped onto an
238
+ * artefact filed away in the sidepanel would move the ghost with nothing on
239
+ * screen to explain it. An owner past the fourteen-slot cap therefore cycles
240
+ * through its thirteen ranked artefacts; the rest stay one catalogue away.
241
+ *
242
+ * `kind` is what decides, not the owner: an entry of kind `'tool'` — a link
243
+ * tool, the evolution arrow, the Wardley area polygon — arms a gesture of its
244
+ * own and has no footprint to ghost, so it is never armed here and never
245
+ * stepped onto.
246
+ */
247
+ export function artefactCommandsFor(std, owner) {
248
+ return seniorMenuSelection(std, owner).commands.filter(command => command.kind === 'artefact');
249
+ }
250
+ /**
251
+ * Arm the artefact `dir` steps along the owner's row, wrapping at both ends.
252
+ * Returns false when nothing is armed, so a caller can fall through to whatever
253
+ * the keystroke means otherwise.
254
+ *
255
+ * An artefact armed from the catalogue is not in the row: a backwards step then
256
+ * enters on the row's last entry, a forwards one on its first — the same "enter
257
+ * from nothing" the open menu's highlight gives.
258
+ */
259
+ export function cycleArmedArtefact(gfx, dir) {
260
+ const armed = armedArtefact(gfx);
261
+ if (!armed)
262
+ return false;
263
+ const commands = artefactCommandsFor(gfx.std, armed.owner);
264
+ if (commands.length === 0)
265
+ return false;
266
+ const current = commands.findIndex(command => command.id === armed.command.id);
267
+ const next = current < 0
268
+ ? dir === 1
269
+ ? 0
270
+ : commands.length - 1
271
+ : (current + dir + commands.length) % commands.length;
272
+ armArtefact(gfx, armed.owner, commands[next]);
273
+ return true;
274
+ }
@@ -0,0 +1,3 @@
1
+ export * from './artefact-ghost-overlay.js';
2
+ export * from './artefact-placement-tool.js';
3
+ export * from './translate-created.js';
@@ -0,0 +1,3 @@
1
+ export * from './artefact-ghost-overlay.js';
2
+ export * from './artefact-placement-tool.js';
3
+ export * from './translate-created.js';
@@ -0,0 +1,25 @@
1
+ import type { GfxController } from '../../std/gfx/index.js';
2
+ /**
3
+ * Run `body` and report the ids of everything it put on the board — canvas
4
+ * elements and canvas blocks alike.
5
+ *
6
+ * Both subscriptions are synchronous: a Yjs observer fires when the transaction
7
+ * commits, inside the `addElement` / `addBlock` call, so an action that creates
8
+ * on the spot is fully accounted for by the time `body` returns. An action that
9
+ * creates from a promise is NOT, and its artefact is left where the command put
10
+ * it — which is today's behaviour for every command, so nothing regresses.
11
+ */
12
+ export declare function collectCreated(gfx: GfxController, body: () => void): string[];
13
+ /**
14
+ * Move a freshly created drawing by `(dx, dy)`, and report what is left to
15
+ * select.
16
+ *
17
+ * Only the TOP-LEVEL items move. An element the same run filed inside a group
18
+ * it also created is carried by that group, and moving it twice would tear the
19
+ * drawing apart. A group is moved through its children — `GfxGroupLikeElement`'s
20
+ * `xywh` setter is a deliberate no-op, its box being derived from what it holds
21
+ * — which is exactly what {@link updateXYWH} does, along with a connector's free
22
+ * endpoints (an anchored one simply follows what it is tied to) and a note's
23
+ * collapsed height. Hence no second opinion here.
24
+ */
25
+ export declare function translateCreated(gfx: GfxController, ids: string[], dx: number, dy: number): string[];
@@ -0,0 +1,67 @@
1
+ import { EdgelessCRUDIdentifier, updateXYWH, } from '../../affine-block-surface/index.js';
2
+ import { Bound } from '../../global/gfx/index.js';
3
+ /**
4
+ * Run `body` and report the ids of everything it put on the board — canvas
5
+ * elements and canvas blocks alike.
6
+ *
7
+ * Both subscriptions are synchronous: a Yjs observer fires when the transaction
8
+ * commits, inside the `addElement` / `addBlock` call, so an action that creates
9
+ * on the spot is fully accounted for by the time `body` returns. An action that
10
+ * creates from a promise is NOT, and its artefact is left where the command put
11
+ * it — which is today's behaviour for every command, so nothing regresses.
12
+ */
13
+ export function collectCreated(gfx, body) {
14
+ const ids = [];
15
+ const subscriptions = [
16
+ gfx.surface?.elementAdded.subscribe(({ id }) => {
17
+ ids.push(id);
18
+ }),
19
+ gfx.std.store.slots.blockUpdated.subscribe(payload => {
20
+ if (payload.type === 'add')
21
+ ids.push(payload.id);
22
+ }),
23
+ ];
24
+ try {
25
+ body();
26
+ }
27
+ finally {
28
+ subscriptions.forEach(subscription => subscription?.unsubscribe());
29
+ }
30
+ return ids;
31
+ }
32
+ /**
33
+ * Move a freshly created drawing by `(dx, dy)`, and report what is left to
34
+ * select.
35
+ *
36
+ * Only the TOP-LEVEL items move. An element the same run filed inside a group
37
+ * it also created is carried by that group, and moving it twice would tear the
38
+ * drawing apart. A group is moved through its children — `GfxGroupLikeElement`'s
39
+ * `xywh` setter is a deliberate no-op, its box being derived from what it holds
40
+ * — which is exactly what {@link updateXYWH} does, along with a connector's free
41
+ * endpoints (an anchored one simply follows what it is tied to) and a note's
42
+ * collapsed height. Hence no second opinion here.
43
+ */
44
+ export function translateCreated(gfx, ids, dx, dy) {
45
+ const created = new Set(ids);
46
+ const models = ids
47
+ .map(id => gfx.getElementById(id))
48
+ .filter((model) => !!model && 'xywh' in model);
49
+ const top = models.filter(model => !model.group || !created.has(model.group.id));
50
+ if (dx !== 0 || dy !== 0) {
51
+ const updateElement = gfx.std.get(EdgelessCRUDIdentifier).updateElement;
52
+ // Wrapped, not handed over: `Store.updateBlock` is a prototype method that
53
+ // reads `this.readonly` and `this._crud`. `updateXYWH` happens to re-bind it
54
+ // (`updateBlock.call(ele.store, …)`), so today nothing breaks — but an
55
+ // unbound method sitting in a variable is a landmine that reads correct, and
56
+ // the day that `.call` becomes a plain call the first canvas block placed
57
+ // would throw on `readonly` of undefined.
58
+ const updateBlock = (model, props) => gfx.std.store.updateBlock(model, props);
59
+ for (const model of top) {
60
+ const bound = Bound.deserialize(model.xywh);
61
+ bound.x += dx;
62
+ bound.y += dy;
63
+ updateXYWH(model, bound, updateElement, updateBlock);
64
+ }
65
+ }
66
+ return top.map(model => model.id);
67
+ }
@@ -3,6 +3,7 @@ import { artefactCatalogueDefaultExtension } from './catalogue/artefact-catalogu
3
3
  import { edgelessArtefactCatalogueWidget } from './catalogue/artefact-catalogue-widget.js';
4
4
  import { edgelessToolbarWidget } from './edgeless-toolbar.js';
5
5
  import { effects } from './effects.js';
6
+ import { ArtefactPlacementTool } from './placement/artefact-placement-tool.js';
6
7
  export class EdgelessToolbarViewExtension extends ViewExtensionProvider {
7
8
  constructor() {
8
9
  super(...arguments);
@@ -23,6 +24,10 @@ export class EdgelessToolbarViewExtension extends ViewExtensionProvider {
23
24
  // sidebar overrides the seam and the widget then never opens.
24
25
  context.register(edgelessArtefactCatalogueWidget);
25
26
  context.register(artefactCatalogueDefaultExtension);
27
+ // Unconditionally too, and for the same reason: the tool is generic
28
+ // chrome driven by whatever commands are registered, so a framework whose
29
+ // flag is off simply never arms it. See `docs/adr/0009`.
30
+ context.register(ArtefactPlacementTool);
26
31
  }
27
32
  }
28
33
  }