@arronqzy/react-blueprint 1.0.18 → 1.0.21

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.
Files changed (43) hide show
  1. package/README.md +36 -26
  2. package/dist/blueprint.css +336 -54
  3. package/index.ts +23 -0
  4. package/package.json +5 -5
  5. package/src/BlueprintContextMenu.tsx +1 -1
  6. package/src/BlueprintNodeConfigSidebar.tsx +10 -2
  7. package/src/blueprint.css +336 -54
  8. package/src/components/ApiCollectionManagerDialog.tsx +448 -0
  9. package/src/components/BlueprintExecutionLogPanel.tsx +10 -2
  10. package/src/components/BlueprintLibrarySelect.tsx +1 -1
  11. package/src/components/BlueprintMetaDialog.tsx +1 -1
  12. package/src/components/BlueprintNodeSwitchTaskDialog.tsx +1 -1
  13. package/src/components/BlueprintPanelToolbar.tsx +10 -2
  14. package/src/components/ClockNodeConfigPanel.tsx +1 -1
  15. package/src/components/ConfigHintIcon.tsx +1 -1
  16. package/src/components/FetchNodeConfigPanel.tsx +314 -3
  17. package/src/components/FetchUrlAutocomplete.tsx +1 -1
  18. package/src/components/JsonLintTextarea.tsx +97 -0
  19. package/src/components/JsonNodeConfigPanel.tsx +14 -7
  20. package/src/components/LogicNodeConfigPanel.tsx +1 -1
  21. package/src/components/ScopeTemplateAutocompleteHost.tsx +4 -8
  22. package/src/components/StorageKeyAutocomplete.tsx +1 -1
  23. package/src/components/StorageNodeConfigPanel.tsx +1 -1
  24. package/src/components/ViewElementMultiSelect.tsx +1 -1
  25. package/src/edges/BlueprintSmoothEdge.tsx +2 -2
  26. package/src/graph/blueprint-graph.ts +9 -0
  27. package/src/graph/document.ts +12 -0
  28. package/src/graph/sync-edges.ts +2 -2
  29. package/src/hooks/useBlueprintFlowState.ts +1 -1
  30. package/src/index.tsx +41 -28
  31. package/src/library/api-collection-db.ts +98 -0
  32. package/src/library/api-collection-store.ts +139 -0
  33. package/src/nodes/AndFlowNode.tsx +4 -3
  34. package/src/nodes/BlueprintFlowNode.tsx +8 -3
  35. package/src/nodes/BlueprintNodeCard.tsx +137 -121
  36. package/src/nodes/BlueprintNodeShell.tsx +2 -1
  37. package/src/nodes/ClockFlowNode.tsx +1 -1
  38. package/src/nodes/EventFlowNode.tsx +1 -1
  39. package/src/nodes/FetchFlowNode.tsx +1 -1
  40. package/src/nodes/JsonFlowNode.tsx +1 -1
  41. package/src/nodes/LifecycleFlowNode.tsx +2 -1
  42. package/src/nodes/LogicFlowNode.tsx +1 -1
  43. package/src/nodes/StorageFlowNode.tsx +1 -1
package/README.md CHANGED
@@ -1,15 +1,25 @@
1
1
  # @arronqzy/react-blueprint
2
2
 
