@xom11/whiteboard 0.7.0 → 0.9.1
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/README.md +51 -1
- package/dist/chunk-74VEEZBV.mjs +619 -0
- package/dist/chunk-74VEEZBV.mjs.map +1 -0
- package/dist/chunk-DU2NFHRR.mjs +103 -0
- package/dist/chunk-DU2NFHRR.mjs.map +1 -0
- package/dist/{chunk-SHFOGORM.mjs → chunk-DU3RHKT5.mjs} +4 -4
- package/dist/{chunk-SHFOGORM.mjs.map → chunk-DU3RHKT5.mjs.map} +1 -1
- package/dist/{chunk-HYXFHEDJ.mjs → chunk-IUVV52HO.mjs} +22 -7
- package/dist/chunk-IUVV52HO.mjs.map +1 -0
- package/dist/{chunk-BJX4YNA5.mjs → chunk-KEYZ5EZT.mjs} +26 -9
- package/dist/chunk-KEYZ5EZT.mjs.map +1 -0
- package/dist/{chunk-LPM4MM45.mjs → chunk-SBDMF4NQ.mjs} +3 -2
- package/dist/chunk-SBDMF4NQ.mjs.map +1 -0
- package/dist/{chunk-3SSQKRRO.mjs → chunk-ZVN356JZ.mjs} +4 -4
- package/dist/{chunk-3SSQKRRO.mjs.map → chunk-ZVN356JZ.mjs.map} +1 -1
- package/dist/geometry-2d.js +250 -218
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +2 -2
- package/dist/geometry-3d.d.mts +1 -1
- package/dist/geometry-3d.d.ts +1 -1
- package/dist/geometry-3d.js +3276 -1201
- package/dist/geometry-3d.js.map +1 -1
- package/dist/geometry-3d.mjs +3 -2
- package/dist/graph-2d.js +360 -66
- package/dist/graph-2d.js.map +1 -1
- package/dist/graph-2d.mjs +2 -2
- package/dist/{host-2QGKMGCT.mjs → host-LZH2FZ2N.mjs} +3 -3
- package/dist/{host-2QGKMGCT.mjs.map → host-LZH2FZ2N.mjs.map} +1 -1
- package/dist/host-PIIDSMVE.mjs +3187 -0
- package/dist/host-PIIDSMVE.mjs.map +1 -0
- package/dist/{host-T2W6R6SO.mjs → host-VDNAJMLC.mjs} +221 -216
- package/dist/host-VDNAJMLC.mjs.map +1 -0
- package/dist/index.d.mts +6 -5
- package/dist/index.d.ts +6 -5
- package/dist/index.js +4365 -1821
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +246 -102
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/dist/chunk-BJX4YNA5.mjs.map +0 -1
- package/dist/chunk-DJTBZEAR.mjs +0 -25
- package/dist/chunk-DJTBZEAR.mjs.map +0 -1
- package/dist/chunk-HM7RIXJE.mjs +0 -331
- package/dist/chunk-HM7RIXJE.mjs.map +0 -1
- package/dist/chunk-HYXFHEDJ.mjs.map +0 -1
- package/dist/chunk-LPM4MM45.mjs.map +0 -1
- package/dist/host-T2W6R6SO.mjs.map +0 -1
- package/dist/host-XUFON6CQ.mjs +0 -1422
- package/dist/host-XUFON6CQ.mjs.map +0 -1
package/dist/geometry-2d.js
CHANGED
|
@@ -139,12 +139,36 @@ var init_serialize = __esm({
|
|
|
139
139
|
}
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
+
// src/stamps/shared/safeJsx.ts
|
|
143
|
+
function safeJsx(label, fn, fallback) {
|
|
144
|
+
try {
|
|
145
|
+
return fn();
|
|
146
|
+
} catch (err) {
|
|
147
|
+
if (isDev) {
|
|
148
|
+
console.warn("[whiteboard:jsxgraph]", label, err);
|
|
149
|
+
}
|
|
150
|
+
return fallback;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
var isDev;
|
|
154
|
+
var init_safeJsx = __esm({
|
|
155
|
+
"src/stamps/shared/safeJsx.ts"() {
|
|
156
|
+
isDev = (() => {
|
|
157
|
+
try {
|
|
158
|
+
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
159
|
+
} catch {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
})();
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
142
166
|
// src/stamps/geometry-2d/render.ts
|
|
143
167
|
async function renderGeometrySvgFromState(jsonState) {
|
|
144
168
|
const parsed = JSON.parse(jsonState);
|
|
145
169
|
const palette = paletteFor(false);
|
|
146
170
|
const JXG = (await import('jsxgraph')).default;
|
|
147
|
-
|
|
171
|
+
safeJsx("render.applyOptions", () => {
|
|
148
172
|
const opts = JXG.Options;
|
|
149
173
|
if (opts) {
|
|
150
174
|
opts.text = opts.text || {};
|
|
@@ -161,8 +185,7 @@ async function renderGeometrySvgFromState(jsonState) {
|
|
|
161
185
|
opts.grid = opts.grid || {};
|
|
162
186
|
opts.grid.strokeColor = palette.grid;
|
|
163
187
|
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
188
|
+
});
|
|
166
189
|
const container = document.createElement("div");
|
|
167
190
|
const containerId = "jxg_offscreen_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
168
191
|
container.id = containerId;
|
|
@@ -182,10 +205,9 @@ async function renderGeometrySvgFromState(jsonState) {
|
|
|
182
205
|
board.update();
|
|
183
206
|
return renderGeometryToSvg(container);
|
|
184
207
|
} finally {
|
|
185
|
-
|
|
208
|
+
safeJsx("render.freeBoard", () => {
|
|
186
209
|
if (board) JXG.JSXGraph.freeBoard(board);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
210
|
+
});
|
|
189
211
|
if (container.parentNode) container.parentNode.removeChild(container);
|
|
190
212
|
}
|
|
191
213
|
}
|
|
@@ -194,6 +216,7 @@ var init_render = __esm({
|
|
|
194
216
|
init_renderInline();
|
|
195
217
|
init_serialize();
|
|
196
218
|
init_theme();
|
|
219
|
+
init_safeJsx();
|
|
197
220
|
}
|
|
198
221
|
});
|
|
199
222
|
|
|
@@ -529,14 +552,8 @@ function handleDown(ctx, e) {
|
|
|
529
552
|
const tmp1 = ctx.boardRef.current.create("intersection", [a, b, 1], { visible: false, withLabel: false });
|
|
530
553
|
const d0 = Math.hypot((tmp0.X?.() ?? 0) - x, (tmp0.Y?.() ?? 0) - y);
|
|
531
554
|
const d1 = Math.hypot((tmp1.X?.() ?? 0) - x, (tmp1.Y?.() ?? 0) - y);
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
} catch {
|
|
535
|
-
}
|
|
536
|
-
try {
|
|
537
|
-
ctx.boardRef.current.removeObject(tmp1);
|
|
538
|
-
} catch {
|
|
539
|
-
}
|
|
555
|
+
safeJsx("handlers.removeObject(intersect.tmp0)", () => ctx.boardRef.current.removeObject(tmp0));
|
|
556
|
+
safeJsx("handlers.removeObject(intersect.tmp1)", () => ctx.boardRef.current.removeObject(tmp1));
|
|
540
557
|
const idx = d0 <= d1 ? 0 : 1;
|
|
541
558
|
ctx.create("intersection", [aId, bId, idx], attrs);
|
|
542
559
|
}
|
|
@@ -573,7 +590,7 @@ function handleDown(ctx, e) {
|
|
|
573
590
|
})();
|
|
574
591
|
if (ctx.pendingRef.current.length > 0 && ctx.boardRef.current) {
|
|
575
592
|
const prev = ctx.pendingRef.current[ctx.pendingRef.current.length - 1];
|
|
576
|
-
|
|
593
|
+
safeJsx("handlers.createPreviewSegment", () => {
|
|
577
594
|
const seg = ctx.boardRef.current.create("segment", [prev, pick2], {
|
|
578
595
|
strokeColor: "#3b82f6",
|
|
579
596
|
strokeWidth: 1.5,
|
|
@@ -583,8 +600,7 @@ function handleDown(ctx, e) {
|
|
|
583
600
|
withLabel: false
|
|
584
601
|
});
|
|
585
602
|
ctx.previewSegRef.current.push(seg);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
603
|
+
});
|
|
588
604
|
}
|
|
589
605
|
ctx.pendingRef.current.push(pick2);
|
|
590
606
|
ctx.setPendingCount(ctx.pendingRef.current.length);
|
|
@@ -695,10 +711,7 @@ function handleUp(ctx, e) {
|
|
|
695
711
|
if (!sc2) return;
|
|
696
712
|
const [ex, ey] = sc2;
|
|
697
713
|
if (mq.rect) {
|
|
698
|
-
|
|
699
|
-
ctx.boardRef.current?.removeObject(mq.rect);
|
|
700
|
-
} catch {
|
|
701
|
-
}
|
|
714
|
+
safeJsx("handlers.removeObject(marquee.rect)", () => ctx.boardRef.current?.removeObject(mq.rect));
|
|
702
715
|
}
|
|
703
716
|
if (Math.hypot(ex - mq.startSx, ey - mq.startSy) < 4) return;
|
|
704
717
|
const x1 = Math.min(mq.startSx, ex), x2 = Math.max(mq.startSx, ex);
|
|
@@ -731,10 +744,7 @@ function handleUp(ctx, e) {
|
|
|
731
744
|
}
|
|
732
745
|
}
|
|
733
746
|
ctx.setSelectionTick((tt) => tt + 1);
|
|
734
|
-
|
|
735
|
-
board.update();
|
|
736
|
-
} catch {
|
|
737
|
-
}
|
|
747
|
+
safeJsx("handlers.board.update(marquee)", () => board.update());
|
|
738
748
|
return;
|
|
739
749
|
}
|
|
740
750
|
if (t !== "move") return;
|
|
@@ -781,12 +791,9 @@ function handleMove(ctx, e) {
|
|
|
781
791
|
const [x2u, y2u] = ux2 && ux2.length >= 2 ? [ux2[0], ux2[1]] : toUsr(Math.max(startSx, sx), Math.max(startSy, sy));
|
|
782
792
|
const rect = ctx.marqueeRef.current.rect;
|
|
783
793
|
if (rect) {
|
|
784
|
-
|
|
785
|
-
ctx.boardRef.current.removeObject(rect);
|
|
786
|
-
} catch {
|
|
787
|
-
}
|
|
794
|
+
safeJsx("handlers.removeObject(marquee.prevRect)", () => ctx.boardRef.current.removeObject(rect));
|
|
788
795
|
}
|
|
789
|
-
|
|
796
|
+
safeJsx("handlers.createMarqueePolygon", () => {
|
|
790
797
|
ctx.marqueeRef.current.rect = ctx.boardRef.current.create("polygon", [
|
|
791
798
|
[x1u, y1u],
|
|
792
799
|
[x2u, y1u],
|
|
@@ -801,8 +808,7 @@ function handleMove(ctx, e) {
|
|
|
801
808
|
highlight: false,
|
|
802
809
|
withLabel: false
|
|
803
810
|
});
|
|
804
|
-
}
|
|
805
|
-
}
|
|
811
|
+
});
|
|
806
812
|
}
|
|
807
813
|
return;
|
|
808
814
|
}
|
|
@@ -812,20 +818,20 @@ function handleMove(ctx, e) {
|
|
|
812
818
|
ctx.previewRafRef.current = requestAnimationFrame(() => {
|
|
813
819
|
ctx.previewRafRef.current = null;
|
|
814
820
|
if (!ctx.boardRef.current || !ctx.phantomRef.current) return;
|
|
815
|
-
|
|
821
|
+
safeJsx("handlers.phantomMove", () => {
|
|
816
822
|
const coords = ctx.boardRef.current.getUsrCoordsOfMouse(e);
|
|
817
823
|
const JXG = ctx.jxgRef.current;
|
|
818
824
|
if (!JXG) return;
|
|
819
825
|
ctx.phantomRef.current.setPositionDirectly(JXG.COORDS_BY_USER, [coords[0], coords[1]]);
|
|
820
826
|
ctx.boardRef.current.update();
|
|
821
|
-
}
|
|
822
|
-
}
|
|
827
|
+
});
|
|
823
828
|
});
|
|
824
829
|
}
|
|
825
830
|
var init_handlers = __esm({
|
|
826
831
|
"src/stamps/geometry-2d/editor/handlers.ts"() {
|
|
827
832
|
init_tools();
|
|
828
833
|
init_transforms();
|
|
834
|
+
init_safeJsx();
|
|
829
835
|
}
|
|
830
836
|
});
|
|
831
837
|
var JSXGraphMiniBoard;
|
|
@@ -836,6 +842,7 @@ var init_MiniBoard = __esm({
|
|
|
836
842
|
init_tools();
|
|
837
843
|
init_theme();
|
|
838
844
|
init_handlers();
|
|
845
|
+
init_safeJsx();
|
|
839
846
|
JSXGraphMiniBoard = ({ onReady, initialState, isDark }) => {
|
|
840
847
|
const isDarkRef = react.useRef(!!isDark);
|
|
841
848
|
isDarkRef.current = !!isDark;
|
|
@@ -845,6 +852,7 @@ var init_MiniBoard = __esm({
|
|
|
845
852
|
const jxgRef = react.useRef(null);
|
|
846
853
|
const axisObjsRef = react.useRef({});
|
|
847
854
|
const creationLogRef = react.useRef([]);
|
|
855
|
+
const redoStackRef = react.useRef([]);
|
|
848
856
|
const [tool, setTool] = react.useState("move");
|
|
849
857
|
const toolRef = react.useRef("move");
|
|
850
858
|
toolRef.current = tool;
|
|
@@ -894,13 +902,17 @@ var init_MiniBoard = __esm({
|
|
|
894
902
|
return a;
|
|
895
903
|
});
|
|
896
904
|
}, []);
|
|
905
|
+
const pushCreationLog = react.useCallback((entry) => {
|
|
906
|
+
creationLogRef.current.push(entry);
|
|
907
|
+
redoStackRef.current = [];
|
|
908
|
+
}, []);
|
|
897
909
|
const pushLog = react.useCallback(
|
|
898
910
|
(id, type, args, attrs, obj) => {
|
|
899
|
-
|
|
911
|
+
pushCreationLog({ id, type, args, attrs });
|
|
900
912
|
objMapRef.current.set(id, obj);
|
|
901
913
|
setHistoryTick((t) => t + 1);
|
|
902
914
|
},
|
|
903
|
-
[]
|
|
915
|
+
[pushCreationLog]
|
|
904
916
|
);
|
|
905
917
|
const create = react.useCallback(
|
|
906
918
|
(type, args, attrs = {}) => {
|
|
@@ -983,16 +995,10 @@ var init_MiniBoard = __esm({
|
|
|
983
995
|
if (patch.remove) {
|
|
984
996
|
const vl = valueLabelsRef.current.get(o);
|
|
985
997
|
if (vl) {
|
|
986
|
-
|
|
987
|
-
boardRef.current.removeObject(vl);
|
|
988
|
-
} catch {
|
|
989
|
-
}
|
|
998
|
+
safeJsx("MiniBoard.removeObject(valueLabel)", () => boardRef.current.removeObject(vl));
|
|
990
999
|
valueLabelsRef.current.delete(o);
|
|
991
1000
|
}
|
|
992
|
-
|
|
993
|
-
boardRef.current.removeObject(o);
|
|
994
|
-
} catch {
|
|
995
|
-
}
|
|
1001
|
+
safeJsx("MiniBoard.removeObject(target)", () => boardRef.current.removeObject(o));
|
|
996
1002
|
const board = boardRef.current;
|
|
997
1003
|
const aliveIds = /* @__PURE__ */ new Set();
|
|
998
1004
|
for (const [id, obj2] of objMapRef.current.entries()) {
|
|
@@ -1017,7 +1023,7 @@ var init_MiniBoard = __esm({
|
|
|
1017
1023
|
const targetId = localIdOf(o);
|
|
1018
1024
|
if (targetId) {
|
|
1019
1025
|
const id = nextLocalId();
|
|
1020
|
-
|
|
1026
|
+
pushCreationLog({ id, type: "valueLabel", args: [targetId], attrs: {} });
|
|
1021
1027
|
objMapRef.current.set(id, txt);
|
|
1022
1028
|
setHistoryTick((t) => t + 1);
|
|
1023
1029
|
}
|
|
@@ -1026,10 +1032,7 @@ var init_MiniBoard = __esm({
|
|
|
1026
1032
|
const txt = valueLabelsRef.current.get(o);
|
|
1027
1033
|
valueLabelsRef.current.delete(o);
|
|
1028
1034
|
if (txt) {
|
|
1029
|
-
|
|
1030
|
-
boardRef.current.removeObject(txt);
|
|
1031
|
-
} catch {
|
|
1032
|
-
}
|
|
1035
|
+
safeJsx("MiniBoard.removeObject(valueLabel.text)", () => boardRef.current.removeObject(txt));
|
|
1033
1036
|
const txtId = localIdOf(txt);
|
|
1034
1037
|
if (txtId) {
|
|
1035
1038
|
creationLogRef.current = creationLogRef.current.filter((e) => e.id !== txtId);
|
|
@@ -1040,10 +1043,7 @@ var init_MiniBoard = __esm({
|
|
|
1040
1043
|
}
|
|
1041
1044
|
}
|
|
1042
1045
|
if (patch.attrs) {
|
|
1043
|
-
|
|
1044
|
-
o.setAttribute(patch.attrs);
|
|
1045
|
-
} catch {
|
|
1046
|
-
}
|
|
1046
|
+
safeJsx("MiniBoard.setAttribute", () => o.setAttribute(patch.attrs));
|
|
1047
1047
|
const id = localIdOf(o);
|
|
1048
1048
|
if (id) {
|
|
1049
1049
|
const entry = creationLogRef.current.find((e) => e.id === id);
|
|
@@ -1051,19 +1051,13 @@ var init_MiniBoard = __esm({
|
|
|
1051
1051
|
setHistoryTick((t) => t + 1);
|
|
1052
1052
|
}
|
|
1053
1053
|
}
|
|
1054
|
-
|
|
1055
|
-
boardRef.current.update();
|
|
1056
|
-
} catch {
|
|
1057
|
-
}
|
|
1054
|
+
safeJsx("MiniBoard.board.update(mutate)", () => boardRef.current.update());
|
|
1058
1055
|
}, [createValueLabelFor, localIdOf, nextLocalId]);
|
|
1059
1056
|
const clearPreviewSegs = react.useCallback(() => {
|
|
1060
1057
|
const b = boardRef.current;
|
|
1061
1058
|
if (!b) return;
|
|
1062
1059
|
for (const s of previewSegRef.current) {
|
|
1063
|
-
|
|
1064
|
-
b.removeObject(s);
|
|
1065
|
-
} catch {
|
|
1066
|
-
}
|
|
1060
|
+
safeJsx("MiniBoard.removeObject(previewSeg)", () => b.removeObject(s));
|
|
1067
1061
|
}
|
|
1068
1062
|
previewSegRef.current = [];
|
|
1069
1063
|
}, []);
|
|
@@ -1071,17 +1065,11 @@ var init_MiniBoard = __esm({
|
|
|
1071
1065
|
const b = boardRef.current;
|
|
1072
1066
|
if (!b) return;
|
|
1073
1067
|
if (previewShapeRef.current) {
|
|
1074
|
-
|
|
1075
|
-
b.removeObject(previewShapeRef.current);
|
|
1076
|
-
} catch {
|
|
1077
|
-
}
|
|
1068
|
+
safeJsx("MiniBoard.removeObject(previewShape)", () => b.removeObject(previewShapeRef.current));
|
|
1078
1069
|
previewShapeRef.current = null;
|
|
1079
1070
|
}
|
|
1080
1071
|
if (phantomRef.current) {
|
|
1081
|
-
|
|
1082
|
-
b.removeObject(phantomRef.current);
|
|
1083
|
-
} catch {
|
|
1084
|
-
}
|
|
1072
|
+
safeJsx("MiniBoard.removeObject(phantom)", () => b.removeObject(phantomRef.current));
|
|
1085
1073
|
phantomRef.current = null;
|
|
1086
1074
|
}
|
|
1087
1075
|
}, []);
|
|
@@ -1093,7 +1081,7 @@ var init_MiniBoard = __esm({
|
|
|
1093
1081
|
}, [clearPreviewSegs, removePhantom]);
|
|
1094
1082
|
const applySelectionStyle = react.useCallback((obj) => {
|
|
1095
1083
|
if (!obj || selOriginalRef.current.has(obj)) return;
|
|
1096
|
-
|
|
1084
|
+
safeJsx("MiniBoard.applySelectionStyle", () => {
|
|
1097
1085
|
const visProp = obj.visProp ?? {};
|
|
1098
1086
|
selOriginalRef.current.set(obj, {
|
|
1099
1087
|
strokeColor: visProp.strokecolor,
|
|
@@ -1105,19 +1093,17 @@ var init_MiniBoard = __esm({
|
|
|
1105
1093
|
} else {
|
|
1106
1094
|
obj.setAttribute({ strokeColor: "#06b6d4", strokeWidth: 3 });
|
|
1107
1095
|
}
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1096
|
+
});
|
|
1110
1097
|
}, []);
|
|
1111
1098
|
const restoreSelectionStyle = react.useCallback((obj) => {
|
|
1112
1099
|
const orig = selOriginalRef.current.get(obj);
|
|
1113
1100
|
if (!orig) return;
|
|
1114
|
-
|
|
1101
|
+
safeJsx("MiniBoard.restoreSelectionStyle", () => {
|
|
1115
1102
|
const attrs = {};
|
|
1116
1103
|
if (orig.strokeColor !== void 0) attrs.strokeColor = orig.strokeColor;
|
|
1117
1104
|
if (orig.strokeWidth !== void 0) attrs.strokeWidth = orig.strokeWidth;
|
|
1118
1105
|
obj.setAttribute(attrs);
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1106
|
+
});
|
|
1121
1107
|
selOriginalRef.current.delete(obj);
|
|
1122
1108
|
}, []);
|
|
1123
1109
|
const clearSelection = react.useCallback(() => {
|
|
@@ -1126,10 +1112,7 @@ var init_MiniBoard = __esm({
|
|
|
1126
1112
|
}
|
|
1127
1113
|
selectedSetRef.current.clear();
|
|
1128
1114
|
setSelectionTick((t) => t + 1);
|
|
1129
|
-
|
|
1130
|
-
boardRef.current?.update();
|
|
1131
|
-
} catch {
|
|
1132
|
-
}
|
|
1115
|
+
safeJsx("MiniBoard.board.update(clearSelection)", () => boardRef.current?.update());
|
|
1133
1116
|
}, [restoreSelectionStyle]);
|
|
1134
1117
|
const toggleSelect = react.useCallback((obj, additive) => {
|
|
1135
1118
|
if (!obj) return;
|
|
@@ -1149,10 +1132,7 @@ var init_MiniBoard = __esm({
|
|
|
1149
1132
|
}
|
|
1150
1133
|
}
|
|
1151
1134
|
setSelectionTick((t) => t + 1);
|
|
1152
|
-
|
|
1153
|
-
boardRef.current?.update();
|
|
1154
|
-
} catch {
|
|
1155
|
-
}
|
|
1135
|
+
safeJsx("MiniBoard.board.update(toggleSelect)", () => boardRef.current?.update());
|
|
1156
1136
|
}, [applySelectionStyle, restoreSelectionStyle]);
|
|
1157
1137
|
const deleteSelected = react.useCallback(() => {
|
|
1158
1138
|
const board = boardRef.current;
|
|
@@ -1160,10 +1140,7 @@ var init_MiniBoard = __esm({
|
|
|
1160
1140
|
if (selectedSetRef.current.size === 0) return;
|
|
1161
1141
|
for (const o of selectedSetRef.current) selOriginalRef.current.delete(o);
|
|
1162
1142
|
for (const o of selectedSetRef.current) {
|
|
1163
|
-
|
|
1164
|
-
board.removeObject(o);
|
|
1165
|
-
} catch {
|
|
1166
|
-
}
|
|
1143
|
+
safeJsx("MiniBoard.removeObject(selected)", () => board.removeObject(o));
|
|
1167
1144
|
}
|
|
1168
1145
|
selectedSetRef.current.clear();
|
|
1169
1146
|
const aliveIds = /* @__PURE__ */ new Set();
|
|
@@ -1236,10 +1213,7 @@ var init_MiniBoard = __esm({
|
|
|
1236
1213
|
const b = boardRef.current;
|
|
1237
1214
|
if (!b) return;
|
|
1238
1215
|
if (previewShapeRef.current) {
|
|
1239
|
-
|
|
1240
|
-
b.removeObject(previewShapeRef.current);
|
|
1241
|
-
} catch {
|
|
1242
|
-
}
|
|
1216
|
+
safeJsx("MiniBoard.removeObject(refreshPreview)", () => b.removeObject(previewShapeRef.current));
|
|
1243
1217
|
previewShapeRef.current = null;
|
|
1244
1218
|
}
|
|
1245
1219
|
const t = toolRef.current;
|
|
@@ -1358,7 +1332,7 @@ var init_MiniBoard = __esm({
|
|
|
1358
1332
|
}
|
|
1359
1333
|
case "toggleLabel": {
|
|
1360
1334
|
const obj = picks[0];
|
|
1361
|
-
|
|
1335
|
+
safeJsx("MiniBoard.toggleLabel", () => {
|
|
1362
1336
|
if (obj.label) {
|
|
1363
1337
|
const visible = obj.label.visProp.visible !== false;
|
|
1364
1338
|
obj.label.setAttribute({ visible: !visible });
|
|
@@ -1367,23 +1341,21 @@ var init_MiniBoard = __esm({
|
|
|
1367
1341
|
obj.setAttribute({ withLabel: !cur });
|
|
1368
1342
|
}
|
|
1369
1343
|
boardRef.current.update();
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1344
|
+
});
|
|
1372
1345
|
break;
|
|
1373
1346
|
}
|
|
1374
1347
|
case "toggleVisible": {
|
|
1375
1348
|
const obj = picks[0];
|
|
1376
|
-
|
|
1349
|
+
safeJsx("MiniBoard.toggleVisible", () => {
|
|
1377
1350
|
const visible = obj.visProp.visible !== false;
|
|
1378
1351
|
obj.setAttribute({ visible: !visible });
|
|
1379
1352
|
boardRef.current.update();
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1353
|
+
});
|
|
1382
1354
|
break;
|
|
1383
1355
|
}
|
|
1384
1356
|
case "delete": {
|
|
1385
1357
|
const obj = picks[0];
|
|
1386
|
-
|
|
1358
|
+
safeJsx("MiniBoard.deleteOne", () => {
|
|
1387
1359
|
boardRef.current.removeObject(obj);
|
|
1388
1360
|
const board = boardRef.current;
|
|
1389
1361
|
const aliveIds = /* @__PURE__ */ new Set();
|
|
@@ -1398,8 +1370,7 @@ var init_MiniBoard = __esm({
|
|
|
1398
1370
|
if (!aliveIds.has(id)) objMapRef.current.delete(id);
|
|
1399
1371
|
}
|
|
1400
1372
|
setHistoryTick((t) => t + 1);
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1373
|
+
});
|
|
1403
1374
|
break;
|
|
1404
1375
|
}
|
|
1405
1376
|
}
|
|
@@ -1434,7 +1405,7 @@ var init_MiniBoard = __esm({
|
|
|
1434
1405
|
}
|
|
1435
1406
|
const stepId = nextLocalId();
|
|
1436
1407
|
const stepObj = boardRef.current.create("transform", step.params, step.attrs);
|
|
1437
|
-
|
|
1408
|
+
pushCreationLog({ id: stepId, type: "transform", args: stepLogArgs, attrs: step.attrs });
|
|
1438
1409
|
objMapRef.current.set(stepId, stepObj);
|
|
1439
1410
|
transformObjs.push(stepObj);
|
|
1440
1411
|
transformIds.push(stepId);
|
|
@@ -1448,7 +1419,7 @@ var init_MiniBoard = __esm({
|
|
|
1448
1419
|
const newName = srcName ? `${srcName}'` : nextLabel();
|
|
1449
1420
|
const attrs = { name: newName, size: 3, color: "#0ea5e9", strokeColor: "#0ea5e9", fillColor: "#0ea5e9" };
|
|
1450
1421
|
const obj = boardRef.current.create("point", [src, transformParent], attrs);
|
|
1451
|
-
|
|
1422
|
+
pushCreationLog({ id, type: "point", args: [srcId ?? src, transformLogRef], attrs });
|
|
1452
1423
|
objMapRef.current.set(id, obj);
|
|
1453
1424
|
return obj;
|
|
1454
1425
|
});
|
|
@@ -1479,6 +1450,30 @@ var init_MiniBoard = __esm({
|
|
|
1479
1450
|
}
|
|
1480
1451
|
setHistoryTick((t) => t + 1);
|
|
1481
1452
|
}, [create, flashWarn, localIdOf, nextLabel, nextLocalId]);
|
|
1453
|
+
const recreateFromLogEntry = react.useCallback((el) => {
|
|
1454
|
+
const board = boardRef.current;
|
|
1455
|
+
if (!board) return false;
|
|
1456
|
+
const idMap = objMapRef.current;
|
|
1457
|
+
const resolved = el.args.map((a) => typeof a === "string" && idMap.has(a) ? idMap.get(a) : a);
|
|
1458
|
+
try {
|
|
1459
|
+
if (el.type === "valueLabel") {
|
|
1460
|
+
const target = resolved[0];
|
|
1461
|
+
if (!target) return false;
|
|
1462
|
+
const txt = createValueLabelFor(target);
|
|
1463
|
+
if (!txt) return false;
|
|
1464
|
+
idMap.set(el.id, txt);
|
|
1465
|
+
valueLabelsRef.current.set(target, txt);
|
|
1466
|
+
return true;
|
|
1467
|
+
}
|
|
1468
|
+
const themedAttrs = resolveAttrColors({ ...el.attrs }, paletteFor(isDarkRef.current));
|
|
1469
|
+
const obj = board.create(el.type, resolved, themedAttrs);
|
|
1470
|
+
idMap.set(el.id, obj);
|
|
1471
|
+
return true;
|
|
1472
|
+
} catch (err) {
|
|
1473
|
+
console.warn("Recreate failed for", el.type, err);
|
|
1474
|
+
return false;
|
|
1475
|
+
}
|
|
1476
|
+
}, [createValueLabelFor]);
|
|
1482
1477
|
const undoLast = react.useCallback(() => {
|
|
1483
1478
|
const b = boardRef.current;
|
|
1484
1479
|
if (!b) return;
|
|
@@ -1488,21 +1483,31 @@ var init_MiniBoard = __esm({
|
|
|
1488
1483
|
const obj = objMapRef.current.get(last.id);
|
|
1489
1484
|
objMapRef.current.delete(last.id);
|
|
1490
1485
|
if (obj) {
|
|
1491
|
-
|
|
1492
|
-
b.removeObject(obj);
|
|
1493
|
-
} catch {
|
|
1494
|
-
}
|
|
1486
|
+
safeJsx("MiniBoard.removeObject(undo)", () => b.removeObject(obj));
|
|
1495
1487
|
clearPending();
|
|
1488
|
+
redoStackRef.current.push(last);
|
|
1496
1489
|
setHistoryTick((t) => t + 1);
|
|
1497
|
-
|
|
1498
|
-
b.update();
|
|
1499
|
-
} catch {
|
|
1500
|
-
}
|
|
1490
|
+
safeJsx("MiniBoard.board.update(undo)", () => b.update());
|
|
1501
1491
|
return;
|
|
1502
1492
|
}
|
|
1503
1493
|
}
|
|
1504
1494
|
setHistoryTick((t) => t + 1);
|
|
1505
1495
|
}, [clearPending]);
|
|
1496
|
+
const redoNext = react.useCallback(() => {
|
|
1497
|
+
const b = boardRef.current;
|
|
1498
|
+
if (!b) return;
|
|
1499
|
+
const entry = redoStackRef.current.pop();
|
|
1500
|
+
if (!entry) {
|
|
1501
|
+
setHistoryTick((t) => t + 1);
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
const ok = recreateFromLogEntry(entry);
|
|
1505
|
+
if (ok) {
|
|
1506
|
+
creationLogRef.current.push(entry);
|
|
1507
|
+
}
|
|
1508
|
+
setHistoryTick((t) => t + 1);
|
|
1509
|
+
safeJsx("MiniBoard.board.update(redo)", () => b.update());
|
|
1510
|
+
}, [recreateFromLogEntry]);
|
|
1506
1511
|
react.useEffect(() => {
|
|
1507
1512
|
const onKey = (e) => {
|
|
1508
1513
|
const ae = document.activeElement;
|
|
@@ -1514,6 +1519,13 @@ var init_MiniBoard = __esm({
|
|
|
1514
1519
|
undoLastRef.current();
|
|
1515
1520
|
return;
|
|
1516
1521
|
}
|
|
1522
|
+
if ((e.metaKey || e.ctrlKey) && (e.key.toLowerCase() === "z" && e.shiftKey || e.key.toLowerCase() === "y" && !e.shiftKey)) {
|
|
1523
|
+
if (inField) return;
|
|
1524
|
+
e.preventDefault();
|
|
1525
|
+
e.stopPropagation();
|
|
1526
|
+
redoNextRef.current();
|
|
1527
|
+
return;
|
|
1528
|
+
}
|
|
1517
1529
|
if (e.key === "Escape" && !inField) {
|
|
1518
1530
|
if (pendingRef.current.length > 0) {
|
|
1519
1531
|
e.preventDefault();
|
|
@@ -1560,16 +1572,14 @@ var init_MiniBoard = __esm({
|
|
|
1560
1572
|
if (!sc) return [];
|
|
1561
1573
|
const [sx, sy] = sc;
|
|
1562
1574
|
const list = [];
|
|
1563
|
-
|
|
1575
|
+
safeJsx("MiniBoard.objectsAt.loop", () => {
|
|
1564
1576
|
const objs = b.objectsList || [];
|
|
1565
1577
|
for (const o of objs) {
|
|
1566
|
-
|
|
1578
|
+
safeJsx("MiniBoard.objectsAt.hasPoint", () => {
|
|
1567
1579
|
if (o.hasPoint && o.hasPoint(sx, sy)) list.push(o);
|
|
1568
|
-
}
|
|
1569
|
-
}
|
|
1580
|
+
});
|
|
1570
1581
|
}
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1582
|
+
});
|
|
1573
1583
|
return list;
|
|
1574
1584
|
}, [screenCoordsOf]);
|
|
1575
1585
|
const findNearestPoint = react.useCallback((evt, tolPx = 12) => {
|
|
@@ -1579,24 +1589,23 @@ var init_MiniBoard = __esm({
|
|
|
1579
1589
|
if (!sc) return null;
|
|
1580
1590
|
const [sx, sy] = sc;
|
|
1581
1591
|
const tol2 = tolPx * tolPx;
|
|
1582
|
-
|
|
1583
|
-
|
|
1592
|
+
const bestRef = { current: null };
|
|
1593
|
+
safeJsx("MiniBoard.findNearestPoint.loop", () => {
|
|
1584
1594
|
const objs = b.objectsList || [];
|
|
1585
1595
|
for (const o of objs) {
|
|
1586
|
-
|
|
1587
|
-
if (objKind(o) !== "point")
|
|
1596
|
+
safeJsx("MiniBoard.findNearestPoint.iter", () => {
|
|
1597
|
+
if (objKind(o) !== "point") return;
|
|
1588
1598
|
const pc = o.coords?.scrCoords;
|
|
1589
|
-
if (!pc)
|
|
1599
|
+
if (!pc) return;
|
|
1590
1600
|
const dx = pc[1] - sx;
|
|
1591
1601
|
const dy = pc[2] - sy;
|
|
1592
1602
|
const d2 = dx * dx + dy * dy;
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
}
|
|
1603
|
+
const cur = bestRef.current;
|
|
1604
|
+
if (d2 <= tol2 && (!cur || d2 < cur.d2)) bestRef.current = { obj: o, d2 };
|
|
1605
|
+
});
|
|
1596
1606
|
}
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
return best ? best.obj : null;
|
|
1607
|
+
});
|
|
1608
|
+
return bestRef.current ? bestRef.current.obj : null;
|
|
1600
1609
|
}, [screenCoordsOf]);
|
|
1601
1610
|
const promoteLabel = react.useCallback((o) => {
|
|
1602
1611
|
if (!o) return o;
|
|
@@ -1604,31 +1613,25 @@ var init_MiniBoard = __esm({
|
|
|
1604
1613
|
if (t !== "text") return o;
|
|
1605
1614
|
const b = boardRef.current;
|
|
1606
1615
|
if (!b) return o;
|
|
1607
|
-
|
|
1616
|
+
const promoted = safeJsx("MiniBoard.promoteLabel", () => {
|
|
1608
1617
|
for (const c of b.objectsList || []) {
|
|
1609
1618
|
if (c.label === o) return c;
|
|
1610
1619
|
}
|
|
1611
|
-
|
|
1612
|
-
}
|
|
1613
|
-
return o;
|
|
1620
|
+
return null;
|
|
1621
|
+
}, null);
|
|
1622
|
+
return promoted ?? o;
|
|
1614
1623
|
}, []);
|
|
1615
1624
|
const pendingTransformRef = react.useRef(null);
|
|
1616
1625
|
const transformSubsRef = react.useRef(/* @__PURE__ */ new Set());
|
|
1617
1626
|
const emitTransform = react.useCallback((info) => {
|
|
1618
1627
|
transformSubsRef.current.forEach((cb) => {
|
|
1619
|
-
|
|
1620
|
-
cb(info);
|
|
1621
|
-
} catch {
|
|
1622
|
-
}
|
|
1628
|
+
safeJsx("MiniBoard.emitTransform.cb", () => cb(info));
|
|
1623
1629
|
});
|
|
1624
1630
|
}, []);
|
|
1625
1631
|
const selectSubsRef = react.useRef(/* @__PURE__ */ new Set());
|
|
1626
1632
|
const emitSelect = react.useCallback((snap) => {
|
|
1627
1633
|
selectSubsRef.current.forEach((cb) => {
|
|
1628
|
-
|
|
1629
|
-
cb(snap);
|
|
1630
|
-
} catch {
|
|
1631
|
-
}
|
|
1634
|
+
safeJsx("MiniBoard.emitSelect.cb", () => cb(snap));
|
|
1632
1635
|
});
|
|
1633
1636
|
}, []);
|
|
1634
1637
|
const moveDownRef = react.useRef(null);
|
|
@@ -1640,7 +1643,7 @@ var init_MiniBoard = __esm({
|
|
|
1640
1643
|
const JXG = (await import('jsxgraph')).default;
|
|
1641
1644
|
if (cancelled || !containerRef.current) return;
|
|
1642
1645
|
jxgRef.current = JXG;
|
|
1643
|
-
|
|
1646
|
+
safeJsx("MiniBoard.applyJxgOptions", () => {
|
|
1644
1647
|
const opts = JXG.Options;
|
|
1645
1648
|
if (opts) {
|
|
1646
1649
|
opts.text = opts.text || {};
|
|
@@ -1653,8 +1656,7 @@ var init_MiniBoard = __esm({
|
|
|
1653
1656
|
opts.label.strokeColor = themeLabel(isDarkRef.current);
|
|
1654
1657
|
opts.text.strokeColor = themeLabel(isDarkRef.current);
|
|
1655
1658
|
}
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1659
|
+
});
|
|
1658
1660
|
const board = JXG.JSXGraph.initBoard(containerId, {
|
|
1659
1661
|
boundingbox: initialState?.bbox ?? [-10, 10, 10, -10],
|
|
1660
1662
|
axis: false,
|
|
@@ -1675,43 +1677,20 @@ var init_MiniBoard = __esm({
|
|
|
1675
1677
|
});
|
|
1676
1678
|
boardRef.current = board;
|
|
1677
1679
|
if (initialState && initialState.elements.length > 0) {
|
|
1678
|
-
const idMap = objMapRef.current;
|
|
1679
1680
|
for (const el of initialState.elements) {
|
|
1680
|
-
|
|
1681
|
-
try {
|
|
1682
|
-
if (el.type === "valueLabel") {
|
|
1683
|
-
const target = resolved[0];
|
|
1684
|
-
if (target) {
|
|
1685
|
-
const txt = createValueLabelFor(target);
|
|
1686
|
-
if (txt) {
|
|
1687
|
-
idMap.set(el.id, txt);
|
|
1688
|
-
valueLabelsRef.current.set(target, txt);
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
continue;
|
|
1692
|
-
}
|
|
1693
|
-
const themedAttrs = resolveAttrColors({ ...el.attrs }, paletteFor(isDarkRef.current));
|
|
1694
|
-
const obj = board.create(el.type, resolved, themedAttrs);
|
|
1695
|
-
idMap.set(el.id, obj);
|
|
1696
|
-
} catch (err) {
|
|
1697
|
-
console.warn("Replay failed for", el.type, err);
|
|
1698
|
-
}
|
|
1681
|
+
recreateFromLogEntry(el);
|
|
1699
1682
|
}
|
|
1700
1683
|
creationLogRef.current = [...initialState.elements];
|
|
1701
1684
|
labelIdxRef.current = initialState.elements.filter((e) => e.type === "point").length;
|
|
1702
1685
|
}
|
|
1703
1686
|
if (showAxisRef.current) {
|
|
1704
|
-
|
|
1687
|
+
safeJsx("MiniBoard.initAxes", () => {
|
|
1705
1688
|
axisObjsRef.current.x = board.create("axis", [[0, 0], [1, 0]], { strokeColor: themeAxis(isDarkRef.current), name: "", withLabel: false });
|
|
1706
1689
|
axisObjsRef.current.y = board.create("axis", [[0, 0], [0, 1]], { strokeColor: themeAxis(isDarkRef.current), name: "", withLabel: false });
|
|
1707
|
-
}
|
|
1708
|
-
}
|
|
1690
|
+
});
|
|
1709
1691
|
}
|
|
1710
1692
|
if (showGridRef.current) {
|
|
1711
|
-
|
|
1712
|
-
board.create("grid", [], { strokeColor: themeGrid(isDarkRef.current), strokeOpacity: 1 });
|
|
1713
|
-
} catch {
|
|
1714
|
-
}
|
|
1693
|
+
safeJsx("MiniBoard.initGrid", () => board.create("grid", [], { strokeColor: themeGrid(isDarkRef.current), strokeOpacity: 1 }));
|
|
1715
1694
|
}
|
|
1716
1695
|
board.on("down", (e) => {
|
|
1717
1696
|
const ctx = {
|
|
@@ -1862,6 +1841,8 @@ var init_MiniBoard = __esm({
|
|
|
1862
1841
|
setShowGrid: (b) => setShowGridRef.current(b),
|
|
1863
1842
|
undo: () => undoLastRef.current(),
|
|
1864
1843
|
canUndo: () => creationLogRef.current.length > 0,
|
|
1844
|
+
redo: () => redoNextRef.current(),
|
|
1845
|
+
canRedo: () => redoStackRef.current.length > 0,
|
|
1865
1846
|
subscribe: (cb) => {
|
|
1866
1847
|
subscribersRef.current.add(cb);
|
|
1867
1848
|
return () => {
|
|
@@ -1874,15 +1855,14 @@ var init_MiniBoard = __esm({
|
|
|
1874
1855
|
const b = boardRef.current;
|
|
1875
1856
|
if (!b) return [];
|
|
1876
1857
|
const out = [];
|
|
1877
|
-
|
|
1858
|
+
safeJsx("MiniBoard.getAllPointNames", () => {
|
|
1878
1859
|
const objs = b.objectsList || [];
|
|
1879
1860
|
for (const o of objs) {
|
|
1880
1861
|
if (objKind(o) === "point" && typeof o.name === "string" && o.name) {
|
|
1881
1862
|
out.push(o.name);
|
|
1882
1863
|
}
|
|
1883
1864
|
}
|
|
1884
|
-
}
|
|
1885
|
-
}
|
|
1865
|
+
});
|
|
1886
1866
|
return out;
|
|
1887
1867
|
},
|
|
1888
1868
|
onSelect: (cb) => {
|
|
@@ -1943,10 +1923,7 @@ var init_MiniBoard = __esm({
|
|
|
1943
1923
|
previewRafRef.current = null;
|
|
1944
1924
|
}
|
|
1945
1925
|
if (boardRef.current && jxgRef.current) {
|
|
1946
|
-
|
|
1947
|
-
jxgRef.current.JSXGraph.freeBoard(boardRef.current);
|
|
1948
|
-
} catch {
|
|
1949
|
-
}
|
|
1926
|
+
safeJsx("MiniBoard.freeBoard", () => jxgRef.current.JSXGraph.freeBoard(boardRef.current));
|
|
1950
1927
|
boardRef.current = null;
|
|
1951
1928
|
}
|
|
1952
1929
|
};
|
|
@@ -1954,19 +1931,13 @@ var init_MiniBoard = __esm({
|
|
|
1954
1931
|
react.useEffect(() => {
|
|
1955
1932
|
const b = boardRef.current;
|
|
1956
1933
|
if (!b) return;
|
|
1957
|
-
|
|
1934
|
+
safeJsx("MiniBoard.toggleAxis", () => {
|
|
1958
1935
|
if (axisObjsRef.current.x) {
|
|
1959
|
-
|
|
1960
|
-
b.removeObject(axisObjsRef.current.x);
|
|
1961
|
-
} catch {
|
|
1962
|
-
}
|
|
1936
|
+
safeJsx("MiniBoard.removeObject(axisX)", () => b.removeObject(axisObjsRef.current.x));
|
|
1963
1937
|
axisObjsRef.current.x = void 0;
|
|
1964
1938
|
}
|
|
1965
1939
|
if (axisObjsRef.current.y) {
|
|
1966
|
-
|
|
1967
|
-
b.removeObject(axisObjsRef.current.y);
|
|
1968
|
-
} catch {
|
|
1969
|
-
}
|
|
1940
|
+
safeJsx("MiniBoard.removeObject(axisY)", () => b.removeObject(axisObjsRef.current.y));
|
|
1970
1941
|
axisObjsRef.current.y = void 0;
|
|
1971
1942
|
}
|
|
1972
1943
|
if (showAxis) {
|
|
@@ -1974,28 +1945,23 @@ var init_MiniBoard = __esm({
|
|
|
1974
1945
|
axisObjsRef.current.y = b.create("axis", [[0, 0], [0, 1]], { strokeColor: themeAxis(isDarkRef.current), name: "", withLabel: false });
|
|
1975
1946
|
}
|
|
1976
1947
|
b.update();
|
|
1977
|
-
}
|
|
1978
|
-
}
|
|
1948
|
+
});
|
|
1979
1949
|
}, [showAxis]);
|
|
1980
1950
|
react.useEffect(() => {
|
|
1981
1951
|
const b = boardRef.current;
|
|
1982
1952
|
if (!b) return;
|
|
1983
|
-
|
|
1953
|
+
safeJsx("MiniBoard.toggleGrid", () => {
|
|
1984
1954
|
const objs = Object.values(b.objects || {});
|
|
1985
1955
|
for (const o of objs) {
|
|
1986
1956
|
if (o && (o.elType === "grid" || o.type === "grid" || o.visProp && o.visProp.type === "grid")) {
|
|
1987
|
-
|
|
1988
|
-
b.removeObject(o);
|
|
1989
|
-
} catch {
|
|
1990
|
-
}
|
|
1957
|
+
safeJsx("MiniBoard.removeObject(grid)", () => b.removeObject(o));
|
|
1991
1958
|
}
|
|
1992
1959
|
}
|
|
1993
1960
|
if (showGrid) {
|
|
1994
1961
|
b.create("grid", [], { strokeColor: themeGrid(isDarkRef.current), strokeOpacity: 1 });
|
|
1995
1962
|
}
|
|
1996
1963
|
b.update();
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1964
|
+
});
|
|
1999
1965
|
}, [showGrid]);
|
|
2000
1966
|
const handleToolChange = react.useCallback((t) => {
|
|
2001
1967
|
clearPending();
|
|
@@ -2003,10 +1969,9 @@ var init_MiniBoard = __esm({
|
|
|
2003
1969
|
setTool(t);
|
|
2004
1970
|
const b = boardRef.current;
|
|
2005
1971
|
if (b) {
|
|
2006
|
-
|
|
1972
|
+
safeJsx("MiniBoard.setPanForTool", () => {
|
|
2007
1973
|
if (b.attr?.pan) b.attr.pan.enabled = t !== "select";
|
|
2008
|
-
}
|
|
2009
|
-
}
|
|
1974
|
+
});
|
|
2010
1975
|
}
|
|
2011
1976
|
}, [clearPending]);
|
|
2012
1977
|
const handleToolChangeRef = react.useRef(handleToolChange);
|
|
@@ -2014,10 +1979,7 @@ var init_MiniBoard = __esm({
|
|
|
2014
1979
|
const subscribersRef = react.useRef(/* @__PURE__ */ new Set());
|
|
2015
1980
|
const notifySubscribers = react.useCallback(() => {
|
|
2016
1981
|
subscribersRef.current.forEach((cb) => {
|
|
2017
|
-
|
|
2018
|
-
cb();
|
|
2019
|
-
} catch {
|
|
2020
|
-
}
|
|
1982
|
+
safeJsx("MiniBoard.notifySubscriber.cb", () => cb());
|
|
2021
1983
|
});
|
|
2022
1984
|
}, []);
|
|
2023
1985
|
react.useEffect(() => {
|
|
@@ -2025,6 +1987,8 @@ var init_MiniBoard = __esm({
|
|
|
2025
1987
|
}, [tool, showAxis, showGrid, historyTick, notifySubscribers]);
|
|
2026
1988
|
const undoLastRef = react.useRef(undoLast);
|
|
2027
1989
|
undoLastRef.current = undoLast;
|
|
1990
|
+
const redoNextRef = react.useRef(redoNext);
|
|
1991
|
+
redoNextRef.current = redoNext;
|
|
2028
1992
|
const clearPendingRef = react.useRef(clearPending);
|
|
2029
1993
|
clearPendingRef.current = clearPending;
|
|
2030
1994
|
const finalizeTransformCreateRef = react.useRef(finalizeTransformCreate);
|
|
@@ -2135,6 +2099,7 @@ function MobileToolDrawer({
|
|
|
2135
2099
|
disabled: a.disabled,
|
|
2136
2100
|
"aria-label": a.label,
|
|
2137
2101
|
title: a.title ?? a.label,
|
|
2102
|
+
"data-testid": a.testId,
|
|
2138
2103
|
className: "inline-flex h-9 w-9 items-center justify-center rounded-full text-slate-600 transition hover:bg-slate-100 hover:text-slate-900 disabled:cursor-not-allowed disabled:text-slate-300 disabled:hover:bg-transparent",
|
|
2139
2104
|
children: a.icon
|
|
2140
2105
|
},
|
|
@@ -2240,6 +2205,12 @@ function UndoIcon() {
|
|
|
2240
2205
|
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.51 13a9 9 0 1 0 2.13-9.36L3 7" })
|
|
2241
2206
|
] });
|
|
2242
2207
|
}
|
|
2208
|
+
function RedoIcon() {
|
|
2209
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2210
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "21 7 21 13 15 13" }),
|
|
2211
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20.49 13a9 9 0 1 1-2.13-9.36L21 7" })
|
|
2212
|
+
] });
|
|
2213
|
+
}
|
|
2243
2214
|
function AxisIcon() {
|
|
2244
2215
|
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2245
2216
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "20", x2: "20", y2: "20" }),
|
|
@@ -2284,7 +2255,7 @@ function useToolHoverTooltip() {
|
|
|
2284
2255
|
return { hover, portalReady, showHover, hideHover };
|
|
2285
2256
|
}
|
|
2286
2257
|
function DesktopGeometryPanel(props) {
|
|
2287
|
-
const { activeTool, onToolChange, showAxis, showGrid, onShowAxisChange, onShowGridChange, onUndo, canUndo, onClose, isDark, chordGroup } = props;
|
|
2258
|
+
const { activeTool, onToolChange, showAxis, showGrid, onShowAxisChange, onShowGridChange, onUndo, canUndo, onRedo, canRedo, onClose, isDark, chordGroup } = props;
|
|
2288
2259
|
const grouped = react.useMemo(() => {
|
|
2289
2260
|
return TOOLS.reduce((acc, t) => {
|
|
2290
2261
|
var _a;
|
|
@@ -2333,9 +2304,23 @@ function DesktopGeometryPanel(props) {
|
|
|
2333
2304
|
disabled: !canUndo,
|
|
2334
2305
|
title: "Ho\xE0n t\xE1c (Ctrl/Cmd+Z)",
|
|
2335
2306
|
"aria-label": "Ho\xE0n t\xE1c",
|
|
2307
|
+
"data-testid": "undo-btn",
|
|
2336
2308
|
className: "ml-auto inline-flex items-center justify-center rounded p-1 text-slate-600 transition hover:bg-slate-100 hover:text-slate-900 disabled:cursor-not-allowed disabled:text-slate-300 disabled:hover:bg-transparent",
|
|
2337
2309
|
children: /* @__PURE__ */ jsxRuntime.jsx(UndoIcon, {})
|
|
2338
2310
|
}
|
|
2311
|
+
),
|
|
2312
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2313
|
+
"button",
|
|
2314
|
+
{
|
|
2315
|
+
type: "button",
|
|
2316
|
+
onClick: onRedo,
|
|
2317
|
+
disabled: !canRedo,
|
|
2318
|
+
title: "L\xE0m l\u1EA1i (Ctrl/Cmd+Shift+Z)",
|
|
2319
|
+
"aria-label": "L\xE0m l\u1EA1i",
|
|
2320
|
+
"data-testid": "redo-btn",
|
|
2321
|
+
className: "inline-flex items-center justify-center rounded p-1 text-slate-600 transition hover:bg-slate-100 hover:text-slate-900 disabled:cursor-not-allowed disabled:text-slate-300 disabled:hover:bg-transparent",
|
|
2322
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RedoIcon, {})
|
|
2323
|
+
}
|
|
2339
2324
|
)
|
|
2340
2325
|
] }) }),
|
|
2341
2326
|
groupKeys.map((group) => {
|
|
@@ -2456,6 +2441,8 @@ function MobileGeometryPanel(props) {
|
|
|
2456
2441
|
onShowGridChange,
|
|
2457
2442
|
onUndo,
|
|
2458
2443
|
canUndo,
|
|
2444
|
+
onRedo,
|
|
2445
|
+
canRedo,
|
|
2459
2446
|
isDark,
|
|
2460
2447
|
drawerOpen,
|
|
2461
2448
|
onDrawerClose
|
|
@@ -2504,6 +2491,13 @@ function MobileGeometryPanel(props) {
|
|
|
2504
2491
|
icon: /* @__PURE__ */ jsxRuntime.jsx(UndoIcon, {}),
|
|
2505
2492
|
onClick: onUndo,
|
|
2506
2493
|
disabled: !canUndo
|
|
2494
|
+
},
|
|
2495
|
+
{
|
|
2496
|
+
label: "L\xE0m l\u1EA1i",
|
|
2497
|
+
title: "L\xE0m l\u1EA1i (Ctrl/Cmd+Shift+Z)",
|
|
2498
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(RedoIcon, {}),
|
|
2499
|
+
onClick: onRedo,
|
|
2500
|
+
disabled: !canRedo
|
|
2507
2501
|
}
|
|
2508
2502
|
],
|
|
2509
2503
|
groups,
|
|
@@ -2969,8 +2963,9 @@ var init_EditorPanel = __esm({
|
|
|
2969
2963
|
init_render();
|
|
2970
2964
|
init_PropertiesPopover();
|
|
2971
2965
|
init_TransformParamPopover();
|
|
2966
|
+
init_LeftPanel();
|
|
2972
2967
|
GeometryEditorPanel = react.forwardRef(
|
|
2973
|
-
function GeometryEditorPanel2({ initialState, onInsert, onClose, withLeftPanel = false, onStateChange, isDark, isMobile = false, onOpenDrawer }, ref) {
|
|
2968
|
+
function GeometryEditorPanel2({ initialState, onInsert, onClose, withLeftPanel = false, onStateChange, isDark, isMobile = false, onOpenDrawer, onUndo, onRedo, canUndo, canRedo }, ref) {
|
|
2974
2969
|
const handleRef = react.useRef(null);
|
|
2975
2970
|
const [ready, setReady] = react.useState(false);
|
|
2976
2971
|
const [propsPopover, setPropsPopover] = react.useState(null);
|
|
@@ -2987,7 +2982,8 @@ var init_EditorPanel = __esm({
|
|
|
2987
2982
|
tool: h.getTool(),
|
|
2988
2983
|
showAxis: h.getShowAxis(),
|
|
2989
2984
|
showGrid: h.getShowGrid(),
|
|
2990
|
-
canUndo: h.canUndo()
|
|
2985
|
+
canUndo: h.canUndo(),
|
|
2986
|
+
canRedo: h.canRedo()
|
|
2991
2987
|
});
|
|
2992
2988
|
}, []);
|
|
2993
2989
|
const handleReady = react.useCallback((h) => {
|
|
@@ -3029,6 +3025,7 @@ var init_EditorPanel = __esm({
|
|
|
3029
3025
|
setShowAxis: (b) => handleRef.current?.setShowAxis(b),
|
|
3030
3026
|
setShowGrid: (b) => handleRef.current?.setShowGrid(b),
|
|
3031
3027
|
undo: () => handleRef.current?.undo(),
|
|
3028
|
+
redo: () => handleRef.current?.redo(),
|
|
3032
3029
|
insert: performInsert,
|
|
3033
3030
|
hasContent: () => (handleRef.current?.getCreationLog().length ?? 0) > 0
|
|
3034
3031
|
}), [performInsert]);
|
|
@@ -3078,17 +3075,45 @@ var init_EditorPanel = __esm({
|
|
|
3078
3075
|
] }),
|
|
3079
3076
|
"D\u1EF1ng h\xECnh h\u1ECDc"
|
|
3080
3077
|
] }),
|
|
3081
|
-
isMobile && /* @__PURE__ */ jsxRuntime.
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3078
|
+
isMobile && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3079
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3080
|
+
"button",
|
|
3081
|
+
{
|
|
3082
|
+
type: "button",
|
|
3083
|
+
onClick: onUndo,
|
|
3084
|
+
disabled: !canUndo,
|
|
3085
|
+
"aria-label": "Ho\xE0n t\xE1c",
|
|
3086
|
+
title: "Ho\xE0n t\xE1c (Ctrl/Cmd+Z)",
|
|
3087
|
+
"data-testid": "undo-btn-mobile",
|
|
3088
|
+
className: "inline-flex h-9 w-9 items-center justify-center rounded transition hover:bg-white/15 disabled:opacity-40",
|
|
3089
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(UndoIcon, {})
|
|
3090
|
+
}
|
|
3091
|
+
),
|
|
3092
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3093
|
+
"button",
|
|
3094
|
+
{
|
|
3095
|
+
type: "button",
|
|
3096
|
+
onClick: onRedo,
|
|
3097
|
+
disabled: !canRedo,
|
|
3098
|
+
"aria-label": "L\xE0m l\u1EA1i",
|
|
3099
|
+
title: "L\xE0m l\u1EA1i (Ctrl/Cmd+Shift+Z)",
|
|
3100
|
+
"data-testid": "redo-btn-mobile",
|
|
3101
|
+
className: "inline-flex h-9 w-9 items-center justify-center rounded transition hover:bg-white/15 disabled:opacity-40",
|
|
3102
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RedoIcon, {})
|
|
3103
|
+
}
|
|
3104
|
+
),
|
|
3105
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3106
|
+
"button",
|
|
3107
|
+
{
|
|
3108
|
+
type: "button",
|
|
3109
|
+
onClick: handleInsert,
|
|
3110
|
+
disabled: !ready,
|
|
3111
|
+
"data-testid": "geometry-insert-btn-mobile",
|
|
3112
|
+
className: "rounded bg-white/15 px-3 py-1.5 text-xs font-semibold transition hover:bg-white/25 disabled:opacity-50",
|
|
3113
|
+
children: "Ch\xE8n"
|
|
3114
|
+
}
|
|
3115
|
+
)
|
|
3116
|
+
] }),
|
|
3092
3117
|
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onClose, "aria-label": "\u0110\xF3ng", className: "inline-flex h-9 w-9 items-center justify-center rounded transition hover:bg-white/15", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3093
3118
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" }),
|
|
3094
3119
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" })
|
|
@@ -3410,7 +3435,8 @@ var init_host = __esm({
|
|
|
3410
3435
|
tool: "move",
|
|
3411
3436
|
showAxis: false,
|
|
3412
3437
|
showGrid: false,
|
|
3413
|
-
canUndo: false
|
|
3438
|
+
canUndo: false,
|
|
3439
|
+
canRedo: false
|
|
3414
3440
|
};
|
|
3415
3441
|
GeometryStampHost = react.forwardRef(
|
|
3416
3442
|
function GeometryStampHost2({ api, editingElement, onClose, isDark }, ref) {
|
|
@@ -3476,6 +3502,8 @@ var init_host = __esm({
|
|
|
3476
3502
|
onShowGridChange: (b) => panelRef.current?.setShowGrid(b),
|
|
3477
3503
|
onUndo: () => panelRef.current?.undo(),
|
|
3478
3504
|
canUndo: geomState.canUndo,
|
|
3505
|
+
onRedo: () => panelRef.current?.redo(),
|
|
3506
|
+
canRedo: geomState.canRedo,
|
|
3479
3507
|
onClose,
|
|
3480
3508
|
isDark,
|
|
3481
3509
|
isMobile,
|
|
@@ -3495,7 +3523,11 @@ var init_host = __esm({
|
|
|
3495
3523
|
withLeftPanel: !isMobile,
|
|
3496
3524
|
isDark,
|
|
3497
3525
|
isMobile,
|
|
3498
|
-
onOpenDrawer: () => setDrawerOpen(true)
|
|
3526
|
+
onOpenDrawer: () => setDrawerOpen(true),
|
|
3527
|
+
onUndo: () => panelRef.current?.undo(),
|
|
3528
|
+
onRedo: () => panelRef.current?.redo(),
|
|
3529
|
+
canUndo: geomState.canUndo,
|
|
3530
|
+
canRedo: geomState.canRedo
|
|
3499
3531
|
}
|
|
3500
3532
|
)
|
|
3501
3533
|
] });
|