@arronqzy/react-view 1.0.5 → 1.0.7
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 +519 -9
- package/package.json +12 -4
- package/src/core/template.tsx +12 -2
- package/src/panel/ReactViewOnlinePreview.tsx +18 -8
- package/src/panel/ReactViewPanel.tsx +386 -170
- package/src/panel/ai/AssistantChatPanel.tsx +895 -0
- package/src/panel/ai/AssistantMarkdown.tsx +256 -0
- package/src/panel/ai/applyAssistantAction.ts +652 -0
- package/src/panel/ai/revealConfigField.ts +137 -0
- package/src/panel/components/ConfigHintIcon.tsx +6 -2
- package/src/panel/components/ElementsLayer.tsx +37 -18
- package/src/panel/components/MaterialSidebar.tsx +157 -109
- package/src/panel/components/MoveableLayer.tsx +7 -6
- package/src/panel/components/PanelConfigSidebar.tsx +434 -389
- package/src/panel/components/ViewElementScopePanel.tsx +9 -5
- package/src/panel/components/WorkspaceConfigSidebar.tsx +5 -2
- package/src/panel/components/WorkspaceProjectNav.tsx +25 -14
- package/src/panel/components/WorkspaceStageSplit.tsx +3 -1
- package/src/panel/components/scope-config/ScopeTemplatePreviewHost.tsx +11 -7
- package/src/panel/components/scope-config/ScopeTemplateUsageHint.tsx +6 -18
- package/src/panel/components/scope-config/ScopeTemplateWarningsPanel.tsx +5 -2
- package/src/panel/components/table/ConditionEditor.tsx +205 -0
- package/src/panel/components/table/JsonCodeEditor.tsx +115 -0
- package/src/panel/components/table/PanelConfigTableSection.tsx +2192 -0
- package/src/panel/components/table/TableNodeContent.tsx +544 -0
- package/src/panel/constants/messages.ts +76 -34
- package/src/panel/hooks/usePanelElements.ts +64 -52
- package/src/panel/hooks/useWorkspaceProjects.ts +11 -8
- package/src/panel/types.ts +4 -0
- package/src/panel/utils/panelElementDefaults.ts +69 -39
- package/src/panel/utils/scope-field-labels.ts +51 -38
- package/src/panel/utils/scope-template-preview.ts +10 -6
- package/src/panel/utils/scope-template-spread.ts +44 -21
- package/src/panel/utils/scope-template-warnings.ts +28 -16
- package/src/panel/utils/scope-template.ts +82 -2
- package/src/tailwind.css +17 -9
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
|
|
3
|
+
type Segment =
|
|
4
|
+
| { type: "text"; value: string }
|
|
5
|
+
| { type: "code"; value: string }
|
|
6
|
+
| { type: "bold"; value: string }
|
|
7
|
+
| { type: "italic"; value: string }
|
|
8
|
+
| { type: "link"; label: string; href: string };
|
|
9
|
+
|
|
10
|
+
function parseInline(text: string): Segment[] {
|
|
11
|
+
const segments: Segment[] = [];
|
|
12
|
+
const re =
|
|
13
|
+
/(`[^`]+`|\*\*[^*]+\*\*|__[^_]+__|\*[^*]+\*|_[^_]+_|\[[^\]]+\]\([^)]+\))/g;
|
|
14
|
+
let last = 0;
|
|
15
|
+
let match: RegExpExecArray | null;
|
|
16
|
+
while ((match = re.exec(text))) {
|
|
17
|
+
if (match.index > last) {
|
|
18
|
+
segments.push({ type: "text", value: text.slice(last, match.index) });
|
|
19
|
+
}
|
|
20
|
+
const token = match[0]!;
|
|
21
|
+
if (token.startsWith("`")) {
|
|
22
|
+
segments.push({ type: "code", value: token.slice(1, -1) });
|
|
23
|
+
} else if (token.startsWith("**") || token.startsWith("__")) {
|
|
24
|
+
segments.push({ type: "bold", value: token.slice(2, -2) });
|
|
25
|
+
} else if (token.startsWith("*") || token.startsWith("_")) {
|
|
26
|
+
segments.push({ type: "italic", value: token.slice(1, -1) });
|
|
27
|
+
} else if (token.startsWith("[")) {
|
|
28
|
+
const m = token.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
|
|
29
|
+
if (m) segments.push({ type: "link", label: m[1]!, href: m[2]! });
|
|
30
|
+
else segments.push({ type: "text", value: token });
|
|
31
|
+
}
|
|
32
|
+
last = match.index + token.length;
|
|
33
|
+
}
|
|
34
|
+
if (last < text.length) {
|
|
35
|
+
segments.push({ type: "text", value: text.slice(last) });
|
|
36
|
+
}
|
|
37
|
+
return segments.length ? segments : [{ type: "text", value: text }];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function Inline({ text }: { text: string }) {
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
{parseInline(text).map((seg, i) => {
|
|
44
|
+
if (seg.type === "code") {
|
|
45
|
+
return (
|
|
46
|
+
<code
|
|
47
|
+
key={i}
|
|
48
|
+
className="rounded bg-muted px-1.5 py-0.5 font-mono text-[12px] text-foreground"
|
|
49
|
+
>
|
|
50
|
+
{seg.value}
|
|
51
|
+
</code>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
if (seg.type === "bold") {
|
|
55
|
+
return (
|
|
56
|
+
<strong key={i} className="font-semibold">
|
|
57
|
+
{seg.value}
|
|
58
|
+
</strong>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
if (seg.type === "italic") {
|
|
62
|
+
return (
|
|
63
|
+
<em key={i} className="italic">
|
|
64
|
+
{seg.value}
|
|
65
|
+
</em>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
if (seg.type === "link") {
|
|
69
|
+
return (
|
|
70
|
+
<a
|
|
71
|
+
key={i}
|
|
72
|
+
href={seg.href}
|
|
73
|
+
target="_blank"
|
|
74
|
+
rel="noreferrer noopener"
|
|
75
|
+
className="text-primary underline underline-offset-2"
|
|
76
|
+
data-no-drag
|
|
77
|
+
>
|
|
78
|
+
{seg.label}
|
|
79
|
+
</a>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return <React.Fragment key={i}>{seg.value}</React.Fragment>;
|
|
83
|
+
})}
|
|
84
|
+
</>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
type Block =
|
|
89
|
+
| { type: "p"; text: string }
|
|
90
|
+
| { type: "h"; level: 1 | 2 | 3; text: string }
|
|
91
|
+
| { type: "ul"; items: string[] }
|
|
92
|
+
| { type: "ol"; items: string[] }
|
|
93
|
+
| { type: "pre"; code: string }
|
|
94
|
+
| { type: "quote"; text: string };
|
|
95
|
+
|
|
96
|
+
function parseBlocks(src: string): Block[] {
|
|
97
|
+
const lines = src.replace(/\r\n/g, "\n").split("\n");
|
|
98
|
+
const blocks: Block[] = [];
|
|
99
|
+
let i = 0;
|
|
100
|
+
|
|
101
|
+
while (i < lines.length) {
|
|
102
|
+
const line = lines[i] ?? "";
|
|
103
|
+
|
|
104
|
+
if (/^```/.test(line)) {
|
|
105
|
+
const code: string[] = [];
|
|
106
|
+
i += 1;
|
|
107
|
+
while (i < lines.length && !/^```/.test(lines[i] ?? "")) {
|
|
108
|
+
code.push(lines[i] ?? "");
|
|
109
|
+
i += 1;
|
|
110
|
+
}
|
|
111
|
+
i += 1;
|
|
112
|
+
blocks.push({ type: "pre", code: code.join("\n") });
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const heading = /^(#{1,3})\s+(.+)$/.exec(line);
|
|
117
|
+
if (heading) {
|
|
118
|
+
blocks.push({
|
|
119
|
+
type: "h",
|
|
120
|
+
level: heading[1]!.length as 1 | 2 | 3,
|
|
121
|
+
text: heading[2]!.trim(),
|
|
122
|
+
});
|
|
123
|
+
i += 1;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (/^>\s?/.test(line)) {
|
|
128
|
+
const parts: string[] = [];
|
|
129
|
+
while (i < lines.length && /^>\s?/.test(lines[i] ?? "")) {
|
|
130
|
+
parts.push((lines[i] ?? "").replace(/^>\s?/, ""));
|
|
131
|
+
i += 1;
|
|
132
|
+
}
|
|
133
|
+
blocks.push({ type: "quote", text: parts.join("\n") });
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (/^\s*[-*]\s+/.test(line)) {
|
|
138
|
+
const items: string[] = [];
|
|
139
|
+
while (i < lines.length && /^\s*[-*]\s+/.test(lines[i] ?? "")) {
|
|
140
|
+
items.push((lines[i] ?? "").replace(/^\s*[-*]\s+/, ""));
|
|
141
|
+
i += 1;
|
|
142
|
+
}
|
|
143
|
+
blocks.push({ type: "ul", items });
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (/^\s*\d+\.\s+/.test(line)) {
|
|
148
|
+
const items: string[] = [];
|
|
149
|
+
while (i < lines.length && /^\s*\d+\.\s+/.test(lines[i] ?? "")) {
|
|
150
|
+
items.push((lines[i] ?? "").replace(/^\s*\d+\.\s+/, ""));
|
|
151
|
+
i += 1;
|
|
152
|
+
}
|
|
153
|
+
blocks.push({ type: "ol", items });
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!line.trim()) {
|
|
158
|
+
i += 1;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const parts: string[] = [line];
|
|
163
|
+
i += 1;
|
|
164
|
+
while (
|
|
165
|
+
i < lines.length &&
|
|
166
|
+
(lines[i] ?? "").trim() &&
|
|
167
|
+
!/^(#{1,3}\s+|```|\s*[-*]\s+|\s*\d+\.\s+|>\s?)/.test(lines[i] ?? "")
|
|
168
|
+
) {
|
|
169
|
+
parts.push(lines[i] ?? "");
|
|
170
|
+
i += 1;
|
|
171
|
+
}
|
|
172
|
+
blocks.push({ type: "p", text: parts.join("\n") });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return blocks;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const headingClass: Record<1 | 2 | 3, string> = {
|
|
179
|
+
1: "mb-1.5 text-[16px] font-semibold tracking-tight text-foreground",
|
|
180
|
+
2: "mb-1 text-[15px] font-semibold tracking-tight text-foreground",
|
|
181
|
+
3: "mb-1 text-[14px] font-semibold text-foreground",
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export function AssistantMarkdown({
|
|
185
|
+
content,
|
|
186
|
+
className = "",
|
|
187
|
+
}: {
|
|
188
|
+
content: string;
|
|
189
|
+
className?: string;
|
|
190
|
+
}) {
|
|
191
|
+
const blocks = useMemo(() => parseBlocks(content.trim()), [content]);
|
|
192
|
+
|
|
193
|
+
if (!content.trim()) return null;
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<div className={`assistant-md space-y-2 text-[14px] leading-6 text-foreground ${className}`}>
|
|
197
|
+
{blocks.map((block, idx) => {
|
|
198
|
+
if (block.type === "h") {
|
|
199
|
+
const Tag = (`h${block.level}` as "h1" | "h2" | "h3");
|
|
200
|
+
return (
|
|
201
|
+
<Tag key={idx} className={headingClass[block.level]}>
|
|
202
|
+
<Inline text={block.text} />
|
|
203
|
+
</Tag>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
if (block.type === "pre") {
|
|
207
|
+
return (
|
|
208
|
+
<pre
|
|
209
|
+
key={idx}
|
|
210
|
+
className="overflow-x-auto rounded-lg border border-border bg-muted/60 p-3 font-mono text-[12px] leading-5 text-foreground"
|
|
211
|
+
>
|
|
212
|
+
<code>{block.code}</code>
|
|
213
|
+
</pre>
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
if (block.type === "ul") {
|
|
217
|
+
return (
|
|
218
|
+
<ul key={idx} className="list-disc space-y-1 pl-5">
|
|
219
|
+
{block.items.map((item, j) => (
|
|
220
|
+
<li key={j}>
|
|
221
|
+
<Inline text={item} />
|
|
222
|
+
</li>
|
|
223
|
+
))}
|
|
224
|
+
</ul>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (block.type === "ol") {
|
|
228
|
+
return (
|
|
229
|
+
<ol key={idx} className="list-decimal space-y-1 pl-5">
|
|
230
|
+
{block.items.map((item, j) => (
|
|
231
|
+
<li key={j}>
|
|
232
|
+
<Inline text={item} />
|
|
233
|
+
</li>
|
|
234
|
+
))}
|
|
235
|
+
</ol>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
if (block.type === "quote") {
|
|
239
|
+
return (
|
|
240
|
+
<blockquote
|
|
241
|
+
key={idx}
|
|
242
|
+
className="border-l-2 border-border pl-3 text-muted-foreground"
|
|
243
|
+
>
|
|
244
|
+
<Inline text={block.text} />
|
|
245
|
+
</blockquote>
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
return (
|
|
249
|
+
<p key={idx} className="whitespace-pre-wrap">
|
|
250
|
+
<Inline text={block.text} />
|
|
251
|
+
</p>
|
|
252
|
+
);
|
|
253
|
+
})}
|
|
254
|
+
</div>
|
|
255
|
+
);
|
|
256
|
+
}
|