@formicoidea/labre-core 0.41.0 → 0.43.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 (343) 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-data-view/configs/tooltips.js +1 -1
  4. package/dist/_pkgs/affine-block-database/configs/tooltips.js +1 -1
  5. package/dist/_pkgs/affine-block-edgeless-text/edgeless-text-block.js +4 -2
  6. package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/config.js +7 -1
  7. package/dist/_pkgs/affine-block-embed/common/iframe-sandbox.d.ts +39 -0
  8. package/dist/_pkgs/affine-block-embed/common/iframe-sandbox.js +39 -0
  9. package/dist/_pkgs/affine-block-embed/embed-figma-block/embed-figma-block.js +4 -1
  10. package/dist/_pkgs/affine-block-embed/embed-github-block/embed-github-block.js +2 -1
  11. package/dist/_pkgs/affine-block-embed/embed-iframe-block/components/embed-iframe-error-card.d.ts +14 -1
  12. package/dist/_pkgs/affine-block-embed/embed-iframe-block/components/embed-iframe-error-card.js +21 -2
  13. package/dist/_pkgs/affine-block-embed/embed-iframe-block/consts.js +2 -0
  14. package/dist/_pkgs/affine-block-embed/embed-iframe-block/embed-iframe-block.d.ts +2 -1
  15. package/dist/_pkgs/affine-block-embed/embed-iframe-block/embed-iframe-block.js +41 -11
  16. package/dist/_pkgs/affine-block-embed/embed-iframe-block/types.d.ts +16 -0
  17. package/dist/_pkgs/affine-block-embed/embed-iframe-block/types.js +17 -1
  18. package/dist/_pkgs/affine-block-embed/embed-iframe-block/utils.d.ts +8 -0
  19. package/dist/_pkgs/affine-block-embed/embed-iframe-block/utils.js +19 -0
  20. package/dist/_pkgs/affine-block-embed/embed-loom-block/embed-loom-block.js +4 -1
  21. package/dist/_pkgs/affine-block-embed/embed-youtube-block/embed-youtube-block.js +4 -1
  22. package/dist/_pkgs/affine-block-embed/index.d.ts +1 -0
  23. package/dist/_pkgs/affine-block-embed/index.js +1 -0
  24. package/dist/_pkgs/affine-block-embed/translations.d.ts +8 -0
  25. package/dist/_pkgs/affine-block-embed/translations.js +28 -0
  26. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/embed-linked-doc-block.js +4 -2
  27. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/embed-synced-doc-block.js +2 -2
  28. package/dist/_pkgs/affine-block-frame/frame-manager.js +6 -3
  29. package/dist/_pkgs/affine-block-frame/frame-tool.js +1 -1
  30. package/dist/_pkgs/affine-block-frame/frame-toolbar.js +6 -1
  31. package/dist/_pkgs/affine-block-list/list-keymap.js +7 -0
  32. package/dist/_pkgs/affine-block-list/utils/get-list-icon.js +3 -1
  33. package/dist/_pkgs/affine-block-note/configs/tooltips.js +1 -1
  34. package/dist/_pkgs/affine-block-note/note-keymap.js +7 -1
  35. package/dist/_pkgs/affine-block-paragraph/paragraph-keymap.js +7 -1
  36. package/dist/_pkgs/affine-block-root/adapters/html.js +2 -2
  37. package/dist/_pkgs/affine-block-root/commands/copy-link-commands.d.ts +2 -0
  38. package/dist/_pkgs/affine-block-root/commands/copy-link-commands.js +155 -0
  39. package/dist/_pkgs/affine-block-root/commands/pivot-commands.js +1 -8
  40. package/dist/_pkgs/affine-block-root/commands/tag-commands.js +1 -8
  41. package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.d.ts +9 -0
  42. package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.js +51 -0
  43. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.d.ts +22 -0
  44. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.js +46 -0
  45. package/dist/_pkgs/affine-block-root/edgeless/utils/pinch-zoom.d.ts +21 -0
  46. package/dist/_pkgs/affine-block-root/edgeless/utils/pinch-zoom.js +24 -0
  47. package/dist/_pkgs/affine-block-root/edgeless/utils/query.js +8 -0
  48. package/dist/_pkgs/affine-block-root/index.d.ts +1 -0
  49. package/dist/_pkgs/affine-block-root/index.js +1 -0
  50. package/dist/_pkgs/affine-block-root/keyboard/keymap.js +1 -16
  51. package/dist/_pkgs/affine-block-root/view.js +2 -0
  52. package/dist/_pkgs/affine-block-surface/element-model/index.d.ts +21 -3
  53. package/dist/_pkgs/affine-block-surface/element-model/index.js +14 -2
  54. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.d.ts +23 -0
  55. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.js +89 -0
  56. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.d.ts +7 -0
  57. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.js +5 -0
  58. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.d.ts +41 -0
  59. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +70 -0
  60. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.d.ts +49 -0
  61. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.js +257 -0
  62. package/dist/_pkgs/affine-block-surface/extensions/export-svg/tagged-path.d.ts +16 -0
  63. package/dist/_pkgs/affine-block-surface/extensions/export-svg/tagged-path.js +24 -0
  64. package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.d.ts +24 -0
  65. package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.js +66 -0
  66. package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +4 -0
  67. package/dist/_pkgs/affine-block-surface/extensions/index.js +4 -0
  68. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.d.ts +66 -4
  69. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.js +253 -11
  70. package/dist/_pkgs/affine-block-surface/extensions/interchange.d.ts +18 -0
  71. package/dist/_pkgs/affine-block-surface/extensions/legend-toolbar.d.ts +81 -0
  72. package/dist/_pkgs/affine-block-surface/extensions/legend-toolbar.js +81 -0
  73. package/dist/_pkgs/affine-block-surface/extensions/legend.d.ts +144 -0
  74. package/dist/_pkgs/affine-block-surface/extensions/legend.js +495 -0
  75. package/dist/_pkgs/affine-block-surface/extensions/morph-toolbar.js +4 -0
  76. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.d.ts +17 -3
  77. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.js +35 -13
  78. package/dist/_pkgs/affine-block-surface/extensions/reading.d.ts +61 -1
  79. package/dist/_pkgs/affine-block-surface/extensions/reading.js +85 -39
  80. package/dist/_pkgs/affine-block-surface/extensions/record-action.d.ts +66 -0
  81. package/dist/_pkgs/affine-block-surface/extensions/record-action.js +145 -0
  82. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch-translations.d.ts +3 -0
  83. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch-translations.js +23 -0
  84. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.d.ts +1 -1
  85. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.js +12 -4
  86. package/dist/_pkgs/affine-block-surface/extensions/validation.d.ts +253 -28
  87. package/dist/_pkgs/affine-block-surface/extensions/validation.js +489 -41
  88. package/dist/_pkgs/affine-block-surface/framework-background/background-view.d.ts +115 -0
  89. package/dist/_pkgs/affine-block-surface/framework-background/background-view.js +185 -0
  90. package/dist/_pkgs/affine-block-surface/framework-background/fit.d.ts +36 -0
  91. package/dist/_pkgs/affine-block-surface/framework-background/fit.js +30 -0
  92. package/dist/_pkgs/affine-block-surface/framework-background/index.d.ts +2 -0
  93. package/dist/_pkgs/affine-block-surface/framework-background/index.js +2 -0
  94. package/dist/_pkgs/affine-block-surface/framework-background/labels.d.ts +16 -1
  95. package/dist/_pkgs/affine-block-surface/framework-background/labels.js +31 -21
  96. package/dist/_pkgs/affine-block-surface/framework-background/renderer.js +29 -5
  97. package/dist/_pkgs/affine-block-surface/framework-background/stacking.d.ts +6 -4
  98. package/dist/_pkgs/affine-block-surface/framework-background/stacking.js +56 -8
  99. package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.d.ts +12 -0
  100. package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.js +15 -0
  101. package/dist/_pkgs/affine-block-surface/renderer/element-highlight-overlay.js +2 -7
  102. package/dist/_pkgs/affine-block-surface/view.js +8 -1
  103. package/dist/_pkgs/affine-block-surface-ref/configs/slash-menu.js +1 -1
  104. package/dist/_pkgs/affine-block-surface-ref/configs/tooltips.js +2 -2
  105. package/dist/_pkgs/affine-components/color-picker/button.d.ts +56 -1
  106. package/dist/_pkgs/affine-components/color-picker/button.js +168 -23
  107. package/dist/_pkgs/affine-components/color-picker/framework-palette.d.ts +106 -0
  108. package/dist/_pkgs/affine-components/color-picker/framework-palette.js +177 -0
  109. package/dist/_pkgs/affine-components/color-picker/index.d.ts +2 -0
  110. package/dist/_pkgs/affine-components/color-picker/index.js +2 -0
  111. package/dist/_pkgs/affine-components/color-picker/palette-carousel.d.ts +85 -0
  112. package/dist/_pkgs/affine-components/color-picker/palette-carousel.js +445 -0
  113. package/dist/_pkgs/affine-components/color-picker/styles.js +1 -1
  114. package/dist/_pkgs/affine-components/context-menu/button.js +3 -1
  115. package/dist/_pkgs/affine-components/edgeless-shape-color-picker/color-picker.d.ts +31 -1
  116. package/dist/_pkgs/affine-components/edgeless-shape-color-picker/color-picker.js +189 -63
  117. package/dist/_pkgs/affine-components/icons/ai.js +3 -3
  118. package/dist/_pkgs/affine-components/icons/list.js +7 -1
  119. package/dist/_pkgs/affine-components/resource/resource.js +29 -16
  120. package/dist/_pkgs/affine-components/size-dropdown-menu/dropdown-menu.js +6 -1
  121. package/dist/_pkgs/affine-components/toolbar/index.d.ts +1 -1
  122. package/dist/_pkgs/affine-components/toolbar/index.js +1 -1
  123. package/dist/_pkgs/affine-components/toolbar/menu-button.d.ts +7 -0
  124. package/dist/_pkgs/affine-components/toolbar/menu-button.js +30 -0
  125. package/dist/_pkgs/affine-components/toolbar/picker-menu.d.ts +16 -1
  126. package/dist/_pkgs/affine-components/toolbar/picker-menu.js +2 -2
  127. package/dist/_pkgs/affine-components/toolbar/toolbar.d.ts +1 -0
  128. package/dist/_pkgs/affine-components/toolbar/toolbar.js +67 -0
  129. package/dist/_pkgs/affine-components/translations.d.ts +8 -0
  130. package/dist/_pkgs/affine-components/translations.js +17 -0
  131. package/dist/_pkgs/affine-foundation/view.js +2 -1
  132. package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card-title-editor.js +1 -1
  133. package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.js +1 -1
  134. package/dist/_pkgs/affine-gfx-brush/element-renderer.js +2 -2
  135. package/dist/_pkgs/affine-gfx-brush/toolbar/components/eraser/icons.js +1 -1
  136. package/dist/_pkgs/affine-gfx-brush/toolbar/configs/brush.js +6 -1
  137. package/dist/_pkgs/affine-gfx-brush/toolbar/configs/highlighter.js +6 -1
  138. package/dist/_pkgs/affine-gfx-connector/connector-manager.d.ts +9 -1
  139. package/dist/_pkgs/affine-gfx-connector/connector-manager.js +61 -0
  140. package/dist/_pkgs/affine-gfx-connector/direction/direction-reveal.d.ts +11 -2
  141. package/dist/_pkgs/affine-gfx-connector/direction/direction-reveal.js +11 -2
  142. package/dist/_pkgs/affine-gfx-connector/element-renderer/connector-dom/index.d.ts +7 -1
  143. package/dist/_pkgs/affine-gfx-connector/element-renderer/connector-dom/index.js +87 -17
  144. package/dist/_pkgs/affine-gfx-connector/element-renderer/index.js +78 -17
  145. package/dist/_pkgs/affine-gfx-connector/element-renderer/utils.d.ts +24 -2
  146. package/dist/_pkgs/affine-gfx-connector/element-renderer/utils.js +31 -8
  147. package/dist/_pkgs/affine-gfx-connector/text/edgeless-connector-label-editor.d.ts +124 -3
  148. package/dist/_pkgs/affine-gfx-connector/text/edgeless-connector-label-editor.js +219 -56
  149. package/dist/_pkgs/affine-gfx-connector/text/text.d.ts +13 -4
  150. package/dist/_pkgs/affine-gfx-connector/text/text.js +13 -44
  151. package/dist/_pkgs/affine-gfx-connector/toolbar/config.d.ts +56 -0
  152. package/dist/_pkgs/affine-gfx-connector/toolbar/config.js +94 -10
  153. package/dist/_pkgs/affine-gfx-connector/toolbar/hollow-endpoint-icons.d.ts +8 -0
  154. package/dist/_pkgs/affine-gfx-connector/toolbar/hollow-endpoint-icons.js +118 -0
  155. package/dist/_pkgs/affine-gfx-connector/translations.d.ts +3 -0
  156. package/dist/_pkgs/affine-gfx-connector/translations.js +23 -0
  157. package/dist/_pkgs/affine-gfx-connector/view/view.d.ts +37 -1
  158. package/dist/_pkgs/affine-gfx-connector/view/view.js +97 -8
  159. package/dist/_pkgs/affine-gfx-group/command/group-api.js +1 -1
  160. package/dist/_pkgs/affine-gfx-group/store.js +0 -2
  161. package/dist/_pkgs/affine-gfx-group/translations.d.ts +9 -10
  162. package/dist/_pkgs/affine-gfx-group/translations.js +9 -13
  163. package/dist/_pkgs/affine-gfx-mindmap/indicator-overlay/index.js +6 -2
  164. package/dist/_pkgs/affine-gfx-mindmap/templates/index.js +1 -1
  165. package/dist/_pkgs/affine-gfx-mindmap/toolbar/basket-elements.js +1 -1
  166. package/dist/_pkgs/affine-gfx-mindmap/toolbar/config.js +4 -2
  167. package/dist/_pkgs/affine-gfx-mindmap/toolbar/utils/import-mindmap.js +2 -2
  168. package/dist/_pkgs/affine-gfx-mindmap/translations.d.ts +7 -1
  169. package/dist/_pkgs/affine-gfx-mindmap/translations.js +11 -1
  170. package/dist/_pkgs/affine-gfx-shape/element-renderer/highlighter.js +2 -2
  171. package/dist/_pkgs/affine-gfx-shape/overlay/polygon-drawing-overlay.d.ts +6 -0
  172. package/dist/_pkgs/affine-gfx-shape/overlay/polygon-drawing-overlay.js +30 -1
  173. package/dist/_pkgs/affine-gfx-shape/polygon-tool.d.ts +20 -1
  174. package/dist/_pkgs/affine-gfx-shape/polygon-tool.js +9 -1
  175. package/dist/_pkgs/affine-gfx-shape/toolbar/config.js +10 -3
  176. package/dist/_pkgs/affine-gfx-shape/toolbar/palette-color-action.js +11 -1
  177. package/dist/_pkgs/affine-gfx-shape/translations.d.ts +7 -0
  178. package/dist/_pkgs/affine-gfx-shape/translations.js +11 -0
  179. package/dist/_pkgs/affine-gfx-template/builtin/other.js +14 -8
  180. package/dist/_pkgs/affine-gfx-template/snapshot-from-action.js +32 -119
  181. package/dist/_pkgs/affine-gfx-template/toolbar/template-loading.js +1 -1
  182. package/dist/_pkgs/affine-gfx-template/toolbar/template-type.d.ts +1 -1
  183. package/dist/_pkgs/affine-gfx-template/translations.d.ts +5 -0
  184. package/dist/_pkgs/affine-gfx-template/translations.js +38 -0
  185. package/dist/_pkgs/affine-gfx-text/dblclick-add-edgeless-text.d.ts +13 -1
  186. package/dist/_pkgs/affine-gfx-text/dblclick-add-edgeless-text.js +19 -4
  187. package/dist/_pkgs/affine-gfx-text/edgeless-text-editor.d.ts +41 -0
  188. package/dist/_pkgs/affine-gfx-text/edgeless-text-editor.js +60 -4
  189. package/dist/_pkgs/affine-gfx-text/toolbar/actions.d.ts +8 -1
  190. package/dist/_pkgs/affine-gfx-text/toolbar/actions.js +14 -2
  191. package/dist/_pkgs/affine-gfx-text/translations.d.ts +9 -0
  192. package/dist/_pkgs/affine-gfx-text/translations.js +14 -1
  193. package/dist/_pkgs/affine-inline-latex/latex-node/latex-editor-menu.js +2 -1
  194. package/dist/_pkgs/affine-inline-preset/markdown.js +5 -1
  195. package/dist/_pkgs/affine-model/consts/connector.d.ts +28 -2
  196. package/dist/_pkgs/affine-model/consts/connector.js +26 -0
  197. package/dist/_pkgs/affine-model/consts/text.d.ts +15 -2
  198. package/dist/_pkgs/affine-model/consts/text.js +25 -1
  199. package/dist/_pkgs/affine-model/elements/bpmn/pool.js +1 -1
  200. package/dist/_pkgs/affine-model/elements/brush/brush.js +1 -1
  201. package/dist/_pkgs/affine-model/elements/c4/board.js +1 -1
  202. package/dist/_pkgs/affine-model/elements/c4/boundary.js +1 -1
  203. package/dist/_pkgs/affine-model/elements/connector/connector.d.ts +135 -0
  204. package/dist/_pkgs/affine-model/elements/connector/connector.js +246 -5
  205. package/dist/_pkgs/affine-model/elements/connector/end-label.d.ts +83 -0
  206. package/dist/_pkgs/affine-model/elements/connector/end-label.js +119 -0
  207. package/dist/_pkgs/affine-model/elements/connector/index.d.ts +1 -0
  208. package/dist/_pkgs/affine-model/elements/connector/index.js +1 -0
  209. package/dist/_pkgs/affine-model/elements/context-map/context-map.js +1 -1
  210. package/dist/_pkgs/affine-model/elements/core-domain/core-domain.d.ts +28 -0
  211. package/dist/_pkgs/affine-model/elements/core-domain/core-domain.js +129 -2
  212. package/dist/_pkgs/affine-model/elements/cynefin/cynefin.d.ts +8 -0
  213. package/dist/_pkgs/affine-model/elements/cynefin/cynefin.js +45 -2
  214. package/dist/_pkgs/affine-model/elements/edgy/board.js +1 -1
  215. package/dist/_pkgs/affine-model/elements/edgy/facets.js +1 -1
  216. package/dist/_pkgs/affine-model/elements/estuarine/estuarine.d.ts +6 -0
  217. package/dist/_pkgs/affine-model/elements/estuarine/estuarine.js +36 -2
  218. package/dist/_pkgs/affine-model/elements/event-storming/event-storming.d.ts +18 -7
  219. package/dist/_pkgs/affine-model/elements/event-storming/event-storming.js +23 -8
  220. package/dist/_pkgs/affine-model/elements/framework-background/background.d.ts +16 -0
  221. package/dist/_pkgs/affine-model/elements/framework-background/background.js +18 -0
  222. package/dist/_pkgs/affine-model/elements/highlighter/highlighter.js +1 -1
  223. package/dist/_pkgs/affine-model/elements/index.d.ts +8 -0
  224. package/dist/_pkgs/affine-model/elements/index.js +1 -0
  225. package/dist/_pkgs/affine-model/elements/shape/shape.js +1 -1
  226. package/dist/_pkgs/affine-model/elements/text/text.js +1 -1
  227. package/dist/_pkgs/affine-model/elements/uml/band.d.ts +39 -0
  228. package/dist/_pkgs/affine-model/elements/uml/band.js +31 -0
  229. package/dist/_pkgs/affine-model/elements/uml/diagram.d.ts +158 -0
  230. package/dist/_pkgs/affine-model/elements/uml/diagram.js +229 -0
  231. package/dist/_pkgs/affine-model/elements/uml/fragment.d.ts +161 -0
  232. package/dist/_pkgs/affine-model/elements/uml/fragment.js +205 -0
  233. package/dist/_pkgs/affine-model/elements/uml/index.d.ts +8 -0
  234. package/dist/_pkgs/affine-model/elements/uml/index.js +8 -0
  235. package/dist/_pkgs/affine-model/elements/uml/lifeline.d.ts +77 -0
  236. package/dist/_pkgs/affine-model/elements/uml/lifeline.js +89 -0
  237. package/dist/_pkgs/affine-model/elements/uml/node.d.ts +142 -0
  238. package/dist/_pkgs/affine-model/elements/uml/node.js +190 -0
  239. package/dist/_pkgs/affine-model/elements/uml/partition.d.ts +106 -0
  240. package/dist/_pkgs/affine-model/elements/uml/partition.js +172 -0
  241. package/dist/_pkgs/affine-model/elements/uml/region.d.ts +75 -0
  242. package/dist/_pkgs/affine-model/elements/uml/region.js +150 -0
  243. package/dist/_pkgs/affine-model/elements/uml/subject.d.ts +37 -0
  244. package/dist/_pkgs/affine-model/elements/uml/subject.js +108 -0
  245. package/dist/_pkgs/affine-model/elements/wardley/wardley.js +1 -1
  246. package/dist/_pkgs/affine-shared/services/embed-iframe/embed-iframe-config.d.ts +1 -0
  247. package/dist/_pkgs/affine-shared/services/font-loader/config.d.ts +18 -0
  248. package/dist/_pkgs/affine-shared/services/font-loader/config.js +82 -50
  249. package/dist/_pkgs/affine-shared/services/pivot-materiality-publisher.js +1 -9
  250. package/dist/_pkgs/affine-shared/services/telemetry-service/document-damage-watcher.d.ts +53 -0
  251. package/dist/_pkgs/affine-shared/services/telemetry-service/document-damage-watcher.js +95 -0
  252. package/dist/_pkgs/affine-shared/services/telemetry-service/index.d.ts +1 -0
  253. package/dist/_pkgs/affine-shared/services/telemetry-service/index.js +1 -0
  254. package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +26 -1
  255. package/dist/_pkgs/affine-shared/services/telemetry-service/telemetry-service.d.ts +2 -2
  256. package/dist/_pkgs/affine-shared/services/theme-service.d.ts +19 -0
  257. package/dist/_pkgs/affine-shared/services/theme-service.js +24 -0
  258. package/dist/_pkgs/affine-shared/services/toolbar-service/command-action.d.ts +34 -0
  259. package/dist/_pkgs/affine-shared/services/toolbar-service/command-action.js +63 -0
  260. package/dist/_pkgs/affine-shared/services/toolbar-service/index.d.ts +1 -0
  261. package/dist/_pkgs/affine-shared/services/toolbar-service/index.js +1 -0
  262. package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +97 -7
  263. package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +178 -7
  264. package/dist/_pkgs/affine-shared/styles/index.d.ts +1 -0
  265. package/dist/_pkgs/affine-shared/styles/index.js +1 -0
  266. package/dist/_pkgs/affine-shared/styles/motion.d.ts +14 -0
  267. package/dist/_pkgs/affine-shared/styles/motion.js +38 -0
  268. package/dist/_pkgs/affine-shared/utils/event.d.ts +10 -0
  269. package/dist/_pkgs/affine-shared/utils/event.js +20 -0
  270. package/dist/_pkgs/affine-shared/utils/file/filesys.d.ts +16 -0
  271. package/dist/_pkgs/affine-shared/utils/file/filesys.js +25 -0
  272. package/dist/_pkgs/affine-shared/utils/index.d.ts +1 -0
  273. package/dist/_pkgs/affine-shared/utils/index.js +1 -0
  274. package/dist/_pkgs/affine-shared/utils/link-preview-refresh.d.ts +12 -0
  275. package/dist/_pkgs/affine-shared/utils/link-preview-refresh.js +13 -0
  276. package/dist/_pkgs/affine-widget-edgeless-dragging-area/edgeless-dragging-area-rect.js +2 -2
  277. package/dist/_pkgs/affine-widget-edgeless-selected-rect/utils.js +5 -1
  278. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.d.ts +12 -4
  279. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.js +27 -4
  280. package/dist/_pkgs/affine-widget-edgeless-toolbar/config/types.d.ts +15 -0
  281. package/dist/_pkgs/affine-widget-edgeless-toolbar/config/utils.d.ts +1 -1
  282. package/dist/_pkgs/affine-widget-edgeless-toolbar/config/utils.js +7 -2
  283. package/dist/_pkgs/affine-widget-edgeless-toolbar/create-popper.js +13 -0
  284. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.d.ts +2 -0
  285. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.js +2 -0
  286. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.d.ts +80 -0
  287. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.js +270 -81
  288. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/senior-menu-selection.d.ts +15 -0
  289. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/senior-menu-selection.js +15 -0
  290. package/dist/_pkgs/affine-widget-edgeless-toolbar/panel/font-family-panel.d.ts +18 -0
  291. package/dist/_pkgs/affine-widget-edgeless-toolbar/panel/font-family-panel.js +52 -6
  292. package/dist/_pkgs/affine-widget-edgeless-toolbar/panel/font-weight-and-style-panel.js +8 -1
  293. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-ghost-overlay.d.ts +42 -0
  294. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-ghost-overlay.js +100 -0
  295. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-placement-tool.d.ts +100 -0
  296. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-placement-tool.js +274 -0
  297. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/index.d.ts +3 -0
  298. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/index.js +3 -0
  299. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/translate-created.d.ts +25 -0
  300. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/translate-created.js +67 -0
  301. package/dist/_pkgs/affine-widget-edgeless-toolbar/translations.d.ts +6 -0
  302. package/dist/_pkgs/affine-widget-edgeless-toolbar/translations.js +10 -0
  303. package/dist/_pkgs/affine-widget-edgeless-toolbar/view.js +5 -0
  304. package/dist/_pkgs/affine-widget-frame-title/edgeless-frame-title-editor.js +2 -1
  305. package/dist/_pkgs/affine-widget-slash-menu/translations.d.ts +16 -0
  306. package/dist/_pkgs/affine-widget-slash-menu/translations.js +23 -1
  307. package/dist/_pkgs/affine-widget-toolbar/utils.js +57 -14
  308. package/dist/_pkgs/data-view/core/detail/field.js +2 -1
  309. package/dist/_pkgs/data-view/core/filter/literal/define.js +3 -1
  310. package/dist/_pkgs/data-view/core/group-by/renderer/boolean-group.js +1 -1
  311. package/dist/_pkgs/data-view/property-presets/checkbox/cell-renderer.js +8 -2
  312. package/dist/_pkgs/data-view/view-presets/kanban/pc/cell.js +1 -1
  313. package/dist/_pkgs/data-view/view-presets/kanban/pc/controller/drag.js +2 -1
  314. package/dist/_pkgs/data-view/view-presets/table/pc/controller/drag.js +2 -1
  315. package/dist/_pkgs/data-view/view-presets/table/pc/controller/selection.js +1 -1
  316. package/dist/_pkgs/data-view/view-presets/table/pc/header/vertical-indicator.js +2 -1
  317. package/dist/_pkgs/data-view/view-presets/table/pc/row/row-select-checkbox.js +3 -1
  318. package/dist/_pkgs/data-view/view-presets/table/pc-virtual/controller/drag.js +2 -1
  319. package/dist/_pkgs/data-view/view-presets/table/pc-virtual/controller/selection.js +1 -1
  320. package/dist/_pkgs/data-view/view-presets/table/pc-virtual/group/top/header/vertical-indicator.js +2 -1
  321. package/dist/_pkgs/data-view/view-presets/table/pc-virtual/row/row-header.js +3 -1
  322. package/dist/_pkgs/global/gfx/xywh.js +7 -0
  323. package/dist/_pkgs/std/extension/command-registry.d.ts +158 -1
  324. package/dist/_pkgs/std/extension/command-registry.js +22 -0
  325. package/dist/_pkgs/std/gfx/index.d.ts +1 -1
  326. package/dist/_pkgs/std/gfx/interactivity/gfx-view-event-handler.d.ts +12 -0
  327. package/dist/_pkgs/std/gfx/interactivity/gfx-view-event-handler.js +20 -1
  328. package/dist/_pkgs/std/gfx/interactivity/manager.d.ts +10 -0
  329. package/dist/_pkgs/std/gfx/interactivity/manager.js +12 -0
  330. package/dist/_pkgs/std/gfx/model/surface/element-model.js +12 -7
  331. package/dist/_pkgs/std/gfx/model/surface/role.d.ts +10 -5
  332. package/dist/_pkgs/std/gfx/model/surface/surface-model.d.ts +56 -0
  333. package/dist/_pkgs/std/gfx/model/surface/surface-model.js +84 -3
  334. package/dist/_pkgs/std/gfx/view/view.d.ts +11 -2
  335. package/dist/_pkgs/std/gfx/view/view.js +16 -2
  336. package/dist/commands.d.ts +6 -0
  337. package/dist/commands.js +10 -2
  338. package/dist/frameworks.d.ts +9 -0
  339. package/dist/frameworks.js +19 -0
  340. package/dist/translations.js +21 -0
  341. package/package.json +13 -4
  342. package/dist/_pkgs/affine-gfx-group/group-watcher.d.ts +0 -1
  343. package/dist/_pkgs/affine-gfx-group/group-watcher.js +0 -20
