@formicoidea/labre-core 0.32.0 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/dist/_pkgs/affine-block-attachment/attachment-block.js +3 -3
  2. package/dist/_pkgs/affine-block-attachment/configs/toolbar.d.ts +2 -2
  3. package/dist/_pkgs/affine-block-attachment/configs/toolbar.js +9 -7
  4. package/dist/_pkgs/affine-block-bookmark/configs/toolbar.js +12 -12
  5. package/dist/_pkgs/affine-block-callout/callout-block.js +1 -1
  6. package/dist/_pkgs/affine-block-code/code-block-inline.js +1 -1
  7. package/dist/_pkgs/affine-block-code/code-block.js +2 -2
  8. package/dist/_pkgs/affine-block-code/code-toolbar/config.js +9 -1
  9. package/dist/_pkgs/affine-block-code/code-toolbar/index.js +1 -1
  10. package/dist/_pkgs/affine-block-database/data-source.js +1 -2
  11. package/dist/_pkgs/affine-block-database/database-block.js +2 -2
  12. package/dist/_pkgs/affine-block-database/external-data-source.js +1 -1
  13. package/dist/_pkgs/affine-block-edgeless-text/edgeless-text-block.js +1 -1
  14. package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/config.js +1 -1
  15. package/dist/_pkgs/affine-block-embed/common/render-linked-doc.js +3 -3
  16. package/dist/_pkgs/affine-block-embed/configs/toolbar.js +11 -11
  17. package/dist/_pkgs/affine-block-embed/embed-figma-block/embed-figma-service.js +1 -1
  18. package/dist/_pkgs/affine-block-embed/embed-html-block/configs/toolbar.js +5 -5
  19. package/dist/_pkgs/affine-block-embed/embed-iframe-block/configs/toolbar.d.ts +7 -7
  20. package/dist/_pkgs/affine-block-embed/embed-iframe-block/configs/toolbar.js +14 -14
  21. package/dist/_pkgs/affine-block-embed/embed-iframe-block/embed-iframe-block.js +2 -2
  22. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/configs/toolbar.js +10 -10
  23. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/embed-linked-doc-block.js +4 -4
  24. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/utils.js +1 -1
  25. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/components/embed-synced-doc-card.js +5 -4
  26. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/configs/toolbar.js +10 -10
  27. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/embed-synced-doc-block.js +1 -1
  28. package/dist/_pkgs/affine-block-frame/frame-manager.js +3 -1
  29. package/dist/_pkgs/affine-block-frame/frame-tool.js +1 -1
  30. package/dist/_pkgs/affine-block-frame/frame-toolbar.js +2 -2
  31. package/dist/_pkgs/affine-block-image/components/page-image-block.js +1 -1
  32. package/dist/_pkgs/affine-block-image/configs/toolbar.js +4 -4
  33. package/dist/_pkgs/affine-block-image/image-edgeless-block.js +1 -1
  34. package/dist/_pkgs/affine-block-list/utils/forward-delete.js +1 -1
  35. package/dist/_pkgs/affine-block-note/commands/select-block.js +1 -1
  36. package/dist/_pkgs/affine-block-note/commands/select-blocks-between.js +1 -1
  37. package/dist/_pkgs/affine-block-note/configs/toolbar.js +2 -2
  38. package/dist/_pkgs/affine-block-note/move-block.js +1 -1
  39. package/dist/_pkgs/affine-block-paragraph/utils/forward-delete.js +2 -2
  40. package/dist/_pkgs/affine-block-paragraph/utils/merge-with-prev.js +1 -1
  41. package/dist/_pkgs/affine-block-root/configs/toolbar.d.ts +6 -4
  42. package/dist/_pkgs/affine-block-root/configs/toolbar.js +6 -6
  43. package/dist/_pkgs/affine-block-root/edgeless/configs/toolbar/misc.d.ts +10 -10
  44. package/dist/_pkgs/affine-block-root/edgeless/configs/toolbar/misc.js +4 -4
  45. package/dist/_pkgs/affine-block-root/edgeless/configs/toolbar/more.d.ts +7 -7
  46. package/dist/_pkgs/affine-block-root/edgeless/configs/toolbar/more.js +9 -9
  47. package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.js +1 -1
  48. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.js +3 -1
  49. package/dist/_pkgs/affine-block-root/edgeless/utils/clipboard-utils.js +1 -1
  50. package/dist/_pkgs/affine-block-surface/adapters/markdown/element-adapter/type.js +1 -1
  51. package/dist/_pkgs/affine-block-surface/adapters/plain-text/element-adapter/type.js +1 -1
  52. package/dist/_pkgs/affine-block-surface/element-model/index.d.ts +18 -3
  53. package/dist/_pkgs/affine-block-surface/element-model/index.js +12 -2
  54. package/dist/_pkgs/affine-block-surface/extensions/audit.js +23 -6
  55. package/dist/_pkgs/affine-block-surface/extensions/crud-extension.js +10 -5
  56. package/dist/_pkgs/affine-block-surface/extensions/editor-anchored-panel.js +2 -1
  57. package/dist/_pkgs/affine-block-surface/extensions/element-renderer.js +1 -1
  58. package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +1 -1
  59. package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +4 -0
  60. package/dist/_pkgs/affine-block-surface/extensions/index.js +4 -0
  61. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.d.ts +172 -0
  62. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.js +404 -0
  63. package/dist/_pkgs/affine-block-surface/extensions/interchange.d.ts +323 -0
  64. package/dist/_pkgs/affine-block-surface/extensions/interchange.js +64 -0
  65. package/dist/_pkgs/affine-block-surface/extensions/map-quality-widget.js +61 -61
  66. package/dist/_pkgs/affine-block-surface/extensions/morph-toolbar.d.ts +248 -0
  67. package/dist/_pkgs/affine-block-surface/extensions/morph-toolbar.js +248 -0
  68. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.js +78 -80
  69. package/dist/_pkgs/affine-block-surface/extensions/reading.js +2 -2
  70. package/dist/_pkgs/affine-block-surface/extensions/spotlight.d.ts +21 -0
  71. package/dist/_pkgs/affine-block-surface/extensions/spotlight.js +17 -3
  72. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.d.ts +107 -0
  73. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.js +958 -0
  74. package/dist/_pkgs/affine-block-surface/extensions/validation.d.ts +809 -20
  75. package/dist/_pkgs/affine-block-surface/extensions/validation.js +1661 -50
  76. package/dist/_pkgs/affine-block-surface/extensions/violation-detail-widget.d.ts +50 -6
  77. package/dist/_pkgs/affine-block-surface/extensions/violation-detail-widget.js +129 -32
  78. package/dist/_pkgs/affine-block-surface/framework-background/def.d.ts +289 -0
  79. package/dist/_pkgs/affine-block-surface/framework-background/def.js +126 -1
  80. package/dist/_pkgs/affine-block-surface/framework-background/labels.d.ts +42 -2
  81. package/dist/_pkgs/affine-block-surface/framework-background/labels.js +80 -4
  82. package/dist/_pkgs/affine-block-surface/framework-background/renderer.js +172 -11
  83. package/dist/_pkgs/affine-block-surface/index.d.ts +1 -0
  84. package/dist/_pkgs/affine-block-surface/index.js +1 -0
  85. package/dist/_pkgs/affine-block-surface/renderer/element-highlight-overlay.d.ts +17 -0
  86. package/dist/_pkgs/affine-block-surface/renderer/element-highlight-overlay.js +66 -0
  87. package/dist/_pkgs/affine-block-surface/renderer/overlay.js +1 -1
  88. package/dist/_pkgs/affine-block-surface/view.js +5 -0
  89. package/dist/_pkgs/affine-block-surface-ref/configs/toolbar.js +4 -4
  90. package/dist/_pkgs/affine-block-surface-ref/portal/note.js +2 -2
  91. package/dist/_pkgs/affine-block-table/commands.js +1 -1
  92. package/dist/_pkgs/affine-components/edgeless-shape-color-picker/color-picker.js +1 -1
  93. package/dist/_pkgs/affine-components/embed-card-modal/embed-card-edit-modal.js +1 -1
  94. package/dist/_pkgs/affine-components/filterable-list/styles.js +1 -1
  95. package/dist/_pkgs/affine-components/highlight-dropdown-menu/highlight-duotone-icon.js +8 -8
  96. package/dist/_pkgs/affine-components/highlight-dropdown-menu/text-duotone-icon.js +11 -11
  97. package/dist/_pkgs/affine-components/icons/text.js +426 -426
  98. package/dist/_pkgs/affine-components/open-doc-dropdown-menu/dropdown-menu.d.ts +2 -0
  99. package/dist/_pkgs/affine-components/peek/peekable.js +1 -1
  100. package/dist/_pkgs/affine-components/resource/resource.js +2 -0
  101. package/dist/_pkgs/affine-components/toolbar/index.d.ts +1 -0
  102. package/dist/_pkgs/affine-components/toolbar/index.js +1 -0
  103. package/dist/_pkgs/affine-components/toolbar/menu-button.js +1 -1
  104. package/dist/_pkgs/affine-components/toolbar/picker-menu.d.ts +55 -0
  105. package/dist/_pkgs/affine-components/toolbar/picker-menu.js +47 -0
  106. package/dist/_pkgs/affine-components/view-dropdown-menu/dropdown-menu.js +27 -14
  107. package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.js +2 -2
  108. package/dist/_pkgs/affine-fragment-frame-panel/header/frame-panel-header.js +2 -2
  109. package/dist/_pkgs/affine-fragment-frame-panel/header/frames-setting-menu.js +1 -1
  110. package/dist/_pkgs/affine-fragment-outline/mobile-outline-panel.js +1 -1
  111. package/dist/_pkgs/affine-gfx-brush/toolbar/components/pen/pen-tool-button.js +1 -1
  112. package/dist/_pkgs/affine-gfx-connector/connector-manager.js +7 -10
  113. package/dist/_pkgs/affine-gfx-connector/connector-tool.d.ts +19 -1
  114. package/dist/_pkgs/affine-gfx-connector/connector-tool.js +10 -2
  115. package/dist/_pkgs/affine-gfx-connector/connector-watcher.js +1 -4
  116. package/dist/_pkgs/affine-gfx-connector/direction/direction-reveal.js +2 -1
  117. package/dist/_pkgs/affine-gfx-connector/direction/invert-direction.js +1 -3
  118. package/dist/_pkgs/affine-gfx-connector/element-renderer/index.js +1 -1
  119. package/dist/_pkgs/affine-gfx-connector/element-renderer/utils.js +1 -1
  120. package/dist/_pkgs/affine-gfx-connector/toolbar/config.js +1 -1
  121. package/dist/_pkgs/affine-gfx-mindmap/adapter/markdown/index.js +1 -1
  122. package/dist/_pkgs/affine-gfx-mindmap/adapter/utils.js +1 -1
  123. package/dist/_pkgs/affine-gfx-mindmap/templates/index.js +583 -4
  124. package/dist/_pkgs/affine-gfx-mindmap/toolbar/mindmap-menu.js +23 -23
  125. package/dist/_pkgs/affine-gfx-mindmap/toolbar/mindmap-tool-button.js +5 -1
  126. package/dist/_pkgs/affine-gfx-mindmap/view/utils.js +1 -1
  127. package/dist/_pkgs/affine-gfx-note/overlay/overlay.js +1 -1
  128. package/dist/_pkgs/affine-gfx-note/toolbar/note-senior-button.js +1 -1
  129. package/dist/_pkgs/affine-gfx-shape/consts.js +1 -1
  130. package/dist/_pkgs/affine-gfx-shape/draggable/shape-draggable.js +1 -1
  131. package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/polygon.js +17 -9
  132. package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/utils.js +8 -3
  133. package/dist/_pkgs/affine-gfx-shape/element-view.js +19 -12
  134. package/dist/_pkgs/affine-gfx-shape/overlay/polygon-drawing-overlay.js +1 -1
  135. package/dist/_pkgs/affine-gfx-shape/overlay/polygon-vertex-editing-overlay.js +12 -7
  136. package/dist/_pkgs/affine-gfx-shape/overlay/shape-overlay.js +1 -1
  137. package/dist/_pkgs/affine-gfx-shape/polygon-tool.js +4 -2
  138. package/dist/_pkgs/affine-gfx-shape/shape-tool.js +1 -1
  139. package/dist/_pkgs/affine-gfx-shape/text/edgeless-shape-text-editor.js +1 -3
  140. package/dist/_pkgs/affine-gfx-template/builtin/other.js +66 -17
  141. package/dist/_pkgs/affine-gfx-template/toolbar/overlay-scrollbar.js +1 -1
  142. package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.js +1 -1
  143. package/dist/_pkgs/affine-gfx-text/toolbar/actions.js +1 -1
  144. package/dist/_pkgs/affine-inline-link/command.js +1 -1
  145. package/dist/_pkgs/affine-inline-link/link-node/configs/toolbar.d.ts +4 -4
  146. package/dist/_pkgs/affine-inline-link/link-node/configs/toolbar.js +6 -6
  147. package/dist/_pkgs/affine-inline-preset/command/format-block.js +1 -1
  148. package/dist/_pkgs/affine-inline-preset/command/format-native.js +2 -2
  149. package/dist/_pkgs/affine-inline-preset/command/format-text.js +1 -1
  150. package/dist/_pkgs/affine-inline-preset/inline-spec.js +1 -1
  151. package/dist/_pkgs/affine-inline-reference/reference-node/configs/toolbar.d.ts +4 -4
  152. package/dist/_pkgs/affine-inline-reference/reference-node/configs/toolbar.js +6 -6
  153. package/dist/_pkgs/affine-inline-reference/reference-node/reference-node.js +1 -1
  154. package/dist/_pkgs/affine-model/elements/bpmn/node.d.ts +40 -7
  155. package/dist/_pkgs/affine-model/elements/bpmn/node.js +4 -2
  156. package/dist/_pkgs/affine-model/elements/bpmn/pool.d.ts +135 -17
  157. package/dist/_pkgs/affine-model/elements/bpmn/pool.js +148 -26
  158. package/dist/_pkgs/affine-model/elements/c4/board.d.ts +88 -0
  159. package/dist/_pkgs/affine-model/elements/c4/board.js +128 -0
  160. package/dist/_pkgs/affine-model/elements/c4/boundary.d.ts +63 -0
  161. package/dist/_pkgs/affine-model/elements/c4/boundary.js +134 -0
  162. package/dist/_pkgs/affine-model/elements/c4/index.d.ts +3 -0
  163. package/dist/_pkgs/affine-model/elements/c4/index.js +3 -0
  164. package/dist/_pkgs/affine-model/elements/c4/node.d.ts +97 -0
  165. package/dist/_pkgs/affine-model/elements/c4/node.js +130 -0
  166. package/dist/_pkgs/affine-model/elements/connector/connector.js +1 -1
  167. package/dist/_pkgs/affine-model/elements/context-map/context-map.d.ts +27 -0
  168. package/dist/_pkgs/affine-model/elements/context-map/context-map.js +94 -0
  169. package/dist/_pkgs/affine-model/elements/context-map/index.d.ts +1 -0
  170. package/dist/_pkgs/affine-model/elements/context-map/index.js +1 -0
  171. package/dist/_pkgs/affine-model/elements/core-domain/core-domain.d.ts +34 -17
  172. package/dist/_pkgs/affine-model/elements/core-domain/core-domain.js +28 -26
  173. package/dist/_pkgs/affine-model/elements/cynefin/cynefin.d.ts +7 -2
  174. package/dist/_pkgs/affine-model/elements/cynefin/cynefin.js +9 -4
  175. package/dist/_pkgs/affine-model/elements/edgy/board.d.ts +7 -2
  176. package/dist/_pkgs/affine-model/elements/edgy/board.js +9 -4
  177. package/dist/_pkgs/affine-model/elements/edgy/facets.d.ts +20 -3
  178. package/dist/_pkgs/affine-model/elements/edgy/facets.js +13 -4
  179. package/dist/_pkgs/affine-model/elements/estuarine/estuarine.d.ts +7 -2
  180. package/dist/_pkgs/affine-model/elements/estuarine/estuarine.js +9 -4
  181. package/dist/_pkgs/affine-model/elements/event-storming/event-storming.d.ts +36 -0
  182. package/dist/_pkgs/affine-model/elements/event-storming/event-storming.js +103 -0
  183. package/dist/_pkgs/affine-model/elements/event-storming/index.d.ts +1 -0
  184. package/dist/_pkgs/affine-model/elements/event-storming/index.js +1 -0
  185. package/dist/_pkgs/affine-model/elements/framework-background/background.d.ts +7 -2
  186. package/dist/_pkgs/affine-model/elements/framework-background/background.js +9 -4
  187. package/dist/_pkgs/affine-model/elements/framework-background/hit-test.d.ts +48 -0
  188. package/dist/_pkgs/affine-model/elements/framework-background/hit-test.js +55 -0
  189. package/dist/_pkgs/affine-model/elements/framework-background/index.d.ts +1 -0
  190. package/dist/_pkgs/affine-model/elements/framework-background/index.js +1 -0
  191. package/dist/_pkgs/affine-model/elements/index.d.ts +11 -0
  192. package/dist/_pkgs/affine-model/elements/index.js +3 -0
  193. package/dist/_pkgs/affine-model/elements/shape/api/polygon.js +2 -8
  194. package/dist/_pkgs/affine-shared/adapters/html/block-adapter.js +1 -1
  195. package/dist/_pkgs/affine-shared/adapters/markdown/block-adapter.js +1 -1
  196. package/dist/_pkgs/affine-shared/adapters/markdown/delta-converter.js +1 -1
  197. package/dist/_pkgs/affine-shared/adapters/notion-html/block-adapter.js +1 -1
  198. package/dist/_pkgs/affine-shared/adapters/notion-html/delta-converter.js +1 -1
  199. package/dist/_pkgs/affine-shared/adapters/plain-text/block-adapter.js +1 -1
  200. package/dist/_pkgs/affine-shared/adapters/plain-text/delta-converter.js +1 -1
  201. package/dist/_pkgs/affine-shared/adapters/utils/color.js +5 -2
  202. package/dist/_pkgs/affine-shared/commands/model-crud/draft-selected-models.js +1 -1
  203. package/dist/_pkgs/affine-shared/commands/selection/focus-block-end.js +1 -1
  204. package/dist/_pkgs/affine-shared/commands/selection/focus-block-start.js +1 -1
  205. package/dist/_pkgs/affine-shared/consts/index.d.ts +10 -0
  206. package/dist/_pkgs/affine-shared/consts/index.js +10 -0
  207. package/dist/_pkgs/affine-shared/services/artefact-catalogue-service.d.ts +55 -0
  208. package/dist/_pkgs/affine-shared/services/artefact-catalogue-service.js +35 -0
  209. package/dist/_pkgs/affine-shared/services/audit-service.d.ts +11 -0
  210. package/dist/_pkgs/affine-shared/services/command-usage-service.d.ts +31 -0
  211. package/dist/_pkgs/affine-shared/services/command-usage-service.js +109 -0
  212. package/dist/_pkgs/affine-shared/services/comment-service/block-comment-manager.js +1 -1
  213. package/dist/_pkgs/affine-shared/services/doc-display-meta-service.js +1 -1
  214. package/dist/_pkgs/affine-shared/services/edit-props-store.d.ts +11 -0
  215. package/dist/_pkgs/affine-shared/services/edit-props-store.js +15 -0
  216. package/dist/_pkgs/affine-shared/services/embed-iframe/embed-iframe-config.js +1 -1
  217. package/dist/_pkgs/affine-shared/services/index.d.ts +2 -0
  218. package/dist/_pkgs/affine-shared/services/index.js +2 -0
  219. package/dist/_pkgs/affine-shared/services/pivot-materiality-publisher.js +2 -1
  220. package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +73 -1
  221. package/dist/_pkgs/affine-shared/services/toolbar-service/action.d.ts +32 -0
  222. package/dist/_pkgs/affine-shared/services/toolbar-service/action.js +16 -0
  223. package/dist/_pkgs/affine-shared/services/toolbar-service/flags.d.ts +10 -0
  224. package/dist/_pkgs/affine-shared/services/toolbar-service/flags.js +32 -1
  225. package/dist/_pkgs/affine-shared/services/toolbar-service/registry.d.ts +44 -0
  226. package/dist/_pkgs/affine-shared/services/toolbar-service/registry.js +161 -3
  227. package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +106 -0
  228. package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +201 -0
  229. package/dist/_pkgs/affine-shared/services/translation-service/index.d.ts +1 -0
  230. package/dist/_pkgs/affine-shared/services/translation-service/index.js +1 -0
  231. package/dist/_pkgs/affine-shared/services/universe-tag-defs-service.js +5 -3
  232. package/dist/_pkgs/affine-shared/test-utils/affine-template.js +1 -1
  233. package/dist/_pkgs/affine-shared/utils/edgeless.js +1 -1
  234. package/dist/_pkgs/affine-shared/utils/file/filesys.d.ts +34 -0
  235. package/dist/_pkgs/affine-shared/utils/file/filesys.js +48 -7
  236. package/dist/_pkgs/affine-shared/utils/zod-schema.js +1 -3
  237. package/dist/_pkgs/affine-widget-drag-handle/utils.js +1 -1
  238. package/dist/_pkgs/affine-widget-edgeless-auto-connect/index.js +1 -1
  239. package/dist/_pkgs/affine-widget-edgeless-dragging-area/edgeless-dragging-area-rect.js +1 -1
  240. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-default.d.ts +14 -0
  241. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-default.js +40 -0
  242. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.d.ts +158 -0
  243. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.js +572 -0
  244. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/catalogue-groups.d.ts +41 -0
  245. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/catalogue-groups.js +49 -0
  246. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/chord-format.d.ts +13 -0
  247. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/chord-format.js +50 -0
  248. package/dist/_pkgs/affine-widget-edgeless-toolbar/edgeless-toolbar.d.ts +6 -0
  249. package/dist/_pkgs/affine-widget-edgeless-toolbar/edgeless-toolbar.js +15 -5
  250. package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.d.ts +2 -0
  251. package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.js +2 -0
  252. package/dist/_pkgs/affine-widget-edgeless-toolbar/extension/index.d.ts +7 -0
  253. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.d.ts +4 -0
  254. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.js +4 -0
  255. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.d.ts +19 -0
  256. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.js +51 -10
  257. package/dist/_pkgs/affine-widget-edgeless-toolbar/view.js +9 -0
  258. package/dist/_pkgs/affine-widget-keyboard-toolbar/config.js +2 -1
  259. package/dist/_pkgs/affine-widget-keyboard-toolbar/icons.js +98 -98
  260. package/dist/_pkgs/affine-widget-keyboard-toolbar/keyboard-tool-panel.js +1 -1
  261. package/dist/_pkgs/affine-widget-linked-doc/import-doc/import-doc.js +1 -1
  262. package/dist/_pkgs/affine-widget-linked-doc/linked-doc-popover.js +1 -1
  263. package/dist/_pkgs/affine-widget-page-dragging-area/index.js +1 -1
  264. package/dist/_pkgs/affine-widget-remote-selection/doc/doc-remote-selection.js +1 -1
  265. package/dist/_pkgs/affine-widget-slash-menu/config.js +2 -1
  266. package/dist/_pkgs/affine-widget-toolbar/toolbar.js +11 -2
  267. package/dist/_pkgs/affine-widget-toolbar/utils.d.ts +19 -2
  268. package/dist/_pkgs/affine-widget-toolbar/utils.js +28 -9
  269. package/dist/_pkgs/data-view/core/group-by/renderer/boolean-group.js +11 -11
  270. package/dist/_pkgs/data-view/core/utils/menu-title.js +17 -17
  271. package/dist/_pkgs/data-view/view-presets/calendar/pc/actions.js +8 -12
  272. package/dist/_pkgs/data-view/view-presets/calendar/pc/view.js +52 -40
  273. package/dist/_pkgs/data-view/view-presets/table/mobile/group.js +3 -1
  274. package/dist/_pkgs/data-view/view-presets/table/pc/group.js +3 -1
  275. package/dist/_pkgs/data-view/view-presets/table/pc-virtual/group/top/group-title.js +18 -18
  276. package/dist/_pkgs/std/clipboard/utils.js +4 -1
  277. package/dist/_pkgs/std/extension/command-registry.d.ts +195 -5
  278. package/dist/_pkgs/std/extension/command-registry.js +218 -4
  279. package/dist/_pkgs/std/extension/shortcut.js +2 -1
  280. package/dist/_pkgs/std/extension/translation-manifest.d.ts +46 -1
  281. package/dist/_pkgs/std/extension/translation-manifest.js +58 -0
  282. package/dist/_pkgs/std/gfx/grid.js +1 -1
  283. package/dist/_pkgs/std/gfx/highlight.d.ts +84 -0
  284. package/dist/_pkgs/std/gfx/highlight.js +112 -0
  285. package/dist/_pkgs/std/gfx/index.d.ts +2 -1
  286. package/dist/_pkgs/std/gfx/index.js +1 -0
  287. package/dist/_pkgs/std/gfx/interactivity/gfx-view-event-handler.js +17 -3
  288. package/dist/_pkgs/std/gfx/model/surface/element-model.d.ts +160 -0
  289. package/dist/_pkgs/std/gfx/model/surface/element-model.js +75 -1
  290. package/dist/_pkgs/std/gfx/model/surface/role.js +5 -3
  291. package/dist/_pkgs/std/gfx/model/surface/surface-model.js +2 -1
  292. package/dist/_pkgs/std/gfx/selection.js +1 -1
  293. package/dist/_pkgs/std/gfx/viewport.js +1 -1
  294. package/dist/_pkgs/std/inline/extensions/inline-manager.js +1 -1
  295. package/dist/_pkgs/std/inline/extensions/markdown-matcher.js +1 -1
  296. package/dist/_pkgs/std/scope/std-scope.d.ts +2 -1
  297. package/dist/_pkgs/std/scope/std-scope.js +2 -0
  298. package/dist/_pkgs/std/utils/gfx.js +2 -0
  299. package/dist/_pkgs/store/model/store/crud.js +4 -1
  300. package/dist/commands.js +1 -1
  301. package/dist/extensions/command-usage.d.ts +23 -0
  302. package/dist/extensions/command-usage.js +37 -0
  303. package/dist/extensions/view.js +12 -0
  304. package/dist/frameworks.js +32 -0
  305. package/dist/shortcuts.d.ts +20 -6
  306. package/dist/shortcuts.js +7 -9
  307. package/dist/translations.js +98 -3
  308. package/package.json +13 -1
