@formicoidea/labre-core 0.50.0 → 0.51.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 (191) hide show
  1. package/dist/_pkgs/affine-block-attachment/asset-picker.d.ts +24 -0
  2. package/dist/_pkgs/affine-block-attachment/asset-picker.js +87 -0
  3. package/dist/_pkgs/affine-block-attachment/configs/slash-menu.js +3 -20
  4. package/dist/_pkgs/affine-block-attachment/index.d.ts +1 -0
  5. package/dist/_pkgs/affine-block-attachment/index.js +1 -0
  6. package/dist/_pkgs/affine-block-attachment/utils.d.ts +9 -1
  7. package/dist/_pkgs/affine-block-attachment/utils.js +9 -0
  8. package/dist/_pkgs/affine-block-bookmark/adapters/markdown/markdown.js +14 -1
  9. package/dist/_pkgs/affine-block-bookmark/adapters/notion-html.js +5 -1
  10. package/dist/_pkgs/affine-block-database/adapters/markdown.js +5 -3
  11. package/dist/_pkgs/affine-block-embed/common/adapters/html.js +5 -3
  12. package/dist/_pkgs/affine-block-embed/common/adapters/markdown.js +11 -0
  13. package/dist/_pkgs/affine-block-frame/frame-template.d.ts +58 -0
  14. package/dist/_pkgs/affine-block-frame/frame-template.js +207 -0
  15. package/dist/_pkgs/affine-block-frame/frame-toolbar.js +19 -3
  16. package/dist/_pkgs/affine-block-frame/index.d.ts +1 -0
  17. package/dist/_pkgs/affine-block-frame/index.js +1 -0
  18. package/dist/_pkgs/affine-block-frame/translations.d.ts +7 -0
  19. package/dist/_pkgs/affine-block-frame/translations.js +16 -1
  20. package/dist/_pkgs/affine-block-frame/view.js +6 -0
  21. package/dist/_pkgs/affine-block-image/asset-picker.d.ts +63 -0
  22. package/dist/_pkgs/affine-block-image/asset-picker.js +183 -0
  23. package/dist/_pkgs/affine-block-image/commands/insert-images.d.ts +5 -0
  24. package/dist/_pkgs/affine-block-image/commands/insert-images.js +8 -8
  25. package/dist/_pkgs/affine-block-image/components/page-image-block.d.ts +11 -0
  26. package/dist/_pkgs/affine-block-image/components/page-image-block.js +81 -12
  27. package/dist/_pkgs/affine-block-image/configs/replace-action.d.ts +9 -0
  28. package/dist/_pkgs/affine-block-image/configs/replace-action.js +27 -0
  29. package/dist/_pkgs/affine-block-image/configs/toolbar.js +6 -0
  30. package/dist/_pkgs/affine-block-image/crop/crop-controller.d.ts +46 -0
  31. package/dist/_pkgs/affine-block-image/crop/crop-controller.js +104 -0
  32. package/dist/_pkgs/affine-block-image/crop/crop-math.d.ts +70 -0
  33. package/dist/_pkgs/affine-block-image/crop/crop-math.js +141 -0
  34. package/dist/_pkgs/affine-block-image/crop/crop-overlay.d.ts +57 -0
  35. package/dist/_pkgs/affine-block-image/crop/crop-overlay.js +343 -0
  36. package/dist/_pkgs/affine-block-image/crop/crop-toolbar.d.ts +12 -0
  37. package/dist/_pkgs/affine-block-image/crop/crop-toolbar.js +78 -0
  38. package/dist/_pkgs/affine-block-image/crop/write-crop.d.ts +16 -0
  39. package/dist/_pkgs/affine-block-image/crop/write-crop.js +57 -0
  40. package/dist/_pkgs/affine-block-image/edgeless-clipboard-config.js +4 -1
  41. package/dist/_pkgs/affine-block-image/effects.js +2 -0
  42. package/dist/_pkgs/affine-block-image/image-block.d.ts +2 -0
  43. package/dist/_pkgs/affine-block-image/image-block.js +2 -0
  44. package/dist/_pkgs/affine-block-image/image-edgeless-block.d.ts +2 -0
  45. package/dist/_pkgs/affine-block-image/image-edgeless-block.js +36 -8
  46. package/dist/_pkgs/affine-block-image/image-resize-manager.js +15 -0
  47. package/dist/_pkgs/affine-block-image/index.d.ts +1 -0
  48. package/dist/_pkgs/affine-block-image/index.js +1 -0
  49. package/dist/_pkgs/affine-block-image/translations.d.ts +15 -0
  50. package/dist/_pkgs/affine-block-image/translations.js +43 -0
  51. package/dist/_pkgs/affine-block-image/utils.d.ts +13 -0
  52. package/dist/_pkgs/affine-block-image/utils.js +10 -1
  53. package/dist/_pkgs/affine-block-root/clipboard/page-clipboard.js +5 -0
  54. package/dist/_pkgs/affine-block-root/commands/page-export-commands.d.ts +2 -0
  55. package/dist/_pkgs/affine-block-root/commands/page-export-commands.js +71 -0
  56. package/dist/_pkgs/affine-block-root/index.d.ts +1 -0
  57. package/dist/_pkgs/affine-block-root/index.js +1 -0
  58. package/dist/_pkgs/affine-block-root/view.js +8 -0
  59. package/dist/_pkgs/affine-block-surface/extensions/drawio-export/capability.d.ts +30 -0
  60. package/dist/_pkgs/affine-block-surface/extensions/drawio-export/capability.js +44 -0
  61. package/dist/_pkgs/affine-block-surface/extensions/drawio-export/colors.d.ts +26 -0
  62. package/dist/_pkgs/affine-block-surface/extensions/drawio-export/colors.js +82 -0
  63. package/dist/_pkgs/affine-block-surface/extensions/drawio-export/command.d.ts +18 -0
  64. package/dist/_pkgs/affine-block-surface/extensions/drawio-export/command.js +91 -0
  65. package/dist/_pkgs/affine-block-surface/extensions/drawio-export/index.d.ts +3 -0
  66. package/dist/_pkgs/affine-block-surface/extensions/drawio-export/index.js +3 -0
  67. package/dist/_pkgs/affine-block-surface/extensions/drawio-export/writer.d.ts +50 -0
  68. package/dist/_pkgs/affine-block-surface/extensions/drawio-export/writer.js +732 -0
  69. package/dist/_pkgs/affine-block-surface/extensions/export-manager/draw-image-block.d.ts +12 -0
  70. package/dist/_pkgs/affine-block-surface/extensions/export-manager/draw-image-block.js +15 -0
  71. package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +7 -1
  72. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.d.ts +7 -1
  73. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.js +60 -1
  74. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.d.ts +2 -2
  75. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.js +2 -2
  76. package/dist/_pkgs/affine-block-surface/extensions/export-svg/marker-version.d.ts +6 -0
  77. package/dist/_pkgs/affine-block-surface/extensions/export-svg/marker-version.js +8 -0
  78. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.d.ts +28 -1
  79. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +66 -6
  80. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.d.ts +2 -7
  81. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.js +2 -6
  82. package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +2 -0
  83. package/dist/_pkgs/affine-block-surface/extensions/index.js +2 -0
  84. package/dist/_pkgs/affine-block-surface/extensions/interchange-export.d.ts +84 -0
  85. package/dist/_pkgs/affine-block-surface/extensions/interchange-export.js +150 -0
  86. package/dist/_pkgs/affine-block-surface/extensions/interchange-import.js +24 -2
  87. package/dist/_pkgs/affine-block-surface/extensions/interchange.d.ts +23 -2
  88. package/dist/_pkgs/affine-block-surface/extensions/interchange.js +4 -1
  89. package/dist/_pkgs/affine-block-surface/extensions/legend-role.d.ts +18 -0
  90. package/dist/_pkgs/affine-block-surface/extensions/legend-role.js +20 -0
  91. package/dist/_pkgs/affine-block-surface/extensions/legend.d.ts +2 -19
  92. package/dist/_pkgs/affine-block-surface/extensions/legend.js +2 -18
  93. package/dist/_pkgs/affine-block-surface/extensions/svg-sanitize.d.ts +67 -0
  94. package/dist/_pkgs/affine-block-surface/extensions/svg-sanitize.js +235 -0
  95. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch-translations.d.ts +1 -0
  96. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch-translations.js +9 -0
  97. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.d.ts +17 -13
  98. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.js +52 -80
  99. package/dist/_pkgs/affine-block-surface/extensions/xml-element.d.ts +98 -0
  100. package/dist/_pkgs/affine-block-surface/extensions/xml-element.js +261 -0
  101. package/dist/_pkgs/affine-block-surface/extensions/xml-reader.d.ts +238 -0
  102. package/dist/_pkgs/affine-block-surface/extensions/xml-reader.js +570 -0
  103. package/dist/_pkgs/affine-block-surface/framework-background/def.js +1 -1
  104. package/dist/_pkgs/affine-block-surface/interchange-headless.d.ts +29 -0
  105. package/dist/_pkgs/affine-block-surface/interchange-headless.js +32 -0
  106. package/dist/_pkgs/affine-block-surface/view.js +22 -2
  107. package/dist/_pkgs/affine-block-table/adapters/utils.js +24 -1
  108. package/dist/_pkgs/affine-gfx-note/toolbar/note-menu.js +5 -8
  109. package/dist/_pkgs/affine-gfx-template/contribute.d.ts +14 -4
  110. package/dist/_pkgs/affine-gfx-template/contribute.js +47 -6
  111. package/dist/_pkgs/affine-gfx-template/toolbar/builtin-templates.d.ts +7 -2
  112. package/dist/_pkgs/affine-gfx-template/toolbar/builtin-templates.js +14 -40
  113. package/dist/_pkgs/affine-gfx-template/toolbar/resolve-name.d.ts +1 -1
  114. package/dist/_pkgs/affine-gfx-template/toolbar/resolve-name.js +1 -1
  115. package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.d.ts +4 -4
  116. package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.js +9 -9
  117. package/dist/_pkgs/affine-gfx-template/toolbar/template-type.d.ts +2 -4
  118. package/dist/_pkgs/affine-gfx-template/translations.d.ts +5 -0
  119. package/dist/_pkgs/affine-gfx-template/translations.js +9 -0
  120. package/dist/_pkgs/affine-inline-footnote/adapters/markdown/inline-delta.js +6 -0
  121. package/dist/_pkgs/affine-inline-footnote/adapters/markdown/markdown-inline.js +7 -0
  122. package/dist/_pkgs/affine-inline-link/adapters/html/html-inline.js +4 -1
  123. package/dist/_pkgs/affine-inline-link/adapters/html/inline-delta.js +3 -1
  124. package/dist/_pkgs/affine-inline-link/adapters/markdown/inline-delta.js +4 -1
  125. package/dist/_pkgs/affine-inline-link/adapters/notion-html/html-inline.js +2 -1
  126. package/dist/_pkgs/affine-inline-link/link-node/affine-link.d.ts +7 -0
  127. package/dist/_pkgs/affine-inline-link/link-node/affine-link.js +37 -0
  128. package/dist/_pkgs/affine-inline-link/link-node/index.d.ts +1 -0
  129. package/dist/_pkgs/affine-inline-link/link-node/index.js +1 -0
  130. package/dist/_pkgs/affine-inline-link/link-node/propose-views.d.ts +22 -0
  131. package/dist/_pkgs/affine-inline-link/link-node/propose-views.js +59 -0
  132. package/dist/_pkgs/affine-model/blocks/image/image-crop.d.ts +48 -0
  133. package/dist/_pkgs/affine-model/blocks/image/image-crop.js +78 -0
  134. package/dist/_pkgs/affine-model/blocks/image/image-model.d.ts +6 -0
  135. package/dist/_pkgs/affine-model/blocks/image/image-model.js +2 -0
  136. package/dist/_pkgs/affine-model/blocks/image/index.d.ts +1 -0
  137. package/dist/_pkgs/affine-model/blocks/image/index.js +1 -0
  138. package/dist/_pkgs/affine-model/consts/shape.d.ts +2 -0
  139. package/dist/_pkgs/affine-model/consts/shape.js +5 -0
  140. package/dist/_pkgs/affine-model/elements/bpmn/consts.d.ts +31 -0
  141. package/dist/_pkgs/affine-model/elements/bpmn/consts.js +31 -0
  142. package/dist/_pkgs/affine-model/elements/bpmn/index.d.ts +1 -0
  143. package/dist/_pkgs/affine-model/elements/bpmn/index.js +1 -0
  144. package/dist/_pkgs/affine-model/elements/bpmn/pool.d.ts +0 -25
  145. package/dist/_pkgs/affine-model/elements/bpmn/pool.js +1 -25
  146. package/dist/_pkgs/affine-model/elements/shape/shape.d.ts +0 -2
  147. package/dist/_pkgs/affine-model/elements/shape/shape.js +1 -2
  148. package/dist/_pkgs/affine-model/elements/uml/consts.d.ts +133 -0
  149. package/dist/_pkgs/affine-model/elements/uml/consts.js +107 -0
  150. package/dist/_pkgs/affine-model/elements/uml/diagram.d.ts +1 -79
  151. package/dist/_pkgs/affine-model/elements/uml/diagram.js +1 -53
  152. package/dist/_pkgs/affine-model/elements/uml/fragment.d.ts +0 -15
  153. package/dist/_pkgs/affine-model/elements/uml/fragment.js +1 -15
  154. package/dist/_pkgs/affine-model/elements/uml/index.d.ts +1 -0
  155. package/dist/_pkgs/affine-model/elements/uml/index.js +1 -0
  156. package/dist/_pkgs/affine-model/elements/uml/partition.d.ts +0 -20
  157. package/dist/_pkgs/affine-model/elements/uml/partition.js +1 -20
  158. package/dist/_pkgs/affine-model/elements/uml/region.d.ts +0 -11
  159. package/dist/_pkgs/affine-model/elements/uml/region.js +1 -11
  160. package/dist/_pkgs/affine-model/headless.d.ts +19 -0
  161. package/dist/_pkgs/affine-model/headless.js +19 -0
  162. package/dist/_pkgs/affine-shared/headless.d.ts +10 -0
  163. package/dist/_pkgs/affine-shared/headless.js +10 -0
  164. package/dist/_pkgs/affine-shared/services/asset-picker-service.d.ts +63 -0
  165. package/dist/_pkgs/affine-shared/services/asset-picker-service.js +20 -0
  166. package/dist/_pkgs/affine-shared/services/frame-template-service.d.ts +83 -0
  167. package/dist/_pkgs/affine-shared/services/frame-template-service.js +17 -0
  168. package/dist/_pkgs/affine-shared/services/index.d.ts +2 -0
  169. package/dist/_pkgs/affine-shared/services/index.js +2 -0
  170. package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +6 -0
  171. package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +10 -0
  172. package/dist/_pkgs/affine-widget-drag-handle/watchers/drag-event-watcher.js +8 -3
  173. package/dist/_pkgs/affine-widget-keyboard-toolbar/config.js +4 -16
  174. package/dist/_pkgs/affine-widget-linked-doc/transformers/html.d.ts +7 -0
  175. package/dist/_pkgs/affine-widget-linked-doc/transformers/html.js +25 -24
  176. package/dist/_pkgs/affine-widget-linked-doc/transformers/index.d.ts +1 -1
  177. package/dist/_pkgs/affine-widget-linked-doc/transformers/markdown.d.ts +7 -0
  178. package/dist/_pkgs/affine-widget-linked-doc/transformers/markdown.js +26 -25
  179. package/dist/_pkgs/affine-widget-linked-doc/transformers/utils.d.ts +23 -0
  180. package/dist/_pkgs/affine-widget-linked-doc/transformers/utils.js +14 -0
  181. package/dist/commands.js +5 -2
  182. package/dist/host-panels.d.ts +21 -1
  183. package/dist/host-panels.js +50 -10
  184. package/dist/interchange.d.ts +1 -0
  185. package/dist/interchange.js +1 -0
  186. package/dist/model/headless.d.ts +1 -0
  187. package/dist/model/headless.js +1 -0
  188. package/dist/shared/headless.d.ts +1 -0
  189. package/dist/shared/headless.js +1 -0
  190. package/dist/translations.js +8 -1
  191. package/package.json +13 -1
