@vegintech/langchain-react-agent 0.0.12 → 0.0.14
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/index.d.mts +82 -7
- package/dist/index.mjs +122 -29
- package/package.json +9 -8
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as react from "react";
|
|
2
|
-
import { CSSProperties, ReactNode } from "react";
|
|
2
|
+
import React$1, { CSSProperties, ReactNode } from "react";
|
|
3
3
|
import { Components } from "streamdown";
|
|
4
|
+
import { BaseMessage } from "@langchain/core/messages";
|
|
4
5
|
import { BaseNode, InsertPosition, NodeRender, SenderProps, SkillType, SlotConfigType } from "@ant-design/x/es/sender/interface.ts";
|
|
5
6
|
|
|
6
7
|
//#region src/types.d.ts
|
|
@@ -88,10 +89,7 @@ interface SenderSubmitParams {
|
|
|
88
89
|
/** onPreSend 钩子返回值:只返回消息数组 */
|
|
89
90
|
interface PreSendResult {
|
|
90
91
|
/** 要发送的消息数组 */
|
|
91
|
-
messages:
|
|
92
|
-
type: string;
|
|
93
|
-
content: string;
|
|
94
|
-
}>;
|
|
92
|
+
messages: BaseMessage[];
|
|
95
93
|
}
|
|
96
94
|
/** Sender 组件的可定制参数 */
|
|
97
95
|
interface SenderCustomizationProps {
|
|
@@ -105,6 +103,8 @@ interface SenderCustomizationProps {
|
|
|
105
103
|
header?: BaseNode | NodeRender;
|
|
106
104
|
/** 前缀区域 */
|
|
107
105
|
prefix?: BaseNode | NodeRender;
|
|
106
|
+
/** 粘贴文件时的回调函数 */
|
|
107
|
+
onPasteFile?: (files: FileList) => void;
|
|
108
108
|
}
|
|
109
109
|
/** ChatInput 组件对外暴露的方法 */
|
|
110
110
|
interface AgentChatInputRef {
|
|
@@ -130,11 +130,27 @@ interface ToolParameterSchema {
|
|
|
130
130
|
}
|
|
131
131
|
/** 消息类型,用于区分用户和助手消息 */
|
|
132
132
|
type MessageType = "human" | "ai" | "system" | "tool" | "function";
|
|
133
|
+
/** 消息内容块类型 */
|
|
134
|
+
type MessageContentBlock = {
|
|
135
|
+
type: "text";
|
|
136
|
+
text: string;
|
|
137
|
+
} | {
|
|
138
|
+
type: "image_url";
|
|
139
|
+
image_url: {
|
|
140
|
+
url: string;
|
|
141
|
+
};
|
|
142
|
+
} | {
|
|
143
|
+
type: string;
|
|
144
|
+
[key: string]: unknown;
|
|
145
|
+
};
|
|
146
|
+
/** 消息内容类型:字符串或内容块数组 */
|
|
147
|
+
type MessageContent = string | MessageContentBlock[];
|
|
133
148
|
/** 扩展的消息类型,确保包含 id 和必要的字段 */
|
|
134
149
|
interface ChatMessage {
|
|
135
150
|
id: string;
|
|
136
151
|
type: MessageType;
|
|
137
|
-
|
|
152
|
+
/** 消息内容,保留原始结构(字符串或内容块数组) */
|
|
153
|
+
content: MessageContent;
|
|
138
154
|
name?: string;
|
|
139
155
|
additional_kwargs?: Record<string, unknown>;
|
|
140
156
|
/** 思考内容(来自 additional_kwargs.reasoning_content) */
|
|
@@ -255,6 +271,36 @@ interface AgentChatRef {
|
|
|
255
271
|
/** 聚焦输入框 */
|
|
256
272
|
focusInput: () => void;
|
|
257
273
|
}
|
|
274
|
+
/** Streamdown 安全过滤配置 */
|
|
275
|
+
interface StreamdownSecurityConfig {
|
|
276
|
+
/** 允许的标签及其属性 */
|
|
277
|
+
allowedTags?: Record<string, string[]>;
|
|
278
|
+
/** 作为字面量内容处理的标签(不解析内部 Markdown) */
|
|
279
|
+
literalTagContent?: string[];
|
|
280
|
+
}
|
|
281
|
+
interface MessageListProps {
|
|
282
|
+
messages: ChatMessage[];
|
|
283
|
+
isLoading?: boolean;
|
|
284
|
+
className?: string;
|
|
285
|
+
/** 工具定义列表 */
|
|
286
|
+
tools?: ToolDefinition<any>[];
|
|
287
|
+
/** 工具执行记录 */
|
|
288
|
+
toolExecutions: Map<string, ToolExecutionRecord>;
|
|
289
|
+
/** Markdown 自定义组件 */
|
|
290
|
+
components?: Components;
|
|
291
|
+
/** Streamdown 安全过滤配置 */
|
|
292
|
+
securityConfig?: StreamdownSecurityConfig;
|
|
293
|
+
/** Loading 动画颜色,支持 CSS 颜色值 */
|
|
294
|
+
loadingColor?: string;
|
|
295
|
+
/** Interrupt 渲染函数,用于在消息列表中渲染中断 UI */
|
|
296
|
+
interruptRender?: () => ReactNode;
|
|
297
|
+
/** 空状态配置 */
|
|
298
|
+
emptyState?: {
|
|
299
|
+
/** 空状态标题 */title?: string; /** 空状态描述 */
|
|
300
|
+
description?: string; /** 自定义渲染 */
|
|
301
|
+
render?: () => ReactNode;
|
|
302
|
+
};
|
|
303
|
+
}
|
|
258
304
|
//#endregion
|
|
259
305
|
//#region src/components/AgentChat.d.ts
|
|
260
306
|
declare const AgentChat: react.ForwardRefExoticComponent<AgentChatProps & react.RefAttributes<AgentChatRef>>;
|
|
@@ -266,4 +312,33 @@ declare const AgentChat: react.ForwardRefExoticComponent<AgentChatProps & react.
|
|
|
266
312
|
*/
|
|
267
313
|
declare const ToolCard: React.FC<ToolCardProps>;
|
|
268
314
|
//#endregion
|
|
269
|
-
|
|
315
|
+
//#region src/components/MessageContentRenderer.d.ts
|
|
316
|
+
interface MessageContentRendererProps {
|
|
317
|
+
content: MessageContent;
|
|
318
|
+
components?: Components;
|
|
319
|
+
securityConfig?: MessageListProps["securityConfig"];
|
|
320
|
+
}
|
|
321
|
+
/** 消息内容渲染组件 - 支持字符串和多模态内容块 */
|
|
322
|
+
declare const MessageContentRenderer: React$1.FC<MessageContentRendererProps>;
|
|
323
|
+
//#endregion
|
|
324
|
+
//#region src/utils/messageUtils.d.ts
|
|
325
|
+
/**
|
|
326
|
+
* 创建人类消息(HumanMessage)
|
|
327
|
+
* @param content 消息内容,可以是字符串或多模态内容块数组
|
|
328
|
+
* @returns HumanMessage 实例
|
|
329
|
+
* @example
|
|
330
|
+
* // 纯文本消息
|
|
331
|
+
* createHumanMessage("你好")
|
|
332
|
+
*
|
|
333
|
+
* // 多模态消息
|
|
334
|
+
* createHumanMessage([
|
|
335
|
+
* { type: "text", text: "看看这张图片" },
|
|
336
|
+
* { type: "image_url", image_url: { url: "https://example.com/image.png" } }
|
|
337
|
+
* ])
|
|
338
|
+
*/
|
|
339
|
+
declare function createHumanMessage(content: string | {
|
|
340
|
+
type: string;
|
|
341
|
+
[key: string]: unknown;
|
|
342
|
+
}[]): BaseMessage;
|
|
343
|
+
//#endregion
|
|
344
|
+
export { AgentChat, type AgentChatInputRef, type AgentChatProps, type AgentChatRef, type BackendTool, type ChatMessage, type ContextItem, type EmptyStateConfig, type FrontendTool, type InputConfig, type InterruptConfig, type InterruptEvent, type InterruptManagerProps, type InterruptRenderProps, type MessageConfig, type MessageContent, type MessageContentBlock, MessageContentRenderer, type MessageContentRendererProps, type MessageType, type SenderCustomizationProps, type SenderSlotConfig, type SenderSubmitParams, type ToolCallInput, ToolCard, type ToolCardProps, type ToolCardStyles, type ToolDefinition, type ToolExecutionRecord, type ToolExecutionStatus, type ToolParameterSchema, type ToolRenderProps, createHumanMessage };
|
package/dist/index.mjs
CHANGED
|
@@ -3,9 +3,10 @@ import { useStream } from "@langchain/react";
|
|
|
3
3
|
import { Actions, Bubble, Sender, Think } from "@ant-design/x";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { Streamdown } from "streamdown";
|
|
6
|
+
import { HumanMessage } from "@langchain/core/messages";
|
|
6
7
|
//#region src/components/ChatInput.tsx
|
|
7
8
|
const slotConfig = [];
|
|
8
|
-
const ChatInput = forwardRef(({ onSend, onStop, isLoading = false, disabled = false, placeholder = "输入消息...", className = "", footer, skill: externalSkill, header, prefix }, ref) => {
|
|
9
|
+
const ChatInput = forwardRef(({ onSend, onStop, isLoading = false, disabled = false, placeholder = "输入消息...", className = "", onPasteFile, footer, skill: externalSkill, header, prefix }, ref) => {
|
|
9
10
|
const senderRef = useRef(null);
|
|
10
11
|
const [internalSkill, setInternalSkill] = useState(externalSkill);
|
|
11
12
|
useImperativeHandle(ref, () => ({
|
|
@@ -38,6 +39,7 @@ const ChatInput = forwardRef(({ onSend, onStop, isLoading = false, disabled = fa
|
|
|
38
39
|
disabled,
|
|
39
40
|
onSubmit: handleSubmit,
|
|
40
41
|
onCancel: onStop,
|
|
42
|
+
onPasteFile,
|
|
41
43
|
autoSize: {
|
|
42
44
|
minRows: 1,
|
|
43
45
|
maxRows: 6
|
|
@@ -164,6 +166,65 @@ const ReasoningContent = ({ content }) => {
|
|
|
164
166
|
})] });
|
|
165
167
|
};
|
|
166
168
|
//#endregion
|
|
169
|
+
//#region src/components/MessageContentRenderer.tsx
|
|
170
|
+
const CustomParagraph = (props) => {
|
|
171
|
+
const { node: _node, ...rest } = props;
|
|
172
|
+
return /* @__PURE__ */ jsx("span", { ...rest });
|
|
173
|
+
};
|
|
174
|
+
/** 渲染单个内容块 */
|
|
175
|
+
const ContentBlock = ({ block, index, components, securityConfig }) => {
|
|
176
|
+
if (block.type === "text" && "text" in block) return /* @__PURE__ */ jsx(Streamdown, {
|
|
177
|
+
components: {
|
|
178
|
+
p: CustomParagraph,
|
|
179
|
+
...components
|
|
180
|
+
},
|
|
181
|
+
allowedTags: securityConfig?.allowedTags,
|
|
182
|
+
literalTagContent: securityConfig?.literalTagContent,
|
|
183
|
+
controls: { table: {
|
|
184
|
+
copy: false,
|
|
185
|
+
download: false,
|
|
186
|
+
fullscreen: false
|
|
187
|
+
} },
|
|
188
|
+
children: String(block.text)
|
|
189
|
+
}, index);
|
|
190
|
+
if (block.type === "image_url" && "image_url" in block) {
|
|
191
|
+
const imageUrl = block.image_url.url;
|
|
192
|
+
return /* @__PURE__ */ jsx("img", {
|
|
193
|
+
src: imageUrl,
|
|
194
|
+
alt: "Message content",
|
|
195
|
+
style: {
|
|
196
|
+
maxWidth: "100%",
|
|
197
|
+
borderRadius: "8px",
|
|
198
|
+
marginTop: "8px"
|
|
199
|
+
}
|
|
200
|
+
}, index);
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
};
|
|
204
|
+
/** 消息内容渲染组件 - 支持字符串和多模态内容块 */
|
|
205
|
+
const MessageContentRenderer = ({ content, components, securityConfig }) => {
|
|
206
|
+
if (typeof content === "string") return /* @__PURE__ */ jsx(Streamdown, {
|
|
207
|
+
components: {
|
|
208
|
+
p: CustomParagraph,
|
|
209
|
+
...components
|
|
210
|
+
},
|
|
211
|
+
allowedTags: securityConfig?.allowedTags,
|
|
212
|
+
literalTagContent: securityConfig?.literalTagContent,
|
|
213
|
+
controls: { table: {
|
|
214
|
+
copy: false,
|
|
215
|
+
download: false,
|
|
216
|
+
fullscreen: false
|
|
217
|
+
} },
|
|
218
|
+
children: content
|
|
219
|
+
});
|
|
220
|
+
return /* @__PURE__ */ jsx(Fragment, { children: content.map((block, index) => /* @__PURE__ */ jsx(ContentBlock, {
|
|
221
|
+
block,
|
|
222
|
+
index,
|
|
223
|
+
components,
|
|
224
|
+
securityConfig
|
|
225
|
+
}, index)) });
|
|
226
|
+
};
|
|
227
|
+
//#endregion
|
|
167
228
|
//#region src/components/WaveLoading.tsx
|
|
168
229
|
/**
|
|
169
230
|
* 波浪动画 Loading 组件
|
|
@@ -204,13 +265,10 @@ const WaveLoading = ({ color = "#1890ff" }) => {
|
|
|
204
265
|
};
|
|
205
266
|
//#endregion
|
|
206
267
|
//#region src/components/MessageList.tsx
|
|
207
|
-
const CustomParagraph = (props) => {
|
|
208
|
-
const { node, ...rest } = props;
|
|
209
|
-
return /* @__PURE__ */ jsx("span", { ...rest });
|
|
210
|
-
};
|
|
211
268
|
const renderMessageContent = (message, isLastMessage, isLoading, tools, toolExecutions, components, securityConfig) => {
|
|
212
269
|
const hasToolCalls = message.toolCalls && message.toolCalls.length > 0;
|
|
213
|
-
const
|
|
270
|
+
const isContentEmpty = !message.content || (typeof message.content === "string" ? message.content === "" : message.content.length === 0);
|
|
271
|
+
const shouldBlink = isLastMessage && isLoading && isContentEmpty && message.toolCalls?.length == 0;
|
|
214
272
|
return /* @__PURE__ */ jsxs("div", {
|
|
215
273
|
className: "message-item",
|
|
216
274
|
children: [
|
|
@@ -225,21 +283,12 @@ const renderMessageContent = (message, isLastMessage, isLoading, tools, toolExec
|
|
|
225
283
|
blink: shouldBlink,
|
|
226
284
|
children: /* @__PURE__ */ jsx(ReasoningContent, { content: message.reasoningContent })
|
|
227
285
|
}),
|
|
228
|
-
|
|
286
|
+
!isContentEmpty && /* @__PURE__ */ jsx("div", {
|
|
229
287
|
style: { marginTop: message.reasoningContent ? "8px" : "3px" },
|
|
230
|
-
children: /* @__PURE__ */ jsx(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
},
|
|
235
|
-
allowedTags: securityConfig?.allowedTags,
|
|
236
|
-
literalTagContent: securityConfig?.literalTagContent,
|
|
237
|
-
controls: { table: {
|
|
238
|
-
copy: false,
|
|
239
|
-
download: false,
|
|
240
|
-
fullscreen: false
|
|
241
|
-
} },
|
|
242
|
-
children: message.content
|
|
288
|
+
children: /* @__PURE__ */ jsx(MessageContentRenderer, {
|
|
289
|
+
content: message.content,
|
|
290
|
+
components,
|
|
291
|
+
securityConfig
|
|
243
292
|
})
|
|
244
293
|
}),
|
|
245
294
|
hasToolCalls && /* @__PURE__ */ jsx("div", {
|
|
@@ -349,7 +398,16 @@ const MessageList = ({ messages, isLoading = false, className = "", tools, toolE
|
|
|
349
398
|
placement: "start"
|
|
350
399
|
};
|
|
351
400
|
});
|
|
352
|
-
const
|
|
401
|
+
const hasVisibleContent = (msg) => {
|
|
402
|
+
if (!msg) return false;
|
|
403
|
+
const hasContent = msg.content && (typeof msg.content === "string" ? msg.content !== "" : msg.content.length > 0);
|
|
404
|
+
const hasReasoning = !!msg.reasoningContent;
|
|
405
|
+
const hasToolCalls = msg.toolCalls && msg.toolCalls.length > 0;
|
|
406
|
+
return hasContent || hasReasoning || hasToolCalls;
|
|
407
|
+
};
|
|
408
|
+
const lastMessage = processedMessages[processedMessages.length - 1];
|
|
409
|
+
const isLastMessageFromUser = lastMessage?.type === "human";
|
|
410
|
+
const allItems = isLoading && (isLastMessageFromUser || !hasVisibleContent(lastMessage)) ? [...items, {
|
|
353
411
|
key: "loading",
|
|
354
412
|
role: "ai",
|
|
355
413
|
content: /* @__PURE__ */ jsx(WaveLoading, { color: loadingColor }),
|
|
@@ -509,7 +567,8 @@ function DebugPanel({ messages, streamState, visible = true }) {
|
|
|
509
567
|
};
|
|
510
568
|
const formatContent = (content) => {
|
|
511
569
|
if (!content) return "";
|
|
512
|
-
return content;
|
|
570
|
+
if (Array.isArray(content)) return content.map((item) => typeof item === "string" ? item : JSON.stringify(item)).join("");
|
|
571
|
+
return String(content);
|
|
513
572
|
};
|
|
514
573
|
const renderMessageContent = (message) => {
|
|
515
574
|
const hasToolCalls = message.tool_calls && Array.isArray(message.tool_calls) && message.tool_calls.length > 0;
|
|
@@ -1051,6 +1110,23 @@ function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChan
|
|
|
1051
1110
|
//#endregion
|
|
1052
1111
|
//#region src/utils/messageUtils.ts
|
|
1053
1112
|
/**
|
|
1113
|
+
* 创建人类消息(HumanMessage)
|
|
1114
|
+
* @param content 消息内容,可以是字符串或多模态内容块数组
|
|
1115
|
+
* @returns HumanMessage 实例
|
|
1116
|
+
* @example
|
|
1117
|
+
* // 纯文本消息
|
|
1118
|
+
* createHumanMessage("你好")
|
|
1119
|
+
*
|
|
1120
|
+
* // 多模态消息
|
|
1121
|
+
* createHumanMessage([
|
|
1122
|
+
* { type: "text", text: "看看这张图片" },
|
|
1123
|
+
* { type: "image_url", image_url: { url: "https://example.com/image.png" } }
|
|
1124
|
+
* ])
|
|
1125
|
+
*/
|
|
1126
|
+
function createHumanMessage(content) {
|
|
1127
|
+
return new HumanMessage({ content });
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1054
1130
|
* 从 BaseMessage 中提取 tool_calls
|
|
1055
1131
|
*/
|
|
1056
1132
|
function extractToolCalls(message) {
|
|
@@ -1061,14 +1137,31 @@ function extractToolCalls(message) {
|
|
|
1061
1137
|
}));
|
|
1062
1138
|
}
|
|
1063
1139
|
/**
|
|
1064
|
-
* 从 BaseMessage
|
|
1140
|
+
* 从 BaseMessage 中提取原始内容
|
|
1141
|
+
* 保留原始结构:字符串或内容块数组
|
|
1065
1142
|
*/
|
|
1066
1143
|
function extractContent(message) {
|
|
1067
1144
|
if (typeof message.content === "string") return message.content;
|
|
1068
|
-
if (Array.isArray(message.content)) return message.content.map((c) =>
|
|
1145
|
+
if (Array.isArray(message.content)) return message.content.map((c) => {
|
|
1146
|
+
if (typeof c === "object" && c !== null) return c;
|
|
1147
|
+
return {
|
|
1148
|
+
type: "text",
|
|
1149
|
+
text: String(c)
|
|
1150
|
+
};
|
|
1151
|
+
});
|
|
1069
1152
|
return "";
|
|
1070
1153
|
}
|
|
1071
1154
|
/**
|
|
1155
|
+
* 从 MessageContent 中提取纯文本内容(用于渲染)
|
|
1156
|
+
*/
|
|
1157
|
+
function extractTextFromContent(content) {
|
|
1158
|
+
if (typeof content === "string") return content;
|
|
1159
|
+
return content.map((block) => {
|
|
1160
|
+
if (block.type === "text") return block.text;
|
|
1161
|
+
return "";
|
|
1162
|
+
}).join("");
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1072
1165
|
* 将 BaseMessage 转换为 ChatMessage
|
|
1073
1166
|
*/
|
|
1074
1167
|
function toChatMessage(message, toolResults) {
|
|
@@ -1102,11 +1195,11 @@ function processMessages(rawMessages) {
|
|
|
1102
1195
|
for (const message of rawMessages) if (message.type === "tool") {
|
|
1103
1196
|
const toolCallId = message.tool_call_id || message.additional_kwargs?.tool_call_id;
|
|
1104
1197
|
if (toolCallId) {
|
|
1105
|
-
const
|
|
1198
|
+
const textContent = extractTextFromContent(extractContent(message));
|
|
1106
1199
|
try {
|
|
1107
|
-
toolResults.set(toolCallId, JSON.parse(
|
|
1200
|
+
toolResults.set(toolCallId, JSON.parse(textContent));
|
|
1108
1201
|
} catch {
|
|
1109
|
-
toolResults.set(toolCallId,
|
|
1202
|
+
toolResults.set(toolCallId, textContent);
|
|
1110
1203
|
}
|
|
1111
1204
|
}
|
|
1112
1205
|
}
|
|
@@ -1343,7 +1436,7 @@ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: external
|
|
|
1343
1436
|
}, [submitToStream]);
|
|
1344
1437
|
const handleSend = useCallback(async (params) => {
|
|
1345
1438
|
let messages = [];
|
|
1346
|
-
if (onPreSend && params.message.trim()) messages = (await onPreSend(params)).messages.filter((m) => m != null)
|
|
1439
|
+
if (onPreSend && params.message.trim()) messages = (await onPreSend(params)).messages.filter((m) => m != null);
|
|
1347
1440
|
else {
|
|
1348
1441
|
if (!params.message.trim()) return;
|
|
1349
1442
|
messages = [{
|
|
@@ -1448,4 +1541,4 @@ const ToolCard = ({ prefix, content, icon, style, styles }) => {
|
|
|
1448
1541
|
});
|
|
1449
1542
|
};
|
|
1450
1543
|
//#endregion
|
|
1451
|
-
export { AgentChat, ToolCard };
|
|
1544
|
+
export { AgentChat, MessageContentRenderer, ToolCard, createHumanMessage };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vegintech/langchain-react-agent",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "LangChain Agent UI component library for React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -15,6 +15,13 @@
|
|
|
15
15
|
"publishConfig": {
|
|
16
16
|
"access": "public"
|
|
17
17
|
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "vp pack",
|
|
20
|
+
"dev": "vp pack --watch",
|
|
21
|
+
"test": "vp test",
|
|
22
|
+
"check": "vp check",
|
|
23
|
+
"prepublishOnly": "vp run build"
|
|
24
|
+
},
|
|
18
25
|
"dependencies": {
|
|
19
26
|
"@ant-design/x": "^2.4.0",
|
|
20
27
|
"@langchain/core": "^1.1.36",
|
|
@@ -36,11 +43,5 @@
|
|
|
36
43
|
"peerDependencies": {
|
|
37
44
|
"react": ">=18.0.0",
|
|
38
45
|
"react-dom": ">=18.0.0"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "vp pack",
|
|
42
|
-
"dev": "vp pack --watch",
|
|
43
|
-
"test": "vp test",
|
|
44
|
-
"check": "vp check"
|
|
45
46
|
}
|
|
46
|
-
}
|
|
47
|
+
}
|