@xom11/whiteboard 0.24.2 → 0.25.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/README.md +84 -11
- package/dist/ai.d.mts +422 -566
- package/dist/ai.d.ts +422 -566
- package/dist/ai.js +1527 -407
- package/dist/ai.js.map +1 -1
- package/dist/ai.mjs +1008 -512
- package/dist/ai.mjs.map +1 -1
- package/dist/catalog.json +4 -4
- package/dist/{chunk-BKSXPNPQ.mjs → chunk-AYSFWUPK.mjs} +4 -3
- package/dist/chunk-AYSFWUPK.mjs.map +1 -0
- package/dist/chunk-B4NJJZFR.mjs +18 -0
- package/dist/chunk-B4NJJZFR.mjs.map +1 -0
- package/dist/{chunk-LVNCYP4J.mjs → chunk-CJBLJUWG.mjs} +5 -5
- package/dist/{chunk-LVNCYP4J.mjs.map → chunk-CJBLJUWG.mjs.map} +1 -1
- package/dist/{chunk-7WQXXEVR.mjs → chunk-ESVPQWHX.mjs} +5 -5
- package/dist/{chunk-7WQXXEVR.mjs.map → chunk-ESVPQWHX.mjs.map} +1 -1
- package/dist/{chunk-KRC2XOIG.mjs → chunk-I24QOHPU.mjs} +3 -3
- package/dist/{chunk-KRC2XOIG.mjs.map → chunk-I24QOHPU.mjs.map} +1 -1
- package/dist/{chunk-ZBJBQKJ2.mjs → chunk-IHUFOV7L.mjs} +4 -19
- package/dist/chunk-IHUFOV7L.mjs.map +1 -0
- package/dist/{chunk-AZIARTGX.mjs → chunk-M42TGYT6.mjs} +3 -3
- package/dist/{chunk-AZIARTGX.mjs.map → chunk-M42TGYT6.mjs.map} +1 -1
- package/dist/{chunk-45CGKJ7S.mjs → chunk-NDEZJKNY.mjs} +4 -4
- package/dist/{chunk-45CGKJ7S.mjs.map → chunk-NDEZJKNY.mjs.map} +1 -1
- package/dist/{chunk-BEZSQKPY.mjs → chunk-ONBCUWVI.mjs} +5 -4
- package/dist/chunk-ONBCUWVI.mjs.map +1 -0
- package/dist/{chunk-WM2VDYQA.mjs → chunk-REIJZDVZ.mjs} +4 -3
- package/dist/chunk-REIJZDVZ.mjs.map +1 -0
- package/dist/{chunk-2WF6KIGF.mjs → chunk-TB4CL25L.mjs} +9 -8
- package/dist/chunk-TB4CL25L.mjs.map +1 -0
- package/dist/chunk-VNCCIV6O.mjs +938 -0
- package/dist/chunk-VNCCIV6O.mjs.map +1 -0
- package/dist/{chunk-CGZZO4BX.mjs → chunk-VRHWDZ66.mjs} +5 -5
- package/dist/{chunk-CGZZO4BX.mjs.map → chunk-VRHWDZ66.mjs.map} +1 -1
- package/dist/{chunk-4DS3MKID.mjs → chunk-YSJOVBCD.mjs} +4 -4
- package/dist/{chunk-4DS3MKID.mjs.map → chunk-YSJOVBCD.mjs.map} +1 -1
- package/dist/geometry-2d.d.mts +2 -2
- package/dist/geometry-2d.d.ts +2 -2
- package/dist/geometry-2d.js +1383 -23
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +6 -5
- package/dist/geometry-3d.d.mts +2 -2
- package/dist/geometry-3d.d.ts +2 -2
- package/dist/geometry-3d.js +2 -2
- package/dist/geometry-3d.js.map +1 -1
- package/dist/geometry-3d.mjs +5 -4
- package/dist/graph-2d.d.mts +2 -2
- package/dist/graph-2d.d.ts +2 -2
- package/dist/graph-2d.js +2 -2
- package/dist/graph-2d.js.map +1 -1
- package/dist/graph-2d.mjs +8 -7
- package/dist/{host-ZIQ77W33.mjs → host-A64ITWVX.mjs} +7 -6
- package/dist/host-A64ITWVX.mjs.map +1 -0
- package/dist/{host-EPZCNFLH.mjs → host-L7FMFZUW.mjs} +226 -29
- package/dist/host-L7FMFZUW.mjs.map +1 -0
- package/dist/{host-LKCMYEAV.mjs → host-QK53UYMD.mjs} +11 -10
- package/dist/host-QK53UYMD.mjs.map +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1414 -54
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +18 -17
- package/dist/index.mjs.map +1 -1
- package/dist/latex.d.mts +2 -2
- package/dist/latex.d.ts +2 -2
- package/dist/render-3WTY7NZB.mjs +9 -0
- package/dist/{render-SA4JTOW3.mjs.map → render-3WTY7NZB.mjs.map} +1 -1
- package/dist/serialize-SRJVKYUG.mjs +8 -0
- package/dist/{serialize-JAVOU22E.mjs.map → serialize-SRJVKYUG.mjs.map} +1 -1
- package/dist/{types-vtvyKGAA.d.mts → types-DWRyCa2m.d.mts} +187 -2
- package/dist/{types-Crbefnfe.d.ts → types-DWRyCa2m.d.ts} +187 -2
- package/package.json +1 -1
- package/dist/chunk-2WF6KIGF.mjs.map +0 -1
- package/dist/chunk-BEZSQKPY.mjs.map +0 -1
- package/dist/chunk-BKSXPNPQ.mjs.map +0 -1
- package/dist/chunk-WM2VDYQA.mjs.map +0 -1
- package/dist/chunk-ZBJBQKJ2.mjs.map +0 -1
- package/dist/host-EPZCNFLH.mjs.map +0 -1
- package/dist/host-LKCMYEAV.mjs.map +0 -1
- package/dist/host-ZIQ77W33.mjs.map +0 -1
- package/dist/render-SA4JTOW3.mjs +0 -8
- package/dist/serialize-JAVOU22E.mjs +0 -7
- package/dist/types-DxlMPh-6.d.mts +0 -49
- package/dist/types-DxlMPh-6.d.ts +0 -49
|
@@ -1,18 +1,20 @@
|
|
|
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 } 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-TB4CL25L.mjs';
|
|
5
|
+
import { serializeBoard, renderGeometrySvgFromState, isGeometryCustomData, deserializeBoard } from './chunk-VRHWDZ66.mjs';
|
|
6
6
|
import { themeLabel, paletteFor, themeAxis, themeGrid } from './chunk-R5FL6S7L.mjs';
|
|
7
|
-
import { JxgRenderer } from './chunk-
|
|
7
|
+
import { JxgRenderer } from './chunk-AYSFWUPK.mjs';
|
|
8
8
|
import './chunk-ICR4CVOE.mjs';
|
|
9
|
-
import { nextLabel, useEditorState, listObjects } from './chunk-
|
|
10
|
-
import './chunk-
|
|
9
|
+
import { nextLabel, useEditorState, listObjects } from './chunk-REIJZDVZ.mjs';
|
|
10
|
+
import './chunk-IHUFOV7L.mjs';
|
|
11
|
+
import { describeDsl, serializeState } from './chunk-VNCCIV6O.mjs';
|
|
11
12
|
import { DEFAULT_VIEW_2D } from './chunk-73Q7ADVL.mjs';
|
|
13
|
+
import './chunk-B4NJJZFR.mjs';
|
|
12
14
|
import { useIsMobile } from './chunk-P2AOIF7S.mjs';
|
|
13
15
|
import { insertStampImage } from './chunk-QGNU34T7.mjs';
|
|
14
16
|
import './chunk-5UTGXHLJ.mjs';
|
|
15
|
-
import { forwardRef, useRef, useId, useState, useEffect, useCallback, useImperativeHandle,
|
|
17
|
+
import { forwardRef, useRef, useId, useState, useEffect, useCallback, useImperativeHandle, useSyncExternalStore, useMemo, useLayoutEffect } from 'react';
|
|
16
18
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
17
19
|
import { createPortal } from 'react-dom';
|
|
18
20
|
|
|
@@ -2620,12 +2622,41 @@ var TransformParamPopover = ({ kind, anchor, defaultValue, onConfirm, onCancel,
|
|
|
2620
2622
|
);
|
|
2621
2623
|
return createPortal(node, document.body);
|
|
2622
2624
|
};
|
|
2623
|
-
function useAiFigure(generator) {
|
|
2625
|
+
function useAiFigure(generator, options = {}) {
|
|
2626
|
+
const { currentState } = options;
|
|
2624
2627
|
const [prompt, setPrompt] = useState("");
|
|
2625
2628
|
const [isLoading, setIsLoading] = useState(false);
|
|
2626
2629
|
const [error, setError] = useState(null);
|
|
2630
|
+
const [tokens, setTokens] = useState(0);
|
|
2627
2631
|
const abortRef = useRef(null);
|
|
2628
2632
|
const requestIdRef = useRef(0);
|
|
2633
|
+
const { dsl: currentDsl, unsupported, entityCount, hasContent } = useMemo(() => {
|
|
2634
|
+
if (!currentState || currentState.order.length === 0) {
|
|
2635
|
+
return {
|
|
2636
|
+
dsl: null,
|
|
2637
|
+
unsupported: [],
|
|
2638
|
+
entityCount: { points: 0, shapes: 0 },
|
|
2639
|
+
hasContent: false
|
|
2640
|
+
};
|
|
2641
|
+
}
|
|
2642
|
+
const { dsl, unsupported: unsupported2 } = serializeState(currentState);
|
|
2643
|
+
return {
|
|
2644
|
+
dsl,
|
|
2645
|
+
unsupported: unsupported2,
|
|
2646
|
+
entityCount: { points: dsl.points.length, shapes: dsl.shapes.length },
|
|
2647
|
+
hasContent: true
|
|
2648
|
+
};
|
|
2649
|
+
}, [currentState]);
|
|
2650
|
+
const hasUnsupported = unsupported.length > 0;
|
|
2651
|
+
const initialMode = hasContent && !hasUnsupported ? "refine" : "build";
|
|
2652
|
+
const [mode, setModeInternal] = useState(initialMode);
|
|
2653
|
+
useEffect(() => {
|
|
2654
|
+
if (!hasContent && mode === "refine") setModeInternal("build");
|
|
2655
|
+
if (hasUnsupported && mode === "refine") setModeInternal("build");
|
|
2656
|
+
}, [hasContent, hasUnsupported, mode]);
|
|
2657
|
+
const setMode = useCallback((next) => {
|
|
2658
|
+
setModeInternal(next);
|
|
2659
|
+
}, []);
|
|
2629
2660
|
useEffect(() => () => abortRef.current?.abort(), []);
|
|
2630
2661
|
const submit = useCallback(async () => {
|
|
2631
2662
|
const problem = prompt.trim();
|
|
@@ -2643,8 +2674,15 @@ function useAiFigure(generator) {
|
|
|
2643
2674
|
abortRef.current = controller;
|
|
2644
2675
|
setIsLoading(true);
|
|
2645
2676
|
setError(null);
|
|
2677
|
+
setTokens(0);
|
|
2646
2678
|
try {
|
|
2647
|
-
const generated = await generator(problem, {
|
|
2679
|
+
const generated = await generator(problem, {
|
|
2680
|
+
signal: controller.signal,
|
|
2681
|
+
onProgress: (info) => {
|
|
2682
|
+
if (requestId === requestIdRef.current) setTokens(info.tokens);
|
|
2683
|
+
},
|
|
2684
|
+
...mode === "refine" && currentDsl ? { currentDsl } : {}
|
|
2685
|
+
});
|
|
2648
2686
|
if (controller.signal.aborted || requestId !== requestIdRef.current) return null;
|
|
2649
2687
|
if (!generated.ok) {
|
|
2650
2688
|
setError(generated.message);
|
|
@@ -2656,7 +2694,9 @@ function useAiFigure(generator) {
|
|
|
2656
2694
|
return null;
|
|
2657
2695
|
}
|
|
2658
2696
|
if (requestId === requestIdRef.current) {
|
|
2659
|
-
setError(
|
|
2697
|
+
setError(
|
|
2698
|
+
caught instanceof Error && caught.message ? caught.message : "Kh\xF4ng th\u1EC3 d\u1EF1ng h\xECnh b\u1EB1ng AI."
|
|
2699
|
+
);
|
|
2660
2700
|
}
|
|
2661
2701
|
return null;
|
|
2662
2702
|
} finally {
|
|
@@ -2665,22 +2705,81 @@ function useAiFigure(generator) {
|
|
|
2665
2705
|
setIsLoading(false);
|
|
2666
2706
|
}
|
|
2667
2707
|
}
|
|
2668
|
-
}, [generator, prompt]);
|
|
2669
|
-
|
|
2708
|
+
}, [generator, prompt, mode, currentDsl]);
|
|
2709
|
+
const cancel = useCallback(() => {
|
|
2710
|
+
abortRef.current?.abort();
|
|
2711
|
+
}, []);
|
|
2712
|
+
return {
|
|
2713
|
+
prompt,
|
|
2714
|
+
setPrompt,
|
|
2715
|
+
isLoading,
|
|
2716
|
+
error,
|
|
2717
|
+
submit,
|
|
2718
|
+
cancel,
|
|
2719
|
+
tokens,
|
|
2720
|
+
mode,
|
|
2721
|
+
setMode,
|
|
2722
|
+
entityCount,
|
|
2723
|
+
hasUnsupported
|
|
2724
|
+
};
|
|
2670
2725
|
}
|
|
2671
|
-
|
|
2726
|
+
var BUILD_EXAMPLES = [
|
|
2727
|
+
"Tam gi\xE1c ABC, d\u1EF1ng trung \u0111i\u1EC3m M c\u1EE7a BC",
|
|
2728
|
+
"Tam gi\xE1c ABC vu\xF4ng t\u1EA1i A, AH l\xE0 \u0111\u01B0\u1EDDng cao xu\u1ED1ng BC",
|
|
2729
|
+
"H\xECnh thoi ABCD, hai \u0111\u01B0\u1EDDng ch\xE9o c\u1EAFt nhau t\u1EA1i O",
|
|
2730
|
+
"T\u1EEB \u0111i\u1EC3m M ngo\xE0i \u0111\u01B0\u1EDDng tr\xF2n (O), k\u1EBB hai ti\u1EBFp tuy\u1EBFn"
|
|
2731
|
+
];
|
|
2732
|
+
var REFINE_EXAMPLES = [
|
|
2733
|
+
"Th\xEAm trung \u0111i\u1EC3m M c\u1EE7a BC",
|
|
2734
|
+
"D\u1EF1ng \u0111\u01B0\u1EDDng cao AH xu\u1ED1ng BC",
|
|
2735
|
+
"V\u1EBD \u0111\u01B0\u1EDDng tr\xF2n ngo\u1EA1i ti\u1EBFp",
|
|
2736
|
+
"Th\xEAm ti\u1EBFp tuy\u1EBFn t\u1EA1i A"
|
|
2737
|
+
];
|
|
2738
|
+
function AiFigurePrompt({ generator, onGenerated, currentState }) {
|
|
2672
2739
|
const {
|
|
2673
2740
|
prompt,
|
|
2674
2741
|
setPrompt,
|
|
2675
2742
|
isLoading,
|
|
2676
2743
|
error,
|
|
2677
|
-
submit
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2744
|
+
submit,
|
|
2745
|
+
cancel,
|
|
2746
|
+
tokens,
|
|
2747
|
+
mode,
|
|
2748
|
+
setMode,
|
|
2749
|
+
entityCount,
|
|
2750
|
+
hasUnsupported
|
|
2751
|
+
} = useAiFigure(generator, { currentState });
|
|
2752
|
+
const [elapsed, setElapsed] = useState(0);
|
|
2753
|
+
useEffect(() => {
|
|
2754
|
+
if (!isLoading) {
|
|
2755
|
+
setElapsed(0);
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
setElapsed(0);
|
|
2759
|
+
const id = setInterval(() => setElapsed((s) => s + 1), 1e3);
|
|
2760
|
+
return () => clearInterval(id);
|
|
2761
|
+
}, [isLoading]);
|
|
2762
|
+
const handleSubmit = useCallback(
|
|
2763
|
+
async (event) => {
|
|
2764
|
+
event.preventDefault();
|
|
2765
|
+
const generated = await submit();
|
|
2766
|
+
if (generated) onGenerated(generated);
|
|
2767
|
+
},
|
|
2768
|
+
[onGenerated, submit]
|
|
2769
|
+
);
|
|
2770
|
+
const handleSwitchToBuild = useCallback(() => {
|
|
2771
|
+
if (currentState && currentState.order.length > 0) {
|
|
2772
|
+
const ok = window.confirm(
|
|
2773
|
+
"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?"
|
|
2774
|
+
);
|
|
2775
|
+
if (!ok) return;
|
|
2776
|
+
}
|
|
2777
|
+
setMode("build");
|
|
2778
|
+
}, [currentState, setMode]);
|
|
2779
|
+
const primaryLabel = isLoading ? tokens > 0 ? `\u0110ang d\u1EF1ng ${tokens}tok / ${elapsed}s \u2014 Hu\u1EF7` : `\u0110ang d\u1EF1ng... ${elapsed}s \u2014 Hu\u1EF7` : "D\u1EF1ng b\u1EB1ng AI";
|
|
2780
|
+
const hasContent = currentState != null && currentState.order.length > 0;
|
|
2781
|
+
const examples = mode === "refine" ? REFINE_EXAMPLES : BUILD_EXAMPLES;
|
|
2782
|
+
const refineChipLabel = entityCount.points + entityCount.shapes > 0 ? `Th\xEAm v\xE0o \xB7 ${entityCount.points}\u0111, ${entityCount.shapes}\u0111o\u1EA1n` : "Th\xEAm v\xE0o";
|
|
2684
2783
|
return /* @__PURE__ */ jsxs(
|
|
2685
2784
|
"form",
|
|
2686
2785
|
{
|
|
@@ -2690,7 +2789,47 @@ function AiFigurePrompt({ generator, onGenerated }) {
|
|
|
2690
2789
|
},
|
|
2691
2790
|
className: "border-b border-slate-200 bg-slate-50 px-3 py-2",
|
|
2692
2791
|
children: [
|
|
2693
|
-
/* @__PURE__ */ jsx(
|
|
2792
|
+
/* @__PURE__ */ jsx(
|
|
2793
|
+
"label",
|
|
2794
|
+
{
|
|
2795
|
+
htmlFor: "geometry-ai-prompt",
|
|
2796
|
+
className: "mb-1 block text-xs font-medium text-slate-600",
|
|
2797
|
+
children: "D\u1EF1ng h\xECnh b\u1EB1ng AI"
|
|
2798
|
+
}
|
|
2799
|
+
),
|
|
2800
|
+
hasContent && /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2", children: [
|
|
2801
|
+
/* @__PURE__ */ jsx(
|
|
2802
|
+
"button",
|
|
2803
|
+
{
|
|
2804
|
+
type: "button",
|
|
2805
|
+
"data-testid": "geometry-ai-mode-refine",
|
|
2806
|
+
onClick: () => setMode("refine"),
|
|
2807
|
+
disabled: isLoading || hasUnsupported,
|
|
2808
|
+
className: `rounded-full border px-2 py-0.5 text-[11px] transition ${mode === "refine" ? "border-emerald-600 bg-emerald-100 text-emerald-800" : "border-slate-300 bg-white text-slate-600 hover:border-emerald-400"} ${hasUnsupported ? "cursor-not-allowed opacity-50" : ""}`,
|
|
2809
|
+
title: hasUnsupported ? "H\xECnh hi\u1EC7n t\u1EA1i c\xF3 \u0111\u1ED1i t\u01B0\u1EE3ng ngo\xE0i DSL \u2014 ch\u1EC9 d\u1EF1ng m\u1EDBi \u0111\u01B0\u1EE3c" : refineChipLabel,
|
|
2810
|
+
children: refineChipLabel
|
|
2811
|
+
}
|
|
2812
|
+
),
|
|
2813
|
+
/* @__PURE__ */ jsx(
|
|
2814
|
+
"button",
|
|
2815
|
+
{
|
|
2816
|
+
type: "button",
|
|
2817
|
+
"data-testid": "geometry-ai-mode-build",
|
|
2818
|
+
onClick: handleSwitchToBuild,
|
|
2819
|
+
disabled: isLoading,
|
|
2820
|
+
className: `rounded-full border px-2 py-0.5 text-[11px] transition ${mode === "build" ? "border-emerald-600 bg-emerald-100 text-emerald-800" : "border-slate-300 bg-white text-slate-600 hover:border-emerald-400"}`,
|
|
2821
|
+
children: "D\u1EF1ng m\u1EDBi"
|
|
2822
|
+
}
|
|
2823
|
+
),
|
|
2824
|
+
hasUnsupported && /* @__PURE__ */ jsx(
|
|
2825
|
+
"span",
|
|
2826
|
+
{
|
|
2827
|
+
className: "text-[10px] text-amber-700",
|
|
2828
|
+
"data-testid": "geometry-ai-unsupported-warning",
|
|
2829
|
+
children: "H\xECnh c\xF3 \u0111\u1ED1i t\u01B0\u1EE3ng ngo\xE0i DSL"
|
|
2830
|
+
}
|
|
2831
|
+
)
|
|
2832
|
+
] }),
|
|
2694
2833
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
2695
2834
|
/* @__PURE__ */ jsx(
|
|
2696
2835
|
"textarea",
|
|
@@ -2701,21 +2840,42 @@ function AiFigurePrompt({ generator, onGenerated }) {
|
|
|
2701
2840
|
onChange: (event) => setPrompt(event.target.value),
|
|
2702
2841
|
disabled: isLoading,
|
|
2703
2842
|
rows: 2,
|
|
2704
|
-
placeholder: "V\xED d\u1EE5: Cho tam gi\xE1c ABC, d\u1EF1ng \u0111\u01B0\u1EDDng cao AH.",
|
|
2843
|
+
placeholder: mode === "refine" ? "V\xED d\u1EE5: th\xEAm trung \u0111i\u1EC3m M c\u1EE7a BC" : "V\xED d\u1EE5: Cho tam gi\xE1c ABC, d\u1EF1ng \u0111\u01B0\u1EDDng cao AH.",
|
|
2705
2844
|
className: "min-h-12 flex-1 resize-none rounded border border-slate-300 bg-white px-2 py-1.5 text-xs text-slate-800 outline-none focus:border-emerald-500 disabled:opacity-60"
|
|
2706
2845
|
}
|
|
2707
2846
|
),
|
|
2708
|
-
/* @__PURE__ */ jsx(
|
|
2847
|
+
isLoading ? /* @__PURE__ */ jsx(
|
|
2848
|
+
"button",
|
|
2849
|
+
{
|
|
2850
|
+
type: "button",
|
|
2851
|
+
onClick: cancel,
|
|
2852
|
+
className: "rounded bg-amber-600 px-3 py-2 text-xs font-medium text-white transition hover:bg-amber-700",
|
|
2853
|
+
children: primaryLabel
|
|
2854
|
+
}
|
|
2855
|
+
) : /* @__PURE__ */ jsx(
|
|
2709
2856
|
"button",
|
|
2710
2857
|
{
|
|
2711
2858
|
type: "submit",
|
|
2712
|
-
disabled:
|
|
2859
|
+
disabled: !prompt.trim(),
|
|
2713
2860
|
className: "rounded bg-emerald-600 px-3 py-2 text-xs font-medium text-white transition hover:bg-emerald-700 disabled:opacity-50",
|
|
2714
|
-
children:
|
|
2861
|
+
children: primaryLabel
|
|
2715
2862
|
}
|
|
2716
2863
|
)
|
|
2717
2864
|
] }),
|
|
2718
|
-
error && /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-1 text-xs text-red-600", children: error })
|
|
2865
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-1 text-xs text-red-600", children: error }),
|
|
2866
|
+
!isLoading && !prompt.trim() && !error && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-1", children: [
|
|
2867
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-slate-500", children: "G\u1EE3i \xFD:" }),
|
|
2868
|
+
examples.map((ex) => /* @__PURE__ */ jsx(
|
|
2869
|
+
"button",
|
|
2870
|
+
{
|
|
2871
|
+
type: "button",
|
|
2872
|
+
onClick: () => setPrompt(ex),
|
|
2873
|
+
className: "rounded-full border border-slate-300 bg-white px-2 py-0.5 text-[10px] text-slate-600 transition hover:border-emerald-400 hover:bg-emerald-50 hover:text-emerald-700",
|
|
2874
|
+
children: ex
|
|
2875
|
+
},
|
|
2876
|
+
ex
|
|
2877
|
+
))
|
|
2878
|
+
] })
|
|
2719
2879
|
]
|
|
2720
2880
|
}
|
|
2721
2881
|
);
|
|
@@ -2752,6 +2912,11 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
2752
2912
|
onSelectionChangeRef.current = onSelectionChange;
|
|
2753
2913
|
}, [onSelectionChange]);
|
|
2754
2914
|
useEditorState({ store, onHistoryChange });
|
|
2915
|
+
const currentSceneState = useSyncExternalStore(
|
|
2916
|
+
(cb) => store.subscribe(cb),
|
|
2917
|
+
() => store.getState(),
|
|
2918
|
+
() => store.getState()
|
|
2919
|
+
);
|
|
2755
2920
|
useEffect(() => {
|
|
2756
2921
|
const sync = () => setHasContent(Object.keys(store.getState().objects).length > 0);
|
|
2757
2922
|
sync();
|
|
@@ -2945,7 +3110,7 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
2945
3110
|
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" })
|
|
2946
3111
|
] }) })
|
|
2947
3112
|
] }),
|
|
2948
|
-
generateGeometryFigure && /* @__PURE__ */ jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure }),
|
|
3113
|
+
generateGeometryFigure && /* @__PURE__ */ jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure, currentState: currentSceneState }),
|
|
2949
3114
|
/* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1", children: /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
2950
3115
|
MiniBoard2D,
|
|
2951
3116
|
{
|
|
@@ -3070,6 +3235,36 @@ var GeometryEditorPanel = forwardRef(
|
|
|
3070
3235
|
return /* @__PURE__ */ jsx(ToastProvider, { children: /* @__PURE__ */ jsx(GeometryEditorPanelInner, { ...props, ref }) });
|
|
3071
3236
|
}
|
|
3072
3237
|
);
|
|
3238
|
+
function makeDslRenderRow(store) {
|
|
3239
|
+
return function renderDslRow(obj, defaults) {
|
|
3240
|
+
const state = store.getState();
|
|
3241
|
+
const noop = () => {
|
|
3242
|
+
};
|
|
3243
|
+
return /* @__PURE__ */ jsx(
|
|
3244
|
+
ObjectRow,
|
|
3245
|
+
{
|
|
3246
|
+
obj,
|
|
3247
|
+
state,
|
|
3248
|
+
selected: defaults.selected,
|
|
3249
|
+
onSelect: defaults.onClick,
|
|
3250
|
+
onToggleVisible: (id) => {
|
|
3251
|
+
const o = state.objects[id];
|
|
3252
|
+
if (!o) return;
|
|
3253
|
+
store.dispatch({ type: "UPDATE", payload: { id, patch: { visible: !o.visible } } });
|
|
3254
|
+
},
|
|
3255
|
+
onToggleLocked: (id) => {
|
|
3256
|
+
const o = state.objects[id];
|
|
3257
|
+
if (!o) return;
|
|
3258
|
+
store.dispatch({ type: "UPDATE", payload: { id, patch: { locked: !o.locked } } });
|
|
3259
|
+
},
|
|
3260
|
+
onRename: noop,
|
|
3261
|
+
onChangeColor: noop,
|
|
3262
|
+
onDelete: (id) => store.dispatch({ type: "DELETE", payload: { id } }),
|
|
3263
|
+
describe: describeDsl
|
|
3264
|
+
}
|
|
3265
|
+
);
|
|
3266
|
+
};
|
|
3267
|
+
}
|
|
3073
3268
|
function parseInitialState(data) {
|
|
3074
3269
|
if (!isGeometryCustomData(data)) return null;
|
|
3075
3270
|
return deserializeBoard(data.jsonState);
|
|
@@ -3100,6 +3295,7 @@ var GeometryStampHost = forwardRef(
|
|
|
3100
3295
|
onSelect: (key) => setSelectedTool(key),
|
|
3101
3296
|
enabled: !isMobile
|
|
3102
3297
|
});
|
|
3298
|
+
const renderRow = useMemo(() => makeDslRenderRow(sceneStore), [sceneStore]);
|
|
3103
3299
|
const handleInsert = useCallback(
|
|
3104
3300
|
async (jsonState, svgString) => {
|
|
3105
3301
|
if (!api) return;
|
|
@@ -3161,7 +3357,8 @@ var GeometryStampHost = forwardRef(
|
|
|
3161
3357
|
onObjectSelect: (id) => {
|
|
3162
3358
|
setSelectedObjectId(id ?? void 0);
|
|
3163
3359
|
panelRef.current?.selectObject(id);
|
|
3164
|
-
}
|
|
3360
|
+
},
|
|
3361
|
+
renderRow
|
|
3165
3362
|
},
|
|
3166
3363
|
isMobile,
|
|
3167
3364
|
drawerOpen,
|
|
@@ -3196,5 +3393,5 @@ var GeometryStampHost = forwardRef(
|
|
|
3196
3393
|
);
|
|
3197
3394
|
|
|
3198
3395
|
export { GeometryStampHost };
|
|
3199
|
-
//# sourceMappingURL=host-
|
|
3200
|
-
//# sourceMappingURL=host-
|
|
3396
|
+
//# sourceMappingURL=host-L7FMFZUW.mjs.map
|
|
3397
|
+
//# sourceMappingURL=host-L7FMFZUW.mjs.map
|