@@ -12,7 +12,7 @@ import { type ShortcutDescriptor, type ShortcutScope } from './shortcut.js';
12
12
  */
13
13
  export type ElementCreationSource = 'shortcut' | 'toolbar:general' | 'toolbar:dnd' | 'canvas:drop' | 'canvas:draw' | 'canvas:dbclick' | 'canvas:paste' | 'context-menu' | 'ai' | 'internal' | 'conversation' | 'manually save';
14
14
  /**
15
- * The seven framework modules that own commands. An EXPLICIT list, not a
15
+ * The eight framework modules that own commands. An EXPLICIT list, not a
16
16
  * subset assertion over `OPTIONAL_BLOCKS`: that list mixes frameworks with
17
17
  * plain blocks. `packages/affine/all/src/frameworks.ts` asserts that every id
18
18
  * here is a real flag key (`satisfies readonly OptionalBlock[]`).
@@ -20,7 +20,7 @@ export type ElementCreationSource = 'shortcut' | 'toolbar:general' | 'toolbar:dn
20
20
  * `ddd-aggregate` is deliberately absent: it ships DDD *templates* only — no
21
21
  * senior button, no commands — so it is a packaging bundle, not a framework.
22
22
  */
23
- export declare const FRAMEWORK_IDS: readonly ["wardley", "edgy", "cynefin-estuarine", "bpmn", "ddd-event-storming", "ddd-core-domain", "ddd-context-map"];
23
+ export declare const FRAMEWORK_IDS: readonly ["wardley", "edgy", "cynefin-estuarine", "bpmn", "c4", "ddd-event-storming", "ddd-core-domain", "ddd-context-map"];
24
24
  export type FrameworkId = (typeof FRAMEWORK_IDS)[number];
