@tsdraw/react 0.6.1 → 0.6.2
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/index.cjs +96 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +97 -28
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -365,11 +365,15 @@ function createSessionId() {
|
|
|
365
365
|
}
|
|
366
366
|
function getOrCreateSessionId() {
|
|
367
367
|
if (typeof window === "undefined") return createSessionId();
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
368
|
+
try {
|
|
369
|
+
const existing = window.sessionStorage.getItem(SESSION_STORAGE_KEY);
|
|
370
|
+
if (existing) return existing;
|
|
371
|
+
const newId = createSessionId();
|
|
372
|
+
window.sessionStorage.setItem(SESSION_STORAGE_KEY, newId);
|
|
373
|
+
return newId;
|
|
374
|
+
} catch {
|
|
375
|
+
return createSessionId();
|
|
376
|
+
}
|
|
373
377
|
}
|
|
374
378
|
|
|
375
379
|
// src/canvas/useTsdrawCanvasController.ts
|
|
@@ -388,6 +392,7 @@ function resolveDrawColor(colorStyle, theme) {
|
|
|
388
392
|
function useTsdrawCanvasController(options = {}) {
|
|
389
393
|
const stylePanelToolIds = options.stylePanelToolIds ?? ["pen"];
|
|
390
394
|
const stylePanelToolIdsRef = react.useRef(stylePanelToolIds);
|
|
395
|
+
const onMountRef = react.useRef(options.onMount);
|
|
391
396
|
const containerRef = react.useRef(null);
|
|
392
397
|
const canvasRef = react.useRef(null);
|
|
393
398
|
const editorRef = react.useRef(null);
|
|
@@ -440,6 +445,9 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
440
445
|
react.useEffect(() => {
|
|
441
446
|
stylePanelToolIdsRef.current = stylePanelToolIds;
|
|
442
447
|
}, [stylePanelToolIds]);
|
|
448
|
+
react.useEffect(() => {
|
|
449
|
+
onMountRef.current = options.onMount;
|
|
450
|
+
}, [options.onMount]);
|
|
443
451
|
react.useEffect(() => {
|
|
444
452
|
selectedShapeIdsRef.current = selectedShapeIds;
|
|
445
453
|
}, [selectedShapeIds]);
|
|
@@ -713,7 +721,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
713
721
|
additive: first.shiftKey,
|
|
714
722
|
initialSelection: [...selectedShapeIdsRef.current]
|
|
715
723
|
};
|
|
716
|
-
setSelectionBrush({
|
|
724
|
+
setSelectionBrush(toScreenRect(editor, { minX: x, minY: y, maxX: x, maxY: y }));
|
|
717
725
|
if (!e.shiftKey) {
|
|
718
726
|
setSelectedShapeIds([]);
|
|
719
727
|
selectedShapeIdsRef.current = [];
|
|
@@ -870,6 +878,35 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
870
878
|
}
|
|
871
879
|
editor.endHistoryEntry();
|
|
872
880
|
};
|
|
881
|
+
const handlePointerCancel = () => {
|
|
882
|
+
if (!isPointerActiveRef.current) return;
|
|
883
|
+
isPointerActiveRef.current = false;
|
|
884
|
+
lastPointerClientRef.current = null;
|
|
885
|
+
editor.input.pointerUp();
|
|
886
|
+
if (currentToolRef.current === "select") {
|
|
887
|
+
const drag = selectDragRef.current;
|
|
888
|
+
if (drag.mode === "rotate") setIsRotatingSelection(false);
|
|
889
|
+
if (drag.mode === "resize") setIsResizingSelection(false);
|
|
890
|
+
if (drag.mode === "move") setIsMovingSelection(false);
|
|
891
|
+
if (drag.mode === "marquee") setSelectionBrush(null);
|
|
892
|
+
if (drag.mode !== "none") {
|
|
893
|
+
selectDragRef.current.mode = "none";
|
|
894
|
+
render();
|
|
895
|
+
refreshSelectionBounds(editor);
|
|
896
|
+
}
|
|
897
|
+
editor.endHistoryEntry();
|
|
898
|
+
} else {
|
|
899
|
+
editor.tools.pointerUp();
|
|
900
|
+
render();
|
|
901
|
+
refreshSelectionBounds(editor);
|
|
902
|
+
editor.endHistoryEntry();
|
|
903
|
+
}
|
|
904
|
+
if (pendingRemoteDocumentRef.current) {
|
|
905
|
+
const pending = pendingRemoteDocumentRef.current;
|
|
906
|
+
pendingRemoteDocumentRef.current = null;
|
|
907
|
+
applyRemoteDocumentSnapshot(pending);
|
|
908
|
+
}
|
|
909
|
+
};
|
|
873
910
|
const handleKeyDown = (e) => {
|
|
874
911
|
const isMetaPressed = e.metaKey || e.ctrlKey;
|
|
875
912
|
const loweredKey = e.key.toLowerCase();
|
|
@@ -916,22 +953,42 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
916
953
|
}
|
|
917
954
|
editor.loadHistorySnapshot(loaded.history);
|
|
918
955
|
syncHistoryState();
|
|
956
|
+
if (disposed) return;
|
|
919
957
|
persistenceActive = true;
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
if (isPointerActiveRef.current) {
|
|
929
|
-
pendingRemoteDocumentRef.current = nextDocument;
|
|
958
|
+
if (typeof BroadcastChannel !== "undefined") {
|
|
959
|
+
persistenceChannel = new BroadcastChannel(`tsdraw:persistence:${persistenceKey}`);
|
|
960
|
+
let isLoadingRemote = false;
|
|
961
|
+
let pendingRemoteLoad = false;
|
|
962
|
+
persistenceChannel.onmessage = () => {
|
|
963
|
+
if (disposed) return;
|
|
964
|
+
if (isLoadingRemote) {
|
|
965
|
+
pendingRemoteLoad = true;
|
|
930
966
|
return;
|
|
931
967
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
968
|
+
isLoadingRemote = true;
|
|
969
|
+
const processLoad = async () => {
|
|
970
|
+
try {
|
|
971
|
+
do {
|
|
972
|
+
pendingRemoteLoad = false;
|
|
973
|
+
if (!persistenceDb || disposed) return;
|
|
974
|
+
const nextLoaded = await persistenceDb.load(sessionId);
|
|
975
|
+
if (disposed) return;
|
|
976
|
+
if (nextLoaded.records.length > 0) {
|
|
977
|
+
const nextDocument = { records: nextLoaded.records };
|
|
978
|
+
if (isPointerActiveRef.current) {
|
|
979
|
+
pendingRemoteDocumentRef.current = nextDocument;
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
applyRemoteDocumentSnapshot(nextDocument);
|
|
983
|
+
}
|
|
984
|
+
} while (pendingRemoteLoad && !disposed);
|
|
985
|
+
} finally {
|
|
986
|
+
isLoadingRemote = false;
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
void processLoad();
|
|
990
|
+
};
|
|
991
|
+
}
|
|
935
992
|
} finally {
|
|
936
993
|
if (!disposed) {
|
|
937
994
|
setIsPersistenceReady(true);
|
|
@@ -953,12 +1010,13 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
953
1010
|
canvas.addEventListener("pointerdown", handlePointerDown);
|
|
954
1011
|
window.addEventListener("pointermove", handlePointerMove);
|
|
955
1012
|
window.addEventListener("pointerup", handlePointerUp);
|
|
1013
|
+
window.addEventListener("pointercancel", handlePointerCancel);
|
|
956
1014
|
window.addEventListener("keydown", handleKeyDown);
|
|
957
1015
|
window.addEventListener("keyup", handleKeyUp);
|
|
958
1016
|
void initializePersistence().catch((error) => {
|
|
959
1017
|
console.error("failed to initialize tsdraw persistence", error);
|
|
960
1018
|
});
|
|
961
|
-
disposeMount =
|
|
1019
|
+
disposeMount = onMountRef.current?.({
|
|
962
1020
|
editor,
|
|
963
1021
|
container,
|
|
964
1022
|
canvas,
|
|
@@ -1007,6 +1065,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1007
1065
|
canvas.removeEventListener("pointerdown", handlePointerDown);
|
|
1008
1066
|
window.removeEventListener("pointermove", handlePointerMove);
|
|
1009
1067
|
window.removeEventListener("pointerup", handlePointerUp);
|
|
1068
|
+
window.removeEventListener("pointercancel", handlePointerCancel);
|
|
1010
1069
|
window.removeEventListener("keydown", handleKeyDown);
|
|
1011
1070
|
window.removeEventListener("keyup", handleKeyUp);
|
|
1012
1071
|
isPointerActiveRef.current = false;
|
|
@@ -1018,7 +1077,6 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1018
1077
|
}, [
|
|
1019
1078
|
getPagePointFromClient,
|
|
1020
1079
|
options.initialTool,
|
|
1021
|
-
options.onMount,
|
|
1022
1080
|
options.persistenceKey,
|
|
1023
1081
|
options.toolDefinitions,
|
|
1024
1082
|
refreshSelectionBounds,
|
|
@@ -1138,6 +1196,8 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1138
1196
|
};
|
|
1139
1197
|
}
|
|
1140
1198
|
var DEFAULT_TOOLBAR_PARTS = [["undo", "redo"], ["select", "hand", "pen", "eraser"]];
|
|
1199
|
+
var EMPTY_CUSTOM_TOOLS = [];
|
|
1200
|
+
var EMPTY_CUSTOM_ELEMENTS = [];
|
|
1141
1201
|
var DEFAULT_TOOL_LABELS = {
|
|
1142
1202
|
select: "Select",
|
|
1143
1203
|
pen: "Pen",
|
|
@@ -1183,14 +1243,14 @@ function resolvePlacementStyle(placement, fallbackAnchor, fallbackOffsetX, fallb
|
|
|
1183
1243
|
if (offsetY) transforms.push(`translateY(${offsetY}px)`);
|
|
1184
1244
|
}
|
|
1185
1245
|
if (transforms.length > 0) result.transform = transforms.join(" ");
|
|
1186
|
-
return { ...result, ...placement
|
|
1246
|
+
return placement?.style ? { ...result, ...placement.style } : result;
|
|
1187
1247
|
}
|
|
1188
1248
|
function Tsdraw(props) {
|
|
1189
1249
|
const [systemTheme, setSystemTheme] = react.useState(() => {
|
|
1190
1250
|
if (typeof window === "undefined") return "light";
|
|
1191
1251
|
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
1192
1252
|
});
|
|
1193
|
-
const customTools = props.customTools ??
|
|
1253
|
+
const customTools = props.customTools ?? EMPTY_CUSTOM_TOOLS;
|
|
1194
1254
|
const toolbarPartIds = props.uiOptions?.toolbar?.parts ?? DEFAULT_TOOLBAR_PARTS;
|
|
1195
1255
|
const customToolMap = react.useMemo(
|
|
1196
1256
|
() => new Map(customTools.map((customTool) => [customTool.id, customTool])),
|
|
@@ -1297,7 +1357,16 @@ function Tsdraw(props) {
|
|
|
1297
1357
|
}
|
|
1298
1358
|
);
|
|
1299
1359
|
const overlayNode = props.uiOptions?.overlays?.renderToolOverlay?.({ defaultOverlay: defaultToolOverlay, overlayState: toolOverlay, currentTool }) ?? defaultToolOverlay;
|
|
1300
|
-
const customElements = props.uiOptions?.customElements ??
|
|
1360
|
+
const customElements = props.uiOptions?.customElements ?? EMPTY_CUSTOM_ELEMENTS;
|
|
1361
|
+
const onColorSelect = react.useCallback((color) => {
|
|
1362
|
+
applyDrawStyle({ color });
|
|
1363
|
+
}, [applyDrawStyle]);
|
|
1364
|
+
const onDashSelect = react.useCallback((dash) => {
|
|
1365
|
+
applyDrawStyle({ dash });
|
|
1366
|
+
}, [applyDrawStyle]);
|
|
1367
|
+
const onSizeSelect = react.useCallback((size) => {
|
|
1368
|
+
applyDrawStyle({ size });
|
|
1369
|
+
}, [applyDrawStyle]);
|
|
1301
1370
|
const toolbarParts = react.useMemo(
|
|
1302
1371
|
() => toolbarPartIds.map((toolbarPart, partIndex) => {
|
|
1303
1372
|
const items = toolbarPart.map((item) => {
|
|
@@ -1392,9 +1461,9 @@ function Tsdraw(props) {
|
|
|
1392
1461
|
drawColor,
|
|
1393
1462
|
drawDash,
|
|
1394
1463
|
drawSize,
|
|
1395
|
-
onColorSelect
|
|
1396
|
-
onDashSelect
|
|
1397
|
-
onSizeSelect
|
|
1464
|
+
onColorSelect,
|
|
1465
|
+
onDashSelect,
|
|
1466
|
+
onSizeSelect
|
|
1398
1467
|
}
|
|
1399
1468
|
),
|
|
1400
1469
|
customElements.map((customElement) => /* @__PURE__ */ jsxRuntime.jsx(
|