@knotx/core 0.4.11 → 0.4.13

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/README.en.md ADDED
@@ -0,0 +1,738 @@
1
+ # @knotx/core
2
+
3
+ **English** | [中文](./README.md)
4
+
5
+ ---
6
+
7
+ ## 📦 Installation
8
+
9
+ ```bash
10
+ npm install @knotx/core
11
+ ```
12
+
13
+ ```bash
14
+ yarn add @knotx/core
15
+ ```
16
+
17
+ ```bash
18
+ pnpm add @knotx/core
19
+ ```
20
+
21
+ ## 📖 Overview
22
+
23
+ `@knotx/core` is the core package of the Knotx graph editor, providing the fundamental infrastructure needed to build visual graph editors. It includes engine management, plugin system, interaction management, element operations, layer rendering, and other core functionalities, offering developers powerful and flexible graph editing capabilities.
24
+
25
+ ## 🚀 Quick Start
26
+
27
+ ```typescript
28
+ import { Engine } from '@knotx/core'
29
+
30
+ // Create engine instance
31
+ const engine = new Engine({
32
+ container: { width: 800, height: 600, direction: 'horizontal' },
33
+ nodes: [
34
+ { id: '1', position: { x: 100, y: 100 }, data: { label: 'Node 1' } },
35
+ { id: '2', position: { x: 300, y: 200 }, data: { label: 'Node 2' } }
36
+ ],
37
+ edges: [
38
+ { id: 'e1', source: '1', target: '2', data: {} }
39
+ ]
40
+ })
41
+
42
+ // Get nodes
43
+ const nodes = engine.getNodes()
44
+ console.log(nodes)
45
+ ```
46
+
47
+ ## 📚 Complete API Documentation
48
+
49
+ ### 🔧 Core Classes
50
+
51
+ #### Engine Class
52
+
53
+ The Engine is the core of Knotx, responsible for managing the entire graph editor's state and behavior.
54
+
55
+ ```typescript
56
+ // Engine class type definition
57
+ interface Engine<TRenderType extends RenderType = RenderType, TNode extends IRecord = IRecord, TEdge extends IRecord = IRecord> {
58
+ // Engine methods and properties
59
+ }
60
+ ```
61
+
62
+ **Properties:**
63
+ - `runtime: IEngineRuntime` - Runtime configuration
64
+ - `interaction: InteractionManager` - Interaction manager
65
+ - `nodesManager: DataManager<Node<TNode>>` - Node data manager
66
+ - `edgesManager: DataManager<Edge<TEdge>>` - Edge data manager
67
+ - `container: Container` - Container configuration
68
+ - `nodes: Node<TNode>[]` - Node array
69
+ - `edges: Edge<TEdge>[]` - Edge array
70
+ - `layers: Map<number, LayerComponent<TRenderType>[]>` - Layer component mapping
71
+ - `plugins: IPlugin[]` - Plugin array
72
+
73
+ **Methods:**
74
+ - `getNodes(): Node<TNode>[]` - Get all nodes
75
+ - `getEdges(): Edge<TEdge>[]` - Get all edges
76
+ - `getNode({ id }): Node<TNode> | undefined` - Get node by ID
77
+ - `getEdge({ id }): Edge<TEdge> | undefined` - Get edge by ID
78
+ - `getNodeDraft({ id }): Node<TNode> | undefined` - Get node draft
79
+ - `getEdgeDraft({ id }): Edge<TEdge> | undefined` - Get edge draft
80
+ - `getPlugin<TPlugin>({ pluginName }): TPlugin | undefined` - Get plugin
81
+ - `getNodeRenderer(type: string): NodeRenderType | undefined` - Get node renderer
82
+ - `getEdgeRenderer(type: string): EdgeRender | undefined` - Get edge renderer
83
+ - `getLayerComponents(layer: Layer): LayerComponent<TRenderType>[]` - Get layer components
84
+ - `addNodePipe(pipe: DataOperationPipe<Node<TNode>>)` - Add node operation pipe
85
+ - `addEdgePipe(pipe: DataOperationPipe<Edge<TEdge>>)` - Add edge operation pipe
86
+ - `dispatchNodeOperation(operation: DataOperation<Node<TNode>>)` - Dispatch node operation
87
+ - `dispatchEdgeOperation(operation: DataOperation<Edge<TEdge>>)` - Dispatch edge operation
88
+ - `registerNodeRenderer(type: string, renderer: NodeRenderType): () => void` - Register node renderer
89
+ - `registerEdgeRenderer(type: string, renderer: EdgeRenderType, config: Required<EdgeConfig>): () => void` - Register edge renderer
90
+ - `registerPluginData<T, TP>(pluginName: T, property: TP, data: BehaviorSubject<PluginData[T][TP]>): void` - Register plugin data
91
+ - `subscribePluginData<T, TP>(pluginName: T, property: TP, observer: (value: PluginData[T][TP]) => void): Subscription | null` - Subscribe to plugin data
92
+ - `registerPluginTool<T, TP>(pluginName: T, property: TP, data: { description: string; parameters: Schema; func: PluginTools[T][TP] }): void` - Register plugin tool
93
+ - `resetPluginData<T>(pluginName: T): void` - Reset plugin data
94
+ - `resetPluginTool<T>(pluginName: T): void` - Reset plugin tool
95
+ - `changePluginConfig({ pluginName, config }): void` - Change plugin configuration
96
+ - `callTool: CallToolMethod` - Call tool method
97
+ - `listPlugins(): IPluginInfo[]` - List all plugins
98
+ - `listPluginTools({ pluginName }): IToolInfo[]` - List plugin tools
99
+ - `listEngineTools(): IToolInfo[]` - List engine tools
100
+ - `destroy()` - Destroy engine
101
+
102
+ #### BasePlugin Class
103
+
104
+ Base class for plugins, providing fundamental functionality for plugin development.
105
+
106
+ ```typescript
107
+ // BasePlugin abstract class type definition
108
+ abstract class BasePlugin<TPluginName extends string = string, TPluginConfig extends IRecord | undefined = undefined, TRenderType extends RenderType = RenderType> {
109
+ // Plugin abstract methods and properties
110
+ }
111
+ ```
112
+
113
+ **Properties:**
114
+ - `abstract name: TPluginName` - Plugin name
115
+ - `pluginId: string` - Plugin unique ID
116
+ - `protected subscriptions: (SubscriptionLike | (() => void))[]` - Subscription collection
117
+ - `protected callTool: Engine['callTool']` - Call tool method
118
+
119
+ **Methods:**
120
+ - `onInit?(config: TPluginConfig): void` - Initialization callback
121
+ - `onConfigChange?(config: TPluginConfig): void` - Configuration change callback
122
+ - `onDestroy?(): void` - Destroy callback
123
+
124
+ #### InteractionManager Class
125
+
126
+ Interaction manager responsible for managing user interaction priorities and states.
127
+
128
+ ```typescript
129
+ // InteractionManager class type definition
130
+ class InteractionManager {
131
+ // Interaction manager methods and properties
132
+ }
133
+ ```
134
+
135
+ **Properties:**
136
+ - `active: Interaction | undefined` - Current active interaction
137
+
138
+ **Methods:**
139
+ - `canInteract(priority: InteractionPriority): boolean` - Check if can interact
140
+ - `start(pluginId: string, type: string, priority: InteractionPriority): () => void` - Start interaction
141
+ - `end(pluginId: string, type: string): void` - End interaction
142
+
143
+ #### Runtime Class
144
+
145
+ Runtime manager handling context execution and value processing.
146
+
147
+ ```typescript
148
+ // Runtime class type definition
149
+ class Runtime {
150
+ // Runtime methods and properties
151
+ }
152
+ ```
153
+
154
+ **Properties:**
155
+ - `currentContext: { type: any; value: any } | undefined` - Current context
156
+
157
+ **Methods:**
158
+ - `runInContext<T>(type: any, handler: () => T, contextValue?: any): T` - Run in context
159
+ - `getValue<T>(engine: Engine<any>, options: { paths: any[]; matcher?: (engine: Engine<any>) => BehaviorSubject<any>; selector?: (value: T, context?: any) => any }): any` - Get value
160
+ - `static getInstance(): Runtime` - Get singleton instance
161
+ - `static DEFAULT_VALUE_HANDLER: <T>(value: BehaviorSubject<T> | T, options: { paths: string[]; selector?: (value: T, context?: any) => any; context?: any }) => T` - Default value handler
162
+
163
+ #### DataManager Class
164
+
165
+ Data manager for managing CRUD operations and version control.
166
+
167
+ ```typescript
168
+ // DataManager class type definition
169
+ class DataManager<TData extends IData = IData, TTag extends string = any> {
170
+ // Data manager methods and properties
171
+ }
172
+ ```
173
+
174
+ **Properties:**
175
+ - `readonly tag: TTag` - Tag
176
+ - `readonly dataMap$: BehaviorSubject<Map<string, TData>>` - Data mapping
177
+ - `readonly patchVersion$: BehaviorSubject<number>` - Patch version
178
+ - `readonly mapVersion$: BehaviorSubject<number>` - Map version
179
+ - `version: number` - Version number
180
+
181
+ **Methods:**
182
+ - `init(initialDataList: TData[]): void` - Initialize
183
+ - `getDataList$(): Observable<TData[]>` - Get data list stream
184
+ - `getDataList(): TData[]` - Get data list
185
+ - `getData(id: string): TData | undefined` - Get data
186
+ - `getOperations$(): Observable<DataOperation<TData>>` - Get operations stream
187
+ - `dispatch(operation: DataOperation<TData>): void` - Dispatch operation
188
+ - `getDraftDataList(draftId: string): TData[] | undefined` - Get draft data list
189
+
190
+ #### DualRelation Class
191
+
192
+ Dual relation manager for managing parent-child relationships.
193
+
194
+ ```typescript
195
+ // DualRelation class type definition
196
+ class DualRelation<P, C> {
197
+ // Dual relation manager methods and properties
198
+ }
199
+ ```
200
+
201
+ **Properties:**
202
+ - `version: BehaviorSubject<number>` - Version number
203
+
204
+ **Methods:**
205
+ - `addRelation(parent: P, child: C): void` - Add relation
206
+ - `removeRelation(parent: P, child: C): void` - Remove relation
207
+ - `getChildren(parent: P): C[]` - Get children
208
+ - `getParent(child: C): P | undefined` - Get parent
209
+ - `clear(): void` - Clear relations
210
+
211
+ #### Element Interface and DOMElement Class
212
+
213
+ Element abstraction providing cross-platform element operation interfaces.
214
+
215
+ ```typescript
216
+ interface Element {
217
+ classList: ElementClassList
218
+ attribute: ElementAttribute
219
+ uniqSelector: string | undefined
220
+ getRect: () => ElementRect
221
+ addEventListener: EventListenerDefinition
222
+ removeEventListener: EventListenerDefinition
223
+ query: (selector: string) => Element | null
224
+ queryAll: (selector: string) => Element[]
225
+ }
226
+
227
+ class DOMElement implements Element {
228
+ constructor(readonly dom: HTMLElement) {}
229
+ static fromDOM(dom: HTMLElement): DOMElement
230
+ }
231
+ ```
232
+
233
+ ### 🎭 Type Definitions
234
+
235
+ #### Basic Types
236
+ ```typescript
237
+ type HorizontalAlignment = 'left' | 'right'
238
+ type VerticalAlignment = 'top' | 'bottom'
239
+ type Direction = 'horizontal' | 'vertical'
240
+ type IRecord = Record<string, any>
241
+ type Position = VerticalAlignment | HorizontalAlignment | `${HorizontalAlignment}-${VerticalAlignment}` | 'center'
242
+ type RenderType = (...args: any[]) => any
243
+ ```
244
+
245
+ #### Node Related Types
246
+ ```typescript
247
+ interface NodePosition {
248
+ x: number
249
+ y: number
250
+ }
251
+
252
+ interface NodeMeasured {
253
+ width: number
254
+ height: number
255
+ }
256
+
257
+ interface Node<TData extends IRecord = IRecord> {
258
+ id: string
259
+ type?: string
260
+ position: NodePosition
261
+ measured?: NodeMeasured
262
+ data: TData
263
+ }
264
+
265
+ interface NodeProps<TData extends IRecord = IRecord> {
266
+ node: Node<TData>
267
+ renderVersion?: number
268
+ }
269
+
270
+ type NodeRenderType<TD extends IRecord = any, TR = any> = (props: NodeProps<TD>) => TR
271
+ type NodeOperation<T extends IRecord = any> = DataOperation<Node<T>>
272
+ type NodeOperationPipe<T extends IRecord = any> = DataOperationPipe<Node<T>>
273
+ type NodeOperatorFunction<T extends IRecord = any, TArgs extends any[] = any[]> = (...args: TArgs) => NodeOperation<T>[]
274
+ ```
275
+
276
+ #### Edge Related Types
277
+ ```typescript
278
+ interface EdgeConfig {
279
+ sourcePosition?: Position
280
+ targetPosition?: Position
281
+ sourceYOffset?: string | number
282
+ sourceXOffset?: string | number
283
+ targetYOffset?: string | number
284
+ targetXOffset?: string | number
285
+ }
286
+
287
+ interface Edge<TData extends IRecord = IRecord> extends EdgeConfig {
288
+ id: string
289
+ source: string
290
+ target: string
291
+ type?: string
292
+ data?: TData
293
+ }
294
+
295
+ interface EdgeProps<TData extends IRecord = IRecord> {
296
+ edge: Edge<TData>
297
+ sourceX: number
298
+ sourceY: number
299
+ targetX: number
300
+ targetY: number
301
+ renderVersion?: number
302
+ }
303
+
304
+ type EdgeRenderType<TD extends IRecord = any, TR = any> = (props: EdgeProps<TD>) => TR
305
+
306
+ interface EdgeRender<TD extends IRecord = any, TR = any> {
307
+ renderer: EdgeRenderType<TD, TR>
308
+ config: Required<EdgeConfig>
309
+ }
310
+
311
+ type EdgeOperation<T extends IRecord = any> = DataOperation<Edge<T>>
312
+ type EdgeOperationPipe<T extends IRecord = any> = DataOperationPipe<Edge<T>>
313
+ type EdgeOperatorFunction<T extends IRecord = any, TArgs extends any[] = any[]> = (...args: TArgs) => EdgeOperation<T>[]
314
+ ```
315
+
316
+ #### Container Types
317
+ ```typescript
318
+ interface Container {
319
+ width: number
320
+ height: number
321
+ direction: Direction
322
+ }
323
+ ```
324
+
325
+ #### Layer Types
326
+ ```typescript
327
+ enum Layer {
328
+ Canvas = 0,
329
+ Background = 4,
330
+ Edges = 16,
331
+ Nodes = 64,
332
+ Foreground = 256,
333
+ }
334
+
335
+ interface LayerComponent<TRenderType> {
336
+ plugin: string
337
+ name: string
338
+ layer: Layer
339
+ render: TRenderType
340
+ offset?: number
341
+ }
342
+ ```
343
+
344
+ #### Plugin Types
345
+ ```typescript
346
+ interface IPlugin<TPluginName extends string = string, TPluginConfig extends IRecord | undefined = any> {
347
+ name: TPluginName
348
+ pluginId: string
349
+ description?: string
350
+ onInit?: (config: TPluginConfig) => void
351
+ onConfigChange?: (config: TPluginConfig) => void
352
+ onDestroy?: () => void
353
+ }
354
+
355
+ type Plugin<TName extends string = string, TConfig extends IRecord | undefined = any, TRenderType extends RenderType = RenderType> = new (__: TConfig) => BasePlugin<TName, TConfig, TRenderType>
356
+
357
+ interface PluginData {} // Module augmentation interface
358
+ interface PluginTools {} // Module augmentation interface
359
+ interface EngineTools {} // Module augmentation interface
360
+
361
+ interface IPluginInfo {
362
+ name: string
363
+ description?: string
364
+ }
365
+
366
+ interface IToolInfo {
367
+ type: 'function'
368
+ name: string
369
+ description: string
370
+ parameters: Schema
371
+ }
372
+ ```
373
+
374
+ #### Data Operation Types
375
+ ```typescript
376
+ interface IData {
377
+ id: string
378
+ }
379
+
380
+ interface DataAddOperation<T extends IData = IData> {
381
+ type: 'add'
382
+ data: T
383
+ }
384
+
385
+ interface DataRemoveOperation<_T extends IData = IData> {
386
+ type: 'remove'
387
+ id: string
388
+ }
389
+
390
+ interface DataUpdateOperation<T extends IData = IData> {
391
+ type: 'update'
392
+ id: string
393
+ data: T
394
+ }
395
+
396
+ interface DataBatchOperation<T extends IData = IData> {
397
+ type: 'batch'
398
+ operations: DataOperation<T>[]
399
+ isInit?: boolean
400
+ }
401
+
402
+ interface DataStartDraftOperation<T extends IData = IData> {
403
+ type: 'startDraft'
404
+ draftId: string
405
+ data: T
406
+ }
407
+
408
+ interface DataCommitDraftOperation<T extends IData = IData> {
409
+ type: 'commitDraft'
410
+ draftId: string
411
+ data: T
412
+ }
413
+
414
+ interface DataDiscardDraftOperation<T extends IData = IData> {
415
+ type: 'discardDraft'
416
+ draftId: string
417
+ }
418
+
419
+ interface DataDraftOperation<T extends IData = IData> {
420
+ type: 'draft'
421
+ draftId: string
422
+ operation: DataOperation<T>
423
+ }
424
+
425
+ type DataOperation<T extends IData = IData> = DataAddOperation<T> | DataRemoveOperation<T> | DataUpdateOperation<T> | DataBatchOperation<T> | DataStartDraftOperation<T> | DataCommitDraftOperation<T> | DataDiscardDraftOperation<T> | DataDraftOperation<T>
426
+
427
+ interface DataOperationPipe<T extends IData = IData> {
428
+ transform?: (operations$: Subject<DataOperation<T>>) => OperatorFunction<DataOperation<T>, DataOperation<T>>
429
+ preOperation?: (operations$: Subject<DataOperation<T>>) => OperatorFunction<DataOperation<T>, DataOperation<T>>
430
+ postOperation?: (operations$: Subject<DataOperation<T>>) => OperatorFunction<{ dataMap: Map<string, T>, operations: DataOperation<T>[] }, { dataMap: Map<string, T>, operations: DataOperation<T>[] }>
431
+ }
432
+ ```
433
+
434
+ #### Interaction Types
435
+ ```typescript
436
+ enum InteractionPriority {
437
+ InputActive = 2000,
438
+ EntityConnectDrag = 1930,
439
+ EntityMeasureDrag = 1920,
440
+ EntityPositionDrag = 1910,
441
+ ContinuousDrag = 1900,
442
+ ContextMenu = 1800,
443
+ KeyboardShortcut = 1700,
444
+ ClickSelection = 1600,
445
+ DoubleClickEdit = 1500,
446
+ MarqueeSelection = 1300,
447
+ LassoSelection = 1250,
448
+ LongPress = 1100,
449
+ HoverTooltip = 1000,
450
+ CanvasPan = 900,
451
+ CanvasZoom = 800,
452
+ CanvasContextMenu = 700,
453
+ CanvasClick = 600,
454
+ MultiTouchGesture = 500,
455
+ }
456
+
457
+ interface Interaction {
458
+ pluginId: string
459
+ type: string
460
+ priority: InteractionPriority
461
+ active?: boolean
462
+ }
463
+ ```
464
+
465
+ #### Element Types
466
+ ```typescript
467
+ interface ElementClassList {
468
+ toString: () => string
469
+ add: (...tokens: string[]) => void
470
+ contains: (token: string) => boolean
471
+ remove: (...tokens: string[]) => void
472
+ }
473
+
474
+ interface ElementAttribute {
475
+ get: (name: string) => string | null
476
+ set: (name: string, value: string) => void
477
+ remove: (name: string) => void
478
+ }
479
+
480
+ interface ElementRect {
481
+ height: number
482
+ width: number
483
+ x: number
484
+ y: number
485
+ }
486
+
487
+ interface EventListenerDefinition<E = any> {
488
+ (type: string, listener: ((evt: E) => void) | EventListenerObject<E>, options?: boolean | AddEventListenerOptions): void
489
+ }
490
+ ```
491
+
492
+ #### Engine Types
493
+ ```typescript
494
+ interface EngineOptions<TNode extends IRecord = IRecord, TEdge extends IRecord = IRecord> {
495
+ container: Container
496
+ plugins?: Plugin[]
497
+ pluginConfig?: IRecord
498
+ nodes?: Node<TNode>[]
499
+ edges?: Edge<TEdge>[]
500
+ runtime?: IEngineRuntime
501
+ }
502
+
503
+ interface IEngineRuntime {
504
+ render?: {
505
+ getValue: <T, R = T>(value: BehaviorSubject<T> | T, options: {
506
+ paths: string[]
507
+ selector?: (value: T, context?: any) => R
508
+ context?: any
509
+ }) => T | R
510
+ }
511
+ }
512
+
513
+ interface CallToolMethod {
514
+ <T extends keyof PluginTools, TP extends keyof PluginTools[T]>(pluginName: Extract<T, keyof PluginTools>, toolName: Extract<TP, keyof PluginTools[T]>, ...args: Parameters<PluginTools[T][TP]>): ReturnType<PluginTools[T][TP]>
515
+ <T extends keyof EngineTools>(engineToolName: Extract<T, keyof EngineTools>, ...args: Parameters<EngineTools[T]>): ReturnType<EngineTools[T]>
516
+ }
517
+ ```
518
+
519
+ ### 🛠️ Utility Functions
520
+
521
+ #### Hook Functions
522
+ ```typescript
523
+ function use<T>(hook: () => T): T
524
+ function use<T, TContext>(hook: () => { __contextRef__: T, __contextValue__: TContext }, context: TContext): T
525
+ ```
526
+
527
+ #### Layer Functions
528
+ ```typescript
529
+ function getLayerRenders<TRenderType extends RenderType = RenderType>(plugin: IPlugin): LayerComponent<TRenderType>[]
530
+ ```
531
+
532
+ #### Utility Functions (from @knotx/utils)
533
+ ```typescript
534
+ // BEM class name utilities
535
+ function bem(block: string, element?: string, modifier?: string, prefix?: string): string
536
+ function addBemModifier(className: string, modifier: string): string
537
+
538
+ // Unique ID generation
539
+ function generateId(): string
540
+
541
+ // Symbol utilities
542
+ function getSymbol<TName extends string>(name: TName): symbol & { __knotx__?: TName }
543
+
544
+ // Data operation utilities
545
+ function isInitOperation<T extends IData>(operation: DataOperation<T>): operation is DataInitBatchOperation<T>
546
+ function isDraftOperation<T extends IData>(operation: DataOperation<T>): operation is Extract<DataOperation<T>, { draftId: string }>
547
+ function isEmptyBatchOperation<T extends IData>(operation: DataOperation<T>): operation is DataEmptyBatchOperation<T>
548
+ function flattenOperations<T extends IData>(operations: DataOperation<T>[]): DataOperation<T>[]
549
+ function emptyOperation<T extends IData>(): DataEmptyBatchOperation<T>
550
+ function buildDiffOperation<T extends IData>(previousDataMap: Map<string, T>, dataMap: Map<string, T>, compare?: (a: T | undefined, b: T | undefined) => boolean): DataBatchOperation<T>
551
+ ```
552
+
553
+ ### 📘 Usage Examples
554
+
555
+ #### Basic Usage
556
+ ```typescript
557
+ import { Engine } from '@knotx/core'
558
+
559
+ // Create engine
560
+ const engine = new Engine({
561
+ container: { width: 800, height: 600, direction: 'horizontal' },
562
+ nodes: [
563
+ { id: '1', position: { x: 100, y: 100 }, data: { label: 'Node 1' } }
564
+ ],
565
+ edges: []
566
+ })
567
+
568
+ // Get data
569
+ const nodes = engine.getNodes()
570
+ const node = engine.getNode({ id: '1' })
571
+ ```
572
+
573
+ #### Plugin Development
574
+ ```typescript
575
+ import { BasePlugin, Layer } from '@knotx/core'
576
+
577
+ class MyPlugin extends BasePlugin<'my-plugin', { theme: string }> {
578
+ name = 'my-plugin' as const
579
+
580
+ onInit(config: { theme: string }) {
581
+ // Plugin initialization logic
582
+ }
583
+ }
584
+ ```
585
+
586
+ #### Data Operations
587
+ ```typescript
588
+ import { DataManager } from '@knotx/core'
589
+
590
+ const dataManager = new DataManager<Node>('nodes')
591
+ dataManager.init([
592
+ { id: '1', position: { x: 0, y: 0 }, data: {} }
593
+ ])
594
+
595
+ // Add data
596
+ dataManager.dispatch({
597
+ type: 'add',
598
+ data: { id: '2', position: { x: 100, y: 100 }, data: {} }
599
+ })
600
+ ```
601
+
602
+ #### Interaction Management
603
+ ```typescript
604
+ import { InteractionManager, InteractionPriority } from '@knotx/core'
605
+
606
+ const interaction = new InteractionManager()
607
+ const cancel = interaction.start('plugin-id', 'drag', InteractionPriority.EntityPositionDrag)
608
+
609
+ // Check if can interact
610
+ if (interaction.canInteract(InteractionPriority.ClickSelection)) {
611
+ // Execute interaction logic
612
+ }
613
+
614
+ // Cancel interaction
615
+ cancel()
616
+ ```
617
+
618
+ ## 🗂️ File Directory Structure
619
+
620
+ ```
621
+ packages/core/
622
+ ├── src/
623
+ │ ├── index.ts # Main export file
624
+ │ ├── definition.ts # Type definitions and interfaces
625
+ │ ├── engine.ts # Core engine implementation
626
+ │ ├── element.ts # Element abstraction layer
627
+ │ ├── plugin.ts # Plugin base class
628
+ │ ├── interaction.ts # Interaction manager
629
+ │ ├── runtime.ts # Runtime management
630
+ │ ├── layer.tsx # Layer rendering
631
+ │ ├── use.ts # Hook functions
632
+ │ ├── data.ts # Data management (re-export)
633
+ │ └── utils.ts # Utility functions (re-export)
634
+ ├── dist/ # Build output directory
635
+ ├── package.json # Package configuration
636
+ ├── tsconfig.json # TypeScript configuration
637
+ ├── build.config.ts # Build configuration
638
+ └── README.md # Project documentation
639
+ ```
640
+
641
+ ## 🔧 Advanced Usage
642
+
643
+ ### Custom Plugin Development
644
+
645
+ ```typescript
646
+ import type { LayerComponent } from '@knotx/core'
647
+
648
+ import { BasePlugin, Layer } from '@knotx/core'
649
+
650
+ class CustomPlugin extends BasePlugin<'custom', { theme: string }> {
651
+ name = 'custom' as const
652
+
653
+ // Declare plugin data
654
+ declare pluginData: {
655
+ selectedNodes: string[]
656
+ highlightColor: string
657
+ }
658
+
659
+ // Declare plugin tools
660
+ declare pluginTools: {
661
+ selectNode: (nodeId: string) => void
662
+ clearSelection: () => void
663
+ }
664
+
665
+ onInit(config: { theme: string }) {
666
+ // Register plugin data
667
+ this.engine.registerPluginData('custom', 'selectedNodes', new BehaviorSubject([]))
668
+ this.engine.registerPluginData('custom', 'highlightColor', new BehaviorSubject('#blue'))
669
+
670
+ // Register plugin tools
671
+ this.engine.registerPluginTool('custom', 'selectNode', {
672
+ description: 'Select node',
673
+ parameters: { type: 'string' },
674
+ func: (nodeId: string) => {
675
+ // Implement selection logic
676
+ console.log('Selecting node:', nodeId)
677
+ }
678
+ })
679
+
680
+ // Register layer component
681
+ this.engine.registerLayerComponent({
682
+ plugin: this.name,
683
+ name: 'selection-layer',
684
+ layer: Layer.Foreground,
685
+ render: this.renderSelection.bind(this)
686
+ })
687
+ }
688
+
689
+ renderSelection() {
690
+ return '<div class="selection-overlay">Selection Layer</div>'
691
+ }
692
+ }
693
+ ```
694
+
695
+ ### Data Operation Pipes
696
+
697
+ ```typescript
698
+ import type { EdgeOperation, NodeOperation } from '@knotx/core'
699
+
700
+ // Node operation pipe
701
+ engine.addNodePipe((operations: NodeOperation[]) => {
702
+ return operations.map((op) => {
703
+ if (op.type === 'update') {
704
+ // Validate data before update
705
+ if (!validateNodeData(op.data)) {
706
+ throw new Error('Invalid node data')
707
+ }
708
+ }
709
+ return op
710
+ })
711
+ })
712
+
713
+ // Edge operation pipe
714
+ engine.addEdgePipe((operations: EdgeOperation[]) => {
715
+ return operations.filter((op) => {
716
+ // Filter invalid edge operations
717
+ return op.source !== op.target
718
+ })
719
+ })
720
+ ```
721
+
722
+ ---
723
+
724
+ ## 📄 License
725
+
726
+ This project is licensed under the [MIT License](../../LICENSE).
727
+
728
+ ---
729
+
730
+ ## 🔗 Related Links
731
+
732
+ - [Homepage](https://github.com/boenfu/knotx)
733
+ - [Issues](https://github.com/boenfu/knotx/issues)
734
+ - [Contributing Guide](../../CONTRIBUTING.md)
735
+
736
+ ---
737
+
738
+ Made with ❤️ by the Knotx team