25
25
  export type CommandOwner = 'core' | FrameworkId;
26
26
  /**
@@ -204,6 +204,13 @@ export interface FrameworkDescriptor {
204
204
  id: FrameworkId;
205
205
  /** Replaces the raw English `SeniorTool.name`. */
206
206
  labelKey: string;
207
+ /**
208
+ * The English wording behind {@link labelKey} — what a standalone editor
209
+ * shows and what every restatement of the name (senior button, tooltip)
210
+ * must agree with. Carried HERE so the manifest knows the fallback and the
211
+ * drift check can hold the restatements to it.
212
+ */
213
+ labelFallback: string;
207
214
  iconKey: string;
208
215
  order?: number;
209
216
  /** First keystroke of this framework's chords — allocated, not ad hoc. */
@@ -248,6 +255,37 @@ export type CommandTelemetryReporter = (report: {
248
255
  invocation: CommandInvocation;
249
256
  }) => void;
250
257
  export declare const CommandTelemetryIdentifier: import("../../global/di/types.js").ServiceIdentifier<CommandTelemetryReporter> & (<U extends CommandTelemetryReporter = CommandTelemetryReporter>(variant: import("../../global/di/types.js").ServiceVariant) => import("../../global/di/types.js").ServiceIdentifier<U>);
258
+ /** What a {@link CommandUsageStore} knows about one command. */
259
+ export interface CommandUsageStats {
260
+ count: number;
261
+ lastUsedAt: number;
262
+ }
263
+ /**
264
+ * Per-user recency and frequency, measured at the same bottleneck telemetry is
265
+ * emitted from — and deliberately NOT the same thing.
266
+ *
267
+ * Telemetry is analytics: it leaves for a product dashboard, it only covers
268
+ * commands that declare a `telemetry` field, and no in-editor decision may
269
+ * depend on it. Usage is local state read back BY the editor: PF6 shows only
270
+ * thirteen of a framework's commands in the senior sub-menu once the framework
271
+ * has more than fourteen artefacts, ranked as "seven most-recent + six
272
+ * most-used" (PO re-arbitration of 2026-08-28, superseding the 4 + 3 of
273
+ * 2026-08-26). That ranking needs a measure for EVERY command — a `core` action, a
274
+ * self-emitting one, one nobody ever thought to instrument — so the record call
275
+ * sits outside the telemetry condition and stays there.
276
+ *
277
+ * ADR 0008 listed this as an open question ("needs a host-side usage store; the
278
+ * registry only needs to accept an injected comparator"). This identifier is
279
+ * the measurement half of that answer; the selection half is
280
+ * {@link selectSeniorMenuCommands}.
281
+ */
282
+ export interface CommandUsageStore {
283
+ /** One invocation happened. Called by {@link runCommand}, best-effort. */
284
+ record(command: AnyCommandDescriptor, invocation: CommandInvocation): void;
285
+ /** `undefined` when the command was never invoked by this user. */
286
+ statsOf(commandId: string): CommandUsageStats | undefined;
287
+ }
288
+ export declare const CommandUsageIdentifier: import("../../global/di/types.js").ServiceIdentifier<CommandUsageStore> & (<U extends CommandUsageStore = CommandUsageStore>(variant: import("../../global/di/types.js").ServiceVariant) => import("../../global/di/types.js").ServiceIdentifier<U>);
251
289
  /**
252
290
  * Mirrors `GfxSelectionManager.editing` without importing `@labre/std/gfx`
253
291
  * (which would close an import cycle through `extension/`): the gfx manager
@@ -272,9 +310,9 @@ export declare const isEditingOnCanvas: (std: BlockStdScope) => boolean;
272
310
  export declare function isCommandAvailable(std: BlockStdScope, command: AnyCommandDescriptor): boolean;
273
311
  /**
274
312
  * THE bottleneck: the one place a command runs, and therefore the one place
275
- * its telemetry is emitted. Every surface (sub-menu, shortcut, palette,
276
- * sidepanel, agent) goes through here, which is what removes the per-menu
277
- * `track()` duplicates.
313
+ * its telemetry is emitted and its usage measured. Every surface (sub-menu,
314
+ * shortcut, palette, sidepanel, agent) goes through here, which is what removes
315
+ * the per-menu `track()` duplicates.
278
316
  */
