@arronqzy/react-view 1.0.13 → 1.0.15
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/styles.css +96 -4
- package/package.json +11 -10
- package/src/panel/ReactViewOnlinePreview.tsx +31 -2
- package/src/panel/ReactViewPanel.tsx +186 -124
- package/src/panel/ai/applyAssistantAction.ts +1 -0
- package/src/panel/components/BusyOverlay.tsx +25 -0
- package/src/panel/components/ElementsLayer.tsx +110 -68
- package/src/panel/components/MaterialSidebar.tsx +15 -0
- package/src/panel/components/MoveableLayer.tsx +8 -0
- package/src/panel/components/PanelCanvas.tsx +3 -0
- package/src/panel/components/PanelConfigSidebar.tsx +140 -91
- package/src/panel/components/SelectLayer.tsx +5 -0
- package/src/panel/components/WorkspaceConfigSidebar.tsx +1 -0
- package/src/panel/components/WorkspaceProjectNav.tsx +27 -4
- package/src/panel/components/config/PanelConfigScene3dSection.tsx +874 -0
- package/src/panel/components/scope-config/ScopeTemplateAutocompleteHost.tsx +1 -2
- package/src/panel/components/table/PanelConfigTableSection.tsx +82 -50
- package/src/panel/components/table/TableNodeContent.tsx +40 -15
- package/src/panel/hooks/usePanelElements.ts +13 -1
- package/src/panel/hooks/useWorkspaceProjects.ts +133 -66
- package/src/panel/library/workspace-project-cache.ts +8 -2
- package/src/panel/library/workspace-project-db.ts +29 -11
- package/src/panel/library/workspace-snapshot.ts +21 -4
- package/src/panel/scope/view-scope-store.ts +8 -0
- package/src/panel/types.ts +4 -3
- package/src/panel/utils/async-work.ts +178 -0
- package/src/panel/utils/gridPlacement.ts +29 -0
- package/src/panel/utils/panelElementDefaults.ts +37 -1
- package/src/panel/utils/scope-autocomplete.ts +0 -114
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { TranslateFn } from "@arronqzy/i18n";
|
|
2
2
|
import { tForLocale } from "@arronqzy/i18n";
|
|
3
|
-
import
|
|
3
|
+
import { createDefaultScene3dConfig } from "@arronqzy/view-scene3d";
|
|
4
|
+
import type { PanelChartConfig, PanelLayer, PanelElement } from "../types";
|
|
4
5
|
import { createDefaultTableConfig, type PanelTableConfig } from "@arronqzy/view-table";
|
|
5
6
|
|
|
6
7
|
const tFallback = tForLocale("zh-CN");
|
|
@@ -21,6 +22,7 @@ const DEFAULT_NODE_NAME_KEYS: Record<string, string> = {
|
|
|
21
22
|
audio: "panel.defaults.audio",
|
|
22
23
|
reference: "panel.defaults.reference",
|
|
23
24
|
geometry: "panel.defaults.geometry",
|
|
25
|
+
scene3d: "panel.defaults.scene3d",
|
|
24
26
|
table: "panel.defaults.table",
|
|
25
27
|
};
|
|
26
28
|
|
|
@@ -80,6 +82,8 @@ export function getDefaultSizeByMaterial(materialType: string) {
|
|
|
80
82
|
return { width: 280, height: 180 };
|
|
81
83
|
case "geometry":
|
|
82
84
|
return { width: 220, height: 220 };
|
|
85
|
+
case "scene3d":
|
|
86
|
+
return { width: 480, height: 320 };
|
|
83
87
|
case "table":
|
|
84
88
|
return { width: 480, height: 280 };
|
|
85
89
|
default:
|
|
@@ -87,6 +91,33 @@ export function getDefaultSizeByMaterial(materialType: string) {
|
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
93
|
|
|
94
|
+
export function cssTextLineHeight(
|
|
95
|
+
value: number | "auto" | undefined
|
|
96
|
+
): string | undefined {
|
|
97
|
+
if (value === "auto") return "normal";
|
|
98
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
99
|
+
return String(value);
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function cssTextAlignStyle(align: PanelElement["textAlign"]): {
|
|
105
|
+
textAlign: "left" | "center" | "right" | "justify";
|
|
106
|
+
display?: "flex";
|
|
107
|
+
flexDirection?: "column";
|
|
108
|
+
justifyContent?: "center";
|
|
109
|
+
} {
|
|
110
|
+
if (align === "middle") {
|
|
111
|
+
return {
|
|
112
|
+
textAlign: "center",
|
|
113
|
+
display: "flex",
|
|
114
|
+
flexDirection: "column",
|
|
115
|
+
justifyContent: "center",
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return { textAlign: align ?? "left" };
|
|
119
|
+
}
|
|
120
|
+
|
|
90
121
|
export function getDefaultTextContent(materialType: string, t: TranslateFn = tFallback) {
|
|
91
122
|
if (materialType !== "text") return {};
|
|
92
123
|
return {
|
|
@@ -188,3 +219,8 @@ export function getDefaultTableConfig(
|
|
|
188
219
|
if (cfg.columns?.[2]) cfg.columns[2].title = t("panel.config.tableColScore");
|
|
189
220
|
return cfg;
|
|
190
221
|
}
|
|
222
|
+
|
|
223
|
+
export function getDefaultScene3dConfigForMaterial(materialType: string) {
|
|
224
|
+
if (materialType !== "scene3d") return {};
|
|
225
|
+
return { scene3d: createDefaultScene3dConfig() };
|
|
226
|
+
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
export type ScopeAutocompleteState = {
|
|
2
|
-
templateStart: number;
|
|
3
|
-
cursor: number;
|
|
4
|
-
path: string[];
|
|
5
|
-
partialKey: string;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
function getValueAtPath(scope: unknown, path: string[]): unknown {
|
|
9
|
-
let current: unknown = scope;
|
|
10
|
-
for (const part of path) {
|
|
11
|
-
if (current === null || typeof current !== "object") return undefined;
|
|
12
|
-
current = (current as Record<string, unknown>)[part];
|
|
13
|
-
}
|
|
14
|
-
return current;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function listObjectKeys(value: unknown): string[] {
|
|
18
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
19
|
-
return [];
|
|
20
|
-
}
|
|
21
|
-
return Object.keys(value as Record<string, unknown>);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** 解析光标处未闭合的 scope 模版表达式 */
|
|
25
|
-
export function parseScopeAutocomplete(
|
|
26
|
-
text: string,
|
|
27
|
-
cursor: number,
|
|
28
|
-
scope: unknown
|
|
29
|
-
): ScopeAutocompleteState | null {
|
|
30
|
-
const before = text.slice(0, cursor);
|
|
31
|
-
const templateStart = before.lastIndexOf("{");
|
|
32
|
-
if (templateStart < 0) return null;
|
|
33
|
-
|
|
34
|
-
const inner = before.slice(templateStart + 1);
|
|
35
|
-
if (inner.includes("}")) return null;
|
|
36
|
-
if (!inner.startsWith("scope")) return null;
|
|
37
|
-
|
|
38
|
-
let body = inner.slice("scope".length);
|
|
39
|
-
if (body === "" || body === "?") {
|
|
40
|
-
return { templateStart, cursor, path: [], partialKey: "" };
|
|
41
|
-
}
|
|
42
|
-
if (!body.startsWith("?.")) return null;
|
|
43
|
-
|
|
44
|
-
body = body.slice(2);
|
|
45
|
-
if (body === "") {
|
|
46
|
-
return { templateStart, cursor, path: [], partialKey: "" };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const segments = body.split("?.");
|
|
50
|
-
const endsWithSeparator = inner.endsWith("?.");
|
|
51
|
-
|
|
52
|
-
if (endsWithSeparator) {
|
|
53
|
-
const path = segments.filter((segment) => segment.length > 0);
|
|
54
|
-
return { templateStart, cursor, path, partialKey: "" };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const lastSegment = segments[segments.length - 1] ?? "";
|
|
58
|
-
const prefixSegments = segments.slice(0, -1).filter((segment) => segment.length > 0);
|
|
59
|
-
const parent = getValueAtPath(scope, prefixSegments);
|
|
60
|
-
const keys = listObjectKeys(parent);
|
|
61
|
-
|
|
62
|
-
if (lastSegment.length === 0) {
|
|
63
|
-
return { templateStart, cursor, path: prefixSegments, partialKey: "" };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (keys.includes(lastSegment)) {
|
|
67
|
-
return {
|
|
68
|
-
templateStart,
|
|
69
|
-
cursor,
|
|
70
|
-
path: [...prefixSegments, lastSegment],
|
|
71
|
-
partialKey: "",
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
templateStart,
|
|
77
|
-
cursor,
|
|
78
|
-
path: prefixSegments,
|
|
79
|
-
partialKey: lastSegment,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function getScopeAutocompleteSuggestions(
|
|
84
|
-
scope: unknown,
|
|
85
|
-
state: ScopeAutocompleteState
|
|
86
|
-
): string[] {
|
|
87
|
-
const parent =
|
|
88
|
-
state.partialKey.length > 0
|
|
89
|
-
? getValueAtPath(scope, state.path)
|
|
90
|
-
: state.path.length > 0
|
|
91
|
-
? getValueAtPath(scope, state.path)
|
|
92
|
-
: scope;
|
|
93
|
-
|
|
94
|
-
const keys = listObjectKeys(parent);
|
|
95
|
-
if (state.partialKey.length === 0) return keys;
|
|
96
|
-
return keys.filter((key) => key.startsWith(state.partialKey));
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function buildScopeExpression(path: string[], selectedKey: string): string {
|
|
100
|
-
return `scope?.${[...path, selectedKey].join("?.")}`;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function applyScopeAutocompleteSelection(
|
|
104
|
-
text: string,
|
|
105
|
-
state: ScopeAutocompleteState,
|
|
106
|
-
selectedKey: string
|
|
107
|
-
): { value: string; cursor: number } {
|
|
108
|
-
const expr = buildScopeExpression(state.path, selectedKey);
|
|
109
|
-
const before = text.slice(0, state.templateStart + 1);
|
|
110
|
-
const after = text.slice(state.cursor);
|
|
111
|
-
const value = `${before}${expr}${after}`;
|
|
112
|
-
const cursor = before.length + expr.length;
|
|
113
|
-
return { value, cursor };
|
|
114
|
-
}
|