3
- Abuilder 的**蓝图编辑器** React 包,基于 [React Flow](https://reactflow.dev/) 提供节点连线编辑、调试执行与蓝图库管理。
3
+ 蓝图编辑器。基于 [React Flow](https://reactflow.dev/):拖节点、连线、单步调试、蓝图库和执行日志。节点怎么跑由 `@arronqzy/blueprint-dsl` 决定,本包只负责画布和调试界面。
4
4
 
5
- ## 功能概览
5
+ 通常由 `@arronqzy/react-view` 嵌在视图下方。单独用时自己管 `graph` 状态。
6
6
 
7
- - **可视化蓝图**:拖拽节点、连线、对齐、视口平移缩放
8
- - **节点类型**:逻辑、请求、时钟、JSON、子蓝图引用等(由 `blueprint-dsl` 定义行为)
9
- - **调试执行**:单步/连续调试、执行轨迹、连线信号高亮、时钟节点进度
10
- - **蓝图库**:IndexedDB 存储、导入导出、元数据编辑
11
- - **执行日志**:运行记录持久化、导出与清理策略
12
- - **视图联动**:生命周期钩子向视图节点写入 Scope
7
+ ![视图下方的蓝图画布,可从库里选蓝图、保存和同步](https://github.com/qianzhuoyao/APanel5/raw/v5/docs/guide-assets/live-zh/40-blueprint-open.png)
8
+
9
+ 选中节点后,配置侧栏说明这个节点是什么、引用哪份蓝图、假信号要不要继续往下传:
10
+
11
+ ![蓝图节点配置](https://github.com/qianzhuoyao/APanel5/raw/v5/docs/guide-assets/live-zh/42-blueprint-node-config.png)
12
+
13
+ ## 能编辑什么
14
+
15
+ - 画布:拖节点、连线、右键菜单、平移缩放
16
+ - 内置节点:蓝图引用、逻辑、与门、生命周期、请求、JSON、存储、时钟、事件
17
+ - 调试:模拟场景、全部运行、回到起点、上一步 / 下一步、连线信号高亮、时钟进度
18
+ - 蓝图库:IndexedDB 保存、导入导出、重命名
19
+ - 执行日志:持久化、导出、保留天数和条数
20
+ - 和视图联动:生命周期钩子把 Scope 写回视图节点
21
+
22
+ 节点在没有匹配的 `I18nProvider` 时不会直接抛错(`EnsureI18nProvider` + `useI18nOptional`)。Umi 等打包器打出两份 `@arronqzy/i18n` 时,界面仍能打开;若语言不跟随面板切换,用 `overrides` 把 `@arronqzy/i18n` 收成一份。
13
23
 
14
24
  ## 安装
15
25
 
@@ -21,9 +31,7 @@ pnpm add @arronqzy/react-blueprint @xyflow/react
21
31
  import "@arronqzy/react-blueprint/blueprint.css";
22
32
  ```
23
33
 
24
- ## 使用
25
-
26
- ### 蓝图画布
34
+ ## 画布
27
35
 
28
36
  ```tsx
29
37
  import { useState } from "react";
@@ -44,7 +52,9 @@ function BlueprintEditor() {
44
52
  }
45
53
  ```
46
54
 
47
- ### 文档转可执行图
55
+ ## 调试和生命周期
56
+
57
+ 把文档变成可执行图:
48
58
 
49
59
  ```ts
50
60
  import { documentToRunnableGraph } from "@arronqzy/react-blueprint";
@@ -52,7 +62,7 @@ import { documentToRunnableGraph } from "@arronqzy/react-blueprint";
52
62
  const runnable = documentToRunnableGraph(document, { libraryNameById });
53
63
  ```
54
64
 
55
- ### 调试会话
65
+ 调试会话(工具栏的单步、全部运行都走这里):
56
66
 
57
67
  ```tsx
58
68
  import { useBlueprintDebugSession } from "@arronqzy/react-blueprint";
@@ -62,11 +72,13 @@ const debug = useBlueprintDebugSession({
62
72
  blueprintId,
63
73
  blueprintName: "我的蓝图",
64
74
  resolveLibraryBlueprint,
65
- onViewScopeUpdate: (ids, scope) => { /* 回写视图 Scope */ },
75
+ onViewScopeUpdate: (ids, scope) => {
76
+ // 回写视图 Scope
77
+ },
66
78
  });
67
79
  ```
68
80
 
69
- ### 页面生命周期(与视图集成)
81
+ 页面打开 / 关闭时启停蓝图:
70
82
 
71
83
  ```tsx
72
84
  import { useBlueprintPageLifecycle } from "@arronqzy/react-blueprint";
@@ -81,22 +93,20 @@ useBlueprintPageLifecycle({
81
93
 
82
94
  ## 主要导出
83
95
 
84
- | 模块 | 说明 |
96
+ | 导出 | 说明 |
85
97
  |------|------|
86
- | `BluePrintReactRoot` | 蓝图主画布 |
87
- | `BlueprintGraph` | 图数据结构(`src/graph`) |
98
+ | `BluePrintReactRoot` | 主画布 |
99
+ | `BlueprintGraph` | 图数据,`empty()` 得到空图 |
88
100
  | `documentToRunnableGraph` | 文档 → 运行时图 |
89
- | `useBlueprintDebugSession` | 调试工具栏与会话 |
90
- | `useBlueprintPageLifecycle` | 挂载/卸载时启停蓝图 |
101
+ | `useBlueprintDebugSession` | 调试会话 |
102
+ | `useBlueprintPageLifecycle` | 挂载 / 卸载时启停 |
91
103
  | `BlueprintNodeConfigSidebar` | 节点配置侧栏 |
92
- | `BlueprintPanelToolbar` | 蓝图工具栏 |
93
- | `blueprint-library-db` | 蓝图库 IndexedDB API |
104
+ | `BlueprintPanelToolbar` | 库、保存、同步、调试按钮 |
105
+ | `BlueprintExecutionLogPanel` | 执行日志 |
94
106
 
95
- ## 依赖关系
107
+ ## 依赖
96
108
 
97
- - `@arronqzy/blueprint-dsl` — 节点定义与执行引擎
98
- - `@arronqzy/react-rx-store` — 与画布状态订阅
99
- - `@arronqzy/ui` — UI 组件
109
+ `@arronqzy/blueprint-dsl`、`@arronqzy/i18n`、`@arronqzy/react-rx-store`、`@arronqzy/ui`、`@xyflow/react`。
100
110
 
101
111
  ## 许可证
102
112
 
@@ -14,13 +14,13 @@
14
14
  .bp-flow.react-flow,
15
15
  [data-workspace-region="blueprint"] .react-flow {
16
16
  --xy-background-color: transparent;
17
- --xy-edge-stroke: #2563eb;
18
- --xy-edge-stroke-width: 2.5;
19
- --xy-edge-stroke-selected: #1d4ed8;
20
- --xy-connectionline-stroke: #2563eb;
21
- --xy-connectionline-stroke-width: 2.5;
22
- --xy-handle-background-color: hsl(var(--primary));
23
- --xy-handle-border-color: hsl(var(--background));
17
+ --xy-edge-stroke: #94a3b8;
18
+ --xy-edge-stroke-width: 1.75;
19
+ --xy-edge-stroke-selected: #64748b;
20
+ --xy-connectionline-stroke: #94a3b8;
21
+ --xy-connectionline-stroke-width: 1.75;
22
+ --xy-handle-background-color: #ffffff;
23
+ --xy-handle-border-color: #94a3b8;
24
24
  background-color: transparent;
25
25
  }
26
26
 
@@ -73,16 +73,16 @@
73
73
  [data-workspace-region="blueprint"] .react-flow__edges path.react-flow__edge-path,
74
74
  [data-workspace-region="blueprint"] .react-flow__edges path.bp-edge-visible {
75
75
  fill: none !important;
76
- stroke: #2563eb !important;
77
- stroke-width: 2.5px !important;
76
+ stroke: #94a3b8 !important;
77
+ stroke-width: 1.75px !important;
78
78
  opacity: 1 !important;
79
79
  }
80
80
 
81
81
  .bp-canvas .react-flow__edge.selected path.react-flow__edge-path,
82
82
  .bp-flow .react-flow__edge.selected path.react-flow__edge-path,
83
83
  [data-workspace-region="blueprint"] .react-flow__edge.selected path.react-flow__edge-path {
84
- stroke: #1d4ed8 !important;
85
- stroke-width: 3px !important;
84
+ stroke: #64748b !important;
85
+ stroke-width: 2.25px !important;
86
86
  }
87
87
 
88
88
  .bp-canvas .react-flow__edge.bp-edge--signal-true path.react-flow__edge-path,
@@ -130,16 +130,16 @@
130
130
  .bp-canvas .react-flow__arrowhead polyline,
131
131
  .bp-flow .react-flow__arrowhead polyline,
132
132
  [data-workspace-region="blueprint"] .react-flow__arrowhead polyline {
133
- stroke: #2563eb;
134
- fill: #2563eb;
133
+ stroke: #94a3b8;
134
+ fill: #94a3b8;
135
135
  }
136
136
 
137
137
  .bp-canvas .react-flow__connection-path,
138
138
  .bp-flow .react-flow__connection-path,
139
139
  [data-workspace-region="blueprint"] .react-flow__connection-path {
140
140
  fill: none !important;
141
- stroke: #2563eb !important;
142
- stroke-width: 2.5px !important;
141
+ stroke: #94a3b8 !important;
142
+ stroke-width: 1.75px !important;
143
143
  }
144
144
 
145
145
  .bp-canvas .react-flow__edge-interaction,
@@ -167,95 +167,115 @@
167
167
  padding: 0;
168
168
  }
169
169
 
170
- /* 连接点:禁止 transform,避免覆盖 React Flow 的 translate(-50%, -50%) 定位 */
170
+ /* 以卡片壳为 handle 定位基准,避免挂到外层导致左右/垂直偏移 */
171
+ .bp-node {
172
+ position: relative;
173
+ display: block;
174
+ width: max-content;
175
+ min-height: 1px;
176
+ }
177
+
178
+ /* 连接点:显式锚定左右中线(勿覆盖 transform 以外的 RF 行为) */
171
179
  .bp-canvas .react-flow__handle.bp-flow-handle,
172
180
  .bp-flow .react-flow__handle.bp-flow-handle,
173
181
  [data-workspace-region="blueprint"] .react-flow__handle.bp-flow-handle {
182
+ position: absolute !important;
174
183
  z-index: 3;
175
- width: 10px;
176
- height: 10px;
177
- min-width: 10px;
178
- min-height: 10px;
179
- border: 2px solid hsl(var(--background)) !important;
184
+ width: 8px;
185
+ height: 8px;
186
+ min-width: 8px;
187
+ min-height: 8px;
188
+ border: 1.5px solid hsl(var(--card)) !important;
180
189
  border-radius: 9999px;
181
- background-color: hsl(var(--foreground) / 0.42) !important;
190
+ background-color: #ffffff !important;
191
+ box-shadow: 0 0 0 1px rgb(148 163 184 / 0.55);
192
+ pointer-events: all !important;
182
193
  transition:
183
194
  background-color 0.15s ease,
184
195
  border-color 0.15s ease,
185
196
  box-shadow 0.15s ease;
186
197
  }
187
198
 
199
+ .bp-node > .react-flow__handle.react-flow__handle-left,
200
+ .bp-node > .react-flow__handle[data-handlepos="left"] {
201
+ top: 50%;
202
+ left: 0;
203
+ right: auto;
204
+ bottom: auto;
205
+ transform: translate(-50%, -50%);
206
+ }
207
+
208
+ .bp-node > .react-flow__handle.react-flow__handle-right,
209
+ .bp-node > .react-flow__handle[data-handlepos="right"] {
210
+ top: 50%;
211
+ right: 0;
212
+ left: auto;
213
+ bottom: auto;
214
+ transform: translate(50%, -50%);
215
+ }
216
+
188
217
  .bp-canvas .react-flow__handle.bp-flow-handle:hover,
189
218
  .bp-flow .react-flow__handle.bp-flow-handle:hover,
190
219
  [data-workspace-region="blueprint"] .react-flow__handle.bp-flow-handle:hover {
191
- background-color: hsl(var(--primary)) !important;
192
- border-color: hsl(var(--background)) !important;
193
- box-shadow: 0 0 0 3px hsl(var(--primary) / 0.28);
220
+ background-color: #ffffff !important;
221
+ border-color: hsl(var(--primary)) !important;
222
+ box-shadow: 0 0 0 3px hsl(var(--primary) / 0.22);
194
223
  }
195
224
 
196
225
  .bp-canvas .react-flow__handle.bp-flow-handle--target,
197
226
  .bp-flow .react-flow__handle.bp-flow-handle--target,
198
227
  [data-workspace-region="blueprint"] .react-flow__handle.bp-flow-handle--target {
199
- background-color: hsl(var(--foreground) / 0.48) !important;
228
+ background-color: #ffffff !important;
200
229
  }
201
230
 
202
231
  .bp-canvas .react-flow__handle.bp-flow-handle--source,
203
232
  .bp-flow .react-flow__handle.bp-flow-handle--source,
204
233
  [data-workspace-region="blueprint"] .react-flow__handle.bp-flow-handle--source {
205
- background-color: hsl(var(--primary) / 0.72) !important;
234
+ background-color: #ffffff !important;
206
235
  }
207
236
 
208
237
  .bp-node--selected .bp-flow-handle {
209
- border-color: hsl(var(--card)) !important;
210
- box-shadow: 0 0 0 2px hsl(var(--primary) / 0.35);
211
- }
212
-
213
- .bp-node--selected .bp-flow-handle--target {
214
- background-color: hsl(var(--foreground) / 0.55) !important;
238
+ border-color: hsl(var(--primary) / 0.55) !important;
239
+ box-shadow: 0 0 0 2px hsl(var(--primary) / 0.2);
215
240
  }
216
241
 
242
+ .bp-node--selected .bp-flow-handle--target,
217
243
  .bp-node--selected .bp-flow-handle--source {
218
- background-color: hsl(var(--primary)) !important;
244
+ background-color: #ffffff !important;
219
245
  }
220
246
 
221
247
  .bp-node--execution-true .bp-node-card {
222
- border-color: rgb(22 163 74 / 0.65);
248
+ border-color: rgb(22 163 74 / 0.55);
223
249
  box-shadow:
224
- 0 0 0 1px rgb(22 163 74 / 0.35),
225
- 0 4px 14px rgb(22 163 74 / 0.18);
250
+ 0 0 0 1px rgb(22 163 74 / 0.28),
251
+ 0 8px 24px rgb(22 163 74 / 0.14);
226
252
  }
227
253
 
228
254
  .bp-node--execution-true .bp-flow-handle {
229
- border-color: hsl(var(--card));
230
- box-shadow: 0 0 0 2px rgb(22 163 74 / 0.45);
231
- }
232
-
233
- .bp-node--execution-true .bp-flow-handle--source {
234
- background-color: #16a34a !important;
255
+ border-color: rgb(22 163 74 / 0.7) !important;
256
+ box-shadow: 0 0 0 2px rgb(22 163 74 / 0.28);
235
257
  }
236
258
 
259
+ .bp-node--execution-true .bp-flow-handle--source,
237
260
  .bp-node--execution-true .bp-flow-handle--target {
238
- background-color: rgb(22 163 74 / 0.55) !important;
261
+ background-color: #ffffff !important;
239
262
  }
240
263
 
241
264
  .bp-node--execution-false .bp-node-card {
242
- border-color: hsl(var(--destructive) / 0.65);
265
+ border-color: hsl(var(--destructive) / 0.55);
243
266
  box-shadow:
244
- 0 0 0 1px hsl(var(--destructive) / 0.4),
245
- 0 4px 14px hsl(var(--destructive) / 0.16);
267
+ 0 0 0 1px hsl(var(--destructive) / 0.3),
268
+ 0 8px 24px hsl(var(--destructive) / 0.12);
246
269
  }
247
270
 
248
271
  .bp-node--execution-false .bp-flow-handle {
249
- border-color: hsl(var(--card));
250
- box-shadow: 0 0 0 2px hsl(var(--destructive) / 0.4);
251
- }
252
-
253
- .bp-node--execution-false .bp-flow-handle--source {
254
- background-color: hsl(var(--destructive)) !important;
272
+ border-color: hsl(var(--destructive) / 0.65) !important;
273
+ box-shadow: 0 0 0 2px hsl(var(--destructive) / 0.25);
255
274
  }
256
275
 
276
+ .bp-node--execution-false .bp-flow-handle--source,
257
277
  .bp-node--execution-false .bp-flow-handle--target {
258
- background-color: hsl(var(--destructive) / 0.55) !important;
278
+ background-color: #ffffff !important;
259
279
  }
260
280
 
261
281
  /* 生命周期节点无输入口:隐藏任何左侧/目标连接点(含旧数据产生的幽灵 handle) */
@@ -325,3 +345,265 @@
325
345
  margin: 4px 0;
326
346
  background: hsl(var(--border));
327
347
  }
348
+
349
+ /* Soft UI 节点卡片(写入 CSS,避免 Tailwind content 未扫到 react-blueprint) */
350
+ .bp-node-card {
351
+ width: 200px;
352
+ overflow: hidden;
353
+ border-radius: 1rem;
354
+ border: 1px solid hsl(var(--border) / 0.7);
355
+ background: hsl(var(--card));
356
+ color: hsl(var(--card-foreground));
357
+ box-shadow: 0 8px 24px rgb(15 23 42 / 0.08);
358
+ cursor: grab;
359
+ transition:
360
+ box-shadow 0.15s ease,
361
+ border-color 0.15s ease;
362
+ }
363
+
364
+ .bp-node-card:active {
365
+ cursor: grabbing;
366
+ }
367
+
368
+ .bp-node-card.bp-node-card--selected {
369
+ border-color: hsl(var(--primary) / 0.7);
370
+ box-shadow:
371
+ 0 0 0 2px hsl(var(--primary) / 0.35),
372
+ 0 10px 28px hsl(var(--primary) / 0.18);
373
+ }
374
+
375
+ .bp-node-card__body {
376
+ display: flex;
377
+ width: 100%;
378
+ align-items: flex-start;
379
+ padding: 10px 12px;
380
+ border: none;
381
+ background: transparent;
382
+ color: inherit;
383
+ text-align: left;
384
+ cursor: inherit;
385
+ outline: none;
386
+ transition: background-color 0.15s ease;
387
+ }
388
+
389
+ .bp-node-card__body:hover {
390
+ background: hsl(var(--accent) / 0.25);
391
+ }
392
+
393
+ .bp-node-card__body:focus-visible {
394
+ box-shadow: inset 0 0 0 1px hsl(var(--primary));
395
+ }
396
+
397
+ .bp-node-card__content {
398
+ min-width: 0;
399
+ flex: 1;
400
+ }
401
+
402
+ .bp-node-card__title-row {
403
+ display: flex;
404
+ align-items: flex-start;
405
+ gap: 6px;
406
+ }
407
+
408
+ .bp-node-card__title {
409
+ min-width: 0;
410
+ flex: 1;
411
+ overflow: hidden;
412
+ text-overflow: ellipsis;
413
+ white-space: nowrap;
414
+ font-size: 13px;
415
+ font-weight: 600;
416
+ line-height: 1.35;
417
+ color: hsl(var(--foreground));
418
+ }
419
+
420
+ .bp-node-card__meta,
421
+ .bp-node-card__subtitle {
422
+ margin-top: 2px;
423
+ overflow: hidden;
424
+ text-overflow: ellipsis;
425
+ white-space: nowrap;
426
+ line-height: 1.3;
427
+ color: hsl(var(--muted-foreground));
428
+ }
429
+
430
+ .bp-node-card__meta {
431
+ font-size: 11px;
432
+ }
433
+
434
+ .bp-node-card__subtitle {
435
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
436
+ font-size: 10px;
437
+ opacity: 0.85;
438
+ }
439
+
440
+ .bp-node-card__badge {
441
+ flex-shrink: 0;
442
+ border-radius: 6px;
443
+ padding: 2px 6px;
444
+ font-size: 10px;
445
+ font-weight: 600;
446
+ line-height: 1;
447
+ }
448
+
449
+ .bp-node-icon {
450
+ display: flex;
451
+ flex-shrink: 0;
452
+ align-items: center;
453
+ justify-content: center;
454
+ width: 28px;
455
+ height: 28px;
456
+ margin-top: 2px;
457
+ margin-right: 10px;
458
+ border-radius: 8px;
459
+ }
460
+
461
+ .bp-node-icon svg {
462
+ width: 14px;
463
+ height: 14px;
464
+ }
465
+
466
+ .bp-node-icon--blueprint {
467
+ background: hsl(var(--primary) / 0.14);
468
+ color: hsl(var(--primary));
469
+ }
470
+
471
+ .bp-node-icon--view {
472
+ background: rgb(100 116 139 / 0.18);
473
+ color: rgb(71 85 105);
474
+ }
475
+
476
+ .bp-node-icon--logic {
477
+ background: rgb(14 165 233 / 0.15);
478
+ color: rgb(2 132 199);
479
+ }
480
+
481
+ .bp-node-icon--and {
482
+ background: rgb(99 102 241 / 0.15);
483
+ color: rgb(79 70 229);
484
+ }
485
+
486
+ .bp-node-icon--lifecycle {
487
+ background: rgb(245 158 11 / 0.15);
488
+ color: rgb(217 119 6);
489
+ }
490
+
491
+ .bp-node-icon--event {
492
+ background: rgb(217 70 239 / 0.15);
493
+ color: rgb(192 38 211);
494
+ }
495
+
496
+ .bp-node-icon--fetch {
497
+ background: rgb(139 92 246 / 0.15);
498
+ color: rgb(124 58 237);
499
+ }
500
+
501
+ .bp-node-icon--json {
502
+ background: rgb(20 184 166 / 0.15);
503
+ color: rgb(13 148 136);
504
+ }
505
+
506
+ .bp-node-icon--storage {
507
+ background: rgb(16 185 129 / 0.15);
508
+ color: rgb(5 150 105);
509
+ }
510
+
511
+ .bp-node-icon--clock {
512
+ background: rgb(244 63 94 / 0.15);
513
+ color: rgb(225 29 72);
514
+ }
515
+
516
+ .bp-node-card__badge--blueprint {
517
+ background: hsl(var(--primary) / 0.1);
518
+ color: hsl(var(--primary));
519
+ }
520
+
521
+ .bp-node-card__badge--view {
522
+ background: rgb(100 116 139 / 0.12);
523
+ color: rgb(51 65 85);
524
+ }
525
+
526
+ .bp-node-card__badge--logic {
527
+ background: rgb(14 165 233 / 0.1);
528
+ color: rgb(3 105 161);
529
+ }
530
+
531
+ .bp-node-card__badge--and {
532
+ background: rgb(99 102 241 / 0.1);
533
+ color: rgb(67 56 202);
534
+ }
535
+
536
+ .bp-node-card__badge--lifecycle {
537
+ background: rgb(245 158 11 / 0.1);
538
+ color: rgb(180 83 9);
539
+ }
540
+
541
+ .bp-node-card__badge--event {
542
+ background: rgb(217 70 239 / 0.1);
543
+ color: rgb(162 28 175);
544
+ }
545
+
546
+ .bp-node-card__badge--fetch {
547
+ background: rgb(139 92 246 / 0.1);
548
+ color: rgb(109 40 217);
549
+ }
550
+
551
+ .bp-node-card__badge--json {
552
+ background: rgb(20 184 166 / 0.1);
553
+ color: rgb(15 118 110);
554
+ }
555
+
556
+ .bp-node-card__badge--storage {
557
+ background: rgb(16 185 129 / 0.1);
558
+ color: rgb(4 120 87);
559
+ }
560
+
561
+ .bp-node-card__badge--clock {
562
+ background: rgb(244 63 94 / 0.1);
563
+ color: rgb(190 18 60);
564
+ }
565
+
566
+ .dark .bp-node-icon--logic,
567
+ :root.dark .bp-node-icon--logic {
568
+ color: rgb(125 211 252);
569
+ }
570
+
571
+ .dark .bp-node-icon--view,
572
+ :root.dark .bp-node-icon--view {
573
+ color: rgb(203 213 225);
574
+ }
575
+
576
+ .dark .bp-node-icon--and,
577
+ :root.dark .bp-node-icon--and {
578
+ color: rgb(165 180 252);
579
+ }
580
+
581
+ .dark .bp-node-icon--lifecycle,
582
+ :root.dark .bp-node-icon--lifecycle {
583
+ color: rgb(252 211 77);
584
+ }
585
+
586
+ .dark .bp-node-icon--event,
587
+ :root.dark .bp-node-icon--event {
588
+ color: rgb(240 171 252);
589
+ }
590
+
591
+ .dark .bp-node-icon--fetch,
592
+ :root.dark .bp-node-icon--fetch {
593
+ color: rgb(196 181 253);
594
+ }
595
+
596
+ .dark .bp-node-icon--json,
597
+ :root.dark .bp-node-icon--json {
598
+ color: rgb(94 234 212);
599
+ }
600
+
601
+ .dark .bp-node-icon--storage,
602
+ :root.dark .bp-node-icon--storage {
603
+ color: rgb(110 231 183);
604
+ }
605
+
606
+ .dark .bp-node-icon--clock,
607
+ :root.dark .bp-node-icon--clock {
608
+ color: rgb(253 164 175);
609
+ }
package/index.ts CHANGED
@@ -36,6 +36,29 @@ export { useBlueprintNodeSelectionGuard } from "./src/hooks/useBlueprintNodeSele
36
36
  export type { PendingBlueprintNodeSwitch } from "./src/hooks/useBlueprintNodeSelectionGuard";
37
37
  export { BlueprintMetaDialog } from "./src/components/BlueprintMetaDialog";
38
38
  export type { BlueprintMetaDialogProps } from "./src/components/BlueprintMetaDialog";
39
+ export { ApiCollectionManagerDialog } from "./src/components/ApiCollectionManagerDialog";
40
+ export type {
41
+ ApiCollectionManagerDialogProps,
42
+ ApiCollectionUploadStartInfo,
43
+ ApiCollectionUploadSuccessInfo,
44
+ } from "./src/components/ApiCollectionManagerDialog";
45
+ export {
46
+ hydrateApiCollections,
47
+ getApiCollectionRecords,
48
+ getApiCollectionById,
49
+ getApiCollectionListItems,
50
+ upsertApiCollectionFromJson,
51
+ removeApiCollection,
52
+ subscribeApiCollections,
53
+ useApiCollections,
54
+ useApiCollectionListItems,
55
+ } from "./src/library/api-collection-store";
56
+ export {
57
+ listApiCollectionRecords,
58
+ getApiCollectionRecord,
59
+ putApiCollectionRecord,
60
+ deleteApiCollectionRecord,
61
+ } from "./src/library/api-collection-db";
39
62
  export { BlueprintLibrarySelect } from "./src/components/BlueprintLibrarySelect";
40
63
  export type { BlueprintLibrarySelectProps } from "./src/components/BlueprintLibrarySelect";
41
64
  export { BlueprintPanelToolbar, BlueprintRenameDialog, BlueprintDeleteDialog } from "./src/components/BlueprintPanelToolbar";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arronqzy/react-blueprint",
3
- "version": "1.0.18",
3
+ "version": "1.0.21",
4
4
  "description": "",
5
5
  "files": [
6
6
  "index.ts",
@@ -18,9 +18,9 @@
18
18
  "dayjs": "^1.11.13",
19
19
  "react-dom": "^19",
20
20
  "@xyflow/react": "^12.9.3",
21
- "@arronqzy/i18n": "0.1.13",
21
+ "@arronqzy/blueprint-dsl": "1.0.16",
22
22
  "@arronqzy/ui": "1.0.9",
23
- "@arronqzy/blueprint-dsl": "1.0.15",
23
+ "@arronqzy/i18n": "0.1.16",
24
24
  "@arronqzy/react-rx-store": "1.1.8"
25
25
  },
26
26
  "devDependencies": {
@@ -35,8 +35,8 @@
35
35
  "typescript": "^5.5.4",
36
36
  "vite": "^5.1.4",
37
37
  "@arronqzy/eslint-config": "0.0.0",
38
- "@arronqzy/tailwind": "1.0.2",
39
- "@arronqzy/typescript-config": "1.0.0"
38
+ "@arronqzy/typescript-config": "1.0.0",
39
+ "@arronqzy/tailwind": "1.0.2"
40
40
  },
41
41
  "keywords": [],
42
42
  "author": "",
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useRef } from "react";
2
- import { useI18n } from "@arronqzy/i18n/react";
2
+ import { useI18nOptional as useI18n } from "@arronqzy/i18n/react";
3
3
 
4
4
  export type BlueprintContextMenuState =
5
5
  | {
@@ -16,7 +16,7 @@ import {
16
16
  type PageLifecyclePhase,
17
17
  type ViewEventType,
18
18
  } from "@arronqzy/blueprint-dsl";
19
- import { useI18n } from "@arronqzy/i18n/react";
19
+ import { EnsureI18nProvider, useI18nOptional as useI18n } from "@arronqzy/i18n/react";
20
20
 
21
21
  import { FetchNodeConfigPanel } from "./components/FetchNodeConfigPanel";
22
22
  import { ClockNodeConfigPanel } from "./components/ClockNodeConfigPanel";
@@ -96,7 +96,15 @@ const ROLE_LABEL_KEYS: Record<BlueprintNodeRole, string> = {
96
96
  event: "blueprint.config.roleEvent",
97
97
  };
98
98
 
99
- export function BlueprintNodeConfigSidebar({
99
+ export function BlueprintNodeConfigSidebar(props: BlueprintNodeConfigSidebarProps) {
100
+ return (
101
+ <EnsureI18nProvider>
102
+ <BlueprintNodeConfigSidebarInner {...props} />
103
+ </EnsureI18nProvider>
104
+ );
105
+ }
106
+
107
+ function BlueprintNodeConfigSidebarInner({
100
108
  node,
101
109
  graphNodes = [],
102
110
  graphEdges = [],