@knotx/plugins-selection 0.2.15 → 0.3.1

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/dist/index.cjs CHANGED
@@ -10,9 +10,7 @@ const SelectionArea__default = /*#__PURE__*/_interopDefaultCompat(SelectionArea)
10
10
 
11
11
  var __create = Object.create;
12
12
  var __defProp = Object.defineProperty;
13
- var __defProps = Object.defineProperties;
14
13
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
15
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
16
14
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
17
15
  var __hasOwnProp = Object.prototype.hasOwnProperty;
18
16
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -32,7 +30,6 @@ var __spreadValues = (a, b) => {
32
30
  }
33
31
  return a;
34
32
  };
35
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
36
33
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
37
34
  var __decoratorStart = (base) => {
38
35
  var _a2;
@@ -76,120 +73,186 @@ var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use
76
73
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
77
74
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
78
75
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
79
- var _destroy_dec, _clearSelection_dec, _getSelectedNodeIds_dec, _init_dec, _canInteract_dec, _endInteraction_dec, _startInteraction_dec, _selectStatus_dec, _selectedNodeIds_dec, _a, _init;
80
- class Selection extends (_a = core.BasePlugin, _selectedNodeIds_dec = [decorators.register("selectedNodeIds")], _selectStatus_dec = [decorators.register("selectStatus")], _startInteraction_dec = [decorators.inject.startInteraction()], _endInteraction_dec = [decorators.inject.endInteraction()], _canInteract_dec = [decorators.inject.canInteract()], _init_dec = [decorators.OnInit], _getSelectedNodeIds_dec = [decorators.tool("Get selected node ids", {})], _clearSelection_dec = [decorators.tool("Clear selection", {})], _destroy_dec = [decorators.OnDestroy], _a) {
76
+ var _destroy_dec, _clearSelection_dec, _getSelected_dec, _init_dec, _canInteract_dec, _endInteraction_dec, _startInteraction_dec, _registerRules_dec, _selected_dec, _a, _init;
77
+ class Selection extends (_a = core.BasePlugin, _selected_dec = [decorators.register("selected")], _registerRules_dec = [decorators.register("registerRules")], _startInteraction_dec = [decorators.inject.startInteraction()], _endInteraction_dec = [decorators.inject.endInteraction()], _canInteract_dec = [decorators.inject.canInteract()], _init_dec = [decorators.OnInit], _getSelected_dec = [decorators.tool("Get selected items", {})], _clearSelection_dec = [decorators.tool("Clear selection", {})], _destroy_dec = [decorators.OnDestroy], _a) {
81
78
  constructor() {
82
79
  super(...arguments);
83
80
  __runInitializers(_init, 5, this);
84
81
  __publicField(this, "name", "selection");
85
- __publicField(this, "config");
86
82
  __publicField(this, "selection");
87
- __publicField(this, "selectedNodeIds", __runInitializers(_init, 8, this, [])), __runInitializers(_init, 11, this);
88
- __publicField(this, "selectStatus", __runInitializers(_init, 12, this, "stop")), __runInitializers(_init, 15, this);
83
+ __publicField(this, "container", "body");
84
+ __publicField(this, "selectionAreaClassName");
85
+ __publicField(this, "ruleMap", /* @__PURE__ */ new Map());
86
+ __publicField(this, "enableDrag", true);
87
+ __publicField(this, "isDragging", false);
88
+ __publicField(this, "updateFrameId");
89
+ __publicField(this, "selected", __runInitializers(_init, 8, this, [])), __runInitializers(_init, 11, this);
90
+ __publicField(this, "registerRules", __runInitializers(_init, 12, this, (rules) => {
91
+ rules.forEach((rule) => {
92
+ this.ruleMap.set(rule.className, rule);
93
+ });
94
+ return () => {
95
+ rules.forEach((rule) => {
96
+ if (this.ruleMap.get(rule.className) === rule) {
97
+ this.ruleMap.delete(rule.className);
98
+ }
99
+ });
100
+ };
101
+ })), __runInitializers(_init, 15, this);
89
102
  __publicField(this, "startInteraction", __runInitializers(_init, 16, this)), __runInitializers(_init, 19, this);
90
103
  __publicField(this, "endInteraction", __runInitializers(_init, 20, this)), __runInitializers(_init, 23, this);
91
104
  __publicField(this, "canInteract", __runInitializers(_init, 24, this)), __runInitializers(_init, 27, this);
92
- }
93
- init(config) {
94
- this.config = __spreadValues({
95
- boundaries: [`.${core.bem("canvas", "wrapper")}`]
96
- }, config);
97
- this.createSelection();
98
- }
99
- createSelection() {
100
- const nodeWrapperClassName = core.bem("node", "wrapper");
101
- const nodeClassName = core.addBemModifier(nodeWrapperClassName, "selected");
102
- const selectionAreaClass = core.bem("selection-area");
103
- const selectables = [`.${nodeWrapperClassName}`];
104
- const endSelect = () => {
105
- this.endInteraction(this.pluginId, "select");
106
- this.selectStatus = "stop";
107
- };
108
- this.selection = new SelectionArea__default(__spreadProps(__spreadValues({}, this.config), { selectionAreaClass, selectables })).on("start", ({ store, event, selection }) => {
105
+ __publicField(this, "onBeforeStart", (_) => {
106
+ });
107
+ __publicField(this, "onBeforeDrag", () => {
108
+ this.isDragging = this.enableDrag;
109
+ return this.enableDrag && this.canInteract(this.pluginId, "select", core.InteractionPriority.MarqueeSelection);
110
+ });
111
+ __publicField(this, "onStart", ({ event, store }) => {
112
+ var _a2;
113
+ this.startInteraction(this.pluginId, "select", core.InteractionPriority.MarqueeSelection);
109
114
  if (!(event == null ? void 0 : event.ctrlKey) && !(event == null ? void 0 : event.metaKey) && !(event == null ? void 0 : event.shiftKey)) {
110
- store.stored.forEach((el) => {
111
- if (el.className.includes(nodeWrapperClassName)) {
112
- el.classList.remove(nodeClassName);
115
+ store.stored.forEach((element) => {
116
+ const rule = this.getElementRule(element);
117
+ if (rule == null ? void 0 : rule.activeClassName) {
118
+ element.classList.remove(rule.activeClassName);
113
119
  }
114
120
  });
115
- selection.clearSelection();
116
- this.selectedNodeIds = [];
121
+ (_a2 = this.selection) == null ? void 0 : _a2.clearSelection(true, true);
117
122
  }
118
- this.startInteraction(this.pluginId, "select", core.InteractionPriority.MarqueeSelection);
119
- this.selectStatus = "start";
120
- }).on("move", ({ store: { changed: { added, removed } }, selection, event }) => {
121
- if (event) {
122
- this.selectStatus = "moving";
123
- }
124
- if (!this.canInteract(this.pluginId, "select", core.InteractionPriority.MarqueeSelection)) {
125
- selection.cancel();
126
- endSelect();
127
- return;
128
- }
129
- const addedNodeIds = [];
130
- added.forEach((el) => {
131
- if (el.className.includes(nodeWrapperClassName)) {
132
- el.classList.add(nodeClassName);
133
- const nodeId = el.getAttribute("data-node-id");
134
- if (nodeId)
135
- addedNodeIds.push(nodeId);
123
+ });
124
+ __publicField(this, "onMove", ({ store: { stored, changed: { added, removed } }, selection }) => {
125
+ const getSelectedElements = () => {
126
+ return stored.reduce((dict, item) => {
127
+ const rule = this.getElementRule(item);
128
+ if (rule) {
129
+ dict[rule.type] = [...dict[rule.type] || [], { id: rule.idGetter(item), element: item }];
130
+ }
131
+ return dict;
132
+ }, {});
133
+ };
134
+ const context = {
135
+ isDragging: this.isDragging,
136
+ getSelectedElements,
137
+ select: (elements) => {
138
+ elements.forEach((element) => {
139
+ selection.select(element);
140
+ });
141
+ },
142
+ deselect: (elements) => {
143
+ elements.forEach((element) => {
144
+ selection.deselect(element);
145
+ });
146
+ }
147
+ };
148
+ removed.forEach((element) => {
149
+ const rule = this.getElementRule(element);
150
+ if (!rule) {
151
+ return;
152
+ }
153
+ if (rule.activeClassName) {
154
+ element.classList.remove(rule.activeClassName);
136
155
  }
137
156
  });
138
- const removedNodeIds = [];
139
- removed.forEach((el) => {
140
- if (el.className.includes(nodeWrapperClassName)) {
141
- el.classList.remove(nodeClassName);
142
- const nodeId = el.getAttribute("data-node-id");
143
- if (nodeId)
144
- removedNodeIds.push(nodeId);
157
+ added.forEach((element) => {
158
+ const rule = this.getElementRule(element);
159
+ if (!rule) {
160
+ return;
161
+ }
162
+ const type = rule.type;
163
+ const id = rule.idGetter(element);
164
+ for (const [, rule2] of this.ruleMap) {
165
+ if (rule2.onSelected) {
166
+ if (!rule2.onSelected(__spreadValues({ element, type, id }, context))) {
167
+ selection.deselect(element, true);
168
+ return;
169
+ }
170
+ }
171
+ }
172
+ if (rule.activeClassName) {
173
+ element.classList.add(rule.activeClassName);
145
174
  }
146
175
  });
147
- this.updateSelection(addedNodeIds, removedNodeIds);
148
- }).on("stop", ({ event }) => {
176
+ });
177
+ __publicField(this, "onStop", ({ event }) => {
178
+ this.endInteraction(this.pluginId, "select");
149
179
  if (event) {
150
- endSelect();
180
+ if (this.isDragging) {
181
+ this.isDragging = false;
182
+ }
151
183
  }
184
+ cancelAnimationFrame(this.updateFrameId);
185
+ this.updateFrameId = requestAnimationFrame(this.updateSelection);
186
+ });
187
+ __publicField(this, "updateSelection", () => {
188
+ var _a2;
189
+ const selected = [];
190
+ for (const element of ((_a2 = this.selection) == null ? void 0 : _a2.getSelection()) || []) {
191
+ const rule = this.getElementRule(element);
192
+ if (rule) {
193
+ selected.push({ type: rule.type, id: rule.idGetter(element) });
194
+ }
195
+ }
196
+ this.selected = selected;
152
197
  });
153
198
  }
154
- // 更新选中的节点和组
155
- updateSelection(addedNodeIds = [], removedNodeIds = []) {
156
- const currentNodeIds = this.selectedNodeIds;
157
- const newNodeIds = [
158
- ...currentNodeIds.filter((id) => !removedNodeIds.includes(id)),
159
- ...addedNodeIds.filter((id) => !currentNodeIds.includes(id))
160
- ];
161
- this.selectedNodeIds = newNodeIds;
162
- }
163
- getSelectedNodeIds() {
164
- return this.selectedNodeIds;
199
+ init(config = {}) {
200
+ this.container = config.container || core.bemSelector("canvas", "wrapper");
201
+ this.selectionAreaClassName = config.selectionAreaClassName || core.bem("selection-area");
202
+ if (!config.disableDefaultRules) {
203
+ const nodeRule = {
204
+ type: "node",
205
+ className: core.bem("node", "wrapper"),
206
+ activeClassName: core.bem("node", "wrapper", "selected"),
207
+ idGetter: (element) => element.getAttribute("data-node-id") || ""
208
+ };
209
+ this.ruleMap.set(nodeRule.className, nodeRule);
210
+ }
211
+ for (const rule of config.rules || []) {
212
+ this.ruleMap.set(rule.className, rule);
213
+ }
214
+ if (config.enableDrag !== void 0) {
215
+ this.enableDrag = config.enableDrag;
216
+ }
217
+ queueMicrotask(() => this.createSelection());
165
218
  }
166
- clearSelection() {
167
- this.selectedNodeIds = [];
219
+ createSelection() {
220
+ const container = this.container;
221
+ this.selection = new SelectionArea__default({
222
+ // container,
223
+ boundaries: [container],
224
+ selectionAreaClass: this.selectionAreaClassName,
225
+ selectables: Array.from(this.ruleMap.keys()).map((className) => `.${className}`)
226
+ }).on("beforedrag", this.onBeforeDrag).on("beforestart", this.onBeforeStart).on("start", this.onStart).on("move", this.onMove).on("stop", this.onStop);
168
227
  }
169
- // 选择节点
170
- selectNodes(nodeIds, clearPrevious = true) {
171
- if (clearPrevious) {
172
- this.selectedNodeIds = nodeIds;
173
- } else {
174
- const currentNodeIds = this.selectedNodeIds;
175
- this.selectedNodeIds = [
176
- ...currentNodeIds,
177
- ...nodeIds.filter((id) => !currentNodeIds.includes(id))
178
- ];
228
+ getElementRule(element) {
229
+ for (const [className, rule] of this.ruleMap) {
230
+ if (element.classList.contains(className)) {
231
+ return rule;
232
+ }
179
233
  }
234
+ return void 0;
235
+ }
236
+ getSelected() {
237
+ return this.selected;
238
+ }
239
+ clearSelection() {
240
+ var _a2;
241
+ (_a2 = this.selection) == null ? void 0 : _a2.clearSelection(true, false);
180
242
  }
181
243
  destroy() {
182
244
  var _a2;
183
245
  (_a2 = this.selection) == null ? void 0 : _a2.destroy();
246
+ this.ruleMap.clear();
184
247
  }
185
248
  }
186
249
  _init = __decoratorStart(_a);
187
250
  __decorateElement(_init, 1, "init", _init_dec, Selection);
188
- __decorateElement(_init, 1, "getSelectedNodeIds", _getSelectedNodeIds_dec, Selection);
251
+ __decorateElement(_init, 1, "getSelected", _getSelected_dec, Selection);
189
252
  __decorateElement(_init, 1, "clearSelection", _clearSelection_dec, Selection);
190
253
  __decorateElement(_init, 1, "destroy", _destroy_dec, Selection);
191
- __decorateElement(_init, 5, "selectedNodeIds", _selectedNodeIds_dec, Selection);
192
- __decorateElement(_init, 5, "selectStatus", _selectStatus_dec, Selection);
254
+ __decorateElement(_init, 5, "selected", _selected_dec, Selection);
255
+ __decorateElement(_init, 5, "registerRules", _registerRules_dec, Selection);
193
256
  __decorateElement(_init, 5, "startInteraction", _startInteraction_dec, Selection);
194
257
  __decorateElement(_init, 5, "endInteraction", _endInteraction_dec, Selection);
195
258
  __decorateElement(_init, 5, "canInteract", _canInteract_dec, Selection);
package/dist/index.d.cts CHANGED
@@ -1,38 +1,90 @@
1
- import { PartialSelectionOptions } from '@viselect/vanilla';
2
1
  import { BasePlugin } from '@knotx/core';
3
2
 
3
+ interface SelectionSelectedItem {
4
+ type: string;
5
+ id: string;
6
+ }
4
7
  declare module '@knotx/core' {
5
8
  interface PluginData {
6
9
  selection: {
7
- selectedNodeIds: string[];
8
- selectStatus: 'start' | 'moving' | 'stop';
10
+ selected: SelectionSelectedItem[];
11
+ registerRules: (rules: SelectionRule[]) => () => void;
9
12
  };
10
13
  }
11
14
  interface PluginTools {
12
15
  selection: {
13
- getSelectedNodeIds: () => string[];
16
+ getSelected: () => SelectionSelectedItem[];
14
17
  clearSelection: () => void;
15
18
  };
16
19
  }
17
20
  }
18
- interface SelectionConfig extends PartialSelectionOptions {
21
+ interface SelectionRule {
22
+ /**
23
+ * resource type
24
+ */
25
+ type: string;
26
+ className: string;
27
+ idGetter: (element: Element) => string;
28
+ /**
29
+ * default: null
30
+ */
31
+ activeClassName?: string;
32
+ onSelected?: (context: {
33
+ element: Element;
34
+ type: string;
35
+ id: string;
36
+ isDragging: boolean;
37
+ getSelectedElements: () => Record<string, {
38
+ id: string;
39
+ element: Element;
40
+ }[]>;
41
+ select: (elements: Element[]) => void;
42
+ deselect: (elements: Element[]) => void;
43
+ }) => boolean;
44
+ }
45
+ interface SelectionConfig {
46
+ selectionAreaClassName?: string;
47
+ /**
48
+ * default: true
49
+ */
50
+ enableDrag?: boolean;
51
+ rules?: SelectionRule[];
52
+ /**
53
+ * default:
54
+ * [{type: 'node', className: bem('node', 'wrapper'), activeClassName: bem('node', 'wrapper', 'selected') }]
55
+ */
56
+ disableDefaultRules?: boolean;
57
+ /**
58
+ * default: bemSelector('canvas', 'wrapper')
59
+ */
60
+ container?: string;
19
61
  }
20
62
  declare class Selection extends BasePlugin<'selection', SelectionConfig> {
21
63
  name: "selection";
22
- private config;
23
64
  private selection;
24
- selectedNodeIds: string[];
25
- selectStatus: 'start' | 'moving' | 'stop';
65
+ private container;
66
+ private selectionAreaClassName;
67
+ private ruleMap;
68
+ private enableDrag;
69
+ private isDragging;
70
+ private updateFrameId;
71
+ selected: SelectionSelectedItem[];
72
+ registerRules: (rules: SelectionRule[]) => () => void;
26
73
  private startInteraction;
27
74
  private endInteraction;
28
75
  private canInteract;
29
- init(config: SelectionConfig): void;
76
+ init(config?: SelectionConfig): void;
30
77
  private createSelection;
78
+ private onBeforeStart;
79
+ private onBeforeDrag;
80
+ private onStart;
81
+ private onMove;
82
+ private onStop;
83
+ private getElementRule;
31
84
  private updateSelection;
32
- getSelectedNodeIds(): string[];
85
+ getSelected(): SelectionSelectedItem[];
33
86
  clearSelection(): void;
34
- selectNodes(nodeIds: string[], clearPrevious?: boolean): void;
35
87
  destroy(): void;
36
88
  }
37
89
 
38
- export { Selection, type SelectionConfig };
90
+ export { Selection, type SelectionConfig, type SelectionRule, type SelectionSelectedItem };
package/dist/index.d.mts CHANGED
@@ -1,38 +1,90 @@
1
- import { PartialSelectionOptions } from '@viselect/vanilla';
2
1
  import { BasePlugin } from '@knotx/core';
3
2
 
3
+ interface SelectionSelectedItem {
4
+ type: string;
5
+ id: string;
6
+ }
4
7
  declare module '@knotx/core' {
5
8
  interface PluginData {
6
9
  selection: {
7
- selectedNodeIds: string[];
8
- selectStatus: 'start' | 'moving' | 'stop';
10
+ selected: SelectionSelectedItem[];
11
+ registerRules: (rules: SelectionRule[]) => () => void;
9
12
  };
10
13
  }
11
14
  interface PluginTools {
12
15
  selection: {
13
- getSelectedNodeIds: () => string[];
16
+ getSelected: () => SelectionSelectedItem[];
14
17
  clearSelection: () => void;
15
18
  };
16
19
  }
17
20
  }
18
- interface SelectionConfig extends PartialSelectionOptions {
21
+ interface SelectionRule {
22
+ /**
23
+ * resource type
24
+ */
25
+ type: string;
26
+ className: string;
27
+ idGetter: (element: Element) => string;
28
+ /**
29
+ * default: null
30
+ */
31
+ activeClassName?: string;
32
+ onSelected?: (context: {
33
+ element: Element;
34
+ type: string;
35
+ id: string;
36
+ isDragging: boolean;
37
+ getSelectedElements: () => Record<string, {
38
+ id: string;
39
+ element: Element;
40
+ }[]>;
41
+ select: (elements: Element[]) => void;
42
+ deselect: (elements: Element[]) => void;
43
+ }) => boolean;
44
+ }
45
+ interface SelectionConfig {
46
+ selectionAreaClassName?: string;
47
+ /**
48
+ * default: true
49
+ */
50
+ enableDrag?: boolean;
51
+ rules?: SelectionRule[];
52
+ /**
53
+ * default:
54
+ * [{type: 'node', className: bem('node', 'wrapper'), activeClassName: bem('node', 'wrapper', 'selected') }]
55
+ */
56
+ disableDefaultRules?: boolean;
57
+ /**
58
+ * default: bemSelector('canvas', 'wrapper')
59
+ */
60
+ container?: string;
19
61
  }
20
62
  declare class Selection extends BasePlugin<'selection', SelectionConfig> {
21
63
  name: "selection";
22
- private config;
23
64
  private selection;
24
- selectedNodeIds: string[];
25
- selectStatus: 'start' | 'moving' | 'stop';
65
+ private container;
66
+ private selectionAreaClassName;
67
+ private ruleMap;
68
+ private enableDrag;
69
+ private isDragging;
70
+ private updateFrameId;
71
+ selected: SelectionSelectedItem[];
72
+ registerRules: (rules: SelectionRule[]) => () => void;
26
73
  private startInteraction;
27
74
  private endInteraction;
28
75
  private canInteract;
29
- init(config: SelectionConfig): void;
76
+ init(config?: SelectionConfig): void;
30
77
  private createSelection;
78
+ private onBeforeStart;
79
+ private onBeforeDrag;
80
+ private onStart;
81
+ private onMove;
82
+ private onStop;
83
+ private getElementRule;
31
84
  private updateSelection;
32
- getSelectedNodeIds(): string[];
85
+ getSelected(): SelectionSelectedItem[];
33
86
  clearSelection(): void;
34
- selectNodes(nodeIds: string[], clearPrevious?: boolean): void;
35
87
  destroy(): void;
36
88
  }
37
89
 
38
- export { Selection, type SelectionConfig };
90
+ export { Selection, type SelectionConfig, type SelectionRule, type SelectionSelectedItem };
package/dist/index.d.ts CHANGED
@@ -1,38 +1,90 @@
1
- import { PartialSelectionOptions } from '@viselect/vanilla';
2
1
  import { BasePlugin } from '@knotx/core';
3
2
 
3
+ interface SelectionSelectedItem {
4
+ type: string;
5
+ id: string;
6
+ }
4
7
  declare module '@knotx/core' {
5
8
  interface PluginData {
6
9
  selection: {
7
- selectedNodeIds: string[];
8
- selectStatus: 'start' | 'moving' | 'stop';
10
+ selected: SelectionSelectedItem[];
11
+ registerRules: (rules: SelectionRule[]) => () => void;
9
12
  };
10
13
  }
11
14
  interface PluginTools {
12
15
  selection: {
13
- getSelectedNodeIds: () => string[];
16
+ getSelected: () => SelectionSelectedItem[];
14
17
  clearSelection: () => void;
15
18
  };
16
19
  }
17
20
  }
18
- interface SelectionConfig extends PartialSelectionOptions {
21
+ interface SelectionRule {
22
+ /**
23
+ * resource type
24
+ */
25
+ type: string;
26
+ className: string;
27
+ idGetter: (element: Element) => string;
28
+ /**
29
+ * default: null
30
+ */
31
+ activeClassName?: string;
32
+ onSelected?: (context: {
33
+ element: Element;
34
+ type: string;
35
+ id: string;
36
+ isDragging: boolean;
37
+ getSelectedElements: () => Record<string, {
38
+ id: string;
39
+ element: Element;
40
+ }[]>;
41
+ select: (elements: Element[]) => void;
42
+ deselect: (elements: Element[]) => void;
43
+ }) => boolean;
44
+ }
45
+ interface SelectionConfig {
46
+ selectionAreaClassName?: string;
47
+ /**
48
+ * default: true
49
+ */
50
+ enableDrag?: boolean;
51
+ rules?: SelectionRule[];
52
+ /**
53
+ * default:
54
+ * [{type: 'node', className: bem('node', 'wrapper'), activeClassName: bem('node', 'wrapper', 'selected') }]
55
+ */
56
+ disableDefaultRules?: boolean;
57
+ /**
58
+ * default: bemSelector('canvas', 'wrapper')
59
+ */
60
+ container?: string;
19
61
  }
20
62
  declare class Selection extends BasePlugin<'selection', SelectionConfig> {
21
63
  name: "selection";
22
- private config;
23
64
  private selection;
24
- selectedNodeIds: string[];
25
- selectStatus: 'start' | 'moving' | 'stop';
65
+ private container;
66
+ private selectionAreaClassName;
67
+ private ruleMap;
68
+ private enableDrag;
69
+ private isDragging;
70
+ private updateFrameId;
71
+ selected: SelectionSelectedItem[];
72
+ registerRules: (rules: SelectionRule[]) => () => void;
26
73
  private startInteraction;
27
74
  private endInteraction;
28
75
  private canInteract;
29
- init(config: SelectionConfig): void;
76
+ init(config?: SelectionConfig): void;
30
77
  private createSelection;
78
+ private onBeforeStart;
79
+ private onBeforeDrag;
80
+ private onStart;
81
+ private onMove;
82
+ private onStop;
83
+ private getElementRule;
31
84
  private updateSelection;
32
- getSelectedNodeIds(): string[];
85
+ getSelected(): SelectionSelectedItem[];
33
86
  clearSelection(): void;
34
- selectNodes(nodeIds: string[], clearPrevious?: boolean): void;
35
87
  destroy(): void;
36
88
  }
37
89
 
38
- export { Selection, type SelectionConfig };
90
+ export { Selection, type SelectionConfig, type SelectionRule, type SelectionSelectedItem };
package/dist/index.js CHANGED
@@ -1,12 +1,10 @@
1
- import { bem, addBemModifier, InteractionPriority, BasePlugin } from '@knotx/core';
1
+ import { bemSelector, bem, BasePlugin, InteractionPriority } from '@knotx/core';
2
2
  import { register, inject, tool, OnInit, OnDestroy } from '@knotx/decorators';
3
3
  import SelectionArea from '@viselect/vanilla';
4
4
 
5
5
  var __create = Object.create;
6
6
  var __defProp = Object.defineProperty;
7
- var __defProps = Object.defineProperties;
8
7
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
10
8
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
11
9
  var __hasOwnProp = Object.prototype.hasOwnProperty;
12
10
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -26,7 +24,6 @@ var __spreadValues = (a, b) => {
26
24
  }
27
25
  return a;
28
26
  };
29
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
30
27
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
31
28
  var __decoratorStart = (base) => {
32
29
  var _a2;
@@ -70,120 +67,186 @@ var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use
70
67
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
71
68
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
72
69
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
73
- var _destroy_dec, _clearSelection_dec, _getSelectedNodeIds_dec, _init_dec, _canInteract_dec, _endInteraction_dec, _startInteraction_dec, _selectStatus_dec, _selectedNodeIds_dec, _a, _init;
74
- class Selection extends (_a = BasePlugin, _selectedNodeIds_dec = [register("selectedNodeIds")], _selectStatus_dec = [register("selectStatus")], _startInteraction_dec = [inject.startInteraction()], _endInteraction_dec = [inject.endInteraction()], _canInteract_dec = [inject.canInteract()], _init_dec = [OnInit], _getSelectedNodeIds_dec = [tool("Get selected node ids", {})], _clearSelection_dec = [tool("Clear selection", {})], _destroy_dec = [OnDestroy], _a) {
70
+ var _destroy_dec, _clearSelection_dec, _getSelected_dec, _init_dec, _canInteract_dec, _endInteraction_dec, _startInteraction_dec, _registerRules_dec, _selected_dec, _a, _init;
71
+ class Selection extends (_a = BasePlugin, _selected_dec = [register("selected")], _registerRules_dec = [register("registerRules")], _startInteraction_dec = [inject.startInteraction()], _endInteraction_dec = [inject.endInteraction()], _canInteract_dec = [inject.canInteract()], _init_dec = [OnInit], _getSelected_dec = [tool("Get selected items", {})], _clearSelection_dec = [tool("Clear selection", {})], _destroy_dec = [OnDestroy], _a) {
75
72
  constructor() {
76
73
  super(...arguments);
77
74
  __runInitializers(_init, 5, this);
78
75
  __publicField(this, "name", "selection");
79
- __publicField(this, "config");
80
76
  __publicField(this, "selection");
81
- __publicField(this, "selectedNodeIds", __runInitializers(_init, 8, this, [])), __runInitializers(_init, 11, this);
82
- __publicField(this, "selectStatus", __runInitializers(_init, 12, this, "stop")), __runInitializers(_init, 15, this);
77
+ __publicField(this, "container", "body");
78
+ __publicField(this, "selectionAreaClassName");
79
+ __publicField(this, "ruleMap", /* @__PURE__ */ new Map());
80
+ __publicField(this, "enableDrag", true);
81
+ __publicField(this, "isDragging", false);
82
+ __publicField(this, "updateFrameId");
83
+ __publicField(this, "selected", __runInitializers(_init, 8, this, [])), __runInitializers(_init, 11, this);
84
+ __publicField(this, "registerRules", __runInitializers(_init, 12, this, (rules) => {
85
+ rules.forEach((rule) => {
86
+ this.ruleMap.set(rule.className, rule);
87
+ });
88
+ return () => {
89
+ rules.forEach((rule) => {
90
+ if (this.ruleMap.get(rule.className) === rule) {
91
+ this.ruleMap.delete(rule.className);
92
+ }
93
+ });
94
+ };
95
+ })), __runInitializers(_init, 15, this);
83
96
  __publicField(this, "startInteraction", __runInitializers(_init, 16, this)), __runInitializers(_init, 19, this);
84
97
  __publicField(this, "endInteraction", __runInitializers(_init, 20, this)), __runInitializers(_init, 23, this);
85
98
  __publicField(this, "canInteract", __runInitializers(_init, 24, this)), __runInitializers(_init, 27, this);
86
- }
87
- init(config) {
88
- this.config = __spreadValues({
89
- boundaries: [`.${bem("canvas", "wrapper")}`]
90
- }, config);
91
- this.createSelection();
92
- }
93
- createSelection() {
94
- const nodeWrapperClassName = bem("node", "wrapper");
95
- const nodeClassName = addBemModifier(nodeWrapperClassName, "selected");
96
- const selectionAreaClass = bem("selection-area");
97
- const selectables = [`.${nodeWrapperClassName}`];
98
- const endSelect = () => {
99
- this.endInteraction(this.pluginId, "select");
100
- this.selectStatus = "stop";
101
- };
102
- this.selection = new SelectionArea(__spreadProps(__spreadValues({}, this.config), { selectionAreaClass, selectables })).on("start", ({ store, event, selection }) => {
99
+ __publicField(this, "onBeforeStart", (_) => {
100
+ });
101
+ __publicField(this, "onBeforeDrag", () => {
102
+ this.isDragging = this.enableDrag;
103
+ return this.enableDrag && this.canInteract(this.pluginId, "select", InteractionPriority.MarqueeSelection);
104
+ });
105
+ __publicField(this, "onStart", ({ event, store }) => {
106
+ var _a2;
107
+ this.startInteraction(this.pluginId, "select", InteractionPriority.MarqueeSelection);
103
108
  if (!(event == null ? void 0 : event.ctrlKey) && !(event == null ? void 0 : event.metaKey) && !(event == null ? void 0 : event.shiftKey)) {
104
- store.stored.forEach((el) => {
105
- if (el.className.includes(nodeWrapperClassName)) {
106
- el.classList.remove(nodeClassName);
109
+ store.stored.forEach((element) => {
110
+ const rule = this.getElementRule(element);
111
+ if (rule == null ? void 0 : rule.activeClassName) {
112
+ element.classList.remove(rule.activeClassName);
107
113
  }
108
114
  });
109
- selection.clearSelection();
110
- this.selectedNodeIds = [];
115
+ (_a2 = this.selection) == null ? void 0 : _a2.clearSelection(true, true);
111
116
  }
112
- this.startInteraction(this.pluginId, "select", InteractionPriority.MarqueeSelection);
113
- this.selectStatus = "start";
114
- }).on("move", ({ store: { changed: { added, removed } }, selection, event }) => {
115
- if (event) {
116
- this.selectStatus = "moving";
117
- }
118
- if (!this.canInteract(this.pluginId, "select", InteractionPriority.MarqueeSelection)) {
119
- selection.cancel();
120
- endSelect();
121
- return;
122
- }
123
- const addedNodeIds = [];
124
- added.forEach((el) => {
125
- if (el.className.includes(nodeWrapperClassName)) {
126
- el.classList.add(nodeClassName);
127
- const nodeId = el.getAttribute("data-node-id");
128
- if (nodeId)
129
- addedNodeIds.push(nodeId);
117
+ });
118
+ __publicField(this, "onMove", ({ store: { stored, changed: { added, removed } }, selection }) => {
119
+ const getSelectedElements = () => {
120
+ return stored.reduce((dict, item) => {
121
+ const rule = this.getElementRule(item);
122
+ if (rule) {
123
+ dict[rule.type] = [...dict[rule.type] || [], { id: rule.idGetter(item), element: item }];
124
+ }
125
+ return dict;
126
+ }, {});
127
+ };
128
+ const context = {
129
+ isDragging: this.isDragging,
130
+ getSelectedElements,
131
+ select: (elements) => {
132
+ elements.forEach((element) => {
133
+ selection.select(element);
134
+ });
135
+ },
136
+ deselect: (elements) => {
137
+ elements.forEach((element) => {
138
+ selection.deselect(element);
139
+ });
140
+ }
141
+ };
142
+ removed.forEach((element) => {
143
+ const rule = this.getElementRule(element);
144
+ if (!rule) {
145
+ return;
146
+ }
147
+ if (rule.activeClassName) {
148
+ element.classList.remove(rule.activeClassName);
130
149
  }
131
150
  });
132
- const removedNodeIds = [];
133
- removed.forEach((el) => {
134
- if (el.className.includes(nodeWrapperClassName)) {
135
- el.classList.remove(nodeClassName);
136
- const nodeId = el.getAttribute("data-node-id");
137
- if (nodeId)
138
- removedNodeIds.push(nodeId);
151
+ added.forEach((element) => {
152
+ const rule = this.getElementRule(element);
153
+ if (!rule) {
154
+ return;
155
+ }
156
+ const type = rule.type;
157
+ const id = rule.idGetter(element);
158
+ for (const [, rule2] of this.ruleMap) {
159
+ if (rule2.onSelected) {
160
+ if (!rule2.onSelected(__spreadValues({ element, type, id }, context))) {
161
+ selection.deselect(element, true);
162
+ return;
163
+ }
164
+ }
165
+ }
166
+ if (rule.activeClassName) {
167
+ element.classList.add(rule.activeClassName);
139
168
  }
140
169
  });
141
- this.updateSelection(addedNodeIds, removedNodeIds);
142
- }).on("stop", ({ event }) => {
170
+ });
171
+ __publicField(this, "onStop", ({ event }) => {
172
+ this.endInteraction(this.pluginId, "select");
143
173
  if (event) {
144
- endSelect();
174
+ if (this.isDragging) {
175
+ this.isDragging = false;
176
+ }
145
177
  }
178
+ cancelAnimationFrame(this.updateFrameId);
179
+ this.updateFrameId = requestAnimationFrame(this.updateSelection);
180
+ });
181
+ __publicField(this, "updateSelection", () => {
182
+ var _a2;
183
+ const selected = [];
184
+ for (const element of ((_a2 = this.selection) == null ? void 0 : _a2.getSelection()) || []) {
185
+ const rule = this.getElementRule(element);
186
+ if (rule) {
187
+ selected.push({ type: rule.type, id: rule.idGetter(element) });
188
+ }
189
+ }
190
+ this.selected = selected;
146
191
  });
147
192
  }
148
- // 更新选中的节点和组
149
- updateSelection(addedNodeIds = [], removedNodeIds = []) {
150
- const currentNodeIds = this.selectedNodeIds;
151
- const newNodeIds = [
152
- ...currentNodeIds.filter((id) => !removedNodeIds.includes(id)),
153
- ...addedNodeIds.filter((id) => !currentNodeIds.includes(id))
154
- ];
155
- this.selectedNodeIds = newNodeIds;
156
- }
157
- getSelectedNodeIds() {
158
- return this.selectedNodeIds;
193
+ init(config = {}) {
194
+ this.container = config.container || bemSelector("canvas", "wrapper");
195
+ this.selectionAreaClassName = config.selectionAreaClassName || bem("selection-area");
196
+ if (!config.disableDefaultRules) {
197
+ const nodeRule = {
198
+ type: "node",
199
+ className: bem("node", "wrapper"),
200
+ activeClassName: bem("node", "wrapper", "selected"),
201
+ idGetter: (element) => element.getAttribute("data-node-id") || ""
202
+ };
203
+ this.ruleMap.set(nodeRule.className, nodeRule);
204
+ }
205
+ for (const rule of config.rules || []) {
206
+ this.ruleMap.set(rule.className, rule);
207
+ }
208
+ if (config.enableDrag !== void 0) {
209
+ this.enableDrag = config.enableDrag;
210
+ }
211
+ queueMicrotask(() => this.createSelection());
159
212
  }
160
- clearSelection() {
161
- this.selectedNodeIds = [];
213
+ createSelection() {
214
+ const container = this.container;
215
+ this.selection = new SelectionArea({
216
+ // container,
217
+ boundaries: [container],
218
+ selectionAreaClass: this.selectionAreaClassName,
219
+ selectables: Array.from(this.ruleMap.keys()).map((className) => `.${className}`)
220
+ }).on("beforedrag", this.onBeforeDrag).on("beforestart", this.onBeforeStart).on("start", this.onStart).on("move", this.onMove).on("stop", this.onStop);
162
221
  }
163
- // 选择节点
164
- selectNodes(nodeIds, clearPrevious = true) {
165
- if (clearPrevious) {
166
- this.selectedNodeIds = nodeIds;
167
- } else {
168
- const currentNodeIds = this.selectedNodeIds;
169
- this.selectedNodeIds = [
170
- ...currentNodeIds,
171
- ...nodeIds.filter((id) => !currentNodeIds.includes(id))
172
- ];
222
+ getElementRule(element) {
223
+ for (const [className, rule] of this.ruleMap) {
224
+ if (element.classList.contains(className)) {
225
+ return rule;
226
+ }
173
227
  }
228
+ return void 0;
229
+ }
230
+ getSelected() {
231
+ return this.selected;
232
+ }
233
+ clearSelection() {
234
+ var _a2;
235
+ (_a2 = this.selection) == null ? void 0 : _a2.clearSelection(true, false);
174
236
  }
175
237
  destroy() {
176
238
  var _a2;
177
239
  (_a2 = this.selection) == null ? void 0 : _a2.destroy();
240
+ this.ruleMap.clear();
178
241
  }
179
242
  }
180
243
  _init = __decoratorStart(_a);
181
244
  __decorateElement(_init, 1, "init", _init_dec, Selection);
182
- __decorateElement(_init, 1, "getSelectedNodeIds", _getSelectedNodeIds_dec, Selection);
245
+ __decorateElement(_init, 1, "getSelected", _getSelected_dec, Selection);
183
246
  __decorateElement(_init, 1, "clearSelection", _clearSelection_dec, Selection);
184
247
  __decorateElement(_init, 1, "destroy", _destroy_dec, Selection);
185
- __decorateElement(_init, 5, "selectedNodeIds", _selectedNodeIds_dec, Selection);
186
- __decorateElement(_init, 5, "selectStatus", _selectStatus_dec, Selection);
248
+ __decorateElement(_init, 5, "selected", _selected_dec, Selection);
249
+ __decorateElement(_init, 5, "registerRules", _registerRules_dec, Selection);
187
250
  __decorateElement(_init, 5, "startInteraction", _startInteraction_dec, Selection);
188
251
  __decorateElement(_init, 5, "endInteraction", _endInteraction_dec, Selection);
189
252
  __decorateElement(_init, 5, "canInteract", _canInteract_dec, Selection);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knotx/plugins-selection",
3
- "version": "0.2.15",
3
+ "version": "0.3.1",
4
4
  "description": "Selection Plugin for Knotx",
5
5
  "author": "boenfu",
6
6
  "license": "MIT",
@@ -30,13 +30,13 @@
30
30
  "dependencies": {
31
31
  "@viselect/vanilla": "^3.9.0",
32
32
  "rxjs": "^7.8.1",
33
- "@knotx/core": "0.2.14",
34
- "@knotx/decorators": "0.2.15"
33
+ "@knotx/core": "0.3.1",
34
+ "@knotx/decorators": "0.3.1"
35
35
  },
36
36
  "devDependencies": {
37
- "@knotx/build-config": "0.2.13",
38
- "@knotx/eslint-config": "0.2.13",
39
- "@knotx/typescript-config": "0.2.13"
37
+ "@knotx/build-config": "0.3.1",
38
+ "@knotx/eslint-config": "0.3.1",
39
+ "@knotx/typescript-config": "0.3.1"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "unbuild",