@formicoidea/labre-core 0.50.0 → 0.52.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.
- package/dist/_pkgs/affine-block-attachment/asset-picker.d.ts +24 -0
- package/dist/_pkgs/affine-block-attachment/asset-picker.js +87 -0
- package/dist/_pkgs/affine-block-attachment/configs/slash-menu.js +3 -20
- package/dist/_pkgs/affine-block-attachment/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-attachment/index.js +1 -0
- package/dist/_pkgs/affine-block-attachment/utils.d.ts +9 -1
- package/dist/_pkgs/affine-block-attachment/utils.js +9 -0
- package/dist/_pkgs/affine-block-bookmark/adapters/markdown/markdown.js +14 -1
- package/dist/_pkgs/affine-block-bookmark/adapters/notion-html.js +5 -1
- package/dist/_pkgs/affine-block-database/adapters/markdown.js +5 -3
- package/dist/_pkgs/affine-block-embed/common/adapters/html.js +5 -3
- package/dist/_pkgs/affine-block-embed/common/adapters/markdown.js +11 -0
- package/dist/_pkgs/affine-block-frame/frame-template.d.ts +58 -0
- package/dist/_pkgs/affine-block-frame/frame-template.js +207 -0
- package/dist/_pkgs/affine-block-frame/frame-toolbar.js +19 -3
- package/dist/_pkgs/affine-block-frame/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-frame/index.js +1 -0
- package/dist/_pkgs/affine-block-frame/translations.d.ts +7 -0
- package/dist/_pkgs/affine-block-frame/translations.js +16 -1
- package/dist/_pkgs/affine-block-frame/view.js +6 -0
- package/dist/_pkgs/affine-block-image/asset-picker.d.ts +63 -0
- package/dist/_pkgs/affine-block-image/asset-picker.js +183 -0
- package/dist/_pkgs/affine-block-image/commands/insert-images.d.ts +5 -0
- package/dist/_pkgs/affine-block-image/commands/insert-images.js +8 -8
- package/dist/_pkgs/affine-block-image/components/page-image-block.d.ts +11 -0
- package/dist/_pkgs/affine-block-image/components/page-image-block.js +81 -12
- package/dist/_pkgs/affine-block-image/configs/replace-action.d.ts +9 -0
- package/dist/_pkgs/affine-block-image/configs/replace-action.js +27 -0
- package/dist/_pkgs/affine-block-image/configs/toolbar.js +6 -0
- package/dist/_pkgs/affine-block-image/crop/crop-controller.d.ts +46 -0
- package/dist/_pkgs/affine-block-image/crop/crop-controller.js +104 -0
- package/dist/_pkgs/affine-block-image/crop/crop-math.d.ts +70 -0
- package/dist/_pkgs/affine-block-image/crop/crop-math.js +141 -0
- package/dist/_pkgs/affine-block-image/crop/crop-overlay.d.ts +57 -0
- package/dist/_pkgs/affine-block-image/crop/crop-overlay.js +343 -0
- package/dist/_pkgs/affine-block-image/crop/crop-toolbar.d.ts +12 -0
- package/dist/_pkgs/affine-block-image/crop/crop-toolbar.js +78 -0
- package/dist/_pkgs/affine-block-image/crop/write-crop.d.ts +16 -0
- package/dist/_pkgs/affine-block-image/crop/write-crop.js +57 -0
- package/dist/_pkgs/affine-block-image/edgeless-clipboard-config.js +4 -1
- package/dist/_pkgs/affine-block-image/effects.js +2 -0
- package/dist/_pkgs/affine-block-image/image-block.d.ts +2 -0
- package/dist/_pkgs/affine-block-image/image-block.js +2 -0
- package/dist/_pkgs/affine-block-image/image-edgeless-block.d.ts +2 -0
- package/dist/_pkgs/affine-block-image/image-edgeless-block.js +36 -8
- package/dist/_pkgs/affine-block-image/image-resize-manager.js +15 -0
- package/dist/_pkgs/affine-block-image/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-image/index.js +1 -0
- package/dist/_pkgs/affine-block-image/translations.d.ts +15 -0
- package/dist/_pkgs/affine-block-image/translations.js +43 -0
- package/dist/_pkgs/affine-block-image/utils.d.ts +13 -0
- package/dist/_pkgs/affine-block-image/utils.js +10 -1
- package/dist/_pkgs/affine-block-root/clipboard/page-clipboard.js +5 -0
- package/dist/_pkgs/affine-block-root/commands/page-export-commands.d.ts +2 -0
- package/dist/_pkgs/affine-block-root/commands/page-export-commands.js +71 -0
- package/dist/_pkgs/affine-block-root/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-root/index.js +1 -0
- package/dist/_pkgs/affine-block-root/view.js +8 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/capability.d.ts +30 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/capability.js +44 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/colors.d.ts +26 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/colors.js +82 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/command.d.ts +18 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/command.js +91 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/index.d.ts +3 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/index.js +3 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/writer.d.ts +50 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/writer.js +732 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/draw-image-block.d.ts +12 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/draw-image-block.js +15 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +7 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.d.ts +7 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.js +60 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.d.ts +2 -2
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.js +2 -2
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/marker-version.d.ts +6 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/marker-version.js +8 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.d.ts +28 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +66 -6
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.d.ts +2 -7
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.js +2 -6
- package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +2 -0
- package/dist/_pkgs/affine-block-surface/extensions/index.js +2 -0
- package/dist/_pkgs/affine-block-surface/extensions/interchange-export.d.ts +84 -0
- package/dist/_pkgs/affine-block-surface/extensions/interchange-export.js +150 -0
- package/dist/_pkgs/affine-block-surface/extensions/interchange-import.js +24 -2
- package/dist/_pkgs/affine-block-surface/extensions/interchange.d.ts +23 -2
- package/dist/_pkgs/affine-block-surface/extensions/interchange.js +4 -1
- package/dist/_pkgs/affine-block-surface/extensions/legend-role.d.ts +18 -0
- package/dist/_pkgs/affine-block-surface/extensions/legend-role.js +20 -0
- package/dist/_pkgs/affine-block-surface/extensions/legend.d.ts +2 -19
- package/dist/_pkgs/affine-block-surface/extensions/legend.js +2 -18
- package/dist/_pkgs/affine-block-surface/extensions/svg-sanitize.d.ts +67 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sanitize.js +235 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch-translations.d.ts +1 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch-translations.js +9 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.d.ts +17 -13
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.js +52 -80
- package/dist/_pkgs/affine-block-surface/extensions/xml-element.d.ts +98 -0
- package/dist/_pkgs/affine-block-surface/extensions/xml-element.js +261 -0
- package/dist/_pkgs/affine-block-surface/extensions/xml-reader.d.ts +238 -0
- package/dist/_pkgs/affine-block-surface/extensions/xml-reader.js +570 -0
- package/dist/_pkgs/affine-block-surface/framework-background/def.js +1 -1
- package/dist/_pkgs/affine-block-surface/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-surface/index.js +1 -0
- package/dist/_pkgs/affine-block-surface/interchange-headless.d.ts +29 -0
- package/dist/_pkgs/affine-block-surface/interchange-headless.js +32 -0
- package/dist/_pkgs/affine-block-surface/view.js +22 -2
- package/dist/_pkgs/affine-block-table/adapters/utils.js +24 -1
- package/dist/_pkgs/affine-gfx-note/toolbar/note-menu.js +5 -8
- package/dist/_pkgs/affine-gfx-template/contribute.d.ts +14 -4
- package/dist/_pkgs/affine-gfx-template/contribute.js +47 -6
- package/dist/_pkgs/affine-gfx-template/toolbar/builtin-templates.d.ts +7 -2
- package/dist/_pkgs/affine-gfx-template/toolbar/builtin-templates.js +14 -40
- package/dist/_pkgs/affine-gfx-template/toolbar/resolve-name.d.ts +1 -1
- package/dist/_pkgs/affine-gfx-template/toolbar/resolve-name.js +1 -1
- package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.d.ts +4 -4
- package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.js +9 -9
- package/dist/_pkgs/affine-gfx-template/toolbar/template-type.d.ts +2 -4
- package/dist/_pkgs/affine-gfx-template/translations.d.ts +5 -0
- package/dist/_pkgs/affine-gfx-template/translations.js +9 -0
- package/dist/_pkgs/affine-inline-footnote/adapters/markdown/inline-delta.js +6 -0
- package/dist/_pkgs/affine-inline-footnote/adapters/markdown/markdown-inline.js +7 -0
- package/dist/_pkgs/affine-inline-link/adapters/html/html-inline.js +4 -1
- package/dist/_pkgs/affine-inline-link/adapters/html/inline-delta.js +3 -1
- package/dist/_pkgs/affine-inline-link/adapters/markdown/inline-delta.js +4 -1
- package/dist/_pkgs/affine-inline-link/adapters/notion-html/html-inline.js +2 -1
- package/dist/_pkgs/affine-inline-link/link-node/affine-link.d.ts +7 -0
- package/dist/_pkgs/affine-inline-link/link-node/affine-link.js +37 -0
- package/dist/_pkgs/affine-inline-link/link-node/index.d.ts +1 -0
- package/dist/_pkgs/affine-inline-link/link-node/index.js +1 -0
- package/dist/_pkgs/affine-inline-link/link-node/propose-views.d.ts +22 -0
- package/dist/_pkgs/affine-inline-link/link-node/propose-views.js +59 -0
- package/dist/_pkgs/affine-model/blocks/image/image-crop.d.ts +48 -0
- package/dist/_pkgs/affine-model/blocks/image/image-crop.js +78 -0
- package/dist/_pkgs/affine-model/blocks/image/image-model.d.ts +6 -0
- package/dist/_pkgs/affine-model/blocks/image/image-model.js +2 -0
- package/dist/_pkgs/affine-model/blocks/image/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/blocks/image/index.js +1 -0
- package/dist/_pkgs/affine-model/consts/shape.d.ts +2 -0
- package/dist/_pkgs/affine-model/consts/shape.js +5 -0
- package/dist/_pkgs/affine-model/elements/bpmn/consts.d.ts +31 -0
- package/dist/_pkgs/affine-model/elements/bpmn/consts.js +31 -0
- package/dist/_pkgs/affine-model/elements/bpmn/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/elements/bpmn/index.js +1 -0
- package/dist/_pkgs/affine-model/elements/bpmn/pool.d.ts +0 -25
- package/dist/_pkgs/affine-model/elements/bpmn/pool.js +1 -25
- package/dist/_pkgs/affine-model/elements/shape/shape.d.ts +0 -2
- package/dist/_pkgs/affine-model/elements/shape/shape.js +1 -2
- package/dist/_pkgs/affine-model/elements/uml/consts.d.ts +133 -0
- package/dist/_pkgs/affine-model/elements/uml/consts.js +107 -0
- package/dist/_pkgs/affine-model/elements/uml/diagram.d.ts +1 -79
- package/dist/_pkgs/affine-model/elements/uml/diagram.js +1 -53
- package/dist/_pkgs/affine-model/elements/uml/fragment.d.ts +0 -15
- package/dist/_pkgs/affine-model/elements/uml/fragment.js +1 -15
- package/dist/_pkgs/affine-model/elements/uml/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/elements/uml/index.js +1 -0
- package/dist/_pkgs/affine-model/elements/uml/partition.d.ts +0 -20
- package/dist/_pkgs/affine-model/elements/uml/partition.js +1 -20
- package/dist/_pkgs/affine-model/elements/uml/region.d.ts +0 -11
- package/dist/_pkgs/affine-model/elements/uml/region.js +1 -11
- package/dist/_pkgs/affine-model/headless.d.ts +19 -0
- package/dist/_pkgs/affine-model/headless.js +19 -0
- package/dist/_pkgs/affine-shared/headless.d.ts +10 -0
- package/dist/_pkgs/affine-shared/headless.js +10 -0
- package/dist/_pkgs/affine-shared/services/asset-picker-service.d.ts +63 -0
- package/dist/_pkgs/affine-shared/services/asset-picker-service.js +20 -0
- package/dist/_pkgs/affine-shared/services/frame-template-service.d.ts +83 -0
- package/dist/_pkgs/affine-shared/services/frame-template-service.js +17 -0
- package/dist/_pkgs/affine-shared/services/index.d.ts +3 -0
- package/dist/_pkgs/affine-shared/services/index.js +3 -0
- package/dist/_pkgs/affine-shared/services/thread-marks-service.d.ts +69 -0
- package/dist/_pkgs/affine-shared/services/thread-marks-service.js +20 -0
- package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +6 -0
- package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +10 -0
- package/dist/_pkgs/affine-widget-drag-handle/watchers/drag-event-watcher.js +8 -3
- package/dist/_pkgs/affine-widget-keyboard-toolbar/config.js +4 -16
- package/dist/_pkgs/affine-widget-linked-doc/transformers/html.d.ts +7 -0
- package/dist/_pkgs/affine-widget-linked-doc/transformers/html.js +25 -24
- package/dist/_pkgs/affine-widget-linked-doc/transformers/index.d.ts +1 -1
- package/dist/_pkgs/affine-widget-linked-doc/transformers/markdown.d.ts +7 -0
- package/dist/_pkgs/affine-widget-linked-doc/transformers/markdown.js +26 -25
- package/dist/_pkgs/affine-widget-linked-doc/transformers/utils.d.ts +23 -0
- package/dist/_pkgs/affine-widget-linked-doc/transformers/utils.js +14 -0
- package/dist/_pkgs/affine-widget-thread-marks/effects.d.ts +1 -0
- package/dist/_pkgs/affine-widget-thread-marks/effects.js +4 -0
- package/dist/_pkgs/affine-widget-thread-marks/excerpt.d.ts +19 -0
- package/dist/_pkgs/affine-widget-thread-marks/excerpt.js +68 -0
- package/dist/_pkgs/affine-widget-thread-marks/index.d.ts +5 -0
- package/dist/_pkgs/affine-widget-thread-marks/index.js +8 -0
- package/dist/_pkgs/affine-widget-thread-marks/toolbar.d.ts +49 -0
- package/dist/_pkgs/affine-widget-thread-marks/toolbar.js +108 -0
- package/dist/_pkgs/affine-widget-thread-marks/translations.d.ts +9 -0
- package/dist/_pkgs/affine-widget-thread-marks/translations.js +11 -0
- package/dist/_pkgs/affine-widget-thread-marks/view.d.ts +12 -0
- package/dist/_pkgs/affine-widget-thread-marks/view.js +25 -0
- package/dist/_pkgs/affine-widget-thread-marks/widget.d.ts +51 -0
- package/dist/_pkgs/affine-widget-thread-marks/widget.js +214 -0
- package/dist/commands.js +5 -2
- package/dist/extensions/view.js +2 -0
- package/dist/host-panels.d.ts +24 -1
- package/dist/host-panels.js +61 -10
- package/dist/interchange.d.ts +1 -0
- package/dist/interchange.js +1 -0
- package/dist/model/headless.d.ts +1 -0
- package/dist/model/headless.js +1 -0
- package/dist/shared/headless.d.ts +1 -0
- package/dist/shared/headless.js +1 -0
- package/dist/translations.js +10 -1
- 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,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';
|