@xom11/whiteboard 0.24.1 → 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 +85 -12
- package/dist/ai.d.mts +472 -0
- package/dist/ai.d.ts +472 -0
- package/dist/ai.js +2156 -0
- package/dist/ai.js.map +1 -0
- package/dist/ai.mjs +1495 -0
- package/dist/ai.mjs.map +1 -0
- package/dist/catalog.json +4 -4
- package/dist/chunk-73Q7ADVL.mjs +35 -0
- package/dist/chunk-73Q7ADVL.mjs.map +1 -0
- 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-YIPI3WUL.mjs → chunk-ESVPQWHX.mjs} +5 -5
- package/dist/{chunk-YIPI3WUL.mjs.map → chunk-ESVPQWHX.mjs.map} +1 -1
- package/dist/{chunk-IBTRMWD6.mjs → chunk-I24QOHPU.mjs} +3 -3
- package/dist/{chunk-IBTRMWD6.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-WWMQ2VHZ.mjs → chunk-NDEZJKNY.mjs} +4 -4
- package/dist/{chunk-WWMQ2VHZ.mjs.map → chunk-NDEZJKNY.mjs.map} +1 -1
- package/dist/{chunk-CSCF3YFZ.mjs → chunk-ONBCUWVI.mjs} +6 -4
- package/dist/chunk-ONBCUWVI.mjs.map +1 -0
- package/dist/{chunk-6V4SH4JJ.mjs → chunk-REIJZDVZ.mjs} +6 -35
- package/dist/chunk-REIJZDVZ.mjs.map +1 -0
- package/dist/{chunk-4D5CSIJO.mjs → chunk-TB4CL25L.mjs} +10 -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-MFOGFFIL.mjs → chunk-VRHWDZ66.mjs} +6 -5
- package/dist/chunk-VRHWDZ66.mjs.map +1 -0
- package/dist/{chunk-CRAPWQKJ.mjs → chunk-YSJOVBCD.mjs} +4 -4
- package/dist/{chunk-CRAPWQKJ.mjs.map → chunk-YSJOVBCD.mjs.map} +1 -1
- package/dist/geometry-2d.d.mts +2 -1
- package/dist/geometry-2d.d.ts +2 -1
- package/dist/geometry-2d.js +1383 -23
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +7 -5
- package/dist/geometry-3d.d.mts +2 -1
- package/dist/geometry-3d.d.ts +2 -1
- package/dist/geometry-3d.js +2 -2
- package/dist/geometry-3d.js.map +1 -1
- package/dist/geometry-3d.mjs +6 -4
- package/dist/graph-2d.d.mts +2 -1
- package/dist/graph-2d.d.ts +2 -1
- package/dist/graph-2d.js +2 -2
- package/dist/graph-2d.js.map +1 -1
- package/dist/graph-2d.mjs +9 -7
- package/dist/{host-TLIXN4CF.mjs → host-A64ITWVX.mjs} +8 -6
- package/dist/host-A64ITWVX.mjs.map +1 -0
- package/dist/{host-DOAYVL35.mjs → host-L7FMFZUW.mjs} +228 -30
- package/dist/host-L7FMFZUW.mjs.map +1 -0
- package/dist/{host-GKNQBBUE.mjs → host-QK53UYMD.mjs} +12 -10
- package/dist/host-QK53UYMD.mjs.map +1 -0
- package/dist/index.d.mts +4 -616
- package/dist/index.d.ts +4 -616
- package/dist/index.js +8889 -8529
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +21 -1012
- package/dist/index.mjs.map +1 -1
- package/dist/latex.d.mts +2 -1
- package/dist/latex.d.ts +2 -1
- 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-3NZS6A6Q.mjs.map → serialize-SRJVKYUG.mjs.map} +1 -1
- package/dist/{types-rA4slL08.d.ts → types-DWRyCa2m.d.mts} +139 -1
- package/dist/{types-rA4slL08.d.mts → types-DWRyCa2m.d.ts} +139 -1
- package/package.json +6 -1
- package/dist/chunk-4D5CSIJO.mjs.map +0 -1
- package/dist/chunk-6V4SH4JJ.mjs.map +0 -1
- package/dist/chunk-BKSXPNPQ.mjs.map +0 -1
- package/dist/chunk-CSCF3YFZ.mjs.map +0 -1
- package/dist/chunk-MFOGFFIL.mjs.map +0 -1
- package/dist/chunk-ZBJBQKJ2.mjs.map +0 -1
- package/dist/host-DOAYVL35.mjs.map +0 -1
- package/dist/host-GKNQBBUE.mjs.map +0 -1
- package/dist/host-TLIXN4CF.mjs.map +0 -1
- package/dist/render-SA4JTOW3.mjs +0 -8
- package/dist/serialize-3NZS6A6Q.mjs +0 -6
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useToolStateMachine } from './chunk-NVJ7K3DK.mjs';
|
|
3
|
-
import { serializeBoard, renderGeometrySvgFromState, isGeometryCustomData, deserializeBoard } from './chunk-MFOGFFIL.mjs';
|
|
4
|
-
import { JxgRenderer } from './chunk-BKSXPNPQ.mjs';
|
|
5
2
|
import { useChordShortcut } from './chunk-HNQLZIEP.mjs';
|
|
6
|
-
import {
|
|
3
|
+
import { useToolStateMachine } from './chunk-NVJ7K3DK.mjs';
|
|
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';
|
|
7
6
|
import { themeLabel, paletteFor, themeAxis, themeGrid } from './chunk-R5FL6S7L.mjs';
|
|
7
|
+
import { JxgRenderer } from './chunk-AYSFWUPK.mjs';
|
|
8
8
|
import './chunk-ICR4CVOE.mjs';
|
|
9
|
-
import {
|
|
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';
|
|
12
|
+
import { DEFAULT_VIEW_2D } from './chunk-73Q7ADVL.mjs';
|
|
13
|
+
import './chunk-B4NJJZFR.mjs';
|
|
11
14
|
import { useIsMobile } from './chunk-P2AOIF7S.mjs';
|
|
12
15
|
import { insertStampImage } from './chunk-QGNU34T7.mjs';
|
|
13
16
|
import './chunk-5UTGXHLJ.mjs';
|
|
14
|
-
import { forwardRef, useRef, useId, useState, useEffect, useCallback, useImperativeHandle,
|
|
17
|
+
import { forwardRef, useRef, useId, useState, useEffect, useCallback, useImperativeHandle, useSyncExternalStore, useMemo, useLayoutEffect } from 'react';
|
|
15
18
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
16
19
|
import { createPortal } from 'react-dom';
|
|
17
20
|
|
|
@@ -2619,12 +2622,41 @@ var TransformParamPopover = ({ kind, anchor, defaultValue, onConfirm, onCancel,
|
|
|
2619
2622
|
);
|
|
2620
2623
|
return createPortal(node, document.body);
|
|
2621
2624
|
};
|
|
2622
|
-
function useAiFigure(generator) {
|
|
2625
|
+
function useAiFigure(generator, options = {}) {
|
|
2626
|
+
const { currentState } = options;
|
|
2623
2627
|
const [prompt, setPrompt] = useState("");
|
|
2624
2628
|
const [isLoading, setIsLoading] = useState(false);
|
|
2625
2629
|
const [error, setError] = useState(null);
|
|
2630
|
+
const [tokens, setTokens] = useState(0);
|
|
2626
2631
|
const abortRef = useRef(null);
|
|
2627
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
|
+
}, []);
|
|
2628
2660
|
useEffect(() => () => abortRef.current?.abort(), []);
|
|
2629
2661
|
const submit = useCallback(async () => {
|
|
2630
2662
|
const problem = prompt.trim();
|
|
@@ -2642,8 +2674,15 @@ function useAiFigure(generator) {
|
|
|
2642
2674
|
abortRef.current = controller;
|
|
2643
2675
|
setIsLoading(true);
|
|
2644
2676
|
setError(null);
|
|
2677
|
+
setTokens(0);
|
|
2645
2678
|
try {
|
|
2646
|
-
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
|
+
});
|
|
2647
2686
|
if (controller.signal.aborted || requestId !== requestIdRef.current) return null;
|
|
2648
2687
|
if (!generated.ok) {
|
|
2649
2688
|
setError(generated.message);
|
|
@@ -2655,7 +2694,9 @@ function useAiFigure(generator) {
|
|
|
2655
2694
|
return null;
|
|
2656
2695
|
}
|
|
2657
2696
|
if (requestId === requestIdRef.current) {
|
|
2658
|
-
setError(
|
|
2697
|
+
setError(
|
|
2698
|
+
caught instanceof Error && caught.message ? caught.message : "Kh\xF4ng th\u1EC3 d\u1EF1ng h\xECnh b\u1EB1ng AI."
|
|
2699
|
+
);
|
|
2659
2700
|
}
|
|
2660
2701
|
return null;
|
|
2661
2702
|
} finally {
|
|
@@ -2664,22 +2705,81 @@ function useAiFigure(generator) {
|
|
|
2664
2705
|
setIsLoading(false);
|
|
2665
2706
|
}
|
|
2666
2707
|
}
|
|
2667
|
-
}, [generator, prompt]);
|
|
2668
|
-
|
|
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
|
+
};
|
|
2669
2725
|
}
|
|
2670
|
-
|
|
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 }) {
|
|
2671
2739
|
const {
|
|
2672
2740
|
prompt,
|
|
2673
2741
|
setPrompt,
|
|
2674
2742
|
isLoading,
|
|
2675
2743
|
error,
|
|
2676
|
-
submit
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
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";
|
|
2683
2783
|
return /* @__PURE__ */ jsxs(
|
|
2684
2784
|
"form",
|
|
2685
2785
|
{
|
|
@@ -2689,7 +2789,47 @@ function AiFigurePrompt({ generator, onGenerated }) {
|
|
|
2689
2789
|
},
|
|
2690
2790
|
className: "border-b border-slate-200 bg-slate-50 px-3 py-2",
|
|
2691
2791
|
children: [
|
|
2692
|
-
/* @__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
|
+
] }),
|
|
2693
2833
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
2694
2834
|
/* @__PURE__ */ jsx(
|
|
2695
2835
|
"textarea",
|
|
@@ -2700,21 +2840,42 @@ function AiFigurePrompt({ generator, onGenerated }) {
|
|
|
2700
2840
|
onChange: (event) => setPrompt(event.target.value),
|
|
2701
2841
|
disabled: isLoading,
|
|
2702
2842
|
rows: 2,
|
|
2703
|
-
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.",
|
|
2704
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"
|
|
2705
2845
|
}
|
|
2706
2846
|
),
|
|
2707
|
-
/* @__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(
|
|
2708
2856
|
"button",
|
|
2709
2857
|
{
|
|
2710
2858
|
type: "submit",
|
|
2711
|
-
disabled:
|
|
2859
|
+
disabled: !prompt.trim(),
|
|
2712
2860
|
className: "rounded bg-emerald-600 px-3 py-2 text-xs font-medium text-white transition hover:bg-emerald-700 disabled:opacity-50",
|
|
2713
|
-
children:
|
|
2861
|
+
children: primaryLabel
|
|
2714
2862
|
}
|
|
2715
2863
|
)
|
|
2716
2864
|
] }),
|
|
2717
|
-
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
|
+
] })
|
|
2718
2879
|
]
|
|
2719
2880
|
}
|
|
2720
2881
|
);
|
|
@@ -2751,6 +2912,11 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
2751
2912
|
onSelectionChangeRef.current = onSelectionChange;
|
|
2752
2913
|
}, [onSelectionChange]);
|
|
2753
2914
|
useEditorState({ store, onHistoryChange });
|
|
2915
|
+
const currentSceneState = useSyncExternalStore(
|
|
2916
|
+
(cb) => store.subscribe(cb),
|
|
2917
|
+
() => store.getState(),
|
|
2918
|
+
() => store.getState()
|
|
2919
|
+
);
|
|
2754
2920
|
useEffect(() => {
|
|
2755
2921
|
const sync = () => setHasContent(Object.keys(store.getState().objects).length > 0);
|
|
2756
2922
|
sync();
|
|
@@ -2944,7 +3110,7 @@ var GeometryEditorPanelInner = forwardRef(
|
|
|
2944
3110
|
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" })
|
|
2945
3111
|
] }) })
|
|
2946
3112
|
] }),
|
|
2947
|
-
generateGeometryFigure && /* @__PURE__ */ jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure }),
|
|
3113
|
+
generateGeometryFigure && /* @__PURE__ */ jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure, currentState: currentSceneState }),
|
|
2948
3114
|
/* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1", children: /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
2949
3115
|
MiniBoard2D,
|
|
2950
3116
|
{
|
|
@@ -3069,6 +3235,36 @@ var GeometryEditorPanel = forwardRef(
|
|
|
3069
3235
|
return /* @__PURE__ */ jsx(ToastProvider, { children: /* @__PURE__ */ jsx(GeometryEditorPanelInner, { ...props, ref }) });
|
|
3070
3236
|
}
|
|
3071
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
|
+
}
|
|
3072
3268
|
function parseInitialState(data) {
|
|
3073
3269
|
if (!isGeometryCustomData(data)) return null;
|
|
3074
3270
|
return deserializeBoard(data.jsonState);
|
|
@@ -3099,6 +3295,7 @@ var GeometryStampHost = forwardRef(
|
|
|
3099
3295
|
onSelect: (key) => setSelectedTool(key),
|
|
3100
3296
|
enabled: !isMobile
|
|
3101
3297
|
});
|
|
3298
|
+
const renderRow = useMemo(() => makeDslRenderRow(sceneStore), [sceneStore]);
|
|
3102
3299
|
const handleInsert = useCallback(
|
|
3103
3300
|
async (jsonState, svgString) => {
|
|
3104
3301
|
if (!api) return;
|
|
@@ -3160,7 +3357,8 @@ var GeometryStampHost = forwardRef(
|
|
|
3160
3357
|
onObjectSelect: (id) => {
|
|
3161
3358
|
setSelectedObjectId(id ?? void 0);
|
|
3162
3359
|
panelRef.current?.selectObject(id);
|
|
3163
|
-
}
|
|
3360
|
+
},
|
|
3361
|
+
renderRow
|
|
3164
3362
|
},
|
|
3165
3363
|
isMobile,
|
|
3166
3364
|
drawerOpen,
|
|
@@ -3195,5 +3393,5 @@ var GeometryStampHost = forwardRef(
|
|
|
3195
3393
|
);
|
|
3196
3394
|
|
|
3197
3395
|
export { GeometryStampHost };
|
|
3198
|
-
//# sourceMappingURL=host-
|
|
3199
|
-
//# sourceMappingURL=host-
|
|
3396
|
+
//# sourceMappingURL=host-L7FMFZUW.mjs.map
|
|
3397
|
+
//# sourceMappingURL=host-L7FMFZUW.mjs.map
|