js-draw 1.18.0 → 1.20.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +51 -0
- package/dist/Editor.css +78 -5
- package/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +20 -1
- package/dist/cjs/Editor.js +6 -0
- package/dist/cjs/{SVGLoader.d.ts → SVGLoader/index.d.ts} +1 -1
- package/dist/cjs/{SVGLoader.js → SVGLoader/index.js} +15 -30
- package/dist/cjs/SVGLoader/utils/determineFontSize.d.ts +3 -0
- package/dist/cjs/SVGLoader/utils/determineFontSize.js +27 -0
- package/dist/cjs/Viewport.d.ts +33 -1
- package/dist/cjs/components/TextComponent.js +3 -1
- package/dist/cjs/image/EditorImage.d.ts +2 -1
- package/dist/cjs/image/EditorImage.js +101 -5
- package/dist/cjs/rendering/caching/RenderingCacheNode.js +20 -15
- package/dist/cjs/rendering/renderers/CanvasRenderer.js +4 -4
- package/dist/cjs/testing/findNodeWithText.d.ts +3 -0
- package/dist/cjs/testing/findNodeWithText.js +16 -0
- package/dist/cjs/testing/firstElementAncestorOfNode.d.ts +3 -0
- package/dist/cjs/testing/firstElementAncestorOfNode.js +13 -0
- package/dist/cjs/testing/sendKeyPressRelease.d.ts +3 -0
- package/dist/cjs/testing/sendKeyPressRelease.js +8 -0
- package/dist/cjs/testing/sendPenEvent.d.ts +2 -2
- package/dist/cjs/testing/sendPenEvent.js +26 -3
- package/dist/cjs/toolbar/localization.d.ts +3 -0
- package/dist/cjs/toolbar/localization.js +3 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.js +1 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +23 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.js +65 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/fileToImages.d.ts +3 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/fileToImages.js +21 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/index.d.ts +37 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/index.js +289 -0
- package/dist/cjs/toolbar/widgets/TextToolWidget.js +5 -3
- package/dist/cjs/toolbar/widgets/TextToolWidget.test.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/components/makeFileInput.d.ts +12 -2
- package/dist/cjs/toolbar/widgets/components/makeFileInput.js +113 -45
- package/dist/cjs/toolbar/widgets/components/makeFileInput.test.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/components/makeSnappedList.d.ts +15 -0
- package/dist/cjs/toolbar/widgets/components/makeSnappedList.js +168 -0
- package/dist/cjs/tools/Eraser.d.ts +7 -2
- package/dist/cjs/tools/Eraser.js +76 -6
- package/dist/cjs/tools/PanZoom.d.ts +54 -0
- package/dist/cjs/tools/PanZoom.js +54 -2
- package/dist/cjs/tools/SelectionTool/Selection.d.ts +2 -2
- package/dist/cjs/tools/SelectionTool/Selection.js +20 -20
- package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +8 -2
- package/dist/cjs/tools/SelectionTool/SelectionHandle.js +6 -0
- package/dist/cjs/tools/SelectionTool/SelectionTool.js +1 -1
- package/dist/cjs/tools/SelectionTool/types.d.ts +19 -0
- package/dist/cjs/tools/TextTool.js +2 -1
- package/dist/cjs/tools/TextTool.test.d.ts +1 -0
- package/dist/cjs/tools/ToolController.d.ts +2 -0
- package/dist/cjs/tools/ToolController.js +10 -1
- package/dist/cjs/util/ReactiveValue.d.ts +6 -0
- package/dist/cjs/util/ReactiveValue.js +16 -0
- package/dist/cjs/util/bytesToSizeString.d.ts +8 -0
- package/dist/cjs/util/bytesToSizeString.js +26 -0
- package/dist/cjs/util/bytesToSizeString.test.d.ts +1 -0
- package/dist/cjs/util/stopPropagationOfScrollingWheelEvents.js +10 -6
- package/dist/cjs/util/waitForAll.d.ts +2 -0
- package/dist/cjs/util/waitForAll.js +2 -0
- package/dist/cjs/util/waitForImageLoaded.js +3 -0
- package/dist/cjs/util/waitForTimeout.d.ts +1 -0
- package/dist/cjs/util/waitForTimeout.js +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +20 -1
- package/dist/mjs/Editor.mjs +6 -0
- package/dist/mjs/{SVGLoader.d.ts → SVGLoader/index.d.ts} +1 -1
- package/dist/mjs/{SVGLoader.mjs → SVGLoader/index.mjs} +15 -30
- package/dist/mjs/SVGLoader/index.test.d.ts +1 -0
- package/dist/mjs/SVGLoader/utils/determineFontSize.d.ts +3 -0
- package/dist/mjs/SVGLoader/utils/determineFontSize.mjs +25 -0
- package/dist/mjs/Viewport.d.ts +33 -1
- package/dist/mjs/components/TextComponent.mjs +3 -1
- package/dist/mjs/image/EditorImage.d.ts +2 -1
- package/dist/mjs/image/EditorImage.mjs +101 -5
- package/dist/mjs/rendering/caching/RenderingCacheNode.mjs +20 -15
- package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +4 -4
- package/dist/mjs/testing/findNodeWithText.d.ts +3 -0
- package/dist/mjs/testing/findNodeWithText.mjs +14 -0
- package/dist/mjs/testing/firstElementAncestorOfNode.d.ts +3 -0
- package/dist/mjs/testing/firstElementAncestorOfNode.mjs +11 -0
- package/dist/mjs/testing/sendKeyPressRelease.d.ts +3 -0
- package/dist/mjs/testing/sendKeyPressRelease.mjs +6 -0
- package/dist/mjs/testing/sendPenEvent.d.ts +2 -2
- package/dist/mjs/testing/sendPenEvent.mjs +3 -3
- package/dist/mjs/toolbar/localization.d.ts +3 -0
- package/dist/mjs/toolbar/localization.mjs +3 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +1 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +23 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.mjs +61 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/fileToImages.d.ts +3 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/fileToImages.mjs +16 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/index.d.ts +37 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/index.mjs +284 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/index.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/TextToolWidget.mjs +5 -3
- package/dist/mjs/toolbar/widgets/TextToolWidget.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/components/makeFileInput.d.ts +12 -2
- package/dist/mjs/toolbar/widgets/components/makeFileInput.mjs +113 -45
- package/dist/mjs/toolbar/widgets/components/makeFileInput.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/components/makeSnappedList.d.ts +15 -0
- package/dist/mjs/toolbar/widgets/components/makeSnappedList.mjs +163 -0
- package/dist/mjs/tools/Eraser.d.ts +7 -2
- package/dist/mjs/tools/Eraser.mjs +76 -6
- package/dist/mjs/tools/PanZoom.d.ts +54 -0
- package/dist/mjs/tools/PanZoom.mjs +54 -2
- package/dist/mjs/tools/SelectionTool/Selection.d.ts +2 -2
- package/dist/mjs/tools/SelectionTool/Selection.mjs +20 -20
- package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +8 -2
- package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +6 -0
- package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/types.d.ts +19 -0
- package/dist/mjs/tools/TextTool.mjs +2 -1
- package/dist/mjs/tools/TextTool.test.d.ts +1 -0
- package/dist/mjs/tools/ToolController.d.ts +2 -0
- package/dist/mjs/tools/ToolController.mjs +10 -1
- package/dist/mjs/util/ReactiveValue.d.ts +6 -0
- package/dist/mjs/util/ReactiveValue.mjs +16 -0
- package/dist/mjs/util/bytesToSizeString.d.ts +8 -0
- package/dist/mjs/util/bytesToSizeString.mjs +24 -0
- package/dist/mjs/util/bytesToSizeString.test.d.ts +1 -0
- package/dist/mjs/util/stopPropagationOfScrollingWheelEvents.mjs +10 -6
- package/dist/mjs/util/waitForAll.d.ts +2 -0
- package/dist/mjs/util/waitForAll.mjs +2 -0
- package/dist/mjs/util/waitForImageLoaded.mjs +3 -0
- package/dist/mjs/util/waitForTimeout.d.ts +1 -0
- package/dist/mjs/util/waitForTimeout.mjs +1 -1
- package/dist/mjs/version.mjs +1 -1
- package/package.json +4 -4
- package/src/toolbar/EdgeToolbar.scss +8 -3
- package/src/toolbar/toolbar.scss +1 -7
- package/src/toolbar/widgets/{InsertImageWidget.scss → InsertImageWidget/index.scss} +3 -2
- package/src/toolbar/widgets/components/components.scss +2 -1
- package/src/toolbar/widgets/components/makeFileInput.scss +14 -1
- package/src/toolbar/widgets/components/makeSnappedList.scss +74 -0
- package/src/toolbar/widgets/widgets.scss +7 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget.d.ts +0 -22
- package/dist/cjs/toolbar/widgets/InsertImageWidget.js +0 -269
- package/dist/mjs/toolbar/widgets/InsertImageWidget.d.ts +0 -22
- package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +0 -264
- /package/dist/cjs/{SVGLoader.test.d.ts → SVGLoader/index.test.d.ts} +0 -0
- /package/dist/{mjs/SVGLoader.test.d.ts → cjs/toolbar/widgets/InsertImageWidget/index.test.d.ts} +0 -0
@@ -64,6 +64,11 @@ class SelectionHandle {
|
|
64
64
|
addTo(container) {
|
65
65
|
container.appendChild(this.element);
|
66
66
|
}
|
67
|
+
/**
|
68
|
+
* Removes this element from its container. Should only be called
|
69
|
+
* after {@link addTo}.
|
70
|
+
*/
|
71
|
+
remove() { this.element.remove(); }
|
67
72
|
/**
|
68
73
|
* Returns this handle's bounding box relative to the top left of the
|
69
74
|
* selection box.
|
@@ -112,6 +117,7 @@ class SelectionHandle {
|
|
112
117
|
handleDragStart(pointer) {
|
113
118
|
this.onDragStart(pointer.canvasPos);
|
114
119
|
this.dragLastPos = pointer.canvasPos;
|
120
|
+
return true;
|
115
121
|
}
|
116
122
|
handleDragUpdate(pointer) {
|
117
123
|
if (!this.dragLastPos) {
|
@@ -1,3 +1,5 @@
|
|
1
|
+
import type { Rect2, Point2 } from '@js-draw/math';
|
2
|
+
import Pointer from '../../Pointer';
|
1
3
|
export declare enum ResizeMode {
|
2
4
|
Both = 0,
|
3
5
|
HorizontalOnly = 1,
|
@@ -7,3 +9,20 @@ export declare enum TransformMode {
|
|
7
9
|
Snap = 0,
|
8
10
|
NoSnap = 1
|
9
11
|
}
|
12
|
+
/**
|
13
|
+
* Represents a child of the selection that should move with the selection
|
14
|
+
* and handle events.
|
15
|
+
*
|
16
|
+
* Although selection children should be `HTMLElement`s, the selection may be
|
17
|
+
* hidden behind an invisible element. As such, these elements should handle
|
18
|
+
* drag start/update/end events.
|
19
|
+
*/
|
20
|
+
export interface SelectionBoxChild {
|
21
|
+
updatePosition(selectionScreenBBox: Rect2): void;
|
22
|
+
containsPoint(point: Point2): boolean;
|
23
|
+
addTo(container: HTMLElement): void;
|
24
|
+
remove(): void;
|
25
|
+
handleDragStart(pointer: Pointer): boolean;
|
26
|
+
handleDragUpdate(pointer: Pointer): void;
|
27
|
+
handleDragEnd(): void;
|
28
|
+
}
|
@@ -23,9 +23,10 @@ class TextTool extends BaseTool_1.default {
|
|
23
23
|
this.textMeasuringCtx = null;
|
24
24
|
this.textScale = math_1.Vec2.of(1, 1);
|
25
25
|
this.removeExistingCommand = null;
|
26
|
+
const editorFonts = editor.getCurrentSettings().text?.fonts ?? [];
|
26
27
|
this.textStyleValue = ReactiveValue_1.ReactiveValue.fromInitialValue({
|
27
28
|
size: 32,
|
28
|
-
fontFamily: 'sans-serif',
|
29
|
+
fontFamily: editorFonts.length > 0 ? editorFonts[0] : 'sans-serif',
|
29
30
|
renderingStyle: {
|
30
31
|
fill: math_1.Color4.purple,
|
31
32
|
},
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -55,6 +55,8 @@ export default class ToolController implements InputEventListener {
|
|
55
55
|
insertToolsAfter(insertAfter: BaseTool, toolsToInsert: BaseTool[]): void;
|
56
56
|
/** @see {@link insertToolsAfter} */
|
57
57
|
insertToolsBefore(insertBefore: BaseTool, toolsToInsert: BaseTool[]): void;
|
58
|
+
/** @internal */
|
59
|
+
changeActiveToolTo(tool: BaseTool): void;
|
58
60
|
private onEventInternal;
|
59
61
|
/** Alias for {@link dispatchInputEvent}. */
|
60
62
|
onEvent(event: InputEvt): boolean;
|
@@ -62,6 +62,7 @@ class ToolController {
|
|
62
62
|
const secondaryPenTool = new Pen_1.default(editor, localization.penTool(2), { color: math_1.Color4.clay, thickness: 4 });
|
63
63
|
// Stabilize the secondary pen tool.
|
64
64
|
secondaryPenTool.setInputMapper(new InputStabilizer_1.default(editor.viewport));
|
65
|
+
const eraser = new Eraser_1.default(editor, localization.eraserTool);
|
65
66
|
const primaryTools = [
|
66
67
|
// Three pens
|
67
68
|
primaryPenTool,
|
@@ -72,7 +73,7 @@ class ToolController {
|
|
72
73
|
thickness: 40,
|
73
74
|
factory: PressureSensitiveFreehandLineBuilder_1.makePressureSensitiveFreehandLineBuilder
|
74
75
|
}),
|
75
|
-
|
76
|
+
eraser,
|
76
77
|
new SelectionTool_1.default(editor, localization.selectionTool),
|
77
78
|
new TextTool_1.default(editor, localization.textTool, localization),
|
78
79
|
new PanZoom_1.default(editor, PanZoom_1.PanZoomMode.SinglePointerGestures, localization.anyDevicePanning),
|
@@ -90,6 +91,7 @@ class ToolController {
|
|
90
91
|
new UndoRedoShortcut_1.default(editor),
|
91
92
|
new ToolbarShortcutHandler_1.default(editor),
|
92
93
|
new ToolSwitcherShortcut_1.default(editor),
|
94
|
+
eraser.makeEraserSwitcherTool(),
|
93
95
|
new FindTool_1.default(editor),
|
94
96
|
new PasteHandler_1.default(editor),
|
95
97
|
new SelectAllShortcutHandler_1.default(editor),
|
@@ -208,6 +210,13 @@ class ToolController {
|
|
208
210
|
insertToolsBefore(insertBefore, toolsToInsert) {
|
209
211
|
this.insertTools(insertBefore, toolsToInsert, 'before');
|
210
212
|
}
|
213
|
+
/** @internal */
|
214
|
+
changeActiveToolTo(tool) {
|
215
|
+
if (!tool.isEnabled()) {
|
216
|
+
tool.setEnabled(true);
|
217
|
+
}
|
218
|
+
this.activeTool = tool;
|
219
|
+
}
|
211
220
|
// @internal use `dispatchEvent` rather than calling `onEvent` directly.
|
212
221
|
onEventInternal(event) {
|
213
222
|
const isEditorReadOnly = this.isEditorReadOnly.get();
|
@@ -2,6 +2,9 @@ type ListenerResult = {
|
|
2
2
|
remove(): void;
|
3
3
|
};
|
4
4
|
type UpdateCallback<T> = (value: T) => void;
|
5
|
+
type ReactiveValuesOf<T extends unknown[]> = {
|
6
|
+
[key in keyof T]: ReactiveValue<T[key]>;
|
7
|
+
};
|
5
8
|
/**
|
6
9
|
* A `ReactiveValue` is a value that
|
7
10
|
* - updates periodically,
|
@@ -33,6 +36,8 @@ export declare abstract class ReactiveValue<T> {
|
|
33
36
|
* @see {@link onUpdate}.
|
34
37
|
*/
|
35
38
|
abstract onUpdateAndNow(callback: UpdateCallback<T>): ListenerResult;
|
39
|
+
/** Returns a promise that resolves when this value is next changed. */
|
40
|
+
waitForNextUpdate(): Promise<T>;
|
36
41
|
/** Creates a `ReactiveValue` with an initial value, `initialValue`. */
|
37
42
|
static fromInitialValue<T>(initialValue: T): MutableReactiveValue<T>;
|
38
43
|
/** Returns a `ReactiveValue` that is **known** will never change. */
|
@@ -54,6 +59,7 @@ export declare abstract class ReactiveValue<T> {
|
|
54
59
|
* Returns a reactive value derived from a single `source`.
|
55
60
|
*/
|
56
61
|
static map<A, B>(source: ReactiveValue<A>, map: (a: A) => B, inverseMap: (b: B) => A): MutableReactiveValue<B>;
|
62
|
+
static union<Values extends [...unknown[]]>(values: ReactiveValuesOf<Values>): ReactiveValue<Values>;
|
57
63
|
}
|
58
64
|
export declare abstract class MutableReactiveValue<T> extends ReactiveValue<T> {
|
59
65
|
/**
|
@@ -38,6 +38,15 @@ const noOpSetUpdateListener = () => {
|
|
38
38
|
* Avoid extending this class from an external library, as that may not be stable.
|
39
39
|
*/
|
40
40
|
class ReactiveValue {
|
41
|
+
/** Returns a promise that resolves when this value is next changed. */
|
42
|
+
waitForNextUpdate() {
|
43
|
+
return new Promise(resolve => {
|
44
|
+
const listener = this.onUpdate(value => {
|
45
|
+
listener.remove();
|
46
|
+
resolve(value);
|
47
|
+
});
|
48
|
+
});
|
49
|
+
}
|
41
50
|
/** Creates a `ReactiveValue` with an initial value, `initialValue`. */
|
42
51
|
static fromInitialValue(initialValue) {
|
43
52
|
return new ReactiveValueImpl(initialValue);
|
@@ -51,6 +60,8 @@ class ReactiveValue {
|
|
51
60
|
callback(value);
|
52
61
|
return noOpUpdateListenerResult;
|
53
62
|
},
|
63
|
+
// Never resolves -- immutable.
|
64
|
+
waitForNextUpdate: () => new Promise(() => { }),
|
54
65
|
};
|
55
66
|
}
|
56
67
|
/**
|
@@ -95,6 +106,11 @@ class ReactiveValue {
|
|
95
106
|
}
|
96
107
|
return result;
|
97
108
|
}
|
109
|
+
static union(values) {
|
110
|
+
return ReactiveValue.fromCallback(() => {
|
111
|
+
return values.map(value => value.get());
|
112
|
+
}, values);
|
113
|
+
}
|
98
114
|
}
|
99
115
|
exports.ReactiveValue = ReactiveValue;
|
100
116
|
class MutableReactiveValue extends ReactiveValue {
|
@@ -0,0 +1,26 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
/**
|
4
|
+
* Returns a size in bytes, KiB, or MiB with units suffix.
|
5
|
+
*/
|
6
|
+
const bytesToSizeString = (sizeBytes) => {
|
7
|
+
const sizeInKiB = sizeBytes / 1024;
|
8
|
+
const sizeInMiB = sizeInKiB / 1024;
|
9
|
+
const sizeInGiB = sizeInMiB / 1024;
|
10
|
+
let units = 'B';
|
11
|
+
let size = sizeBytes;
|
12
|
+
if (sizeInGiB >= 1) {
|
13
|
+
size = sizeInGiB;
|
14
|
+
units = 'GiB';
|
15
|
+
}
|
16
|
+
else if (sizeInMiB >= 1) {
|
17
|
+
size = sizeInMiB;
|
18
|
+
units = 'MiB';
|
19
|
+
}
|
20
|
+
else if (sizeInKiB >= 1) {
|
21
|
+
size = sizeInKiB;
|
22
|
+
units = 'KiB';
|
23
|
+
}
|
24
|
+
return { size, units };
|
25
|
+
};
|
26
|
+
exports.default = bytesToSizeString;
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -1,15 +1,19 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
const stopPropagationOfScrollingWheelEvents = (scrollingContainer) => {
|
4
|
+
const scrollsAxis = (delta, clientSize, scrollOffset, scrollSize) => {
|
5
|
+
const hasScroll = clientSize !== scrollSize && delta !== 0;
|
6
|
+
const eventScrollsPastStart = scrollOffset + delta <= 0;
|
7
|
+
const scrollEnd = scrollOffset + clientSize;
|
8
|
+
const eventScrollsPastEnd = scrollEnd + delta > scrollSize;
|
9
|
+
return hasScroll && !eventScrollsPastStart && !eventScrollsPastEnd;
|
10
|
+
};
|
4
11
|
scrollingContainer.onwheel = (event) => {
|
5
|
-
const
|
6
|
-
|
7
|
-
const eventScrollsPastLeft = scrollingContainer.scrollLeft + event.deltaX <= 0;
|
8
|
-
const scrollRight = scrollingContainer.scrollLeft + scrollingContainer.clientWidth;
|
9
|
-
const eventScrollsPastRight = scrollRight + event.deltaX > scrollingContainer.scrollWidth;
|
12
|
+
const scrollsX = scrollsAxis(event.deltaX, scrollingContainer.clientWidth, scrollingContainer.scrollLeft, scrollingContainer.scrollWidth);
|
13
|
+
const scrollsY = scrollsAxis(event.deltaY, scrollingContainer.clientHeight, scrollingContainer.scrollTop, scrollingContainer.scrollHeight);
|
10
14
|
// Stop the editor from receiving the event if it will scroll the pen type selector
|
11
15
|
// instead.
|
12
|
-
if (
|
16
|
+
if (scrollsX || scrollsY) {
|
13
17
|
event.stopPropagation();
|
14
18
|
}
|
15
19
|
};
|
@@ -1,6 +1,8 @@
|
|
1
1
|
/**
|
2
2
|
* Resolves when all given promises have resolved. If no promises are given,
|
3
3
|
* does not return a Promise.
|
4
|
+
*
|
5
|
+
* If all elements of `results` are known to be `Promise`s, use `Promise.all`.
|
4
6
|
*/
|
5
7
|
declare const waitForAll: (results: (Promise<void> | void)[]) => Promise<void> | void;
|
6
8
|
export default waitForAll;
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
/**
|
4
4
|
* Resolves when all given promises have resolved. If no promises are given,
|
5
5
|
* does not return a Promise.
|
6
|
+
*
|
7
|
+
* If all elements of `results` are known to be `Promise`s, use `Promise.all`.
|
6
8
|
*/
|
7
9
|
const waitForAll = (results) => {
|
8
10
|
// If any are Promises...
|
@@ -4,7 +4,10 @@ const waitForImageLoad = async (image) => {
|
|
4
4
|
if (!image.complete) {
|
5
5
|
await new Promise((resolve, reject) => {
|
6
6
|
image.onload = event => resolve(event);
|
7
|
+
// TODO(v2): Return a `new Error(event.message)`
|
8
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- Forwarding an error-like object.
|
7
9
|
image.onerror = event => reject(event);
|
10
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- Forwarding an error-like object.
|
8
11
|
image.onabort = event => reject(event);
|
9
12
|
});
|
10
13
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
|
3
|
+
/** Returns a promise that resolves after `timeout` milliseconds. */
|
4
4
|
const waitForTimeout = (timeout) => {
|
5
5
|
return new Promise(resolve => {
|
6
6
|
setTimeout(() => resolve(), timeout);
|
package/dist/cjs/version.js
CHANGED
package/dist/mjs/Editor.d.ts
CHANGED
@@ -19,6 +19,7 @@ import RenderablePathSpec from './rendering/RenderablePathSpec';
|
|
19
19
|
import { AboutDialogEntry } from './dialogs/makeAboutDialog';
|
20
20
|
import ReactiveValue, { MutableReactiveValue } from './util/ReactiveValue';
|
21
21
|
import { PenTypeRecord } from './toolbar/widgets/PenToolWidget';
|
22
|
+
import { ShowCustomFilePickerCallback } from './toolbar/widgets/components/makeFileInput';
|
22
23
|
/**
|
23
24
|
* Provides settings to an instance of an editor. See the Editor {@link Editor.constructor}.
|
24
25
|
*
|
@@ -76,7 +77,7 @@ export interface EditorSettings {
|
|
76
77
|
version?: string;
|
77
78
|
} | null;
|
78
79
|
/**
|
79
|
-
* Configures the default
|
80
|
+
* Configures the default {@link PenTool} tools.
|
80
81
|
*
|
81
82
|
* **Example**:
|
82
83
|
* [[include:doc-pages/inline-examples/editor-settings-polyline-pen.md]]
|
@@ -102,6 +103,24 @@ export interface EditorSettings {
|
|
102
103
|
*/
|
103
104
|
filterPenTypes?: (penType: PenTypeRecord) => boolean;
|
104
105
|
} | null;
|
106
|
+
/** Configures the default {@link TextTool} control and text tool. */
|
107
|
+
text: {
|
108
|
+
/** Fonts to show in the text UI. */
|
109
|
+
fonts?: string[];
|
110
|
+
} | null;
|
111
|
+
/** Configures the default {@link InsertImageWidget} control. */
|
112
|
+
image: {
|
113
|
+
/**
|
114
|
+
* A custom callback to show an image picker. If given, this should return
|
115
|
+
* a list of `File`s representing the images selected by the picker.
|
116
|
+
*
|
117
|
+
* If not given, the default file picker shown by a [file input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file)
|
118
|
+
* is shown.
|
119
|
+
*
|
120
|
+
* @beta -- API may change between minor releases.
|
121
|
+
*/
|
122
|
+
showImagePicker?: ShowCustomFilePickerCallback;
|
123
|
+
} | null;
|
105
124
|
}
|
106
125
|
/**
|
107
126
|
* The main entrypoint for the full editor.
|
package/dist/mjs/Editor.mjs
CHANGED
@@ -113,6 +113,12 @@ export class Editor {
|
|
113
113
|
additionalPenTypes: settings.pens?.additionalPenTypes ?? [],
|
114
114
|
filterPenTypes: settings.pens?.filterPenTypes ?? (() => true)
|
115
115
|
},
|
116
|
+
text: {
|
117
|
+
fonts: settings.text?.fonts ?? ['sans-serif', 'serif', 'monospace'],
|
118
|
+
},
|
119
|
+
image: {
|
120
|
+
showImagePicker: settings.image?.showImagePicker ?? undefined,
|
121
|
+
},
|
116
122
|
};
|
117
123
|
// Validate settings
|
118
124
|
if (this.settings.minZoom > this.settings.maxZoom) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Rect2 } from '@js-draw/math';
|
2
|
-
import { ComponentAddedListener, ImageLoader, OnDetermineExportRectListener, OnProgressListener } from '
|
2
|
+
import { ComponentAddedListener, ImageLoader, OnDetermineExportRectListener, OnProgressListener } from '../types';
|
3
3
|
export declare const defaultSVGViewRect: Rect2;
|
4
4
|
export declare const svgAttributesDataKey = "svgAttrs";
|
5
5
|
export declare const svgStyleAttributesDataKey = "svgStyleAttrs";
|
@@ -1,12 +1,13 @@
|
|
1
1
|
import { Color4, Mat33, Path, Rect2, Vec2 } from '@js-draw/math';
|
2
|
-
import BackgroundComponent, { BackgroundType, backgroundTypeToClassNameMap, imageBackgroundCSSClassName, imageBackgroundGridSizeCSSPrefix, imageBackgroundNonAutomaticSecondaryColorCSSClassName } from '
|
3
|
-
import ImageComponent from '
|
4
|
-
import Stroke from '
|
5
|
-
import SVGGlobalAttributesObject from '
|
6
|
-
import TextComponent, { TextTransformMode } from '
|
7
|
-
import UnknownSVGObject from '
|
8
|
-
import { pathToRenderable } from '
|
9
|
-
import { renderedStylesheetId } from '
|
2
|
+
import BackgroundComponent, { BackgroundType, backgroundTypeToClassNameMap, imageBackgroundCSSClassName, imageBackgroundGridSizeCSSPrefix, imageBackgroundNonAutomaticSecondaryColorCSSClassName } from '../components/BackgroundComponent.mjs';
|
3
|
+
import ImageComponent from '../components/ImageComponent.mjs';
|
4
|
+
import Stroke from '../components/Stroke.mjs';
|
5
|
+
import SVGGlobalAttributesObject from '../components/SVGGlobalAttributesObject.mjs';
|
6
|
+
import TextComponent, { TextTransformMode } from '../components/TextComponent.mjs';
|
7
|
+
import UnknownSVGObject from '../components/UnknownSVGObject.mjs';
|
8
|
+
import { pathToRenderable } from '../rendering/RenderablePathSpec.mjs';
|
9
|
+
import { renderedStylesheetId } from '../rendering/renderers/SVGRenderer.mjs';
|
10
|
+
import determineFontSize from './utils/determineFontSize.mjs';
|
10
11
|
// Size of a loaded image if no size is specified.
|
11
12
|
export const defaultSVGViewRect = new Rect2(0, 0, 500, 500);
|
12
13
|
// Key to retrieve unrecognised attributes from an AbstractComponent
|
@@ -46,7 +47,9 @@ export default class SVGLoader {
|
|
46
47
|
let fill = Color4.transparent;
|
47
48
|
let stroke;
|
48
49
|
// If possible, use computedStyles (allows property inheritance).
|
49
|
-
|
50
|
+
// Chromium, however, sets .fill to a falsy, but not undefined value in some cases where
|
51
|
+
// styles are available. As such, use || instead of ??.
|
52
|
+
const fillAttribute = node.getAttribute('fill') ?? (computedStyles?.fill || node.style?.fill);
|
50
53
|
if (fillAttribute) {
|
51
54
|
try {
|
52
55
|
fill = Color4.fromString(fillAttribute);
|
@@ -296,31 +299,13 @@ export default class SVGLoader {
|
|
296
299
|
}
|
297
300
|
// Compute styles.
|
298
301
|
const computedStyles = this.getComputedStyle(elem);
|
299
|
-
const
|
300
|
-
// In some environments, computedStyles.fontSize can be increased by the system.
|
301
|
-
// Thus, to prevent text from growing on load/save, prefer .style.fontSize.
|
302
|
-
let fontSizeMatch = fontSizeExp.exec(elem.style?.fontSize ?? '');
|
303
|
-
if (!fontSizeMatch && elem.tagName.toLowerCase() === 'tspan' && elem.parentElement) {
|
304
|
-
// Try to inherit the font size of the parent text element.
|
305
|
-
fontSizeMatch = fontSizeExp.exec(elem.parentElement.style?.fontSize ?? '');
|
306
|
-
}
|
307
|
-
// If we still couldn't find a font size, try to use computedStyles (which can be
|
308
|
-
// wrong).
|
309
|
-
if (!fontSizeMatch && computedStyles) {
|
310
|
-
fontSizeMatch = fontSizeExp.exec(computedStyles.fontSize);
|
311
|
-
}
|
312
|
-
const supportedStyleAttrs = [
|
302
|
+
const supportedStyleAttrs = new Set([
|
313
303
|
'fontFamily',
|
314
304
|
'transform',
|
315
305
|
...supportedStrokeFillStyleAttrs,
|
316
|
-
];
|
317
|
-
let fontSize = 12;
|
318
|
-
if (fontSizeMatch) {
|
319
|
-
supportedStyleAttrs.push('fontSize');
|
320
|
-
fontSize = parseFloat(fontSizeMatch[1]);
|
321
|
-
}
|
306
|
+
]);
|
322
307
|
const style = {
|
323
|
-
size:
|
308
|
+
size: determineFontSize(elem, computedStyles, supportedStyleAttrs),
|
324
309
|
fontFamily: computedStyles?.fontFamily || elem.style?.fontFamily || 'sans-serif',
|
325
310
|
fontWeight: computedStyles?.fontWeight || elem.style?.fontWeight || undefined,
|
326
311
|
fontStyle: computedStyles?.fontStyle || elem.style?.fontStyle || undefined,
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,3 @@
|
|
1
|
+
/** Computes the font size of a text element, based on style information. */
|
2
|
+
declare const determineFontSize: (elem: SVGTextElement | SVGTSpanElement, computedStyles: CSSStyleDeclaration | undefined, supportedStyleAttrs: Set<string>) => number;
|
3
|
+
export default determineFontSize;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/** Computes the font size of a text element, based on style information. */
|
2
|
+
const determineFontSize = (elem, computedStyles,
|
3
|
+
// output: Written to to update supported style attributes
|
4
|
+
supportedStyleAttrs) => {
|
5
|
+
const fontSizeExp = /^([-0-9.e]+)px/i;
|
6
|
+
// In some environments, computedStyles.fontSize can be increased by the system.
|
7
|
+
// Thus, to prevent text from growing on load/save, prefer .style.fontSize.
|
8
|
+
let fontSizeMatch = fontSizeExp.exec(elem.style?.fontSize ?? '');
|
9
|
+
if (!fontSizeMatch && elem.tagName.toLowerCase() === 'tspan' && elem.parentElement) {
|
10
|
+
// Try to inherit the font size of the parent text element.
|
11
|
+
fontSizeMatch = fontSizeExp.exec(elem.parentElement.style?.fontSize ?? '');
|
12
|
+
}
|
13
|
+
// If we still couldn't find a font size, try to use computedStyles (which can be
|
14
|
+
// wrong).
|
15
|
+
if (!fontSizeMatch && computedStyles) {
|
16
|
+
fontSizeMatch = fontSizeExp.exec(computedStyles.fontSize);
|
17
|
+
}
|
18
|
+
let fontSize = 12;
|
19
|
+
if (fontSizeMatch) {
|
20
|
+
supportedStyleAttrs.add('fontSize');
|
21
|
+
fontSize = parseFloat(fontSizeMatch[1]);
|
22
|
+
}
|
23
|
+
return fontSize;
|
24
|
+
};
|
25
|
+
export default determineFontSize;
|
package/dist/mjs/Viewport.d.ts
CHANGED
@@ -55,7 +55,39 @@ export declare class Viewport {
|
|
55
55
|
*
|
56
56
|
* @see {@link getGridSize} and {@link getScaleFactorToNearestPowerOf}.
|
57
57
|
*/
|
58
|
-
snapToGrid(canvasPos: Point2):
|
58
|
+
snapToGrid(canvasPos: Point2): {
|
59
|
+
readonly x: number;
|
60
|
+
readonly y: number;
|
61
|
+
readonly z: number;
|
62
|
+
readonly xy: {
|
63
|
+
x: number;
|
64
|
+
y: number;
|
65
|
+
};
|
66
|
+
at(idx: number): number;
|
67
|
+
length(): number;
|
68
|
+
magnitude(): number;
|
69
|
+
magnitudeSquared(): number;
|
70
|
+
squareDistanceTo(p: Vec3): number;
|
71
|
+
distanceTo(p: Vec3): number;
|
72
|
+
maximumEntryMagnitude(): number;
|
73
|
+
angle(): number;
|
74
|
+
normalized(): Vec3;
|
75
|
+
normalizedOrZero(): Vec3;
|
76
|
+
times(c: number): Vec3;
|
77
|
+
plus(v: Vec3): Vec3;
|
78
|
+
minus(v: Vec3): Vec3;
|
79
|
+
dot(other: Vec3): number;
|
80
|
+
cross(other: Vec3): Vec3;
|
81
|
+
scale(other: number | Vec3): Vec3;
|
82
|
+
orthog(): Vec3;
|
83
|
+
extend(distance: number, direction: Vec3): Vec3;
|
84
|
+
lerp(target: Vec3, fractionTo: number): Vec3;
|
85
|
+
zip(other: Vec3, zip: (componentInThis: number, componentInOther: number) => number): Vec3;
|
86
|
+
map(fn: (component: number, index: number) => number): Vec3;
|
87
|
+
asArray(): [number, number, number];
|
88
|
+
eq(other: Vec3, fuzz?: number | undefined): boolean;
|
89
|
+
toString(): string;
|
90
|
+
};
|
59
91
|
/** Returns the size of one screen pixel in canvas units. */
|
60
92
|
getSizeOfPixelOnCanvas(): number;
|
61
93
|
/**
|
@@ -83,7 +83,9 @@ class TextComponent extends AbstractComponent {
|
|
83
83
|
}
|
84
84
|
static applyTextStyles(ctx, style) {
|
85
85
|
// Quote the font family if necessary.
|
86
|
-
const
|
86
|
+
const hasSpaces = style.fontFamily.match(/\s/);
|
87
|
+
const isQuoted = style.fontFamily.match(/^".*"$/);
|
88
|
+
const fontFamily = hasSpaces && !isQuoted ? `"${style.fontFamily.replace(/["]/g, '\\"')}"` : style.fontFamily;
|
87
89
|
ctx.font = [
|
88
90
|
style.fontStyle ?? '',
|
89
91
|
style.fontWeight ?? '',
|
@@ -166,7 +166,7 @@ export default class EditorImage {
|
|
166
166
|
*
|
167
167
|
* @internal
|
168
168
|
*/
|
169
|
-
setDebugMode(newDebugMode: boolean): void;
|
169
|
+
static setDebugMode(newDebugMode: boolean): void;
|
170
170
|
private static SetImportExportRectCommand;
|
171
171
|
}
|
172
172
|
/**
|
@@ -214,6 +214,7 @@ export declare class ImageNode {
|
|
214
214
|
renderAllAsync(renderer: AbstractRenderer, preRenderComponent: PreRenderComponentCallback): Promise<boolean>;
|
215
215
|
render(renderer: AbstractRenderer, visibleRect?: Rect2): void;
|
216
216
|
renderDebugBoundingBoxes(renderer: AbstractRenderer, visibleRect: Rect2, depth?: number): void;
|
217
|
+
private checkRep;
|
217
218
|
}
|
218
219
|
/** An `ImageNode` that can properly handle fullscreen/data components. @internal */
|
219
220
|
export declare class RootImageNode extends ImageNode {
|