279
317
  export declare function runCommand(std: BlockStdScope, command: AnyCommandDescriptor, invocation: CommandInvocation, params?: unknown): void;
280
318
  /**
@@ -287,6 +325,42 @@ export declare function runCommand(std: BlockStdScope, command: AnyCommandDescri
287
325
  * verbatim, which is what keeps hosts' persisted v0.29 override tables valid.
288
326
  */
289
327
  export declare function toShortcutDescriptor(command: AnyCommandDescriptor): ShortcutDescriptor;
328
+ /**
329
+ * The DATA-ONLY shortcut projection: what a host's Settings › Shortcuts pane
330
+ * reads to draw a row, and nothing else. No `handler`, no `run`, no `params` —
331
+ * so a module holding these entries carries no reference to the action graph
332
+ * behind the command and can be published on its own subpath (each framework
333
+ * bundle's `./commands-manifest`).
334
+ *
335
+ * It is the SIX fields the panel needs. `labelFallback` is one of them and that
336
+ * is deliberate: the projection used to drop it, which left a host with no
337
+ * catalogue rendering raw i18n keys for the rows it could not translate, and
338
+ * forced every host to re-project from the main entry to recover a wording the
339
+ * library already knew.
340
+ *
341
+ * `owner` is a {@link CommandOwner} rather than `ShortcutDescriptor`'s open
342
+ * `string`: the panel groups by owner, and the closed union is what makes that
343
+ * grouping exhaustive host-side.
344
+ */
345
+ export interface ShortcutManifestEntry {
346
+ id: string;
347
+ labelKey: string;
348
+ /** English default behind {@link labelKey}; see {@link CommandDescriptor.labelFallback}. */
349
+ labelFallback?: string;
350
+ defaultKeys: {
351
+ mac: string[];
352
+ other: string[];
353
+ };
354
+ scope: ShortcutScope;
355
+ owner: CommandOwner;
356
+ }
357
+ /**
358
+ * The third permanent projection out of {@link CommandDescriptor}, beside
359
+ * {@link toShortcutDescriptor} and {@link toCommandManifestEntry}. TOTAL for
360
+ * the same reason the shortcut descriptor is: a keyless command still yields a
361
+ * row, so Settings › Shortcuts can bind it.
362
+ */
363
+ export declare function toShortcutManifestEntry(command: AnyCommandDescriptor): ShortcutManifestEntry;
290
364
  /**
291
365
  * Project a command's zod parameter contract onto the serializable seam, so the
292
366
  * `'agent'` surface is usable end to end: without it an agent reading the
@@ -317,5 +391,121 @@ export declare function getRegisteredCommands(std: BlockStdScope): AnyCommandDes
317
391
  * button list anywhere.
318
392
  */
319
393
  export declare function getCommandsForSurface(std: BlockStdScope, owner: CommandOwner, surface: CommandSurface): AnyCommandDescriptor[];
394
+ /**
395
+ * The senior sub-menu's hard cap: 14 buttons in one row of the popover. The
396
+ * registry test asserts no owner DECLARES more than this; the ranking below is
397
+ * what happens when an owner's whole catalogue outgrows it.
398
+ */
399
+ export declare const SENIOR_MENU_CAP = 14;
400
+ /**
401
+ * How many buttons survive once an owner overflows: {@link MENU_RECENT_SLOTS}
402
+ * by recency plus {@link MENU_USED_SLOTS} by frequency — thirteen (PO
403
+ * re-arbitration of 2026-08-28, superseding the 4 + 3 of 2026-08-26).
404
+ *
405
+ * Thirteen and not fourteen because the permanent "More artefacts…" button is
406
+ * the fourteenth: an overflowed sub-menu therefore renders exactly the cap, and
407
+ * the row a user meets past the cap is as wide as the one they meet below it.
408
+ */
409
+ export declare const SENIOR_MENU_RANKED_SLOTS: number;
410
+ /**
411
+ * How many rows the catalogue sidepanel's "Recent & frequent" head section
412
+ * holds: {@link HEAD_RECENT_SLOTS} + {@link HEAD_USED_SLOTS} = seven.
413
+ *
414
+ * Deliberately NOT {@link SENIOR_MENU_RANKED_SLOTS}, and this is the third
415
+ * decision of 2026-08-28 (architect's ruling on review of the two PO ones). The
416
+ * sub-menu's thirteen is argued from ITS geometry — a horizontal row of ~24px
417
+ * icon buttons, thirteen of them plus the More button making up the fourteen
418
+ * cap. None of that transfers to a vertical list of 44px rows in a panel
419
+ * `min(320px, 85vw)` wide: thirteen of those is ~604px of head section, which
420
+ * on a 13" laptop is the entire first screen, every row of it a duplicate of a
421
+ * row filed below, pushing the categories — the panel's actual information
422
+ * architecture — wholly under the fold. Worst for exactly the power user the
423
+ * section exists to serve.
424
+ *
425
+ * So the two surfaces share the ARBITRATION and not the MAGNITUDE: one
426
+ * algorithm, two parameterisations. Seven keeps the size the PO recette of
427
+ * 27/08/2026 signed off on, and the 4 + 3 split keeps both halves of a section
428
+ * labelled "Recent & frequent" — a plain `.slice(0, 7)` of the sub-menu's pick
429
+ * would have returned seven recency picks and zero frequency ones, quietly
430
+ * deleting the "& frequent" half.
431
+ */
432
+ export declare const CATALOGUE_HEAD_RANKED_SLOTS: number;
433
+ /**
434
+ * Which of an owner's commands the senior sub-menu actually shows.
435
+ *
436
+ * Pure — no `std`, no DOM, no store — because this is the arbitration between
437
+ * a framework's whole toolbox and fourteen buttons, and an arbitration nobody
438
+ * can run in a unit test is a design review in disguise (`docs/adr/0008`,
439
+ * amendment of 2026-08-26).
440
+ *
441
+ * Below the cap nothing is arbitrated: the sub-menu IS the framework's
442
+ * `'senior-menu'` surface, authored order and all. Past it the sub-menu becomes
443
+ * a shortcut to the thirteen commands THIS user reaches for, beside one button
444
+ * to the catalogue sidepanel where the rest live.
445
+ *
446
+ * **Eligibility is declared, never earned** (PO ruling of 2026-08-28). What
447
+ * gets ranked is the `'senior-menu'` surface — the ≤14 its author nominated —
448
+ * and NOT the whole catalogue. The trigger still reads the catalogue (an owner
449
+ * overflows when its total toolbox outgrows the cap), but a command that
450
+ * deliberately declines the sub-menu stays out of it however often it is
451
+ * invoked. `bpmn.exportXml` is the case that made the rule: its subject is the
452
+ * whole BOARD, it lives in the pool's "⋮" and in the catalogue, and usage alone
453
+ * used to drag it into a row of things you DRAW — where "Export BPMN" answers
454
+ * no question a user asked. A surface a command declines is a statement about
455
+ * where it belongs, not a default to be out-voted.
456
+ *
457
+ * The thirteen are chosen on two axes because one is not enough — frequency
458
+ * alone never surfaces what the user picked up yesterday, recency alone
459
+ * reshuffles every click. They are then laid out in **authored order**, not in
460
+ * rank order: a menu whose buttons swap places under the cursor is the dark
461
+ * pattern this whole feature exists to avoid, so what the ranking decides is
462
+ * membership, never position.
463
+ *
464
+ * With no usage recorded at all, both axes collapse to authored order and the
465
+ * result is the first thirteen of the nominated list — a deterministic cold
466
+ * start, not an empty menu.
467
+ *
468
+ * @param menu the owner's `'senior-menu'` commands, already order-sorted. It is
469
+ * both the pool the ranking draws membership from and the authored order the
470
+ * survivors are laid back out in.
471
+ * @param catalogue the owner's whole `'catalogue'` surface, already
472
+ * order-sorted. Read only for its length, to decide whether the owner
473
+ * overflows at all; it contributes no candidate.
474
+ * @param statsOf per-user measure; `undefined` for a command never invoked
475
+ */
476
+ export declare function selectSeniorMenuCommands(menu: AnyCommandDescriptor[], catalogue: AnyCommandDescriptor[], statsOf: (id: string) => CommandUsageStats | undefined): {
477
+ commands: AnyCommandDescriptor[];
478
+ overflow: boolean;
479
+ };
480
+ /**
481
+ * The commands a user actually reaches for, for surfaces that lead with them —
482
+ * the catalogue sidepanel's "recent & frequent" head section (PO recette,
483
+ * 27/08/2026).
484
+ *
485
+ * Same arbitration as the senior sub-menu ({@link pickByUsage}) — one ranking,
486
+ * two consumers, never two opinions — with four deliberate differences:
487
+ *
488
+ * - it seats {@link CATALOGUE_HEAD_RANKED_SLOTS} (4 recent + 3 used), not the
489
+ * sub-menu's thirteen. The two surfaces share the arbitration and not the
490
+ * magnitude: see {@link CATALOGUE_HEAD_RANKED_SLOTS} for why thirteen 44px
491
+ * rows in a 320px panel would bury the categories under the fold.
492
+ * - it ranks the CATALOGUE surface, and keeps doing so after the eligibility
493
+ * ruling of 2026-08-28 narrowed the sub-menu to `'senior-menu'` declarers.
494
+ * That ruling is about the sub-menu, which is a row of things you DRAW; the
495
+ * sidepanel is the full-catalogue surface, the one place every command of a
496
+ * framework is reachable, so a catalogue-only command like `bpmn.exportXml`
497
+ * heading this section is the section working — "here is what you reach for"
498
+ * over a panel that lists everything, not a board action smuggled into a
499
+ * palette. Passing the menu surface here would hide a user's own habits from
500
+ * the very panel built to show them.
501
+ * - only commands that CARRY a measure are returned. The sub-menu backfills
502
+ * with authored order because it must always show something; a "recently
503
+ * used" section padded with the never-used would be a label that lies, so
504
+ * with no usage at all this returns `[]` and the section is simply absent.
505
+ * - the PICK order is kept (the recency ranks, then the frequency additions),
506
+ * not re-sorted by authored order: the section's whole message is "yours,
507
+ * latest first", and it only recomposes when the panel reopens.
508
+ */
509
+ export declare function rankCommandsByUsage(catalogue: AnyCommandDescriptor[], statsOf: (id: string) => CommandUsageStats | undefined): AnyCommandDescriptor[];
320
510
  /** Resolve an `iconKey` through the registered icon tables. */
