@formicoidea/labre-core 0.41.0 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/LICENSE +384 -0
  2. package/dist/_pkgs/affine-block-bookmark/bookmark-block.js +2 -2
  3. package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/config.js +7 -1
  4. package/dist/_pkgs/affine-block-embed/embed-figma-block/embed-figma-block.js +2 -1
  5. package/dist/_pkgs/affine-block-embed/embed-github-block/embed-github-block.js +2 -1
  6. package/dist/_pkgs/affine-block-embed/embed-iframe-block/consts.d.ts +2 -0
  7. package/dist/_pkgs/affine-block-embed/embed-iframe-block/consts.js +5 -0
  8. package/dist/_pkgs/affine-block-embed/embed-iframe-block/embed-iframe-block.d.ts +1 -0
  9. package/dist/_pkgs/affine-block-embed/embed-iframe-block/embed-iframe-block.js +30 -8
  10. package/dist/_pkgs/affine-block-embed/embed-iframe-block/utils.d.ts +8 -0
  11. package/dist/_pkgs/affine-block-embed/embed-iframe-block/utils.js +19 -0
  12. package/dist/_pkgs/affine-block-embed/embed-loom-block/embed-loom-block.js +2 -1
  13. package/dist/_pkgs/affine-block-embed/embed-youtube-block/embed-youtube-block.js +2 -1
  14. package/dist/_pkgs/affine-block-frame/frame-manager.js +1 -1
  15. package/dist/_pkgs/affine-block-frame/frame-tool.js +1 -1
  16. package/dist/_pkgs/affine-block-frame/frame-toolbar.js +6 -1
  17. package/dist/_pkgs/affine-block-list/list-keymap.js +7 -0
  18. package/dist/_pkgs/affine-block-note/note-keymap.js +7 -1
  19. package/dist/_pkgs/affine-block-paragraph/paragraph-keymap.js +7 -1
  20. package/dist/_pkgs/affine-block-root/commands/pivot-commands.js +1 -8
  21. package/dist/_pkgs/affine-block-root/commands/tag-commands.js +1 -8
  22. package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.d.ts +9 -0
  23. package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.js +51 -0
  24. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.d.ts +22 -0
  25. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.js +46 -0
  26. package/dist/_pkgs/affine-block-root/edgeless/utils/pinch-zoom.d.ts +21 -0
  27. package/dist/_pkgs/affine-block-root/edgeless/utils/pinch-zoom.js +24 -0
  28. package/dist/_pkgs/affine-block-root/edgeless/utils/query.js +8 -0
  29. package/dist/_pkgs/affine-block-root/keyboard/keymap.js +1 -16
  30. package/dist/_pkgs/affine-block-surface/element-model/index.d.ts +21 -3
  31. package/dist/_pkgs/affine-block-surface/element-model/index.js +14 -2
  32. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.d.ts +23 -0
  33. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.js +89 -0
  34. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.d.ts +7 -0
  35. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.js +5 -0
  36. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.d.ts +41 -0
  37. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +70 -0
  38. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.d.ts +49 -0
  39. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.js +257 -0
  40. package/dist/_pkgs/affine-block-surface/extensions/export-svg/tagged-path.d.ts +16 -0
  41. package/dist/_pkgs/affine-block-surface/extensions/export-svg/tagged-path.js +24 -0
  42. package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.d.ts +24 -0
  43. package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.js +66 -0
  44. package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +4 -0
  45. package/dist/_pkgs/affine-block-surface/extensions/index.js +4 -0
  46. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.d.ts +66 -4
  47. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.js +241 -11
  48. package/dist/_pkgs/affine-block-surface/extensions/interchange.d.ts +18 -0
  49. package/dist/_pkgs/affine-block-surface/extensions/legend-toolbar.d.ts +81 -0
  50. package/dist/_pkgs/affine-block-surface/extensions/legend-toolbar.js +81 -0
  51. package/dist/_pkgs/affine-block-surface/extensions/legend.d.ts +136 -0
  52. package/dist/_pkgs/affine-block-surface/extensions/legend.js +439 -0
  53. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.d.ts +17 -3
  54. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.js +35 -13
  55. package/dist/_pkgs/affine-block-surface/extensions/reading.d.ts +61 -1
  56. package/dist/_pkgs/affine-block-surface/extensions/reading.js +85 -39
  57. package/dist/_pkgs/affine-block-surface/extensions/record-action.d.ts +66 -0
  58. package/dist/_pkgs/affine-block-surface/extensions/record-action.js +145 -0
  59. package/dist/_pkgs/affine-block-surface/extensions/validation.d.ts +253 -28
  60. package/dist/_pkgs/affine-block-surface/extensions/validation.js +489 -41
  61. package/dist/_pkgs/affine-block-surface/framework-background/background-view.d.ts +115 -0
  62. package/dist/_pkgs/affine-block-surface/framework-background/background-view.js +185 -0
  63. package/dist/_pkgs/affine-block-surface/framework-background/index.d.ts +1 -0
  64. package/dist/_pkgs/affine-block-surface/framework-background/index.js +1 -0
  65. package/dist/_pkgs/affine-block-surface/framework-background/labels.d.ts +16 -1
  66. package/dist/_pkgs/affine-block-surface/framework-background/labels.js +31 -21
  67. package/dist/_pkgs/affine-block-surface/framework-background/renderer.js +29 -5
  68. package/dist/_pkgs/affine-block-surface/framework-background/stacking.d.ts +6 -4
  69. package/dist/_pkgs/affine-block-surface/framework-background/stacking.js +56 -8
  70. package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.d.ts +12 -0
  71. package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.js +15 -0
  72. package/dist/_pkgs/affine-block-surface/view.js +8 -1
  73. package/dist/_pkgs/affine-block-surface-ref/configs/slash-menu.js +1 -1
  74. package/dist/_pkgs/affine-components/color-picker/button.d.ts +56 -1
  75. package/dist/_pkgs/affine-components/color-picker/button.js +168 -23
  76. package/dist/_pkgs/affine-components/color-picker/framework-palette.d.ts +106 -0
  77. package/dist/_pkgs/affine-components/color-picker/framework-palette.js +177 -0
  78. package/dist/_pkgs/affine-components/color-picker/index.d.ts +2 -0
  79. package/dist/_pkgs/affine-components/color-picker/index.js +2 -0
  80. package/dist/_pkgs/affine-components/color-picker/palette-carousel.d.ts +85 -0
  81. package/dist/_pkgs/affine-components/color-picker/palette-carousel.js +440 -0
  82. package/dist/_pkgs/affine-components/edgeless-shape-color-picker/color-picker.d.ts +31 -1
  83. package/dist/_pkgs/affine-components/edgeless-shape-color-picker/color-picker.js +189 -63
  84. package/dist/_pkgs/affine-components/resource/resource.js +29 -16
  85. package/dist/_pkgs/affine-components/translations.d.ts +8 -0
  86. package/dist/_pkgs/affine-components/translations.js +17 -0
  87. package/dist/_pkgs/affine-foundation/view.js +2 -1
  88. package/dist/_pkgs/affine-gfx-brush/element-renderer.js +2 -2
  89. package/dist/_pkgs/affine-gfx-brush/toolbar/configs/brush.js +6 -1
  90. package/dist/_pkgs/affine-gfx-brush/toolbar/configs/highlighter.js +6 -1
  91. package/dist/_pkgs/affine-gfx-connector/connector-manager.d.ts +9 -1
  92. package/dist/_pkgs/affine-gfx-connector/connector-manager.js +61 -0
  93. package/dist/_pkgs/affine-gfx-connector/element-renderer/connector-dom/index.d.ts +7 -1
  94. package/dist/_pkgs/affine-gfx-connector/element-renderer/connector-dom/index.js +87 -17
  95. package/dist/_pkgs/affine-gfx-connector/element-renderer/index.js +78 -17
  96. package/dist/_pkgs/affine-gfx-connector/element-renderer/utils.d.ts +24 -2
  97. package/dist/_pkgs/affine-gfx-connector/element-renderer/utils.js +31 -8
  98. package/dist/_pkgs/affine-gfx-connector/text/edgeless-connector-label-editor.d.ts +124 -3
  99. package/dist/_pkgs/affine-gfx-connector/text/edgeless-connector-label-editor.js +216 -54
  100. package/dist/_pkgs/affine-gfx-connector/text/text.d.ts +13 -4
  101. package/dist/_pkgs/affine-gfx-connector/text/text.js +13 -44
  102. package/dist/_pkgs/affine-gfx-connector/toolbar/config.d.ts +56 -0
  103. package/dist/_pkgs/affine-gfx-connector/toolbar/config.js +72 -4
  104. package/dist/_pkgs/affine-gfx-connector/toolbar/hollow-endpoint-icons.d.ts +8 -0
  105. package/dist/_pkgs/affine-gfx-connector/toolbar/hollow-endpoint-icons.js +118 -0
  106. package/dist/_pkgs/affine-gfx-connector/view/view.d.ts +37 -1
  107. package/dist/_pkgs/affine-gfx-connector/view/view.js +97 -8
  108. package/dist/_pkgs/affine-gfx-group/command/group-api.js +1 -1
  109. package/dist/_pkgs/affine-gfx-group/store.js +0 -2
  110. package/dist/_pkgs/affine-gfx-group/translations.d.ts +9 -10
  111. package/dist/_pkgs/affine-gfx-group/translations.js +9 -13
  112. package/dist/_pkgs/affine-gfx-mindmap/templates/index.js +1 -1
  113. package/dist/_pkgs/affine-gfx-mindmap/toolbar/basket-elements.js +1 -1
  114. package/dist/_pkgs/affine-gfx-mindmap/toolbar/utils/import-mindmap.js +2 -2
  115. package/dist/_pkgs/affine-gfx-mindmap/translations.d.ts +1 -1
  116. package/dist/_pkgs/affine-gfx-mindmap/translations.js +1 -1
  117. package/dist/_pkgs/affine-gfx-shape/element-renderer/highlighter.js +2 -2
  118. package/dist/_pkgs/affine-gfx-shape/overlay/polygon-drawing-overlay.d.ts +6 -0
  119. package/dist/_pkgs/affine-gfx-shape/overlay/polygon-drawing-overlay.js +30 -1
  120. package/dist/_pkgs/affine-gfx-shape/polygon-tool.d.ts +20 -1
  121. package/dist/_pkgs/affine-gfx-shape/polygon-tool.js +9 -1
  122. package/dist/_pkgs/affine-gfx-shape/toolbar/config.js +6 -1
  123. package/dist/_pkgs/affine-gfx-shape/toolbar/palette-color-action.js +11 -1
  124. package/dist/_pkgs/affine-gfx-template/builtin/other.js +1 -1
  125. package/dist/_pkgs/affine-gfx-template/snapshot-from-action.js +32 -119
  126. package/dist/_pkgs/affine-gfx-template/toolbar/template-type.d.ts +1 -1
  127. package/dist/_pkgs/affine-gfx-text/dblclick-add-edgeless-text.d.ts +13 -1
  128. package/dist/_pkgs/affine-gfx-text/dblclick-add-edgeless-text.js +19 -4
  129. package/dist/_pkgs/affine-gfx-text/edgeless-text-editor.d.ts +41 -0
  130. package/dist/_pkgs/affine-gfx-text/edgeless-text-editor.js +57 -2
  131. package/dist/_pkgs/affine-gfx-text/toolbar/actions.d.ts +8 -1
  132. package/dist/_pkgs/affine-gfx-text/toolbar/actions.js +12 -2
  133. package/dist/_pkgs/affine-gfx-text/translations.d.ts +1 -0
  134. package/dist/_pkgs/affine-gfx-text/translations.js +2 -1
  135. package/dist/_pkgs/affine-inline-preset/markdown.js +5 -1
  136. package/dist/_pkgs/affine-model/consts/connector.d.ts +28 -2
  137. package/dist/_pkgs/affine-model/consts/connector.js +26 -0
  138. package/dist/_pkgs/affine-model/elements/bpmn/pool.js +1 -1
  139. package/dist/_pkgs/affine-model/elements/brush/brush.js +1 -1
  140. package/dist/_pkgs/affine-model/elements/c4/board.js +1 -1
  141. package/dist/_pkgs/affine-model/elements/c4/boundary.js +1 -1
  142. package/dist/_pkgs/affine-model/elements/connector/connector.d.ts +135 -0
  143. package/dist/_pkgs/affine-model/elements/connector/connector.js +246 -5
  144. package/dist/_pkgs/affine-model/elements/connector/end-label.d.ts +83 -0
  145. package/dist/_pkgs/affine-model/elements/connector/end-label.js +119 -0
  146. package/dist/_pkgs/affine-model/elements/connector/index.d.ts +1 -0
  147. package/dist/_pkgs/affine-model/elements/connector/index.js +1 -0
  148. package/dist/_pkgs/affine-model/elements/context-map/context-map.js +1 -1
  149. package/dist/_pkgs/affine-model/elements/core-domain/core-domain.d.ts +28 -0
  150. package/dist/_pkgs/affine-model/elements/core-domain/core-domain.js +129 -2
  151. package/dist/_pkgs/affine-model/elements/cynefin/cynefin.d.ts +8 -0
  152. package/dist/_pkgs/affine-model/elements/cynefin/cynefin.js +45 -2
  153. package/dist/_pkgs/affine-model/elements/edgy/board.js +1 -1
  154. package/dist/_pkgs/affine-model/elements/edgy/facets.js +1 -1
  155. package/dist/_pkgs/affine-model/elements/estuarine/estuarine.d.ts +6 -0
  156. package/dist/_pkgs/affine-model/elements/estuarine/estuarine.js +36 -2
  157. package/dist/_pkgs/affine-model/elements/event-storming/event-storming.d.ts +18 -7
  158. package/dist/_pkgs/affine-model/elements/event-storming/event-storming.js +23 -8
  159. package/dist/_pkgs/affine-model/elements/framework-background/background.d.ts +16 -0
  160. package/dist/_pkgs/affine-model/elements/framework-background/background.js +18 -0
  161. package/dist/_pkgs/affine-model/elements/highlighter/highlighter.js +1 -1
  162. package/dist/_pkgs/affine-model/elements/index.d.ts +8 -0
  163. package/dist/_pkgs/affine-model/elements/index.js +1 -0
  164. package/dist/_pkgs/affine-model/elements/shape/shape.js +1 -1
  165. package/dist/_pkgs/affine-model/elements/text/text.js +1 -1
  166. package/dist/_pkgs/affine-model/elements/uml/band.d.ts +39 -0
  167. package/dist/_pkgs/affine-model/elements/uml/band.js +31 -0
  168. package/dist/_pkgs/affine-model/elements/uml/diagram.d.ts +158 -0
  169. package/dist/_pkgs/affine-model/elements/uml/diagram.js +229 -0
  170. package/dist/_pkgs/affine-model/elements/uml/fragment.d.ts +161 -0
  171. package/dist/_pkgs/affine-model/elements/uml/fragment.js +205 -0
  172. package/dist/_pkgs/affine-model/elements/uml/index.d.ts +8 -0
  173. package/dist/_pkgs/affine-model/elements/uml/index.js +8 -0
  174. package/dist/_pkgs/affine-model/elements/uml/lifeline.d.ts +77 -0
  175. package/dist/_pkgs/affine-model/elements/uml/lifeline.js +89 -0
  176. package/dist/_pkgs/affine-model/elements/uml/node.d.ts +142 -0
  177. package/dist/_pkgs/affine-model/elements/uml/node.js +190 -0
  178. package/dist/_pkgs/affine-model/elements/uml/partition.d.ts +106 -0
  179. package/dist/_pkgs/affine-model/elements/uml/partition.js +172 -0
  180. package/dist/_pkgs/affine-model/elements/uml/region.d.ts +75 -0
  181. package/dist/_pkgs/affine-model/elements/uml/region.js +150 -0
  182. package/dist/_pkgs/affine-model/elements/uml/subject.d.ts +37 -0
  183. package/dist/_pkgs/affine-model/elements/uml/subject.js +108 -0
  184. package/dist/_pkgs/affine-model/elements/wardley/wardley.js +1 -1
  185. package/dist/_pkgs/affine-shared/services/embed-iframe/embed-iframe-config.d.ts +1 -0
  186. package/dist/_pkgs/affine-shared/services/font-loader/config.d.ts +7 -0
  187. package/dist/_pkgs/affine-shared/services/font-loader/config.js +43 -0
  188. package/dist/_pkgs/affine-shared/services/pivot-materiality-publisher.js +1 -9
  189. package/dist/_pkgs/affine-shared/services/telemetry-service/document-damage-watcher.d.ts +53 -0
  190. package/dist/_pkgs/affine-shared/services/telemetry-service/document-damage-watcher.js +95 -0
  191. package/dist/_pkgs/affine-shared/services/telemetry-service/index.d.ts +1 -0
  192. package/dist/_pkgs/affine-shared/services/telemetry-service/index.js +1 -0
  193. package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +26 -1
  194. package/dist/_pkgs/affine-shared/services/telemetry-service/telemetry-service.d.ts +2 -2
  195. package/dist/_pkgs/affine-shared/services/toolbar-service/command-action.d.ts +34 -0
  196. package/dist/_pkgs/affine-shared/services/toolbar-service/command-action.js +63 -0
  197. package/dist/_pkgs/affine-shared/services/toolbar-service/index.d.ts +1 -0
  198. package/dist/_pkgs/affine-shared/services/toolbar-service/index.js +1 -0
  199. package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +77 -7
  200. package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +97 -7
  201. package/dist/_pkgs/affine-shared/styles/index.d.ts +1 -0
  202. package/dist/_pkgs/affine-shared/styles/index.js +1 -0
  203. package/dist/_pkgs/affine-shared/styles/motion.d.ts +14 -0
  204. package/dist/_pkgs/affine-shared/styles/motion.js +38 -0
  205. package/dist/_pkgs/affine-shared/utils/event.d.ts +10 -0
  206. package/dist/_pkgs/affine-shared/utils/event.js +20 -0
  207. package/dist/_pkgs/affine-shared/utils/file/filesys.d.ts +16 -0
  208. package/dist/_pkgs/affine-shared/utils/file/filesys.js +25 -0
  209. package/dist/_pkgs/affine-shared/utils/index.d.ts +1 -0
  210. package/dist/_pkgs/affine-shared/utils/index.js +1 -0
  211. package/dist/_pkgs/affine-shared/utils/link-preview-refresh.d.ts +12 -0
  212. package/dist/_pkgs/affine-shared/utils/link-preview-refresh.js +13 -0
  213. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.d.ts +12 -4
  214. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.js +27 -4
  215. package/dist/_pkgs/affine-widget-edgeless-toolbar/create-popper.js +13 -0
  216. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.d.ts +2 -0
  217. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.js +2 -0
  218. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.d.ts +80 -0
  219. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.js +270 -81
  220. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/senior-menu-selection.d.ts +15 -0
  221. package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/senior-menu-selection.js +15 -0
  222. package/dist/_pkgs/affine-widget-edgeless-toolbar/panel/font-weight-and-style-panel.js +8 -1
  223. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-ghost-overlay.d.ts +42 -0
  224. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-ghost-overlay.js +100 -0
  225. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-placement-tool.d.ts +100 -0
  226. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/artefact-placement-tool.js +274 -0
  227. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/index.d.ts +3 -0
  228. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/index.js +3 -0
  229. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/translate-created.d.ts +25 -0
  230. package/dist/_pkgs/affine-widget-edgeless-toolbar/placement/translate-created.js +67 -0
  231. package/dist/_pkgs/affine-widget-edgeless-toolbar/view.js +5 -0
  232. package/dist/_pkgs/global/gfx/xywh.js +7 -0
  233. package/dist/_pkgs/std/extension/command-registry.d.ts +158 -1
  234. package/dist/_pkgs/std/extension/command-registry.js +22 -0
  235. package/dist/_pkgs/std/gfx/index.d.ts +1 -1
  236. package/dist/_pkgs/std/gfx/interactivity/gfx-view-event-handler.d.ts +12 -0
  237. package/dist/_pkgs/std/gfx/interactivity/gfx-view-event-handler.js +20 -1
  238. package/dist/_pkgs/std/gfx/interactivity/manager.d.ts +10 -0
  239. package/dist/_pkgs/std/gfx/interactivity/manager.js +12 -0
  240. package/dist/_pkgs/std/gfx/model/surface/element-model.js +12 -7
  241. package/dist/_pkgs/std/gfx/model/surface/surface-model.d.ts +56 -0
  242. package/dist/_pkgs/std/gfx/model/surface/surface-model.js +84 -3
  243. package/dist/_pkgs/std/gfx/view/view.d.ts +11 -2
  244. package/dist/_pkgs/std/gfx/view/view.js +16 -2
  245. package/dist/commands.d.ts +6 -0
  246. package/dist/commands.js +8 -1
  247. package/dist/frameworks.d.ts +9 -0
  248. package/dist/frameworks.js +19 -0
  249. package/dist/translations.js +16 -0
  250. package/package.json +9 -4
  251. package/dist/_pkgs/affine-gfx-group/group-watcher.d.ts +0 -1
  252. package/dist/_pkgs/affine-gfx-group/group-watcher.js +0 -20
