@xom11/whiteboard 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai.d.mts +236 -295
- package/dist/ai.d.ts +236 -295
- package/dist/ai.js +6015 -7577
- package/dist/ai.js.map +1 -1
- package/dist/ai.mjs +4804 -5426
- package/dist/ai.mjs.map +1 -1
- package/dist/catalog.json +4 -4
- package/dist/{chunk-D5JLJ3PT.mjs → chunk-5JM35CXV.mjs} +4 -4
- package/dist/{chunk-D5JLJ3PT.mjs.map → chunk-5JM35CXV.mjs.map} +1 -1
- package/dist/{chunk-KYMBUTPO.mjs → chunk-BU5KLO3P.mjs} +3 -3
- package/dist/{chunk-KYMBUTPO.mjs.map → chunk-BU5KLO3P.mjs.map} +1 -1
- package/dist/{chunk-AJAHD35N.mjs → chunk-E6EDOPGT.mjs} +3 -105
- package/dist/chunk-E6EDOPGT.mjs.map +1 -0
- package/dist/{chunk-KZGPSTZI.mjs → chunk-GEC2D2EQ.mjs} +4 -4
- package/dist/{chunk-KZGPSTZI.mjs.map → chunk-GEC2D2EQ.mjs.map} +1 -1
- package/dist/{chunk-AYJPOHCI.mjs → chunk-H22OZYTW.mjs} +3 -3
- package/dist/{chunk-AYJPOHCI.mjs.map → chunk-H22OZYTW.mjs.map} +1 -1
- package/dist/{chunk-I3L56GVH.mjs → chunk-OQIQNKPQ.mjs} +3 -3
- package/dist/{chunk-I3L56GVH.mjs.map → chunk-OQIQNKPQ.mjs.map} +1 -1
- package/dist/{chunk-4ETJ4CDY.mjs → chunk-QRUAEXLR.mjs} +4 -4
- package/dist/{chunk-4ETJ4CDY.mjs.map → chunk-QRUAEXLR.mjs.map} +1 -1
- package/dist/{chunk-HLAOGXEK.mjs → chunk-V3YJ6JFL.mjs} +3 -3
- package/dist/{chunk-HLAOGXEK.mjs.map → chunk-V3YJ6JFL.mjs.map} +1 -1
- package/dist/{chunk-D5LWSN2Y.mjs → chunk-ZTQBUKLJ.mjs} +30 -13
- package/dist/chunk-ZTQBUKLJ.mjs.map +1 -0
- package/dist/geometry-2d.d.mts +1 -2
- package/dist/geometry-2d.d.ts +1 -2
- package/dist/geometry-2d.js +961 -3586
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +3 -3
- package/dist/geometry-3d.d.mts +1 -2
- package/dist/geometry-3d.d.ts +1 -2
- package/dist/geometry-3d.js +28 -11
- package/dist/geometry-3d.js.map +1 -1
- package/dist/geometry-3d.mjs +3 -3
- package/dist/graph-2d.d.mts +1 -2
- package/dist/graph-2d.d.ts +1 -2
- package/dist/graph-2d.js +28 -11
- package/dist/graph-2d.js.map +1 -1
- package/dist/graph-2d.mjs +3 -3
- package/dist/{host-M26FS244.mjs → host-2ISGVO7O.mjs} +5 -5
- package/dist/{host-M26FS244.mjs.map → host-2ISGVO7O.mjs.map} +1 -1
- package/dist/{host-HAYCJJ2T.mjs → host-HKMZSCIT.mjs} +142 -318
- package/dist/host-HKMZSCIT.mjs.map +1 -0
- package/dist/{host-LTJHAY5A.mjs → host-HOSJHQ5H.mjs} +6 -6
- package/dist/{host-LTJHAY5A.mjs.map → host-HOSJHQ5H.mjs.map} +1 -1
- package/dist/index.d.mts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.js +913 -3540
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +17 -16
- package/dist/index.mjs.map +1 -1
- package/dist/latex.d.mts +1 -2
- package/dist/latex.d.ts +1 -2
- package/dist/serialize-N4G6RFBB.mjs +9 -0
- package/dist/{serialize-C3LSUMSA.mjs.map → serialize-N4G6RFBB.mjs.map} +1 -1
- package/dist/{types-zc_Pa0mp.d.ts → types-C3FjpoUi.d.mts} +22 -229
- package/dist/{types-zc_Pa0mp.d.mts → types-C3FjpoUi.d.ts} +22 -229
- package/package.json +1 -9
- package/dist/chunk-AJAHD35N.mjs.map +0 -1
- package/dist/chunk-D5LWSN2Y.mjs.map +0 -1
- package/dist/chunk-T3SOHYB2.mjs +0 -851
- package/dist/chunk-T3SOHYB2.mjs.map +0 -1
- package/dist/handleExtractProblem-C-U5KluK.d.mts +0 -158
- package/dist/handleExtractProblem-C-U5KluK.d.ts +0 -158
- package/dist/host-HAYCJJ2T.mjs.map +0 -1
- package/dist/serialize-C3LSUMSA.mjs +0 -9
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useChordShortcut } from './chunk-HNQLZIEP.mjs';
|
|
3
3
|
import { useToolStateMachine } from './chunk-NVJ7K3DK.mjs';
|
|
4
|
-
import { safeJsx, initJxgBoard, attachJxgWheelZoom, useToast, ToastHost, STAMP_PANEL_DESKTOP, ToastProvider, useStampStore, StampLeftPanel, ObjectRow } from './chunk-
|
|
5
|
-
import { serializeBoard, renderGeometrySvgFromState, isGeometryCustomData, deserializeBoard } from './chunk-
|
|
4
|
+
import { safeJsx, initJxgBoard, attachJxgWheelZoom, useToast, ToastHost, STAMP_PANEL_DESKTOP, ToastProvider, useStampStore, StampLeftPanel, ObjectRow } from './chunk-OQIQNKPQ.mjs';
|
|
5
|
+
import { serializeBoard, renderGeometrySvgFromState, isGeometryCustomData, deserializeBoard } from './chunk-H22OZYTW.mjs';
|
|
6
6
|
import { themeLabel, paletteFor, themeAxis, themeGrid } from './chunk-R5FL6S7L.mjs';
|
|
7
7
|
import { JxgRenderer } from './chunk-SZDAS7LK.mjs';
|
|
8
8
|
import './chunk-ICR4CVOE.mjs';
|
|
9
|
-
import { nextLabel, useEditorState, listObjects } from './chunk-
|
|
9
|
+
import { nextLabel, useEditorState, listObjects } from './chunk-ZTQBUKLJ.mjs';
|
|
10
10
|
import './chunk-IHUFOV7L.mjs';
|
|
11
|
-
import {
|
|
12
|
-
import { handleExtractProblem } from './chunk-T3SOHYB2.mjs';
|
|
11
|
+
import { describeDsl } from './chunk-E6EDOPGT.mjs';
|
|
13
12
|
import { DEFAULT_VIEW_2D } from './chunk-73Q7ADVL.mjs';
|
|
14
13
|
import './chunk-B4NJJZFR.mjs';
|
|
15
14
|
import { useIsMobile } from './chunk-P2AOIF7S.mjs';
|
|
16
15
|
import { insertStampImage } from './chunk-QGNU34T7.mjs';
|
|
17
16
|
import './chunk-5UTGXHLJ.mjs';
|
|
18
17
|
import { __export } from './chunk-J5LGTIGS.mjs';
|
|
19
|
-
import { forwardRef, useRef, useId, useState, useEffect, useCallback, useImperativeHandle,
|
|
18
|
+
import { forwardRef, useRef, useId, useState, useEffect, useCallback, useImperativeHandle, useMemo, useLayoutEffect } from 'react';
|
|
20
19
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
21
20
|
import { createPortal } from 'react-dom';
|
|
22
21
|
|
|
@@ -3268,41 +3267,13 @@ var TransformParamPopover = ({ kind, anchor, defaultValue, onConfirm, onCancel,
|
|
|
3268
3267
|
);
|
|
3269
3268
|
return createPortal(node, document.body);
|
|
3270
3269
|
};
|
|
3271
|
-
function useAiFigure(generator
|
|
3272
|
-
const { currentState } = options;
|
|
3270
|
+
function useAiFigure(generator) {
|
|
3273
3271
|
const [prompt, setPrompt] = useState("");
|
|
3274
3272
|
const [isLoading, setIsLoading] = useState(false);
|
|
3275
3273
|
const [error, setError] = useState(null);
|
|
3276
3274
|
const [tokens, setTokens] = useState(0);
|
|
3277
3275
|
const abortRef = useRef(null);
|
|
3278
3276
|
const requestIdRef = useRef(0);
|
|
3279
|
-
const { dsl: currentDsl, unsupported, entityCount, hasContent } = useMemo(() => {
|
|
3280
|
-
if (!currentState || currentState.order.length === 0) {
|
|
3281
|
-
return {
|
|
3282
|
-
dsl: null,
|
|
3283
|
-
unsupported: [],
|
|
3284
|
-
entityCount: { points: 0, shapes: 0 },
|
|
3285
|
-
hasContent: false
|
|
3286
|
-
};
|
|
3287
|
-
}
|
|
3288
|
-
const { dsl, unsupported: unsupported2 } = serializeState(currentState);
|
|
3289
|
-
return {
|
|
3290
|
-
dsl,
|
|
3291
|
-
unsupported: unsupported2,
|
|
3292
|
-
entityCount: { points: dsl.points.length, shapes: dsl.shapes.length },
|
|
3293
|
-
hasContent: true
|
|
3294
|
-
};
|
|
3295
|
-
}, [currentState]);
|
|
3296
|
-
const hasUnsupported = unsupported.length > 0;
|
|
3297
|
-
const initialMode = hasContent && !hasUnsupported ? "refine" : "build";
|
|
3298
|
-
const [mode, setModeInternal] = useState(initialMode);
|
|
3299
|
-
useEffect(() => {
|
|
3300
|
-
if (!hasContent && mode === "refine") setModeInternal("build");
|
|
3301
|
-
if (hasUnsupported && mode === "refine") setModeInternal("build");
|
|
3302
|
-
}, [hasContent, hasUnsupported, mode]);
|
|
3303
|
-
const setMode = useCallback((next) => {
|
|
3304
|
-
setModeInternal(next);
|
|
3305
|
-
}, []);
|
|
3306
3277
|
useEffect(() => () => abortRef.current?.abort(), []);
|
|
3307
3278
|
const submit = useCallback(async () => {
|
|
3308
3279
|
const problem = prompt.trim();
|
|
@@ -3326,8 +3297,7 @@ function useAiFigure(generator, options = {}) {
|
|
|
3326
3297
|
signal: controller.signal,
|
|
3327
3298
|
onProgress: (info) => {
|
|
3328
3299
|
if (requestId === requestIdRef.current) setTokens(info.tokens);
|
|
3329
|
-
}
|
|
3330
|
-
...mode === "refine" && currentDsl ? { currentDsl } : {}
|
|
3300
|
+
}
|
|
3331
3301
|
});
|
|
3332
3302
|
if (controller.signal.aborted || requestId !== requestIdRef.current) return null;
|
|
3333
3303
|
if (!generated.ok) {
|
|
@@ -3351,7 +3321,7 @@ function useAiFigure(generator, options = {}) {
|
|
|
3351
3321
|
setIsLoading(false);
|
|
3352
3322
|
}
|
|
3353
3323
|
}
|
|
3354
|
-
}, [generator, prompt
|
|
3324
|
+
}, [generator, prompt]);
|
|
3355
3325
|
const cancel = useCallback(() => {
|
|
3356
3326
|
abortRef.current?.abort();
|
|
3357
3327
|
}, []);
|
|
@@ -3362,27 +3332,9 @@ function useAiFigure(generator, options = {}) {
|
|
|
3362
3332
|
error,
|
|
3363
3333
|
submit,
|
|
3364
3334
|
cancel,
|
|
3365
|
-
tokens
|
|
3366
|
-
mode,
|
|
3367
|
-
setMode,
|
|
3368
|
-
entityCount,
|
|
3369
|
-
hasUnsupported
|
|
3335
|
+
tokens
|
|
3370
3336
|
};
|
|
3371
3337
|
}
|
|
3372
|
-
var PaperclipIcon = (props) => /* @__PURE__ */ jsx(
|
|
3373
|
-
"svg",
|
|
3374
|
-
{
|
|
3375
|
-
viewBox: "0 0 24 24",
|
|
3376
|
-
fill: "none",
|
|
3377
|
-
stroke: "currentColor",
|
|
3378
|
-
strokeWidth: 1.75,
|
|
3379
|
-
strokeLinecap: "round",
|
|
3380
|
-
strokeLinejoin: "round",
|
|
3381
|
-
"aria-hidden": true,
|
|
3382
|
-
...props,
|
|
3383
|
-
children: /* @__PURE__ */ jsx("path", { d: "M21.44 11.05 12.25 20.24a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66L9.41 17.41a2 2 0 1 1-2.83-2.83l8.49-8.49" })
|
|
3384
|
-
}
|
|
3385
|
-
);
|
|
3386
3338
|
var ArrowUpIcon = (props) => /* @__PURE__ */ jsxs(
|
|
3387
3339
|
"svg",
|
|
3388
3340
|
{
|
|
@@ -3401,12 +3353,7 @@ var ArrowUpIcon = (props) => /* @__PURE__ */ jsxs(
|
|
|
3401
3353
|
}
|
|
3402
3354
|
);
|
|
3403
3355
|
var StopIcon = (props) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsx("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) });
|
|
3404
|
-
function AiFigurePrompt({
|
|
3405
|
-
generator,
|
|
3406
|
-
onGenerated,
|
|
3407
|
-
currentState,
|
|
3408
|
-
extractProblem = handleExtractProblem
|
|
3409
|
-
}) {
|
|
3356
|
+
function AiFigurePrompt({ generator, onGenerated }) {
|
|
3410
3357
|
const {
|
|
3411
3358
|
prompt,
|
|
3412
3359
|
setPrompt,
|
|
@@ -3414,12 +3361,8 @@ function AiFigurePrompt({
|
|
|
3414
3361
|
error,
|
|
3415
3362
|
submit,
|
|
3416
3363
|
cancel,
|
|
3417
|
-
tokens
|
|
3418
|
-
|
|
3419
|
-
setMode,
|
|
3420
|
-
entityCount,
|
|
3421
|
-
hasUnsupported
|
|
3422
|
-
} = useAiFigure(generator, { currentState });
|
|
3364
|
+
tokens
|
|
3365
|
+
} = useAiFigure(generator);
|
|
3423
3366
|
const [elapsed, setElapsed] = useState(0);
|
|
3424
3367
|
useEffect(() => {
|
|
3425
3368
|
if (!isLoading) {
|
|
@@ -3429,184 +3372,20 @@ function AiFigurePrompt({
|
|
|
3429
3372
|
const id = setInterval(() => setElapsed((s) => s + 1), 1e3);
|
|
3430
3373
|
return () => clearInterval(id);
|
|
3431
3374
|
}, [isLoading]);
|
|
3432
|
-
const [image, setImage] = useState(null);
|
|
3433
|
-
const [ocrLoading, setOcrLoading] = useState(false);
|
|
3434
|
-
const [ocrError, setOcrError] = useState(null);
|
|
3435
|
-
const [ocrWarning, setOcrWarning] = useState(null);
|
|
3436
|
-
const [isDragOver, setIsDragOver] = useState(false);
|
|
3437
|
-
const fileInputRef = useRef(null);
|
|
3438
3375
|
const textareaRef = useRef(null);
|
|
3439
|
-
const imagePreview = image ? `data:${image.mediaType};base64,${image.base64}` : null;
|
|
3440
|
-
useEffect(() => {
|
|
3441
|
-
setOcrError(null);
|
|
3442
|
-
setOcrWarning(null);
|
|
3443
|
-
}, [image]);
|
|
3444
|
-
const handleFile = useCallback(
|
|
3445
|
-
async (file) => {
|
|
3446
|
-
if (isLoading || ocrLoading) return;
|
|
3447
|
-
const v = validateFile(file);
|
|
3448
|
-
if (!v.ok) {
|
|
3449
|
-
setOcrError(v.message);
|
|
3450
|
-
return;
|
|
3451
|
-
}
|
|
3452
|
-
try {
|
|
3453
|
-
const part = await fileToImagePart(file);
|
|
3454
|
-
setImage(part);
|
|
3455
|
-
} catch (e) {
|
|
3456
|
-
setOcrError(e instanceof Error ? e.message : "Kh\xF4ng decode \u0111\u01B0\u1EE3c \u1EA3nh");
|
|
3457
|
-
}
|
|
3458
|
-
},
|
|
3459
|
-
[isLoading, ocrLoading]
|
|
3460
|
-
);
|
|
3461
|
-
const handleFileInput = useCallback(
|
|
3462
|
-
(e) => {
|
|
3463
|
-
const file = e.target.files?.[0];
|
|
3464
|
-
if (file) void handleFile(file);
|
|
3465
|
-
e.target.value = "";
|
|
3466
|
-
},
|
|
3467
|
-
[handleFile]
|
|
3468
|
-
);
|
|
3469
|
-
const handlePaste = useCallback(
|
|
3470
|
-
(e) => {
|
|
3471
|
-
const item = Array.from(e.clipboardData.items).find(
|
|
3472
|
-
(it) => it.kind === "file" && it.type.startsWith("image/")
|
|
3473
|
-
);
|
|
3474
|
-
if (!item) return;
|
|
3475
|
-
const file = item.getAsFile();
|
|
3476
|
-
if (!file) return;
|
|
3477
|
-
e.preventDefault();
|
|
3478
|
-
void handleFile(file);
|
|
3479
|
-
},
|
|
3480
|
-
[handleFile]
|
|
3481
|
-
);
|
|
3482
|
-
const handleDrop = useCallback(
|
|
3483
|
-
(e) => {
|
|
3484
|
-
e.preventDefault();
|
|
3485
|
-
setIsDragOver(false);
|
|
3486
|
-
const file = Array.from(e.dataTransfer.files).find(
|
|
3487
|
-
(f) => f.type.startsWith("image/")
|
|
3488
|
-
);
|
|
3489
|
-
if (file) void handleFile(file);
|
|
3490
|
-
},
|
|
3491
|
-
[handleFile]
|
|
3492
|
-
);
|
|
3493
|
-
const runOcr = useCallback(async () => {
|
|
3494
|
-
if (!image) return;
|
|
3495
|
-
setOcrLoading(true);
|
|
3496
|
-
setOcrError(null);
|
|
3497
|
-
setOcrWarning(null);
|
|
3498
|
-
try {
|
|
3499
|
-
const r = await extractProblem(image);
|
|
3500
|
-
if (r.kind === "success" || r.kind === "low-confidence") {
|
|
3501
|
-
setPrompt(r.text);
|
|
3502
|
-
if (r.kind === "low-confidence") setOcrWarning(r.warning);
|
|
3503
|
-
requestAnimationFrame(() => textareaRef.current?.focus());
|
|
3504
|
-
} else {
|
|
3505
|
-
setOcrError(r.message);
|
|
3506
|
-
}
|
|
3507
|
-
} finally {
|
|
3508
|
-
setOcrLoading(false);
|
|
3509
|
-
}
|
|
3510
|
-
}, [image, setPrompt, extractProblem]);
|
|
3511
3376
|
const handleSendClick = useCallback(async () => {
|
|
3512
|
-
if (image && !prompt.trim() && !ocrLoading) {
|
|
3513
|
-
await runOcr();
|
|
3514
|
-
return;
|
|
3515
|
-
}
|
|
3516
3377
|
const generated = await submit();
|
|
3517
3378
|
if (generated) onGenerated(generated);
|
|
3518
|
-
}, [
|
|
3519
|
-
const handleSwitchToBuild = useCallback(() => {
|
|
3520
|
-
if (currentState && currentState.order.length > 0) {
|
|
3521
|
-
const ok = window.confirm(
|
|
3522
|
-
"D\u1EF1ng m\u1EDBi s\u1EBD thay to\xE0n b\u1ED9 h\xECnh hi\u1EC7n t\u1EA1i b\u1EB1ng h\xECnh m\u1EDBi t\u1EEB AI. Ti\u1EBFp t\u1EE5c?"
|
|
3523
|
-
);
|
|
3524
|
-
if (!ok) return;
|
|
3525
|
-
}
|
|
3526
|
-
setMode("build");
|
|
3527
|
-
}, [currentState, setMode]);
|
|
3528
|
-
const hasContent = currentState != null && currentState.order.length > 0;
|
|
3379
|
+
}, [submit, onGenerated]);
|
|
3529
3380
|
const promptEmpty = !prompt.trim();
|
|
3530
|
-
const
|
|
3531
|
-
const sendDisabled = !image && promptEmpty || ocrLoading || isLoading && !willOcr;
|
|
3532
|
-
const refineChipLabel = entityCount.points + entityCount.shapes > 0 ? `Th\xEAm v\xE0o \xB7 ${entityCount.points}\u0111, ${entityCount.shapes}\u0111o\u1EA1n` : "Th\xEAm v\xE0o";
|
|
3533
|
-
const placeholder = willOcr ? "B\u1EA5m g\u1EEDi \u0111\u1EC3 \u0111\u1ECDc \u0111\u1EC1 t\u1EEB \u1EA3nh \u2014 ho\u1EB7c t\u1EF1 g\xF5 \u1EDF \u0111\xE2y\u2026" : mode === "refine" ? "M\xF4 t\u1EA3 ph\u1EA7n c\u1EA7n th\xEAm (vd: trung \u0111i\u1EC3m M c\u1EE7a BC). C\xF3 th\u1EC3 d\xE1n \u1EA3nh \u0111\u1EC1 (Ctrl+V)." : "M\xF4 t\u1EA3 \u0111\u1EC1 b\xE0i c\u1EA7n d\u1EF1ng \u2014 ho\u1EB7c d\xE1n/\u0111\xEDnh \u1EA3nh \u0111\u1EC1 (Ctrl+V).";
|
|
3381
|
+
const sendDisabled = promptEmpty || isLoading;
|
|
3534
3382
|
return /* @__PURE__ */ jsxs("div", { className: "border-b border-slate-200 bg-slate-50 px-3 py-3", children: [
|
|
3535
|
-
/* @__PURE__ */
|
|
3536
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium tracking-wide text-slate-600", children: "D\u1EF1ng h\xECnh b\u1EB1ng AI" }),
|
|
3537
|
-
hasContent && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", role: "tablist", "aria-label": "Ch\u1EBF \u0111\u1ED9 AI", children: [
|
|
3538
|
-
/* @__PURE__ */ jsx(
|
|
3539
|
-
"button",
|
|
3540
|
-
{
|
|
3541
|
-
type: "button",
|
|
3542
|
-
role: "tab",
|
|
3543
|
-
"aria-selected": mode === "refine",
|
|
3544
|
-
"data-testid": "geometry-ai-mode-refine",
|
|
3545
|
-
onClick: () => setMode("refine"),
|
|
3546
|
-
disabled: isLoading || hasUnsupported,
|
|
3547
|
-
title: hasUnsupported ? "H\xECnh c\xF3 \u0111\u1ED1i t\u01B0\u1EE3ng ngo\xE0i DSL \u2014 ch\u1EC9 d\u1EF1ng m\u1EDBi \u0111\u01B0\u1EE3c" : refineChipLabel,
|
|
3548
|
-
className: `rounded-full px-2.5 py-0.5 text-[11px] transition ${mode === "refine" ? "bg-emerald-600 text-white shadow-sm" : "text-slate-500 hover:text-emerald-700"} ${hasUnsupported ? "cursor-not-allowed opacity-40" : ""}`,
|
|
3549
|
-
children: refineChipLabel
|
|
3550
|
-
}
|
|
3551
|
-
),
|
|
3552
|
-
/* @__PURE__ */ jsx(
|
|
3553
|
-
"button",
|
|
3554
|
-
{
|
|
3555
|
-
type: "button",
|
|
3556
|
-
role: "tab",
|
|
3557
|
-
"aria-selected": mode === "build",
|
|
3558
|
-
"data-testid": "geometry-ai-mode-build",
|
|
3559
|
-
onClick: handleSwitchToBuild,
|
|
3560
|
-
disabled: isLoading,
|
|
3561
|
-
className: `rounded-full px-2.5 py-0.5 text-[11px] transition ${mode === "build" ? "bg-emerald-600 text-white shadow-sm" : "text-slate-500 hover:text-emerald-700"}`,
|
|
3562
|
-
children: "D\u1EF1ng m\u1EDBi"
|
|
3563
|
-
}
|
|
3564
|
-
)
|
|
3565
|
-
] })
|
|
3566
|
-
] }),
|
|
3567
|
-
hasUnsupported && /* @__PURE__ */ jsx(
|
|
3568
|
-
"p",
|
|
3569
|
-
{
|
|
3570
|
-
className: "mb-1.5 text-[10px] text-amber-700",
|
|
3571
|
-
"data-testid": "geometry-ai-unsupported-warning",
|
|
3572
|
-
children: "H\xECnh c\xF3 \u0111\u1ED1i t\u01B0\u1EE3ng ngo\xE0i DSL \u2014 ch\u1EC9 d\u1EF1ng m\u1EDBi \u0111\u01B0\u1EE3c"
|
|
3573
|
-
}
|
|
3574
|
-
),
|
|
3383
|
+
/* @__PURE__ */ jsx("div", { className: "mb-2 flex items-center justify-between gap-2", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium tracking-wide text-slate-600", children: "D\u1EF1ng h\xECnh b\u1EB1ng AI" }) }),
|
|
3575
3384
|
/* @__PURE__ */ jsxs(
|
|
3576
3385
|
"div",
|
|
3577
3386
|
{
|
|
3578
|
-
|
|
3579
|
-
e.preventDefault();
|
|
3580
|
-
setIsDragOver(true);
|
|
3581
|
-
},
|
|
3582
|
-
onDragLeave: () => setIsDragOver(false),
|
|
3583
|
-
onDrop: handleDrop,
|
|
3584
|
-
onPaste: handlePaste,
|
|
3585
|
-
"aria-label": "Khu v\u1EF1c k\xE9o th\u1EA3 \u1EA3nh",
|
|
3586
|
-
role: "region",
|
|
3587
|
-
className: "group relative flex flex-col rounded-2xl bg-white shadow-sm transition-all duration-150 ring-1 ring-slate-200 focus-within:ring-2 focus-within:ring-emerald-400/70 focus-within:shadow-md " + (isDragOver ? "ring-2 ring-emerald-500 bg-emerald-50/40" : ""),
|
|
3387
|
+
className: "group relative flex flex-col rounded-2xl bg-white shadow-sm transition-all duration-150 ring-1 ring-slate-200 focus-within:ring-2 focus-within:ring-emerald-400/70 focus-within:shadow-md",
|
|
3588
3388
|
children: [
|
|
3589
|
-
image && imagePreview && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 px-3 pt-2.5", children: /* @__PURE__ */ jsxs("div", { className: "group/chip relative", children: [
|
|
3590
|
-
/* @__PURE__ */ jsx(
|
|
3591
|
-
"img",
|
|
3592
|
-
{
|
|
3593
|
-
src: imagePreview,
|
|
3594
|
-
alt: "\u1EA2nh \u0111\u1EC1 b\xE0i",
|
|
3595
|
-
className: "max-h-48 max-w-full h-auto w-auto rounded-lg border border-slate-200 shadow-sm"
|
|
3596
|
-
}
|
|
3597
|
-
),
|
|
3598
|
-
/* @__PURE__ */ jsx(
|
|
3599
|
-
"button",
|
|
3600
|
-
{
|
|
3601
|
-
type: "button",
|
|
3602
|
-
onClick: () => setImage(null),
|
|
3603
|
-
disabled: ocrLoading || isLoading,
|
|
3604
|
-
"aria-label": "Xo\xE1 \u1EA3nh",
|
|
3605
|
-
className: "absolute -right-1.5 -top-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-slate-900/85 text-[11px] font-medium text-white shadow ring-2 ring-white transition hover:bg-slate-900 disabled:opacity-50",
|
|
3606
|
-
children: "\xD7"
|
|
3607
|
-
}
|
|
3608
|
-
)
|
|
3609
|
-
] }) }),
|
|
3610
3389
|
/* @__PURE__ */ jsx(
|
|
3611
3390
|
"textarea",
|
|
3612
3391
|
{
|
|
@@ -3624,79 +3403,122 @@ function AiFigurePrompt({
|
|
|
3624
3403
|
},
|
|
3625
3404
|
disabled: isLoading,
|
|
3626
3405
|
rows: 2,
|
|
3627
|
-
placeholder,
|
|
3406
|
+
placeholder: "M\xF4 t\u1EA3 \u0111\u1EC1 b\xE0i c\u1EA7n d\u1EF1ng.",
|
|
3628
3407
|
className: "block w-full resize-none rounded-2xl bg-transparent px-3.5 pt-2.5 pb-1 text-sm leading-relaxed text-slate-800 placeholder:text-slate-400 outline-none disabled:opacity-60 field-sizing-content max-h-44"
|
|
3629
3408
|
}
|
|
3630
3409
|
),
|
|
3631
|
-
/* @__PURE__ */
|
|
3632
|
-
/* @__PURE__ */
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3659
|
-
(isLoading || ocrLoading) && /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] tabular-nums text-slate-500", children: ocrLoading ? "\u0111\u1ECDc \u1EA3nh\u2026" : tokens > 0 ? `${tokens}tok \xB7 ${elapsed}s` : `${elapsed}s` }),
|
|
3660
|
-
isLoading ? /* @__PURE__ */ jsx(
|
|
3661
|
-
"button",
|
|
3662
|
-
{
|
|
3663
|
-
type: "button",
|
|
3664
|
-
onClick: cancel,
|
|
3665
|
-
"aria-label": "Hu\u1EF7 d\u1EF1ng h\xECnh AI",
|
|
3666
|
-
"data-testid": "geometry-ai-cancel",
|
|
3667
|
-
title: `\u0110ang d\u1EF1ng\u2026 ${elapsed}s \u2014 b\u1EA5m \u0111\u1EC3 hu\u1EF7`,
|
|
3668
|
-
className: "flex h-8 w-8 items-center justify-center rounded-full bg-amber-500 text-white shadow-sm transition hover:scale-105 hover:bg-amber-600 active:scale-95",
|
|
3669
|
-
children: /* @__PURE__ */ jsx(StopIcon, { className: "h-3.5 w-3.5" })
|
|
3670
|
-
}
|
|
3671
|
-
) : /* @__PURE__ */ jsx(
|
|
3672
|
-
"button",
|
|
3673
|
-
{
|
|
3674
|
-
type: "button",
|
|
3675
|
-
onClick: () => void handleSendClick(),
|
|
3676
|
-
disabled: sendDisabled,
|
|
3677
|
-
"aria-label": willOcr ? "\u0110\u1ECDc \u0111\u1EC1 t\u1EEB \u1EA3nh" : "D\u1EF1ng b\u1EB1ng AI",
|
|
3678
|
-
title: willOcr ? "\u0110\u1ECDc \u0111\u1EC1 t\u1EEB \u1EA3nh (s\u1EBD \u0111i\u1EC1n v\xE0o \xF4 chat)" : "D\u1EF1ng b\u1EB1ng AI (Ctrl/\u2318+Enter)",
|
|
3679
|
-
"data-testid": willOcr ? "geometry-ai-ocr" : "geometry-ai-submit",
|
|
3680
|
-
className: "flex h-8 w-8 items-center justify-center rounded-full bg-emerald-600 text-white shadow-sm transition hover:scale-105 hover:bg-emerald-700 active:scale-95 disabled:cursor-not-allowed disabled:bg-slate-300 disabled:hover:scale-100",
|
|
3681
|
-
children: /* @__PURE__ */ jsx(ArrowUpIcon, { className: "h-[18px] w-[18px]" })
|
|
3682
|
-
}
|
|
3683
|
-
)
|
|
3684
|
-
] })
|
|
3685
|
-
] }),
|
|
3686
|
-
isDragOver && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center rounded-2xl bg-emerald-50/60 text-xs font-medium text-emerald-700", children: "Th\u1EA3 \u1EA3nh v\xE0o \u0111\xE2y" })
|
|
3410
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-2 px-2 pb-2 pt-1", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3411
|
+
isLoading && /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] tabular-nums text-slate-500", children: tokens > 0 ? `${tokens}tok \xB7 ${elapsed}s` : `${elapsed}s` }),
|
|
3412
|
+
isLoading ? /* @__PURE__ */ jsx(
|
|
3413
|
+
"button",
|
|
3414
|
+
{
|
|
3415
|
+
type: "button",
|
|
3416
|
+
onClick: cancel,
|
|
3417
|
+
"aria-label": "Hu\u1EF7 d\u1EF1ng h\xECnh AI",
|
|
3418
|
+
"data-testid": "geometry-ai-cancel",
|
|
3419
|
+
title: `\u0110ang d\u1EF1ng\u2026 ${elapsed}s \u2014 b\u1EA5m \u0111\u1EC3 hu\u1EF7`,
|
|
3420
|
+
className: "flex h-8 w-8 items-center justify-center rounded-full bg-amber-500 text-white shadow-sm transition hover:scale-105 hover:bg-amber-600 active:scale-95",
|
|
3421
|
+
children: /* @__PURE__ */ jsx(StopIcon, { className: "h-3.5 w-3.5" })
|
|
3422
|
+
}
|
|
3423
|
+
) : /* @__PURE__ */ jsx(
|
|
3424
|
+
"button",
|
|
3425
|
+
{
|
|
3426
|
+
type: "button",
|
|
3427
|
+
onClick: () => void handleSendClick(),
|
|
3428
|
+
disabled: sendDisabled,
|
|
3429
|
+
"aria-label": "D\u1EF1ng b\u1EB1ng AI",
|
|
3430
|
+
title: "D\u1EF1ng b\u1EB1ng AI (Ctrl/\u2318+Enter)",
|
|
3431
|
+
"data-testid": "geometry-ai-submit",
|
|
3432
|
+
className: "flex h-8 w-8 items-center justify-center rounded-full bg-emerald-600 text-white shadow-sm transition hover:scale-105 hover:bg-emerald-700 active:scale-95 disabled:cursor-not-allowed disabled:bg-slate-300 disabled:hover:scale-100",
|
|
3433
|
+
children: /* @__PURE__ */ jsx(ArrowUpIcon, { className: "h-[18px] w-[18px]" })
|
|
3434
|
+
}
|
|
3435
|
+
)
|
|
3436
|
+
] }) })
|
|
3687
3437
|
]
|
|
3688
3438
|
}
|
|
3689
3439
|
),
|
|
3690
|
-
/* @__PURE__ */
|
|
3691
|
-
"D\xE1n \u1EA3nh (Ctrl+V), k\xE9o th\u1EA3, ho\u1EB7c b\u1EA5m ",
|
|
3692
|
-
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u{1F4CE}" }),
|
|
3693
|
-
" \u0111\u1EC3 \u0111\xEDnh \u1EA3nh \u0111\u1EC1."
|
|
3694
|
-
] }),
|
|
3695
|
-
error && /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-1 px-1 text-xs text-red-600", children: error }),
|
|
3696
|
-
ocrError && /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-1 px-1 text-xs text-red-600", children: ocrError }),
|
|
3697
|
-
ocrWarning && /* @__PURE__ */ jsx("p", { className: "mt-1 rounded bg-amber-50 px-2 py-1 text-[11px] text-amber-700", children: ocrWarning })
|
|
3440
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-1 px-1 text-xs text-red-600", children: error })
|
|
3698
3441
|
] });
|
|
3699
3442
|
}
|
|
3443
|
+
|
|
3444
|
+
// src/stamps/geometry-2d/draft.ts
|
|
3445
|
+
function svgIntrinsicSize(svg) {
|
|
3446
|
+
const w = svg.match(/<svg[^>]*\swidth="([\d.]+)"/);
|
|
3447
|
+
const h = svg.match(/<svg[^>]*\sheight="([\d.]+)"/);
|
|
3448
|
+
if (w && h) return { width: parseFloat(w[1]), height: parseFloat(h[1]) };
|
|
3449
|
+
const vb = svg.match(/viewBox="0 0 ([\d.]+) ([\d.]+)"/);
|
|
3450
|
+
if (vb) return { width: parseFloat(vb[1]), height: parseFloat(vb[2]) };
|
|
3451
|
+
return { width: 300, height: 200 };
|
|
3452
|
+
}
|
|
3453
|
+
function draftFromViewport(svg, appState, seq) {
|
|
3454
|
+
const { width, height } = svgIntrinsicSize(svg);
|
|
3455
|
+
const zoom = appState.zoom?.value ?? 1;
|
|
3456
|
+
const vw = appState.width ?? 800;
|
|
3457
|
+
const vh = appState.height ?? 600;
|
|
3458
|
+
const cx = appState.scrollX + vw / 2 / zoom;
|
|
3459
|
+
const cy = appState.scrollY + vh / 2 / zoom;
|
|
3460
|
+
return { svg, width, height, x: cx - width / 2, y: cy - height / 2, seq };
|
|
3461
|
+
}
|
|
3462
|
+
function didStateChange(seen, jsonState) {
|
|
3463
|
+
if (seen.last === jsonState) return false;
|
|
3464
|
+
seen.last = jsonState;
|
|
3465
|
+
return true;
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3468
|
+
// src/stamps/geometry-2d/editor/useGeometryDraftEmit.ts
|
|
3469
|
+
function useGeometryDraftEmit({
|
|
3470
|
+
store,
|
|
3471
|
+
handleRef,
|
|
3472
|
+
api,
|
|
3473
|
+
showAxis,
|
|
3474
|
+
showGrid,
|
|
3475
|
+
onGeometryDraft,
|
|
3476
|
+
debounceMs = 350
|
|
3477
|
+
}) {
|
|
3478
|
+
const seqRef = useRef(0);
|
|
3479
|
+
const seenRef = useRef({ last: null });
|
|
3480
|
+
const timerRef = useRef(null);
|
|
3481
|
+
const cbRef = useRef(onGeometryDraft);
|
|
3482
|
+
cbRef.current = onGeometryDraft;
|
|
3483
|
+
useEffect(() => {
|
|
3484
|
+
if (!cbRef.current) return;
|
|
3485
|
+
const emit = () => {
|
|
3486
|
+
const h = handleRef.current;
|
|
3487
|
+
if (!h) return;
|
|
3488
|
+
const state = h.getState();
|
|
3489
|
+
if (Object.keys(state.objects).length === 0) {
|
|
3490
|
+
if (seenRef.current.last !== null) {
|
|
3491
|
+
seenRef.current.last = null;
|
|
3492
|
+
cbRef.current?.(null);
|
|
3493
|
+
}
|
|
3494
|
+
return;
|
|
3495
|
+
}
|
|
3496
|
+
const bbox = h.getBbox();
|
|
3497
|
+
const jsonState = serializeBoard(state, { bbox, showAxis, showGrid });
|
|
3498
|
+
if (!didStateChange(seenRef.current, jsonState)) return;
|
|
3499
|
+
void (async () => {
|
|
3500
|
+
try {
|
|
3501
|
+
const svg = await renderGeometrySvgFromState(jsonState);
|
|
3502
|
+
const appState = api?.getAppState?.() ?? { scrollX: 0, scrollY: 0, width: 800, height: 600, zoom: { value: 1 } };
|
|
3503
|
+
seqRef.current += 1;
|
|
3504
|
+
cbRef.current?.(draftFromViewport(svg, appState, seqRef.current));
|
|
3505
|
+
} catch (err) {
|
|
3506
|
+
console.warn("[geometry] draft render failed:", err);
|
|
3507
|
+
}
|
|
3508
|
+
})();
|
|
3509
|
+
};
|
|
3510
|
+
const schedule = () => {
|
|
3511
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
3512
|
+
timerRef.current = setTimeout(emit, debounceMs);
|
|
3513
|
+
};
|
|
3514
|
+
const unsub = store.subscribe(schedule);
|
|
3515
|
+
return () => {
|
|
3516
|
+
unsub();
|
|
3517
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
3518
|
+
cbRef.current?.(null);
|
|
3519
|
+
};
|
|
3520
|
+
}, [store, handleRef, api, showAxis, showGrid, debounceMs]);
|
|
3521
|
+
}
|
|
3700
3522
|
var GeometryEditorPanelInner = forwardRef(
|
|
3701
3523
|
function GeometryEditorPanelInner2({
|
|
3702
3524
|
store,
|
|
@@ -3715,7 +3537,9 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
3715
3537
|
canUndo,
|
|
3716
3538
|
canRedo,
|
|
3717
3539
|
onSelectionChange,
|
|
3718
|
-
generateGeometryFigure
|
|
3540
|
+
generateGeometryFigure,
|
|
3541
|
+
api,
|
|
3542
|
+
onGeometryDraft
|
|
3719
3543
|
}, ref) {
|
|
3720
3544
|
const { showToast } = useToast();
|
|
3721
3545
|
const handleRef = useRef(null);
|
|
@@ -3728,12 +3552,12 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
3728
3552
|
useEffect(() => {
|
|
3729
3553
|
onSelectionChangeRef.current = onSelectionChange;
|
|
3730
3554
|
}, [onSelectionChange]);
|
|
3555
|
+
const onGeometryDraftRef = useRef(onGeometryDraft);
|
|
3556
|
+
useEffect(() => {
|
|
3557
|
+
onGeometryDraftRef.current = onGeometryDraft;
|
|
3558
|
+
}, [onGeometryDraft]);
|
|
3731
3559
|
useEditorState({ store, onHistoryChange });
|
|
3732
|
-
|
|
3733
|
-
(cb) => store.subscribe(cb),
|
|
3734
|
-
() => store.getState(),
|
|
3735
|
-
() => store.getState()
|
|
3736
|
-
);
|
|
3560
|
+
useGeometryDraftEmit({ store, handleRef, api, showAxis, showGrid, onGeometryDraft });
|
|
3737
3561
|
useEffect(() => {
|
|
3738
3562
|
const sync = () => setHasContent(Object.keys(store.getState().objects).length > 0);
|
|
3739
3563
|
sync();
|
|
@@ -3810,15 +3634,13 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
3810
3634
|
try {
|
|
3811
3635
|
const svgString = await renderGeometrySvgFromState(jsonState);
|
|
3812
3636
|
onInsert(jsonState, svgString);
|
|
3637
|
+
onGeometryDraftRef.current?.(null);
|
|
3813
3638
|
} catch (err) {
|
|
3814
3639
|
console.error("Geometry insert failed:", err);
|
|
3815
3640
|
}
|
|
3816
3641
|
})();
|
|
3817
3642
|
return true;
|
|
3818
3643
|
}, [onInsert, showAxis, showGrid]);
|
|
3819
|
-
const handleInsert = useCallback(() => {
|
|
3820
|
-
performInsert();
|
|
3821
|
-
}, [performInsert]);
|
|
3822
3644
|
const loadAiFigure = useCallback((generated) => {
|
|
3823
3645
|
handleRef.current?.clearSelection();
|
|
3824
3646
|
setPropsPopover(null);
|
|
@@ -3913,7 +3735,7 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
3913
3735
|
"button",
|
|
3914
3736
|
{
|
|
3915
3737
|
type: "button",
|
|
3916
|
-
onClick:
|
|
3738
|
+
onClick: performInsert,
|
|
3917
3739
|
disabled: !ready || !hasContent,
|
|
3918
3740
|
title: !hasContent ? "V\u1EBD \xEDt nh\u1EA5t m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng tr\u01B0\u1EDBc khi ch\xE8n" : void 0,
|
|
3919
3741
|
"data-testid": "geometry-insert-btn-mobile",
|
|
@@ -3927,7 +3749,7 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
3927
3749
|
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" })
|
|
3928
3750
|
] }) })
|
|
3929
3751
|
] }),
|
|
3930
|
-
generateGeometryFigure && /* @__PURE__ */ jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure
|
|
3752
|
+
generateGeometryFigure && /* @__PURE__ */ jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure }),
|
|
3931
3753
|
/* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1", children: /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
3932
3754
|
MiniBoard2D,
|
|
3933
3755
|
{
|
|
@@ -4031,7 +3853,7 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
4031
3853
|
/* @__PURE__ */ jsx(
|
|
4032
3854
|
"button",
|
|
4033
3855
|
{
|
|
4034
|
-
onClick:
|
|
3856
|
+
onClick: performInsert,
|
|
4035
3857
|
disabled: !ready || !hasContent,
|
|
4036
3858
|
title: !hasContent ? "V\u1EBD \xEDt nh\u1EA5t m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng tr\u01B0\u1EDBc khi ch\xE8n" : void 0,
|
|
4037
3859
|
"data-testid": "geometry-insert-btn",
|
|
@@ -4087,7 +3909,7 @@ function parseInitialState(data) {
|
|
|
4087
3909
|
return deserializeBoard(data.jsonState);
|
|
4088
3910
|
}
|
|
4089
3911
|
var GeometryStampHost = forwardRef(
|
|
4090
|
-
function GeometryStampHost2({ api, editingElement, onClose, isDark, generateGeometryFigure }, ref) {
|
|
3912
|
+
function GeometryStampHost2({ api, editingElement, onClose, isDark, generateGeometryFigure, onGeometryDraft }, ref) {
|
|
4091
3913
|
const panelRef = useRef(null);
|
|
4092
3914
|
const { isMobile } = useIsMobile();
|
|
4093
3915
|
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
@@ -4202,7 +4024,9 @@ var GeometryStampHost = forwardRef(
|
|
|
4202
4024
|
canUndo,
|
|
4203
4025
|
canRedo,
|
|
4204
4026
|
onSelectionChange: setSelectedObjectId,
|
|
4205
|
-
generateGeometryFigure
|
|
4027
|
+
generateGeometryFigure,
|
|
4028
|
+
api,
|
|
4029
|
+
onGeometryDraft
|
|
4206
4030
|
}
|
|
4207
4031
|
)
|
|
4208
4032
|
] });
|
|
@@ -4210,5 +4034,5 @@ var GeometryStampHost = forwardRef(
|
|
|
4210
4034
|
);
|
|
4211
4035
|
|
|
4212
4036
|
export { GeometryStampHost };
|
|
4213
|
-
//# sourceMappingURL=host-
|
|
4214
|
-
//# sourceMappingURL=host-
|
|
4037
|
+
//# sourceMappingURL=host-HKMZSCIT.mjs.map
|
|
4038
|
+
//# sourceMappingURL=host-HKMZSCIT.mjs.map
|