321
511
  export declare function getCommandIcon(std: BlockStdScope, iconKey: string | undefined): TemplateResult | undefined;
@@ -2,7 +2,7 @@ import { createIdentifier } from '../../global/di/index.js';
2
2
  import { SurfaceSelection } from '../selection/index.js';
3
3
  import { ShortcutExtension, } from './shortcut.js';
4
4
  /**
5
- * The seven framework modules that own commands. An EXPLICIT list, not a
5
+ * The eight framework modules that own commands. An EXPLICIT list, not a
6
6
  * subset assertion over `OPTIONAL_BLOCKS`: that list mixes frameworks with
7
7
  * plain blocks. `packages/affine/all/src/frameworks.ts` asserts that every id
8
8
  * here is a real flag key (`satisfies readonly OptionalBlock[]`).
@@ -15,6 +15,7 @@ export const FRAMEWORK_IDS = [
15
15
  'edgy',
16
16
  'cynefin-estuarine',
17
17
  'bpmn',
18
+ 'c4',
18
19
  'ddd-event-storming',
19
20
  'ddd-core-domain',
20
21
  'ddd-context-map',
@@ -24,6 +25,7 @@ export const CommandDescriptorIdentifier = createIdentifier('CommandDescriptor')
24
25
  /** Multi-instance: one `iconKey → template` table per contributing package. */
25
26
  export const CommandIconsIdentifier = createIdentifier('CommandIcons');
26
27
  export const CommandTelemetryIdentifier = createIdentifier('CommandTelemetry');
28
+ export const CommandUsageIdentifier = createIdentifier('CommandUsage');
27
29
  const surfaceSelections = (std) => std.selection.filter(SurfaceSelection);
28
30
  /**
29
31
  * Mirrors `GfxSelectionManager.editing` without importing `@labre/std/gfx`
@@ -60,14 +62,17 @@ export function isCommandAvailable(std, command) {
60
62
  }
61
63
  /**
62
64
  * THE bottleneck: the one place a command runs, and therefore the one place
63
- * its telemetry is emitted. Every surface (sub-menu, shortcut, palette,
64
- * sidepanel, agent) goes through here, which is what removes the per-menu
65
- * `track()` duplicates.
65
+ * its telemetry is emitted and its usage measured. Every surface (sub-menu,
66
+ * shortcut, palette, sidepanel, agent) goes through here, which is what removes
67
+ * the per-menu `track()` duplicates.
66
68
  */
67
69
  export function runCommand(std, command, invocation, params) {
68
70
  const result = command.run(std, invocation, params);
69
71
  if (result instanceof Promise)
70
72
  result.catch(console.error);
73
+ // Before the telemetry gate on purpose: usage is measured for EVERY command,
74
+ // including the ones with no `telemetry` field and the self-emitting ones.
75
+ std.getOptional(CommandUsageIdentifier)?.record(command, invocation);
71
76
  if (!command.telemetry)
72
77
  return;
73
78
  std.getOptional(CommandTelemetryIdentifier)?.({ std, command, invocation });
@@ -102,6 +107,22 @@ export function toShortcutDescriptor(command) {
102
107
  },
103
108
  };
104
109
  }
110
+ /**
111
+ * The third permanent projection out of {@link CommandDescriptor}, beside
112
+ * {@link toShortcutDescriptor} and {@link toCommandManifestEntry}. TOTAL for
113
+ * the same reason the shortcut descriptor is: a keyless command still yields a
114
+ * row, so Settings › Shortcuts can bind it.
115
+ */
116
+ export function toShortcutManifestEntry(command) {
117
+ return {
118
+ id: command.id,
119
+ labelKey: command.labelKey,
120
+ labelFallback: command.labelFallback,
121
+ defaultKeys: command.defaultKeys,
122
+ scope: command.scope,
123
+ owner: command.owner,
124
+ };
125
+ }
105
126
  const zodDef = (schema) => schema?._def ?? {};