@@ -59,10 +59,39 @@ export class PolygonDrawingOverlay extends ToolOverlay {
59
59
  _effectiveStrokeColor() {
60
60
  return this._strokeStyle === 'none' ? 'transparent' : this._strokeColor;
61
61
  }
62
+ /**
63
+ * The marker shown at the pointer while the tool is armed and empty: the same
64
+ * dot the first placed vertex gets, plus a light ring, so the promise the
65
+ * cursor makes is the shape the click keeps.
66
+ */
67
+ _renderFirstVertexHint(ctx, [cx, cy]) {
68
+ const zoom = this.gfx.viewport.zoom;
69
+ ctx.beginPath();
70
+ ctx.arc(cx, cy, VERTEX_INDICATOR_RADIUS, 0, Math.PI * 2);
71
+ ctx.fillStyle = this._strokeColor;
72
+ ctx.fill();
73
+ ctx.beginPath();
74
+ ctx.arc(cx, cy, CLOSE_SNAP_INDICATOR_RADIUS / zoom, 0, Math.PI * 2);
75
+ ctx.strokeStyle = this._strokeColor;
76
+ ctx.lineWidth = 1.5 / zoom;
77
+ ctx.setLineDash([]);
78
+ ctx.globalAlpha = this.globalAlpha * 0.4;
79
+ ctx.stroke();
80
+ ctx.globalAlpha = this.globalAlpha;
81
+ }
62
82
  render(ctx, _rc) {
63
83
  const { vertices, cursorPos, isDrawing } = this;
64
84
  ctx.globalAlpha = this.globalAlpha;
65
- if (!isDrawing || vertices.length === 0)
85
+ if (vertices.length === 0) {
86
+ // Nothing is placed yet, so there is no outline to preview — but the tool
87
+ // IS armed, and until now the canvas said nothing about it. Marking where
88
+ // the next click would land a corner is what tells the author the board
89
+ // is waiting for a first vertex rather than ignoring the pointer.
90
+ if (cursorPos)
91
+ this._renderFirstVertexHint(ctx, cursorPos);
92
+ return;
93
+ }
94
+ if (!isDrawing)
66
95
  return;
67
96
  const effectiveStroke = this._effectiveStrokeColor();
68
97
  const strokeWidth = Math.max(this._strokeWidth, 1);
@@ -1,6 +1,25 @@
1
1
  import type { PointerEventState } from '../std/index.js';
2
2
  import { BaseTool, type GfxController } from '../std/gfx/index.js';
3
- export type PolygonToolOption = Record<string, unknown>;
3
+ export type PolygonToolOption = {
4
+ /**
5
+ * Props the activation stamps on the shape the closed outline produces — the
6
+ * same seam `ConnectorTool`'s `role` / `style` options are: a framework arms
7
+ * this tool to draw ITS artefact (a Wardley zone) rather than a plain
8
+ * polygon, so the element is born typed instead of being converted after the
9
+ * fact. Absent for the plain polygon tool, which keeps drawing a shape.
10
+ *
11
+ * Merged BEFORE the geometry: a framework's description of an artefact
12
+ * carries the box and the outline it would have been born with, and the
13
+ * outline the author just drew must win over both.
14
+ */
15
+ props?: Record<string, unknown>;
16
+ /**
17
+ * Called once the element exists, for the placement an element description
18
+ * cannot express — a Wardley zone has to be lowered to just above the map it
19
+ * covers, which depends on what is already on the board.
20
+ */
21
+ onCreated?: (gfx: GfxController, id: string) => void;
22
+ };
4
23
  /**
5
24
  * PolygonTool allows users to draw arbitrary polygons by clicking to place
6
25
  * vertices on the edgeless canvas. The polygon is finalised by either:
@@ -228,8 +228,15 @@ export class PolygonTool extends BaseTool {
228
228
  const id = this.gfx.surface.addElement({
229
229
  type: CanvasElementType.SHAPE,
230
230
  shapeType: ShapeType.Polygon,
231
- xywh: bound.serialize(),
232
231
  radius: 0,
232
+ // What the activation asked for, if anything — it may change the element
233
+ // type itself, which is how a framework gets its own artefact out of this
234
+ // gesture. Spread here so the geometry below always wins: the props of a
235
+ // framework artefact describe the shape it would have been born with,
236
+ // outline included, and that outline is exactly what the author just
237
+ // replaced by drawing.
238
+ ...this.activatedOption.props,
239
+ xywh: bound.serialize(),
233
240
  vertices: normalizedVertices,
234
241
  isClosed: true,
235
242
  smoothFlags: smoothFlagsForModel,
@@ -237,6 +244,7 @@ export class PolygonTool extends BaseTool {
237
244
  ? { controlPoints: controlPointsForModel }
238
245
  : {}),
239
246
  });
247
+ this.activatedOption.onCreated?.(this.gfx, id);
240
248
  this.std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
241
249
  control: 'canvas:draw',
242
250
  page: 'whiteboard editor',
@@ -1,5 +1,5 @@
1
1
  import { EdgelessCRUDIdentifier } from '../../affine-block-surface/index.js';
2
- import { packColor, } from '../../affine-components/color-picker/index.js';
2
+ import { frameworkPaletteGroups, packColor, } from '../../affine-components/color-picker/index.js';
3
3
  import { createTextActions } from '../../affine-gfx-text/index.js';
4
4
  import { DefaultTheme, FontFamily, getShapeName, getShapeRadius, getShapeType, isTransparent, LineWidth, MindmapElementModel, resolveColor, ShapeElementModel, ShapeStyle, ShapeType, StrokeStyle, TextFitMode, } from '../../affine-model/index.js';
5
5
  import { STYLE_MENU_LABEL, ToolbarModuleExtension, translateKey, } from '../../affine-shared/services/index.js';
@@ -192,11 +192,16 @@ export const shapeToolbarConfig = {
192
192
  .updateElement(model.id, { strokeStyle });
193
193
  }
194
194
  };
195
+ // The base palette, plus a page per framework whose tooling is on —
196
+ // opening on the one the selection belongs to (`docs/adr/0027`).
197
+ const carousel = frameworkPaletteGroups(ctx.std, models, DefaultTheme.Palettes);
195
198
  return html `
196
199
  <edgeless-shape-color-picker
197
200
  @pickFillColor=${onPickFillColor}
198
201
  @pickStrokeColor=${onPickStrokeColor}
199
202
  @pickStrokeStyle=${onPickStrokeStyle}
203
+ .paletteGroups=${carousel.groups}
204
+ .activeGroupKey=${carousel.activeKey}
200
205
  .payload=${{
201
206
  fillColor,
202
207
  strokeColor,
@@ -1,5 +1,5 @@
1
1
  import { EdgelessCRUDIdentifier } from '../../affine-block-surface/index.js';
2
- import { packColor, } from '../../affine-components/color-picker/index.js';
2
+ import { frameworkPaletteGroups, packColor, } from '../../affine-components/color-picker/index.js';
3
3
  import { DefaultTheme, isTransparent, LineWidth, resolveColor, ShapeElementModel, StrokeStyle, } from '../../affine-model/index.js';
4
4
  import { getMostCommonValue } from '../../affine-shared/utils/index.js';
5
5
  import { html } from 'lit';
@@ -99,12 +99,22 @@ export function paletteColorAction(id, palettes, fillColorFor = (_model, value)
99
99
  crud.updateElement(model.id, props);
100
100
  }
101
101
  };
102
+ // The carousel: the editor palette, then a page per framework whose
103
+ // tooling is on. A Wardley node resolves to `wardley` and therefore
104
+ // OPENS on the very swatches `palettes` holds, since the framework
105
+ // registers that same list (`docs/adr/0027`). With its flag off the
106
+ // framework contributes no page and the picker opens on the editor
107
+ // palette — a palette is tooling (`docs/adr/0009`), the colour already
108
+ // stored is not and does not move.
109
+ const carousel = frameworkPaletteGroups(ctx.std, models, DefaultTheme.Palettes);
102
110
  return html `
103
111
  <edgeless-shape-color-picker
104
112
  @pickFillColor=${onPickFillColor}
105
113
  @pickStrokeColor=${onPickStrokeColor}
106
114
  @pickStrokeStyle=${onPickStrokeStyle}
107
115
  .palettes=${palettes}
116
+ .paletteGroups=${carousel.groups}
117
+ .activeGroupKey=${carousel.activeKey}
108
118
  .payload=${{
109
119
  fillColor,
110
120
  strokeColor,
@@ -258,7 +258,7 @@ const previews = {
258
258
  /**
259
259
  * A hand-composed template — what is left once the artefacts are derived. The
260
260
  * seeds a template writes into the document go through the translation seam
261
- * at placement (ADR 0016); `content` stays the English build, and `localize`
261
+ * at placement (ADR 0023); `content` stays the English build, and `localize`
262
262
  * rebuilds the same snapshot with translated seeds.
263
263
  */
264
264
  function t(name, preview, build) {
@@ -1,7 +1,5 @@
1
- import { EdgelessCRUDIdentifier } from '../affine-block-surface/index.js';
2
- import { TranslationProvider } from '../affine-shared/services/index.js';
1
+ import { recordAction } from '../affine-block-surface/index.js';
3
2
  import { Bound } from '../global/gfx/index.js';
4
- import { generateKeyBetween, GfxControllerIdentifier } from '../std/gfx/index.js';
5
3
  import * as Y from 'yjs';
6
4
  import { makeTemplateSnapshot, surfaceText, surfaceYMap, } from './make-snapshot.js';
7
5
  /**
@@ -35,124 +33,39 @@ function materialize(text) {
35
33
  * the action writes its English fallbacks.
36
34
  */
37
35
  export function snapshotFromAction(run, name, host) {
38
- const elements = new Map();
39
- let n = 0;
40
- let lastIndex = null;
41
- const nextIndex = () => (lastIndex = generateKeyBetween(lastIndex, null));
42
- const addElement = (props) => {
43
- const id = `el-${n++}`;
44
- const record = {};
45
- for (const [key, value] of Object.entries(props)) {
46
- if (value !== undefined)
47
- record[key] = value;
48
- }
49
- record['id'] = id;
50
- // ponytail: the Y conversions are hard-coded (`text`, and a group's
51
- // `children` / `title`) instead of asking each element class for its own
52
- // `propsToY`. Ceiling: it covers every prop the framework actions pass
53
- // today. Upgrade path: run the real `propsToY` once the element-ctor map is
54
- // reachable without a live surface.
55
- const text = record['text'];
56
- if (typeof text === 'string')
57
- record['text'] = surfaceText(text);
58
- else if (text instanceof Y.Text)
59
- record['text'] = surfaceText(materialize(text));
60
- if (record['type'] === 'group') {
61
- const children = record['children'];
62
- if (children && typeof children === 'object') {
63
- record['children'] = surfaceYMap(Object.fromEntries(Object.keys(children).map(key => [key, true])));
64
- }
65
- const title = record['title'];
66
- if (typeof title === 'string')
67
- record['title'] = surfaceText(title);
68
- else if (title instanceof Y.Text)
69
- record['title'] = surfaceText(materialize(title));
70
- }
71
- if (record['index'] === undefined)
72
- record['index'] = nextIndex();
73
- // The model members an action reads back off `getElementById`, kept
74
- // non-enumerable so they never leak into the snapshot.
75
- Object.defineProperties(record, {
76
- group: { value: null },
77
- deserializedXYWH: {
78
- get: () => typeof record['xywh'] === 'string'
79
- ? Bound.deserialize(record['xywh'])
80
- : null,
81
- },
82
- });
83
- elements.set(id, record);
84
- return id;
85
- };
86
- const records = () => [...elements.values()];
87
- const surface = {
88
- addElement,
89
- getElementById: (id) => elements.get(id) ?? null,
90
- getElementsByType: (type) => records().filter(el => el['type'] === type),
91
- get elementModels() {
92
- return records();
93
- },
94
- };
95
- const gfx = {
96
- surface,
97
- viewport: { centerX: 0, centerY: 0, zoom: 1, center: { x: 0, y: 0 } },
98
- doc: { captureSync: () => { } },
99
- selection: { set: () => { }, selectedElements: [] },
100
- tool: { setTool: () => { } },
101
- layer: {
102
- generateIndex: () => nextIndex(),
103
- getReorderedIndex: (_model, direction) => {
104
- const sorted = records()
105
- .map(el => String(el['index']))
106
- .sort();
107
- return direction === 'back'
108
- ? generateKeyBetween(null, sorted[0] ?? null)
109
- : generateKeyBetween(sorted[sorted.length - 1] ?? null, null);
110
- },
111
- get canvasElements() {
112
- return records();
113
- },
114
- },
115
- std: null,
116
- };
117
- const crud = {
118
- addElement: (type, props) => addElement({ ...props, type }),
119
- };
120
- const std = {
121
- get: (identifier) => {
122
- if (identifier === GfxControllerIdentifier)
123
- return gfx;
124
- if (identifier === EdgelessCRUDIdentifier)
125
- return crud;
126
- throw new Error(`snapshotFromAction: unsupported service "${identifier?.identifierName ?? String(identifier)}"`);
127
- },
128
- getOptional: (identifier) => identifier === TranslationProvider
129
- ? host?.getOptional(TranslationProvider)
130
- : undefined,
131
- command: {
132
- // Really run the command, so a group built by `createGroupCommand` is
133
- // whatever that command says a group is — no second definition here.
134
- exec: (cmd, payload) => {
135
- let out;
136
- cmd({ std: gfx.std, ...payload }, r => {
137
- out = r;
138
- });
139
- return [{}, out ?? {}];
140
- },
141
- },
142
- store: {
143
- readonly: false,
144
- captureSync: () => { },
145
- id: 'doc:template',
146
- workspace: { meta: { getDocMeta: () => undefined } },
147
- },
148
- };
149
- gfx.std = std;
150
- run(gfx.std);
151
- if (elements.size === 0) {
36
+ const { records } = recordAction(run, { host, encode: toSnapshotProps });
37
+ if (records.length === 0) {
152
38
  throw new Error('snapshotFromAction: the action added no element (a tool-arming command?)');
153
39
  }
154
- normalizeToOrigin(records());
155
- return makeTemplateSnapshot(Object.fromEntries(elements), name);
40
+ normalizeToOrigin(records);
41
+ return makeTemplateSnapshot(Object.fromEntries(records.map(record => [String(record['id']), record])), name);
42
+ }
43
+ /**
44
+ * The Y-carrying props, in the serialized form a snapshot holds them in.
45
+ *
46
+ * ponytail: the conversions are hard-coded (`text`, and a group's `children` /
47
+ * `title`) instead of asking each element class for its own `propsToY`.
48
+ * Ceiling: it covers every prop the framework actions pass today. Upgrade path:
49
+ * run the real `propsToY` once the element-ctor map is reachable without a live
50
+ * surface.
51
+ */
52
+ function toSnapshotProps(record) {
53
+ const text = record['text'];
54
+ if (typeof text === 'string')
55
+ record['text'] = surfaceText(text);
56
+ else if (text instanceof Y.Text)
57
+ record['text'] = surfaceText(materialize(text));
58
+ if (record['type'] === 'group') {
59
+ const children = record['children'];
60
+ if (children && typeof children === 'object') {
61
+ record['children'] = surfaceYMap(Object.fromEntries(Object.keys(children).map(key => [key, true])));
62
+ }
63
+ const title = record['title'];
64
+ if (typeof title === 'string')
65
+ record['title'] = surfaceText(title);
66
+ else if (title instanceof Y.Text)
67
+ record['title'] = surfaceText(materialize(title));
68
+ }
156
69
  }
157
70
  /** The connector endpoints that carry a free position rather than an anchor. */
158
71
  function freeEndpoints(el) {
@@ -46,7 +46,7 @@ export type Template = {
46
46
  * Rebuild {@link content} in the inserting editor's language — the seeds a
47
47
  * template writes into the document (a component's name, a lane's title) go
48
48
  * through the translation seam at placement, like a creation action's
49
- * (ADR 0016). Called once per insertion; without it `content` is inserted
49
+ * (ADR 0023). Called once per insertion; without it `content` is inserted
50
50
  * as is.
51
51
  *
52
52
  * With no `TranslationProvider` registered it must return exactly
@@ -1,4 +1,16 @@
1
- import { InteractivityExtension } from '../std/gfx/index.js';
1
+ import { type GfxController, InteractivityExtension } from '../std/gfx/index.js';
2
+ /**
3
+ * Whether a double click at this model point lands on nothing at all.
4
+ *
5
+ * Two layers have to agree, because they answer different questions: the model
6
+ * hit test (`getElementByPoint`) answers "may I be selected here?", the view
7
+ * router answers "is this point mine?". Since framework backgrounds became
8
+ * border-only for picking (#194), their axis labels are a place where the two
9
+ * disagree — the model calls the label empty canvas while the view is opening
10
+ * its rename editor there, and dropping a text block on top blurs that editor
11
+ * shut before the user can type.
12
+ */
13
+ export declare function isEmptyCanvasAt(gfx: GfxController, x: number, y: number): boolean;
2
14
  export declare class DblClickAddEdgelessText extends InteractivityExtension {
3
15
  static key: string;
4
16
  mounted(): void;
@@ -1,7 +1,23 @@
1
1
  import { FeatureFlagService, TelemetryProvider, } from '../affine-shared/services/index.js';
2
- import { InteractivityExtension, } from '../std/gfx/index.js';
2
+ import { InteractivityExtension, InteractivityIdentifier, } from '../std/gfx/index.js';
3
3
  import { insertEdgelessTextCommand } from './commands/index.js';
4
4
  import { addText } from './edgeless-text-editor.js';
5
+ /**
6
+ * Whether a double click at this model point lands on nothing at all.
7
+ *
8
+ * Two layers have to agree, because they answer different questions: the model
9
+ * hit test (`getElementByPoint`) answers "may I be selected here?", the view
10
+ * router answers "is this point mine?". Since framework backgrounds became
11
+ * border-only for picking (#194), their axis labels are a place where the two
12
+ * disagree — the model calls the label empty canvas while the view is opening
13
+ * its rename editor there, and dropping a text block on top blurs that editor
14
+ * shut before the user can type.
15
+ */
16
+ export function isEmptyCanvasAt(gfx, x, y) {
17
+ if (gfx.getElementByPoint(x, y))
18
+ return false;
19
+ return !gfx.std.getOptional(InteractivityIdentifier)?.hasViewAt(x, y);
20
+ }
5
21
  export class DblClickAddEdgelessText extends InteractivityExtension {
6
22
  static { this.key = 'dbl-click-add-edgeless-text'; }
7
23
  mounted() {
@@ -10,12 +26,11 @@ export class DblClickAddEdgelessText extends InteractivityExtension {
10
26
  const textFlag = this.std.store
11
27
  .get(FeatureFlagService)
12
28
  .getFlag('enable_edgeless_text');
13
- const picked = this.gfx.getElementByPoint(...this.gfx.viewport.toModelCoord(e.x, e.y));
14
- if (picked) {
29
+ const [x, y] = this.gfx.viewport.toModelCoord(e.x, e.y);
30
+ if (!isEmptyCanvasAt(this.gfx, x, y)) {
15
31
  return;
16
32
  }
17
33
  if (textFlag) {
18
- const [x, y] = this.gfx.viewport.toModelCoord(e.x, e.y);
19
34
  this.std.command.exec(insertEdgelessTextCommand, { x, y });
20
35
  }
21
36
  else {
@@ -9,6 +9,46 @@ export declare function mountTextElementEditor(textElement: TextElementModel, ed
9
9
  * Canvas Text has been deprecated
10
10
  */
11
11
  export declare function addText(edgeless: BlockComponent, event: PointerEventState): void;
12
+ /**
13
+ * What the editor does with a canvas text the author committed EMPTY: delete it,
14
+ * or leave it standing.
15
+ *
16
+ * ## Why anything survives being emptied
17
+ *
18
+ * A free canvas text emptied of its words IS nothing, and deleting it is what
19
+ * keeps an invisible, selectable box off the board. That was the only rule until
20
+ * the PO's recette of 14/09/2026 found what it costs a COMPARTMENT: emptying a
21
+ * classifier's title deleted the `uml:name` tier out of its group, and the next
22
+ * double-click on the body fell through to the SHAPE's own inner text
23
+ * (`UmlNodeView`), which R16 keeps empty and no framework renderer paints —
24
+ * "je n'arrive pas à entrer dans l'édition de texte".
25
+ *
26
+ * ## …and why a `role` alone is not the test
27
+ *
28
+ * A role says the element means something to a framework. It does NOT say the
29
+ * element is a tier of a composite: a Wardley `wardley:label` and a BPMN name
30
+ * are roled texts that float BESIDE their artefact, sized to their own words,
31
+ * and one emptied to nothing leaves exactly the invisible box the deletion rule
32
+ * exists to remove — with no placeholder drawn over it and no layout to put it
33
+ * back.
34
+ *
35
+ * A compartment tier is the one that has both halves: a `role`, and
36
+ * `hasMaxWidth` — a FIXED width, given at creation by every framework that lays
37
+ * tiers out (`uml/presets.ts`, `c4/actions.ts`), because a tier's width is its
38
+ * compartment's and not its content's. That fixed width is also, and not by
39
+ * coincidence, what leaves a full-width hit box for the next double-click to
40
+ * land on when the words are gone.
41
+ *
42
+ * Pure and total, so it can be asked without an editor, an element model or a
43
+ * document.
44
+ */
45
+ export declare function emptiedTextIsDeleted(element: {
46
+ text: {
47
+ length: number;
48
+ };
49
+ role?: string;
50
+ hasMaxWidth?: boolean;
51
+ }): boolean;
12
52
  declare const EdgelessTextEditor_base: typeof ShadowlessElement & import("../global/utils/types.js").Constructor<import("../global/lit/with-disposable.js").DisposableClass>;
13
53
  export declare class EdgelessTextEditor extends EdgelessTextEditor_base {
14
54
  get crud(): import("../affine-block-surface/index.js").EdgelessCRUDExtension;
@@ -20,6 +60,7 @@ export declare class EdgelessTextEditor extends EdgelessTextEditor_base {
20
60
  static styles: import("lit").CSSResult;
21
61
  private _isComposition;
22
62
  private _keeping;
63
+ private _removing;
23
64
  private readonly _updateRect;
24
65
  get inlineEditor(): import("../affine-shared/types/index.js").AffineInlineEditor | null;
25
66
  get inlineEditorContainer(): import("../std/inline/inline-editor.js").InlineRootElement<import("../affine-shared/types/index.js").AffineTextAttributes> | null | undefined;
@@ -97,6 +97,44 @@ export function addText(edgeless, event) {
97
97
  }
98
98
  }
99
99
  }
100
+ /**
101
+ * What the editor does with a canvas text the author committed EMPTY: delete it,
102
+ * or leave it standing.
103
+ *
104
+ * ## Why anything survives being emptied
105
+ *
106
+ * A free canvas text emptied of its words IS nothing, and deleting it is what
107
+ * keeps an invisible, selectable box off the board. That was the only rule until
108
+ * the PO's recette of 14/09/2026 found what it costs a COMPARTMENT: emptying a
109
+ * classifier's title deleted the `uml:name` tier out of its group, and the next
110
+ * double-click on the body fell through to the SHAPE's own inner text
111
+ * (`UmlNodeView`), which R16 keeps empty and no framework renderer paints —
112
+ * "je n'arrive pas à entrer dans l'édition de texte".
113
+ *
114
+ * ## …and why a `role` alone is not the test
115
+ *
116
+ * A role says the element means something to a framework. It does NOT say the
117
+ * element is a tier of a composite: a Wardley `wardley:label` and a BPMN name
118
+ * are roled texts that float BESIDE their artefact, sized to their own words,
119
+ * and one emptied to nothing leaves exactly the invisible box the deletion rule
120
+ * exists to remove — with no placeholder drawn over it and no layout to put it
121
+ * back.
122
+ *
123
+ * A compartment tier is the one that has both halves: a `role`, and
124
+ * `hasMaxWidth` — a FIXED width, given at creation by every framework that lays
125
+ * tiers out (`uml/presets.ts`, `c4/actions.ts`), because a tier's width is its
126
+ * compartment's and not its content's. That fixed width is also, and not by
127
+ * coincidence, what leaves a full-width hit box for the next double-click to
128
+ * land on when the words are gone.
129
+ *
130
+ * Pure and total, so it can be asked without an editor, an element model or a
131
+ * document.
132
+ */
133
+ export function emptiedTextIsDeleted(element) {
134
+ if (element.text.length !== 0)
135
+ return false;
136
+ return !(element.role !== undefined && element.hasMaxWidth === true);
137
+ }
100
138
  let EdgelessTextEditor = (() => {
101
139
  let _classSuper = WithDisposable(ShadowlessElement);
102
140
  let _std_decorators;
@@ -203,7 +241,12 @@ let EdgelessTextEditor = (() => {
203
241
  this.disposables.add(dispatcher.add('doubleClick', () => true));
204
242
  this.disposables.add(() => {
205
243
  element.display = true;
206
- if (element.text.length === 0) {
244
+ // An emptied COMPARTMENT TIER stays, at its compartment's box,
245
+ // showing the placeholder its framework draws and answering the next
246
+ // double-click; anything else emptied goes. The whole rule, and why it
247
+ // is those two properties and not one, is on
248
+ // {@link emptiedTextIsDeleted}.
249
+ if (emptiedTextIsDeleted(element)) {
207
250
  this.crud.deleteElements([element]);
208
251
  }
209
252
  this.gfx.selection.set({
@@ -213,7 +256,18 @@ let EdgelessTextEditor = (() => {
213
256
  });
214
257
  if (!this.inlineEditorContainer)
215
258
  return;
216
- this.disposables.addFromEvent(this.inlineEditorContainer, 'blur', () => !this._keeping && this.remove());
259
+ this.disposables.addFromEvent(this.inlineEditorContainer, 'blur', () => {
260
+ // Re-entrant, and the connector label editor already says why:
261
+ // Chrome fires the focused child's blur SYNCHRONOUSLY inside
262
+ // `remove()`, before the node is detached, and the commit in
263
+ // `disconnectedCallback` moves the focus again. Without the flag the
264
+ // handler removes a node whose removal is in progress — a
265
+ // `NotFoundError` out of a listener nobody is awaiting.
266
+ if (this._keeping || this._removing)
267
+ return;
268
+ this._removing = true;
269
+ this.remove();
270
+ });
217
271
  this.disposables.addFromEvent(this.inlineEditorContainer, 'compositionstart', () => {
218
272
  this._isComposition = true;
219
273
  this.requestUpdate();
@@ -353,6 +407,7 @@ let EdgelessTextEditor = (() => {
353
407
  super(...arguments);
354
408
  this._isComposition = false;
355
409
  this._keeping = false;
410
+ this._removing = false;
356
411
  this._updateRect = () => {
357
412
  const element = this.element;
358
413
  if (!element || !this.inlineEditorContainer)
@@ -1,6 +1,12 @@
1
1
  import { type SurfaceTextModelMap, type TextStyleProps } from '../../affine-model/index.js';
2
2
  import { type ToolbarContext } from '../../affine-shared/services/index.js';
3
- export declare function createTextActions<K extends abstract new (...args: any) => any, T extends keyof SurfaceTextModelMap>(klass: K, type: T, update?: (ctx: ToolbarContext, model: InstanceType<K>, props: Partial<TextStyleProps>) => void, mapInto?: (model: InstanceType<K>) => TextStyleProps, stash?: <P extends keyof TextStyleProps>(model: InstanceType<K>, type: 'stash' | 'pop', field: P) => void): [{
3
+ /**
4
+ * What the dropdowns read off a selected model. `fontSize` is optional because
5
+ * `affine:edgeless-text` has no such prop — it scales instead, which is why the
6
+ * `d.font-size` action skips that type.
7
+ */
8
+ type ReadableTextStyleProps = Omit<TextStyleProps, 'fontSize'> & Partial<Pick<TextStyleProps, 'fontSize'>>;
9
+ export declare function createTextActions<K extends abstract new (...args: any) => any, T extends keyof SurfaceTextModelMap>(klass: K, type: T, update?: (ctx: ToolbarContext, model: InstanceType<K>, props: Partial<TextStyleProps>) => void, mapInto?: (model: InstanceType<K>) => ReadableTextStyleProps, stash?: <P extends keyof TextStyleProps>(model: InstanceType<K>, type: 'stash' | 'pop', field: P) => void): [{
4
10
  readonly id: "a.font";
5
11
  readonly content: (ctx: ToolbarContext) => import("lit-html").TemplateResult<1> | null;
6
12
  }, {
@@ -17,3 +23,4 @@ export declare function createTextActions<K extends abstract new (...args: any)
17
23
  readonly id: "e.alignment";
18
24
  readonly content: (ctx: ToolbarContext) => import("lit-html").TemplateResult<1> | null;
19
25
  }];
26
+ export {};
@@ -1,5 +1,5 @@
1
1
  import { EdgelessCRUDIdentifier, TextUtils } from '../../affine-block-surface/index.js';
2
- import { packColor, } from '../../affine-components/color-picker/index.js';
2
+ import { frameworkPaletteGroups, packColor, } from '../../affine-components/color-picker/index.js';
3
3
  import { EditorChevronDown } from '../../affine-components/toolbar/index.js';
4
4
  import { DefaultTheme, FontFamily, FontStyle, FontWeight, resolveColor, TextAlign, } from '../../affine-model/index.js';
5
5
  import { translateKey, } from '../../affine-shared/services/index.js';
@@ -10,7 +10,7 @@ import { signal } from '@preact/signals-core';
10
10
  import { html } from 'lit';
11
11
  import { styleMap } from 'lit/directives/style-map.js';
12
12
  import { isFontStyleSupported, isFontWeightSupported, } from '../element-renderer/utils.js';
13
- import { TEXT_ALIGN_CENTER, TEXT_ALIGN_LEFT, TEXT_ALIGN_RIGHT, TEXT_TOOLBAR_ALIGNMENT, TEXT_TOOLBAR_FONT, TEXT_TOOLBAR_FONT_STYLE, TEXT_TOOLBAR_FONT_STYLE_ITALIC, TEXT_TOOLBAR_FONT_WEIGHT_LIGHT, TEXT_TOOLBAR_FONT_WEIGHT_REGULAR, TEXT_TOOLBAR_FONT_WEIGHT_SEMIBOLD, TEXT_TOOLBAR_FONT_SIZE, TEXT_TOOLBAR_TEXT_COLOR, } from '../translations.js';
13
+ import { TEXT_ALIGN_CENTER, TEXT_ALIGN_LEFT, TEXT_ALIGN_RIGHT, TEXT_TOOLBAR_ALIGNMENT, TEXT_TOOLBAR_FONT, TEXT_TOOLBAR_FONT_STYLE, TEXT_TOOLBAR_FONT_STYLE_ITALIC, TEXT_TOOLBAR_FONT_WEIGHT_BOLD, TEXT_TOOLBAR_FONT_WEIGHT_LIGHT, TEXT_TOOLBAR_FONT_WEIGHT_REGULAR, TEXT_TOOLBAR_FONT_WEIGHT_SEMIBOLD, TEXT_TOOLBAR_FONT_SIZE, TEXT_TOOLBAR_TEXT_COLOR, } from '../translations.js';
14
14
  const FONT_WEIGHT_LIST = [
15
15
  {
16
16
  key: 'Light',
@@ -27,6 +27,11 @@ const FONT_WEIGHT_LIST = [
27
27
  keyWording: TEXT_TOOLBAR_FONT_WEIGHT_SEMIBOLD,
28
28
  value: FontWeight.SemiBold,
29
29
  },
30
+ {
31
+ key: 'Bold',
32
+ keyWording: TEXT_TOOLBAR_FONT_WEIGHT_BOLD,
33
+ value: FontWeight.Bold,
34
+ },
30
35
  ];
31
36
  const FONT_STYLE_LIST = [
32
37
  {
@@ -167,6 +172,9 @@ export function createTextActions(klass, type, update = (ctx, model, props) => c
167
172
  break;
168
173
  }
169
174
  };
175
+ // A label on a framework board opens on that framework's hues; the
176
+ // text palette of the editor stays page one (`docs/adr/0027`).
177
+ const carousel = frameworkPaletteGroups(ctx.std, models, palettes);
170
178
  return html `
171
179
  <edgeless-color-picker-button
172
180
  class="text-color"
@@ -179,6 +187,8 @@ export function createTextActions(klass, type, update = (ctx, model, props) => c
179
187
  .hollowCircle=${true}
180
188
  .originalColor=${originalColor}
181
189
  .palettes=${palettes}
190
+ .paletteGroups=${carousel.groups}
191
+ .activeGroupKey=${carousel.activeKey}
182
192
  .enableCustomColor=${enableCustomColor}
183
193
  >
184
194
  </edgeless-color-picker-button>
@@ -11,6 +11,7 @@ export declare const TEXT_TOOLBAR_FONT_SIZE: ChromeWording;
11
11
  export declare const TEXT_TOOLBAR_FONT_WEIGHT_LIGHT: ChromeWording;
12
12
  export declare const TEXT_TOOLBAR_FONT_WEIGHT_REGULAR: ChromeWording;
13
13
  export declare const TEXT_TOOLBAR_FONT_WEIGHT_SEMIBOLD: ChromeWording;
14
+ export declare const TEXT_TOOLBAR_FONT_WEIGHT_BOLD: ChromeWording;
14
15
  export declare const TEXT_TOOLBAR_FONT_STYLE_ITALIC: ChromeWording;
15
16
  export declare const TEXT_TOOLBAR_FONT: ChromeWording;
16
17
  export declare const TEXT_TOOLBAR_TEXT_COLOR: ChromeWording;
@@ -1,4 +1,4 @@
1
- import { FONT_SIZE_LABEL, FONT_STYLE_ITALIC, FONT_WEIGHT_LIGHT, FONT_WEIGHT_REGULAR, FONT_WEIGHT_SEMIBOLD, } from '../affine-shared/services/index.js';
1
+ import { FONT_SIZE_LABEL, FONT_STYLE_ITALIC, FONT_WEIGHT_BOLD, FONT_WEIGHT_LIGHT, FONT_WEIGHT_REGULAR, FONT_WEIGHT_SEMIBOLD, } from '../affine-shared/services/index.js';
2
2
  /**
3
3
  * The shared text toolbar's own wordings (`createTextActions`, rendered by
4
4
  * every framework that draws real text — shape, mindmap, connector,
@@ -11,6 +11,7 @@ export const TEXT_TOOLBAR_FONT_SIZE = FONT_SIZE_LABEL;
11
11
  export const TEXT_TOOLBAR_FONT_WEIGHT_LIGHT = FONT_WEIGHT_LIGHT;
12
12
  export const TEXT_TOOLBAR_FONT_WEIGHT_REGULAR = FONT_WEIGHT_REGULAR;
13
13
  export const TEXT_TOOLBAR_FONT_WEIGHT_SEMIBOLD = FONT_WEIGHT_SEMIBOLD;
14
+ export const TEXT_TOOLBAR_FONT_WEIGHT_BOLD = FONT_WEIGHT_BOLD;
14
15
  export const TEXT_TOOLBAR_FONT_STYLE_ITALIC = FONT_STYLE_ITALIC;
15
16
  export const TEXT_TOOLBAR_FONT = [
16
17
  'com.labre.text-toolbar.font',
@@ -195,14 +195,18 @@ export const CodeExtension = InlineMarkdownExtension({
195
195
  });
196
196
  // typographic replacement: word -- + space => word — + space
197
197
  // not convert: --- + space (divider shortcut), --flag + space, inside inline code
198
+ // an odd number of backticks before the dashes means a code span is still open:
199
+ // the closing backtick has not run yet, so the dashes are code in the making
198
200
  export const EmDashExtension = InlineMarkdownExtension({
199
201
  name: 'em-dash',
200
202
  pattern: /(?:^|[^-])--\s$/,
201
- action: ({ inlineEditor, inlineRange, undoManager }) => {
203
+ action: ({ inlineEditor, inlineRange, prefixText, undoManager }) => {
202
204
  const dashes = { index: inlineRange.index - 3, length: 2 };
203
205
  const format = inlineEditor.getFormat(dashes);
204
206
  if (format.code)
205
207
  return;
208
+ if ((prefixText.match(/`/g) ?? []).length % 2 === 1)
209
+ return;
206
210
  undoManager.stopCapturing();
207
211
  inlineEditor.insertText(dashes, '—', format);
208
212
  inlineEditor.setInlineRange({