@formicoidea/labre-core 0.43.1 → 0.45.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 (263) hide show
  1. package/dist/_pkgs/affine-block-attachment/utils.js +4 -0
  2. package/dist/_pkgs/affine-block-bookmark/configs/toolbar.js +17 -4
  3. package/dist/_pkgs/affine-block-callout/commands/turn-into-callout.d.ts +29 -0
  4. package/dist/_pkgs/affine-block-callout/commands/turn-into-callout.js +81 -0
  5. package/dist/_pkgs/affine-block-callout/configs/slash-menu.js +6 -4
  6. package/dist/_pkgs/affine-block-callout/configs/turn-into.d.ts +8 -0
  7. package/dist/_pkgs/affine-block-callout/configs/turn-into.js +19 -0
  8. package/dist/_pkgs/affine-block-callout/translations.d.ts +4 -2
  9. package/dist/_pkgs/affine-block-callout/translations.js +4 -2
  10. package/dist/_pkgs/affine-block-callout/view.js +3 -0
  11. package/dist/_pkgs/affine-block-code/code-block-service.d.ts +13 -0
  12. package/dist/_pkgs/affine-block-code/code-block-service.js +26 -0
  13. package/dist/_pkgs/affine-block-code/code-block.d.ts +6 -0
  14. package/dist/_pkgs/affine-block-code/code-block.js +11 -2
  15. package/dist/_pkgs/affine-block-code/code-toolbar/components/lang-button.js +31 -8
  16. package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/config.d.ts +11 -0
  17. package/dist/_pkgs/affine-block-edgeless-text/svg-painter.d.ts +20 -0
  18. package/dist/_pkgs/affine-block-edgeless-text/svg-painter.js +76 -0
  19. package/dist/_pkgs/affine-block-edgeless-text/view.js +2 -0
  20. package/dist/_pkgs/affine-block-embed/configs/toolbar.js +11 -2
  21. package/dist/_pkgs/affine-block-embed/embed-iframe-block/configs/toolbar.js +11 -2
  22. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/embed-edgeless-linked-doc-block.js +3 -1
  23. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/configs/toolbar.js +7 -2
  24. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/embed-edgeless-synced-doc-block.js +3 -1
  25. package/dist/_pkgs/affine-block-frame/frame-manager.d.ts +5 -0
  26. package/dist/_pkgs/affine-block-frame/frame-manager.js +48 -17
  27. package/dist/_pkgs/affine-block-frame/frame-tool.js +3 -1
  28. package/dist/_pkgs/affine-block-image/utils.js +4 -1
  29. package/dist/_pkgs/affine-block-latex/adapters/markdown/preprocessor.d.ts +8 -0
  30. package/dist/_pkgs/affine-block-latex/adapters/markdown/preprocessor.js +9 -5
  31. package/dist/_pkgs/affine-block-note/translations.d.ts +0 -1
  32. package/dist/_pkgs/affine-block-note/translations.js +0 -5
  33. package/dist/_pkgs/affine-block-root/configs/toolbar.js +17 -1
  34. package/dist/_pkgs/affine-block-root/edgeless/clipboard/clipboard.js +2 -1
  35. package/dist/_pkgs/affine-block-root/edgeless/clipboard/command.js +161 -83
  36. package/dist/_pkgs/affine-block-root/edgeless/clipboard/paste-order.d.ts +21 -0
  37. package/dist/_pkgs/affine-block-root/edgeless/clipboard/paste-order.js +85 -0
  38. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.d.ts +6 -0
  39. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.js +18 -1
  40. package/dist/_pkgs/affine-block-root/edgeless/utils/clone-utils.d.ts +9 -0
  41. package/dist/_pkgs/affine-block-root/edgeless/utils/clone-utils.js +28 -0
  42. package/dist/_pkgs/affine-block-root/keyboard/commands.js +9 -6
  43. package/dist/_pkgs/affine-block-root/preview/edgeless-root-preview-block.js +15 -2
  44. package/dist/_pkgs/affine-block-surface/adapters/markdown/element-adapter/type.d.ts +1 -1
  45. package/dist/_pkgs/affine-block-surface/element-model/index.d.ts +1 -1
  46. package/dist/_pkgs/affine-block-surface/element-model/index.js +1 -1
  47. package/dist/_pkgs/affine-block-surface/extensions/audit.js +13 -61
  48. package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/commands.d.ts +2 -0
  49. package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/commands.js +71 -0
  50. package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/index.d.ts +1 -0
  51. package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/index.js +1 -0
  52. package/dist/_pkgs/affine-block-surface/extensions/clipboard-config.js +4 -0
  53. package/dist/_pkgs/affine-block-surface/extensions/crud-extension.js +4 -0
  54. package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.d.ts +12 -0
  55. package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +27 -7
  56. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.d.ts +2 -1
  57. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.js +22 -3
  58. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.d.ts +6 -3
  59. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.js +4 -2
  60. package/dist/_pkgs/affine-block-surface/extensions/export-svg/parts.d.ts +63 -0
  61. package/dist/_pkgs/affine-block-surface/extensions/export-svg/parts.js +67 -0
  62. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.d.ts +62 -5
  63. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +98 -18
  64. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.d.ts +14 -0
  65. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.js +82 -1
  66. package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.d.ts +2 -2
  67. package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.js +112 -10
  68. package/dist/_pkgs/affine-block-surface/extensions/export-svg/translations.d.ts +13 -0
  69. package/dist/_pkgs/affine-block-surface/extensions/export-svg/translations.js +33 -0
  70. package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +3 -0
  71. package/dist/_pkgs/affine-block-surface/extensions/index.js +3 -0
  72. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.d.ts +13 -6
  73. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.js +26 -10
  74. package/dist/_pkgs/affine-block-surface/extensions/reading.d.ts +82 -6
  75. package/dist/_pkgs/affine-block-surface/extensions/reading.js +99 -21
  76. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.d.ts +80 -0
  77. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.js +248 -0
  78. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.d.ts +82 -0
  79. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.js +342 -0
  80. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/index.d.ts +3 -0
  81. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/index.js +3 -0
  82. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/tree.d.ts +137 -0
  83. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/tree.js +323 -0
  84. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.d.ts +112 -4
  85. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.js +86 -15
  86. package/dist/_pkgs/affine-block-surface/extensions/user-layers/actions.d.ts +76 -0
  87. package/dist/_pkgs/affine-block-surface/extensions/user-layers/actions.js +299 -0
  88. package/dist/_pkgs/affine-block-surface/extensions/user-layers/active-layer.d.ts +20 -0
  89. package/dist/_pkgs/affine-block-surface/extensions/user-layers/active-layer.js +34 -0
  90. package/dist/_pkgs/affine-block-surface/extensions/user-layers/commands.d.ts +67 -0
  91. package/dist/_pkgs/affine-block-surface/extensions/user-layers/commands.js +172 -0
  92. package/dist/_pkgs/affine-block-surface/extensions/user-layers/creation.d.ts +40 -0
  93. package/dist/_pkgs/affine-block-surface/extensions/user-layers/creation.js +69 -0
  94. package/dist/_pkgs/affine-block-surface/extensions/user-layers/index.d.ts +5 -0
  95. package/dist/_pkgs/affine-block-surface/extensions/user-layers/index.js +5 -0
  96. package/dist/_pkgs/affine-block-surface/extensions/user-layers/translations.d.ts +10 -0
  97. package/dist/_pkgs/affine-block-surface/extensions/user-layers/translations.js +14 -0
  98. package/dist/_pkgs/affine-block-surface/framework-background/facts.d.ts +55 -2
  99. package/dist/_pkgs/affine-block-surface/framework-background/facts.js +63 -1
  100. package/dist/_pkgs/affine-block-surface/framework-background/stacking.d.ts +16 -8
  101. package/dist/_pkgs/affine-block-surface/framework-background/stacking.js +26 -14
  102. package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.js +17 -3
  103. package/dist/_pkgs/affine-block-surface/renderer/dom-renderer.d.ts +3 -1
  104. package/dist/_pkgs/affine-block-surface/renderer/dom-renderer.js +22 -2
  105. package/dist/_pkgs/affine-block-surface/renderer/paint-predicate.d.ts +30 -0
  106. package/dist/_pkgs/affine-block-surface/renderer/paint-predicate.js +29 -0
  107. package/dist/_pkgs/affine-block-surface/surface-block.js +6 -0
  108. package/dist/_pkgs/affine-block-surface/surface-model.js +5 -0
  109. package/dist/_pkgs/affine-block-surface/surface-transformer.js +5 -0
  110. package/dist/_pkgs/affine-block-surface/tool/default-tool.js +28 -5
  111. package/dist/_pkgs/affine-block-surface/view.js +23 -1
  112. package/dist/_pkgs/affine-block-surface-ref/surface-ref-block.js +12 -2
  113. package/dist/_pkgs/affine-components/context-menu/button.js +14 -0
  114. package/dist/_pkgs/affine-components/filterable-list/index.js +30 -9
  115. package/dist/_pkgs/affine-components/icons/index.d.ts +0 -1
  116. package/dist/_pkgs/affine-components/icons/index.js +0 -1
  117. package/dist/_pkgs/affine-components/icons/text.d.ts +1 -0
  118. package/dist/_pkgs/affine-components/icons/text.js +11 -0
  119. package/dist/_pkgs/affine-fragment-adapter-panel/adapter-panel.d.ts +2 -2
  120. package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.js +2 -2
  121. package/dist/_pkgs/affine-fragment-frame-panel/header/frame-panel-header.d.ts +1 -1
  122. package/dist/_pkgs/affine-fragment-frame-panel/header/frame-panel-header.js +8 -27
  123. package/dist/_pkgs/affine-fragment-frame-panel/index.d.ts +1 -0
  124. package/dist/_pkgs/affine-fragment-frame-panel/index.js +1 -0
  125. package/dist/_pkgs/affine-gfx-connector/element-renderer/connector-dom/index.js +3 -1
  126. package/dist/_pkgs/affine-gfx-connector/element-renderer/index.js +21 -4
  127. package/dist/_pkgs/affine-gfx-connector/text/edgeless-connector-label-editor.js +3 -2
  128. package/dist/_pkgs/affine-gfx-connector/toolbar/config.js +1 -1
  129. package/dist/_pkgs/affine-gfx-group/command/group-api.js +52 -1
  130. package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/index.js +21 -3
  131. package/dist/_pkgs/affine-gfx-shape/text/edgeless-shape-text-editor.js +2 -0
  132. package/dist/_pkgs/affine-gfx-shape/toolbar/config.js +1 -1
  133. package/dist/_pkgs/affine-gfx-template/services/template-middlewares.d.ts +9 -0
  134. package/dist/_pkgs/affine-gfx-template/services/template-middlewares.js +23 -1
  135. package/dist/_pkgs/affine-gfx-template/services/template.js +2 -1
  136. package/dist/_pkgs/affine-gfx-text/edgeless-text-editor.js +2 -1
  137. package/dist/_pkgs/affine-gfx-text/element-renderer/index.js +20 -3
  138. package/dist/_pkgs/affine-gfx-text/element-renderer/utils.d.ts +67 -1
  139. package/dist/_pkgs/affine-gfx-text/element-renderer/utils.js +101 -0
  140. package/dist/_pkgs/affine-gfx-text/toolbar/actions.d.ts +11 -0
  141. package/dist/_pkgs/affine-gfx-text/toolbar/actions.js +53 -2
  142. package/dist/_pkgs/affine-gfx-text/toolbar/config.d.ts +11 -0
  143. package/dist/_pkgs/affine-gfx-text/toolbar/config.js +1 -1
  144. package/dist/_pkgs/affine-inline-preset/adapters/html/html-inline.d.ts +3 -0
  145. package/dist/_pkgs/affine-inline-preset/adapters/html/html-inline.js +31 -0
  146. package/dist/_pkgs/affine-inline-preset/adapters/html/inline-delta.d.ts +4 -0
  147. package/dist/_pkgs/affine-inline-preset/adapters/html/inline-delta.js +14 -0
  148. package/dist/_pkgs/affine-inline-preset/command/config.js +21 -3
  149. package/dist/_pkgs/affine-inline-preset/command/index.d.ts +1 -1
  150. package/dist/_pkgs/affine-inline-preset/command/index.js +1 -1
  151. package/dist/_pkgs/affine-inline-preset/command/text-style.d.ts +2 -1
  152. package/dist/_pkgs/affine-inline-preset/command/text-style.js +1 -0
  153. package/dist/_pkgs/affine-inline-preset/default-inline-manager.js +2 -1
  154. package/dist/_pkgs/affine-inline-preset/inline-spec.d.ts +4 -0
  155. package/dist/_pkgs/affine-inline-preset/inline-spec.js +14 -0
  156. package/dist/_pkgs/affine-inline-preset/translations.d.ts +2 -2
  157. package/dist/_pkgs/affine-inline-preset/translations.js +2 -2
  158. package/dist/_pkgs/affine-model/blocks/attachment/attachment-model.js +2 -0
  159. package/dist/_pkgs/affine-model/blocks/bookmark/bookmark-model.js +2 -0
  160. package/dist/_pkgs/affine-model/blocks/edgeless-text/edgeless-text-model.d.ts +1 -1
  161. package/dist/_pkgs/affine-model/blocks/edgeless-text/edgeless-text-model.js +2 -0
  162. package/dist/_pkgs/affine-model/blocks/embed/iframe/iframe-model.js +2 -0
  163. package/dist/_pkgs/affine-model/blocks/frame/frame-model.js +2 -0
  164. package/dist/_pkgs/affine-model/blocks/image/image-model.js +2 -0
  165. package/dist/_pkgs/affine-model/blocks/latex/latex-model.js +2 -0
  166. package/dist/_pkgs/affine-model/blocks/note/note-model.js +2 -0
  167. package/dist/_pkgs/affine-model/consts/text.d.ts +26 -0
  168. package/dist/_pkgs/affine-model/consts/text.js +25 -0
  169. package/dist/_pkgs/affine-model/elements/shape/shape.d.ts +6 -1
  170. package/dist/_pkgs/affine-model/elements/shape/shape.js +14 -1
  171. package/dist/_pkgs/affine-model/elements/text/text.d.ts +6 -1
  172. package/dist/_pkgs/affine-model/elements/text/text.js +13 -1
  173. package/dist/_pkgs/affine-model/utils/helper.js +2 -0
  174. package/dist/_pkgs/affine-rich-text/conversion.d.ts +25 -0
  175. package/dist/_pkgs/affine-rich-text/conversion.js +9 -0
  176. package/dist/_pkgs/affine-rich-text/index.d.ts +1 -1
  177. package/dist/_pkgs/affine-rich-text/index.js +1 -1
  178. package/dist/_pkgs/affine-shared/commands/model-crud/replace-selected-text-with-blocks.d.ts +1 -1
  179. package/dist/_pkgs/affine-shared/services/canvas-grid.d.ts +63 -0
  180. package/dist/_pkgs/affine-shared/services/canvas-grid.js +109 -0
  181. package/dist/_pkgs/affine-shared/services/canvas-local-visibility.d.ts +64 -0
  182. package/dist/_pkgs/affine-shared/services/canvas-local-visibility.js +192 -0
  183. package/dist/_pkgs/affine-shared/services/edit-props-store.d.ts +27 -0
  184. package/dist/_pkgs/affine-shared/services/edit-props-store.js +34 -0
  185. package/dist/_pkgs/affine-shared/services/editor-setting-service.d.ts +3 -0
  186. package/dist/_pkgs/affine-shared/services/editor-setting-service.js +7 -0
  187. package/dist/_pkgs/affine-shared/services/feature-flag-service.d.ts +4 -0
  188. package/dist/_pkgs/affine-shared/services/index.d.ts +3 -0
  189. package/dist/_pkgs/affine-shared/services/index.js +3 -0
  190. package/dist/_pkgs/affine-shared/services/selection-pane-service.d.ts +44 -0
  191. package/dist/_pkgs/affine-shared/services/selection-pane-service.js +28 -0
  192. package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +69 -0
  193. package/dist/_pkgs/affine-shared/services/telemetry-service/telemetry-service.d.ts +2 -2
  194. package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +5 -0
  195. package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +9 -0
  196. package/dist/_pkgs/affine-shared/styles/index.d.ts +1 -0
  197. package/dist/_pkgs/affine-shared/styles/index.js +1 -0
  198. package/dist/_pkgs/affine-shared/styles/panel-header.d.ts +31 -0
  199. package/dist/_pkgs/affine-shared/styles/panel-header.js +61 -0
  200. package/dist/_pkgs/affine-shared/styles/text.js +7 -7
  201. package/dist/_pkgs/affine-shared/types/index.d.ts +6 -0
  202. package/dist/_pkgs/affine-shared/utils/canvas-export-colors.d.ts +26 -0
  203. package/dist/_pkgs/affine-shared/utils/canvas-export-colors.js +127 -0
  204. package/dist/_pkgs/affine-shared/utils/file/filesys.d.ts +8 -11
  205. package/dist/_pkgs/affine-shared/utils/file/filesys.js +8 -11
  206. package/dist/_pkgs/affine-shared/utils/index.d.ts +2 -0
  207. package/dist/_pkgs/affine-shared/utils/index.js +2 -0
  208. package/dist/_pkgs/affine-shared/utils/label-mode.d.ts +47 -0
  209. package/dist/_pkgs/affine-shared/utils/label-mode.js +55 -0
  210. package/dist/_pkgs/affine-shared/utils/model/merge-to-code-model.js +7 -1
  211. package/dist/_pkgs/affine-shared/utils/model/transform-model.js +5 -0
  212. package/dist/_pkgs/affine-widget-edgeless-selected-rect/utils.js +10 -3
  213. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.js +25 -49
  214. package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.d.ts +4 -0
  215. package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.js +4 -0
  216. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.d.ts +4 -0
  217. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.js +4 -0
  218. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.d.ts +61 -0
  219. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.js +91 -0
  220. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/labels.d.ts +17 -0
  221. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/labels.js +95 -0
  222. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-default.d.ts +10 -0
  223. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-default.js +31 -0
  224. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-tool.d.ts +26 -0
  225. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-tool.js +82 -0
  226. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.d.ts +170 -0
  227. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.js +1381 -0
  228. package/dist/_pkgs/affine-widget-edgeless-toolbar/translations.d.ts +52 -0
  229. package/dist/_pkgs/affine-widget-edgeless-toolbar/translations.js +161 -1
  230. package/dist/_pkgs/affine-widget-edgeless-toolbar/view.js +10 -0
  231. package/dist/_pkgs/affine-widget-note-slicer/note-slicer.js +7 -3
  232. package/dist/_pkgs/std/gfx/controller.d.ts +13 -0
  233. package/dist/_pkgs/std/gfx/controller.js +22 -2
  234. package/dist/_pkgs/std/gfx/grid.d.ts +31 -2
  235. package/dist/_pkgs/std/gfx/index.d.ts +3 -1
  236. package/dist/_pkgs/std/gfx/index.js +3 -1
  237. package/dist/_pkgs/std/gfx/interactivity/manager.js +7 -0
  238. package/dist/_pkgs/std/gfx/layer.js +73 -5
  239. package/dist/_pkgs/std/gfx/local-visibility.d.ts +88 -0
  240. package/dist/_pkgs/std/gfx/local-visibility.js +217 -0
  241. package/dist/_pkgs/std/gfx/model/gfx-block-model.d.ts +13 -0
  242. package/dist/_pkgs/std/gfx/model/surface/element-model.d.ts +34 -0
  243. package/dist/_pkgs/std/gfx/model/surface/element-model.js +65 -1
  244. package/dist/_pkgs/std/gfx/model/surface/surface-model.d.ts +27 -0
  245. package/dist/_pkgs/std/gfx/model/surface/surface-model.js +43 -0
  246. package/dist/_pkgs/std/gfx/model/surface/user-layers.d.ts +68 -0
  247. package/dist/_pkgs/std/gfx/model/surface/user-layers.js +127 -0
  248. package/dist/_pkgs/std/utils/layer.d.ts +10 -0
  249. package/dist/_pkgs/std/utils/layer.js +64 -13
  250. package/dist/_pkgs/std/view/element/gfx-block-component.js +10 -2
  251. package/dist/commands.js +4 -1
  252. package/dist/translations.js +10 -6
  253. package/package.json +9 -2
  254. package/dist/_pkgs/affine-components/icons/file-icons-rc.d.ts +0 -1
  255. package/dist/_pkgs/affine-components/icons/file-icons-rc.js +0 -130
  256. package/dist/_pkgs/affine-shared/test-utils/affine-template.d.ts +0 -6
  257. package/dist/_pkgs/affine-shared/test-utils/affine-template.js +0 -258
  258. package/dist/_pkgs/affine-shared/test-utils/affine-test-utils.d.ts +0 -8
  259. package/dist/_pkgs/affine-shared/test-utils/affine-test-utils.js +0 -81
  260. package/dist/_pkgs/affine-shared/test-utils/create-test-host.d.ts +0 -23
  261. package/dist/_pkgs/affine-shared/test-utils/create-test-host.js +0 -187
  262. package/dist/_pkgs/affine-shared/test-utils/index.d.ts +0 -3
  263. package/dist/_pkgs/affine-shared/test-utils/index.js +0 -3