@@ -1,6 +1,8 @@
1
+ import { ImageBlockModel, readImageCrop } from '../affine-model/index.js';
1
2
  import { DocModeProvider } from '../affine-shared/services/index.js';
2
3
  import { getClosestBlockComponentByElement, getModelByElement, } from '../affine-shared/utils/index.js';
3
4
  import { GfxControllerIdentifier } from '../std/gfx/index.js';
5
+ import { wholeImageSize } from './crop/crop-math.js';
4
6
  export class ImageResizeManager {
5
7
  constructor() {
6
8
  this._activeComponent = null;
@@ -16,6 +18,19 @@ export class ImageResizeManager {
16
18
  const dragModel = getModelByElement(this._activeComponent);
17
19
  dragModel?.store.captureSync();
18
20
  const { width, height } = this._imageContainer.getBoundingClientRect();
21
+ // A cropped page image shows a window on the picture, but `width` and
22
+ // `height` stay the size of the WHOLE picture (ADR 0037): the HTML
23
+ // adapter and an older client draw it whole at that size.
24
+ const crop = dragModel instanceof ImageBlockModel
25
+ ? readImageCrop(dragModel.props.crop)
26
+ : undefined;
27
+ if (crop) {
28
+ const img = this._activeComponent.querySelector('img');
29
+ dragModel?.store.updateBlock(dragModel, wholeImageSize({ w: width / this._zoom, h: height / this._zoom }, crop, img?.naturalWidth && img.naturalHeight
30
+ ? { width: img.naturalWidth, height: img.naturalHeight }
31
+ : null));
32
+ return;
33
+ }
19
34
  dragModel?.store.updateBlock(dragModel, {
20
35
  width: width / this._zoom,
21
36
  height: height / this._zoom,
@@ -1,4 +1,5 @@
1
1
  export * from './adapters/index.js';
2
+ export { addImagesFromAssets, addSiblingImageBlocksFromAssets, pickAndAddImages, pickAndAddSiblingImageBlocks, replaceImage, } from './asset-picker.js';
2
3
  export * from './commands/index.js';
3
4
  export * from './edgeless-clipboard-config.js';
4
5
  export * from './image-block.js';
@@ -1,4 +1,5 @@
1
1
  export * from './adapters/index.js';
2
+ export { addImagesFromAssets, addSiblingImageBlocksFromAssets, pickAndAddImages, pickAndAddSiblingImageBlocks, replaceImage, } from './asset-picker.js';
2
3
  export * from './commands/index.js';
3
4
  export * from './edgeless-clipboard-config.js';
4
5
  export * from './image-block.js';
@@ -14,6 +14,16 @@ export declare const IMAGE_SLASH_DESCRIPTION: ChromeWording;
14
14
  /** The slash-menu tooltip's own caption, distinct from the item's name. */
15
15
  export declare const IMAGE_SLASH_PHOTO_CAPTION: ChromeWording;
16
16
  export declare const IMAGE_TOOLBAR_TURN_INTO_CARD_VIEW: ChromeWording;
17
+ /**
18
+ * « Rogner » (ADR 0037): the toolbar button, its presets and the way back to
19
+ * the whole picture. The ratios are words too — a host may write « 16/9 ».
20
+ */
21
+ export declare const IMAGE_TOOLBAR_CROP: ChromeWording;
22
+ export declare const IMAGE_TOOLBAR_CROP_FREE: ChromeWording;
23
+ export declare const IMAGE_TOOLBAR_CROP_16_9: ChromeWording;
24
+ export declare const IMAGE_TOOLBAR_CROP_4_3: ChromeWording;
25
+ export declare const IMAGE_TOOLBAR_CROP_1_1: ChromeWording;
26
+ export declare const IMAGE_TOOLBAR_CROP_ORIGINAL: ChromeWording;
17
27
  export declare const IMAGE_PREVIEW_TITLE: ChromeWording;
18
28
  /**
19
29
  * The upload/download toasts (`utils.ts`) and the resource controller's
@@ -25,6 +35,11 @@ export declare const IMAGE_TOAST_DOWNLOAD_FAILED: ChromeWording;
25
35
  export declare const IMAGE_TOAST_DOWNLOADING: ChromeWording;
26
36
  export declare const IMAGE_TOAST_COPIED: ChromeWording;
27
37
  export declare const IMAGE_TOAST_READ_SIZE_FAILED: ChromeWording;
38
+ /**
39
+ * The image toolbar's "Replace" (`configs/replace-action.ts`), offered only
40
+ * with a host asset dialog (`AssetPickerProvider`).
41
+ */
42
+ export declare const IMAGE_TOOLBAR_REPLACE: ChromeWording;
28
43
  /**
29
44
  * This package's contribution to the translation-key manifest, listed in
30
45
  * `PACKAGE_WORDINGS` under source `chrome`
@@ -23,6 +23,34 @@ export const IMAGE_TOOLBAR_TURN_INTO_CARD_VIEW = [
23
23
  'com.labre.image.toolbar.turn-into-card-view',
24
24
  'Turn into card view',
25
25
  ];
26
+ /**
27
+ * « Rogner » (ADR 0037): the toolbar button, its presets and the way back to
28
+ * the whole picture. The ratios are words too — a host may write « 16/9 ».
29
+ */
30
+ export const IMAGE_TOOLBAR_CROP = [
31
+ 'com.labre.image.toolbar.crop',
32
+ 'Crop',
33
+ ];
34
+ export const IMAGE_TOOLBAR_CROP_FREE = [
35
+ 'com.labre.image.toolbar.crop.free',
36
+ 'Free',
37
+ ];
38
+ export const IMAGE_TOOLBAR_CROP_16_9 = [
39
+ 'com.labre.image.toolbar.crop.ratio-16-9',
40
+ '16:9',
41
+ ];
42
+ export const IMAGE_TOOLBAR_CROP_4_3 = [
43
+ 'com.labre.image.toolbar.crop.ratio-4-3',
44
+ '4:3',
45
+ ];
46
+ export const IMAGE_TOOLBAR_CROP_1_1 = [
47
+ 'com.labre.image.toolbar.crop.ratio-1-1',
48
+ '1:1',
49
+ ];
50
+ export const IMAGE_TOOLBAR_CROP_ORIGINAL = [
51
+ 'com.labre.image.toolbar.crop.original',
52
+ 'Original image',
53
+ ];
26
54
  export const IMAGE_PREVIEW_TITLE = [
27
55
  'com.labre.image.preview.title',
28
56
  'Image Block',
@@ -49,6 +77,14 @@ export const IMAGE_TOAST_READ_SIZE_FAILED = [
49
77
  'com.labre.image.toast.read-size-failed',
50
78
  'Failed to read image size, please try another image',
51
79
  ];
80
+ /**
81
+ * The image toolbar's "Replace" (`configs/replace-action.ts`), offered only
82
+ * with a host asset dialog (`AssetPickerProvider`).
83
+ */
84
+ export const IMAGE_TOOLBAR_REPLACE = [
85
+ 'com.labre.image.toolbar.replace',
86
+ 'Replace',
87
+ ];
52
88
  /**
53
89
  * This package's contribution to the translation-key manifest, listed in
54
90
  * `PACKAGE_WORDINGS` under source `chrome`
@@ -60,9 +96,16 @@ export const IMAGE_WORDINGS = [
60
96
  IMAGE_SLASH_DESCRIPTION,
61
97
  IMAGE_SLASH_PHOTO_CAPTION,
62
98
  IMAGE_TOOLBAR_TURN_INTO_CARD_VIEW,
99
+ IMAGE_TOOLBAR_CROP,
100
+ IMAGE_TOOLBAR_CROP_FREE,
101
+ IMAGE_TOOLBAR_CROP_16_9,
102
+ IMAGE_TOOLBAR_CROP_4_3,
103
+ IMAGE_TOOLBAR_CROP_1_1,
104
+ IMAGE_TOOLBAR_CROP_ORIGINAL,
63
105
  IMAGE_PREVIEW_TITLE,
64
106
  IMAGE_TOAST_DOWNLOAD_FAILED,
65
107
  IMAGE_TOAST_DOWNLOADING,
66
108
  IMAGE_TOAST_COPIED,
67
109
  IMAGE_TOAST_READ_SIZE_FAILED,
110
+ IMAGE_TOOLBAR_REPLACE,
68
111
  ];
@@ -1,3 +1,4 @@
1
+ import { type ImageBlockProps } from '../affine-model/index.js';
1
2
  import { Bound, type IVec } from '../global/gfx/index.js';
2
3
  import { type BlockStdScope } from '../std/index.js';
3
4
  import type { BlockModel } from '../store/index.js';
@@ -19,5 +20,17 @@ export declare function addImages(std: BlockStdScope, files: File[], options: {
19
20
  maxWidth?: number;
20
21
  shouldTransformPoint?: boolean;
21
22
  }): Promise<string[]>;
23
+ export type ImageBlockSource = Pick<Required<ImageBlockProps>, 'size' | 'sourceId' | 'width' | 'height'>;
24
+ /**
25
+ * Lays image blocks out on the canvas around `options.point` (the viewport's
26
+ * centre without one), in the viewer's active layer, and selects them. Shared
27
+ * by the files path (`addImages`) and the asset path
28
+ * (`addImagesFromAssets`), which only differ in where `sourceId` comes from.
29
+ */
30
+ export declare function placeImagesOnCanvas(std: BlockStdScope, propsArray: ImageBlockSource[], options: {
31
+ point?: IVec;
32
+ maxWidth?: number;
33
+ shouldTransformPoint?: boolean;
34
+ }): string[];
22
35
  export declare function calcBoundByOrigin(point: IVec, inTopLeft?: boolean, width?: number, height?: number): Bound;
23
36
  export declare function duplicate(block: ImageBlockComponent): void;
@@ -194,8 +194,17 @@ export async function addImages(std, files, options) {
194
194
  return [];
195
195
  if (hasExceeded(std, files))
196
196
  return [];
197
- const flavour = ImageBlockSchema.model.flavour;
198
197
  const propsArray = await Promise.all(files.map(file => buildPropsWith(std, file)));
198
+ return placeImagesOnCanvas(std, propsArray, options);
199
+ }
200
+ /**
201
+ * Lays image blocks out on the canvas around `options.point` (the viewport's
202
+ * centre without one), in the viewer's active layer, and selects them. Shared
203
+ * by the files path (`addImages`) and the asset path
204
+ * (`addImagesFromAssets`), which only differ in where `sourceId` comes from.
205
+ */
206
+ export function placeImagesOnCanvas(std, propsArray, options) {
207
+ const flavour = ImageBlockSchema.model.flavour;
199
208
  const gfx = std.get(GfxControllerIdentifier);
200
209
  const isMultiple = propsArray.length > 1;
201
210
  const inTopLeft = isMultiple;
@@ -1,3 +1,4 @@
1
+ import { lonePastedUrl, proposeLinkViews } from '../../affine-inline-link/index.js';
1
2
  import { deleteTextCommand } from '../../affine-inline-preset/index.js';
2
3
  import { pasteMiddleware, replaceIdMiddleware, surfaceRefToEmbed, uploadMiddleware, } from '../../affine-shared/adapters/index.js';
3
4
  import { clearAndSelectFirstModelCommand, deleteSelectedModelsCommand, getBlockIndexCommand, getBlockSelectionsCommand, getImageSelectionsCommand, getSelectedModelsCommand, getTextSelectionCommand, retainFirstModelCommand, } from '../../affine-shared/commands/index.js';
@@ -112,8 +113,12 @@ export class PageClipboard extends ReadOnlyClipboard {
112
113
  if (!ctx.parentBlock) {
113
114
  return;
114
115
  }
116
+ // A lone URL still pastes as a plain link; its views are then offered,
117
+ // never applied (labre REQ-IM-1).
118
+ const url = lonePastedUrl(e.clipboardData?.getData('text/plain'));
115
119
  this.std.clipboard
116
120
  .paste(e, this.std.store, ctx.parentBlock.model.id, ctx.blockIndex ? ctx.blockIndex + 1 : 1)
121
+ .then(() => (url ? proposeLinkViews(this.std, url) : false))
117
122
  .catch(console.error);
118
123
  return next();
119
124
  })
@@ -0,0 +1,2 @@
1
+ import type { AnyCommandDescriptor } from '../../std/index.js';
2
+ export declare const pageExportCommands: AnyCommandDescriptor[];
@@ -0,0 +1,71 @@
1
+ /**
2
+ * `page.export.markdown` and `page.export.html` — the page as a Markdown or an
3
+ * HTML file, through the adapters the library already ships
4
+ * (`MarkdownTransformer.docFile`, `HtmlTransformer.docFile`).
5
+ *
6
+ * View actions (ADR 0034, amendments of 2026-10-13 and 2026-10-14): on the
7
+ * `'view-menu'` surface under the `'export'` category, so a host lists them
8
+ * with every other export of the view it shows (`getViewExports`,
9
+ * `@labre/affine/host-panels`), and on the palette. Given `params.deliver`
10
+ * (`runViewAction`) the file goes to the host and nothing is downloaded;
11
+ * without it (the palette, a bound chord) the command downloads it itself.
12
+ *
13
+ * `scope: 'global'`: the page's text is the same in both views — the notes of
14
+ * a canvas are the page's paragraphs — so both views list them. A page whose
15
+ * blocks reference images or attachments comes out as a zip, the file
16
+ * (`index.md` / `index.html`) beside an `assets/` folder its links point at.
17
+ *
18
+ * `owner: 'core'` and no `telemetry` (it names no framework, like the canvas
19
+ * exports); `runCommand` still records usage. It READS: no read-only guard.
20
+ * Not `'agent'`: an agent turn would drop a file the user did not ask for.
21
+ */
22
+ import { downloadBlob } from '../../affine-shared/utils/index.js';
23
+ import { HtmlTransformer, MarkdownTransformer, } from '../../affine-widget-linked-doc/index.js';
24
+ async function exportPage(std, render, params) {
25
+ const file = await render(std);
26
+ if (!file)
27
+ return;
28
+ const deliver = params?.deliver;
29
+ if (typeof deliver === 'function')
30
+ deliver(file);
31
+ else
32
+ downloadBlob(file.blob, file.filename);
33
+ }
34
+ const exportMarkdown = {
35
+ id: 'page.export.markdown',
36
+ owner: 'core',
37
+ kind: 'action',
38
+ labelKey: 'com.labre.command.page.export.markdown',
39
+ labelFallback: 'Export as Markdown',
40
+ descriptionKey: 'com.labre.command.page.export.markdown.description',
41
+ descriptionFallback: 'Download the page as a Markdown file, in a zip with its images when it has any.',
42
+ category: 'export',
43
+ iconKey: 'page.export.markdown',
44
+ keywords: ['markdown', 'md', 'export', 'download'],
45
+ surfaces: ['view-menu', 'palette'],
46
+ order: 15,
47
+ scope: 'global',
48
+ defaultKeys: { mac: [], other: [] },
49
+ run: (std, _invocation, params) => exportPage(std, ({ store }) => MarkdownTransformer.docFile(store), params),
50
+ };
51
+ const exportHtml = {
52
+ id: 'page.export.html',
53
+ owner: 'core',
54
+ kind: 'action',
55
+ labelKey: 'com.labre.command.page.export.html',
56
+ labelFallback: 'Export as HTML',
57
+ descriptionKey: 'com.labre.command.page.export.html.description',
58
+ descriptionFallback: 'Download the page as an HTML file, in a zip with its images when it has any.',
59
+ category: 'export',
60
+ iconKey: 'page.export.html',
61
+ keywords: ['html', 'web', 'export', 'download'],
62
+ surfaces: ['view-menu', 'palette'],
63
+ order: 16,
64
+ scope: 'global',
65
+ defaultKeys: { mac: [], other: [] },
66
+ run: (std, _invocation, params) => exportPage(std, ({ store }) => HtmlTransformer.docFile(store), params),
67
+ };
68
+ export const pageExportCommands = [
69
+ exportMarkdown,
70
+ exportHtml,
71
+ ];
@@ -1,6 +1,7 @@
1
1
  export * from './adapters/index.js';
2
2
  export * from './clipboard/index.js';
3
3
  export * from './commands/copy-link-commands.js';
4
+ export * from './commands/page-export-commands.js';
4
5
  export * from './commands/pivot-commands.js';
5
6
  export * from './commands/reading-commands.js';
6
7
  export * from './commands/tag-commands.js';
@@ -1,6 +1,7 @@
1
1
  export * from './adapters/index.js';
2
2
  export * from './clipboard/index.js';
3
3
  export * from './commands/copy-link-commands.js';
4
+ export * from './commands/page-export-commands.js';
4
5
  export * from './commands/pivot-commands.js';
5
6
  export * from './commands/reading-commands.js';
6
7
  export * from './commands/tag-commands.js';
@@ -1,3 +1,4 @@
1
+ import { ExportToHtmlIcon, ExportToMarkdownIcon } from '@blocksuite/icons/lit';
1
2
  import { ViewExtensionProvider, } from '../affine-ext-loader/index.js';
2
3
  import { NoteBlockSchema } from '../affine-model/index.js';
3
4
  import { ToolbarModuleExtension, ViewportElementExtension, } from '../affine-shared/services/index.js';
@@ -5,6 +6,7 @@ import { BlockFlavourIdentifier, BlockViewExtension, FlavourExtension, CommandEx
5
6
  import { literal } from 'lit/static-html.js';
6
7
  import { PageClipboard, ReadOnlyClipboard } from './clipboard/index.js';
7
8
  import { copyLinkCommands } from './commands/copy-link-commands.js';
9
+ import { pageExportCommands } from './commands/page-export-commands.js';
8
10
  import { pivotCommands } from './commands/pivot-commands.js';
9
11
  import { readingCommands } from './commands/reading-commands.js';
10
12
  import { tagCommands } from './commands/tag-commands.js';
@@ -73,6 +75,12 @@ export class RootViewExtension extends ViewExtensionProvider {
73
75
  ...readingCommands,
74
76
  ...copyLinkCommands,
75
77
  ]),
78
+ // The page as Markdown or HTML (ADR 0034, amendment of 2026-10-14):
79
+ // view actions of both views, never gated — the page's own text.
80
+ CommandExtension(pageExportCommands, {
81
+ 'page.export.markdown': ExportToMarkdownIcon(),
82
+ 'page.export.html': ExportToHtmlIcon(),
83
+ }),
76
84
  ShortcutKeymapExtension('global'),
77
85
  ToolbarModuleExtension({
78
86
  id: BlockFlavourIdentifier(NoteBlockSchema.model.flavour),
@@ -0,0 +1,30 @@
1
+ import { type InterchangeExportCapability, type InterchangeFormat } from '../interchange.js';
2
+ /**
3
+ * The owner of what the CANVAS writes, whatever drew on it (`docs/adr/0019`,
4
+ * amendment of 2026-10-14).
5
+ *
6
+ * The registry's `framework` field names who owns the vocabulary a capability
7
+ * speaks (`docs/adr/0012` P1). A generic rendering speaks none — a shape, a
8
+ * line, a group — so its owner is the canvas itself, the owner `'core'` plays
9
+ * for the canvas's PNG export in the command registry. Unlike a framework's,
10
+ * this capability is registered UNCONDITIONALLY, from the surface's own view
11
+ * extension: no flag gates a picture of what is on the canvas
12
+ * (`interchange-gating.unit.spec.ts` pins that it survives every flag off).
13
+ */
14
+ export declare const CANVAS_INTERCHANGE_OWNER = "canvas";
15
+ /**
16
+ * draw.io, as the canvas writes it. **Visual** (`docs/adr/0012` P2): the file
17
+ * carries a drawing, so no round trip is promised and none is implied — the
18
+ * same tier, id and extensions as UML's draw.io READER (`UML_DRAWIO_FORMAT`),
19
+ * because it is the same format, read and written by two owners.
20
+ */
21
+ export declare const CANVAS_DRAWIO_FORMAT: InterchangeFormat;
22
+ /**
23
+ * `canvas:drawio:export` — the canvas, or a selection of it, as one
24
+ * uncompressed draw.io page. `run` is {@link exportCanvasDrawio}, the pure
25
+ * writer labre-mcp can call directly; the `canvas.export.drawio` command
26
+ * calls THIS, so the two cannot write different bytes.
27
+ */
28
+ export declare const CANVAS_DRAWIO_EXPORT: InterchangeExportCapability;
29
+ /** Everything the canvas registers, for the surface's view extension. */
30
+ export declare const CANVAS_INTERCHANGE: readonly InterchangeExportCapability[];
@@ -0,0 +1,44 @@
1
+ import { interchangeCapabilityId, } from '../interchange.js';
2
+ import { DRAWIO_EXTENSION, DRAWIO_MIME, exportCanvasDrawio } from './writer.js';
3
+ /**
4
+ * The owner of what the CANVAS writes, whatever drew on it (`docs/adr/0019`,
5
+ * amendment of 2026-10-14).
6
+ *
7
+ * The registry's `framework` field names who owns the vocabulary a capability
8
+ * speaks (`docs/adr/0012` P1). A generic rendering speaks none — a shape, a
9
+ * line, a group — so its owner is the canvas itself, the owner `'core'` plays
10
+ * for the canvas's PNG export in the command registry. Unlike a framework's,
11
+ * this capability is registered UNCONDITIONALLY, from the surface's own view
12
+ * extension: no flag gates a picture of what is on the canvas
13
+ * (`interchange-gating.unit.spec.ts` pins that it survives every flag off).
14
+ */
15
+ export const CANVAS_INTERCHANGE_OWNER = 'canvas';
16
+ /**
17
+ * draw.io, as the canvas writes it. **Visual** (`docs/adr/0012` P2): the file
18
+ * carries a drawing, so no round trip is promised and none is implied — the
19
+ * same tier, id and extensions as UML's draw.io READER (`UML_DRAWIO_FORMAT`),
20
+ * because it is the same format, read and written by two owners.
21
+ */
22
+ export const CANVAS_DRAWIO_FORMAT = {
23
+ id: 'drawio',
24
+ tier: 'visual',
25
+ extensions: [DRAWIO_EXTENSION, '.drawio.xml', '.xml'],
26
+ mime: DRAWIO_MIME,
27
+ };
28
+ /**
29
+ * `canvas:drawio:export` — the canvas, or a selection of it, as one
30
+ * uncompressed draw.io page. `run` is {@link exportCanvasDrawio}, the pure
31
+ * writer labre-mcp can call directly; the `canvas.export.drawio` command
32
+ * calls THIS, so the two cannot write different bytes.
33
+ */
34
+ export const CANVAS_DRAWIO_EXPORT = {
35
+ id: interchangeCapabilityId(CANVAS_INTERCHANGE_OWNER, CANVAS_DRAWIO_FORMAT.id, 'export'),
36
+ framework: CANVAS_INTERCHANGE_OWNER,
37
+ format: CANVAS_DRAWIO_FORMAT,
38
+ direction: 'export',
39
+ run: exportCanvasDrawio,
40
+ };
41
+ /** Everything the canvas registers, for the surface's view extension. */
42
+ export const CANVAS_INTERCHANGE = [
43
+ CANVAS_DRAWIO_EXPORT,
44
+ ];
@@ -0,0 +1,26 @@
1
+ /**
2
+ * A stored colour as draw.io can paint it: `#RRGGBB`, or `none`.
3
+ *
4
+ * draw.io has none of our variables, so every colour is RESOLVED to a value
5
+ * here, the way `ThemeProvider.getColorValue(color, fallback, true)` resolves
6
+ * one for a canvas painter — without its DOM, which a pure writer has none of:
7
+ * a `{ light, dark }` pair takes its LIGHT side (a file is printed on white), a
8
+ * legacy `--affine-*` name is looked up in the same static table the theme
9
+ * service reads, and a `var(--…)` inside that table is followed, a bounded
10
+ * number of hops.
11
+ *
12
+ * `opacity` is the alpha a value carried (`rgba(…, .5)`, `#rrggbbaa`), in
13
+ * draw.io's percent, and only when it is below 100: the style keys draw.io
14
+ * takes it under differ per use (`fillOpacity`, `strokeOpacity`), so the
15
+ * caller names the key.
16
+ */
17
+ export interface DrawioColor {
18
+ value: string;
19
+ opacity?: number;
20
+ }
21
+ /**
22
+ * Resolve a stored {@link Color} for the file. `undefined` when there is
23
+ * nothing to say (no colour stored, or one this writer cannot read), so the
24
+ * caller leaves draw.io's own default in place rather than writing a guess.
25
+ */
26
+ export declare function drawioColor(color: unknown): DrawioColor | undefined;
@@ -0,0 +1,82 @@
1
+ import { ColorScheme, resolveColor } from '../../../affine-model/index.js';
2
+ import { combinedLightCssVariables } from '@toeverything/theme';
3
+ const NONE = { value: 'none' };
4
+ /** How many `var(--…)` hops a value may take before it is given up on. */
5
+ const MAX_VAR_HOPS = 4;
6
+ const VAR = /^var\(\s*(--[\w-]+)\s*(?:,[^)]*)?\)$/;
7
+ const HEX = /^#([\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/i;
8
+ const RGB = /^rgba?\(([^)]*)\)$/i;
9
+ const hex2 = (channel) => Math.round(Math.min(255, Math.max(0, channel)))
10
+ .toString(16)
11
+ .padStart(2, '0');
12
+ function withAlpha(rgb, alpha) {
13
+ if (alpha <= 0)
14
+ return NONE;
15
+ const value = `#${rgb.map(hex2).join('')}`.toUpperCase();
16
+ return alpha < 1 ? { value, opacity: Math.round(alpha * 100) } : { value };
17
+ }
18
+ function parseValue(raw) {
19
+ const value = raw.trim();
20
+ if (!value)
21
+ return undefined;
22
+ if (value.toLowerCase() === 'transparent' || value.toLowerCase() === 'none') {
23
+ return NONE;
24
+ }
25
+ const hex = HEX.exec(value)?.[1];
26
+ if (hex) {
27
+ const full = hex.length <= 4
28
+ ? [...hex].map(digit => digit + digit).join('')
29
+ : hex.toLowerCase();
30
+ const channel = (at) => Number.parseInt(full.slice(at, at + 2), 16);
31
+ return withAlpha([channel(0), channel(2), channel(4)], full.length === 8 ? channel(6) / 255 : 1);
32
+ }
33
+ const rgb = RGB.exec(value)?.[1];
34
+ if (rgb) {
35
+ const parts = rgb
36
+ .split(/[\s,/]+/)
37
+ .filter(Boolean)
38
+ .map(part => part.endsWith('%')
39
+ ? (Number.parseFloat(part) / 100) * 255
40
+ : Number.parseFloat(part));
41
+ const [r, g, b] = parts;
42
+ if (r === undefined ||
43
+ g === undefined ||
44
+ b === undefined ||
45
+ ![r, g, b].every(Number.isFinite)) {
46
+ return undefined;
47
+ }
48
+ // The alpha of `rgba(…, 50%)` was scaled as a channel above; undo that.
49
+ const rawAlpha = rgb.split(/[\s,/]+/).filter(Boolean)[3];
50
+ const alpha = rawAlpha === undefined
51
+ ? 1
52
+ : rawAlpha.endsWith('%')
53
+ ? Number.parseFloat(rawAlpha) / 100
54
+ : Number.parseFloat(rawAlpha);
55
+ return withAlpha([r, g, b], Number.isFinite(alpha) ? alpha : 1);
56
+ }
57
+ return undefined;
58
+ }
59
+ /**
60
+ * Resolve a stored {@link Color} for the file. `undefined` when there is
61
+ * nothing to say (no colour stored, or one this writer cannot read), so the
62
+ * caller leaves draw.io's own default in place rather than writing a guess.
63
+ */
64
+ export function drawioColor(color) {
65
+ if (color === undefined || color === null || color === '')
66
+ return undefined;
67
+ if (typeof color !== 'string' && typeof color !== 'object')
68
+ return undefined;
69
+ let value = resolveColor(color, ColorScheme.Light, '');
70
+ for (let hop = 0; hop <= MAX_VAR_HOPS; hop++) {
71
+ const name = value.startsWith('--') ? value : VAR.exec(value)?.[1];
72
+ if (!name)
73
+ return parseValue(value);
74
+ if (name.endsWith('transparent'))
75
+ return NONE;
76
+ const next = combinedLightCssVariables[name];
77
+ if (!next)
78
+ return undefined;
79
+ value = next;
80
+ }
81
+ return undefined;
82
+ }
@@ -0,0 +1,18 @@
1
+ import type { AnyCommandDescriptor, BlockStdScope, CommandFile } from '../../../std/index.js';
2
+ import { type GfxModel } from '../../../std/gfx/index.js';
3
+ /**
4
+ * What the export takes: the selection when there is one, the whole canvas
5
+ * otherwise — in the canvas's own z-order, and as this viewer SEES it (ADR
6
+ * 0031: what they hid is neither painted nor exported, the PNG's rule).
7
+ *
8
+ * A selected group or frame brings what it holds: selecting a classifier
9
+ * selects its group, and a group exported without its shape and its words
10
+ * would be an empty box.
11
+ */
12
+ export declare function canvasDrawioSource(std: BlockStdScope): GfxModel[];
13
+ /**
14
+ * The canvas (or its selection) as a draw.io file, or `null` when there is
15
+ * nothing on it. Through the declared capability, never round it.
16
+ */
17
+ export declare function canvasDrawioFile(std: BlockStdScope): CommandFile | null;
18
+ export declare const canvasDrawioExportCommands: AnyCommandDescriptor[];
@@ -0,0 +1,91 @@
1
+ import { downloadBlob } from '../../../affine-shared/utils/index.js';
2
+ import { GfxBlockElementModel, GfxControllerIdentifier, GfxPrimitiveElementModel, } from '../../../std/gfx/index.js';
3
+ import { CANVAS_DRAWIO_EXPORT } from './capability.js';
4
+ /**
5
+ * What the export takes: the selection when there is one, the whole canvas
6
+ * otherwise — in the canvas's own z-order, and as this viewer SEES it (ADR
7
+ * 0031: what they hid is neither painted nor exported, the PNG's rule).
8
+ *
9
+ * A selected group or frame brings what it holds: selecting a classifier
10
+ * selects its group, and a group exported without its shape and its words
11
+ * would be an empty box.
12
+ */
13
+ export function canvasDrawioSource(std) {
14
+ const gfx = std.get(GfxControllerIdentifier);
15
+ const selection = gfx.selection.editing ? [] : gfx.selection.selectedElements;
16
+ let models;
17
+ if (selection.length === 0) {
18
+ models = gfx.gfxElements;
19
+ }
20
+ else {
21
+ const picked = new Set();
22
+ for (const model of selection) {
23
+ picked.add(model);
24
+ const descendants = model
25
+ .descendantElements;
26
+ if (Array.isArray(descendants)) {
27
+ for (const descendant of descendants) {
28
+ picked.add(descendant);
29
+ }
30
+ }
31
+ }
32
+ models = [...picked];
33
+ }
34
+ return models
35
+ .filter(model => !gfx.localVisibility.isHidden(model))
36
+ .sort((a, b) => gfx.layer.compare(a, b));
37
+ }
38
+ /**
39
+ * The canvas (or its selection) as a draw.io file, or `null` when there is
40
+ * nothing on it. Through the declared capability, never round it.
41
+ */
42
+ export function canvasDrawioFile(std) {
43
+ const models = canvasDrawioSource(std);
44
+ if (models.length === 0)
45
+ return null;
46
+ const { text, filename, mime } = CANVAS_DRAWIO_EXPORT.run(models.filter((model) => model instanceof GfxPrimitiveElementModel), {
47
+ name: std.store.workspace.meta.getDocMeta(std.store.id)?.title,
48
+ blocks: models.filter((model) => model instanceof GfxBlockElementModel),
49
+ });
50
+ return { blob: new Blob([text], { type: mime }), filename };
51
+ }
52
+ /**
53
+ * "Export as draw.io", the third export of the canvas's "This view" section
54
+ * (ADR 0034, amendment of 2026-10-13), on the model of `canvas.export.png`:
55
+ * given `params.deliver` it hands the file over and downloads nothing
56
+ * (`runViewAction`), without it (the palette) it downloads the file itself.
57
+ *
58
+ * `owner: 'core'` and never gated, for the PNG's reason: a picture of what is
59
+ * on the canvas is not a framework's tooling. Not `'agent'`: an agent turn
60
+ * would drop a file the user did not ask for. It READS, so no read-only guard.
61
+ * Nothing to export, no file and no error.
62
+ */
63
+ const exportDrawio = {
64
+ id: 'canvas.export.drawio',
65
+ owner: 'core',
66
+ kind: 'action',
67
+ labelKey: 'com.labre.command.canvas.export.drawio',
68
+ labelFallback: 'Export as draw.io',
69
+ descriptionKey: 'com.labre.command.canvas.export.drawio.description',
70
+ descriptionFallback: 'Download the selection, or the whole canvas, as a draw.io drawing: shapes, lines and words, best effort, no round trip.',
71
+ category: 'export',
72
+ iconKey: 'canvas.export.drawio',
73
+ keywords: ['drawio', 'draw.io', 'diagrams.net', 'mxgraph', 'export'],
74
+ surfaces: ['view-menu', 'palette'],
75
+ order: 12,
76
+ scope: 'edgeless',
77
+ defaultKeys: { mac: [], other: [] },
78
+ run: (std, _invocation, params) => {
79
+ const file = canvasDrawioFile(std);
80
+ if (!file)
81
+ return;
82
+ const deliver = params?.deliver;
83
+ if (typeof deliver === 'function')
84
+ deliver(file);
85
+ else
86
+ downloadBlob(file.blob, file.filename);
87
+ },
88
+ };
89
+ export const canvasDrawioExportCommands = [
90
+ exportDrawio,
91
+ ];
@@ -0,0 +1,3 @@
1
+ export { CANVAS_DRAWIO_EXPORT, CANVAS_DRAWIO_FORMAT, CANVAS_INTERCHANGE, CANVAS_INTERCHANGE_OWNER, } from './capability.js';
2
+ export { canvasDrawioExportCommands, canvasDrawioFile, canvasDrawioSource, } from './command.js';
3
+ export { exportCanvasDrawio } from './writer.js';
@@ -0,0 +1,3 @@
1
+ export { CANVAS_DRAWIO_EXPORT, CANVAS_DRAWIO_FORMAT, CANVAS_INTERCHANGE, CANVAS_INTERCHANGE_OWNER, } from './capability.js';
2
+ export { canvasDrawioExportCommands, canvasDrawioFile, canvasDrawioSource, } from './command.js';
3
+ export { exportCanvasDrawio } from './writer.js';