106
127
  const ZOD_KIND = {
107
128
  ZodString: 'string',
@@ -220,6 +241,199 @@ export function getCommandsForSurface(std, owner, surface) {
220
241
  .filter(c => c.owner === owner && c.surfaces.includes(surface))
221
242
  .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
222
243
  }
244
+ /**
245
+ * The senior sub-menu's hard cap: 14 buttons in one row of the popover. The
246
+ * registry test asserts no owner DECLARES more than this; the ranking below is
247
+ * what happens when an owner's whole catalogue outgrows it.
248
+ */
249
+ export const SENIOR_MENU_CAP = 14;
250
+ const MENU_RECENT_SLOTS = 7;
251
+ const MENU_USED_SLOTS = 6;
252
+ /**
253
+ * How many buttons survive once an owner overflows: {@link MENU_RECENT_SLOTS}
254
+ * by recency plus {@link MENU_USED_SLOTS} by frequency — thirteen (PO
255
+ * re-arbitration of 2026-08-28, superseding the 4 + 3 of 2026-08-26).
256
+ *
257
+ * Thirteen and not fourteen because the permanent "More artefacts…" button is
258
+ * the fourteenth: an overflowed sub-menu therefore renders exactly the cap, and
259
+ * the row a user meets past the cap is as wide as the one they meet below it.
260
+ */
261
+ export const SENIOR_MENU_RANKED_SLOTS = MENU_RECENT_SLOTS + MENU_USED_SLOTS;
262
+ const HEAD_RECENT_SLOTS = 4;
263
+ const HEAD_USED_SLOTS = 3;
264
+ /**
265
+ * How many rows the catalogue sidepanel's "Recent & frequent" head section
266
+ * holds: {@link HEAD_RECENT_SLOTS} + {@link HEAD_USED_SLOTS} = seven.
267
+ *
268
+ * Deliberately NOT {@link SENIOR_MENU_RANKED_SLOTS}, and this is the third
269
+ * decision of 2026-08-28 (architect's ruling on review of the two PO ones). The
270
+ * sub-menu's thirteen is argued from ITS geometry — a horizontal row of ~24px
271
+ * icon buttons, thirteen of them plus the More button making up the fourteen
272
+ * cap. None of that transfers to a vertical list of 44px rows in a panel
273
+ * `min(320px, 85vw)` wide: thirteen of those is ~604px of head section, which
274
+ * on a 13" laptop is the entire first screen, every row of it a duplicate of a
275
+ * row filed below, pushing the categories — the panel's actual information
276
+ * architecture — wholly under the fold. Worst for exactly the power user the
277
+ * section exists to serve.
278
+ *
279
+ * So the two surfaces share the ARBITRATION and not the MAGNITUDE: one
280
+ * algorithm, two parameterisations. Seven keeps the size the PO recette of
281
+ * 27/08/2026 signed off on, and the 4 + 3 split keeps both halves of a section
282
+ * labelled "Recent & frequent" — a plain `.slice(0, 7)` of the sub-menu's pick
283
+ * would have returned seven recency picks and zero frequency ones, quietly
284
+ * deleting the "& frequent" half.
285
+ */
286
+ export const CATALOGUE_HEAD_RANKED_SLOTS = HEAD_RECENT_SLOTS + HEAD_USED_SLOTS;
287
+ /**
288
+ * Which of an owner's commands the senior sub-menu actually shows.
289
+ *
290
+ * Pure — no `std`, no DOM, no store — because this is the arbitration between
291
+ * a framework's whole toolbox and fourteen buttons, and an arbitration nobody
292
+ * can run in a unit test is a design review in disguise (`docs/adr/0008`,
293
+ * amendment of 2026-08-26).
294
+ *
295
+ * Below the cap nothing is arbitrated: the sub-menu IS the framework's
296
+ * `'senior-menu'` surface, authored order and all. Past it the sub-menu becomes
297
+ * a shortcut to the thirteen commands THIS user reaches for, beside one button
298
+ * to the catalogue sidepanel where the rest live.
299
+ *
300
+ * **Eligibility is declared, never earned** (PO ruling of 2026-08-28). What
301
+ * gets ranked is the `'senior-menu'` surface — the ≤14 its author nominated —
302
+ * and NOT the whole catalogue. The trigger still reads the catalogue (an owner
303
+ * overflows when its total toolbox outgrows the cap), but a command that
304
+ * deliberately declines the sub-menu stays out of it however often it is
305
+ * invoked. `bpmn.exportXml` is the case that made the rule: its subject is the
306
+ * whole BOARD, it lives in the pool's "⋮" and in the catalogue, and usage alone
307
+ * used to drag it into a row of things you DRAW — where "Export BPMN" answers
308
+ * no question a user asked. A surface a command declines is a statement about
309
+ * where it belongs, not a default to be out-voted.
310
+ *
311
+ * The thirteen are chosen on two axes because one is not enough — frequency
312
+ * alone never surfaces what the user picked up yesterday, recency alone
313
+ * reshuffles every click. They are then laid out in **authored order**, not in
314
+ * rank order: a menu whose buttons swap places under the cursor is the dark
315
+ * pattern this whole feature exists to avoid, so what the ranking decides is
316
+ * membership, never position.
317
+ *
318
+ * With no usage recorded at all, both axes collapse to authored order and the
319
+ * result is the first thirteen of the nominated list — a deterministic cold
320
+ * start, not an empty menu.
321
+ *
322
+ * @param menu the owner's `'senior-menu'` commands, already order-sorted. It is
323
+ * both the pool the ranking draws membership from and the authored order the
324
+ * survivors are laid back out in.
325
+ * @param catalogue the owner's whole `'catalogue'` surface, already
326
+ * order-sorted. Read only for its length, to decide whether the owner
327
+ * overflows at all; it contributes no candidate.
328
+ * @param statsOf per-user measure; `undefined` for a command never invoked
329
+ */
330
+ export function selectSeniorMenuCommands(menu, catalogue, statsOf) {
331
+ if (catalogue.length <= SENIOR_MENU_CAP) {
332
+ return { commands: menu, overflow: false };
333
+ }
334
+ const authored = new Map(menu.map((command, index) => [command, index]));
335
+ const order = (command) => authored.get(command) ?? 0;
336
+ // (7, 6): thirteen icon buttons, plus the "More artefacts…" one, is the cap.
337
+ const { commands } = pickByUsage(menu, statsOf, MENU_RECENT_SLOTS, MENU_USED_SLOTS);
338
+ return {
339
+ commands: commands.sort((a, b) => order(a) - order(b)),
340
+ overflow: true,
341
+ };
342
+ }
343
+ /**
344
+ * The shared arbitration, over whatever pool its caller hands it: `recentSlots`
345
+ * by recency plus `usedSlots` by frequency, deduplicated.
346
+ *
347
+ * The two slot counts are PARAMETERS rather than constants because the two
348
+ * consumers share this ranking and not its magnitude — the sub-menu passes
349
+ * (7, 6) for a row of icon buttons, the sidepanel head (4, 3) for a vertical
350
+ * list of 44px rows. One arbitration, two parameterisations, still never two
351
+ * opinions.
352
+ *
353
+ * Recency goes FIRST since the PO's re-arbitration of 2026-08-28 (it was 4
354
+ * most-used + 3 most-recent): what a user reached for this morning is what they
355
+ * are still working on, and a row that leads with the all-time workhorses is a
356
+ * row that takes weeks to notice a new habit. So a command that tops BOTH axes
357
+ * consumes a RECENT slot, and the most-used slot it would have taken goes to
358
+ * the next candidate down the frequency ranking — which is what the backfill
359
+ * loop below does by walking `mostUsed` whole rather than only its head.
360
+ *
361
+ * Returned in PICK order (the recency ranks first, the frequency additions
362
+ * after); each consumer imposes its own display order. The `stats` map is
363
+ * returned with them so a consumer that filters on "was this ever measured?"
364
+ * does not ask the store a second time — see {@link rankCommandsByUsage}.
365
+ */
366
+ function pickByUsage(pool, statsOf, recentSlots, usedSlots) {
367
+ const authored = new Map(pool.map((command, index) => [command, index]));
368
+ const order = (command) => authored.get(command) ?? 0;
369
+ // One read per command per selection: the store answers from storage, and the
370
+ // two axes would otherwise ask it the same question twice.
371
+ const stats = new Map(pool.map(c => [c, statsOf(c.id)]));
372
+ const rankBy = (primary, secondary) => [...pool].sort((a, b) => {
373
+ const left = stats.get(a);
374
+ const right = stats.get(b);
375
+ // A command nobody ever invoked ranks after every command somebody did,
376
+ // on either axis — it has no measure, not a low one.
377
+ if (!left || !right) {
378
+ return left ? -1 : right ? 1 : order(a) - order(b);
379
+ }
380
+ return (primary(right) - primary(left) ||
381
+ secondary(right) - secondary(left) ||
382
+ order(a) - order(b));
383
+ });
384
+ const mostUsed = rankBy(used => used.count, used => used.lastUsedAt);
385
+ const mostRecent = rankBy(used => used.lastUsedAt, used => used.count);
386
+ const total = recentSlots + usedSlots;
387
+ const chosen = new Set();
388
+ for (const command of mostRecent.slice(0, recentSlots)) {
389
+ chosen.add(command);
390
+ }
391
+ // The `usedSlots` remaining seats, from the frequency ranking: walking it
392
+ // whole rather than only its head is what makes a double pick free its
393
+ // most-used slot for the next candidate instead of wasting it.
394
+ for (const command of mostUsed) {
395
+ if (chosen.size >= total)
396
+ break;
397
+ chosen.add(command);
398
+ }
399
+ return { commands: [...chosen].slice(0, total), stats };
400
+ }
401
+ /**
402
+ * The commands a user actually reaches for, for surfaces that lead with them —
403
+ * the catalogue sidepanel's "recent & frequent" head section (PO recette,
404
+ * 27/08/2026).
405
+ *
406
+ * Same arbitration as the senior sub-menu ({@link pickByUsage}) — one ranking,
407
+ * two consumers, never two opinions — with four deliberate differences:
408
+ *
409
+ * - it seats {@link CATALOGUE_HEAD_RANKED_SLOTS} (4 recent + 3 used), not the
410
+ * sub-menu's thirteen. The two surfaces share the arbitration and not the
411
+ * magnitude: see {@link CATALOGUE_HEAD_RANKED_SLOTS} for why thirteen 44px
412
+ * rows in a 320px panel would bury the categories under the fold.
413
+ * - it ranks the CATALOGUE surface, and keeps doing so after the eligibility
414
+ * ruling of 2026-08-28 narrowed the sub-menu to `'senior-menu'` declarers.
415
+ * That ruling is about the sub-menu, which is a row of things you DRAW; the
416
+ * sidepanel is the full-catalogue surface, the one place every command of a
417
+ * framework is reachable, so a catalogue-only command like `bpmn.exportXml`
418
+ * heading this section is the section working — "here is what you reach for"
419
+ * over a panel that lists everything, not a board action smuggled into a
420
+ * palette. Passing the menu surface here would hide a user's own habits from
421
+ * the very panel built to show them.
422
+ * - only commands that CARRY a measure are returned. The sub-menu backfills
423
+ * with authored order because it must always show something; a "recently
424
+ * used" section padded with the never-used would be a label that lies, so
425
+ * with no usage at all this returns `[]` and the section is simply absent.
426
+ * - the PICK order is kept (the recency ranks, then the frequency additions),
427
+ * not re-sorted by authored order: the section's whole message is "yours,
428
+ * latest first", and it only recomposes when the panel reopens.
429
+ */
430
+ export function rankCommandsByUsage(catalogue, statsOf) {
431
+ const { commands, stats } = pickByUsage(catalogue, statsOf, HEAD_RECENT_SLOTS, HEAD_USED_SLOTS);
432
+ // Through the map the ranking already built, not a second round of store
433
+ // reads: "one read per command per selection" is a promise this function used
434
+ // to break once per returned row.
435
+ return commands.filter(command => stats.get(command) !== undefined);
436
+ }
223
437
  /** Resolve an `iconKey` through the registered icon tables. */
224
438
  export function getCommandIcon(std, iconKey) {
225
439
  if (!iconKey)
@@ -60,7 +60,8 @@ const LEGACY_MODIFIER = /^(mod|cmd|meta|ctrl|control|alt|shift)$/i;
60
60
  * folded: they are valid chord prefixes.
61
61
  */
62
62
  export function normalizeLegacyCombo(keys) {
63
- if (keys.length > 1 && keys.slice(0, -1).every(k => LEGACY_MODIFIER.test(k))) {
63
+ if (keys.length > 1 &&
64
+ keys.slice(0, -1).every(k => LEGACY_MODIFIER.test(k))) {
64
65
  return [keys.join('-')];
65
66
  }
66
67
  return keys;
@@ -12,7 +12,17 @@ import { type AnyCommandDescriptor } from './command-registry.js';
12
12
  * exactly the composition the command registry already does (see
13
13
  * `packages/affine/all/src/commands.ts` and `scripts/build-bundles.mjs`).
14
14
  */
15
- export type TranslationKeySource = 'command' | 'framework' | 'role' | 'background' | 'rule' | 'nudge' | 'profile' | 'audit-criterion' | 'reading' | 'chrome';
15
+ export type TranslationKeySource = 'command' | 'framework' | 'role' | 'background' | 'rule' | 'nudge' | 'profile' | 'audit-criterion' | 'reading'
16
+ /**
17
+ * The words a framework WRITES ONTO THE CANVAS when an artefact is placed —
18
+ * the "Task" a fresh BPMN task is captioned with, the "People" under an EDGY
19
+ * person. Document content and not chrome, which is why they are a source of
20
+ * their own: they are resolved ONCE, at placement, and what lands in the
21
+ * document is a string the author then owns and edits. Changing the
22
+ * catalogue afterwards renames nothing, exactly as renaming a shape by hand
23
+ * would not.
24
+ */
25
+ | 'seed' | 'chrome';
16
26
  export interface TranslationKeyManifestEntry {
17
27
  key: string;
18
28
  /**
@@ -41,6 +51,41 @@ export declare function collectTranslationKeys(source: TranslationKeySource, val
41
51
  * mean walking zod internals.
42
52
  */
43
53
  export declare function commandTranslationEntries(commands: readonly AnyCommandDescriptor[]): TranslationKeyManifestEntry[];
54
+ /** The i18n key prefix every artefact-catalogue group header is looked up under. */
55
+ export declare const CATALOGUE_CATEGORY_KEY_PREFIX = "com.labre.catalogue.category.";
56
+ /**
57
+ * The English default for a category header, derived from the category id.
58
+ *
59
+ * `'backgrounds'` → `'Backgrounds'`, `'value-flow'` → `'Value flow'`,
60
+ * `'boundedContext'` → `'Bounded context'`. Sentence case, not title case: a
61
+ * header is a phrase, and capitalising every word turns `'change arrows'` into
62
+ * a product name.
63
+ *
64
+ * It is a FALLBACK and nothing more. A host with a catalogue answers
65
+ * `com.labre.catalogue.category.<id>` and this is never seen; a standalone
66
+ * playground reads a word instead of a raw key. The library still invents no
67
+ * framework prose — a category id is the framework's own word, only respelled.
68
+ *
69
+ * It lives in `@labre/std` rather than beside the panel that renders it because
70
+ * a FRAMEWORK has to derive the same fallback for its own contribution to the
71
+ * key manifest (see {@link commandCategoryTranslationEntries}), and `@labre/std`
72
+ * is the only layer every framework package already depends on. The catalogue
73
+ * widget re-exports it, so the panel and the manifest cannot drift.
74
+ */
75
+ export declare function humanizeCategory(category: string): string;
76
+ /**
77
+ * The catalogue group headers a command group implies: one entry per distinct
78
+ * `category` it declares, with the panel's own humanised fallback.
79
+ *
80
+ * A framework contributes these WITH its commands, for the reason the command
81
+ * entries themselves ship with the framework: `@formicoidea/labre-core` is the
82
+ * editor minus the frameworks, so a header key derived from core's registry
83
+ * alone knows nothing about "events", "gateways" or "swimlanes" — and a bundled
84
+ * host ended up drawing translated catalogue entries under English headers
85
+ * (#183). Deriving them from the same `commands` array on both sides makes the
86
+ * monorepo assembly and the composed bundle produce the same list.
87
+ */
88
+ export declare function commandCategoryTranslationEntries(commands: readonly AnyCommandDescriptor[]): TranslationKeyManifestEntry[];
44
89
  /**
45
90
  * Compose contributions into one manifest: first occurrence of a key wins (so
46
91
  * the caller's order decides which `source` a shared key reports), sorted by
@@ -54,6 +54,64 @@ export function collectTranslationKeys(source, value) {
54
54
  export function commandTranslationEntries(commands) {
55
55
  return collectTranslationKeys('command', commands.map(toCommandManifestEntry));
56
56
  }
57
+ /** The i18n key prefix every artefact-catalogue group header is looked up under. */
58
+ export const CATALOGUE_CATEGORY_KEY_PREFIX = 'com.labre.catalogue.category.';
59
+ /**
60
+ * The English default for a category header, derived from the category id.
61
+ *
62
+ * `'backgrounds'` → `'Backgrounds'`, `'value-flow'` → `'Value flow'`,
63
+ * `'boundedContext'` → `'Bounded context'`. Sentence case, not title case: a
64
+ * header is a phrase, and capitalising every word turns `'change arrows'` into
65
+ * a product name.
66
+ *
67
+ * It is a FALLBACK and nothing more. A host with a catalogue answers
68
+ * `com.labre.catalogue.category.<id>` and this is never seen; a standalone
69
+ * playground reads a word instead of a raw key. The library still invents no
70
+ * framework prose — a category id is the framework's own word, only respelled.
71
+ *
72
+ * It lives in `@labre/std` rather than beside the panel that renders it because
73
+ * a FRAMEWORK has to derive the same fallback for its own contribution to the
74
+ * key manifest (see {@link commandCategoryTranslationEntries}), and `@labre/std`
75
+ * is the only layer every framework package already depends on. The catalogue
76
+ * widget re-exports it, so the panel and the manifest cannot drift.
77
+ */
78
+ export function humanizeCategory(category) {
79
+ const words = category
80
+ // camelCase and PascalCase boundaries, before the separators are split on:
81
+ // `'boundedContext'` has no separator to find otherwise.
82
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
83
+ .split(/[-_\s]+/)
84
+ .filter(Boolean)
85
+ .map(word => word.toLowerCase());
86
+ if (!words.length)
87
+ return category;
88
+ const [first, ...rest] = words;
89
+ return [first.charAt(0).toUpperCase() + first.slice(1), ...rest].join(' ');
90
+ }
91
+ /**
92
+ * The catalogue group headers a command group implies: one entry per distinct
93
+ * `category` it declares, with the panel's own humanised fallback.
94
+ *
95
+ * A framework contributes these WITH its commands, for the reason the command
96
+ * entries themselves ship with the framework: `@formicoidea/labre-core` is the
97
+ * editor minus the frameworks, so a header key derived from core's registry
98
+ * alone knows nothing about "events", "gateways" or "swimlanes" — and a bundled
99
+ * host ended up drawing translated catalogue entries under English headers
100
+ * (#183). Deriving them from the same `commands` array on both sides makes the
101
+ * monorepo assembly and the composed bundle produce the same list.
102
+ */
103
+ export function commandCategoryTranslationEntries(commands) {
104
+ const categories = new Set();
105
+ for (const command of commands) {
106
+ if (command.category)
107
+ categories.add(command.category);
108
+ }
109
+ return [...categories].map(category => ({
110
+ key: `${CATALOGUE_CATEGORY_KEY_PREFIX}${category}`,
111
+ fallback: humanizeCategory(category),
112
+ source: 'chrome',
113
+ }));
114
+ }
57
115
  /**
58
116
  * Compose contributions into one manifest: first occurrence of a key wins (so
59
117
  * the caller's order decides which `source` a shared key reports), sorted by
@@ -1,5 +1,5 @@
1
1
  import { DisposableGroup } from '../../global/disposable/index.js';
2
- import { Bound, getBoundWithRotation, intersects, } from '../../global/gfx/index.js';
2
+ import { Bound, getBoundWithRotation, intersects } from '../../global/gfx/index.js';
3
3
  import { compare } from '../utils/layer.js';
4
4
  import { GfxExtension } from './extension.js';
5
5
  import { GfxBlockElementModel } from './model/gfx-block-model.js';