@@ -1,3 +1,4 @@
1
+ import { applyCreationLayer } from '../affine-block-surface/index.js';
1
2
  import { toast } from '../affine-components/toast/index.js';
2
3
  import { AttachmentBlockSchema, } from '../affine-model/index.js';
3
4
  import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH, } from '../affine-shared/consts/index.js';
@@ -142,6 +143,9 @@ export async function addAttachments(std, files, point, shouldTransformPoint //
142
143
  const xywh = Bound.fromCenter(center, width, height).serialize();
143
144
  return { flavour, blockProps: { ...props, style, xywh } };
144
145
  });
146
+ // The viewer's active layer, as the CRUD `addBlock` path stamps it
147
+ // (ADR 0031 §6): several blocks at once go straight to `store.addBlocks`.
148
+ blocks.forEach(({ blockProps }) => applyCreationLayer(std, blockProps));
145
149
  const blockIds = std.store.addBlocks(blocks, gfx.surface);
146
150
  gfx.selection.set({
147
151
  elements: blockIds,
@@ -1,5 +1,5 @@
1
1
  import { canEmbedAsEmbedBlock, canEmbedAsIframe, EMBED_IFRAME_DEFAULT_HEIGHT_IN_SURFACE, EMBED_IFRAME_DEFAULT_WIDTH_IN_SURFACE, } from '../../affine-block-embed/index.js';
2
- import { reassociateConnectorsCommand } from '../../affine-block-surface/index.js';
2
+ import { applyCreationLayer, reassociateConnectorsCommand, sourceLayerOf, } from '../../affine-block-surface/index.js';
3
3
  import { toast } from '../../affine-components/toast/index.js';
4
4
  import { BookmarkBlockModel, BookmarkStyles, } from '../../affine-model/index.js';
5
5
  import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH, } from '../../affine-shared/consts/index.js';
@@ -291,6 +291,13 @@ const builtinSurfaceToolbarConfig = {
291
291
  return;
292
292
  const { id: oldId, xywh, parent } = model;
293
293
  const { url, caption, title, description } = model.props;
294
+ // The replacement takes the bookmark's place, layer included
295
+ // (ADR 0031 §6).
296
+ const withLayer = (props) => {
297
+ props.layer = sourceLayerOf(model);
298
+ applyCreationLayer(ctx.std, props);
299
+ return props;
300
+ };
294
301
  let newId;
295
302
  // first try to embed as a custom embed block
296
303
  if (canEmbedAsEmbedBlock(ctx.std, url)) {
@@ -307,14 +314,14 @@ const builtinSurfaceToolbarConfig = {
307
314
  const bound = Bound.deserialize(xywh);
308
315
  bound.w = EMBED_CARD_WIDTH[style];
309
316
  bound.h = EMBED_CARD_HEIGHT[style];
310
- newId = ctx.store.addBlock(flavour, {
317
+ newId = ctx.store.addBlock(flavour, withLayer({
311
318
  url,
312
319
  caption,
313
320
  title,
314
321
  description,
315
322
  style,
316
323
  xywh: bound.serialize(),
317
- }, parent);
324
+ }), parent);
318
325
  }
319
326
  else if (canEmbedAsIframe(ctx.std, url)) {
320
327
  const embedIframeService = ctx.std.get(EmbedIframeService);
@@ -328,7 +335,13 @@ const builtinSurfaceToolbarConfig = {
328
335
  bound.w = widthInSurface ?? EMBED_IFRAME_DEFAULT_WIDTH_IN_SURFACE;
329
336
  bound.h =
330
337
  heightInSurface ?? EMBED_IFRAME_DEFAULT_HEIGHT_IN_SURFACE;
331
- newId = ctx.store.addBlock('affine:embed-iframe', { url, caption, title, description, xywh: bound.serialize() }, parent);
338
+ newId = ctx.store.addBlock('affine:embed-iframe', withLayer({
339
+ url,
340
+ caption,
341
+ title,
342
+ description,
343
+ xywh: bound.serialize(),
344
+ }), parent);
332
345
  }
333
346
  if (!newId)
334
347
  return;
@@ -0,0 +1,29 @@
1
+ import type { Command } from '../../std/index.js';
2
+ import type { BlockModel, Store } from '../../store/index.js';
3
+ /**
4
+ * The selected blocks "Turn into → Callout" would actually wrap.
5
+ *
6
+ * Decided BEFORE anything is written, so that a refusal costs nothing: a
7
+ * block already inside a callout (a callout never nests) or inside an
8
+ * edgeless text (where the slash item is not offered either), a parent that
9
+ * does not accept a callout, or a child the inner paragraph could not adopt —
10
+ * `deleteBlock({ bringChildrenTo })` detaches the source before it validates
11
+ * the children, so a refused child there would orphan the whole block. A
12
+ * selected child of another selected block is dropped too: it moves with its
13
+ * parent.
14
+ */
15
+ export declare function calloutConversionTargets(store: Store, models: BlockModel[]): BlockModel[];
16
+ /**
17
+ * Wraps each selected paragraph, list item or code block in a callout (#418).
18
+ *
19
+ * A callout is a hub with no text of its own, so this cannot be
20
+ * `transformModel`: the callout takes the block's place, a paragraph inside it
21
+ * takes the text, and the block's children move under that paragraph. Every
22
+ * callout is built before any source is removed; if one cannot be, the ones
23
+ * already built are deleted and every source stays as it was.
24
+ */
25
+ export declare const turnIntoCalloutCommand: Command<{
26
+ models: BlockModel[];
27
+ }, {
28
+ updatedBlocks: BlockModel[];
29
+ }>;
@@ -0,0 +1,81 @@
1
+ import { CodeBlockModel, ListBlockModel, ParagraphBlockModel, } from '../../affine-model/index.js';
2
+ import { focusTextModel } from '../../affine-rich-text/index.js';
3
+ import { isInsideBlockByFlavour, matchModels, } from '../../affine-shared/utils/index.js';
4
+ const isAncestor = (store, ancestor, block) => {
5
+ for (let at = store.getParent(block); at; at = store.getParent(at)) {
6
+ if (at === ancestor)
7
+ return true;
8
+ }
9
+ return false;
10
+ };
11
+ /**
12
+ * The selected blocks "Turn into → Callout" would actually wrap.
13
+ *
14
+ * Decided BEFORE anything is written, so that a refusal costs nothing: a
15
+ * block already inside a callout (a callout never nests) or inside an
16
+ * edgeless text (where the slash item is not offered either), a parent that
17
+ * does not accept a callout, or a child the inner paragraph could not adopt —
18
+ * `deleteBlock({ bringChildrenTo })` detaches the source before it validates
19
+ * the children, so a refused child there would orphan the whole block. A
20
+ * selected child of another selected block is dropped too: it moves with its
21
+ * parent.
22
+ */
23
+ export function calloutConversionTargets(store, models) {
24
+ const { schema } = store;
25
+ const convertible = models.filter(model => {
26
+ if (!matchModels(model, [ParagraphBlockModel, ListBlockModel, CodeBlockModel]))
27
+ return false;
28
+ if (isInsideBlockByFlavour(store, model, 'affine:callout'))
29
+ return false;
30
+ if (isInsideBlockByFlavour(store, model, 'affine:edgeless-text'))
31
+ return false;
32
+ const parent = store.getParent(model);
33
+ if (!parent || !schema.isValid('affine:callout', parent.flavour))
34
+ return false;
35
+ return model.children.every(child => schema.isValid(child.flavour, 'affine:paragraph'));
36
+ });
37
+ return convertible.filter(model => !convertible.some(other => isAncestor(store, other, model)));
38
+ }
39
+ /**
40
+ * Wraps each selected paragraph, list item or code block in a callout (#418).
41
+ *
42
+ * A callout is a hub with no text of its own, so this cannot be
43
+ * `transformModel`: the callout takes the block's place, a paragraph inside it
44
+ * takes the text, and the block's children move under that paragraph. Every
45
+ * callout is built before any source is removed; if one cannot be, the ones
46
+ * already built are deleted and every source stays as it was.
47
+ */
48
+ export const turnIntoCalloutCommand = (ctx, next) => {
49
+ const { std, models } = ctx;
50
+ const store = std.store;
51
+ if (store.readonly)
52
+ return;
53
+ const targets = calloutConversionTargets(store, models);
54
+ if (targets.length === 0)
55
+ return;
56
+ store.captureSync();
57
+ const callouts = [];
58
+ const paragraphs = [];
59
+ for (const model of targets) {
60
+ const parent = store.getParent(model);
61
+ const callout = parent
62
+ ? store.getModelById(store.addBlock('affine:callout', {}, parent, parent.children.indexOf(model)))
63
+ : null;
64
+ if (callout)
65
+ callouts.push(callout);
66
+ // `addBlock` returns an id even for a block the store refused, so only
67
+ // `getModelById` proves the block exists.
68
+ const paragraph = callout
69
+ ? store.getModelById(store.addBlock('affine:paragraph', { text: model.text?.clone() }, callout))
70
+ : null;
71
+ if (!paragraph) {
72
+ callouts.forEach(created => store.deleteBlock(created));
73
+ return;
74
+ }
75
+ paragraphs.push(paragraph);
76
+ }
77
+ targets.forEach((model, i) => store.deleteBlock(model, { bringChildrenTo: paragraphs[i] }));
78
+ const first = paragraphs[0];
79
+ focusTextModel(std, first.id, first.text?.length ?? 0);
80
+ return next({ updatedBlocks: paragraphs });
81
+ };
@@ -1,10 +1,13 @@
1
1
  import { focusBlockEnd } from '../../affine-shared/commands/index.js';
2
- import { FeatureFlagService } from '../../affine-shared/services/index.js';
3
2
  import { isInsideBlockByFlavour } from '../../affine-shared/utils/index.js';
4
3
  import {} from '../../affine-widget-slash-menu/index.js';
5
4
  import { FontIcon } from '@blocksuite/icons/lit';
6
5
  import { CALLOUT_SLASH_CAPTION, CALLOUT_SLASH_DESCRIPTION, CALLOUT_SLASH_NAME, } from '../translations.js';
7
6
  import { calloutTooltip } from './tooltips.js';
7
+ // Gated by the `callout` block flag alone: `CalloutViewExtension` registers
8
+ // this config and is itself flag-gated (ADR 0009). The deprecated
9
+ // `enable_callout` feature flag is not read.
10
+ //
8
11
  // No `disableWhen` here on purpose. The widget ORs every config's `disableWhen`
9
12
  // together and then refuses to open at all, so the callout's own guard used to
10
13
  // silence the WHOLE slash menu inside a callout — every block, every framework,
@@ -24,9 +27,8 @@ export const calloutSlashMenuConfig = {
24
27
  },
25
28
  searchAlias: ['callout'],
26
29
  group: '0_Basic@9',
27
- when: ({ std, model }) => {
28
- return (std.get(FeatureFlagService).getFlag('enable_callout') &&
29
- !isInsideBlockByFlavour(model.store, model, 'affine:edgeless-text') &&
30
+ when: ({ model }) => {
31
+ return (!isInsideBlockByFlavour(model.store, model, 'affine:edgeless-text') &&
30
32
  // The schema forbids a callout inside a callout, so offering the item
31
33
  // there would only produce a thrown insertion.
32
34
  !isInsideBlockByFlavour(model.store, model, 'affine:callout'));
@@ -0,0 +1,8 @@
1
+ import type { TextConversionEntry } from '../../affine-rich-text/index.js';
2
+ /**
3
+ * "Callout" in the "Turn into" menu, registered by `CalloutViewExtension` so
4
+ * the `callout` flag removes it with the slash item (ADR 0009). That flag is
5
+ * the only switch: the deprecated `enable_callout` feature flag is not read,
6
+ * so the two entries always appear and disappear together.
7
+ */
8
+ export declare const calloutTurnIntoEntry: TextConversionEntry;
@@ -0,0 +1,19 @@
1
+ import { FontIcon } from '@blocksuite/icons/lit';
2
+ import { calloutConversionTargets, turnIntoCalloutCommand, } from '../commands/turn-into-callout.js';
3
+ import { CALLOUT_TURN_INTO_NAME } from '../translations.js';
4
+ /**
5
+ * "Callout" in the "Turn into" menu, registered by `CalloutViewExtension` so
6
+ * the `callout` flag removes it with the slash item (ADR 0009). That flag is
7
+ * the only switch: the deprecated `enable_callout` feature flag is not read,
8
+ * so the two entries always appear and disappear together.
9
+ */
10
+ export const calloutTurnIntoEntry = {
11
+ flavour: 'affine:callout',
12
+ name: 'Callout',
13
+ nameWording: CALLOUT_TURN_INTO_NAME,
14
+ icon: FontIcon(),
15
+ when: (std, models) => calloutConversionTargets(std.store, models).length > 0,
16
+ run: (std, models) => {
17
+ std.command.exec(turnIntoCalloutCommand, { models });
18
+ },
19
+ };
@@ -7,10 +7,12 @@ export declare const CALLOUT_SLASH_NAME: ChromeWording;
7
7
  export declare const CALLOUT_SLASH_DESCRIPTION: ChromeWording;
8
8
  /** The item's tooltip caption says the exact same word as its name. */
9
9
  export declare const CALLOUT_SLASH_CAPTION: ChromeWording;
10
+ /** "Turn into → Callout" names the block with the slash item's own word. */
11
+ export declare const CALLOUT_TURN_INTO_NAME: ChromeWording;
10
12
  /**
11
13
  * Every wording declared above, in declaration order — walked by
12
14
  * `PACKAGE_WORDINGS` in `packages/affine/all/src/translations.ts`. The
13
- * caption alias is not listed again, same rule other packages' chrome
14
- * aliases already follow.
15
+ * caption and turn-into aliases are not listed again, same rule other
16
+ * packages' chrome aliases already follow.
15
17
  */
16
18
  export declare const CALLOUT_WORDINGS: readonly ChromeWording[];
@@ -12,11 +12,13 @@ export const CALLOUT_SLASH_DESCRIPTION = [
12
12
  ];
13
13
  /** The item's tooltip caption says the exact same word as its name. */
14
14
  export const CALLOUT_SLASH_CAPTION = CALLOUT_SLASH_NAME;
15
+ /** "Turn into → Callout" names the block with the slash item's own word. */
16
+ export const CALLOUT_TURN_INTO_NAME = CALLOUT_SLASH_NAME;
15
17
  /**
16
18
  * Every wording declared above, in declaration order — walked by
17
19
  * `PACKAGE_WORDINGS` in `packages/affine/all/src/translations.ts`. The
18
- * caption alias is not listed again, same rule other packages' chrome
19
- * aliases already follow.
20
+ * caption and turn-into aliases are not listed again, same rule other
21
+ * packages' chrome aliases already follow.
20
22
  */
21
23
  export const CALLOUT_WORDINGS = [
22
24
  CALLOUT_SLASH_NAME,
@@ -1,9 +1,11 @@
1
1
  import { ViewExtensionProvider, } from '../affine-ext-loader/index.js';
2
+ import { TextConversionEntryExtension } from '../affine-rich-text/index.js';
2
3
  import { SlashMenuConfigExtension } from '../affine-widget-slash-menu/index.js';
3
4
  import { BlockViewExtension, FlavourExtension } from '../std/index.js';
4
5
  import { literal } from 'lit/static-html.js';
5
6
  import { CalloutKeymapExtension } from './callout-keymap.js';
6
7
  import { calloutSlashMenuConfig } from './configs/slash-menu.js';
8
+ import { calloutTurnIntoEntry } from './configs/turn-into.js';
7
9
  import { effects } from './effects.js';
8
10
  export class CalloutViewExtension extends ViewExtensionProvider {
9
11
  constructor() {
@@ -21,6 +23,7 @@ export class CalloutViewExtension extends ViewExtensionProvider {
21
23
  BlockViewExtension('affine:callout', literal `affine-callout`),
22
24
  CalloutKeymapExtension,
23
25
  SlashMenuConfigExtension('affine:callout', calloutSlashMenuConfig),
26
+ TextConversionEntryExtension(calloutTurnIntoEntry),
24
27
  ]);
25
28
  }
26
29
  }
@@ -6,8 +6,21 @@ export declare class CodeBlockHighlighter extends LifeCycleWatcher {
6
6
  private _darkThemeKey;
7
7
  private _lightThemeKey;
8
8
  highlighter$: Signal<HighlighterCore | null>;
9
+ /**
10
+ * In-flight grammar loads, one per language. Per instance rather than
11
+ * static: each editor owns its own shiki core, and a grammar loaded into
12
+ * another editor's core is not loaded into this one.
13
+ */
14
+ private readonly _languageLoads;
9
15
  get themeKey(): string | undefined;
10
16
  private readonly _loadTheme;
17
+ /**
18
+ * Loads a grammar into the shiki core, sharing the pending promise between
19
+ * concurrent callers (every code block of that language asks at once on
20
+ * first paint). A settled load leaves the map, so a failed one is retried
21
+ * on the next request.
22
+ */
23
+ loadLanguage(lang: string, input: Parameters<HighlighterCore['loadLanguage']>[0]): Promise<void>;
11
24
  mounted(): void;
12
25
  unmounted(): void;
13
26
  }
@@ -10,6 +10,12 @@ export class CodeBlockHighlighter extends LifeCycleWatcher {
10
10
  constructor() {
11
11
  super(...arguments);
12
12
  this.highlighter$ = signal(null);
13
+ /**
14
+ * In-flight grammar loads, one per language. Per instance rather than
15
+ * static: each editor owns its own shiki core, and a grammar loaded into
16
+ * another editor's core is not loaded into this one.
17
+ */
18
+ this._languageLoads = new Map();
13
19
  this._loadTheme = async (highlighter) => {
14
20
  const config = this.std.getOptional(CodeBlockConfigExtension.identifier);
15
21
  const darkTheme = config?.theme?.dark ?? CODE_BLOCK_DEFAULT_DARK_THEME;
@@ -27,6 +33,26 @@ export class CodeBlockHighlighter extends LifeCycleWatcher {
27
33
  ? this._darkThemeKey
28
34
  : this._lightThemeKey;
29
35
  }
36
+ /**
37
+ * Loads a grammar into the shiki core, sharing the pending promise between
38
+ * concurrent callers (every code block of that language asks at once on
39
+ * first paint). A settled load leaves the map, so a failed one is retried
40
+ * on the next request.
41
+ */
42
+ loadLanguage(lang, input) {
43
+ const pending = this._languageLoads.get(lang);
44
+ if (pending)
45
+ return pending;
46
+ const highlighter = this.highlighter$.peek();
47
+ if (!highlighter) {
48
+ return Promise.reject(new Error('Code block highlighter is not ready'));
49
+ }
50
+ const load = highlighter.loadLanguage(input).finally(() => {
51
+ this._languageLoads.delete(lang);
52
+ });
53
+ this._languageLoads.set(lang, load);
54
+ return load;
55
+ }
30
56
  mounted() {
31
57
  super.mounted();
32
58
  createHighlighterCore({
@@ -32,6 +32,12 @@ export declare class CodeBlockComponent extends CaptionedBlockComponent<CodeBloc
32
32
  */
33
33
  get showLineNumbers(): boolean;
34
34
  get topContenteditableElement(): BlockComponent<import("../store/index.js").BlockModel<object>, import("../std/index.js").BlockService, string> | null;
35
+ /**
36
+ * Bumped on every highlight request: a grammar load that resolves after a
37
+ * newer request (another language, or plain text) must not repaint the
38
+ * block with its stale tokens (#416).
39
+ */
40
+ private _highlightRequestId;
35
41
  private _updateHighlightTokens;
36
42
  /**
37
43
  * Stable signal: true when the global editor setting enables line numbers.
@@ -84,6 +84,12 @@ let CodeBlockComponent = (() => {
84
84
  ? matchedInfo.name
85
85
  : translateKey(this.std, ...CODE_PLAIN_TEXT_LANGUAGE);
86
86
  });
87
+ /**
88
+ * Bumped on every highlight request: a grammar load that resolves after a
89
+ * newer request (another language, or plain text) must not repaint the
90
+ * block with its stale tokens (#416).
91
+ */
92
+ this._highlightRequestId = 0;
87
93
  /**
88
94
  * Stable signal: true when the global editor setting enables line numbers.
89
95
  * Defaults to true. Updated reactively by an effect in connectedCallback.
@@ -146,6 +152,7 @@ let CodeBlockComponent = (() => {
146
152
  return this.rootComponent;
147
153
  }
148
154
  _updateHighlightTokens() {
155
+ const requestId = ++this._highlightRequestId;
149
156
  const modelLang = this.model.props.language$.value;
150
157
  if (modelLang === null) {
151
158
  this.highlightTokens$.value = [];
@@ -168,9 +175,11 @@ let CodeBlockComponent = (() => {
168
175
  const code = this.model.props.text.toString();
169
176
  const loadedLanguages = highlighter.getLoadedLanguages();
170
177
  if (!loadedLanguages.includes(lang)) {
171
- highlighter
172
- .loadLanguage(langImport)
178
+ this.highlighter
179
+ .loadLanguage(lang, langImport)
173
180
  .then(() => {
181
+ if (requestId !== this._highlightRequestId)
182
+ return;
174
183
  this.highlightTokens$.value = highlighter.codeToTokensBase(code, {
175
184
  lang,
176
185
  theme,
@@ -42,7 +42,17 @@ import { css, LitElement, nothing } from 'lit';
42
42
  import { property, query } from 'lit/decorators.js';
43
43
  import { styleMap } from 'lit/directives/style-map.js';
44
44
  import { html } from 'lit/static-html.js';
45
- import { CODE_SEARCH_FOR_LANGUAGE } from '../../translations.js';
45
+ import { CODE_PLAIN_TEXT_LANGUAGE, CODE_SEARCH_FOR_LANGUAGE, } from '../../translations.js';
46
+ /**
47
+ * The list name of the Plain Text entry, which stands for `language: null`
48
+ * (#417). A colon never appears in a shiki language id, so it cannot collide
49
+ * with one, and no query starting with a letter matches it by name. It lives
50
+ * in the list and its persisted order only, never in the model.
51
+ */
52
+ const PLAIN_TEXT_ITEM_NAME = ':plain-text';
53
+ function languageOf(item) {
54
+ return item.name === PLAIN_TEXT_ITEM_NAME ? null : item.name;
55
+ }
46
56
  let LanguageListButton = (() => {
47
57
  let _classSuper = WithDisposable(SignalWatcher(LitElement));
48
58
  let __langButton_decorators;
@@ -95,16 +105,29 @@ let LanguageListButton = (() => {
95
105
  connectedCallback() {
96
106
  super.connectedCallback();
97
107
  const langList = localStorage.getItem('blocksuite:code-block:lang-list');
98
- if (langList) {
99
- this._sortedBundledLanguages = JSON.parse(langList);
100
- }
101
- else {
102
- this._sortedBundledLanguages = this.blockComponent.langs.map(lang => ({
108
+ const languages = langList
109
+ ? JSON.parse(langList)
110
+ : this.blockComponent.langs.map(lang => ({
103
111
  label: lang.name,
104
112
  name: lang.id,
105
113
  aliases: lang.aliases,
106
114
  }));
115
+ // A list persisted before the entry existed lacks it, and a persisted
116
+ // label is in the locale of the session that wrote it: keep the entry's
117
+ // recently-used position, refresh its words.
118
+ const plainText = {
119
+ label: translateKey(this.blockComponent.std, ...CODE_PLAIN_TEXT_LANGUAGE),
120
+ name: PLAIN_TEXT_ITEM_NAME,
121
+ aliases: ['plain', 'text', 'none'],
122
+ };
123
+ const index = languages.findIndex(item => item.name === PLAIN_TEXT_ITEM_NAME);
124
+ if (index === -1) {
125
+ languages.unshift(plainText);
126
+ }
127
+ else {
128
+ languages[index] = plainText;
107
129
  }
130
+ this._sortedBundledLanguages = languages;
108
131
  this.disposables.add(() => {
109
132
  localStorage.setItem('blocksuite:code-block:lang-list', JSON.stringify(this._sortedBundledLanguages));
110
133
  });
@@ -169,7 +192,7 @@ let LanguageListButton = (() => {
169
192
  sortedBundledLanguages.unshift(item);
170
193
  }
171
194
  this.blockComponent.store.transact(() => {
172
- this.blockComponent.model.props.language$.value = item.name;
195
+ this.blockComponent.model.props.language$.value = languageOf(item);
173
196
  });
174
197
  const std = this.blockComponent.std;
175
198
  const mode = std.getOptional(DocModeProvider)?.getEditorMode() ?? 'page';
@@ -183,7 +206,7 @@ let LanguageListButton = (() => {
183
206
  control: item.name,
184
207
  });
185
208
  },
186
- active: item => item.name === this.blockComponent.model.props.language,
209
+ active: item => languageOf(item) === this.blockComponent.model.props.language,
187
210
  items: this._sortedBundledLanguages,
188
211
  };
189
212
  showPopFilterableList({
@@ -8,6 +8,17 @@ export declare const edgelessTextToolbarConfig: {
8
8
  }, {
9
9
  readonly id: "c.font-style";
10
10
  readonly content: (ctx: import("../../affine-shared/services/index.js").ToolbarContext) => import("lit-html").TemplateResult<1> | null;
11
+ }, {
12
+ readonly id: "c.text-decoration";
13
+ readonly when: boolean;
14
+ readonly actions: {
15
+ id: "a.underline" | "b.overline";
16
+ icon: import("lit-html").TemplateResult<1>;
17
+ tooltipWording: import("../../affine-shared/services/index.js").ChromeWording;
18
+ when: (ctx: import("../../affine-shared/services/index.js").ToolbarContext) => boolean;
19
+ active: (ctx: import("../../affine-shared/services/index.js").ToolbarContext) => boolean;
20
+ run: (ctx: import("../../affine-shared/services/index.js").ToolbarContext) => void;
21
+ }[];
11
22
  }, {
12
23
  readonly id: "d.font-size";
13
24
  readonly when: boolean;
@@ -0,0 +1,20 @@
1
+ import { type BlockSvgPainter } from '../affine-block-surface/index.js';
2
+ import { type EdgelessTextBlockModel } from '../affine-model/index.js';
3
+ /**
4
+ * An edgeless text, redrawn as VECTOR text for "Export SVG" (ADR 0025,
5
+ * amendment of 2026-10-04).
6
+ *
7
+ * The block is DOM, so no canvas renderer paints it; this lays it out the way
8
+ * its CSS does, with the canvas text renderer's own font string and wrapping
9
+ * (`@labre/affine-gfx-text`): one line run per paragraph, its size and weight
10
+ * from `HEADING_SCALE` for a heading and from the 15px body otherwise, wrapped
11
+ * to the block's width only when the block has one (`hasMaxWidth`), then
12
+ * rotated about the block's centre and scaled by `scale`, as on screen.
13
+ *
14
+ * ponytail: each paragraph is drawn in the BLOCK's style — inline bold, italic,
15
+ * colour and links are flattened, list bullets and numbers are not drawn, and
16
+ * heading margins are ignored. Upgrade by walking the paragraph's deltas the
17
+ * way `wrapTextDeltas` does for a canvas text, when a board needs it.
18
+ */
19
+ export declare const edgelessTextSvgPainter: BlockSvgPainter<EdgelessTextBlockModel>;
20
+ export declare const EdgelessTextSvgPainterExtension: import("../store/index.js").ExtensionType;
@@ -0,0 +1,76 @@
1
+ import { BlockSvgPainterExtension, } from '../affine-block-surface/index.js';
2
+ import { getFontString, wrapText } from '../affine-gfx-text/index.js';
3
+ import { DefaultTheme } from '../affine-model/index.js';
4
+ import { HEADING_SCALE } from '../affine-shared/consts/index.js';
5
+ import { EDGELESS_TEXT_BASE_FONT_SIZE } from './edgeless-toolbar/font-size.js';
6
+ /** `--affine-line-height` is `calc(1em + 8px)`: what a body line adds to its size. */
7
+ const BODY_LINE_EXTRA = 8;
8
+ /** The container's 1px border, which the text sits inside. */
9
+ const BORDER = 1;
10
+ /** Every paragraph and list item of the block, depth first, as plain text. */
11
+ function runsOf(model, runs = []) {
12
+ for (const child of model.children) {
13
+ if (child.text) {
14
+ const type = child.props.type;
15
+ runs.push({
16
+ level: type !== undefined && type in HEADING_SCALE
17
+ ? type
18
+ : undefined,
19
+ text: child.text.toString(),
20
+ });
21
+ }
22
+ runsOf(child, runs);
23
+ }
24
+ return runs;
25
+ }
26
+ /**
27
+ * An edgeless text, redrawn as VECTOR text for "Export SVG" (ADR 0025,
28
+ * amendment of 2026-10-04).
29
+ *
30
+ * The block is DOM, so no canvas renderer paints it; this lays it out the way
31
+ * its CSS does, with the canvas text renderer's own font string and wrapping
32
+ * (`@labre/affine-gfx-text`): one line run per paragraph, its size and weight
33
+ * from `HEADING_SCALE` for a heading and from the 15px body otherwise, wrapped
34
+ * to the block's width only when the block has one (`hasMaxWidth`), then
35
+ * rotated about the block's centre and scaled by `scale`, as on screen.
36
+ *
37
+ * ponytail: each paragraph is drawn in the BLOCK's style — inline bold, italic,
38
+ * colour and links are flattened, list bullets and numbers are not drawn, and
39
+ * heading margins are ignored. Upgrade by walking the paragraph's deltas the
40
+ * way `wrapTextDeltas` does for a canvas text, when a board needs it.
41
+ */
42
+ export const edgelessTextSvgPainter = (model, ctx, matrix, renderer) => {
43
+ const { scale, rotate, color, fontFamily, fontStyle, fontWeight, textAlign, hasMaxWidth, } = model.props;
44
+ const [, , w, h] = model.deserializedXYWH;
45
+ ctx.setTransform(matrix
46
+ .translate(w / 2, h / 2)
47
+ .rotate(rotate)
48
+ .translate(-w / 2, -h / 2)
49
+ .scale(scale));
50
+ const width = w / scale - 2 * BORDER;
51
+ const x = BORDER +
52
+ (textAlign === 'center' ? width / 2 : textAlign === 'right' ? width : 0);
53
+ ctx.fillStyle = renderer.getColorValue(color, DefaultTheme.textColor, true);
54
+ ctx.textAlign = textAlign;
55
+ ctx.textBaseline = 'middle';
56
+ let y = BORDER;
57
+ for (const { level, text } of runsOf(model)) {
58
+ const heading = level ? HEADING_SCALE[level] : undefined;
59
+ const fontSize = heading?.fontSize ?? EDGELESS_TEXT_BASE_FONT_SIZE;
60
+ const lineHeight = fontSize + (heading?.lineHeightExtra ?? BODY_LINE_EXTRA);
61
+ const font = getFontString({
62
+ fontStyle,
63
+ fontWeight: heading ? String(heading.fontWeight) : fontWeight,
64
+ fontSize,
65
+ fontFamily,
66
+ });
67
+ ctx.font = font;
68
+ const lines = (hasMaxWidth ? wrapText(text, font, width) : text).split('\n');
69
+ for (const line of lines) {
70
+ if (line)
71
+ ctx.fillText(line, x, y + lineHeight / 2);
72
+ y += lineHeight;
73
+ }
74
+ }
75
+ };
76
+ export const EdgelessTextSvgPainterExtension = BlockSvgPainterExtension('affine:edgeless-text', edgelessTextSvgPainter);
@@ -5,6 +5,7 @@ import { EdgelessClipboardEdgelessTextConfig } from './edgeless-clipboard-config
5
5
  import { EdgelessTextInteraction } from './edgeless-text-block.js';
6
6
  import { edgelessTextToolbarExtension } from './edgeless-toolbar/index.js';
7
7
  import { effects } from './effects.js';
8
+ import { EdgelessTextSvgPainterExtension } from './svg-painter.js';
8
9
  export class EdgelessTextViewExtension extends ViewExtensionProvider {
9
10
  constructor() {
10
11
  super(...arguments);
@@ -24,6 +25,7 @@ export class EdgelessTextViewExtension extends ViewExtensionProvider {
24
25
  context.register(edgelessTextToolbarExtension);
25
26
  context.register(EdgelessClipboardEdgelessTextConfig);
26
27
  context.register(EdgelessTextInteraction);
28
+ context.register(EdgelessTextSvgPainterExtension);
27
29
  }
28
30
  }
29
31
  }
@@ -1,4 +1,4 @@
1
- import { reassociateConnectorsCommand } from '../../affine-block-surface/index.js';
1
+ import { applyCreationLayer, reassociateConnectorsCommand, sourceLayerOf, } from '../../affine-block-surface/index.js';
2
2
  import { toast } from '../../affine-components/toast/index.js';
3
3
  import { BookmarkStyles, EmbedGithubModel, EmbedGithubStyles, isExternalEmbedModel, } from '../../affine-model/index.js';
4
4
  import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH, } from '../../affine-shared/consts/index.js';
@@ -342,7 +342,16 @@ const createBuiltinSurfaceToolbarConfigForExternal = (klass) => {
342
342
  const bounds = Bound.deserialize(xywh);
343
343
  bounds.w = EMBED_CARD_WIDTH[style];
344
344
  bounds.h = EMBED_CARD_HEIGHT[style];
345
- const newId = ctx.store.addBlock(flavour, { url, caption, style, xywh: bounds.serialize() }, parent);
345
+ // The card takes the embed's place, layer included (ADR 0031 §6).
346
+ const props = {
347
+ url,
348
+ caption,
349
+ style,
350
+ xywh: bounds.serialize(),
351
+ layer: sourceLayerOf(model),
352
+ };
353
+ applyCreationLayer(ctx.std, props);
354
+ const newId = ctx.store.addBlock(flavour, props, parent);
346
355
  ctx.command.exec(reassociateConnectorsCommand, { oldId, newId });
347
356
  ctx.store.deleteBlock(model);
348
357
  // Selects new block