@bpmn-nova/react 0.3.1-preview

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/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 BPMN Nova contributors
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,183 @@
1
+ # @bpmn-nova/react
2
+
3
+ BPMN Nova 的 React 18+ Adapter,提供 Studio、Designer、Viewer、审批轨迹、Properties 和实例 Ref。
4
+
5
+ > **English summary:** React 18+ components and refs for BPMN Nova process design, viewing, approval traces, properties, themes, and SVG export.
6
+
7
+ > 当前版本为 `0.3.1-preview`。React 与 React DOM 由宿主工程提供,本包不会替应用选择或升级框架版本。
8
+
9
+ ![BPMN Nova React 流程工作台](https://raw.githubusercontent.com/daxiangme/bpmn-nova/dev/docs/assets/bpmn-nova-designer.jpg)
10
+
11
+ ## 安装
12
+
13
+ ```bash
14
+ npm install @bpmn-nova/react@preview
15
+ ```
16
+
17
+ ```jsx
18
+ import '@bpmn-nova/react/styles.css'
19
+ ```
20
+
21
+ 只安装本包;`@bpmn-nova/studio` 会作为内部依赖自动解析。容器必须有明确高度。
22
+
23
+ ## 流程设计
24
+
25
+ ```jsx
26
+ import { useRef } from 'react'
27
+ import { BpmnStudio } from '@bpmn-nova/react'
28
+ import '@bpmn-nova/react/styles.css'
29
+
30
+ export function WorkflowEditor({ xml }) {
31
+ const studioRef = useRef(null)
32
+
33
+ return (
34
+ <div style={{ height: 720 }}>
35
+ <BpmnStudio
36
+ ref={studioRef}
37
+ xml={xml}
38
+ engine="flowable"
39
+ mode="design"
40
+ theme="auto"
41
+ onChange={(model, reason, nextXml) => {
42
+ console.log(reason, nextXml)
43
+ }}
44
+ />
45
+ </div>
46
+ )
47
+ }
48
+ ```
49
+
50
+ Ref 提供 `exportXml()`、`fitView()`、`setTheme()`、`exportSvg()` 和 `openSvgExportPreview()`。
51
+
52
+ ## 只读展示与审批轨迹
53
+
54
+ ```jsx
55
+ import { BpmnViewer } from '@bpmn-nova/react'
56
+ import '@bpmn-nova/react/styles.css'
57
+
58
+ export function ApprovalTrace({ xml, runtime, resolveAsset }) {
59
+ return (
60
+ <div style={{ height: 720 }}>
61
+ <BpmnViewer
62
+ xml={xml}
63
+ engine="flowable"
64
+ runtime={runtime}
65
+ projection="compact"
66
+ responsive
67
+ theme="auto"
68
+ runtimeAssetResolver={resolveAsset}
69
+ onTraceClick={(event) => console.log(event)}
70
+ />
71
+ </div>
72
+ )
73
+ }
74
+ ```
75
+
76
+ - `approval`:实际发生的有效路径。
77
+ - `compact`:移动时间线、审批动作、图片和附件。
78
+ - `standard`:完整 BPMN 叠加运行状态。
79
+
80
+ ![BPMN Nova React 移动审批时间线](https://raw.githubusercontent.com/daxiangme/bpmn-nova/dev/docs/assets/bpmn-nova-approval-mobile-timeline.jpg)
81
+
82
+ ## Runtime Action 与附件
83
+
84
+ ```js
85
+ const runtime = {
86
+ processInstanceId: 'purchase-20260824',
87
+ status: 'running',
88
+ activities: [{
89
+ id: 'activity-manager-1',
90
+ elementId: 'UserTask_Manager',
91
+ visitId: 'visit-manager-1',
92
+ status: 'completed',
93
+ assignee: '李经理',
94
+ }],
95
+ actions: [{
96
+ id: 'approve-manager-1',
97
+ type: 'approve',
98
+ elementId: 'UserTask_Manager',
99
+ visitId: 'visit-manager-1',
100
+ occurredAt: '2026-08-24T10:12:00+08:00',
101
+ actor: { id: 'manager-li', name: '李经理' },
102
+ content: {
103
+ plainText: '资料完整,同意提交总经理审批。',
104
+ blocks: [{ type: 'file', assetId: 'purchase-checklist' }],
105
+ assets: [{
106
+ id: 'purchase-checklist',
107
+ name: '采购核验清单.txt',
108
+ mediaType: 'text/plain',
109
+ size: 248,
110
+ }],
111
+ },
112
+ }],
113
+ visitedEdges: [],
114
+ }
115
+
116
+ const resolveAsset = async (asset, { purpose, signal }) => {
117
+ const response = await fetch(
118
+ `/api/runtime-assets/${encodeURIComponent(asset.id)}?purpose=${purpose}`,
119
+ { signal },
120
+ )
121
+ return response.ok ? response.url : null
122
+ }
123
+ ```
124
+
125
+ Runtime Snapshot 只保存资源引用;上传、存储和权限签发由宿主负责。
126
+
127
+ ## 主题和 SVG 导出
128
+
129
+ ```jsx
130
+ <BpmnStudio
131
+ ref={studioRef}
132
+ xml={xml}
133
+ theme={{
134
+ mode: 'auto',
135
+ dark: {
136
+ colors: {
137
+ canvas: '#0b1018',
138
+ surface: '#18202b',
139
+ },
140
+ },
141
+ }}
142
+ />
143
+ ```
144
+
145
+ ```js
146
+ studioRef.current?.openSvgExportPreview({
147
+ theme: 'current',
148
+ filename: '采购申请审批流程.svg',
149
+ })
150
+ ```
151
+
152
+ 主题属性变化会更新现有实例,不会重新挂载画布、清除选择或关闭详情。
153
+
154
+ ## Properties 与自定义 Renderer
155
+
156
+ 本包还导出:
157
+
158
+ - `BpmnDesigner`、`BpmnCanvas`、`BpmnPalettePanel`、`BpmnPropertiesPanel`
159
+ - `useBpmnStudio`
160
+ - `createReactPropertyComponent`
161
+ - `createReactRuntimeDetailsComponent`
162
+ - `createReactRuntimeTransitionDetailsComponent`
163
+ - `createReactRuntimeTimelineComponent`
164
+
165
+ ## 常见问题
166
+
167
+ - **无高度:** 为外层容器设置明确高度。
168
+ - **无样式:** 导入一次 `@bpmn-nova/react/styles.css`。
169
+ - **Hooks/React 重复:** React 与 React DOM 应由宿主提供并保持单实例。
170
+ - **SSR:** 将可视组件放到客户端挂载阶段。
171
+ - **包选择:** React 项目只直接安装 `@bpmn-nova/react`。
172
+
173
+ ## 文档与 AI
174
+
175
+ - [完整项目能力](https://github.com/daxiangme/bpmn-nova)
176
+ - [React/Vue 组件说明](https://github.com/daxiangme/bpmn-nova/blob/dev/docs/COMPONENTS.md)
177
+ - [公开 Interface](https://github.com/daxiangme/bpmn-nova/blob/dev/docs/API.md)
178
+ - [AI 接入入口](https://raw.githubusercontent.com/daxiangme/bpmn-nova/dev/llms.txt)
179
+ - [AI 完整上下文](https://raw.githubusercontent.com/daxiangme/bpmn-nova/dev/llms-full.txt)
180
+
181
+ ## License
182
+
183
+ Apache-2.0. See [LICENSE](LICENSE).
@@ -0,0 +1,204 @@
1
+ import type {
2
+ ComponentType,
3
+ CSSProperties,
4
+ ForwardRefExoticComponent,
5
+ RefAttributes,
6
+ } from 'react'
7
+ import type { BpmnEdge, BpmnNode, ElementSelection, EngineId, LayoutOptions, ProcessModel } from '@bpmn-nova/studio'
8
+ import type { BpmnDesigner as DesignerInstance } from '@bpmn-nova/studio/designer'
9
+ import type { IconRegistry } from '@bpmn-nova/studio'
10
+ import type { PaletteItem, PaletteProvider, PaletteRegistry, PaletteSection } from '@bpmn-nova/studio'
11
+ import type {
12
+ PropertiesContext,
13
+ PropertiesProvider,
14
+ PropertiesRegistry,
15
+ PropertyEntry,
16
+ } from '@bpmn-nova/studio'
17
+ import type { ProcessInstanceSnapshot } from '@bpmn-nova/studio/runtime'
18
+ import type { SvgExportArtifact, SvgExportOptions, SvgExportPreviewController } from '@bpmn-nova/studio/export-svg'
19
+ import type {
20
+ BpmnCanvas as CanvasInstance,
21
+ BpmnStudioController,
22
+ BpmnStudioShell,
23
+ ContextMenuRegistry,
24
+ InteractionController,
25
+ StudioCommands,
26
+ StudioShellOptions,
27
+ StudioShellSlots,
28
+ StudioState,
29
+ TemplateRegistry,
30
+ } from '@bpmn-nova/studio'
31
+ import type { NovaThemeInput, NovaThemeState, RuntimeAppearanceOptions } from '@bpmn-nova/studio/theme'
32
+ import type {
33
+ BpmnViewer as ViewerInstance,
34
+ RuntimeDetailsRenderer,
35
+ RuntimeTimelineRenderer,
36
+ RuntimeTraceClickEvent,
37
+ RuntimeTransitionDetailsRenderer,
38
+ ViewerOptions,
39
+ ViewerProjection,
40
+ } from '@bpmn-nova/studio/viewer'
41
+
42
+ export interface BpmnNovaVisualProps {
43
+ theme?: NovaThemeInput
44
+ runtimeAppearance?: RuntimeAppearanceOptions
45
+ onThemeChange?: (state: NovaThemeState) => void
46
+ className?: string
47
+ style?: CSSProperties
48
+ }
49
+ export interface BpmnModelProps {
50
+ model?: ProcessModel
51
+ xml?: string
52
+ engine?: EngineId
53
+ }
54
+ export interface UseBpmnStudioOptions extends BpmnModelProps {
55
+ studio?: BpmnStudioController
56
+ propertiesProfile?: 'business' | 'developer'
57
+ }
58
+ export interface UseBpmnStudioResult { studio: BpmnStudioController; state: StudioState; commands: StudioCommands }
59
+ export function useBpmnStudio(options?: UseBpmnStudioOptions): UseBpmnStudioResult
60
+
61
+ export interface BpmnCanvasProps extends BpmnNovaVisualProps {
62
+ studio: BpmnStudioController
63
+ interactions?: InteractionController
64
+ templates?: TemplateRegistry
65
+ iconRegistry?: IconRegistry
66
+ nodeRenderers?: Record<string, Function>
67
+ nodeRenderer?: Function
68
+ svgExport?: ViewerOptions['svgExport']
69
+ }
70
+ export interface BpmnCanvasHandle {
71
+ readonly instance: CanvasInstance | null
72
+ fitView(padding?: number, options?: Record<string, unknown>): void
73
+ clientToWorld(x: number, y: number): { x: number; y: number } | undefined
74
+ setTheme(theme: NovaThemeInput): NovaThemeState | undefined
75
+ exportSvg(options?: SvgExportOptions): Promise<SvgExportArtifact> | undefined
76
+ openSvgExportPreview(options?: SvgExportOptions & { previewTitle?: string; onDownload?: (artifact: SvgExportArtifact) => void }): SvgExportPreviewController | undefined
77
+ }
78
+ export const BpmnCanvas: ForwardRefExoticComponent<BpmnCanvasProps & RefAttributes<BpmnCanvasHandle>>
79
+
80
+ export interface BpmnPalettePanelProps extends BpmnNovaVisualProps {
81
+ studio: BpmnStudioController
82
+ interactions?: InteractionController
83
+ templates?: TemplateRegistry
84
+ registry?: PaletteRegistry
85
+ providers?: PaletteProvider[]
86
+ canvas?: CanvasInstance | null
87
+ iconRegistry?: IconRegistry
88
+ renderItem?: (context: { item: PaletteItem; panel: unknown }) => HTMLElement | null
89
+ renderSection?: (context: { section: PaletteSection; panel: unknown }) => HTMLElement | null
90
+ }
91
+ export interface BpmnPalettePanelHandle {
92
+ readonly panel: unknown
93
+ render(): void
94
+ setTheme(theme: NovaThemeInput): NovaThemeState | undefined
95
+ }
96
+ export const BpmnPalettePanel: ForwardRefExoticComponent<BpmnPalettePanelProps & RefAttributes<BpmnPalettePanelHandle>>
97
+
98
+ export interface BpmnStudioProps extends BpmnNovaVisualProps, BpmnModelProps {
99
+ studio?: BpmnStudioController
100
+ propertiesProfile?: 'business' | 'developer'
101
+ iconRegistry?: IconRegistry
102
+ paletteRegistry?: PaletteRegistry
103
+ propertiesRegistry?: PropertiesRegistry
104
+ templateRegistry?: TemplateRegistry
105
+ contextMenuRegistry?: ContextMenuRegistry
106
+ nodeRenderers?: Record<string, Function>
107
+ nodeRenderer?: Function
108
+ slots?: StudioShellSlots
109
+ layout?: StudioShellOptions['layout']
110
+ runtime?: ProcessInstanceSnapshot | null
111
+ mode?: 'design' | 'viewer' | 'instance'
112
+ projection?: ViewerProjection
113
+ responsive?: boolean
114
+ projectionOptions?: Array<{ value: ViewerProjection; label: string }>
115
+ leftWidth?: number
116
+ rightWidth?: number
117
+ timeline?: ViewerOptions['timeline']
118
+ runtimeDetails?: ViewerOptions['runtimeDetails']
119
+ runtimeTraceOptions?: ViewerOptions['runtimeTraceOptions']
120
+ runtimePresenter?: ViewerOptions['runtimePresenter']
121
+ runtimeTraceProjector?: ViewerOptions['runtimeTraceProjector']
122
+ runtimeAssetResolver?: ViewerOptions['runtimeAssetResolver']
123
+ runtimeTimelineRenderer?: RuntimeTimelineRenderer
124
+ svgExport?: ViewerOptions['svgExport']
125
+ runtimeDetailsRenderer?: RuntimeDetailsRenderer | null
126
+ runtimeTransitionDetailsRenderer?: RuntimeTransitionDetailsRenderer | null
127
+ onRuntimeTraceItemClick?: ViewerOptions['onRuntimeTraceItemClick']
128
+ onRuntimeDetailsOpen?: ViewerOptions['onRuntimeDetailsOpen']
129
+ onRuntimeTransitionDetailsOpen?: ViewerOptions['onRuntimeTransitionDetailsOpen']
130
+ onElementClick?: ViewerOptions['onElementClick']
131
+ onTraceClick?: (event: RuntimeTraceClickEvent) => void
132
+ onChange?: (model: ProcessModel, reason: string, xml: string) => void
133
+ onSelectionChange?: (selection: ElementSelection | null, element: StudioState['selectedElement']) => void
134
+ onScopeChange?: (activeScopeId: string, scopePath: StudioState['scopePath'], state: StudioState) => void
135
+ }
136
+ export interface BpmnStudioHandle {
137
+ readonly studio: BpmnStudioController
138
+ readonly shell: BpmnStudioShell | null
139
+ exportXml(engine?: EngineId): string
140
+ fitView(): void
141
+ setTheme(theme: NovaThemeInput): NovaThemeState | undefined
142
+ exportSvg(options?: SvgExportOptions): Promise<SvgExportArtifact> | undefined
143
+ openSvgExportPreview(options?: SvgExportOptions & { previewTitle?: string; onDownload?: (artifact: SvgExportArtifact) => void }): SvgExportPreviewController | null | undefined
144
+ }
145
+ export const BpmnStudio: ForwardRefExoticComponent<BpmnStudioProps & RefAttributes<BpmnStudioHandle>>
146
+
147
+ export interface BpmnDesignerProps extends BpmnNovaVisualProps, BpmnModelProps {
148
+ svgExport?: ViewerOptions['svgExport']
149
+ onChange?: (model: ProcessModel, reason: string, xml: string) => void
150
+ onSelectionChange?: (selection: ElementSelection | null, element: BpmnNode | BpmnEdge | null) => void
151
+ }
152
+ export interface BpmnDesignerHandle {
153
+ readonly instance: DesignerInstance | null
154
+ readonly model: ProcessModel | undefined
155
+ exportXml(engine?: EngineId): string
156
+ fitView(): void
157
+ beautify(options?: LayoutOptions): void
158
+ rerouteEdges(options?: LayoutOptions): void
159
+ validate(): Array<{ level: 'error' | 'warning'; elementId?: string; message: string }>
160
+ setTheme(theme: NovaThemeInput): NovaThemeState | undefined
161
+ exportSvg(options?: SvgExportOptions): Promise<SvgExportArtifact> | undefined
162
+ openSvgExportPreview(options?: SvgExportOptions & { previewTitle?: string; onDownload?: (artifact: SvgExportArtifact) => void }): SvgExportPreviewController | undefined
163
+ }
164
+ export const BpmnDesigner: ForwardRefExoticComponent<BpmnDesignerProps & RefAttributes<BpmnDesignerHandle>>
165
+
166
+ export interface BpmnViewerProps extends BpmnNovaVisualProps, BpmnModelProps, Omit<ViewerOptions, 'container' | 'model' | 'theme' | 'runtimeAppearance' | 'onThemeChange'> {}
167
+ export interface BpmnViewerHandle {
168
+ readonly instance: ViewerInstance | null
169
+ fitView(): void
170
+ setProjection(projection: ViewerProjection): void
171
+ setRuntime(runtime: ProcessInstanceSnapshot | null): void
172
+ setDisplayOptions(options: Parameters<ViewerInstance['setDisplayOptions']>[0]): void
173
+ setTheme(theme: NovaThemeInput): NovaThemeState | undefined
174
+ exportSvg(options?: SvgExportOptions): Promise<SvgExportArtifact> | undefined
175
+ openSvgExportPreview(options?: SvgExportOptions & { previewTitle?: string; onDownload?: (artifact: SvgExportArtifact) => void }): SvgExportPreviewController | undefined
176
+ }
177
+ export const BpmnViewer: ForwardRefExoticComponent<BpmnViewerProps & RefAttributes<BpmnViewerHandle>>
178
+
179
+ export interface ReactPropertyComponentProps {
180
+ entry: PropertyEntry
181
+ context: PropertiesContext
182
+ value: unknown
183
+ onChange(value: unknown): void
184
+ }
185
+ export function createReactPropertyComponent(component: ComponentType<ReactPropertyComponentProps>): (context: Record<string, unknown>) => void | (() => void)
186
+ export interface BpmnPropertiesPanelProps extends BpmnNovaVisualProps {
187
+ studio?: BpmnStudioController
188
+ designer?: BpmnStudioController | DesignerInstance
189
+ registry?: PropertiesRegistry
190
+ providers?: PropertiesProvider[]
191
+ dataProviders?: Record<string, unknown>
192
+ components?: Record<string, ComponentType<ReactPropertyComponentProps>>
193
+ }
194
+ export interface BpmnPropertiesPanelHandle {
195
+ readonly panel: unknown
196
+ readonly registry: PropertiesRegistry | null
197
+ render(): void
198
+ setTheme(theme: NovaThemeInput): NovaThemeState | undefined
199
+ }
200
+ export const BpmnPropertiesPanel: ForwardRefExoticComponent<BpmnPropertiesPanelProps & RefAttributes<BpmnPropertiesPanelHandle>>
201
+
202
+ export function createReactRuntimeDetailsComponent(component: ComponentType<Omit<Parameters<RuntimeDetailsRenderer>[0], 'container'>>): RuntimeDetailsRenderer
203
+ export function createReactRuntimeTransitionDetailsComponent(component: ComponentType<Omit<Parameters<RuntimeTransitionDetailsRenderer>[0], 'container'>>): RuntimeTransitionDetailsRenderer
204
+ export function createReactRuntimeTimelineComponent(component: ComponentType<Omit<Parameters<RuntimeTimelineRenderer>[0], 'container'>>): RuntimeTimelineRenderer