@xom11/whiteboard 0.9.1 → 0.10.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/dist/{chunk-ZVN356JZ.mjs → chunk-D257NCQW.mjs} +3 -3
- package/dist/{chunk-ZVN356JZ.mjs.map → chunk-D257NCQW.mjs.map} +1 -1
- package/dist/{chunk-KEYZ5EZT.mjs → chunk-G7FR3AIV.mjs} +44 -5
- package/dist/chunk-G7FR3AIV.mjs.map +1 -0
- package/dist/chunk-PWIMZIB6.mjs +62 -0
- package/dist/chunk-PWIMZIB6.mjs.map +1 -0
- package/dist/chunk-WQOABS6N.mjs +197 -0
- package/dist/chunk-WQOABS6N.mjs.map +1 -0
- package/dist/{chunk-DU3RHKT5.mjs → chunk-YVJP7NRG.mjs} +4 -4
- package/dist/{chunk-DU3RHKT5.mjs.map → chunk-YVJP7NRG.mjs.map} +1 -1
- package/dist/geometry-2d.js +102 -18
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +2 -2
- package/dist/geometry-3d.js +152 -93
- package/dist/geometry-3d.js.map +1 -1
- package/dist/geometry-3d.mjs +2 -2
- package/dist/graph-2d.js +88 -20
- package/dist/graph-2d.js.map +1 -1
- package/dist/graph-2d.mjs +1 -1
- package/dist/{host-PIIDSMVE.mjs → host-N6ACNJKI.mjs} +51 -12
- package/dist/host-N6ACNJKI.mjs.map +1 -0
- package/dist/{host-LZH2FZ2N.mjs → host-NKGV6RF2.mjs} +91 -23
- package/dist/host-NKGV6RF2.mjs.map +1 -0
- package/dist/{host-VDNAJMLC.mjs → host-XVK7UCRE.mjs} +62 -18
- package/dist/host-XVK7UCRE.mjs.map +1 -0
- package/dist/index.d.mts +127 -1
- package/dist/index.d.ts +127 -1
- package/dist/index.js +1336 -177
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +993 -52
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
- package/dist/chunk-DU2NFHRR.mjs +0 -103
- package/dist/chunk-DU2NFHRR.mjs.map +0 -1
- package/dist/chunk-IUVV52HO.mjs +0 -144
- package/dist/chunk-IUVV52HO.mjs.map +0 -1
- package/dist/chunk-KEYZ5EZT.mjs.map +0 -1
- package/dist/host-LZH2FZ2N.mjs.map +0 -1
- package/dist/host-PIIDSMVE.mjs.map +0 -1
- package/dist/host-VDNAJMLC.mjs.map +0 -1
package/dist/geometry-2d.js
CHANGED
|
@@ -116,7 +116,17 @@ function deserializeIntoBoard(board, serialized, options = {}) {
|
|
|
116
116
|
const palette = options.palette ?? paletteFor(false);
|
|
117
117
|
const idMap = /* @__PURE__ */ new Map();
|
|
118
118
|
const resolve = (a) => {
|
|
119
|
-
if (typeof a === "string"
|
|
119
|
+
if (typeof a === "string") {
|
|
120
|
+
if (idMap.has(a)) return idMap.get(a);
|
|
121
|
+
const m = /^(.+):border:(\d+)$/.exec(a);
|
|
122
|
+
if (m) {
|
|
123
|
+
const poly = idMap.get(m[1]);
|
|
124
|
+
const idx = parseInt(m[2], 10);
|
|
125
|
+
if (poly && Array.isArray(poly.borders) && poly.borders[idx]) {
|
|
126
|
+
return poly.borders[idx];
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
120
130
|
if (Array.isArray(a)) return a.map(resolve);
|
|
121
131
|
return a;
|
|
122
132
|
};
|
|
@@ -164,6 +174,29 @@ var init_safeJsx = __esm({
|
|
|
164
174
|
});
|
|
165
175
|
|
|
166
176
|
// src/stamps/geometry-2d/render.ts
|
|
177
|
+
function containerDimsForBbox(bbox) {
|
|
178
|
+
const [xmin, ymax, xmax, ymin] = bbox;
|
|
179
|
+
const w = Math.abs(xmax - xmin);
|
|
180
|
+
const h = Math.abs(ymax - ymin);
|
|
181
|
+
if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {
|
|
182
|
+
return { width: FALLBACK_W, height: FALLBACK_H };
|
|
183
|
+
}
|
|
184
|
+
let width = w * PIXELS_PER_UNIT;
|
|
185
|
+
let height = h * PIXELS_PER_UNIT;
|
|
186
|
+
const maxAxis = Math.max(width, height);
|
|
187
|
+
if (maxAxis > MAX_DIM) {
|
|
188
|
+
const ratio = MAX_DIM / maxAxis;
|
|
189
|
+
width *= ratio;
|
|
190
|
+
height *= ratio;
|
|
191
|
+
}
|
|
192
|
+
const minAxis = Math.min(width, height);
|
|
193
|
+
if (minAxis < MIN_DIM) {
|
|
194
|
+
const ratio = MIN_DIM / minAxis;
|
|
195
|
+
width *= ratio;
|
|
196
|
+
height *= ratio;
|
|
197
|
+
}
|
|
198
|
+
return { width: Math.round(width), height: Math.round(height) };
|
|
199
|
+
}
|
|
167
200
|
async function renderGeometrySvgFromState(jsonState) {
|
|
168
201
|
const parsed = JSON.parse(jsonState);
|
|
169
202
|
const palette = paletteFor(false);
|
|
@@ -186,10 +219,11 @@ async function renderGeometrySvgFromState(jsonState) {
|
|
|
186
219
|
opts.grid.strokeColor = palette.grid;
|
|
187
220
|
}
|
|
188
221
|
});
|
|
222
|
+
const { width, height } = containerDimsForBbox(parsed.bbox);
|
|
189
223
|
const container = document.createElement("div");
|
|
190
224
|
const containerId = "jxg_offscreen_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
191
225
|
container.id = containerId;
|
|
192
|
-
container.style.cssText =
|
|
226
|
+
container.style.cssText = `position:absolute;top:-99999px;left:-99999px;width:${width}px;height:${height}px;visibility:hidden;pointer-events:none;`;
|
|
193
227
|
document.body.appendChild(container);
|
|
194
228
|
let board = null;
|
|
195
229
|
try {
|
|
@@ -199,7 +233,7 @@ async function renderGeometrySvgFromState(jsonState) {
|
|
|
199
233
|
grid: !!parsed.showGrid,
|
|
200
234
|
showCopyright: false,
|
|
201
235
|
showNavigation: false,
|
|
202
|
-
keepAspectRatio:
|
|
236
|
+
keepAspectRatio: true
|
|
203
237
|
});
|
|
204
238
|
deserializeIntoBoard(board, parsed, { palette });
|
|
205
239
|
board.update();
|
|
@@ -211,12 +245,18 @@ async function renderGeometrySvgFromState(jsonState) {
|
|
|
211
245
|
if (container.parentNode) container.parentNode.removeChild(container);
|
|
212
246
|
}
|
|
213
247
|
}
|
|
248
|
+
var PIXELS_PER_UNIT, MIN_DIM, MAX_DIM, FALLBACK_W, FALLBACK_H;
|
|
214
249
|
var init_render = __esm({
|
|
215
250
|
"src/stamps/geometry-2d/render.ts"() {
|
|
216
251
|
init_renderInline();
|
|
217
252
|
init_serialize();
|
|
218
253
|
init_theme();
|
|
219
254
|
init_safeJsx();
|
|
255
|
+
PIXELS_PER_UNIT = 20;
|
|
256
|
+
MIN_DIM = 100;
|
|
257
|
+
MAX_DIM = 1200;
|
|
258
|
+
FALLBACK_W = 400;
|
|
259
|
+
FALLBACK_H = 300;
|
|
220
260
|
}
|
|
221
261
|
});
|
|
222
262
|
|
|
@@ -313,8 +353,12 @@ function letterForGroup(g) {
|
|
|
313
353
|
}
|
|
314
354
|
function objKind(obj) {
|
|
315
355
|
if (!obj) return "other";
|
|
356
|
+
const ec = typeof obj.elementClass === "number" ? obj.elementClass : null;
|
|
357
|
+
if (ec === 1) return "point";
|
|
358
|
+
if (ec === 2) return "line";
|
|
359
|
+
if (ec === 3) return "circle";
|
|
316
360
|
const e = (obj.elType || obj.type || "").toString().toLowerCase();
|
|
317
|
-
if (e === "point" || e === "glider" || e === "midpoint") return "point";
|
|
361
|
+
if (e === "point" || e === "glider" || e === "midpoint" || e === "intersection" || e === "otherintersection" || e === "reflection" || e === "mirrorpoint" || e === "mirrorelement" || e === "orthogonalprojection" || e === "parallelpoint") return "point";
|
|
318
362
|
if (e === "line" || e === "segment" || e === "arrow" || e === "axis" || e === "normal" || e === "parallel" || e === "perpendicular" || e === "tangent" || e === "bisector" || e === "perpendicularsegment") return "line";
|
|
319
363
|
if (e === "circle" || e === "circumcircle") return "circle";
|
|
320
364
|
return "other";
|
|
@@ -514,7 +558,7 @@ function handleDown(ctx, e) {
|
|
|
514
558
|
if (!sc) return;
|
|
515
559
|
const [sx, sy] = sc;
|
|
516
560
|
const hits2 = ctx.objectsAt(e).map(ctx.promoteLabel).filter((o) => o !== ctx.axisObjsRef.current.x && o !== ctx.axisObjsRef.current.y);
|
|
517
|
-
const obj = hits2.find((o) => objKind(o) === "point") ??
|
|
561
|
+
const obj = hits2.find((o) => objKind(o) === "point") ?? ctx.findNearestPoint(e, 12) ?? hits2[0];
|
|
518
562
|
if (obj) {
|
|
519
563
|
const shift = !!(e.shiftKey || e.altKey);
|
|
520
564
|
ctx.toggleSelect(obj, shift);
|
|
@@ -757,7 +801,7 @@ function handleUp(ctx, e) {
|
|
|
757
801
|
const moved = Math.hypot(sx - start.sx, sy - start.sy);
|
|
758
802
|
if (moved > 4) return;
|
|
759
803
|
const hits = ctx.objectsAt(e).map(ctx.promoteLabel).filter((o) => o !== ctx.axisObjsRef.current.x && o !== ctx.axisObjsRef.current.y);
|
|
760
|
-
const best = hits.find((o) => objKind(o) === "point") ??
|
|
804
|
+
const best = hits.find((o) => objKind(o) === "point") ?? ctx.findNearestPoint(e, 12) ?? hits[0];
|
|
761
805
|
if (!best) {
|
|
762
806
|
ctx.lastMoveClickRef.current = { obj: null, time: 0 };
|
|
763
807
|
return;
|
|
@@ -896,8 +940,16 @@ var init_MiniBoard = __esm({
|
|
|
896
940
|
const nextLocalId = react.useCallback(() => "j" + creationLogRef.current.length, []);
|
|
897
941
|
const resolveArgs = react.useCallback((args) => {
|
|
898
942
|
return args.map((a) => {
|
|
899
|
-
if (typeof a === "string"
|
|
900
|
-
return objMapRef.current.get(a);
|
|
943
|
+
if (typeof a === "string") {
|
|
944
|
+
if (objMapRef.current.has(a)) return objMapRef.current.get(a);
|
|
945
|
+
const m = /^(.+):border:(\d+)$/.exec(a);
|
|
946
|
+
if (m) {
|
|
947
|
+
const poly = objMapRef.current.get(m[1]);
|
|
948
|
+
const idx = parseInt(m[2], 10);
|
|
949
|
+
if (poly && Array.isArray(poly.borders) && poly.borders[idx]) {
|
|
950
|
+
return poly.borders[idx];
|
|
951
|
+
}
|
|
952
|
+
}
|
|
901
953
|
}
|
|
902
954
|
return a;
|
|
903
955
|
});
|
|
@@ -927,15 +979,27 @@ var init_MiniBoard = __esm({
|
|
|
927
979
|
[nextLocalId, resolveArgs, pushLog]
|
|
928
980
|
);
|
|
929
981
|
const localIdOf = react.useCallback((obj) => {
|
|
982
|
+
if (!obj) return null;
|
|
930
983
|
for (const [id, o] of objMapRef.current.entries()) {
|
|
931
984
|
if (o === obj) return id;
|
|
932
985
|
}
|
|
986
|
+
for (const [id, o] of objMapRef.current.entries()) {
|
|
987
|
+
const borders = o?.borders;
|
|
988
|
+
if (Array.isArray(borders)) {
|
|
989
|
+
const idx = borders.indexOf(obj);
|
|
990
|
+
if (idx >= 0) return `${id}:border:${idx}`;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
933
993
|
return null;
|
|
934
994
|
}, []);
|
|
935
995
|
const snapshotObject = react.useCallback((obj, anchorScreen) => {
|
|
936
996
|
const o = obj;
|
|
937
997
|
const k = objKind(o);
|
|
938
998
|
if (k !== "point" && k !== "line" && k !== "circle") return null;
|
|
999
|
+
for (const owner of objMapRef.current.values()) {
|
|
1000
|
+
const borders = owner?.borders;
|
|
1001
|
+
if (Array.isArray(borders) && borders.indexOf(o) >= 0) return null;
|
|
1002
|
+
}
|
|
939
1003
|
const v = o.visProp ?? {};
|
|
940
1004
|
const showLabel = v.withlabel !== false;
|
|
941
1005
|
const showValue = valueLabelsRef.current.has(o);
|
|
@@ -1454,7 +1518,22 @@ var init_MiniBoard = __esm({
|
|
|
1454
1518
|
const board = boardRef.current;
|
|
1455
1519
|
if (!board) return false;
|
|
1456
1520
|
const idMap = objMapRef.current;
|
|
1457
|
-
const
|
|
1521
|
+
const resolve = (a) => {
|
|
1522
|
+
if (typeof a === "string") {
|
|
1523
|
+
if (idMap.has(a)) return idMap.get(a);
|
|
1524
|
+
const m = /^(.+):border:(\d+)$/.exec(a);
|
|
1525
|
+
if (m) {
|
|
1526
|
+
const poly = idMap.get(m[1]);
|
|
1527
|
+
const idx = parseInt(m[2], 10);
|
|
1528
|
+
if (poly && Array.isArray(poly.borders) && poly.borders[idx]) {
|
|
1529
|
+
return poly.borders[idx];
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
if (Array.isArray(a)) return a.map(resolve);
|
|
1534
|
+
return a;
|
|
1535
|
+
};
|
|
1536
|
+
const resolved = el.args.map(resolve);
|
|
1458
1537
|
try {
|
|
1459
1538
|
if (el.type === "valueLabel") {
|
|
1460
1539
|
const target = resolved[0];
|
|
@@ -2200,15 +2279,15 @@ function CloseIcon() {
|
|
|
2200
2279
|
] });
|
|
2201
2280
|
}
|
|
2202
2281
|
function UndoIcon() {
|
|
2203
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "
|
|
2204
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
2205
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3
|
|
2282
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
2283
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 10 L8 5 L8 8 L15 8 A5 5 0 0 1 20 13 L20 16" }),
|
|
2284
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 10 L8 15 L8 12" })
|
|
2206
2285
|
] });
|
|
2207
2286
|
}
|
|
2208
2287
|
function RedoIcon() {
|
|
2209
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "
|
|
2210
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
2211
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "
|
|
2288
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
2289
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 10 L16 5 L16 8 L9 8 A5 5 0 0 0 4 13 L4 16" }),
|
|
2290
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 10 L16 15 L16 12" })
|
|
2212
2291
|
] });
|
|
2213
2292
|
}
|
|
2214
2293
|
function AxisIcon() {
|
|
@@ -2968,6 +3047,7 @@ var init_EditorPanel = __esm({
|
|
|
2968
3047
|
function GeometryEditorPanel2({ initialState, onInsert, onClose, withLeftPanel = false, onStateChange, isDark, isMobile = false, onOpenDrawer, onUndo, onRedo, canUndo, canRedo }, ref) {
|
|
2969
3048
|
const handleRef = react.useRef(null);
|
|
2970
3049
|
const [ready, setReady] = react.useState(false);
|
|
3050
|
+
const [hasContent, setHasContent] = react.useState(false);
|
|
2971
3051
|
const [propsPopover, setPropsPopover] = react.useState(null);
|
|
2972
3052
|
const [transformPopover, setTransformPopover] = react.useState(null);
|
|
2973
3053
|
const onStateChangeRef = react.useRef(onStateChange);
|
|
@@ -2976,8 +3056,10 @@ var init_EditorPanel = __esm({
|
|
|
2976
3056
|
}, [onStateChange]);
|
|
2977
3057
|
const emitState = react.useCallback(() => {
|
|
2978
3058
|
const h = handleRef.current;
|
|
3059
|
+
if (!h) return;
|
|
3060
|
+
setHasContent(h.getCreationLog().length > 0);
|
|
2979
3061
|
const cb = onStateChangeRef.current;
|
|
2980
|
-
if (!
|
|
3062
|
+
if (!cb) return;
|
|
2981
3063
|
cb({
|
|
2982
3064
|
tool: h.getTool(),
|
|
2983
3065
|
showAxis: h.getShowAxis(),
|
|
@@ -3107,7 +3189,8 @@ var init_EditorPanel = __esm({
|
|
|
3107
3189
|
{
|
|
3108
3190
|
type: "button",
|
|
3109
3191
|
onClick: handleInsert,
|
|
3110
|
-
disabled: !ready,
|
|
3192
|
+
disabled: !ready || !hasContent,
|
|
3193
|
+
title: !hasContent ? "V\u1EBD \xEDt nh\u1EA5t m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng tr\u01B0\u1EDBc khi ch\xE8n" : void 0,
|
|
3111
3194
|
"data-testid": "geometry-insert-btn-mobile",
|
|
3112
3195
|
className: "rounded bg-white/15 px-3 py-1.5 text-xs font-semibold transition hover:bg-white/25 disabled:opacity-50",
|
|
3113
3196
|
children: "Ch\xE8n"
|
|
@@ -3207,7 +3290,8 @@ var init_EditorPanel = __esm({
|
|
|
3207
3290
|
"button",
|
|
3208
3291
|
{
|
|
3209
3292
|
onClick: handleInsert,
|
|
3210
|
-
disabled: !ready,
|
|
3293
|
+
disabled: !ready || !hasContent,
|
|
3294
|
+
title: !hasContent ? "V\u1EBD \xEDt nh\u1EA5t m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng tr\u01B0\u1EDBc khi ch\xE8n" : void 0,
|
|
3211
3295
|
"data-testid": "geometry-insert-btn",
|
|
3212
3296
|
className: "rounded bg-emerald-600 px-3 py-1 text-xs font-medium text-white transition hover:bg-emerald-700 disabled:opacity-50",
|
|
3213
3297
|
children: "Ch\xE8n"
|