@xom11/whiteboard 0.28.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 +6019 -7612
- package/dist/ai.js.map +1 -1
- package/dist/ai.mjs +4804 -5457
- package/dist/ai.mjs.map +1 -1
- package/dist/catalog.json +2 -2
- package/dist/{chunk-AJAHD35N.mjs → chunk-E6EDOPGT.mjs} +3 -105
- package/dist/chunk-E6EDOPGT.mjs.map +1 -0
- package/dist/{chunk-QCZVFEN4.mjs → chunk-GEC2D2EQ.mjs} +3 -3
- package/dist/{chunk-QCZVFEN4.mjs.map → chunk-GEC2D2EQ.mjs.map} +1 -1
- package/dist/geometry-2d.d.mts +1 -2
- package/dist/geometry-2d.d.ts +1 -2
- package/dist/geometry-2d.js +888 -3623
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +1 -1
- package/dist/geometry-3d.d.mts +1 -2
- package/dist/geometry-3d.d.ts +1 -2
- package/dist/graph-2d.d.mts +1 -2
- package/dist/graph-2d.d.ts +1 -2
- package/dist/{host-4P766V4J.mjs → host-HKMZSCIT.mjs} +54 -313
- package/dist/host-HKMZSCIT.mjs.map +1 -0
- package/dist/index.d.mts +2 -4
- package/dist/index.d.ts +2 -4
- package/dist/index.js +880 -3619
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -4
- package/dist/index.mjs.map +1 -1
- package/dist/latex.d.mts +1 -2
- package/dist/latex.d.ts +1 -2
- package/dist/{types-BHYC2Fiw.d.mts → types-C3FjpoUi.d.mts} +1 -232
- package/dist/{types-BHYC2Fiw.d.ts → types-C3FjpoUi.d.ts} +1 -232
- package/package.json +1 -9
- package/dist/chunk-AJAHD35N.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-4P766V4J.mjs.map +0 -1
package/dist/geometry-2d.mjs
CHANGED
package/dist/geometry-3d.d.mts
CHANGED
package/dist/geometry-3d.d.ts
CHANGED
package/dist/graph-2d.d.mts
CHANGED
package/dist/graph-2d.d.ts
CHANGED
|
@@ -8,15 +8,14 @@ import { JxgRenderer } from './chunk-SZDAS7LK.mjs';
|
|
|
8
8
|
import './chunk-ICR4CVOE.mjs';
|
|
9
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,77 +3403,41 @@ 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
|
}
|
|
3700
3443
|
|
|
@@ -3815,8 +3558,6 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
3815
3558
|
}, [onGeometryDraft]);
|
|
3816
3559
|
useEditorState({ store, onHistoryChange });
|
|
3817
3560
|
useGeometryDraftEmit({ store, handleRef, api, showAxis, showGrid, onGeometryDraft });
|
|
3818
|
-
const snap = () => store.getState();
|
|
3819
|
-
const currentSceneState = useSyncExternalStore((cb) => store.subscribe(cb), snap, snap);
|
|
3820
3561
|
useEffect(() => {
|
|
3821
3562
|
const sync = () => setHasContent(Object.keys(store.getState().objects).length > 0);
|
|
3822
3563
|
sync();
|
|
@@ -3826,22 +3567,22 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
3826
3567
|
const h = handleRef.current;
|
|
3827
3568
|
if (!h) return;
|
|
3828
3569
|
setReady(true);
|
|
3829
|
-
h.onSelect((
|
|
3830
|
-
setPropsPopover(
|
|
3570
|
+
h.onSelect((snap) => {
|
|
3571
|
+
setPropsPopover(snap);
|
|
3831
3572
|
setMultiSelection(null);
|
|
3832
|
-
onSelectionChangeRef.current?.(
|
|
3573
|
+
onSelectionChangeRef.current?.(snap.id);
|
|
3833
3574
|
});
|
|
3834
3575
|
h.onTransformParam((info) => setTransformPopover(info));
|
|
3835
|
-
h.onSelectionState((
|
|
3836
|
-
if (!
|
|
3576
|
+
h.onSelectionState((snap) => {
|
|
3577
|
+
if (!snap || snap.ids.length === 0) {
|
|
3837
3578
|
setPropsPopover(null);
|
|
3838
3579
|
setMultiSelection(null);
|
|
3839
3580
|
onSelectionChangeRef.current?.(void 0);
|
|
3840
3581
|
return;
|
|
3841
3582
|
}
|
|
3842
|
-
if (
|
|
3843
|
-
const id =
|
|
3844
|
-
const single = buildObjectSnapshot(store.getState(), id,
|
|
3583
|
+
if (snap.ids.length === 1) {
|
|
3584
|
+
const id = snap.ids[0];
|
|
3585
|
+
const single = buildObjectSnapshot(store.getState(), id, snap.anchor);
|
|
3845
3586
|
if (single) {
|
|
3846
3587
|
setPropsPopover(single);
|
|
3847
3588
|
setMultiSelection(null);
|
|
@@ -3849,7 +3590,7 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
3849
3590
|
}
|
|
3850
3591
|
return;
|
|
3851
3592
|
}
|
|
3852
|
-
setMultiSelection(
|
|
3593
|
+
setMultiSelection(snap);
|
|
3853
3594
|
setPropsPopover(null);
|
|
3854
3595
|
onSelectionChangeRef.current?.(void 0);
|
|
3855
3596
|
});
|
|
@@ -4008,7 +3749,7 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
4008
3749
|
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" })
|
|
4009
3750
|
] }) })
|
|
4010
3751
|
] }),
|
|
4011
|
-
generateGeometryFigure && /* @__PURE__ */ jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure
|
|
3752
|
+
generateGeometryFigure && /* @__PURE__ */ jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure }),
|
|
4012
3753
|
/* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1", children: /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
4013
3754
|
MiniBoard2D,
|
|
4014
3755
|
{
|
|
@@ -4293,5 +4034,5 @@ var GeometryStampHost = forwardRef(
|
|
|
4293
4034
|
);
|
|
4294
4035
|
|
|
4295
4036
|
export { GeometryStampHost };
|
|
4296
|
-
//# sourceMappingURL=host-
|
|
4297
|
-
//# sourceMappingURL=host-
|
|
4037
|
+
//# sourceMappingURL=host-HKMZSCIT.mjs.map
|
|
4038
|
+
//# sourceMappingURL=host-HKMZSCIT.mjs.map
|