@bpmn-nova/studio 0.3.0-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 +17 -0
- package/README.md +60 -0
- package/dist/canvas.js +943 -0
- package/dist/context-menu.js +168 -0
- package/dist/controller.js +677 -0
- package/dist/index.d.ts +447 -0
- package/dist/index.js +16 -0
- package/dist/interactions.js +54 -0
- package/dist/selection-layout.js +229 -0
- package/dist/shell.js +608 -0
- package/dist/styles.css +1334 -0
- package/package.json +70 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
export * from '@bpmn-nova/core'
|
|
2
|
+
export * from '@bpmn-nova/bpmn-model'
|
|
3
|
+
export * from '@bpmn-nova/runtime'
|
|
4
|
+
export * from '@bpmn-nova/theme'
|
|
5
|
+
export * from '@bpmn-nova/designer'
|
|
6
|
+
export * from '@bpmn-nova/viewer'
|
|
7
|
+
export * from '@bpmn-nova/flowable'
|
|
8
|
+
export * from '@bpmn-nova/activiti'
|
|
9
|
+
export * from '@bpmn-nova/properties'
|
|
10
|
+
export * from '@bpmn-nova/icons'
|
|
11
|
+
export * from '@bpmn-nova/palette'
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
BpmnEdge,
|
|
15
|
+
BpmnNode,
|
|
16
|
+
ElementSelection,
|
|
17
|
+
EngineId,
|
|
18
|
+
LayoutOptions,
|
|
19
|
+
NodeType,
|
|
20
|
+
Point,
|
|
21
|
+
ProcessModel,
|
|
22
|
+
SelectionRect,
|
|
23
|
+
} from '@bpmn-nova/core'
|
|
24
|
+
import type { IconRegistry } from '@bpmn-nova/icons'
|
|
25
|
+
import type { PaletteRegistry } from '@bpmn-nova/palette'
|
|
26
|
+
import type { PropertiesRegistry } from '@bpmn-nova/properties'
|
|
27
|
+
import type { DiagramNodeRenderer, DiagramRendererOptions } from '@bpmn-nova/renderer'
|
|
28
|
+
import type {
|
|
29
|
+
ActivityInstance as RuntimeActivityInstance,
|
|
30
|
+
ProcessInstanceSnapshot as RuntimeProcessInstanceSnapshot,
|
|
31
|
+
} from '@bpmn-nova/runtime'
|
|
32
|
+
import type { NovaThemeInput, NovaThemeMode, NovaThemeState, RuntimeAppearanceOptions, RuntimeAppearanceResolver } from '@bpmn-nova/theme'
|
|
33
|
+
import type {
|
|
34
|
+
RuntimeDetailsRenderer,
|
|
35
|
+
RuntimeTransitionDetailsRenderer,
|
|
36
|
+
} from '@bpmn-nova/viewer'
|
|
37
|
+
|
|
38
|
+
// Aggregate compatibility surface. Studio re-exports the package-level types,
|
|
39
|
+
// and keeps these frequently consumed declarations visible at its own entry.
|
|
40
|
+
export interface ScopedElement { scopeId?: string }
|
|
41
|
+
export type NodeVisualSurface = 'palette' | 'canvas' | 'viewer' | 'timeline'
|
|
42
|
+
export interface NodeRendererContext {
|
|
43
|
+
container: HTMLElement
|
|
44
|
+
node: BpmnNode
|
|
45
|
+
mode: 'design' | 'viewer' | 'instance'
|
|
46
|
+
renderSemanticIcon(target?: Element, options?: { className?: string; title?: string }): SVGSVGElement | null
|
|
47
|
+
}
|
|
48
|
+
export function hydrateIcons(root: ParentNode, registry: IconRegistry): void
|
|
49
|
+
export type PropertyEntryType =
|
|
50
|
+
| 'text' | 'textarea' | 'code' | 'expression' | 'number' | 'select' | 'switch' | 'range' | 'readonly' | 'action' | 'tags'
|
|
51
|
+
| 'table' | 'branchList' | 'flow-list' | 'node-list' | 'user-select' | 'form-select' | 'process-select' | 'resource-select' | 'node-select'
|
|
52
|
+
| (string & {})
|
|
53
|
+
export interface PropertyEntry {
|
|
54
|
+
id: string
|
|
55
|
+
type?: PropertyEntryType
|
|
56
|
+
label?: string
|
|
57
|
+
iconId?: string
|
|
58
|
+
relation?: 'source' | 'target'
|
|
59
|
+
}
|
|
60
|
+
export interface GatewayRoleResolution {
|
|
61
|
+
topologyComplete: boolean
|
|
62
|
+
[key: string]: unknown
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface RuntimeTransitionRouteOptions {
|
|
66
|
+
occupiedRoutes?: Array<Point[] | { points: Point[] }>
|
|
67
|
+
obstacles?: SelectionRect[]
|
|
68
|
+
labelSize?: { width: number; height: number }
|
|
69
|
+
nodeClearance?: number
|
|
70
|
+
laneGap?: number
|
|
71
|
+
laneSpacing?: number
|
|
72
|
+
nearParallelDistance?: number
|
|
73
|
+
anchorOverlapTolerance?: number
|
|
74
|
+
maxLanesPerSide?: number
|
|
75
|
+
}
|
|
76
|
+
export interface RuntimeTransitionRoute {
|
|
77
|
+
points: Point[]
|
|
78
|
+
labelPoint: Point
|
|
79
|
+
direction: 'horizontal' | 'vertical'
|
|
80
|
+
laneSide: 'top' | 'bottom' | 'left' | 'right'
|
|
81
|
+
laneIndex: number
|
|
82
|
+
sourceSide: 'top' | 'right' | 'bottom' | 'left'
|
|
83
|
+
targetSide: 'top' | 'right' | 'bottom' | 'left'
|
|
84
|
+
anchorStrategy: 'outer-same-side' | 'flow-axis-fallback'
|
|
85
|
+
portConflicts: number
|
|
86
|
+
}
|
|
87
|
+
export function routeRuntimeTransition(model: ProcessModel, transition: import('@bpmn-nova/runtime').RuntimeTransition, options?: RuntimeTransitionRouteOptions): RuntimeTransitionRoute | null
|
|
88
|
+
|
|
89
|
+
export type RuntimeParticipant = import('@bpmn-nova/runtime').RuntimeParticipant
|
|
90
|
+
export type RuntimeTransition = import('@bpmn-nova/runtime').RuntimeTransition
|
|
91
|
+
export type NodeRuntimePresentation = import('@bpmn-nova/runtime').NodeRuntimePresentation
|
|
92
|
+
export type RuntimePresentation = import('@bpmn-nova/runtime').RuntimePresentation
|
|
93
|
+
export interface ActivityInstance extends RuntimeActivityInstance {
|
|
94
|
+
visitId?: string
|
|
95
|
+
multiInstanceId?: string
|
|
96
|
+
participant?: RuntimeParticipant
|
|
97
|
+
approvalMode?: 'single' | 'all' | 'any'
|
|
98
|
+
multiInstanceMode?: 'parallel' | 'sequential'
|
|
99
|
+
totalInstances?: number
|
|
100
|
+
requiredInstances?: number
|
|
101
|
+
}
|
|
102
|
+
export interface ProcessInstanceSnapshot extends RuntimeProcessInstanceSnapshot {
|
|
103
|
+
transitions?: RuntimeTransition[]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type ViewerProjection = 'auto' | 'standard' | 'approval' | 'compact'
|
|
107
|
+
export type RuntimeTraceProjection = import('@bpmn-nova/viewer').RuntimeTraceProjection
|
|
108
|
+
export type RuntimeTraceItem = import('@bpmn-nova/viewer').RuntimeTraceItem
|
|
109
|
+
export type RuntimeTraceLink = import('@bpmn-nova/viewer').RuntimeTraceLink
|
|
110
|
+
export type RuntimeTraceGroup = import('@bpmn-nova/viewer').RuntimeTraceGroup
|
|
111
|
+
export interface RuntimeTraceProjectionOptions {
|
|
112
|
+
includePredicted?: boolean
|
|
113
|
+
showStartMilestone?: boolean
|
|
114
|
+
showEndMilestone?: boolean
|
|
115
|
+
}
|
|
116
|
+
export interface ViewerTimelineOptions {
|
|
117
|
+
title?: string | null | ((context: import('@bpmn-nova/viewer').ViewerTimelineContext) => string | null)
|
|
118
|
+
description?: string | null | ((context: import('@bpmn-nova/viewer').ViewerTimelineContext) => string | null)
|
|
119
|
+
}
|
|
120
|
+
export interface RuntimeDetailsLayoutOptions {
|
|
121
|
+
placement?: 'popover' | 'center' | 'bottom'
|
|
122
|
+
width?: number | string
|
|
123
|
+
maxHeight?: number | string
|
|
124
|
+
backdrop?: boolean
|
|
125
|
+
dragToDismiss?: boolean
|
|
126
|
+
}
|
|
127
|
+
export interface RuntimeDetailsOptions {
|
|
128
|
+
autoOpen?: boolean
|
|
129
|
+
desktop?: RuntimeDetailsLayoutOptions
|
|
130
|
+
mobile?: RuntimeDetailsLayoutOptions
|
|
131
|
+
}
|
|
132
|
+
export type RuntimeTimelineRenderer = import('@bpmn-nova/viewer').RuntimeTimelineRenderer
|
|
133
|
+
export type RuntimeTraceClickEvent = import('@bpmn-nova/viewer').RuntimeTraceClickEvent
|
|
134
|
+
export interface ViewerOptions {
|
|
135
|
+
container: HTMLElement
|
|
136
|
+
model: ProcessModel
|
|
137
|
+
runtime?: ProcessInstanceSnapshot | null
|
|
138
|
+
iconRegistry?: IconRegistry
|
|
139
|
+
projection?: ViewerProjection
|
|
140
|
+
responsive?: boolean
|
|
141
|
+
timeline?: ViewerTimelineOptions
|
|
142
|
+
runtimeDetails?: RuntimeDetailsOptions
|
|
143
|
+
runtimeTraceOptions?: RuntimeTraceProjectionOptions
|
|
144
|
+
onTraceClick?: (event: RuntimeTraceClickEvent) => void
|
|
145
|
+
runtimePresenter?: (context: { model: ProcessModel; runtime: ProcessInstanceSnapshot | null; appearance: RuntimeAppearanceResolver }) => RuntimePresentation
|
|
146
|
+
runtimeDetailsRenderer?: RuntimeDetailsRenderer | null
|
|
147
|
+
onRuntimeDetailsOpen?: Function
|
|
148
|
+
runtimeTransitionDetailsRenderer?: RuntimeTransitionDetailsRenderer | null
|
|
149
|
+
onRuntimeTransitionDetailsOpen?: Function
|
|
150
|
+
}
|
|
151
|
+
export class BpmnViewer {
|
|
152
|
+
constructor(options: ViewerOptions)
|
|
153
|
+
setDisplayOptions(options: { timeline?: ViewerTimelineOptions; runtimeDetails?: RuntimeDetailsOptions; runtimeTraceOptions?: RuntimeTraceProjectionOptions }): void
|
|
154
|
+
fitView(): void
|
|
155
|
+
destroy(): void
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export type NodeRenderer = DiagramNodeRenderer
|
|
159
|
+
export interface StudioState {
|
|
160
|
+
model: ProcessModel
|
|
161
|
+
selection: ElementSelection | null
|
|
162
|
+
selectedElement: ProcessModel | BpmnNode | BpmnEdge | Array<BpmnNode | BpmnEdge> | null
|
|
163
|
+
connectingSource: string | null
|
|
164
|
+
canUndo: boolean
|
|
165
|
+
canRedo: boolean
|
|
166
|
+
engine: EngineId
|
|
167
|
+
propertiesProfile: 'business' | 'developer'
|
|
168
|
+
activeScopeId: string
|
|
169
|
+
scopePath: Array<{ id: string; name: string; kind: 'process' | 'subProcess' }>
|
|
170
|
+
}
|
|
171
|
+
export interface NodePreset extends Partial<Omit<BpmnNode, 'properties'>> { properties?: Record<string, unknown> }
|
|
172
|
+
export interface TemplateDefinition {
|
|
173
|
+
nodes: Array<{ key: string; nodeType: NodeType; offset?: Point; preset?: NodePreset }>
|
|
174
|
+
edges?: Array<{ source: string; target: string; preset?: Partial<BpmnEdge> }>
|
|
175
|
+
}
|
|
176
|
+
export type SelectionLayoutOperation =
|
|
177
|
+
| { type: 'align'; alignment: 'left' | 'centerX' | 'right' | 'top' | 'centerY' | 'bottom' }
|
|
178
|
+
| { type: 'distribute'; axis: 'horizontal' | 'vertical' }
|
|
179
|
+
| { type: 'layout' }
|
|
180
|
+
| { type: 'reroute' }
|
|
181
|
+
export interface StudioExtension {
|
|
182
|
+
id: string
|
|
183
|
+
setup(context: { studio: BpmnStudioController }): void | (() => void)
|
|
184
|
+
}
|
|
185
|
+
export interface StudioControllerOptions {
|
|
186
|
+
model: ProcessModel
|
|
187
|
+
historyLimit?: number
|
|
188
|
+
extensions?: StudioExtension[]
|
|
189
|
+
propertiesProfile?: 'business' | 'developer'
|
|
190
|
+
}
|
|
191
|
+
export interface StudioCommands {
|
|
192
|
+
createNode(input: { nodeType: NodeType; point?: Point; preset?: NodePreset }): BpmnNode
|
|
193
|
+
createTemplate(template: TemplateDefinition, point: Point): { nodes: BpmnNode[]; edges: BpmnEdge[] }
|
|
194
|
+
connect(source: string, target: string, overrides?: Partial<BpmnEdge>): BpmnEdge | null
|
|
195
|
+
updateProcess(patch: Partial<ProcessModel>): void
|
|
196
|
+
updateNode(id: string, patch: Partial<BpmnNode>): boolean
|
|
197
|
+
updateEdge(id: string, patch: Partial<BpmnEdge>): boolean
|
|
198
|
+
updateEdges(patches: Array<{ id: string; patch: Partial<BpmnEdge> }>): boolean
|
|
199
|
+
remove(selection?: ElementSelection | null): boolean
|
|
200
|
+
changeElementId(kind: 'process' | 'node' | 'edge', oldId: string, nextId: string): boolean
|
|
201
|
+
changeNodeType(id: string, type: NodeType): boolean
|
|
202
|
+
quickAdd(sourceId: string, type?: NodeType, preset?: NodePreset): BpmnNode | null
|
|
203
|
+
autoLayout(direction?: 'horizontal' | 'vertical'): void
|
|
204
|
+
beautify(options?: LayoutOptions): void
|
|
205
|
+
rerouteEdges(options?: LayoutOptions): void
|
|
206
|
+
resetEdgeRoute(id: string): boolean
|
|
207
|
+
setEngine(engine: EngineId): void
|
|
208
|
+
setPropertiesProfile(profile: 'business' | 'developer'): void
|
|
209
|
+
select(selection: ElementSelection | null): boolean
|
|
210
|
+
selectInRect(rect: SelectionRect, options?: { mode?: 'replace' | 'add' | 'toggle' }): ElementSelection
|
|
211
|
+
getSelectionBounds(): SelectionRect | null
|
|
212
|
+
arrangeSelection(operation: SelectionLayoutOperation): boolean
|
|
213
|
+
groupSelection(): BpmnNode | null
|
|
214
|
+
ungroup(id?: string): boolean
|
|
215
|
+
attachLane(laneId: string, participantId: string, index?: number): boolean
|
|
216
|
+
detachLane(laneId: string, point?: Point): boolean
|
|
217
|
+
enterScope(subProcessId: string): boolean
|
|
218
|
+
leaveScope(): boolean
|
|
219
|
+
navigateToScope(scopeId: string): boolean
|
|
220
|
+
getActiveGraph(): ProcessModel
|
|
221
|
+
undo(): boolean
|
|
222
|
+
redo(): boolean
|
|
223
|
+
}
|
|
224
|
+
export interface StudioEvent {
|
|
225
|
+
type: 'modelChanged' | 'selectionChanged' | 'historyChanged' | 'scopeChanged' | 'propertiesProfileChanged' | string
|
|
226
|
+
reason?: string
|
|
227
|
+
state: StudioState
|
|
228
|
+
[key: string]: unknown
|
|
229
|
+
}
|
|
230
|
+
export function canCreateSequenceFlow(model: ProcessModel, sourceId: string, targetId: string): boolean
|
|
231
|
+
export class BpmnStudioController {
|
|
232
|
+
constructor(options: StudioControllerOptions)
|
|
233
|
+
readonly model: ProcessModel
|
|
234
|
+
selection: ElementSelection | null
|
|
235
|
+
connectingSource: string | null
|
|
236
|
+
activeScopeId: string
|
|
237
|
+
propertiesProfile: 'business' | 'developer'
|
|
238
|
+
readonly commands: StudioCommands
|
|
239
|
+
getState(): StudioState
|
|
240
|
+
getSelectedElement(): StudioState['selectedElement']
|
|
241
|
+
getActiveGraph(): ProcessModel
|
|
242
|
+
subscribe(listener: (event: StudioEvent) => void): () => void
|
|
243
|
+
select(selection: ElementSelection | null): boolean
|
|
244
|
+
selectInRect(rect: SelectionRect, options?: { mode?: 'replace' | 'add' | 'toggle' }): ElementSelection
|
|
245
|
+
getSelectionBounds(): SelectionRect | null
|
|
246
|
+
arrangeSelection(operation: SelectionLayoutOperation): boolean
|
|
247
|
+
groupSelection(): BpmnNode | null
|
|
248
|
+
ungroup(id?: string): boolean
|
|
249
|
+
attachLane(laneId: string, participantId: string, index?: number): boolean
|
|
250
|
+
detachLane(laneId: string, point?: Point): boolean
|
|
251
|
+
enterScope(subProcessId: string): boolean
|
|
252
|
+
leaveScope(): boolean
|
|
253
|
+
navigateToScope(scopeId: string): boolean
|
|
254
|
+
setModel(model: ProcessModel, options?: { resetHistory?: boolean }): void
|
|
255
|
+
setPropertiesProfile(profile: 'business' | 'developer'): void
|
|
256
|
+
startConnect(sourceId: string): boolean
|
|
257
|
+
cancelConnect(): void
|
|
258
|
+
createNode(input: Parameters<StudioCommands['createNode']>[0]): BpmnNode
|
|
259
|
+
createTemplate(template: TemplateDefinition, point: Point): ReturnType<StudioCommands['createTemplate']>
|
|
260
|
+
connect(source: string, target: string, overrides?: Partial<BpmnEdge>): BpmnEdge | null
|
|
261
|
+
updateProcess(patch: Partial<ProcessModel>): void
|
|
262
|
+
updateNode(id: string, patch: Partial<BpmnNode>): boolean
|
|
263
|
+
updateEdge(id: string, patch: Partial<BpmnEdge>): boolean
|
|
264
|
+
updateEdges(patches: Array<{ id: string; patch: Partial<BpmnEdge> }>): boolean
|
|
265
|
+
remove(selection?: ElementSelection | null): boolean
|
|
266
|
+
changeElementId(kind: 'process' | 'node' | 'edge', oldId: string, nextId: string): boolean
|
|
267
|
+
changeNodeType(id: string, type: NodeType): boolean
|
|
268
|
+
quickAdd(sourceId: string, type?: NodeType, preset?: NodePreset): BpmnNode | null
|
|
269
|
+
autoLayout(direction?: 'horizontal' | 'vertical'): void
|
|
270
|
+
beautify(options?: LayoutOptions): void
|
|
271
|
+
rerouteEdges(options?: LayoutOptions): void
|
|
272
|
+
resetEdgeRoute(id: string): boolean
|
|
273
|
+
setEngine(engine: EngineId): void
|
|
274
|
+
undo(): boolean
|
|
275
|
+
redo(): boolean
|
|
276
|
+
exportXml(engine?: EngineId): string
|
|
277
|
+
importXml(xml: string, engine?: EngineId): ProcessModel
|
|
278
|
+
registerExtension(extension: StudioExtension): () => void
|
|
279
|
+
destroy(): void
|
|
280
|
+
}
|
|
281
|
+
export function createStudioController(options: StudioControllerOptions): BpmnStudioController
|
|
282
|
+
|
|
283
|
+
export const CREATE_INTENT_MIME: 'application/x-bpmn-nova-create-intent+json'
|
|
284
|
+
export type CreateIntent =
|
|
285
|
+
| { kind: 'node'; nodeType: NodeType; preset?: NodePreset }
|
|
286
|
+
| { kind: 'template'; templateId: string; [key: string]: unknown }
|
|
287
|
+
| { kind: 'action'; [key: string]: unknown }
|
|
288
|
+
export interface TemplateRegistration {
|
|
289
|
+
id: string
|
|
290
|
+
label?: string
|
|
291
|
+
create(context: unknown): TemplateDefinition
|
|
292
|
+
}
|
|
293
|
+
export class TemplateRegistry {
|
|
294
|
+
constructor(templates?: TemplateRegistration[])
|
|
295
|
+
register(template: TemplateRegistration): () => void
|
|
296
|
+
resolve(id: string): TemplateRegistration | null
|
|
297
|
+
list(): TemplateRegistration[]
|
|
298
|
+
}
|
|
299
|
+
export class InteractionController {
|
|
300
|
+
constructor(options: { studio: BpmnStudioController; templates?: TemplateRegistry })
|
|
301
|
+
beginCreate(intent: CreateIntent): { intent: CreateIntent; startedAt: number }
|
|
302
|
+
serialize(session: unknown): string
|
|
303
|
+
deserialize(value: string): unknown
|
|
304
|
+
drop(session: unknown, pointer: { clientX: number; clientY: number }, canvas: { clientToWorld(x: number, y: number): Point }): unknown
|
|
305
|
+
}
|
|
306
|
+
export function createTemplateRegistry(templates?: TemplateRegistration[]): TemplateRegistry
|
|
307
|
+
export function createInteractionController(options: ConstructorParameters<typeof InteractionController>[0]): InteractionController
|
|
308
|
+
|
|
309
|
+
export type ContextMenuTarget =
|
|
310
|
+
| { kind: 'canvas'; id: string }
|
|
311
|
+
| { kind: 'node' | 'edge'; id: string }
|
|
312
|
+
| { kind: 'multi'; items: Array<{ kind: 'node' | 'edge'; id: string }> }
|
|
313
|
+
export interface ContextMenuContext {
|
|
314
|
+
studio: BpmnStudioController
|
|
315
|
+
canvas: BpmnCanvas
|
|
316
|
+
target: ContextMenuTarget
|
|
317
|
+
selection: ElementSelection | null
|
|
318
|
+
position?: Point
|
|
319
|
+
}
|
|
320
|
+
export interface ContextMenuAction {
|
|
321
|
+
id: string
|
|
322
|
+
label?: string
|
|
323
|
+
iconId?: string
|
|
324
|
+
group?: string
|
|
325
|
+
disabled?: boolean | ((context: ContextMenuContext) => boolean)
|
|
326
|
+
danger?: boolean
|
|
327
|
+
visible?: (context: ContextMenuContext) => boolean
|
|
328
|
+
position?: { before?: string; after?: string; replace?: string; remove?: string; prepend?: boolean; append?: boolean }
|
|
329
|
+
execute?(context: ContextMenuContext): unknown
|
|
330
|
+
}
|
|
331
|
+
export interface ContextMenuProvider { id: string; priority?: number; getActions?(context: ContextMenuContext): ContextMenuAction[]; actions?: ContextMenuAction[] }
|
|
332
|
+
export const defaultContextMenuProvider: ContextMenuProvider
|
|
333
|
+
export class ContextMenuRegistry {
|
|
334
|
+
registerProvider(priority: number, provider: ContextMenuProvider): () => void
|
|
335
|
+
registerProvider(provider: ContextMenuProvider): () => void
|
|
336
|
+
resolve(context: ContextMenuContext): ContextMenuAction[]
|
|
337
|
+
}
|
|
338
|
+
export function createContextMenuRegistry(): ContextMenuRegistry
|
|
339
|
+
export function createDefaultContextMenuRegistry(options?: { providers?: ContextMenuProvider[] }): ContextMenuRegistry
|
|
340
|
+
|
|
341
|
+
export type SelectionToolbarSlot = (context: {
|
|
342
|
+
container: HTMLElement
|
|
343
|
+
studio: BpmnStudioController
|
|
344
|
+
canvas: BpmnCanvas
|
|
345
|
+
selection: Extract<ElementSelection, { kind: 'multi' }>
|
|
346
|
+
elements: BpmnNode[]
|
|
347
|
+
bounds: SelectionRect
|
|
348
|
+
actions: {
|
|
349
|
+
align(alignment: Extract<SelectionLayoutOperation, { type: 'align' }>['alignment']): boolean
|
|
350
|
+
distribute(axis: Extract<SelectionLayoutOperation, { type: 'distribute' }>['axis']): boolean
|
|
351
|
+
layout(): boolean
|
|
352
|
+
reroute(): boolean
|
|
353
|
+
fit(): boolean
|
|
354
|
+
group(): BpmnNode | null
|
|
355
|
+
}
|
|
356
|
+
}) => void | (() => void)
|
|
357
|
+
export type ContextMenuSlot = (context: ContextMenuContext & {
|
|
358
|
+
container: HTMLElement
|
|
359
|
+
position: Point
|
|
360
|
+
actions: ContextMenuAction[]
|
|
361
|
+
execute(id: string): boolean
|
|
362
|
+
close(): void
|
|
363
|
+
}) => void | (() => void)
|
|
364
|
+
export interface BpmnCanvasOptions {
|
|
365
|
+
container: HTMLElement
|
|
366
|
+
studio: BpmnStudioController
|
|
367
|
+
rendererOptions?: DiagramRendererOptions
|
|
368
|
+
interactions?: InteractionController | null
|
|
369
|
+
selectionToolbar?: HTMLElement | SelectionToolbarSlot | null
|
|
370
|
+
contextMenu?: HTMLElement | ContextMenuSlot | null
|
|
371
|
+
contextMenuRegistry?: ContextMenuRegistry
|
|
372
|
+
pointerMode?: 'select' | 'marquee' | 'pan'
|
|
373
|
+
theme?: NovaThemeInput
|
|
374
|
+
onThemeChange?: (state: NovaThemeState) => void
|
|
375
|
+
}
|
|
376
|
+
export class BpmnCanvas {
|
|
377
|
+
constructor(options: BpmnCanvasOptions)
|
|
378
|
+
clientToWorld(clientX: number, clientY: number): Point
|
|
379
|
+
getViewportCenterWorld(): Point
|
|
380
|
+
fitView(padding?: number, options?: Record<string, unknown>): void
|
|
381
|
+
fitSelection(padding?: number): boolean
|
|
382
|
+
setPointerMode(mode: 'select' | 'marquee' | 'pan'): boolean
|
|
383
|
+
getPointerMode(): 'select' | 'marquee' | 'pan'
|
|
384
|
+
zoomBy(factor: number): void
|
|
385
|
+
actualSize(padding?: number): void
|
|
386
|
+
getViewportState(): { zoom: number; pan: Point }
|
|
387
|
+
setTheme(theme: NovaThemeInput): NovaThemeState
|
|
388
|
+
setThemeMode(mode: NovaThemeMode): NovaThemeState
|
|
389
|
+
getThemeState(): NovaThemeState
|
|
390
|
+
closeContextMenu(): void
|
|
391
|
+
destroy(): void
|
|
392
|
+
}
|
|
393
|
+
export function createBpmnCanvas(options: BpmnCanvasOptions): BpmnCanvas
|
|
394
|
+
|
|
395
|
+
export interface StudioShellSlots {
|
|
396
|
+
left?: HTMLElement | ((context: Record<string, unknown>) => void | (() => void))
|
|
397
|
+
right?: HTMLElement | ((context: Record<string, unknown>) => void | (() => void))
|
|
398
|
+
header?: HTMLElement | ((context: Record<string, unknown>) => void | (() => void))
|
|
399
|
+
contextMenu?: ContextMenuSlot
|
|
400
|
+
selectionToolbar?: SelectionToolbarSlot
|
|
401
|
+
runtimeDetails?: RuntimeDetailsRenderer
|
|
402
|
+
runtimeTransitionDetails?: RuntimeTransitionDetailsRenderer
|
|
403
|
+
runtimeTimeline?: RuntimeTimelineRenderer
|
|
404
|
+
[name: string]: HTMLElement | Function | undefined
|
|
405
|
+
}
|
|
406
|
+
export interface StudioShellOptions {
|
|
407
|
+
container: HTMLElement
|
|
408
|
+
studio: BpmnStudioController
|
|
409
|
+
iconRegistry?: IconRegistry
|
|
410
|
+
paletteRegistry?: PaletteRegistry
|
|
411
|
+
propertiesRegistry?: PropertiesRegistry
|
|
412
|
+
templateRegistry?: TemplateRegistry
|
|
413
|
+
contextMenuRegistry?: ContextMenuRegistry
|
|
414
|
+
rendererOptions?: DiagramRendererOptions & {
|
|
415
|
+
runtimeTraceOptions?: RuntimeTraceProjectionOptions
|
|
416
|
+
timeline?: ViewerTimelineOptions
|
|
417
|
+
}
|
|
418
|
+
slots?: StudioShellSlots
|
|
419
|
+
layout?: (context: Record<string, unknown>) => void | (() => void)
|
|
420
|
+
runtime?: ProcessInstanceSnapshot | null
|
|
421
|
+
mode?: 'design' | 'viewer' | 'instance'
|
|
422
|
+
projection?: ViewerProjection
|
|
423
|
+
responsive?: boolean
|
|
424
|
+
projectionOptions?: Array<{ value: ViewerProjection; label: string }>
|
|
425
|
+
leftWidth?: number
|
|
426
|
+
rightWidth?: number
|
|
427
|
+
theme?: NovaThemeInput
|
|
428
|
+
runtimeAppearance?: RuntimeAppearanceOptions
|
|
429
|
+
onThemeChange?: (state: NovaThemeState) => void
|
|
430
|
+
}
|
|
431
|
+
export class BpmnStudioShell {
|
|
432
|
+
constructor(options: StudioShellOptions)
|
|
433
|
+
canvas?: BpmnCanvas
|
|
434
|
+
viewer?: BpmnViewer
|
|
435
|
+
setMode(mode: 'design' | 'viewer' | 'instance'): void
|
|
436
|
+
setRuntime(runtime: ProcessInstanceSnapshot | null): void
|
|
437
|
+
setProjection(projection: ViewerProjection): void
|
|
438
|
+
setTheme(theme: NovaThemeInput): NovaThemeState
|
|
439
|
+
setThemeMode(mode: NovaThemeMode): NovaThemeState
|
|
440
|
+
getThemeState(): NovaThemeState
|
|
441
|
+
subscribeTheme(listener: (state: NovaThemeState) => void): () => void
|
|
442
|
+
setRuntimeAppearance(options: RuntimeAppearanceOptions | null): void
|
|
443
|
+
fitView(): void
|
|
444
|
+
zoomBy(factor: number): void
|
|
445
|
+
destroy(): void
|
|
446
|
+
}
|
|
447
|
+
export function createStudioShell(options: StudioShellOptions): BpmnStudioShell
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from '@bpmn-nova/core';
|
|
2
|
+
export * from '@bpmn-nova/bpmn-model';
|
|
3
|
+
export * from '@bpmn-nova/runtime';
|
|
4
|
+
export * from '@bpmn-nova/theme';
|
|
5
|
+
export * from '@bpmn-nova/designer';
|
|
6
|
+
export * from '@bpmn-nova/viewer';
|
|
7
|
+
export * from '@bpmn-nova/flowable';
|
|
8
|
+
export * from '@bpmn-nova/activiti';
|
|
9
|
+
export * from '@bpmn-nova/properties';
|
|
10
|
+
export * from './controller.js';
|
|
11
|
+
export * from './interactions.js';
|
|
12
|
+
export * from './canvas.js';
|
|
13
|
+
export * from './context-menu.js';
|
|
14
|
+
export * from './shell.js';
|
|
15
|
+
export * from '@bpmn-nova/icons';
|
|
16
|
+
export * from '@bpmn-nova/palette';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { NODE_DEFINITIONS } from '@bpmn-nova/core';
|
|
2
|
+
|
|
3
|
+
export const CREATE_INTENT_MIME = 'application/x-bpmn-nova-create-intent+json';
|
|
4
|
+
|
|
5
|
+
export class TemplateRegistry {
|
|
6
|
+
constructor(templates = []) { this._templates = new Map(); for (const template of templates) this.register(template); }
|
|
7
|
+
register(template) {
|
|
8
|
+
if (!template?.id || typeof template.create !== 'function') throw new Error('Template requires id and create().');
|
|
9
|
+
this._templates.set(template.id, template);
|
|
10
|
+
return () => this._templates.delete(template.id);
|
|
11
|
+
}
|
|
12
|
+
resolve(id) { return this._templates.get(id) || null; }
|
|
13
|
+
list() { return [...this._templates.values()]; }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class InteractionController {
|
|
17
|
+
constructor({ studio, templates = new TemplateRegistry() } = {}) {
|
|
18
|
+
if (!studio) throw new Error('InteractionController requires a studio controller.');
|
|
19
|
+
this.studio = studio;
|
|
20
|
+
this.templates = templates;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
beginCreate(intent) {
|
|
24
|
+
if (!intent || !['node', 'template', 'action'].includes(intent.kind)) throw new Error('Unsupported create intent.');
|
|
25
|
+
const copy = intent.kind === 'action' ? { ...intent } : JSON.parse(JSON.stringify(intent));
|
|
26
|
+
return Object.freeze({ intent: copy, startedAt: Date.now() });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
serialize(session) {
|
|
30
|
+
if (session?.intent?.kind === 'action') throw new Error('Action intents are click-only and cannot be serialized for drag and drop.');
|
|
31
|
+
return JSON.stringify(session.intent);
|
|
32
|
+
}
|
|
33
|
+
deserialize(value) { return this.beginCreate(JSON.parse(value)); }
|
|
34
|
+
|
|
35
|
+
drop(session, pointer, canvas) {
|
|
36
|
+
if (!session?.intent || !canvas?.clientToWorld) throw new Error('Drop requires a create session and canvas coordinate adapter.');
|
|
37
|
+
const point = canvas.clientToWorld(pointer.clientX, pointer.clientY);
|
|
38
|
+
const intent = session.intent;
|
|
39
|
+
if (intent.kind === 'node') {
|
|
40
|
+
const definition = NODE_DEFINITIONS[intent.nodeType];
|
|
41
|
+
const centered = definition ? { x: point.x - definition.width / 2, y: point.y - definition.height / 2 } : point;
|
|
42
|
+
return this.studio.commands.createNode({ nodeType: intent.nodeType, point: centered, preset: intent.preset });
|
|
43
|
+
}
|
|
44
|
+
if (intent.kind === 'template') {
|
|
45
|
+
const template = this.templates.resolve(intent.templateId);
|
|
46
|
+
if (!template) throw new Error(`Unknown template: ${intent.templateId}`);
|
|
47
|
+
return this.studio.commands.createTemplate(template.create({ studio: this.studio, point, intent }), point);
|
|
48
|
+
}
|
|
49
|
+
return intent.run?.({ studio: this.studio, point }) || null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function createTemplateRegistry(templates) { return new TemplateRegistry(templates); }
|
|
54
|
+
export function createInteractionController(options) { return new InteractionController(options); }
|