@@ -0,0 +1,495 @@
1
+ import { ConnectorMode, FontWeight, PointStyle, ShapeStyle, } from '../../affine-model/index.js';
2
+ import { NOTATION_NEUTRALS } from '../../affine-shared/consts/index.js';
3
+ import { BOARD_LEGEND_TITLE, GROUP_SEED_NAME, translateKey, } from '../../affine-shared/services/index.js';
4
+ import { Bound } from '../../global/gfx/index.js';
5
+ import { CATALOGUE_CATEGORY_KEY_PREFIX, getRegisteredCommands, humanizeCategory, } from '../../std/index.js';
6
+ import { GfxControllerIdentifier, roleIsA, RoleVocabularyIdentifier, } from '../../std/gfx/index.js';
7
+ import { EdgelessCRUDIdentifier } from './crud-extension.js';
8
+ /**
9
+ * The ink and the type a notation writes its labels in: this box's rows, and
10
+ * the words the DDD prefabs set beside a dot or a marker.
11
+ *
12
+ * Declared HERE and re-exported by `@labre/affine-gfx-ddd-shared`, rather than
13
+ * the other way round, because that bundle depends on this one and a legend
14
+ * must not depend on a DDD bundle to be drawn.
15
+ */
16
+ export const LABEL_COLOR = NOTATION_NEUTRALS.ink;
17
+ export const LABEL_FONT = 'blocksuite:surface:Inter';
18
+ export const LABEL_FONT_SIZE = 14;
19
+ const NO_STROKE = '#00000000';
20
+ /**
21
+ * The box's geometry, in one place because two callers need it: the one that
22
+ * DRAWS the box and the one that has to know how tall it will be before drawing
23
+ * it (see {@link measureLegend}).
24
+ */
25
+ const LEGEND_METRICS = {
26
+ DEFAULT_W: 260,
27
+ PAD: 16,
28
+ TITLE_H: 32,
29
+ SUB_H: 26,
30
+ ROW_H: 28,
31
+ /** Swatch side (a `line` swatch is this long). */
32
+ SW: 16,
33
+ };
34
+ /**
35
+ * The minimal shape write this module needs — deliberately NOT the DDD
36
+ * `dddShapeProps`, and deliberately without a `role` parameter.
37
+ *
38
+ * That absence is the invariant: a legend is drawn ON the board it describes
39
+ * and the scan detects by role, so a glyph carrying one would list itself the
40
+ * next time a legend was generated and would be counted by every validation
41
+ * rule. Here it is not a rule to remember but a parameter that does not exist.
42
+ */
43
+ function addShape(surface, x, y, w, h, opts) {
44
+ const { shapeType = 'rect', fill, stroke = NO_STROKE, strokeWidth = 0, radius = 0, } = opts;
45
+ return surface.addElement({
46
+ type: 'shape',
47
+ shapeType,
48
+ filled: true,
49
+ fillColor: fill,
50
+ strokeColor: stroke,
51
+ strokeWidth,
52
+ shapeStyle: ShapeStyle.General,
53
+ roughness: 0,
54
+ radius,
55
+ xywh: new Bound(x, y, w, h).serialize(),
56
+ });
57
+ }
58
+ /** A left-aligned (or centred) line of text. No `role`, same reason as above. */
59
+ function addText(surface, x, y, w, text, fontSize, textAlign = 'center', bold = false) {
60
+ return surface.addElement({
61
+ type: 'text',
62
+ text,
63
+ color: LABEL_COLOR,
64
+ fontFamily: LABEL_FONT,
65
+ fontSize,
66
+ textAlign,
67
+ fontWeight: bold ? FontWeight.SemiBold : FontWeight.Regular,
68
+ xywh: new Bound(x, y, w, fontSize + 10).serialize(),
69
+ });
70
+ }
71
+ /**
72
+ * A swatch the FRAMEWORK described: its props, plus the geometry the layout
73
+ * decides — and MINUS any `role`, stripped here so the invariant holds
74
+ * structurally whatever a table says.
75
+ *
76
+ * Cast in one place because the props arrive as data — a table in a framework
77
+ * module, not a literal this file can type — and the surface's own factory is
78
+ * what validates them.
79
+ */
80
+ function addSwatchElement(surface, props) {
81
+ const { role: _role, ...neutral } = props;
82
+ return surface.addElement(neutral);
83
+ }
84
+ /**
85
+ * The role the legend's GROUP carries — the one thing on a generated legend
86
+ * that says what it is.
87
+ *
88
+ * Its glyphs deliberately carry none (see {@link addShape}), which is what
89
+ * keeps a legend out of the scan and out of every validation rule. But "made of
90
+ * nothing in particular" is unreadable to anything that has to tell a legend
91
+ * from a drawing, and something does: the `.bpmn` export counts what it left
92
+ * behind inside a pool, and a legend's fourteen glyphs would be reported as
93
+ * fourteen losses. The wrapper says so instead, once, structurally — no title
94
+ * to match on, no framework name, no geometry.
95
+ *
96
+ * `core:` because it belongs to no framework: no `RoleDefs` declares it, so
97
+ * `roleIsA` matches it against nothing, no rule evaluates it and no legend row
98
+ * lights because of it. Nothing is backfilled, as ever — a legend drawn before
99
+ * this shipped carries no role and is not recognised.
100
+ */
101
+ export const LEGEND_ROLE = 'core:legend';
102
+ /**
103
+ * Group the box's elements under one titled group, without
104
+ * `@labre/affine-gfx-group`'s `createGroupCommand`: that package depends on
105
+ * THIS one, so importing it would close a cycle. The twelve lines below are
106
+ * that command's whole body, run against the same `EdgelessCRUDIdentifier` it
107
+ * uses, so a legend group is what the gesture says a group is — plus the one
108
+ * thing a plain group is not, {@link LEGEND_ROLE}.
109
+ */
110
+ function groupLegendElements(std, ids) {
111
+ const gfx = std.get(GfxControllerIdentifier);
112
+ const crud = std.get(EdgelessCRUDIdentifier);
113
+ const groups = gfx.layer.canvasElements.filter(el => el.type === 'group');
114
+ const groupId = crud.addElement('group', {
115
+ children: Object.fromEntries(ids.map(id => [id, true])),
116
+ // Translated HERE and once: the title is document content the moment it
117
+ // lands (ADR 0023), so the host's catalogue is asked at placement and never
118
+ // again — a renamed group keeps its name.
119
+ title: translateKey(std, ...GROUP_SEED_NAME, { n: groups.length + 1 }),
120
+ role: LEGEND_ROLE,
121
+ });
122
+ return groupId || ids[0];
123
+ }
124
+ /**
125
+ * How big the box {@link addLegend} would draw for these sections is — without
126
+ * drawing it. The engine needs the height to drop the box bottom-left of a
127
+ * board, and measuring is the only honest way to get it: the box grows with the
128
+ * number of sub-titles, rows and extras, which is exactly what the detection
129
+ * pass decides.
130
+ */
131
+ export function measureLegend(sections, layout = {}, extras = []) {
132
+ const { DEFAULT_W, PAD, TITLE_H, SUB_H, ROW_H } = LEGEND_METRICS;
133
+ let subs = 0;
134
+ let rows = 0;
135
+ for (const s of sections) {
136
+ if (s.title)
137
+ subs++;
138
+ rows += s.rows.length;
139
+ }
140
+ return {
141
+ width: layout.width ?? DEFAULT_W,
142
+ height: PAD * 2 +
143
+ TITLE_H +
144
+ subs * SUB_H +
145
+ rows * (layout.rowHeight ?? ROW_H) +
146
+ extras.reduce((sum, extra) => sum + extra.height, 0),
147
+ };
148
+ }
149
+ /**
150
+ * A boxed legend: a bordered container with a bold title and bold section
151
+ * sub-titles, each row a swatch + label, then whatever `extras` add below.
152
+ * Returns the grouped id.
153
+ */
154
+ export function addLegend(surface, std, x, y, opts) {
155
+ const { PAD, TITLE_H, SUB_H, SW } = LEGEND_METRICS;
156
+ const ROW_H = opts.rowHeight ?? LEGEND_METRICS.ROW_H;
157
+ /** The swatch COLUMN: as wide as the widest sample any row may draw. */
158
+ const SWW = opts.swatchWidth ?? SW;
159
+ const SWH = opts.swatchHeight ?? SW;
160
+ const extras = opts.extras ?? [];
161
+ const { width: W, height: H } = measureLegend(opts.sections, opts, extras);
162
+ const ids = [
163
+ addShape(surface, x, y, W, H, {
164
+ fill: NOTATION_NEUTRALS.cardFill,
165
+ stroke: NOTATION_NEUTRALS.legendBorder,
166
+ strokeWidth: 1.5,
167
+ radius: 8,
168
+ }),
169
+ ];
170
+ let cy = y + PAD;
171
+ ids.push(addText(surface, x + PAD, cy, W - PAD * 2, opts.title, 18, 'left', true));
172
+ cy += TITLE_H;
173
+ for (const sec of opts.sections) {
174
+ if (sec.title) {
175
+ ids.push(addText(surface, x + PAD, cy, W - PAD * 2, sec.title, 14, 'left', true));
176
+ cy += SUB_H;
177
+ }
178
+ for (const row of sec.rows) {
179
+ const sx = x + PAD;
180
+ const midY = cy + ROW_H / 2;
181
+ if (row.swatch === 'dot') {
182
+ ids.push(addShape(surface, sx, midY - SW / 2, SW, SW, {
183
+ shapeType: 'ellipse',
184
+ fill: row.color,
185
+ stroke: NOTATION_NEUTRALS.ink,
186
+ strokeWidth: 1,
187
+ }));
188
+ }
189
+ else if (row.swatch === 'square') {
190
+ ids.push(addShape(surface, sx, midY - SW / 2, SW, SW, {
191
+ fill: row.color,
192
+ stroke: NOTATION_NEUTRALS.ink,
193
+ strokeWidth: 1,
194
+ radius: 3,
195
+ }));
196
+ if (row.letter)
197
+ ids.push(addText(surface, sx, midY - 8, SW, row.letter, 11));
198
+ }
199
+ else if (row.swatch === 'glyph') {
200
+ // The artefact itself, at swatch size. `size` wins when the framework
201
+ // declares one — a gradation of sizes IS notation for Wardley, and
202
+ // fitting every pastille to the same box would erase it; otherwise the
203
+ // artefact's own aspect is fitted inside the box and centred, so a
204
+ // portrait picture stays portrait.
205
+ const aspect = row.aspect && row.aspect > 0 ? row.aspect : 1;
206
+ const [gw, gh] = row.size ?? [
207
+ Math.min(SWW, SWH * aspect),
208
+ Math.min(SWW, SWH * aspect) / aspect,
209
+ ];
210
+ ids.push(addSwatchElement(surface, {
211
+ ...row.props,
212
+ xywh: new Bound(sx + (SWW - gw) / 2, midY - gh / 2, gw, gh).serialize(),
213
+ }));
214
+ }
215
+ else if (row.swatch === 'edge') {
216
+ // A real connector across the swatch column, so the endpoint the
217
+ // notation puts on the line — a hollow diamond, a hollow triangle, a
218
+ // stick head — is drawn by the connector renderer rather than guessed at.
219
+ ids.push(addSwatchElement(surface, {
220
+ mode: ConnectorMode.Straight,
221
+ stroke: row.color,
222
+ strokeWidth: 1.5,
223
+ frontEndpointStyle: PointStyle.None,
224
+ rearEndpointStyle: PointStyle.None,
225
+ ...row.props,
226
+ type: 'connector',
227
+ source: { position: [sx, midY] },
228
+ target: { position: [sx + SWW, midY] },
229
+ }));
230
+ }
231
+ else if (row.swatch === 'custom' && row.draw) {
232
+ // A composite the framework draws itself, in the box we hand it. The
233
+ // ids come back so the whole thing joins the group like any other row.
234
+ ids.push(...row.draw(surface, { x: sx, y: midY - SWH / 2, w: SWW, h: SWH }, std));
235
+ }
236
+ else if (row.dashed) {
237
+ // Two 6-unit segments with a 4-unit gap: the same 16 units as a solid
238
+ // bar, read as a dash.
239
+ const seg = 6;
240
+ ids.push(addShape(surface, sx, midY - 2, seg, 4, {
241
+ fill: row.color,
242
+ radius: 1,
243
+ }));
244
+ ids.push(addShape(surface, sx + SW - seg, midY - 2, seg, 4, {
245
+ fill: row.color,
246
+ radius: 1,
247
+ }));
248
+ }
249
+ else {
250
+ ids.push(addShape(surface, sx, midY - 2, SW, 4, { fill: row.color, radius: 1 }));
251
+ }
252
+ ids.push(addText(surface, sx + SWW + 10, midY - LABEL_FONT_SIZE / 2, W - PAD * 2 - SWW - 10, row.label, 13, 'left'));
253
+ cy += ROW_H;
254
+ }
255
+ }
256
+ for (const extra of extras) {
257
+ ids.push(...extra.draw(surface, std, x, cy, W));
258
+ cy += extra.height;
259
+ }
260
+ return groupLegendElements(std, ids);
261
+ }
262
+ /* ── The scan ──────────────────────────────────────────────────────────── */
263
+ /**
264
+ * Distance from the board's left edge / bottom edge, in model units. Wardley's
265
+ * numbers, kept identical so every legend lands in the same place relative to
266
+ * its board.
267
+ */
268
+ const INSET_X = 50;
269
+ const INSET_BOTTOM = 56;
270
+ /**
271
+ * Every role carried by an element inside `bound`.
272
+ *
273
+ * Neutral elements (no role) contribute nothing, which is the whole
274
+ * compatibility promise: a board drawn before the vocabularies existed produces
275
+ * an empty set and therefore a legend with no rows, exactly like an empty board.
276
+ * It is also why a legend never lists itself: nothing it draws carries a role.
277
+ */
278
+ export function rolesInBound(gfx, bound) {
279
+ return rolesOf(gfx.getElementsByBound(bound, { type: 'canvas' }));
280
+ }
281
+ /** {@link rolesInBound} over a perimeter already scanned. */
282
+ function rolesOf(elements) {
283
+ const present = new Set();
284
+ for (const el of elements) {
285
+ if (el.role !== undefined)
286
+ present.add(el.role);
287
+ }
288
+ return present;
289
+ }
290
+ /**
291
+ * The legends ALREADY drawn on this board — what turns the button's second
292
+ * press into "regenerate" rather than a second stacked box (issue #391).
293
+ *
294
+ * The scan already sees them: a generated legend's wrapper carries
295
+ * {@link LEGEND_ROLE}, so recognising one costs a filter over the elements the
296
+ * perimeter pass returned, and nothing in the document format changes.
297
+ *
298
+ * CONTAINMENT rather than intersection, which is what `getElementsByBound`
299
+ * answers with: two boards drawn edge to edge each overlap the other's corner,
300
+ * and the press on one would eat the other's box. A legend is inset well inside
301
+ * the board it documents, so asking for the whole box costs nothing here and
302
+ * keeps the neighbour's.
303
+ *
304
+ * Two boxes it deliberately does not find: one the author dragged off the board
305
+ * (it is no longer this board's legend, and a fresh one is drawn), and one
306
+ * generated before {@link LEGEND_ROLE} shipped in 0.42 — that box carries no
307
+ * role, so the old stacking survives on those documents. Nothing is backfilled,
308
+ * as ever (ADR 0026).
309
+ */
310
+ function legendsOn(elements, bound) {
311
+ return elements.filter(el => el.type === 'group' &&
312
+ el.role === LEGEND_ROLE &&
313
+ bound.contains(el.elementBound));
314
+ }
315
+ /** Every registered vocabulary, merged — a role id is namespaced, so it is flat. */
316
+ function vocabularyOf(std) {
317
+ const merged = {};
318
+ for (const defs of std.provider.getAll(RoleVocabularyIdentifier).values()) {
319
+ Object.assign(merged, defs);
320
+ }
321
+ return merged;
322
+ }
323
+ function entriesOf(command) {
324
+ const { legend } = command;
325
+ if (!legend)
326
+ return [];
327
+ return Array.isArray(legend) ? legend : [legend];
328
+ }
329
+ /**
330
+ * One row's label, through the host's catalogue, in the order of who owns the
331
+ * word:
332
+ *
333
+ * 1. the entry's own {@link CommandLegendEntry.labelWording} — a row that
334
+ * EXPLAINS the notation rather than naming it (Wardley's "Need / capability
335
+ * (activity, practice, data…)" against the role's bare "Component");
336
+ * 2. the ROLE's wording, which is the usual case and the reason a table never
337
+ * restates a label: renaming a role renames its legend row;
338
+ * 3. the COMMAND's wording, for a row whose role declares none.
339
+ *
340
+ * `labelPrefix` (the Context Map's "PS — ") is stitched back on AFTER
341
+ * translation: an abbreviation is never a translatable word.
342
+ */
343
+ function resolveRowLabel(std, roles, command, entry) {
344
+ const def = roles[entry.role];
345
+ const text = entry.labelWording
346
+ ? translateKey(std, ...entry.labelWording)
347
+ : def?.labelKey
348
+ ? translateKey(std, def.labelKey, def.labelFallback ?? entry.role)
349
+ : (def?.labelFallback ??
350
+ translateKey(std, command.labelKey, command.labelFallback ?? command.id));
351
+ return entry.labelPrefix ? `${entry.labelPrefix} — ${text}` : text;
352
+ }
353
+ /**
354
+ * The sub-title a row files itself under: its own {@link
355
+ * CommandLegendEntry.section} when it declares one, otherwise the command's
356
+ * `category` through the catalogue's own header key — the same word the
357
+ * artefact panel puts above the same group of commands, and therefore no new
358
+ * i18n key.
359
+ *
360
+ * A row with neither goes into an untitled bucket, which is what a framework
361
+ * with one flat notation wants.
362
+ */
363
+ function resolveSection(std, command, entry) {
364
+ if (entry.section) {
365
+ return {
366
+ key: entry.section[0],
367
+ title: translateKey(std, ...entry.section),
368
+ };
369
+ }
370
+ const category = command.category;
371
+ if (!category)
372
+ return { key: '' };
373
+ return {
374
+ key: `${CATALOGUE_CATEGORY_KEY_PREFIX}${category}`,
375
+ title: translateKey(std, `${CATALOGUE_CATEGORY_KEY_PREFIX}${category}`, humanizeCategory(category)),
376
+ };
377
+ }
378
+ /**
379
+ * The legend of a board, derived from the commands of the framework that owns
380
+ * it: every subscribed row whose role is present (directly or through a
381
+ * specialisation, unless the entry asks for {@link CommandLegendEntry.exact}),
382
+ * in command order, grouped under the section each declares — or under its
383
+ * command's category — with empty sections dropped.
384
+ *
385
+ * The SUB-TITLES come out in the order the framework first declares them,
386
+ * walking every command whether its row lights or not: a legend is a key to a
387
+ * notation, so the same framework reads in the same order on every board, and
388
+ * only the rows change.
389
+ *
390
+ * Rows are de-duplicated BY ROLE, first declaration winning: two commands draw
391
+ * a Wardley area (a rectangle and a polygon) and the notation has one "Area".
392
+ *
393
+ * When nothing is recognised the result is an EMPTY array, and the caller still
394
+ * draws the box: a legend of a board with nothing on it lists nothing, rather
395
+ * than inventing the full notation the user has not used.
396
+ */
397
+ export function legendFromCommands(std, owner, present) {
398
+ const roles = vocabularyOf(std);
399
+ const commands = getRegisteredCommands(std)
400
+ .filter(command => command.owner === owner && command.legend)
401
+ .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
402
+ const drafts = [];
403
+ const seen = new Set();
404
+ const presentRoles = [...present];
405
+ for (const command of commands) {
406
+ for (const entry of entriesOf(command)) {
407
+ // The bucket is opened for EVERY declared row, lit or not, and emptied
408
+ // ones are dropped at the end. That is what makes the order of the
409
+ // sub-titles a property of the framework's declarations rather than of
410
+ // what happens to be on this board: opening it only when a row lit put
411
+ // BPMN's "Activities" after "Gateways" and "Flows" on a pool that had a
412
+ // user task but no plain task, and the same pool with a plain task read
413
+ // in a different order again.
414
+ const { key, title } = resolveSection(std, command, entry);
415
+ let draft = drafts.find(d => d.key === key);
416
+ if (!draft)
417
+ drafts.push((draft = { key, title, rows: [] }));
418
+ const lit = entry.exact
419
+ ? present.has(entry.role)
420
+ : presentRoles.some(role => roleIsA(role, entry.role, roles));
421
+ if (!lit || seen.has(entry.role))
422
+ continue;
423
+ seen.add(entry.role);
424
+ draft.rows.push({
425
+ ...entry.row,
426
+ label: resolveRowLabel(std, roles, command, entry),
427
+ });
428
+ }
429
+ }
430
+ return drafts
431
+ .filter(draft => draft.rows.length > 0)
432
+ .map(({ title, rows }) => ({ title, rows }));
433
+ }
434
+ /** The `legendBox` of the framework's BOARD command, if it declares one. */
435
+ function boardLegendBox(std, owner) {
436
+ return getRegisteredCommands(std).find(command => command.owner === owner && command.legendBox)?.legendBox;
437
+ }
438
+ /**
439
+ * Build the legend of what is drawn inside `board` and drop it bottom-left of
440
+ * it, grouped and selected. THE gesture the shared toolbar button runs.
441
+ *
442
+ * REPLACES the board's own legend if it already has one, rather than stacking a
443
+ * second box on the first (issue #391): the placement is derived from the board
444
+ * alone, so every press landed at the same pixel and the copies were invisible
445
+ * — one box to the eye, N groups and N × ~15 elements in the document. The
446
+ * second press is therefore a REFRESH, which is what a user who has just added
447
+ * three artefacts is asking for; the cost is that hand retouching of the box is
448
+ * lost, and one undo brings it back (see {@link legendsOn} and ADR 0026).
449
+ *
450
+ * Returns the group id, or `undefined` when there is no surface to draw on.
451
+ */
452
+ export function createBoardLegend(std, board, owner) {
453
+ const gfx = std.get(GfxControllerIdentifier);
454
+ const surface = gfx.surface;
455
+ // The button already refuses on a readonly document; said again here because
456
+ // this gesture now DELETES before it draws, and a refused delete followed by
457
+ // a throwing draw is the one order that could lose a box.
458
+ if (!surface || std.store.readonly)
459
+ return undefined;
460
+ const bound = Bound.deserialize(board.xywh);
461
+ const inside = gfx.getElementsByBound(bound, { type: 'canvas' });
462
+ const previous = legendsOn(inside, bound);
463
+ // The box about to be drawn describes the DRAWING, never the box it replaces:
464
+ // the outgoing wrapper is dropped from the scan so `core:legend` is not among
465
+ // the roles the rows are derived from. Its glyphs carry no role at all.
466
+ const outgoing = new Set(previous);
467
+ const present = rolesOf(inside.filter(el => !outgoing.has(el)));
468
+ const sections = legendFromCommands(std, owner, present);
469
+ const box = boardLegendBox(std, owner);
470
+ const layout = {
471
+ width: box?.width,
472
+ rowHeight: box?.rowHeight,
473
+ swatchWidth: box?.swatchWidth,
474
+ swatchHeight: box?.swatchHeight,
475
+ };
476
+ // Resolved ONCE, in front of the drawing: an extra states its height as a
477
+ // value, so the box can be measured before it is placed.
478
+ const extras = box?.extras?.({ std, board, present }) ?? [];
479
+ const title = translateKey(std, ...(box?.titleWording ?? BOARD_LEGEND_TITLE));
480
+ const { height } = measureLegend(sections, layout, extras);
481
+ // ONE checkpoint, in front of BOTH halves of the replacement: a single
482
+ // Ctrl+Z after a regenerate puts the previous box back whole, rather than
483
+ // leaving the board with no legend at all.
484
+ std.store.captureSync();
485
+ if (previous.length > 0) {
486
+ const crud = std.get(EdgelessCRUDIdentifier);
487
+ // Cascades into the group's children (`crud-extension.ts`), so one call
488
+ // per legend takes the whole box away.
489
+ for (const legend of previous)
490
+ crud.removeElement(legend.id);
491
+ }
492
+ const id = addLegend(surface, std, bound.x + INSET_X, bound.y + bound.h - INSET_BOTTOM - height, { title, sections, extras, ...layout });
493
+ gfx.selection.set({ elements: [id], editing: false });
494
+ return id;
495
+ }
@@ -229,6 +229,10 @@ export function morphToolbarConfig(spec) {
229
229
  return renderPickerMenu({
230
230
  testId: 'element-morph',
231
231
  label: wording(ctx, spec.label),
232
+ // The shell's accessible name stays the stable ENGLISH
233
+ // identifier: composing it from the translated label produced
234
+ // half a sentence per language (#390).
235
+ menuAria: `${spec.label.fallback.toLowerCase()}-menu`,
232
236
  // The current kind's own icon on the closed button, exactly as the
233
237
  // shape picker shows the current shape: the dropdown reads as a
234
238
  // statement about the selection before it is opened.
@@ -82,12 +82,26 @@ export declare class ReadingProposalWidget extends EditorAnchoredPanel {
82
82
  */
83
83
  private _renderNature;
84
84
  /**
85
- * The typed edges touching the subject, grouped by side and named with the
86
- * FRAMEWORK's own two words (`ReadingRelationDef.sides`).
85
+ * The typed edges touching the subject, grouped by TABLE and then by side,
86
+ * and named with the FRAMEWORK's own two words
87
+ * (`ReadingRelationDef.sides`).
88
+ *
89
+ * One line per (table, side) rather than per side, since a profile may
90
+ * declare several tables (`ReadingProfile.alsoRelations`): a UML use case
91
+ * associated with an actor and including another use case has two sentences
92
+ * to say and they are not the same sentence. A framework declaring one table
93
+ * — which is every framework but UML — renders exactly what it did before.
87
94
  *
88
95
  * The `data-testid` keeps the shape it shipped with — `reading-consumers`,
89
96
  * `reading-suppliers` — because it names the SIDE, which is generic, and not
90
- * the wording, which is now the framework's.
97
+ * the wording, which is the framework's. `data-relation-role` is what tells
98
+ * two lines of the same side apart.
99
+ *
100
+ * The FAR end's label rides with the name, in parentheses: a UML association
101
+ * writes its multiplicity there (ADR 0020) and "Associated with: OrderLine
102
+ * (1..*)" is the sentence an author drew. The subject's OWN end label is read
103
+ * too ({@link ReadingRelation.ownEndLabel}) and deliberately not printed —
104
+ * one line about the other end, not a transcription of the connector.
91
105
  */
92
106
  private _renderRelations;
93
107
  /**
@@ -40,7 +40,7 @@ import { css, html, nothing } from 'lit';
40
40
  import { state } from 'lit/decorators.js';
41
41
  import { literal, unsafeStatic } from 'lit/static-html.js';
42
42
  import { EditorAnchoredPanel, editorAnchoredPanelStyles, } from './editor-anchored-panel.js';
43
- import { PivotRecordPickerProvider, ReadingManager, readRecord, readValueFlows, } from './reading.js';
43
+ import { PivotRecordPickerProvider, ReadingManager, readingRelationDefs, readRecord, readValueFlows, } from './reading.js';
44
44
  export const READING_PROPOSAL_WIDGET = 'affine-reading-proposal-widget';
45
45
  /** The two commands the confirmations drive. Spelled once. */
46
46
  const TAG_SET_ID = 'tag.set';
@@ -411,37 +411,59 @@ let ReadingProposalWidget = (() => {
411
411
  : nothing}`);
412
412
  }
413
413
  /**
414
- * The typed edges touching the subject, grouped by side and named with the
415
- * FRAMEWORK's own two words (`ReadingRelationDef.sides`).
414
+ * The typed edges touching the subject, grouped by TABLE and then by side,
415
+ * and named with the FRAMEWORK's own two words
416
+ * (`ReadingRelationDef.sides`).
417
+ *
418
+ * One line per (table, side) rather than per side, since a profile may
419
+ * declare several tables (`ReadingProfile.alsoRelations`): a UML use case
420
+ * associated with an actor and including another use case has two sentences
421
+ * to say and they are not the same sentence. A framework declaring one table
422
+ * — which is every framework but UML — renders exactly what it did before.
416
423
  *
417
424
  * The `data-testid` keeps the shape it shipped with — `reading-consumers`,
418
425
  * `reading-suppliers` — because it names the SIDE, which is generic, and not
419
- * the wording, which is now the framework's.
426
+ * the wording, which is the framework's. `data-relation-role` is what tells
427
+ * two lines of the same side apart.
428
+ *
429
+ * The FAR end's label rides with the name, in parentheses: a UML association
430
+ * writes its multiplicity there (ADR 0020) and "Associated with: OrderLine
431
+ * (1..*)" is the sentence an author drew. The subject's OWN end label is read
432
+ * too ({@link ReadingRelation.ownEndLabel}) and deliberately not printed —
433
+ * one line about the other end, not a transcription of the connector.
420
434
  */
421
435
  _renderRelations(reading, profile) {
422
- const sides = profile.relation?.sides;
423
- const line = (side) => {
424
- const relations = reading.relations.filter(r => r.side === side);
425
- const wording = sides?.[side];
436
+ const named = (relation) => {
437
+ const name = relation.otherName || relation.otherId;
438
+ return relation.otherEndLabel
439
+ ? `${name} (${relation.otherEndLabel})`
440
+ : name;
441
+ };
442
+ const line = (edgeRole, side) => {
443
+ const relations = reading.relations.filter(r => r.side === side && r.relationRole === edgeRole);
444
+ const wording = readingRelationDefs(profile).find(def => def.edgeRole === edgeRole)?.sides[side];
426
445
  // No wording means the framework declared no relation at all, in which
427
446
  // case there is nothing to list either. Silence rather than a heading
428
447
  // this library would have had to invent.
429
448
  if (!relations.length || !wording)
430
449
  return nothing;
431
- return html `<div class="reading-value" data-testid=${`reading-${side}s`}>
450
+ return html `<div
451
+ class="reading-value"
452
+ data-testid=${`reading-${side}s`}
453
+ data-relation-role=${edgeRole}
454
+ >
432
455
  ${translateKey(this.std, wording.labelKey, wording.labelFallback)}:
433
- ${relations
434
- .map(relation => relation.otherName || relation.otherId)
435
- .join(', ')}
456
+ ${relations.map(named).join(', ')}
436
457
  </div>`;
437
458
  };
459
+ const lines = readingRelationDefs(profile).flatMap(def => RELATION_SIDES.map(side => line(def.edgeRole, side)));
438
460
  const contradictions = reading.relations.filter(r => r.contradictsGeometry);
439
461
  return this._field('reading-relations', translateKey(this.std, 'com.labre.reading.field.relations', 'Parent-child relations'), html `${reading.relations.length === 0
440
462
  ? html `<div class="reading-empty">
441
463
  ${translateKey(this.std, 'com.labre.reading.relations.none', 'No typed link touches this component.')}
442
464
  </div>`
443
465
  : nothing}
444
- ${RELATION_SIDES.map(line)}
466
+ ${lines}
445
467
  ${contradictions.length
446
468
  ? html `<div class="reading-note" data-testid="reading-contradiction">
447
469
  ${translateKey(this.std, 'com.labre.reading.relations.contradiction', 'A link states the opposite of what the positions show')}: