@knotx/plugins-selection 0.4.12 → 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.
Files changed (3) hide show
  1. package/README.en.md +344 -0
  2. package/README.md +344 -0
  3. package/package.json +8 -8
package/README.en.md ADDED
@@ -0,0 +1,344 @@
1
+ # @knotx/plugins-selection
2
+
3
+ Selection plugin that provides element selection functionality for KnotX.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @knotx/plugins-selection
9
+ ```
10
+
11
+ ## Overview
12
+
13
+ The Selection plugin provides powerful element selection functionality for KnotX, supporting mouse selection, keyboard operations, and programmatic selection. This plugin is built on the `@knotx/viselect` library and offers flexible selection rules and rich selection events.
14
+
15
+ ## Implementation Principle
16
+
17
+ The core implementation principles of the Selection plugin:
18
+
19
+ 1. **Selection Area Management**: Uses the `@knotx/viselect` library to create selection areas with drag selection support
20
+ 2. **Rule System**: Defines selection behavior for different element types through a rule system
21
+ 3. **Event Handling**: Provides complete selection event lifecycle management
22
+ 4. **State Synchronization**: Synchronizes with canvas transform state to ensure selection area accuracy
23
+
24
+ ## Dependencies
25
+
26
+ ### Core Dependencies
27
+ - `@knotx/core`: Provides base plugin architecture
28
+ - `@knotx/decorators`: Provides decorator support
29
+ - `@knotx/viselect`: Provides selection area functionality
30
+
31
+ ### Plugin Dependencies
32
+ - `@knotx/plugins-canvas`: Retrieves canvas transform state and container information (optional)
33
+
34
+ ## API Documentation
35
+
36
+ ### Main Classes
37
+
38
+ #### Selection
39
+
40
+ The main class of the Selection plugin, extending `BasePlugin`.
41
+
42
+ ```typescript
43
+ export class Selection extends BasePlugin<'selection', SelectionConfig> {
44
+ name = 'selection' as const
45
+ }
46
+ ```
47
+
48
+ ### Configuration Options
49
+
50
+ #### SelectionConfig
51
+
52
+ ```typescript
53
+ export interface SelectionConfig {
54
+ /** Selection area class name */
55
+ selectionAreaClassName?: string
56
+ /** Enable drag selection */
57
+ enableDrag?: boolean
58
+ /** Selection rules */
59
+ rules?: SelectionRule[]
60
+ /** Disable default rules */
61
+ disableDefaultRules?: boolean
62
+ /** Selection container */
63
+ container?: string
64
+ }
65
+ ```
66
+
67
+ #### SelectionRule
68
+
69
+ ```typescript
70
+ export interface SelectionRule {
71
+ /** Resource type */
72
+ type: string
73
+ /** Element class name */
74
+ className: string
75
+ /** ID getter function */
76
+ idGetter: (element: Element) => string
77
+ /** Active state class name */
78
+ activeClassName?: string
79
+ /** Selection callback */
80
+ onSelected?: (context: SelectionContext) => boolean
81
+ /** Data selector type */
82
+ dataSelectorType?: string
83
+ /** Enable rule */
84
+ enabled?: boolean
85
+ }
86
+ ```
87
+
88
+ ### Plugin Data (PluginData)
89
+
90
+ The Selection plugin provides the following data:
91
+
92
+ ```typescript
93
+ interface PluginData {
94
+ selection: {
95
+ selected: SelectionSelectedItem[]
96
+ registerRules: (rules: SelectionRule[]) => () => void
97
+ setRuleEnabled: (type: string, enabled: boolean) => void
98
+ setClearSelectionBeforeStart: (isClearSelectionBeforeStart: boolean) => void
99
+ setElementOverlap: (overlap: OverlapMode) => void
100
+ resolveSelectables: () => void
101
+ }
102
+ }
103
+ ```
104
+
105
+ ### Plugin Tools (PluginTools)
106
+
107
+ The Selection plugin provides the following tool methods:
108
+
109
+ ```typescript
110
+ interface PluginTools {
111
+ selection: {
112
+ select: (items: SelectionSelectedItem[]) => void
113
+ deselect: (items: SelectionSelectedItem[]) => void
114
+ getSelected: () => SelectionSelectedItem[]
115
+ clearSelection: () => void
116
+ }
117
+ }
118
+ ```
119
+
120
+ ### Type Definitions
121
+
122
+ #### SelectionSelectedItem
123
+
124
+ ```typescript
125
+ export interface SelectionSelectedItem {
126
+ type: string
127
+ id: string
128
+ }
129
+ ```
130
+
131
+ ## Usage Examples
132
+
133
+ ### Basic Usage
134
+
135
+ ```typescript
136
+ import { Selection } from '@knotx/plugins-selection'
137
+
138
+ const engine = new Engine({
139
+ plugins: [Selection],
140
+ pluginConfig: {
141
+ selection: {
142
+ enableDrag: true,
143
+ },
144
+ },
145
+ })
146
+ ```
147
+
148
+ ### Custom Selection Rules
149
+
150
+ ```typescript
151
+ const engine = new Engine({
152
+ plugins: [Selection],
153
+ pluginConfig: {
154
+ selection: {
155
+ rules: [
156
+ {
157
+ type: 'custom-node',
158
+ className: 'custom-node-wrapper',
159
+ idGetter: element => element.getAttribute('data-node-id') || '',
160
+ activeClassName: 'custom-node-selected',
161
+ onSelected: (context) => {
162
+ console.log('Custom node selected:', context.id)
163
+ return true // Return true to allow selection
164
+ },
165
+ },
166
+ ],
167
+ },
168
+ },
169
+ })
170
+ ```
171
+
172
+ ### Programmatic Selection
173
+
174
+ ```typescript
175
+ // Select specific elements
176
+ engine.callTool('selection', 'select', [
177
+ { type: 'node', id: 'node-1' },
178
+ { type: 'node', id: 'node-2' },
179
+ ])
180
+
181
+ // Deselect specific elements
182
+ engine.callTool('selection', 'deselect', [
183
+ { type: 'node', id: 'node-1' },
184
+ ])
185
+
186
+ // Get currently selected elements
187
+ const selected = engine.callTool('selection', 'getSelected')
188
+ console.log('Selected items:', selected)
189
+
190
+ // Clear all selections
191
+ engine.callTool('selection', 'clearSelection')
192
+ ```
193
+
194
+ ### Dynamic Rule Management
195
+
196
+ ```typescript
197
+ // Get plugin data
198
+ const selectionData = engine.getPluginData('selection')
199
+
200
+ // Register new rules
201
+ const unregister = selectionData.registerRules([
202
+ {
203
+ type: 'edge',
204
+ className: 'edge-wrapper',
205
+ idGetter: element => element.getAttribute('data-edge-id') || '',
206
+ activeClassName: 'edge-selected',
207
+ },
208
+ ])
209
+
210
+ // Enable/disable rules
211
+ selectionData.setRuleEnabled('edge', false)
212
+
213
+ // Set overlap mode
214
+ selectionData.setElementOverlap('invert') // 'keep' | 'drop' | 'invert'
215
+
216
+ // Unregister rules
217
+ unregister()
218
+ ```
219
+
220
+ ### Listen to Selection Changes
221
+
222
+ ```typescript
223
+ class MyPlugin extends BasePlugin {
224
+ @inject.selection.selected()
225
+ selected!: SelectionSelectedItem[]
226
+
227
+ @subscribe.selection.selected()
228
+ onSelectedChange(selected: SelectionSelectedItem[]) {
229
+ console.log('Selection changed:', selected)
230
+ }
231
+ }
232
+ ```
233
+
234
+ ### Integration with Canvas Plugin
235
+
236
+ ```typescript
237
+ import { Canvas } from '@knotx/plugins-canvas'
238
+ import { Selection } from '@knotx/plugins-selection'
239
+
240
+ const engine = new Engine({
241
+ plugins: [Canvas, Selection],
242
+ pluginConfig: {
243
+ canvas: {
244
+ minScale: 0.1,
245
+ maxScale: 3,
246
+ },
247
+ selection: {
248
+ enableDrag: true,
249
+ container: '.canvas-container', // Specify selection container
250
+ },
251
+ },
252
+ })
253
+ ```
254
+
255
+ ## Advanced Features
256
+
257
+ ### Custom Selection Behavior
258
+
259
+ ```typescript
260
+ const engine = new Engine({
261
+ plugins: [Selection],
262
+ pluginConfig: {
263
+ selection: {
264
+ rules: [
265
+ {
266
+ type: 'node',
267
+ className: 'node-wrapper',
268
+ idGetter: element => element.getAttribute('data-node-id') || '',
269
+ onSelected: (context) => {
270
+ const { element, type, id, isDragging, getSelectedElements, select, deselect } = context
271
+
272
+ // Custom selection logic
273
+ if (isDragging) {
274
+ // Logic for drag selection
275
+ return true
276
+ }
277
+
278
+ // Logic for click selection
279
+ const selectedElements = getSelectedElements()
280
+ if (selectedElements.node && selectedElements.node.length > 0) {
281
+ // Already have selections, execute multi-select logic
282
+ return true
283
+ }
284
+
285
+ return true
286
+ },
287
+ },
288
+ ],
289
+ },
290
+ },
291
+ })
292
+ ```
293
+
294
+ ### Custom Selection Area Styling
295
+
296
+ ```typescript
297
+ const engine = new Engine({
298
+ plugins: [Selection],
299
+ pluginConfig: {
300
+ selection: {
301
+ selectionAreaClassName: 'custom-selection-area',
302
+ },
303
+ },
304
+ })
305
+ ```
306
+
307
+ ```css
308
+ .custom-selection-area {
309
+ background: rgba(74, 144, 226, 0.1);
310
+ border: 2px dashed #4A90E2;
311
+ border-radius: 4px;
312
+ }
313
+ ```
314
+
315
+ ## File Directory Structure
316
+
317
+ ```
318
+ packages/plugins-selection/
319
+ ├── src/
320
+ │ ├── selection.tsx # Main implementation file
321
+ │ └── index.ts # Export file
322
+ ├── dist/ # Build output directory
323
+ ├── package.json # Package configuration
324
+ ├── build.config.ts # Build configuration
325
+ ├── tsconfig.json # TypeScript configuration
326
+ ├── eslint.config.mjs # ESLint configuration
327
+ └── CHANGELOG.md # Changelog
328
+ ```
329
+
330
+ ### Core Files Description
331
+
332
+ - **selection.tsx**: Contains the main implementation of the Selection plugin, including selection area management, rule system, and event handling
333
+ - **index.ts**: Exports the Selection class and related type definitions
334
+
335
+ ## Notes
336
+
337
+ 1. **Performance Considerations**: With large numbers of elements, selection operations may impact performance; consider virtualization or pagination
338
+ 2. **Event Conflicts**: May have event conflicts with other interaction plugins (like drag); pay attention to event priority
339
+ 3. **Memory Management**: Clean up unnecessary selection rules promptly to avoid memory leaks
340
+ 4. **Browser Compatibility**: Depends on modern browser DOM APIs; consider compatibility
341
+
342
+ ## License
343
+
344
+ MIT
package/README.md ADDED
@@ -0,0 +1,344 @@
1
+ # @knotx/plugins-selection
2
+
3
+ 选择插件,为 KnotX 提供元素选择功能。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @knotx/plugins-selection
9
+ ```
10
+
11
+ ## 概述
12
+
13
+ Selection 插件为 KnotX 提供了强大的元素选择功能,支持鼠标框选、键盘操作和程序化选择。该插件基于 `@knotx/viselect` 库实现,提供了灵活的选择规则和丰富的选择事件。
14
+
15
+ ## 实现原理
16
+
17
+ Selection 插件的核心实现原理:
18
+
19
+ 1. **选择区域管理**:使用 `@knotx/viselect` 库创建选择区域,支持拖拽选择
20
+ 2. **规则系统**:通过规则系统定义不同类型元素的选择行为
21
+ 3. **事件处理**:提供完整的选择事件生命周期管理
22
+ 4. **状态同步**:与画布变换状态同步,确保选择区域的准确性
23
+
24
+ ## 依赖关系
25
+
26
+ ### 核心依赖
27
+ - `@knotx/core`:提供基础插件架构
28
+ - `@knotx/decorators`:提供装饰器支持
29
+ - `@knotx/viselect`:提供选择区域功能
30
+
31
+ ### 插件依赖
32
+ - `@knotx/plugins-canvas`:获取画布变换状态和容器信息(可选)
33
+
34
+ ## API 文档
35
+
36
+ ### 主要类
37
+
38
+ #### Selection
39
+
40
+ 选择插件的主要类,继承自 `BasePlugin`。
41
+
42
+ ```typescript
43
+ export class Selection extends BasePlugin<'selection', SelectionConfig> {
44
+ name = 'selection' as const
45
+ }
46
+ ```
47
+
48
+ ### 配置选项
49
+
50
+ #### SelectionConfig
51
+
52
+ ```typescript
53
+ export interface SelectionConfig {
54
+ /** 选择区域的类名 */
55
+ selectionAreaClassName?: string
56
+ /** 是否启用拖拽选择 */
57
+ enableDrag?: boolean
58
+ /** 选择规则 */
59
+ rules?: SelectionRule[]
60
+ /** 是否禁用默认规则 */
61
+ disableDefaultRules?: boolean
62
+ /** 选择容器 */
63
+ container?: string
64
+ }
65
+ ```
66
+
67
+ #### SelectionRule
68
+
69
+ ```typescript
70
+ export interface SelectionRule {
71
+ /** 资源类型 */
72
+ type: string
73
+ /** 元素的类名 */
74
+ className: string
75
+ /** ID 获取函数 */
76
+ idGetter: (element: Element) => string
77
+ /** 激活状态的类名 */
78
+ activeClassName?: string
79
+ /** 选择回调函数 */
80
+ onSelected?: (context: SelectionContext) => boolean
81
+ /** 数据选择器类型 */
82
+ dataSelectorType?: string
83
+ /** 是否启用规则 */
84
+ enabled?: boolean
85
+ }
86
+ ```
87
+
88
+ ### 插件数据 (PluginData)
89
+
90
+ Selection 插件提供以下数据:
91
+
92
+ ```typescript
93
+ interface PluginData {
94
+ selection: {
95
+ selected: SelectionSelectedItem[]
96
+ registerRules: (rules: SelectionRule[]) => () => void
97
+ setRuleEnabled: (type: string, enabled: boolean) => void
98
+ setClearSelectionBeforeStart: (isClearSelectionBeforeStart: boolean) => void
99
+ setElementOverlap: (overlap: OverlapMode) => void
100
+ resolveSelectables: () => void
101
+ }
102
+ }
103
+ ```
104
+
105
+ ### 插件工具 (PluginTools)
106
+
107
+ Selection 插件提供以下工具方法:
108
+
109
+ ```typescript
110
+ interface PluginTools {
111
+ selection: {
112
+ select: (items: SelectionSelectedItem[]) => void
113
+ deselect: (items: SelectionSelectedItem[]) => void
114
+ getSelected: () => SelectionSelectedItem[]
115
+ clearSelection: () => void
116
+ }
117
+ }
118
+ ```
119
+
120
+ ### 类型定义
121
+
122
+ #### SelectionSelectedItem
123
+
124
+ ```typescript
125
+ export interface SelectionSelectedItem {
126
+ type: string
127
+ id: string
128
+ }
129
+ ```
130
+
131
+ ## 使用示例
132
+
133
+ ### 基本用法
134
+
135
+ ```typescript
136
+ import { Selection } from '@knotx/plugins-selection'
137
+
138
+ const engine = new Engine({
139
+ plugins: [Selection],
140
+ pluginConfig: {
141
+ selection: {
142
+ enableDrag: true,
143
+ },
144
+ },
145
+ })
146
+ ```
147
+
148
+ ### 自定义选择规则
149
+
150
+ ```typescript
151
+ const engine = new Engine({
152
+ plugins: [Selection],
153
+ pluginConfig: {
154
+ selection: {
155
+ rules: [
156
+ {
157
+ type: 'custom-node',
158
+ className: 'custom-node-wrapper',
159
+ idGetter: element => element.getAttribute('data-node-id') || '',
160
+ activeClassName: 'custom-node-selected',
161
+ onSelected: (context) => {
162
+ console.log('Custom node selected:', context.id)
163
+ return true // 返回 true 表示允许选择
164
+ },
165
+ },
166
+ ],
167
+ },
168
+ },
169
+ })
170
+ ```
171
+
172
+ ### 程序化选择
173
+
174
+ ```typescript
175
+ // 选择特定元素
176
+ engine.callTool('selection', 'select', [
177
+ { type: 'node', id: 'node-1' },
178
+ { type: 'node', id: 'node-2' },
179
+ ])
180
+
181
+ // 取消选择特定元素
182
+ engine.callTool('selection', 'deselect', [
183
+ { type: 'node', id: 'node-1' },
184
+ ])
185
+
186
+ // 获取当前选择的元素
187
+ const selected = engine.callTool('selection', 'getSelected')
188
+ console.log('Selected items:', selected)
189
+
190
+ // 清空所有选择
191
+ engine.callTool('selection', 'clearSelection')
192
+ ```
193
+
194
+ ### 动态管理选择规则
195
+
196
+ ```typescript
197
+ // 获取插件数据
198
+ const selectionData = engine.getPluginData('selection')
199
+
200
+ // 注册新规则
201
+ const unregister = selectionData.registerRules([
202
+ {
203
+ type: 'edge',
204
+ className: 'edge-wrapper',
205
+ idGetter: element => element.getAttribute('data-edge-id') || '',
206
+ activeClassName: 'edge-selected',
207
+ },
208
+ ])
209
+
210
+ // 启用/禁用规则
211
+ selectionData.setRuleEnabled('edge', false)
212
+
213
+ // 设置重叠模式
214
+ selectionData.setElementOverlap('invert') // 'keep' | 'drop' | 'invert'
215
+
216
+ // 取消注册规则
217
+ unregister()
218
+ ```
219
+
220
+ ### 监听选择变化
221
+
222
+ ```typescript
223
+ class MyPlugin extends BasePlugin {
224
+ @inject.selection.selected()
225
+ selected!: SelectionSelectedItem[]
226
+
227
+ @subscribe.selection.selected()
228
+ onSelectedChange(selected: SelectionSelectedItem[]) {
229
+ console.log('Selection changed:', selected)
230
+ }
231
+ }
232
+ ```
233
+
234
+ ### 与 Canvas 插件集成
235
+
236
+ ```typescript
237
+ import { Canvas } from '@knotx/plugins-canvas'
238
+ import { Selection } from '@knotx/plugins-selection'
239
+
240
+ const engine = new Engine({
241
+ plugins: [Canvas, Selection],
242
+ pluginConfig: {
243
+ canvas: {
244
+ minScale: 0.1,
245
+ maxScale: 3,
246
+ },
247
+ selection: {
248
+ enableDrag: true,
249
+ container: '.canvas-container', // 指定选择容器
250
+ },
251
+ },
252
+ })
253
+ ```
254
+
255
+ ## 高级功能
256
+
257
+ ### 自定义选择行为
258
+
259
+ ```typescript
260
+ const engine = new Engine({
261
+ plugins: [Selection],
262
+ pluginConfig: {
263
+ selection: {
264
+ rules: [
265
+ {
266
+ type: 'node',
267
+ className: 'node-wrapper',
268
+ idGetter: element => element.getAttribute('data-node-id') || '',
269
+ onSelected: (context) => {
270
+ const { element, type, id, isDragging, getSelectedElements, select, deselect } = context
271
+
272
+ // 自定义选择逻辑
273
+ if (isDragging) {
274
+ // 拖拽选择时的逻辑
275
+ return true
276
+ }
277
+
278
+ // 单击选择时的逻辑
279
+ const selectedElements = getSelectedElements()
280
+ if (selectedElements.node && selectedElements.node.length > 0) {
281
+ // 已有选择,执行多选逻辑
282
+ return true
283
+ }
284
+
285
+ return true
286
+ },
287
+ },
288
+ ],
289
+ },
290
+ },
291
+ })
292
+ ```
293
+
294
+ ### 选择区域样式自定义
295
+
296
+ ```typescript
297
+ const engine = new Engine({
298
+ plugins: [Selection],
299
+ pluginConfig: {
300
+ selection: {
301
+ selectionAreaClassName: 'custom-selection-area',
302
+ },
303
+ },
304
+ })
305
+ ```
306
+
307
+ ```css
308
+ .custom-selection-area {
309
+ background: rgba(74, 144, 226, 0.1);
310
+ border: 2px dashed #4A90E2;
311
+ border-radius: 4px;
312
+ }
313
+ ```
314
+
315
+ ## 文件目录结构
316
+
317
+ ```
318
+ packages/plugins-selection/
319
+ ├── src/
320
+ │ ├── selection.tsx # 主要实现文件
321
+ │ └── index.ts # 导出文件
322
+ ├── dist/ # 构建输出目录
323
+ ├── package.json # 包配置文件
324
+ ├── build.config.ts # 构建配置
325
+ ├── tsconfig.json # TypeScript 配置
326
+ ├── eslint.config.mjs # ESLint 配置
327
+ └── CHANGELOG.md # 更新日志
328
+ ```
329
+
330
+ ### 核心文件说明
331
+
332
+ - **selection.tsx**:包含 Selection 插件的主要实现,包括选择区域管理、规则系统和事件处理
333
+ - **index.ts**:导出 Selection 类和相关类型定义
334
+
335
+ ## 注意事项
336
+
337
+ 1. **性能考虑**:大量元素时,选择操作可能影响性能,建议使用虚拟化或分页
338
+ 2. **事件冲突**:与其他交互插件(如拖拽)可能存在事件冲突,注意事件优先级
339
+ 3. **内存管理**:及时清理不需要的选择规则,避免内存泄漏
340
+ 4. **浏览器兼容性**:依赖现代浏览器的 DOM API,注意兼容性
341
+
342
+ ## 许可证
343
+
344
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knotx/plugins-selection",
3
- "version": "0.4.12",
3
+ "version": "0.4.13",
4
4
  "description": "Selection Plugin for Knotx",
5
5
  "author": "boenfu",
6
6
  "license": "MIT",
@@ -28,19 +28,19 @@
28
28
  "dist"
29
29
  ],
30
30
  "peerDependencies": {
31
- "@knotx/plugins-canvas": "0.4.12"
31
+ "@knotx/plugins-canvas": "0.4.13"
32
32
  },
33
33
  "dependencies": {
34
34
  "@knotx/viselect": "^3.9.0",
35
35
  "rxjs": "^7.8.1",
36
- "@knotx/core": "0.4.12",
37
- "@knotx/decorators": "0.4.12"
36
+ "@knotx/core": "0.4.13",
37
+ "@knotx/decorators": "0.4.13"
38
38
  },
39
39
  "devDependencies": {
40
- "@knotx/build-config": "0.4.12",
41
- "@knotx/eslint-config": "0.4.12",
42
- "@knotx/plugins-canvas": "0.4.12",
43
- "@knotx/typescript-config": "0.4.12"
40
+ "@knotx/build-config": "0.4.13",
41
+ "@knotx/eslint-config": "0.4.13",
42
+ "@knotx/plugins-canvas": "0.4.13",
43
+ "@knotx/typescript-config": "0.4.13"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "unbuild",