@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
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
import { unsafeCSSVarV2 } from '../../affine-shared/theme/index.js';
|
|
36
|
+
import { WithDisposable } from '../../global/lit/index.js';
|
|
37
|
+
import { css, html, LitElement } from 'lit';
|
|
38
|
+
import { property, state } from 'lit/decorators.js';
|
|
39
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
40
|
+
import { styleMap } from 'lit/directives/style-map.js';
|
|
41
|
+
import { moveCrop, resizeCrop, WHOLE_IMAGE, } from './crop-math.js';
|
|
42
|
+
const CORNERS = ['nw', 'ne', 'sw', 'se'];
|
|
43
|
+
const rectStyle = (rect) => styleMap({
|
|
44
|
+
left: `${rect.x * 100}%`,
|
|
45
|
+
top: `${rect.y * 100}%`,
|
|
46
|
+
width: `${rect.w * 100}%`,
|
|
47
|
+
height: `${rect.h * 100}%`,
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* The crop frame (ADR 0037): the WHOLE source, laid over the block at the
|
|
51
|
+
* place it would occupy uncropped (the parent sizes this element with
|
|
52
|
+
* `wholeImageFrame`), dimmed outside the window being edited.
|
|
53
|
+
*
|
|
54
|
+
* Dragging the window moves it, dragging a corner resizes it, the ratio held
|
|
55
|
+
* when `ratio` is set. The draft lives here while the pointer is down; the
|
|
56
|
+
* release hands it to `onCommit` once — one gesture, one write, one undo
|
|
57
|
+
* step, decided by the caller (`writeImageCrop`).
|
|
58
|
+
*
|
|
59
|
+
* Pointer events never reach the editor while the frame is open: a press on
|
|
60
|
+
* the frame would otherwise start a canvas drag or a page selection. Escape,
|
|
61
|
+
* Enter or a press anywhere else calls `onExit`.
|
|
62
|
+
*/
|
|
63
|
+
let ImageCropOverlay = (() => {
|
|
64
|
+
let _classSuper = WithDisposable(LitElement);
|
|
65
|
+
let _src_decorators;
|
|
66
|
+
let _src_initializers = [];
|
|
67
|
+
let _src_extraInitializers = [];
|
|
68
|
+
let _crop_decorators;
|
|
69
|
+
let _crop_initializers = [];
|
|
70
|
+
let _crop_extraInitializers = [];
|
|
71
|
+
let _ratio_decorators;
|
|
72
|
+
let _ratio_initializers = [];
|
|
73
|
+
let _ratio_extraInitializers = [];
|
|
74
|
+
let _rotate_decorators;
|
|
75
|
+
let _rotate_initializers = [];
|
|
76
|
+
let _rotate_extraInitializers = [];
|
|
77
|
+
let _onCommit_decorators;
|
|
78
|
+
let _onCommit_initializers = [];
|
|
79
|
+
let _onCommit_extraInitializers = [];
|
|
80
|
+
let _onExit_decorators;
|
|
81
|
+
let _onExit_initializers = [];
|
|
82
|
+
let _onExit_extraInitializers = [];
|
|
83
|
+
let _draft_decorators;
|
|
84
|
+
let _draft_initializers = [];
|
|
85
|
+
let _draft_extraInitializers = [];
|
|
86
|
+
return class ImageCropOverlay extends _classSuper {
|
|
87
|
+
constructor() {
|
|
88
|
+
super(...arguments);
|
|
89
|
+
this.#src_accessor_storage = __runInitializers(this, _src_initializers, '');
|
|
90
|
+
this.#crop_accessor_storage = (__runInitializers(this, _src_extraInitializers), __runInitializers(this, _crop_initializers, WHOLE_IMAGE));
|
|
91
|
+
this.#ratio_accessor_storage = (__runInitializers(this, _crop_extraInitializers), __runInitializers(this, _ratio_initializers, null));
|
|
92
|
+
this.#rotate_accessor_storage = (__runInitializers(this, _ratio_extraInitializers), __runInitializers(this, _rotate_initializers, 0));
|
|
93
|
+
this.#onCommit_accessor_storage = (__runInitializers(this, _rotate_extraInitializers), __runInitializers(this, _onCommit_initializers, () => { }));
|
|
94
|
+
this.#onExit_accessor_storage = (__runInitializers(this, _onCommit_extraInitializers), __runInitializers(this, _onExit_initializers, () => { }));
|
|
95
|
+
this.#draft_accessor_storage = (__runInitializers(this, _onExit_extraInitializers), __runInitializers(this, _draft_initializers, WHOLE_IMAGE));
|
|
96
|
+
this._dragging = (__runInitializers(this, _draft_extraInitializers), false);
|
|
97
|
+
/** Removes the listeners of the gesture in progress, if any. */
|
|
98
|
+
this._releaseGesture = null;
|
|
99
|
+
this._stop = (event) => event.stopPropagation();
|
|
100
|
+
this._onOutsidePointer = (event) => {
|
|
101
|
+
if (event.composedPath().includes(this))
|
|
102
|
+
return;
|
|
103
|
+
this.onExit();
|
|
104
|
+
};
|
|
105
|
+
this._onKeydown = (event) => {
|
|
106
|
+
if (event.key !== 'Escape' && event.key !== 'Enter')
|
|
107
|
+
return;
|
|
108
|
+
event.preventDefault();
|
|
109
|
+
event.stopPropagation();
|
|
110
|
+
this.onExit();
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
static {
|
|
114
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
115
|
+
_src_decorators = [property({ attribute: false })];
|
|
116
|
+
_crop_decorators = [property({ attribute: false })];
|
|
117
|
+
_ratio_decorators = [property({ attribute: false })];
|
|
118
|
+
_rotate_decorators = [property({ attribute: false })];
|
|
119
|
+
_onCommit_decorators = [property({ attribute: false })];
|
|
120
|
+
_onExit_decorators = [property({ attribute: false })];
|
|
121
|
+
_draft_decorators = [state()];
|
|
122
|
+
__esDecorate(this, null, _src_decorators, { kind: "accessor", name: "src", static: false, private: false, access: { has: obj => "src" in obj, get: obj => obj.src, set: (obj, value) => { obj.src = value; } }, metadata: _metadata }, _src_initializers, _src_extraInitializers);
|
|
123
|
+
__esDecorate(this, null, _crop_decorators, { kind: "accessor", name: "crop", static: false, private: false, access: { has: obj => "crop" in obj, get: obj => obj.crop, set: (obj, value) => { obj.crop = value; } }, metadata: _metadata }, _crop_initializers, _crop_extraInitializers);
|
|
124
|
+
__esDecorate(this, null, _ratio_decorators, { kind: "accessor", name: "ratio", static: false, private: false, access: { has: obj => "ratio" in obj, get: obj => obj.ratio, set: (obj, value) => { obj.ratio = value; } }, metadata: _metadata }, _ratio_initializers, _ratio_extraInitializers);
|
|
125
|
+
__esDecorate(this, null, _rotate_decorators, { kind: "accessor", name: "rotate", static: false, private: false, access: { has: obj => "rotate" in obj, get: obj => obj.rotate, set: (obj, value) => { obj.rotate = value; } }, metadata: _metadata }, _rotate_initializers, _rotate_extraInitializers);
|
|
126
|
+
__esDecorate(this, null, _onCommit_decorators, { kind: "accessor", name: "onCommit", static: false, private: false, access: { has: obj => "onCommit" in obj, get: obj => obj.onCommit, set: (obj, value) => { obj.onCommit = value; } }, metadata: _metadata }, _onCommit_initializers, _onCommit_extraInitializers);
|
|
127
|
+
__esDecorate(this, null, _onExit_decorators, { kind: "accessor", name: "onExit", static: false, private: false, access: { has: obj => "onExit" in obj, get: obj => obj.onExit, set: (obj, value) => { obj.onExit = value; } }, metadata: _metadata }, _onExit_initializers, _onExit_extraInitializers);
|
|
128
|
+
__esDecorate(this, null, _draft_decorators, { kind: "accessor", name: "draft", static: false, private: false, access: { has: obj => "draft" in obj, get: obj => obj.draft, set: (obj, value) => { obj.draft = value; } }, metadata: _metadata }, _draft_initializers, _draft_extraInitializers);
|
|
129
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
130
|
+
}
|
|
131
|
+
static { this.styles = css `
|
|
132
|
+
:host {
|
|
133
|
+
position: absolute;
|
|
134
|
+
z-index: 1;
|
|
135
|
+
display: block;
|
|
136
|
+
touch-action: none;
|
|
137
|
+
user-select: none;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.clip {
|
|
141
|
+
position: absolute;
|
|
142
|
+
inset: 0;
|
|
143
|
+
overflow: hidden;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
img {
|
|
147
|
+
display: block;
|
|
148
|
+
width: 100%;
|
|
149
|
+
height: 100%;
|
|
150
|
+
pointer-events: none;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.shade {
|
|
154
|
+
position: absolute;
|
|
155
|
+
box-shadow: 0 0 0 100000px
|
|
156
|
+
${unsafeCSSVarV2('layer/background/modal', 'rgba(0, 0, 0, 0.7)')};
|
|
157
|
+
pointer-events: none;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.window {
|
|
161
|
+
position: absolute;
|
|
162
|
+
box-sizing: border-box;
|
|
163
|
+
border: 1px solid ${unsafeCSSVarV2('button/primary')};
|
|
164
|
+
cursor: move;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.handle {
|
|
168
|
+
position: absolute;
|
|
169
|
+
width: 12px;
|
|
170
|
+
height: 12px;
|
|
171
|
+
box-sizing: border-box;
|
|
172
|
+
border: 1px solid ${unsafeCSSVarV2('button/primary')};
|
|
173
|
+
border-radius: 2px;
|
|
174
|
+
background: ${unsafeCSSVarV2('layer/pureWhite')};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* A wider grip than the square drawn, for a finger. */
|
|
178
|
+
.handle::before {
|
|
179
|
+
content: '';
|
|
180
|
+
position: absolute;
|
|
181
|
+
inset: -10px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.handle[data-corner='nw'] {
|
|
185
|
+
left: -6px;
|
|
186
|
+
top: -6px;
|
|
187
|
+
cursor: nwse-resize;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.handle[data-corner='ne'] {
|
|
191
|
+
right: -6px;
|
|
192
|
+
top: -6px;
|
|
193
|
+
cursor: nesw-resize;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.handle[data-corner='sw'] {
|
|
197
|
+
left: -6px;
|
|
198
|
+
bottom: -6px;
|
|
199
|
+
cursor: nesw-resize;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.handle[data-corner='se'] {
|
|
203
|
+
right: -6px;
|
|
204
|
+
bottom: -6px;
|
|
205
|
+
cursor: nwse-resize;
|
|
206
|
+
}
|
|
207
|
+
`; }
|
|
208
|
+
#src_accessor_storage;
|
|
209
|
+
get src() { return this.#src_accessor_storage; }
|
|
210
|
+
set src(value) { this.#src_accessor_storage = value; }
|
|
211
|
+
#crop_accessor_storage;
|
|
212
|
+
/** The stored crop the frame opens on; the whole image when uncropped. */
|
|
213
|
+
get crop() { return this.#crop_accessor_storage; }
|
|
214
|
+
set crop(value) { this.#crop_accessor_storage = value; }
|
|
215
|
+
#ratio_accessor_storage;
|
|
216
|
+
/** Normalised `w / h` to hold while resizing, `null` for a free crop. */
|
|
217
|
+
get ratio() { return this.#ratio_accessor_storage; }
|
|
218
|
+
set ratio(value) { this.#ratio_accessor_storage = value; }
|
|
219
|
+
#rotate_accessor_storage;
|
|
220
|
+
/** The block's rotation in degrees (canvas only), for pointer deltas. */
|
|
221
|
+
get rotate() { return this.#rotate_accessor_storage; }
|
|
222
|
+
set rotate(value) { this.#rotate_accessor_storage = value; }
|
|
223
|
+
#onCommit_accessor_storage;
|
|
224
|
+
get onCommit() { return this.#onCommit_accessor_storage; }
|
|
225
|
+
set onCommit(value) { this.#onCommit_accessor_storage = value; }
|
|
226
|
+
#onExit_accessor_storage;
|
|
227
|
+
get onExit() { return this.#onExit_accessor_storage; }
|
|
228
|
+
set onExit(value) { this.#onExit_accessor_storage = value; }
|
|
229
|
+
#draft_accessor_storage;
|
|
230
|
+
get draft() { return this.#draft_accessor_storage; }
|
|
231
|
+
set draft(value) { this.#draft_accessor_storage = value; }
|
|
232
|
+
/**
|
|
233
|
+
* The document-wide listeners (a press elsewhere, Escape, Enter) live only
|
|
234
|
+
* as long as this element: the frame is rendered while it is open and
|
|
235
|
+
* removed when it closes, which disposes them.
|
|
236
|
+
*/
|
|
237
|
+
connectedCallback() {
|
|
238
|
+
super.connectedCallback();
|
|
239
|
+
this.disposables.add(() => this._releaseGesture?.());
|
|
240
|
+
this.disposables.addFromEvent(this, 'pointerdown', this._stop);
|
|
241
|
+
this.disposables.addFromEvent(this, 'click', this._stop);
|
|
242
|
+
this.disposables.addFromEvent(this, 'dblclick', this._stop);
|
|
243
|
+
this.disposables.addFromEvent(document, 'pointerdown', this._onOutsidePointer, true);
|
|
244
|
+
this.disposables.addFromEvent(document, 'keydown', this._onKeydown, true);
|
|
245
|
+
}
|
|
246
|
+
willUpdate(changed) {
|
|
247
|
+
if (changed.has('crop') && !this._dragging)
|
|
248
|
+
this.draft = this.crop;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Client pixels per layout pixel, read from the rendered box: the canvas
|
|
252
|
+
* zoom and any CSS scale, without asking the viewport. The bounding box of
|
|
253
|
+
* a rotated element is wider than the element, hence the trigonometry.
|
|
254
|
+
*/
|
|
255
|
+
_geometry() {
|
|
256
|
+
const width = this.offsetWidth;
|
|
257
|
+
const height = this.offsetHeight;
|
|
258
|
+
const t = (this.rotate * Math.PI) / 180;
|
|
259
|
+
const cos = Math.cos(t);
|
|
260
|
+
const sin = Math.sin(t);
|
|
261
|
+
const span = width * Math.abs(cos) + height * Math.abs(sin);
|
|
262
|
+
const scale = span > 0 ? this.getBoundingClientRect().width / span : 1;
|
|
263
|
+
return { width, height, cos, sin, scale: scale || 1 };
|
|
264
|
+
}
|
|
265
|
+
_startGesture(event, grip) {
|
|
266
|
+
if (event.button !== 0)
|
|
267
|
+
return;
|
|
268
|
+
event.preventDefault();
|
|
269
|
+
event.stopPropagation();
|
|
270
|
+
const start = this.draft;
|
|
271
|
+
const originX = event.clientX;
|
|
272
|
+
const originY = event.clientY;
|
|
273
|
+
const { width, height, cos, sin, scale } = this._geometry();
|
|
274
|
+
if (width <= 0 || height <= 0)
|
|
275
|
+
return;
|
|
276
|
+
this._dragging = true;
|
|
277
|
+
const onMove = (move) => {
|
|
278
|
+
move.preventDefault();
|
|
279
|
+
move.stopPropagation();
|
|
280
|
+
const cdx = move.clientX - originX;
|
|
281
|
+
const cdy = move.clientY - originY;
|
|
282
|
+
const dx = (cdx * cos + cdy * sin) / scale / width;
|
|
283
|
+
const dy = (-cdx * sin + cdy * cos) / scale / height;
|
|
284
|
+
this.draft =
|
|
285
|
+
grip === 'move'
|
|
286
|
+
? moveCrop(start, dx, dy)
|
|
287
|
+
: resizeCrop(start, grip, dx, dy, this.ratio);
|
|
288
|
+
};
|
|
289
|
+
const finish = (end, commit) => {
|
|
290
|
+
end.preventDefault();
|
|
291
|
+
end.stopPropagation();
|
|
292
|
+
this._releaseGesture?.();
|
|
293
|
+
this._dragging = false;
|
|
294
|
+
if (commit) {
|
|
295
|
+
this.onCommit(this.draft);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
this.draft = this.crop;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
const onUp = (end) => finish(end, true);
|
|
302
|
+
const onCancel = (end) => finish(end, false);
|
|
303
|
+
this._releaseGesture?.();
|
|
304
|
+
window.addEventListener('pointermove', onMove, true);
|
|
305
|
+
window.addEventListener('pointerup', onUp, true);
|
|
306
|
+
window.addEventListener('pointercancel', onCancel, true);
|
|
307
|
+
this._releaseGesture = () => {
|
|
308
|
+
window.removeEventListener('pointermove', onMove, true);
|
|
309
|
+
window.removeEventListener('pointerup', onUp, true);
|
|
310
|
+
window.removeEventListener('pointercancel', onCancel, true);
|
|
311
|
+
this._releaseGesture = null;
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
render() {
|
|
315
|
+
const draft = this.draft;
|
|
316
|
+
return html `
|
|
317
|
+
<div class="clip">
|
|
318
|
+
<img src=${this.src} draggable="false" alt="" />
|
|
319
|
+
<div class="shade" style=${rectStyle(draft)}></div>
|
|
320
|
+
</div>
|
|
321
|
+
<div
|
|
322
|
+
class="window"
|
|
323
|
+
data-testid="image-crop-window"
|
|
324
|
+
style=${rectStyle(draft)}
|
|
325
|
+
@pointerdown=${(event) => this._startGesture(event, 'move')}
|
|
326
|
+
>
|
|
327
|
+
${repeat(CORNERS, corner => corner, corner => html `
|
|
328
|
+
<div
|
|
329
|
+
class="handle"
|
|
330
|
+
data-corner=${corner}
|
|
331
|
+
data-testid=${`image-crop-handle-${corner}`}
|
|
332
|
+
@pointerdown=${(event) => {
|
|
333
|
+
event.stopPropagation();
|
|
334
|
+
this._startGesture(event, corner);
|
|
335
|
+
}}
|
|
336
|
+
></div>
|
|
337
|
+
`)}
|
|
338
|
+
</div>
|
|
339
|
+
`;
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
})();
|
|
343
|
+
export { ImageCropOverlay };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ToolbarAction, type ToolbarContext } from '../../affine-shared/services/index.js';
|
|
2
|
+
import type { ImageCropController } from './crop-controller.js';
|
|
3
|
+
/**
|
|
4
|
+
* « Rogner » in the image toolbar (ADR 0037), page and canvas alike: the
|
|
5
|
+
* toolbar's own `editor-menu-button` of `editor-menu-action`s, nothing drawn
|
|
6
|
+
* anew. Hidden on a readonly page and until the picture has loaded — a preset
|
|
7
|
+
* needs the source's size.
|
|
8
|
+
*/
|
|
9
|
+
export declare function imageCropToolbarAction(blockOf: (ctx: ToolbarContext) => {
|
|
10
|
+
cropController: ImageCropController;
|
|
11
|
+
blobUrl?: string | null;
|
|
12
|
+
} | null): ToolbarAction;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { EditorChevronDown } from '../../affine-components/toolbar/index.js';
|
|
2
|
+
import { translateKey, } from '../../affine-shared/services/index.js';
|
|
3
|
+
import { CropIcon } from '@blocksuite/icons/lit';
|
|
4
|
+
import { html, nothing } from 'lit';
|
|
5
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
6
|
+
import { IMAGE_TOOLBAR_CROP, IMAGE_TOOLBAR_CROP_1_1, IMAGE_TOOLBAR_CROP_4_3, IMAGE_TOOLBAR_CROP_16_9, IMAGE_TOOLBAR_CROP_FREE, IMAGE_TOOLBAR_CROP_ORIGINAL, } from '../translations.js';
|
|
7
|
+
const MASK_ENTRIES = [
|
|
8
|
+
['free', IMAGE_TOOLBAR_CROP_FREE],
|
|
9
|
+
['16:9', IMAGE_TOOLBAR_CROP_16_9],
|
|
10
|
+
['4:3', IMAGE_TOOLBAR_CROP_4_3],
|
|
11
|
+
['1:1', IMAGE_TOOLBAR_CROP_1_1],
|
|
12
|
+
];
|
|
13
|
+
const testIdOf = (mask) => `image-crop-${mask.replace(':', '-')}`;
|
|
14
|
+
/**
|
|
15
|
+
* « Rogner » in the image toolbar (ADR 0037), page and canvas alike: the
|
|
16
|
+
* toolbar's own `editor-menu-button` of `editor-menu-action`s, nothing drawn
|
|
17
|
+
* anew. Hidden on a readonly page and until the picture has loaded — a preset
|
|
18
|
+
* needs the source's size.
|
|
19
|
+
*/
|
|
20
|
+
export function imageCropToolbarAction(blockOf) {
|
|
21
|
+
return {
|
|
22
|
+
id: 'b.crop',
|
|
23
|
+
when: ctx => !ctx.readonly,
|
|
24
|
+
content(ctx) {
|
|
25
|
+
const block = blockOf(ctx);
|
|
26
|
+
if (!block?.blobUrl)
|
|
27
|
+
return null;
|
|
28
|
+
const controller = block.cropController;
|
|
29
|
+
const crop = controller.crop$.value;
|
|
30
|
+
const current = crop ? (crop.mask ?? 'free') : null;
|
|
31
|
+
const label = translateKey(ctx.std, ...IMAGE_TOOLBAR_CROP);
|
|
32
|
+
const original = translateKey(ctx.std, ...IMAGE_TOOLBAR_CROP_ORIGINAL);
|
|
33
|
+
return html `
|
|
34
|
+
<editor-menu-button
|
|
35
|
+
.contentPadding="${'8px'}"
|
|
36
|
+
.button=${html `
|
|
37
|
+
<editor-icon-button
|
|
38
|
+
aria-label=${label}
|
|
39
|
+
data-testid="image-crop-button"
|
|
40
|
+
.tooltip=${label}
|
|
41
|
+
>
|
|
42
|
+
${CropIcon()} ${EditorChevronDown}
|
|
43
|
+
</editor-icon-button>
|
|
44
|
+
`}
|
|
45
|
+
>
|
|
46
|
+
<div data-size="small" data-orientation="vertical">
|
|
47
|
+
${repeat(MASK_ENTRIES, ([mask]) => mask, ([mask, wording]) => {
|
|
48
|
+
const word = translateKey(ctx.std, ...wording);
|
|
49
|
+
return html `
|
|
50
|
+
<editor-menu-action
|
|
51
|
+
aria-label=${word}
|
|
52
|
+
data-testid=${testIdOf(mask)}
|
|
53
|
+
?data-selected=${current === mask}
|
|
54
|
+
@click=${() => controller.choose(mask)}
|
|
55
|
+
>
|
|
56
|
+
<span class="label">${word}</span>
|
|
57
|
+
</editor-menu-action>
|
|
58
|
+
`;
|
|
59
|
+
})}
|
|
60
|
+
${crop
|
|
61
|
+
? html `
|
|
62
|
+
<editor-menu-action
|
|
63
|
+
aria-label=${original}
|
|
64
|
+
data-testid="image-crop-original"
|
|
65
|
+
@click=${() => {
|
|
66
|
+
controller.restoreOriginal();
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
<span class="label">${original}</span>
|
|
70
|
+
</editor-menu-action>
|
|
71
|
+
`
|
|
72
|
+
: nothing}
|
|
73
|
+
</div>
|
|
74
|
+
</editor-menu-button>
|
|
75
|
+
`;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ImageBlockModel, type ImageCropMask } from '../../affine-model/index.js';
|
|
2
|
+
import { type CropRect } from './crop-math.js';
|
|
3
|
+
/**
|
|
4
|
+
* Record one crop gesture (ADR 0037). Answers whether anything was written.
|
|
5
|
+
*
|
|
6
|
+
* - Nothing on a readonly store, nothing when the crop (mask included) is
|
|
7
|
+
* already the one asked for: an unchanged write is an empty undo step.
|
|
8
|
+
* - One gesture, one undo step: `captureSync` then a single transaction.
|
|
9
|
+
* - The whole image, or `undefined`, REMOVES the key; a full rectangle is
|
|
10
|
+
* never stored.
|
|
11
|
+
* - On the canvas the box is the visible part, so `xywh` moves in the same
|
|
12
|
+
* transaction: the picture keeps its scale and position. On a page,
|
|
13
|
+
* `width`/`height` stay those of the whole picture and nothing else moves.
|
|
14
|
+
* - `sourceId` is never touched: the bytes do not change.
|
|
15
|
+
*/
|
|
16
|
+
export declare function writeImageCrop(model: ImageBlockModel, next: CropRect | undefined, mask: ImageCropMask, onCanvas: boolean): boolean;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isWholeImage, readImageCrop, } from '../../affine-model/index.js';
|
|
2
|
+
import { Bound } from '../../global/gfx/index.js';
|
|
3
|
+
import { cropBoundFor, sameCropRect, WHOLE_IMAGE, } from './crop-math.js';
|
|
4
|
+
/**
|
|
5
|
+
* Record one crop gesture (ADR 0037). Answers whether anything was written.
|
|
6
|
+
*
|
|
7
|
+
* - Nothing on a readonly store, nothing when the crop (mask included) is
|
|
8
|
+
* already the one asked for: an unchanged write is an empty undo step.
|
|
9
|
+
* - One gesture, one undo step: `captureSync` then a single transaction.
|
|
10
|
+
* - The whole image, or `undefined`, REMOVES the key; a full rectangle is
|
|
11
|
+
* never stored.
|
|
12
|
+
* - On the canvas the box is the visible part, so `xywh` moves in the same
|
|
13
|
+
* transaction: the picture keeps its scale and position. On a page,
|
|
14
|
+
* `width`/`height` stay those of the whole picture and nothing else moves.
|
|
15
|
+
* - `sourceId` is never touched: the bytes do not change.
|
|
16
|
+
*/
|
|
17
|
+
export function writeImageCrop(model, next, mask, onCanvas) {
|
|
18
|
+
const store = model.store;
|
|
19
|
+
if (store.readonly)
|
|
20
|
+
return false;
|
|
21
|
+
const current = readImageCrop(model.props.crop);
|
|
22
|
+
const target = next && !isWholeImage(next)
|
|
23
|
+
? {
|
|
24
|
+
x: next.x,
|
|
25
|
+
y: next.y,
|
|
26
|
+
w: next.w,
|
|
27
|
+
h: next.h,
|
|
28
|
+
...(mask === 'free' ? {} : { mask }),
|
|
29
|
+
}
|
|
30
|
+
: undefined;
|
|
31
|
+
if (!current && !target)
|
|
32
|
+
return false;
|
|
33
|
+
if (current &&
|
|
34
|
+
target &&
|
|
35
|
+
sameCropRect(current, target) &&
|
|
36
|
+
(current.mask ?? 'free') === (target.mask ?? 'free')) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const props = {};
|
|
40
|
+
if (onCanvas) {
|
|
41
|
+
const bound = Bound.deserialize(model.xywh);
|
|
42
|
+
if (bound.w > 0 && bound.h > 0) {
|
|
43
|
+
const { x, y, w, h } = cropBoundFor(bound, model.props.rotate ?? 0, current ?? WHOLE_IMAGE, target ?? WHOLE_IMAGE);
|
|
44
|
+
props.xywh = new Bound(x, y, w, h).serialize();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (target)
|
|
48
|
+
props.crop = target;
|
|
49
|
+
store.captureSync();
|
|
50
|
+
store.transact(() => {
|
|
51
|
+
if (Object.keys(props).length > 0)
|
|
52
|
+
store.updateBlock(model, props);
|
|
53
|
+
if (!target)
|
|
54
|
+
delete model.props.crop;
|
|
55
|
+
});
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
@@ -3,7 +3,7 @@ import {} from '../store/index.js';
|
|
|
3
3
|
export class EdgelessClipboardImageConfig extends EdgelessClipboardConfig {
|
|
4
4
|
static { this.key = 'affine:image'; }
|
|
5
5
|
async createBlock(image) {
|
|
6
|
-
const { xywh, rotate, sourceId, size, width, height, caption } = image.props;
|
|
6
|
+
const { xywh, rotate, sourceId, size, width, height, caption, crop } = image.props;
|
|
7
7
|
if (!this.surface)
|
|
8
8
|
return null;
|
|
9
9
|
if (!(await this.std.workspace.blobSync.get(sourceId))) {
|
|
@@ -17,6 +17,9 @@ export class EdgelessClipboardImageConfig extends EdgelessClipboardConfig {
|
|
|
17
17
|
size,
|
|
18
18
|
width,
|
|
19
19
|
height,
|
|
20
|
+
// The box above is the cropped one: without its crop the copy would
|
|
21
|
+
// stretch the whole picture into it (ADR 0037).
|
|
22
|
+
crop,
|
|
20
23
|
}, this.surface.model.id);
|
|
21
24
|
}
|
|
22
25
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ImageBlockFallbackCard } from './components/image-block-fallback.js';
|
|
2
2
|
import { ImageBlockPageComponent } from './components/page-image-block.js';
|
|
3
|
+
import { ImageCropOverlay } from './crop/crop-overlay.js';
|
|
3
4
|
import { ImageBlockComponent } from './image-block.js';
|
|
4
5
|
import { ImageEdgelessBlockComponent } from './image-edgeless-block.js';
|
|
5
6
|
import { ImageEdgelessPlaceholderBlockComponent } from './preview-image/edgeless.js';
|
|
@@ -9,6 +10,7 @@ export function effects() {
|
|
|
9
10
|
customElements.define('affine-edgeless-image', ImageEdgelessBlockComponent);
|
|
10
11
|
customElements.define('affine-page-image', ImageBlockPageComponent);
|
|
11
12
|
customElements.define('affine-image-fallback-card', ImageBlockFallbackCard);
|
|
13
|
+
customElements.define('affine-image-crop-overlay', ImageCropOverlay);
|
|
12
14
|
customElements.define('affine-placeholder-preview-image', ImagePlaceholderBlockComponent);
|
|
13
15
|
customElements.define('affine-edgeless-placeholder-preview-image', ImageEdgelessPlaceholderBlockComponent);
|
|
14
16
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { CaptionedBlockComponent } from '../affine-components/caption/index.js';
|
|
2
2
|
import { ResourceController } from '../affine-components/resource/index.js';
|
|
3
3
|
import type { ImageBlockModel } from '../affine-model/index.js';
|
|
4
|
+
import { ImageCropController } from './crop/crop-controller.js';
|
|
4
5
|
export declare class ImageBlockComponent extends CaptionedBlockComponent<ImageBlockModel> {
|
|
5
6
|
resizeable$: import("@preact/signals-core").ReadonlySignal<boolean>;
|
|
6
7
|
resourceController: ResourceController;
|
|
8
|
+
readonly cropController: ImageCropController;
|
|
7
9
|
get blobUrl(): string | null;
|
|
8
10
|
convertToCardView: () => void;
|
|
9
11
|
copy: () => void;
|
|
@@ -49,6 +49,7 @@ import { html } from 'lit';
|
|
|
49
49
|
import { query } from 'lit/decorators.js';
|
|
50
50
|
import { styleMap } from 'lit/directives/style-map.js';
|
|
51
51
|
import { when } from 'lit/directives/when.js';
|
|
52
|
+
import { ImageCropController } from './crop/crop-controller.js';
|
|
52
53
|
import { IMAGE_LABEL } from './translations.js';
|
|
53
54
|
import { copyImageBlob, downloadImageBlob, refreshData, turnImageIntoCardView, } from './utils.js';
|
|
54
55
|
let ImageBlockComponent = (() => {
|
|
@@ -71,6 +72,7 @@ let ImageBlockComponent = (() => {
|
|
|
71
72
|
super(...arguments);
|
|
72
73
|
this.resizeable$ = computed(() => this.std.selection.value.some(selection => selection.is(ImageSelection) && selection.blockId === this.blockId));
|
|
73
74
|
this.resourceController = new ResourceController(computed(() => this.model.props.sourceId$.value), 'Image');
|
|
75
|
+
this.cropController = new ImageCropController(this, false);
|
|
74
76
|
this.convertToCardView = () => {
|
|
75
77
|
turnImageIntoCardView(this).catch(console.error);
|
|
76
78
|
};
|
|
@@ -2,9 +2,11 @@ import type { BlockCaptionEditor } from '../affine-components/caption/index.js';
|
|
|
2
2
|
import { ResourceController } from '../affine-components/resource/index.js';
|
|
3
3
|
import { type ImageBlockModel } from '../affine-model/index.js';
|
|
4
4
|
import { GfxBlockComponent } from '../std/index.js';
|
|
5
|
+
import { ImageCropController } from './crop/crop-controller.js';
|
|
5
6
|
export declare class ImageEdgelessBlockComponent extends GfxBlockComponent<ImageBlockModel> {
|
|
6
7
|
static styles: import("lit").CSSResult;
|
|
7
8
|
resourceController: ResourceController;
|
|
9
|
+
readonly cropController: ImageCropController;
|
|
8
10
|
get blobUrl(): string | null;
|
|
9
11
|
convertToCardView: () => void;
|
|
10
12
|
copy: () => void;
|
|
@@ -47,6 +47,7 @@ import { css, html } from 'lit';
|
|
|
47
47
|
import { query } from 'lit/decorators.js';
|
|
48
48
|
import { styleMap } from 'lit/directives/style-map.js';
|
|
49
49
|
import { when } from 'lit/directives/when.js';
|
|
50
|
+
import { croppedImageStyle, ImageCropController, } from './crop/crop-controller.js';
|
|
50
51
|
import { IMAGE_LABEL, IMAGE_TOAST_DOWNLOAD_FAILED } from './translations.js';
|
|
51
52
|
import { copyImageBlob, downloadImageBlob, refreshData, turnImageIntoCardView, } from './utils.js';
|
|
52
53
|
let ImageEdgelessBlockComponent = (() => {
|
|
@@ -107,6 +108,16 @@ let ImageEdgelessBlockComponent = (() => {
|
|
|
107
108
|
width: 100%;
|
|
108
109
|
height: 100%;
|
|
109
110
|
}
|
|
111
|
+
|
|
112
|
+
affine-edgeless-image .resizable-img {
|
|
113
|
+
position: relative;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
affine-edgeless-image .labre-image-crop-window {
|
|
117
|
+
position: absolute;
|
|
118
|
+
inset: 0;
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
}
|
|
110
121
|
`; }
|
|
111
122
|
get blobUrl() {
|
|
112
123
|
return this.resourceController.blobUrl$.value;
|
|
@@ -130,6 +141,9 @@ let ImageEdgelessBlockComponent = (() => {
|
|
|
130
141
|
const blobUrl = this.blobUrl;
|
|
131
142
|
const imageLabel = translateKey(this.std, ...IMAGE_LABEL);
|
|
132
143
|
const { rotate = 0, size = 0, caption = imageLabel } = this.model.props;
|
|
144
|
+
// The box is the visible part (ADR 0037): the source is drawn scaled
|
|
145
|
+
// and offset inside it, through a window that clips the rest.
|
|
146
|
+
const crop = this.cropController.crop$.value;
|
|
133
147
|
const containerStyleMap = styleMap({
|
|
134
148
|
display: 'flex',
|
|
135
149
|
position: 'relative',
|
|
@@ -153,14 +167,27 @@ let ImageEdgelessBlockComponent = (() => {
|
|
|
153
167
|
<div class="affine-image-container" style=${containerStyleMap}>
|
|
154
168
|
${when(blobUrl, () => html `
|
|
155
169
|
<div class="resizable-img">
|
|
156
|
-
|
|
157
|
-
class="
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
170
|
+
${crop
|
|
171
|
+
? html `<div class="labre-image-crop-window">
|
|
172
|
+
<img
|
|
173
|
+
class="drag-target"
|
|
174
|
+
draggable="false"
|
|
175
|
+
loading="lazy"
|
|
176
|
+
src=${blobUrl}
|
|
177
|
+
alt=${caption}
|
|
178
|
+
style=${croppedImageStyle(crop)}
|
|
179
|
+
@error=${this._handleError}
|
|
180
|
+
/>
|
|
181
|
+
</div>`
|
|
182
|
+
: html `<img
|
|
183
|
+
class="drag-target"
|
|
184
|
+
draggable="false"
|
|
185
|
+
loading="lazy"
|
|
186
|
+
src=${blobUrl}
|
|
187
|
+
alt=${caption}
|
|
188
|
+
@error=${this._handleError}
|
|
189
|
+
/>`}
|
|
190
|
+
${this.cropController.renderOverlay(blobUrl, rotate)}
|
|
164
191
|
</div>
|
|
165
192
|
${when(loading, () => html `<div class="loading">${icon}</div>`)}
|
|
166
193
|
${when(Boolean(error && description), () => html `<affine-resource-status
|
|
@@ -190,6 +217,7 @@ let ImageEdgelessBlockComponent = (() => {
|
|
|
190
217
|
constructor() {
|
|
191
218
|
super(...arguments);
|
|
192
219
|
this.resourceController = new ResourceController(computed(() => this.model.props.sourceId$.value), 'Image');
|
|
220
|
+
this.cropController = new ImageCropController(this, true);
|
|
193
221
|
this.convertToCardView = () => {
|
|
194
222
|
turnImageIntoCardView(this).catch(console.error);
|
|
195
223
|
};
|