@tft/interact 14.0.0 → 15.0.0
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/{esm2020 → esm2022}/index.mjs +5 -5
- package/{esm2020 → esm2022}/lib/directives/account-for-scale.directive.mjs +26 -26
- package/{esm2020 → esm2022}/lib/directives/apply-scale.directive.mjs +28 -28
- package/esm2022/lib/directives/auto-scroll.directive.mjs +56 -0
- package/{esm2020 → esm2022}/lib/directives/drag-preview.directive.mjs +20 -20
- package/{esm2020 → esm2022}/lib/directives/drag-root.directive.mjs +32 -32
- package/{esm2020 → esm2022}/lib/directives/draggable.directive.mjs +320 -320
- package/{esm2020 → esm2022}/lib/directives/dropzone.directive.mjs +114 -114
- package/{esm2020 → esm2022}/lib/directives/gesturable.directive.mjs +82 -82
- package/{esm2020 → esm2022}/lib/directives/index.mjs +9 -9
- package/esm2022/lib/directives/resizable.directive.mjs +228 -0
- package/{esm2020 → esm2022}/lib/interact.module.mjs +66 -66
- package/{esm2020 → esm2022}/lib/models/index.mjs +1 -1
- package/{esm2020 → esm2022}/lib/models/interact.mjs +27 -27
- package/{esm2020 → esm2022}/lib/pipes/array-of-n.pipe.mjs +22 -22
- package/{esm2020 → esm2022}/lib/pipes/index.mjs +1 -1
- package/{esm2020 → esm2022}/lib/services/interact.service.mjs +197 -197
- package/{esm2020 → esm2022}/lib/utils/helpers.mjs +34 -34
- package/{esm2020 → esm2022}/lib/utils/index.mjs +1 -1
- package/{esm2020 → esm2022}/tft-interact.mjs +4 -4
- package/{fesm2020 → fesm2022}/tft-interact.mjs +1155 -1155
- package/{fesm2020 → fesm2022}/tft-interact.mjs.map +1 -1
- package/index.d.ts +5 -5
- package/lib/directives/account-for-scale.directive.d.ts +15 -15
- package/lib/directives/apply-scale.directive.d.ts +11 -11
- package/lib/directives/auto-scroll.directive.d.ts +34 -34
- package/lib/directives/drag-preview.directive.d.ts +10 -10
- package/lib/directives/drag-root.directive.d.ts +15 -15
- package/lib/directives/draggable.directive.d.ts +76 -76
- package/lib/directives/dropzone.directive.d.ts +40 -40
- package/lib/directives/gesturable.directive.d.ts +27 -27
- package/lib/directives/index.d.ts +9 -9
- package/lib/directives/resizable.directive.d.ts +61 -61
- package/lib/interact.module.d.ts +20 -20
- package/lib/models/index.d.ts +1 -1
- package/lib/models/interact.d.ts +140 -140
- package/lib/pipes/array-of-n.pipe.d.ts +12 -12
- package/lib/pipes/index.d.ts +1 -1
- package/lib/services/interact.service.d.ts +83 -83
- package/lib/utils/helpers.d.ts +12 -12
- package/lib/utils/index.d.ts +1 -1
- package/package.json +7 -15
- package/tft-interact-15.0.0.tgz +0 -0
- package/esm2020/lib/directives/auto-scroll.directive.mjs +0 -56
- package/esm2020/lib/directives/resizable.directive.mjs +0 -228
- package/fesm2015/tft-interact.mjs +0 -1203
- package/fesm2015/tft-interact.mjs.map +0 -1
- package/tft-interact-14.0.0.tgz +0 -0
|
@@ -5,1187 +5,1187 @@ import interact from 'interactjs';
|
|
|
5
5
|
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
|
|
6
6
|
import { shareReplay, tap, map, scan } from 'rxjs/operators';
|
|
7
7
|
|
|
8
|
-
class ArrayOfNPipe {
|
|
9
|
-
/**
|
|
10
|
-
*
|
|
11
|
-
* @param n the number to make an array of
|
|
12
|
-
* @param max the max length of the array (useful for limiting rendering in ngFor loop)
|
|
13
|
-
*/
|
|
14
|
-
transform(n, max) {
|
|
15
|
-
const length = ((max && max < n) || n === Infinity) ? max : n;
|
|
16
|
-
return new Array(length).fill(length).map((x, i) => i);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
22
|
-
type: Pipe,
|
|
23
|
-
args: [{
|
|
24
|
-
name: 'arrayOfN'
|
|
25
|
-
}]
|
|
8
|
+
class ArrayOfNPipe {
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param n the number to make an array of
|
|
12
|
+
* @param max the max length of the array (useful for limiting rendering in ngFor loop)
|
|
13
|
+
*/
|
|
14
|
+
transform(n, max) {
|
|
15
|
+
const length = ((max && max < n) || n === Infinity) ? max : n;
|
|
16
|
+
return new Array(length).fill(length).map((x, i) => i);
|
|
17
|
+
}
|
|
18
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: ArrayOfNPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
19
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.0.9", ngImport: i0, type: ArrayOfNPipe, name: "arrayOfN" }); }
|
|
20
|
+
}
|
|
21
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: ArrayOfNPipe, decorators: [{
|
|
22
|
+
type: Pipe,
|
|
23
|
+
args: [{
|
|
24
|
+
name: 'arrayOfN'
|
|
25
|
+
}]
|
|
26
26
|
}] });
|
|
27
27
|
|
|
28
|
-
const INTERACT_ROOT_CONFIG = new InjectionToken('INTERACT_ROOT_CONFIG_PARAMS');
|
|
29
|
-
const DEFAULT_REGISTRY_ID = 'DEFAULT';
|
|
30
|
-
/**
|
|
31
|
-
* Default initial value for Delta BehaviorSubject
|
|
32
|
-
*/
|
|
33
|
-
const defaultDelta = {
|
|
34
|
-
deltaX: 0,
|
|
35
|
-
deltaY: 0,
|
|
36
|
-
targetElement: null
|
|
37
|
-
};
|
|
38
|
-
/**
|
|
39
|
-
* Default initial value for Size BehaviorSubject
|
|
40
|
-
*/
|
|
41
|
-
const defaultSize = {
|
|
42
|
-
width: null,
|
|
43
|
-
height: null,
|
|
44
|
-
targetElement: null
|
|
45
|
-
};
|
|
46
|
-
/**
|
|
47
|
-
* Default initial value for Position BehaviorSubject
|
|
48
|
-
*/
|
|
49
|
-
const defaultPosition = {
|
|
50
|
-
x: 0,
|
|
51
|
-
y: 0,
|
|
52
|
-
targetElement: null
|
|
28
|
+
const INTERACT_ROOT_CONFIG = new InjectionToken('INTERACT_ROOT_CONFIG_PARAMS');
|
|
29
|
+
const DEFAULT_REGISTRY_ID = 'DEFAULT';
|
|
30
|
+
/**
|
|
31
|
+
* Default initial value for Delta BehaviorSubject
|
|
32
|
+
*/
|
|
33
|
+
const defaultDelta = {
|
|
34
|
+
deltaX: 0,
|
|
35
|
+
deltaY: 0,
|
|
36
|
+
targetElement: null
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Default initial value for Size BehaviorSubject
|
|
40
|
+
*/
|
|
41
|
+
const defaultSize = {
|
|
42
|
+
width: null,
|
|
43
|
+
height: null,
|
|
44
|
+
targetElement: null
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Default initial value for Position BehaviorSubject
|
|
48
|
+
*/
|
|
49
|
+
const defaultPosition = {
|
|
50
|
+
x: 0,
|
|
51
|
+
y: 0,
|
|
52
|
+
targetElement: null
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
class InteractService {
|
|
56
|
-
constructor(rendererFactory, ngZone, rootConfig) {
|
|
57
|
-
this.rendererFactory = rendererFactory;
|
|
58
|
-
this.ngZone = ngZone;
|
|
59
|
-
this.rootConfig = rootConfig;
|
|
60
|
-
this._interactableIndex = 0;
|
|
61
|
-
this._dropzoneIndex = 0;
|
|
62
|
-
// TODO: consider using Map here
|
|
63
|
-
this.dragRegistrySystem = {};
|
|
64
|
-
this.cssUnit = 'px';
|
|
65
|
-
this.renderer = this.rendererFactory.createRenderer(null, null);
|
|
66
|
-
this.cssUnit = rootConfig?.cssDimensionUnit || 'px';
|
|
67
|
-
}
|
|
68
|
-
addDeltaToPosition(delta, position) {
|
|
69
|
-
return {
|
|
70
|
-
x: delta.deltaX + position.x,
|
|
71
|
-
y: delta.deltaY + position.y,
|
|
72
|
-
targetElement: position.targetElement || delta.targetElement
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
addRegistryToSystem(customRegistryId = null) {
|
|
76
|
-
const registryId = customRegistryId || this.createDropzoneId(this._dropzoneIndex++);
|
|
77
|
-
this.dragRegistrySystem[registryId] = {};
|
|
78
|
-
return registryId;
|
|
79
|
-
}
|
|
80
|
-
addDraggableToRegistry(customRegistryId = null, interactableId = null) {
|
|
81
|
-
const registryId = customRegistryId || DEFAULT_REGISTRY_ID;
|
|
82
|
-
// if we pass an id to createInteractableId then it is used when creating the interactable
|
|
83
|
-
// and returned, otherwise a new id is created for the draggable.
|
|
84
|
-
const key = this.createInteractableId(interactableId);
|
|
85
|
-
if (!Object.prototype.hasOwnProperty.call(this.dragRegistrySystem, registryId)) {
|
|
86
|
-
this.dragRegistrySystem[registryId] = {};
|
|
87
|
-
}
|
|
88
|
-
this.dragRegistrySystem[registryId][key] = this.createInteractableState(defaultPosition, defaultSize, defaultDelta);
|
|
89
|
-
return key;
|
|
90
|
-
}
|
|
91
|
-
destroyInteractable(interactableId, registryId = DEFAULT_REGISTRY_ID) {
|
|
92
|
-
const interactableSystem = this.dragRegistrySystem[registryId][interactableId];
|
|
93
|
-
if (interactableSystem) {
|
|
94
|
-
// unsubscribe from all the subscriptions if they're subscriptions
|
|
95
|
-
for (const propName in interactableSystem) {
|
|
96
|
-
const prop = interactableSystem[propName];
|
|
97
|
-
if (prop.unsubscribe && typeof prop.unsubscribe === 'function') {
|
|
98
|
-
prop.unsubscribe();
|
|
99
|
-
}
|
|
100
|
-
;
|
|
101
|
-
}
|
|
102
|
-
delete this.dragRegistrySystem[registryId][interactableId];
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
subscribeToInteractable(interactableId, registryId = DEFAULT_REGISTRY_ID) {
|
|
106
|
-
return this.dragRegistrySystem[registryId][interactableId];
|
|
107
|
-
}
|
|
108
|
-
createInteractableState(initialPosition, initialSize, initialDelta) {
|
|
109
|
-
const deltas$ = new BehaviorSubject(initialDelta);
|
|
110
|
-
// tracks the size of the element
|
|
111
|
-
const size$ = new BehaviorSubject({ ...initialSize, ...initialDelta });
|
|
112
|
-
// Stream of positions as they change
|
|
113
|
-
const position$ = new BehaviorSubject(initialPosition);
|
|
114
|
-
// All draggable data mapped together
|
|
115
|
-
const interactable$ = combineLatest([
|
|
116
|
-
size$.pipe(
|
|
117
|
-
// startWith({...initialSize, ...initialDelta}),
|
|
118
|
-
shareReplay(1),
|
|
119
|
-
// filter(resizeEvent => !!resizeEvent.targetElement),
|
|
120
|
-
tap(({ deltaX, deltaY, width, height, targetElement }) => {
|
|
121
|
-
this.ngZone.runOutsideAngular(() => {
|
|
122
|
-
this.setElementSize(width, height, targetElement);
|
|
123
|
-
});
|
|
124
|
-
// only reposition if necessary i.e when resizing left or up
|
|
125
|
-
if (deltaX || deltaY) {
|
|
126
|
-
deltas$.next({ deltaX, deltaY, targetElement });
|
|
127
|
-
}
|
|
128
|
-
})),
|
|
129
|
-
deltas$.pipe(shareReplay(1), tap((delta) => {
|
|
130
|
-
const position = position$.value;
|
|
131
|
-
const newPosition = this.addDeltaToPosition(delta, position);
|
|
132
|
-
position$.next(newPosition);
|
|
133
|
-
})),
|
|
134
|
-
position$.pipe(shareReplay(1), tap(position => {
|
|
135
|
-
this.ngZone.runOutsideAngular(() => {
|
|
136
|
-
this.setElementTransform(position.x, position.y, position);
|
|
137
|
-
});
|
|
138
|
-
}))
|
|
139
|
-
]).pipe(shareReplay(1), map(([size, deltas, position]) => {
|
|
140
|
-
return {
|
|
141
|
-
x: position.x,
|
|
142
|
-
y: position.y,
|
|
143
|
-
deltaX: deltas.deltaX,
|
|
144
|
-
deltaY: deltas.deltaY,
|
|
145
|
-
width: size.width,
|
|
146
|
-
height: size.height,
|
|
147
|
-
targetElement: size.targetElement || position.targetElement || deltas.targetElement
|
|
148
|
-
};
|
|
149
|
-
}));
|
|
150
|
-
// TODO: update system to handle only returning interactable$
|
|
151
|
-
return {
|
|
152
|
-
deltas$,
|
|
153
|
-
position$,
|
|
154
|
-
size$,
|
|
155
|
-
interactable$
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
createInteractableId(customInteractableId = null) {
|
|
159
|
-
return customInteractableId || `interactable${this._interactableIndex++}`;
|
|
160
|
-
}
|
|
161
|
-
createDropzoneId(index) {
|
|
162
|
-
return `dropzone${index}`;
|
|
163
|
-
}
|
|
164
|
-
getInteractableState(interactableId, registryId = DEFAULT_REGISTRY_ID) {
|
|
165
|
-
return this.dragRegistrySystem[registryId][interactableId].interactable$;
|
|
166
|
-
}
|
|
167
|
-
updateDeltas(interactId, registryId, { deltaX, deltaY }, targetElement) {
|
|
168
|
-
if (!this.interactableExistOnRegistry(interactId, registryId))
|
|
169
|
-
return;
|
|
170
|
-
this.dragRegistrySystem[registryId][interactId].deltas$.next({ deltaX, deltaY, targetElement });
|
|
171
|
-
}
|
|
172
|
-
updatePosition(interactId, registryId, { x, y }, targetElement) {
|
|
173
|
-
if (!this.interactableExistOnRegistry(interactId, registryId))
|
|
174
|
-
return;
|
|
175
|
-
this.dragRegistrySystem[registryId][interactId].position$.next({ x, y, targetElement });
|
|
176
|
-
}
|
|
177
|
-
updateSize(interactId, registryId, { deltaX, deltaY, width, height }, targetElement) {
|
|
178
|
-
if (!this.interactableExistOnRegistry(interactId, registryId))
|
|
179
|
-
return;
|
|
180
|
-
this.dragRegistrySystem[registryId][interactId].size$.next({ deltaX, deltaY, width, height, targetElement });
|
|
181
|
-
}
|
|
182
|
-
interactableExistOnRegistry(interactId, registryId = DEFAULT_REGISTRY_ID) {
|
|
183
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
184
|
-
return this.dragRegistrySystem.hasOwnProperty(registryId) && this.dragRegistrySystem[registryId].hasOwnProperty(interactId);
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Uses renderer to set width and height of angular component
|
|
188
|
-
* @param width the desired width of component
|
|
189
|
-
* @param height the desired height of component
|
|
190
|
-
* @param target the element to transform
|
|
191
|
-
*/
|
|
192
|
-
setElementSize(width, height, target) {
|
|
193
|
-
if (!target)
|
|
194
|
-
return;
|
|
195
|
-
this.renderer.setStyle(target, 'width', `${width}${this.cssUnit}`);
|
|
196
|
-
this.renderer.setStyle(target, 'height', `${height}${this.cssUnit}`);
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Uses renderer to set position of angular component
|
|
200
|
-
* @param x position on x axis
|
|
201
|
-
* @param y position on y axis
|
|
202
|
-
* @param target the element to transform
|
|
203
|
-
*/
|
|
204
|
-
setElementTransform(x, y, position) {
|
|
205
|
-
if (!position?.targetElement)
|
|
206
|
-
return;
|
|
207
|
-
this.renderer.setStyle(position.targetElement, 'left', `${x}${this.cssUnit}`);
|
|
208
|
-
this.renderer.setStyle(position.targetElement, 'top', `${y}${this.cssUnit}`);
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Generates a translate string for the x and y arguments passed to
|
|
212
|
-
* be passed to css transform
|
|
213
|
-
* @param x the position along the x axis
|
|
214
|
-
* @param y the position along the y axis
|
|
215
|
-
*/
|
|
216
|
-
createTransformString(x, y) {
|
|
217
|
-
return `translate3d(${x}${this.cssUnit}, ${y}${this.cssUnit}, 0)`;
|
|
218
|
-
}
|
|
219
|
-
calculatePositionInElement(zoneElement, dragElement, scale) {
|
|
220
|
-
// TODO: this calculation may not cover a lot of scenarios, keep an eye out for possible improvements
|
|
221
|
-
const zoneRect = zoneElement.getBoundingClientRect();
|
|
222
|
-
const dragRect = dragElement.getBoundingClientRect();
|
|
223
|
-
const position = scale
|
|
224
|
-
? {
|
|
225
|
-
x: (dragRect.left - zoneRect.left) / scale || 1,
|
|
226
|
-
y: (dragRect.top - zoneRect.top) / scale || 1
|
|
227
|
-
} : {
|
|
228
|
-
x: dragRect.left - zoneRect.left,
|
|
229
|
-
y: dragRect.top - zoneRect.top
|
|
230
|
-
};
|
|
231
|
-
// console.log({ y:position.y, drt:dragRect.top, zrt: zoneRect.top})
|
|
232
|
-
return position;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
238
|
-
type: Injectable,
|
|
239
|
-
args: [{ providedIn: 'root' }]
|
|
240
|
-
}], ctorParameters:
|
|
241
|
-
type: Optional
|
|
242
|
-
}, {
|
|
243
|
-
type: Inject,
|
|
244
|
-
args: [INTERACT_ROOT_CONFIG]
|
|
245
|
-
}] }]
|
|
55
|
+
class InteractService {
|
|
56
|
+
constructor(rendererFactory, ngZone, rootConfig) {
|
|
57
|
+
this.rendererFactory = rendererFactory;
|
|
58
|
+
this.ngZone = ngZone;
|
|
59
|
+
this.rootConfig = rootConfig;
|
|
60
|
+
this._interactableIndex = 0;
|
|
61
|
+
this._dropzoneIndex = 0;
|
|
62
|
+
// TODO: consider using Map here
|
|
63
|
+
this.dragRegistrySystem = {};
|
|
64
|
+
this.cssUnit = 'px';
|
|
65
|
+
this.renderer = this.rendererFactory.createRenderer(null, null);
|
|
66
|
+
this.cssUnit = rootConfig?.cssDimensionUnit || 'px';
|
|
67
|
+
}
|
|
68
|
+
addDeltaToPosition(delta, position) {
|
|
69
|
+
return {
|
|
70
|
+
x: delta.deltaX + position.x,
|
|
71
|
+
y: delta.deltaY + position.y,
|
|
72
|
+
targetElement: position.targetElement || delta.targetElement
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
addRegistryToSystem(customRegistryId = null) {
|
|
76
|
+
const registryId = customRegistryId || this.createDropzoneId(this._dropzoneIndex++);
|
|
77
|
+
this.dragRegistrySystem[registryId] = {};
|
|
78
|
+
return registryId;
|
|
79
|
+
}
|
|
80
|
+
addDraggableToRegistry(customRegistryId = null, interactableId = null) {
|
|
81
|
+
const registryId = customRegistryId || DEFAULT_REGISTRY_ID;
|
|
82
|
+
// if we pass an id to createInteractableId then it is used when creating the interactable
|
|
83
|
+
// and returned, otherwise a new id is created for the draggable.
|
|
84
|
+
const key = this.createInteractableId(interactableId);
|
|
85
|
+
if (!Object.prototype.hasOwnProperty.call(this.dragRegistrySystem, registryId)) {
|
|
86
|
+
this.dragRegistrySystem[registryId] = {};
|
|
87
|
+
}
|
|
88
|
+
this.dragRegistrySystem[registryId][key] = this.createInteractableState(defaultPosition, defaultSize, defaultDelta);
|
|
89
|
+
return key;
|
|
90
|
+
}
|
|
91
|
+
destroyInteractable(interactableId, registryId = DEFAULT_REGISTRY_ID) {
|
|
92
|
+
const interactableSystem = this.dragRegistrySystem[registryId][interactableId];
|
|
93
|
+
if (interactableSystem) {
|
|
94
|
+
// unsubscribe from all the subscriptions if they're subscriptions
|
|
95
|
+
for (const propName in interactableSystem) {
|
|
96
|
+
const prop = interactableSystem[propName];
|
|
97
|
+
if (prop.unsubscribe && typeof prop.unsubscribe === 'function') {
|
|
98
|
+
prop.unsubscribe();
|
|
99
|
+
}
|
|
100
|
+
;
|
|
101
|
+
}
|
|
102
|
+
delete this.dragRegistrySystem[registryId][interactableId];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
subscribeToInteractable(interactableId, registryId = DEFAULT_REGISTRY_ID) {
|
|
106
|
+
return this.dragRegistrySystem[registryId][interactableId];
|
|
107
|
+
}
|
|
108
|
+
createInteractableState(initialPosition, initialSize, initialDelta) {
|
|
109
|
+
const deltas$ = new BehaviorSubject(initialDelta);
|
|
110
|
+
// tracks the size of the element
|
|
111
|
+
const size$ = new BehaviorSubject({ ...initialSize, ...initialDelta });
|
|
112
|
+
// Stream of positions as they change
|
|
113
|
+
const position$ = new BehaviorSubject(initialPosition);
|
|
114
|
+
// All draggable data mapped together
|
|
115
|
+
const interactable$ = combineLatest([
|
|
116
|
+
size$.pipe(
|
|
117
|
+
// startWith({...initialSize, ...initialDelta}),
|
|
118
|
+
shareReplay(1),
|
|
119
|
+
// filter(resizeEvent => !!resizeEvent.targetElement),
|
|
120
|
+
tap(({ deltaX, deltaY, width, height, targetElement }) => {
|
|
121
|
+
this.ngZone.runOutsideAngular(() => {
|
|
122
|
+
this.setElementSize(width, height, targetElement);
|
|
123
|
+
});
|
|
124
|
+
// only reposition if necessary i.e when resizing left or up
|
|
125
|
+
if (deltaX || deltaY) {
|
|
126
|
+
deltas$.next({ deltaX, deltaY, targetElement });
|
|
127
|
+
}
|
|
128
|
+
})),
|
|
129
|
+
deltas$.pipe(shareReplay(1), tap((delta) => {
|
|
130
|
+
const position = position$.value;
|
|
131
|
+
const newPosition = this.addDeltaToPosition(delta, position);
|
|
132
|
+
position$.next(newPosition);
|
|
133
|
+
})),
|
|
134
|
+
position$.pipe(shareReplay(1), tap(position => {
|
|
135
|
+
this.ngZone.runOutsideAngular(() => {
|
|
136
|
+
this.setElementTransform(position.x, position.y, position);
|
|
137
|
+
});
|
|
138
|
+
}))
|
|
139
|
+
]).pipe(shareReplay(1), map(([size, deltas, position]) => {
|
|
140
|
+
return {
|
|
141
|
+
x: position.x,
|
|
142
|
+
y: position.y,
|
|
143
|
+
deltaX: deltas.deltaX,
|
|
144
|
+
deltaY: deltas.deltaY,
|
|
145
|
+
width: size.width,
|
|
146
|
+
height: size.height,
|
|
147
|
+
targetElement: size.targetElement || position.targetElement || deltas.targetElement
|
|
148
|
+
};
|
|
149
|
+
}));
|
|
150
|
+
// TODO: update system to handle only returning interactable$
|
|
151
|
+
return {
|
|
152
|
+
deltas$,
|
|
153
|
+
position$,
|
|
154
|
+
size$,
|
|
155
|
+
interactable$
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
createInteractableId(customInteractableId = null) {
|
|
159
|
+
return customInteractableId || `interactable${this._interactableIndex++}`;
|
|
160
|
+
}
|
|
161
|
+
createDropzoneId(index) {
|
|
162
|
+
return `dropzone${index}`;
|
|
163
|
+
}
|
|
164
|
+
getInteractableState(interactableId, registryId = DEFAULT_REGISTRY_ID) {
|
|
165
|
+
return this.dragRegistrySystem[registryId][interactableId].interactable$;
|
|
166
|
+
}
|
|
167
|
+
updateDeltas(interactId, registryId, { deltaX, deltaY }, targetElement) {
|
|
168
|
+
if (!this.interactableExistOnRegistry(interactId, registryId))
|
|
169
|
+
return;
|
|
170
|
+
this.dragRegistrySystem[registryId][interactId].deltas$.next({ deltaX, deltaY, targetElement });
|
|
171
|
+
}
|
|
172
|
+
updatePosition(interactId, registryId, { x, y }, targetElement) {
|
|
173
|
+
if (!this.interactableExistOnRegistry(interactId, registryId))
|
|
174
|
+
return;
|
|
175
|
+
this.dragRegistrySystem[registryId][interactId].position$.next({ x, y, targetElement });
|
|
176
|
+
}
|
|
177
|
+
updateSize(interactId, registryId, { deltaX, deltaY, width, height }, targetElement) {
|
|
178
|
+
if (!this.interactableExistOnRegistry(interactId, registryId))
|
|
179
|
+
return;
|
|
180
|
+
this.dragRegistrySystem[registryId][interactId].size$.next({ deltaX, deltaY, width, height, targetElement });
|
|
181
|
+
}
|
|
182
|
+
interactableExistOnRegistry(interactId, registryId = DEFAULT_REGISTRY_ID) {
|
|
183
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
184
|
+
return this.dragRegistrySystem.hasOwnProperty(registryId) && this.dragRegistrySystem[registryId].hasOwnProperty(interactId);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Uses renderer to set width and height of angular component
|
|
188
|
+
* @param width the desired width of component
|
|
189
|
+
* @param height the desired height of component
|
|
190
|
+
* @param target the element to transform
|
|
191
|
+
*/
|
|
192
|
+
setElementSize(width, height, target) {
|
|
193
|
+
if (!target)
|
|
194
|
+
return;
|
|
195
|
+
this.renderer.setStyle(target, 'width', `${width}${this.cssUnit}`);
|
|
196
|
+
this.renderer.setStyle(target, 'height', `${height}${this.cssUnit}`);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Uses renderer to set position of angular component
|
|
200
|
+
* @param x position on x axis
|
|
201
|
+
* @param y position on y axis
|
|
202
|
+
* @param target the element to transform
|
|
203
|
+
*/
|
|
204
|
+
setElementTransform(x, y, position) {
|
|
205
|
+
if (!position?.targetElement)
|
|
206
|
+
return;
|
|
207
|
+
this.renderer.setStyle(position.targetElement, 'left', `${x}${this.cssUnit}`);
|
|
208
|
+
this.renderer.setStyle(position.targetElement, 'top', `${y}${this.cssUnit}`);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Generates a translate string for the x and y arguments passed to
|
|
212
|
+
* be passed to css transform
|
|
213
|
+
* @param x the position along the x axis
|
|
214
|
+
* @param y the position along the y axis
|
|
215
|
+
*/
|
|
216
|
+
createTransformString(x, y) {
|
|
217
|
+
return `translate3d(${x}${this.cssUnit}, ${y}${this.cssUnit}, 0)`;
|
|
218
|
+
}
|
|
219
|
+
calculatePositionInElement(zoneElement, dragElement, scale) {
|
|
220
|
+
// TODO: this calculation may not cover a lot of scenarios, keep an eye out for possible improvements
|
|
221
|
+
const zoneRect = zoneElement.getBoundingClientRect();
|
|
222
|
+
const dragRect = dragElement.getBoundingClientRect();
|
|
223
|
+
const position = scale
|
|
224
|
+
? {
|
|
225
|
+
x: (dragRect.left - zoneRect.left) / scale || 1,
|
|
226
|
+
y: (dragRect.top - zoneRect.top) / scale || 1
|
|
227
|
+
} : {
|
|
228
|
+
x: dragRect.left - zoneRect.left,
|
|
229
|
+
y: dragRect.top - zoneRect.top
|
|
230
|
+
};
|
|
231
|
+
// console.log({ y:position.y, drt:dragRect.top, zrt: zoneRect.top})
|
|
232
|
+
return position;
|
|
233
|
+
}
|
|
234
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: InteractService, deps: [{ token: i0.RendererFactory2 }, { token: i0.NgZone }, { token: INTERACT_ROOT_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
235
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: InteractService, providedIn: 'root' }); }
|
|
236
|
+
}
|
|
237
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: InteractService, decorators: [{
|
|
238
|
+
type: Injectable,
|
|
239
|
+
args: [{ providedIn: 'root' }]
|
|
240
|
+
}], ctorParameters: () => [{ type: i0.RendererFactory2 }, { type: i0.NgZone }, { type: undefined, decorators: [{
|
|
241
|
+
type: Optional
|
|
242
|
+
}, {
|
|
243
|
+
type: Inject,
|
|
244
|
+
args: [INTERACT_ROOT_CONFIG]
|
|
245
|
+
}] }] });
|
|
246
246
|
|
|
247
|
-
/**
|
|
248
|
-
* Use to apply scale to the element and tell the drag and resize directives to account for the scale when
|
|
249
|
-
* @example <div tftAccountForScale [scale]="2.5"> <div tftDraggable> </div> </div>
|
|
250
|
-
* @note if `dragRoot` is used this directive should be used on the same element to ensure that the drag
|
|
251
|
-
* element accounts for scale
|
|
252
|
-
*/
|
|
253
|
-
class AccountForScaleDirective {
|
|
254
|
-
constructor(el) {
|
|
255
|
-
this.el = el;
|
|
256
|
-
// this setup allows consumers to set x, y scale independently or just set them both with scale
|
|
257
|
-
this.scale = 1;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
263
|
-
type: Directive,
|
|
264
|
-
args: [{
|
|
265
|
-
selector: '[tftAccountForScale]'
|
|
266
|
-
}]
|
|
267
|
-
}], ctorParameters:
|
|
268
|
-
type: Input
|
|
247
|
+
/**
|
|
248
|
+
* Use to apply scale to the element and tell the drag and resize directives to account for the scale when
|
|
249
|
+
* @example <div tftAccountForScale [scale]="2.5"> <div tftDraggable> </div> </div>
|
|
250
|
+
* @note if `dragRoot` is used this directive should be used on the same element to ensure that the drag
|
|
251
|
+
* element accounts for scale
|
|
252
|
+
*/
|
|
253
|
+
class AccountForScaleDirective {
|
|
254
|
+
constructor(el) {
|
|
255
|
+
this.el = el;
|
|
256
|
+
// this setup allows consumers to set x, y scale independently or just set them both with scale
|
|
257
|
+
this.scale = 1;
|
|
258
|
+
}
|
|
259
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: AccountForScaleDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
260
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: AccountForScaleDirective, selector: "[tftAccountForScale]", inputs: { scale: "scale" }, ngImport: i0 }); }
|
|
261
|
+
}
|
|
262
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: AccountForScaleDirective, decorators: [{
|
|
263
|
+
type: Directive,
|
|
264
|
+
args: [{
|
|
265
|
+
selector: '[tftAccountForScale]'
|
|
266
|
+
}]
|
|
267
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { scale: [{
|
|
268
|
+
type: Input
|
|
269
269
|
}] } });
|
|
270
270
|
|
|
271
|
-
class DropzoneDirective {
|
|
272
|
-
|
|
273
|
-
this.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
this.
|
|
277
|
-
this.
|
|
278
|
-
this.
|
|
279
|
-
|
|
280
|
-
this.
|
|
281
|
-
this.
|
|
282
|
-
|
|
283
|
-
this.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
ngOnInit() {
|
|
289
|
-
// connects
|
|
290
|
-
this.dropzone = this.connectDropzoneEvents(this.el.nativeElement, this.dropzoneConfig);
|
|
291
|
-
this.dropzoneId = this.interactService.addRegistryToSystem(this.dropzoneId);
|
|
292
|
-
}
|
|
293
|
-
ngOnChanges(changes) {
|
|
294
|
-
if (!changes.dropzoneConfig || !this.dropzone)
|
|
295
|
-
return;
|
|
296
|
-
// this.dropzone.unset();
|
|
297
|
-
// this.dropzone = this.connectDropzoneEvents(this.el.nativeElement, this.dropzoneConfig)
|
|
298
|
-
this.dropzone.dropzone(this.dropzoneConfig);
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Connects element to interacts dropzone events and returns a reference to the interactable
|
|
302
|
-
* @param nativeElement the element to tie drop events to
|
|
303
|
-
* @param dropzoneConfig the interact configuration to use when connecting
|
|
304
|
-
*/
|
|
305
|
-
connectDropzoneEvents(nativeElement, dropzoneConfig) {
|
|
306
|
-
return interact(nativeElement).dropzone(dropzoneConfig)
|
|
307
|
-
// TODO: investigate when this fires in different scenarios
|
|
308
|
-
.on('dropactivate', (event) => {
|
|
309
|
-
this.dropActivate.emit(this.mapDropzoneEvent(event));
|
|
310
|
-
})
|
|
311
|
-
.on('dragenter', (event) => {
|
|
312
|
-
this.renderer.setProperty(event.relatedTarget, 'dropTarget', this);
|
|
313
|
-
this.dragEnter.emit(this.mapDropzoneEvent(event));
|
|
314
|
-
})
|
|
315
|
-
.on('dragleave', (event) => {
|
|
316
|
-
if (event.relatedTarget.dropTarget === this) {
|
|
317
|
-
this.renderer.setProperty(event.relatedTarget, 'dropTarget', null);
|
|
318
|
-
}
|
|
319
|
-
this.dragLeave.emit(this.mapDropzoneEvent(event));
|
|
320
|
-
})
|
|
321
|
-
.on('drop', (event) => {
|
|
322
|
-
this.dragDrop.emit(this.mapDropzoneEvent(event));
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Maps the drop event emitted by interact to something a little easier to use
|
|
327
|
-
* @param event the drop event emitted by interact, extended with extra fields we added to
|
|
328
|
-
*/
|
|
329
|
-
mapDropzoneEvent(event) {
|
|
330
|
-
const zoneElement = event.target;
|
|
331
|
-
const dragElement = event.relatedTarget?.dragRef?.previewRef;
|
|
332
|
-
const scale = this.scale;
|
|
333
|
-
const positionInDropTarget = zoneElement && dragElement
|
|
334
|
-
? this.interactService.calculatePositionInElement(zoneElement, dragElement, scale)
|
|
335
|
-
: null;
|
|
336
|
-
return {
|
|
337
|
-
interactEvent: event,
|
|
338
|
-
dragRef: dragElement.dragRef,
|
|
339
|
-
dragOrigin: dragElement.dragOrigin,
|
|
340
|
-
dropTarget: event.relatedTarget.dropTarget,
|
|
341
|
-
positionInDropTarget
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
348
|
-
type: Directive,
|
|
349
|
-
args: [{
|
|
350
|
-
selector: '[tftDropzone]',
|
|
351
|
-
host: {
|
|
352
|
-
'[id]': 'dropzoneId'
|
|
353
|
-
}
|
|
354
|
-
}]
|
|
355
|
-
}], ctorParameters:
|
|
356
|
-
type: Optional
|
|
357
|
-
}] }]
|
|
358
|
-
type: Input
|
|
359
|
-
}], dropzoneConfig: [{
|
|
360
|
-
type: Input
|
|
361
|
-
}], dropzoneData: [{
|
|
362
|
-
type: Input
|
|
363
|
-
}], position: [{
|
|
364
|
-
type: Input
|
|
365
|
-
}, {
|
|
366
|
-
type: HostBinding,
|
|
367
|
-
args: ['style.position']
|
|
368
|
-
}], dropActivate: [{
|
|
369
|
-
type: Output
|
|
370
|
-
}], dragEnter: [{
|
|
371
|
-
type: Output
|
|
372
|
-
}], dragLeave: [{
|
|
373
|
-
type: Output
|
|
374
|
-
}], dragDrop: [{
|
|
375
|
-
type: Output
|
|
271
|
+
class DropzoneDirective {
|
|
272
|
+
get scale() {
|
|
273
|
+
return this.account_for_scale_dir?.scale;
|
|
274
|
+
}
|
|
275
|
+
constructor(el, renderer, interactService, account_for_scale_dir) {
|
|
276
|
+
this.el = el;
|
|
277
|
+
this.renderer = renderer;
|
|
278
|
+
this.interactService = interactService;
|
|
279
|
+
this.account_for_scale_dir = account_for_scale_dir;
|
|
280
|
+
this.dropzoneConfig = {};
|
|
281
|
+
this.position = 'relative';
|
|
282
|
+
// proxies to pass interact events through to consumer of directive
|
|
283
|
+
this.dropActivate = new EventEmitter();
|
|
284
|
+
this.dragEnter = new EventEmitter();
|
|
285
|
+
this.dragLeave = new EventEmitter();
|
|
286
|
+
this.dragDrop = new EventEmitter();
|
|
287
|
+
}
|
|
288
|
+
ngOnInit() {
|
|
289
|
+
// connects
|
|
290
|
+
this.dropzone = this.connectDropzoneEvents(this.el.nativeElement, this.dropzoneConfig);
|
|
291
|
+
this.dropzoneId = this.interactService.addRegistryToSystem(this.dropzoneId);
|
|
292
|
+
}
|
|
293
|
+
ngOnChanges(changes) {
|
|
294
|
+
if (!changes.dropzoneConfig || !this.dropzone)
|
|
295
|
+
return;
|
|
296
|
+
// this.dropzone.unset();
|
|
297
|
+
// this.dropzone = this.connectDropzoneEvents(this.el.nativeElement, this.dropzoneConfig)
|
|
298
|
+
this.dropzone.dropzone(this.dropzoneConfig);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Connects element to interacts dropzone events and returns a reference to the interactable
|
|
302
|
+
* @param nativeElement the element to tie drop events to
|
|
303
|
+
* @param dropzoneConfig the interact configuration to use when connecting
|
|
304
|
+
*/
|
|
305
|
+
connectDropzoneEvents(nativeElement, dropzoneConfig) {
|
|
306
|
+
return interact(nativeElement).dropzone(dropzoneConfig)
|
|
307
|
+
// TODO: investigate when this fires in different scenarios
|
|
308
|
+
.on('dropactivate', (event) => {
|
|
309
|
+
this.dropActivate.emit(this.mapDropzoneEvent(event));
|
|
310
|
+
})
|
|
311
|
+
.on('dragenter', (event) => {
|
|
312
|
+
this.renderer.setProperty(event.relatedTarget, 'dropTarget', this);
|
|
313
|
+
this.dragEnter.emit(this.mapDropzoneEvent(event));
|
|
314
|
+
})
|
|
315
|
+
.on('dragleave', (event) => {
|
|
316
|
+
if (event.relatedTarget.dropTarget === this) {
|
|
317
|
+
this.renderer.setProperty(event.relatedTarget, 'dropTarget', null);
|
|
318
|
+
}
|
|
319
|
+
this.dragLeave.emit(this.mapDropzoneEvent(event));
|
|
320
|
+
})
|
|
321
|
+
.on('drop', (event) => {
|
|
322
|
+
this.dragDrop.emit(this.mapDropzoneEvent(event));
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Maps the drop event emitted by interact to something a little easier to use
|
|
327
|
+
* @param event the drop event emitted by interact, extended with extra fields we added to
|
|
328
|
+
*/
|
|
329
|
+
mapDropzoneEvent(event) {
|
|
330
|
+
const zoneElement = event.target;
|
|
331
|
+
const dragElement = event.relatedTarget?.dragRef?.previewRef;
|
|
332
|
+
const scale = this.scale;
|
|
333
|
+
const positionInDropTarget = zoneElement && dragElement
|
|
334
|
+
? this.interactService.calculatePositionInElement(zoneElement, dragElement, scale)
|
|
335
|
+
: null;
|
|
336
|
+
return {
|
|
337
|
+
interactEvent: event,
|
|
338
|
+
dragRef: dragElement.dragRef,
|
|
339
|
+
dragOrigin: dragElement.dragOrigin,
|
|
340
|
+
dropTarget: event.relatedTarget.dropTarget,
|
|
341
|
+
positionInDropTarget
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: DropzoneDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: InteractService }, { token: AccountForScaleDirective, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
345
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: DropzoneDirective, selector: "[tftDropzone]", inputs: { dropzoneId: "dropzoneId", dropzoneConfig: "dropzoneConfig", dropzoneData: "dropzoneData", position: "position" }, outputs: { dropActivate: "dropActivate", dragEnter: "dragEnter", dragLeave: "dragLeave", dragDrop: "dragDrop" }, host: { properties: { "id": "dropzoneId", "style.position": "this.position" } }, usesOnChanges: true, ngImport: i0 }); }
|
|
346
|
+
}
|
|
347
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: DropzoneDirective, decorators: [{
|
|
348
|
+
type: Directive,
|
|
349
|
+
args: [{
|
|
350
|
+
selector: '[tftDropzone]',
|
|
351
|
+
host: {
|
|
352
|
+
'[id]': 'dropzoneId'
|
|
353
|
+
}
|
|
354
|
+
}]
|
|
355
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: InteractService }, { type: AccountForScaleDirective, decorators: [{
|
|
356
|
+
type: Optional
|
|
357
|
+
}] }], propDecorators: { dropzoneId: [{
|
|
358
|
+
type: Input
|
|
359
|
+
}], dropzoneConfig: [{
|
|
360
|
+
type: Input
|
|
361
|
+
}], dropzoneData: [{
|
|
362
|
+
type: Input
|
|
363
|
+
}], position: [{
|
|
364
|
+
type: Input
|
|
365
|
+
}, {
|
|
366
|
+
type: HostBinding,
|
|
367
|
+
args: ['style.position']
|
|
368
|
+
}], dropActivate: [{
|
|
369
|
+
type: Output
|
|
370
|
+
}], dragEnter: [{
|
|
371
|
+
type: Output
|
|
372
|
+
}], dragLeave: [{
|
|
373
|
+
type: Output
|
|
374
|
+
}], dragDrop: [{
|
|
375
|
+
type: Output
|
|
376
376
|
}] } });
|
|
377
377
|
|
|
378
|
-
const TFT_DRAG_PREVIEW = new InjectionToken('DragPreviewDirective');
|
|
379
|
-
class DragPreviewDirective {
|
|
380
|
-
constructor(templateRef) {
|
|
381
|
-
this.templateRef = templateRef;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
387
|
-
type: Directive,
|
|
388
|
-
args: [{
|
|
389
|
-
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
390
|
-
selector: 'ng-template[tftDragPreview]',
|
|
391
|
-
}]
|
|
392
|
-
}], ctorParameters:
|
|
393
|
-
type: Input
|
|
378
|
+
const TFT_DRAG_PREVIEW = new InjectionToken('DragPreviewDirective');
|
|
379
|
+
class DragPreviewDirective {
|
|
380
|
+
constructor(templateRef) {
|
|
381
|
+
this.templateRef = templateRef;
|
|
382
|
+
}
|
|
383
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: DragPreviewDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
384
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: DragPreviewDirective, selector: "ng-template[tftDragPreview]", inputs: { dragData: "dragData" }, ngImport: i0 }); }
|
|
385
|
+
}
|
|
386
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: DragPreviewDirective, decorators: [{
|
|
387
|
+
type: Directive,
|
|
388
|
+
args: [{
|
|
389
|
+
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
390
|
+
selector: 'ng-template[tftDragPreview]',
|
|
391
|
+
}]
|
|
392
|
+
}], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { dragData: [{
|
|
393
|
+
type: Input
|
|
394
394
|
}] } });
|
|
395
395
|
|
|
396
|
-
/** Gets the closest ancestor of an element that matches a selector. */
|
|
397
|
-
function getClosestMatchingAncestor(element, selector) {
|
|
398
|
-
let currentElement = element.parentElement;
|
|
399
|
-
while (currentElement) {
|
|
400
|
-
// IE doesn't support `matches` so we have to fall back to `msMatchesSelector`.
|
|
401
|
-
if (currentElement.matches ? currentElement.matches(selector) :
|
|
402
|
-
currentElement.msMatchesSelector(selector)) {
|
|
403
|
-
return currentElement;
|
|
404
|
-
}
|
|
405
|
-
currentElement = currentElement.parentElement;
|
|
406
|
-
}
|
|
407
|
-
return null;
|
|
408
|
-
}
|
|
409
|
-
/**
|
|
410
|
-
* Create a copy of the HTML Element
|
|
411
|
-
*/
|
|
412
|
-
function cloneElement$1(element) {
|
|
413
|
-
const clone = element.cloneNode(true);
|
|
414
|
-
clone.removeAttribute('id');
|
|
415
|
-
return clone;
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Gets the root HTML element of an embedded view.
|
|
419
|
-
* If the root is not an HTML element it gets wrapped in one.
|
|
420
|
-
*/
|
|
421
|
-
function getRootNode(viewRef, _document) {
|
|
422
|
-
const rootNodes = viewRef.rootNodes;
|
|
423
|
-
if (rootNodes.length === 1 && rootNodes[0].nodeType === _document.ELEMENT_NODE) {
|
|
424
|
-
return rootNodes[0];
|
|
425
|
-
}
|
|
426
|
-
const wrapper = _document.createElement('div');
|
|
427
|
-
rootNodes.forEach(node => wrapper.appendChild(node));
|
|
428
|
-
return wrapper;
|
|
396
|
+
/** Gets the closest ancestor of an element that matches a selector. */
|
|
397
|
+
function getClosestMatchingAncestor(element, selector) {
|
|
398
|
+
let currentElement = element.parentElement;
|
|
399
|
+
while (currentElement) {
|
|
400
|
+
// IE doesn't support `matches` so we have to fall back to `msMatchesSelector`.
|
|
401
|
+
if (currentElement.matches ? currentElement.matches(selector) :
|
|
402
|
+
currentElement.msMatchesSelector(selector)) {
|
|
403
|
+
return currentElement;
|
|
404
|
+
}
|
|
405
|
+
currentElement = currentElement.parentElement;
|
|
406
|
+
}
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Create a copy of the HTML Element
|
|
411
|
+
*/
|
|
412
|
+
function cloneElement$1(element) {
|
|
413
|
+
const clone = element.cloneNode(true);
|
|
414
|
+
clone.removeAttribute('id');
|
|
415
|
+
return clone;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Gets the root HTML element of an embedded view.
|
|
419
|
+
* If the root is not an HTML element it gets wrapped in one.
|
|
420
|
+
*/
|
|
421
|
+
function getRootNode(viewRef, _document) {
|
|
422
|
+
const rootNodes = viewRef.rootNodes;
|
|
423
|
+
if (rootNodes.length === 1 && rootNodes[0].nodeType === _document.ELEMENT_NODE) {
|
|
424
|
+
return rootNodes[0];
|
|
425
|
+
}
|
|
426
|
+
const wrapper = _document.createElement('div');
|
|
427
|
+
rootNodes.forEach(node => wrapper.appendChild(node));
|
|
428
|
+
return wrapper;
|
|
429
429
|
}
|
|
430
430
|
|
|
431
|
-
/**
|
|
432
|
-
* Use this directive to select which element to attach the element to while dragging
|
|
433
|
-
* @example <div tftDragRoot><div tftDraggable> </div> </div>
|
|
434
|
-
* @note this directive will overwrite any style transformations (e.g. transform: scale(2); )
|
|
435
|
-
*/
|
|
436
|
-
class DragRootDirective {
|
|
437
|
-
constructor(el,
|
|
438
|
-
// This is used when passing a dragRoot as in input to a draggable element that not a child of that dragRoot
|
|
439
|
-
// It allows the the interact service to check if the drag root has some scaling applied to it and account for it when the component is dragged
|
|
440
|
-
account_for_scale_dir) {
|
|
441
|
-
this.el = el;
|
|
442
|
-
this.account_for_scale_dir = account_for_scale_dir;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
448
|
-
type: Directive,
|
|
449
|
-
args: [{
|
|
450
|
-
selector: '[tftDragRoot]',
|
|
451
|
-
exportAs: 'tftDragRoot'
|
|
452
|
-
}]
|
|
453
|
-
}], ctorParameters:
|
|
454
|
-
type: Optional
|
|
455
|
-
}, {
|
|
456
|
-
type: Self
|
|
457
|
-
}] }]
|
|
431
|
+
/**
|
|
432
|
+
* Use this directive to select which element to attach the element to while dragging
|
|
433
|
+
* @example <div tftDragRoot><div tftDraggable> </div> </div>
|
|
434
|
+
* @note this directive will overwrite any style transformations (e.g. transform: scale(2); )
|
|
435
|
+
*/
|
|
436
|
+
class DragRootDirective {
|
|
437
|
+
constructor(el,
|
|
438
|
+
// This is used when passing a dragRoot as in input to a draggable element that not a child of that dragRoot
|
|
439
|
+
// It allows the the interact service to check if the drag root has some scaling applied to it and account for it when the component is dragged
|
|
440
|
+
account_for_scale_dir) {
|
|
441
|
+
this.el = el;
|
|
442
|
+
this.account_for_scale_dir = account_for_scale_dir;
|
|
443
|
+
}
|
|
444
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: DragRootDirective, deps: [{ token: i0.ElementRef }, { token: AccountForScaleDirective, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
445
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: DragRootDirective, selector: "[tftDragRoot]", exportAs: ["tftDragRoot"], ngImport: i0 }); }
|
|
446
|
+
}
|
|
447
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: DragRootDirective, decorators: [{
|
|
448
|
+
type: Directive,
|
|
449
|
+
args: [{
|
|
450
|
+
selector: '[tftDragRoot]',
|
|
451
|
+
exportAs: 'tftDragRoot'
|
|
452
|
+
}]
|
|
453
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: AccountForScaleDirective, decorators: [{
|
|
454
|
+
type: Optional
|
|
455
|
+
}, {
|
|
456
|
+
type: Self
|
|
457
|
+
}] }] });
|
|
458
458
|
|
|
459
|
-
;
|
|
460
|
-
/**
|
|
461
|
-
* Use to apply scale to the element and tell the drag and resize directives to account for the scale when
|
|
462
|
-
* @example <div tftAccountForScale [scale]="2.5"> <div tftDraggable> </div> </div>
|
|
463
|
-
* @note if `dragRoot` is used this directive should be used on the same element to ensure that the drag
|
|
464
|
-
* element accounts for scale
|
|
465
|
-
*/
|
|
466
|
-
class AutoScrollDirective {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
this.scrollObserver.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
this.
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
500
|
-
type: Directive,
|
|
501
|
-
args: [{
|
|
502
|
-
selector: '[tftAutoScroll]'
|
|
503
|
-
}]
|
|
504
|
-
}], ctorParameters:
|
|
505
|
-
type: Input
|
|
506
|
-
}], scroll: [{
|
|
507
|
-
type: HostListener,
|
|
508
|
-
args: ['scroll', ['$event']]
|
|
459
|
+
;
|
|
460
|
+
/**
|
|
461
|
+
* Use to apply scale to the element and tell the drag and resize directives to account for the scale when
|
|
462
|
+
* @example <div tftAccountForScale [scale]="2.5"> <div tftDraggable> </div> </div>
|
|
463
|
+
* @note if `dragRoot` is used this directive should be used on the same element to ensure that the drag
|
|
464
|
+
* element accounts for scale
|
|
465
|
+
*/
|
|
466
|
+
class AutoScrollDirective {
|
|
467
|
+
// this setup allows consumers to set x, y scale independently or just set them both with scale
|
|
468
|
+
scroll(scrollEvent) {
|
|
469
|
+
const target = scrollEvent.target;
|
|
470
|
+
const { scrollTop, scrollLeft } = target;
|
|
471
|
+
this.scrollSubject.next({ scrollTop, scrollLeft });
|
|
472
|
+
}
|
|
473
|
+
constructor(el) {
|
|
474
|
+
this.el = el;
|
|
475
|
+
/**
|
|
476
|
+
* Limit minimum time between scroll events in milliseconds
|
|
477
|
+
*/
|
|
478
|
+
this.autoScrollConfig = {
|
|
479
|
+
margin: 50,
|
|
480
|
+
distance: 3,
|
|
481
|
+
interval: 50,
|
|
482
|
+
speed: 300,
|
|
483
|
+
enabled: true
|
|
484
|
+
};
|
|
485
|
+
this.scrollDeltaObserver = new Subject();
|
|
486
|
+
const { scrollTop, scrollLeft } = el.nativeElement;
|
|
487
|
+
this.scrollSubject = new BehaviorSubject({ scrollTop, scrollLeft });
|
|
488
|
+
this.scrollObserver = this.scrollSubject.pipe(scan((previous, current) => {
|
|
489
|
+
const scrollTop = current.scrollTop - previous.scrollTop;
|
|
490
|
+
const scrollLeft = current.scrollLeft - previous.scrollLeft;
|
|
491
|
+
this.scrollDeltaObserver.next({ scrollTop, scrollLeft });
|
|
492
|
+
return current;
|
|
493
|
+
}), shareReplay(1));
|
|
494
|
+
this.scrollObserver.subscribe();
|
|
495
|
+
}
|
|
496
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: AutoScrollDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
497
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: AutoScrollDirective, selector: "[tftAutoScroll]", inputs: { autoScrollConfig: "autoScrollConfig" }, host: { listeners: { "scroll": "scroll($event)" } }, ngImport: i0 }); }
|
|
498
|
+
}
|
|
499
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: AutoScrollDirective, decorators: [{
|
|
500
|
+
type: Directive,
|
|
501
|
+
args: [{
|
|
502
|
+
selector: '[tftAutoScroll]'
|
|
503
|
+
}]
|
|
504
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { autoScrollConfig: [{
|
|
505
|
+
type: Input
|
|
506
|
+
}], scroll: [{
|
|
507
|
+
type: HostListener,
|
|
508
|
+
args: ['scroll', ['$event']]
|
|
509
509
|
}] } });
|
|
510
510
|
|
|
511
|
-
/** @dynamic */
|
|
512
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
513
|
-
class DraggableDirective {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
this.
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
this.
|
|
520
|
-
this.
|
|
521
|
-
this.
|
|
522
|
-
this.
|
|
523
|
-
this.
|
|
524
|
-
|
|
525
|
-
this.
|
|
526
|
-
this.
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
this.
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
this.
|
|
535
|
-
this.
|
|
536
|
-
this.
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
}
|
|
543
|
-
ngOnInit() {
|
|
544
|
-
this.interactable = this.initiateDragEvents(this.dragConfig, this.el.nativeElement);
|
|
545
|
-
this.dragRootEl = (this.dragRoot?.el?.nativeElement || this.drag_root_dir?.el?.nativeElement) || this._document.body;
|
|
546
|
-
// register with parent dropzone if it exists, otherwise use default
|
|
547
|
-
// this gives us a place on the registry to store our drag items that don't have a dropzone
|
|
548
|
-
this.registryId = this.dropzone_dir?.dropzoneId || DEFAULT_REGISTRY_ID;
|
|
549
|
-
// add draggable to directory and store its id
|
|
550
|
-
this.interactableId = this.interactService.addDraggableToRegistry(this.registryId, this.interactableId);
|
|
551
|
-
this.alignPositionWithInputs(this.x, this.y);
|
|
552
|
-
// cache subscription to interactable state so we can unsubscribe onDestroy
|
|
553
|
-
this.interactableState = this.interactService
|
|
554
|
-
.getInteractableState(this.interactableId, this.registryId);
|
|
555
|
-
// keep our cached position values in line with our drag state
|
|
556
|
-
this.interactableSubscription = this.interactableState.subscribe((state) => {
|
|
557
|
-
this.y = state.y;
|
|
558
|
-
this.x = state.x;
|
|
559
|
-
});
|
|
560
|
-
this.setDragConfig();
|
|
561
|
-
}
|
|
562
|
-
// TODO: watch config here as well and update interactable
|
|
563
|
-
ngOnChanges(changes) {
|
|
564
|
-
// we do this here instead of using a setter on the input so that it
|
|
565
|
-
// will only run once when there is a change to x and y
|
|
566
|
-
if (changes.y || changes.x) {
|
|
567
|
-
this.alignPositionWithInputs(this.x, this.y);
|
|
568
|
-
}
|
|
569
|
-
if (changes.dragConfig || changes.disabled || changes.dragDisabled) {
|
|
570
|
-
if (!this.interactable)
|
|
571
|
-
return;
|
|
572
|
-
this.setDragConfig();
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* @deprecated remove this in v13
|
|
576
|
-
*/
|
|
577
|
-
if (changes.disabled) {
|
|
578
|
-
console.warn(`It looks like your using the 'disabled' input on a tftDraggable directive, it has been deprecated and is replaced with 'dragDisabled', please migrate by v13`);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
setDragConfig() {
|
|
582
|
-
const enabled = !(this.disabled || this.dragDisabled);
|
|
583
|
-
const dragConfig = { ...this.dragConfig, enabled };
|
|
584
|
-
this.interactable.draggable(dragConfig);
|
|
585
|
-
}
|
|
586
|
-
ngAfterViewInit() {
|
|
587
|
-
this.addDragPropertiesToElement(this.el.nativeElement);
|
|
588
|
-
if (!this.dropzone_dir) {
|
|
589
|
-
this.previewRef = this.el.nativeElement;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
ngOnDestroy() {
|
|
593
|
-
// clean up state and subscriptions related to destroyed component
|
|
594
|
-
this.interactableSubscription.unsubscribe();
|
|
595
|
-
this.interactService.destroyInteractable(this.interactableId, this.registryId);
|
|
596
|
-
}
|
|
597
|
-
dragMoveListener(event, element) {
|
|
598
|
-
const { dx, dy } = event;
|
|
599
|
-
const scale = this.scale;
|
|
600
|
-
const deltaX = scale ? dx / scale : dx;
|
|
601
|
-
const deltaY = scale ? dy / scale : dy;
|
|
602
|
-
this.interactService.updateDeltas(this.interactableId, this.registryId, { deltaX, deltaY }, element);
|
|
603
|
-
}
|
|
604
|
-
setDragStyles(dragElement) {
|
|
605
|
-
this.renderer.setStyle(dragElement, 'touchAction', 'none');
|
|
606
|
-
this.renderer.setStyle(dragElement, 'zIndex', this.dragZIndex);
|
|
607
|
-
this.renderer.setStyle(dragElement, 'position', 'absolute');
|
|
608
|
-
}
|
|
609
|
-
addDragPropertiesToElement(nativeElement) {
|
|
610
|
-
this.renderer.setProperty(nativeElement, 'dropTarget', this.dropzone_dir || null);
|
|
611
|
-
this.renderer.setProperty(nativeElement, 'dragOrigin', this.dropzone_dir || null);
|
|
612
|
-
this.renderer.setProperty(nativeElement, 'dragRef', this);
|
|
613
|
-
}
|
|
614
|
-
mapDragEvent(event) {
|
|
615
|
-
const { target, dropzone } = event;
|
|
616
|
-
const dropzoneElement = dropzone?.target || target.dropTarget?.el.nativeElement;
|
|
617
|
-
const scale = this.scale;
|
|
618
|
-
const positionInDropTarget = target && dropzoneElement
|
|
619
|
-
? this.interactService.calculatePositionInElement(dropzoneElement, this.previewRef, scale)
|
|
620
|
-
: null;
|
|
621
|
-
return {
|
|
622
|
-
interactEvent: event,
|
|
623
|
-
dragRef: this,
|
|
624
|
-
dragOrigin: target.dragOrigin,
|
|
625
|
-
dropTarget: target.dropTarget,
|
|
626
|
-
positionInDropTarget
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
setPosition(x, y) {
|
|
630
|
-
this.interactService.updatePosition(this.interactableId, this.registryId, { x, y }, this.el.nativeElement);
|
|
631
|
-
}
|
|
632
|
-
alignPositionWithInputs(x, y) {
|
|
633
|
-
// short circuit if positions aren't numbers or if they haven't changed
|
|
634
|
-
if (!this.isValidPosition(x, y))
|
|
635
|
-
return;
|
|
636
|
-
this.interactService.updatePosition(this.interactableId, this.registryId, { x, y }, this.el.nativeElement);
|
|
637
|
-
}
|
|
638
|
-
isValidPosition(x, y) {
|
|
639
|
-
return this.isNumeric(x) && this.isNumeric(y);
|
|
640
|
-
}
|
|
641
|
-
// We use use this instead of isNaN here to try and help performance
|
|
642
|
-
// We should be able to reliably restrict to numbers or falsey values
|
|
643
|
-
isNumeric(num) {
|
|
644
|
-
return typeof num === 'number' && !isNaN(num);
|
|
645
|
-
}
|
|
646
|
-
initiateDragEvents(dragConfig, nativeElement) {
|
|
647
|
-
const defaultDragConfig = {
|
|
648
|
-
...dragConfig,
|
|
649
|
-
enabled: !(this.disabled || this.dragDisabled),
|
|
650
|
-
...(this.auto_scroll_dir && {
|
|
651
|
-
autoScroll: {
|
|
652
|
-
...this.auto_scroll_dir.autoScrollConfig,
|
|
653
|
-
container: this.auto_scroll_dir.el.nativeElement
|
|
654
|
-
}
|
|
655
|
-
})
|
|
656
|
-
};
|
|
657
|
-
return interact(nativeElement).draggable(defaultDragConfig)
|
|
658
|
-
.on('dragstart', (event) => {
|
|
659
|
-
const interaction = event.interaction;
|
|
660
|
-
// check if we should append drag element to body
|
|
661
|
-
if (this.enableDragDefault
|
|
662
|
-
&& interaction.pointerIsDown
|
|
663
|
-
// TODO: probably don't need following condition checks anymore remove by 2022
|
|
664
|
-
// && !!this.dropzone_dir
|
|
665
|
-
// && !interaction.interacting()
|
|
666
|
-
) {
|
|
667
|
-
if (this._previewTemplate) {
|
|
668
|
-
const viewRef = this._viewContainerRef.createEmbeddedView(this._previewTemplate.templateRef);
|
|
669
|
-
this.previewRef = getRootNode(viewRef, this._document);
|
|
670
|
-
}
|
|
671
|
-
else {
|
|
672
|
-
this.previewRef = cloneElement(this.el.nativeElement);
|
|
673
|
-
}
|
|
674
|
-
this.addDragPropertiesToElement(this.previewRef);
|
|
675
|
-
this.setDragStyles(this.previewRef);
|
|
676
|
-
this.dragRootEl.prepend(this.previewRef);
|
|
677
|
-
const scale = this.account_for_scale_dir?.scale || this.dragRoot?.account_for_scale_dir?.scale || 1;
|
|
678
|
-
const { x, y } = this.interactService.calculatePositionInElement(this.dragRootEl, nativeElement, scale);
|
|
679
|
-
this.interactService.updatePosition(this.interactableId, this.registryId, { x, y }, this.previewRef);
|
|
680
|
-
if (!this.showPlaceholder) {
|
|
681
|
-
this.renderer.setStyle(this.el.nativeElement, 'display', 'none');
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
// subscribe to scroll events if they are there, by only subscribing on dragstart we avoid wasting subscriptions on interactables that aren't be dragged
|
|
685
|
-
if (this.auto_scroll_dir) {
|
|
686
|
-
this.subscribeToScrollEvents();
|
|
687
|
-
}
|
|
688
|
-
this.dragStart.emit(this.mapDragEvent(event));
|
|
689
|
-
})
|
|
690
|
-
.on('dragmove', (event) => {
|
|
691
|
-
if (this.enableDragDefault) {
|
|
692
|
-
const dragElement = this.dropzone_dir && this.previewRef || nativeElement;
|
|
693
|
-
this.dragMoveListener(event, dragElement);
|
|
694
|
-
}
|
|
695
|
-
const mappedEvent = this.mapDragEvent(event);
|
|
696
|
-
this.dragMove.emit(mappedEvent);
|
|
697
|
-
})
|
|
698
|
-
.on('draginertiastart', (event) => {
|
|
699
|
-
this.dragInertiaStart.emit(this.mapDragEvent(event));
|
|
700
|
-
})
|
|
701
|
-
.on('dragend', (event) => {
|
|
702
|
-
const mappedEvent = this.mapDragEvent(event);
|
|
703
|
-
if (!!this.dropzone_dir && this.dropzone_dir === event.target.dropTarget) {
|
|
704
|
-
const { x, y } = mappedEvent.positionInDropTarget;
|
|
705
|
-
this.setPosition(x, y);
|
|
706
|
-
}
|
|
707
|
-
this.renderer.setStyle(this.el.nativeElement, 'display', '');
|
|
708
|
-
this.dragEnd.emit(mappedEvent);
|
|
709
|
-
// unsubscribe from scroll events if subscribed
|
|
710
|
-
if (this.auto_scroll_dir) {
|
|
711
|
-
this.scrollEventsSubscription.unsubscribe();
|
|
712
|
-
}
|
|
713
|
-
if (this.el.nativeElement !== this.previewRef) {
|
|
714
|
-
// we do this in a timeout, so that we don't remove before the dropzone can get the boundingElementRect
|
|
715
|
-
setTimeout(() => {
|
|
716
|
-
this.dragRootEl.removeChild(this.previewRef);
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
subscribeToScrollEvents() {
|
|
722
|
-
this.scrollEventsSubscription = this.auto_scroll_dir.scrollDeltaObserver.subscribe(({ scrollLeft, scrollTop }) => {
|
|
723
|
-
const deltaX = this.scale ? scrollLeft / this.scale : scrollLeft;
|
|
724
|
-
const deltaY = this.scale ? scrollTop / this.scale : scrollTop;
|
|
725
|
-
this.interactService.updateDeltas(this.interactableId, this.registryId, { deltaX, deltaY }, this.previewRef);
|
|
726
|
-
});
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
732
|
-
type: Directive,
|
|
733
|
-
args: [{
|
|
734
|
-
selector: '[tftDraggable]',
|
|
735
|
-
// eslint-disable-next-line @angular-eslint/no-host-metadata-property
|
|
736
|
-
host: {
|
|
737
|
-
'[style.touchAction]': 'this.dragDisabled ? "auto" : "none"',
|
|
738
|
-
'[style.position]': '"absolute"',
|
|
739
|
-
'[id]': 'interactableId',
|
|
740
|
-
}
|
|
741
|
-
}]
|
|
742
|
-
}], ctorParameters:
|
|
743
|
-
type: Inject,
|
|
744
|
-
args: [DOCUMENT]
|
|
745
|
-
}] }, { type: AccountForScaleDirective, decorators: [{
|
|
746
|
-
type: Optional
|
|
747
|
-
}] }, { type: DropzoneDirective, decorators: [{
|
|
748
|
-
type: Optional
|
|
749
|
-
}, {
|
|
750
|
-
type: SkipSelf
|
|
751
|
-
}] }, { type: DragRootDirective, decorators: [{
|
|
752
|
-
type: Optional
|
|
753
|
-
}, {
|
|
754
|
-
type: SkipSelf
|
|
755
|
-
}] }, { type: AutoScrollDirective, decorators: [{
|
|
756
|
-
type: Optional
|
|
757
|
-
}, {
|
|
758
|
-
type: SkipSelf
|
|
759
|
-
}] }]
|
|
760
|
-
type: Input
|
|
761
|
-
}], y: [{
|
|
762
|
-
type: Input
|
|
763
|
-
}], dragZIndex: [{
|
|
764
|
-
type: Input
|
|
765
|
-
}], zIndex: [{
|
|
766
|
-
type: Input
|
|
767
|
-
}], interactableId: [{
|
|
768
|
-
type: Input
|
|
769
|
-
}], dragData: [{
|
|
770
|
-
type: Input
|
|
771
|
-
}], enableDragDefault: [{
|
|
772
|
-
type: Input
|
|
773
|
-
}], disabled: [{
|
|
774
|
-
type: Input
|
|
775
|
-
}], dragDisabled: [{
|
|
776
|
-
type: Input
|
|
777
|
-
}], dragConfig: [{
|
|
778
|
-
type: Input
|
|
779
|
-
}], showPlaceholder: [{
|
|
780
|
-
type: Input
|
|
781
|
-
}], dragRoot: [{
|
|
782
|
-
type: Input
|
|
783
|
-
}], dragStart: [{
|
|
784
|
-
type: Output
|
|
785
|
-
}], dragMove: [{
|
|
786
|
-
type: Output
|
|
787
|
-
}], dragInertiaStart: [{
|
|
788
|
-
type: Output
|
|
789
|
-
}], dragEnd: [{
|
|
790
|
-
type: Output
|
|
791
|
-
}], _previewTemplate: [{
|
|
792
|
-
type: ContentChild,
|
|
793
|
-
args: [DragPreviewDirective]
|
|
794
|
-
}] } });
|
|
795
|
-
/**
|
|
796
|
-
* Component utils
|
|
797
|
-
*/
|
|
798
|
-
// create a clone of the component passed in and add it to the root component
|
|
799
|
-
function cloneElement(element) {
|
|
800
|
-
const clone = element.cloneNode(true);
|
|
801
|
-
clone.removeAttribute('id');
|
|
802
|
-
return clone;
|
|
803
|
-
}
|
|
804
|
-
function getPreviewInsertionPoint(documentRef) {
|
|
805
|
-
// We can't use the body if the user is in fullscreen mode,
|
|
806
|
-
// because the preview will render under the fullscreen element.
|
|
807
|
-
return documentRef.fullscreenElement ||
|
|
808
|
-
documentRef.webkitFullscreenElement ||
|
|
809
|
-
documentRef.mozFullScreenElement ||
|
|
810
|
-
documentRef.msFullscreenElement ||
|
|
811
|
-
documentRef.body;
|
|
511
|
+
/** @dynamic */
|
|
512
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
513
|
+
class DraggableDirective {
|
|
514
|
+
// check all the different places for scale
|
|
515
|
+
get scale() {
|
|
516
|
+
return this.account_for_scale_dir?.scale || this.drag_root_dir?.account_for_scale_dir?.scale || this.dragRoot?.account_for_scale_dir?.scale || 1;
|
|
517
|
+
}
|
|
518
|
+
constructor(el, interactService, renderer, _viewContainerRef, _document, account_for_scale_dir, dropzone_dir, drag_root_dir, auto_scroll_dir) {
|
|
519
|
+
this.el = el;
|
|
520
|
+
this.interactService = interactService;
|
|
521
|
+
this.renderer = renderer;
|
|
522
|
+
this._viewContainerRef = _viewContainerRef;
|
|
523
|
+
this._document = _document;
|
|
524
|
+
this.account_for_scale_dir = account_for_scale_dir;
|
|
525
|
+
this.dropzone_dir = dropzone_dir;
|
|
526
|
+
this.drag_root_dir = drag_root_dir;
|
|
527
|
+
this.auto_scroll_dir = auto_scroll_dir;
|
|
528
|
+
/* zIndex while dragging*/
|
|
529
|
+
this.dragZIndex = 10000;
|
|
530
|
+
this.enableDragDefault = true;
|
|
531
|
+
/**
|
|
532
|
+
* @deprecated replaced by 'dragDisabled' property, please migrate before v13
|
|
533
|
+
*/
|
|
534
|
+
this.disabled = false;
|
|
535
|
+
this.dragDisabled = false;
|
|
536
|
+
this.showPlaceholder = false;
|
|
537
|
+
// pipes all interact events to event emitters
|
|
538
|
+
this.dragStart = new EventEmitter();
|
|
539
|
+
this.dragMove = new EventEmitter();
|
|
540
|
+
this.dragInertiaStart = new EventEmitter();
|
|
541
|
+
this.dragEnd = new EventEmitter();
|
|
542
|
+
}
|
|
543
|
+
ngOnInit() {
|
|
544
|
+
this.interactable = this.initiateDragEvents(this.dragConfig, this.el.nativeElement);
|
|
545
|
+
this.dragRootEl = (this.dragRoot?.el?.nativeElement || this.drag_root_dir?.el?.nativeElement) || this._document.body;
|
|
546
|
+
// register with parent dropzone if it exists, otherwise use default
|
|
547
|
+
// this gives us a place on the registry to store our drag items that don't have a dropzone
|
|
548
|
+
this.registryId = this.dropzone_dir?.dropzoneId || DEFAULT_REGISTRY_ID;
|
|
549
|
+
// add draggable to directory and store its id
|
|
550
|
+
this.interactableId = this.interactService.addDraggableToRegistry(this.registryId, this.interactableId);
|
|
551
|
+
this.alignPositionWithInputs(this.x, this.y);
|
|
552
|
+
// cache subscription to interactable state so we can unsubscribe onDestroy
|
|
553
|
+
this.interactableState = this.interactService
|
|
554
|
+
.getInteractableState(this.interactableId, this.registryId);
|
|
555
|
+
// keep our cached position values in line with our drag state
|
|
556
|
+
this.interactableSubscription = this.interactableState.subscribe((state) => {
|
|
557
|
+
this.y = state.y;
|
|
558
|
+
this.x = state.x;
|
|
559
|
+
});
|
|
560
|
+
this.setDragConfig();
|
|
561
|
+
}
|
|
562
|
+
// TODO: watch config here as well and update interactable
|
|
563
|
+
ngOnChanges(changes) {
|
|
564
|
+
// we do this here instead of using a setter on the input so that it
|
|
565
|
+
// will only run once when there is a change to x and y
|
|
566
|
+
if (changes.y || changes.x) {
|
|
567
|
+
this.alignPositionWithInputs(this.x, this.y);
|
|
568
|
+
}
|
|
569
|
+
if (changes.dragConfig || changes.disabled || changes.dragDisabled) {
|
|
570
|
+
if (!this.interactable)
|
|
571
|
+
return;
|
|
572
|
+
this.setDragConfig();
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* @deprecated remove this in v13
|
|
576
|
+
*/
|
|
577
|
+
if (changes.disabled) {
|
|
578
|
+
console.warn(`It looks like your using the 'disabled' input on a tftDraggable directive, it has been deprecated and is replaced with 'dragDisabled', please migrate by v13`);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
setDragConfig() {
|
|
582
|
+
const enabled = !(this.disabled || this.dragDisabled);
|
|
583
|
+
const dragConfig = { ...this.dragConfig, enabled };
|
|
584
|
+
this.interactable.draggable(dragConfig);
|
|
585
|
+
}
|
|
586
|
+
ngAfterViewInit() {
|
|
587
|
+
this.addDragPropertiesToElement(this.el.nativeElement);
|
|
588
|
+
if (!this.dropzone_dir) {
|
|
589
|
+
this.previewRef = this.el.nativeElement;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
ngOnDestroy() {
|
|
593
|
+
// clean up state and subscriptions related to destroyed component
|
|
594
|
+
this.interactableSubscription.unsubscribe();
|
|
595
|
+
this.interactService.destroyInteractable(this.interactableId, this.registryId);
|
|
596
|
+
}
|
|
597
|
+
dragMoveListener(event, element) {
|
|
598
|
+
const { dx, dy } = event;
|
|
599
|
+
const scale = this.scale;
|
|
600
|
+
const deltaX = scale ? dx / scale : dx;
|
|
601
|
+
const deltaY = scale ? dy / scale : dy;
|
|
602
|
+
this.interactService.updateDeltas(this.interactableId, this.registryId, { deltaX, deltaY }, element);
|
|
603
|
+
}
|
|
604
|
+
setDragStyles(dragElement) {
|
|
605
|
+
this.renderer.setStyle(dragElement, 'touchAction', 'none');
|
|
606
|
+
this.renderer.setStyle(dragElement, 'zIndex', this.dragZIndex);
|
|
607
|
+
this.renderer.setStyle(dragElement, 'position', 'absolute');
|
|
608
|
+
}
|
|
609
|
+
addDragPropertiesToElement(nativeElement) {
|
|
610
|
+
this.renderer.setProperty(nativeElement, 'dropTarget', this.dropzone_dir || null);
|
|
611
|
+
this.renderer.setProperty(nativeElement, 'dragOrigin', this.dropzone_dir || null);
|
|
612
|
+
this.renderer.setProperty(nativeElement, 'dragRef', this);
|
|
613
|
+
}
|
|
614
|
+
mapDragEvent(event) {
|
|
615
|
+
const { target, dropzone } = event;
|
|
616
|
+
const dropzoneElement = dropzone?.target || target.dropTarget?.el.nativeElement;
|
|
617
|
+
const scale = this.scale;
|
|
618
|
+
const positionInDropTarget = target && dropzoneElement
|
|
619
|
+
? this.interactService.calculatePositionInElement(dropzoneElement, this.previewRef, scale)
|
|
620
|
+
: null;
|
|
621
|
+
return {
|
|
622
|
+
interactEvent: event,
|
|
623
|
+
dragRef: this,
|
|
624
|
+
dragOrigin: target.dragOrigin,
|
|
625
|
+
dropTarget: target.dropTarget,
|
|
626
|
+
positionInDropTarget
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
setPosition(x, y) {
|
|
630
|
+
this.interactService.updatePosition(this.interactableId, this.registryId, { x, y }, this.el.nativeElement);
|
|
631
|
+
}
|
|
632
|
+
alignPositionWithInputs(x, y) {
|
|
633
|
+
// short circuit if positions aren't numbers or if they haven't changed
|
|
634
|
+
if (!this.isValidPosition(x, y))
|
|
635
|
+
return;
|
|
636
|
+
this.interactService.updatePosition(this.interactableId, this.registryId, { x, y }, this.el.nativeElement);
|
|
637
|
+
}
|
|
638
|
+
isValidPosition(x, y) {
|
|
639
|
+
return this.isNumeric(x) && this.isNumeric(y);
|
|
640
|
+
}
|
|
641
|
+
// We use use this instead of isNaN here to try and help performance
|
|
642
|
+
// We should be able to reliably restrict to numbers or falsey values
|
|
643
|
+
isNumeric(num) {
|
|
644
|
+
return typeof num === 'number' && !isNaN(num);
|
|
645
|
+
}
|
|
646
|
+
initiateDragEvents(dragConfig, nativeElement) {
|
|
647
|
+
const defaultDragConfig = {
|
|
648
|
+
...dragConfig,
|
|
649
|
+
enabled: !(this.disabled || this.dragDisabled),
|
|
650
|
+
...(this.auto_scroll_dir && {
|
|
651
|
+
autoScroll: {
|
|
652
|
+
...this.auto_scroll_dir.autoScrollConfig,
|
|
653
|
+
container: this.auto_scroll_dir.el.nativeElement
|
|
654
|
+
}
|
|
655
|
+
})
|
|
656
|
+
};
|
|
657
|
+
return interact(nativeElement).draggable(defaultDragConfig)
|
|
658
|
+
.on('dragstart', (event) => {
|
|
659
|
+
const interaction = event.interaction;
|
|
660
|
+
// check if we should append drag element to body
|
|
661
|
+
if (this.enableDragDefault
|
|
662
|
+
&& interaction.pointerIsDown
|
|
663
|
+
// TODO: probably don't need following condition checks anymore remove by 2022
|
|
664
|
+
// && !!this.dropzone_dir
|
|
665
|
+
// && !interaction.interacting()
|
|
666
|
+
) {
|
|
667
|
+
if (this._previewTemplate) {
|
|
668
|
+
const viewRef = this._viewContainerRef.createEmbeddedView(this._previewTemplate.templateRef);
|
|
669
|
+
this.previewRef = getRootNode(viewRef, this._document);
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
this.previewRef = cloneElement(this.el.nativeElement);
|
|
673
|
+
}
|
|
674
|
+
this.addDragPropertiesToElement(this.previewRef);
|
|
675
|
+
this.setDragStyles(this.previewRef);
|
|
676
|
+
this.dragRootEl.prepend(this.previewRef);
|
|
677
|
+
const scale = this.account_for_scale_dir?.scale || this.dragRoot?.account_for_scale_dir?.scale || 1;
|
|
678
|
+
const { x, y } = this.interactService.calculatePositionInElement(this.dragRootEl, nativeElement, scale);
|
|
679
|
+
this.interactService.updatePosition(this.interactableId, this.registryId, { x, y }, this.previewRef);
|
|
680
|
+
if (!this.showPlaceholder) {
|
|
681
|
+
this.renderer.setStyle(this.el.nativeElement, 'display', 'none');
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
// subscribe to scroll events if they are there, by only subscribing on dragstart we avoid wasting subscriptions on interactables that aren't be dragged
|
|
685
|
+
if (this.auto_scroll_dir) {
|
|
686
|
+
this.subscribeToScrollEvents();
|
|
687
|
+
}
|
|
688
|
+
this.dragStart.emit(this.mapDragEvent(event));
|
|
689
|
+
})
|
|
690
|
+
.on('dragmove', (event) => {
|
|
691
|
+
if (this.enableDragDefault) {
|
|
692
|
+
const dragElement = this.dropzone_dir && this.previewRef || nativeElement;
|
|
693
|
+
this.dragMoveListener(event, dragElement);
|
|
694
|
+
}
|
|
695
|
+
const mappedEvent = this.mapDragEvent(event);
|
|
696
|
+
this.dragMove.emit(mappedEvent);
|
|
697
|
+
})
|
|
698
|
+
.on('draginertiastart', (event) => {
|
|
699
|
+
this.dragInertiaStart.emit(this.mapDragEvent(event));
|
|
700
|
+
})
|
|
701
|
+
.on('dragend', (event) => {
|
|
702
|
+
const mappedEvent = this.mapDragEvent(event);
|
|
703
|
+
if (!!this.dropzone_dir && this.dropzone_dir === event.target.dropTarget) {
|
|
704
|
+
const { x, y } = mappedEvent.positionInDropTarget;
|
|
705
|
+
this.setPosition(x, y);
|
|
706
|
+
}
|
|
707
|
+
this.renderer.setStyle(this.el.nativeElement, 'display', '');
|
|
708
|
+
this.dragEnd.emit(mappedEvent);
|
|
709
|
+
// unsubscribe from scroll events if subscribed
|
|
710
|
+
if (this.auto_scroll_dir) {
|
|
711
|
+
this.scrollEventsSubscription.unsubscribe();
|
|
712
|
+
}
|
|
713
|
+
if (this.el.nativeElement !== this.previewRef) {
|
|
714
|
+
// we do this in a timeout, so that we don't remove before the dropzone can get the boundingElementRect
|
|
715
|
+
setTimeout(() => {
|
|
716
|
+
this.dragRootEl.removeChild(this.previewRef);
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
subscribeToScrollEvents() {
|
|
722
|
+
this.scrollEventsSubscription = this.auto_scroll_dir.scrollDeltaObserver.subscribe(({ scrollLeft, scrollTop }) => {
|
|
723
|
+
const deltaX = this.scale ? scrollLeft / this.scale : scrollLeft;
|
|
724
|
+
const deltaY = this.scale ? scrollTop / this.scale : scrollTop;
|
|
725
|
+
this.interactService.updateDeltas(this.interactableId, this.registryId, { deltaX, deltaY }, this.previewRef);
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: DraggableDirective, deps: [{ token: i0.ElementRef }, { token: InteractService }, { token: i0.Renderer2 }, { token: i0.ViewContainerRef }, { token: DOCUMENT }, { token: AccountForScaleDirective, optional: true }, { token: DropzoneDirective, optional: true, skipSelf: true }, { token: DragRootDirective, optional: true, skipSelf: true }, { token: AutoScrollDirective, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
729
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: DraggableDirective, selector: "[tftDraggable]", inputs: { x: "x", y: "y", dragZIndex: "dragZIndex", zIndex: "zIndex", interactableId: "interactableId", dragData: "dragData", enableDragDefault: "enableDragDefault", disabled: "disabled", dragDisabled: "dragDisabled", dragConfig: "dragConfig", showPlaceholder: "showPlaceholder", dragRoot: "dragRoot" }, outputs: { dragStart: "dragStart", dragMove: "dragMove", dragInertiaStart: "dragInertiaStart", dragEnd: "dragEnd" }, host: { properties: { "style.touchAction": "this.dragDisabled ? \"auto\" : \"none\"", "style.position": "\"absolute\"", "id": "interactableId" } }, queries: [{ propertyName: "_previewTemplate", first: true, predicate: DragPreviewDirective, descendants: true }], usesOnChanges: true, ngImport: i0 }); }
|
|
730
|
+
}
|
|
731
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: DraggableDirective, decorators: [{
|
|
732
|
+
type: Directive,
|
|
733
|
+
args: [{
|
|
734
|
+
selector: '[tftDraggable]',
|
|
735
|
+
// eslint-disable-next-line @angular-eslint/no-host-metadata-property
|
|
736
|
+
host: {
|
|
737
|
+
'[style.touchAction]': 'this.dragDisabled ? "auto" : "none"',
|
|
738
|
+
'[style.position]': '"absolute"',
|
|
739
|
+
'[id]': 'interactableId',
|
|
740
|
+
}
|
|
741
|
+
}]
|
|
742
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: InteractService }, { type: i0.Renderer2 }, { type: i0.ViewContainerRef }, { type: Document, decorators: [{
|
|
743
|
+
type: Inject,
|
|
744
|
+
args: [DOCUMENT]
|
|
745
|
+
}] }, { type: AccountForScaleDirective, decorators: [{
|
|
746
|
+
type: Optional
|
|
747
|
+
}] }, { type: DropzoneDirective, decorators: [{
|
|
748
|
+
type: Optional
|
|
749
|
+
}, {
|
|
750
|
+
type: SkipSelf
|
|
751
|
+
}] }, { type: DragRootDirective, decorators: [{
|
|
752
|
+
type: Optional
|
|
753
|
+
}, {
|
|
754
|
+
type: SkipSelf
|
|
755
|
+
}] }, { type: AutoScrollDirective, decorators: [{
|
|
756
|
+
type: Optional
|
|
757
|
+
}, {
|
|
758
|
+
type: SkipSelf
|
|
759
|
+
}] }], propDecorators: { x: [{
|
|
760
|
+
type: Input
|
|
761
|
+
}], y: [{
|
|
762
|
+
type: Input
|
|
763
|
+
}], dragZIndex: [{
|
|
764
|
+
type: Input
|
|
765
|
+
}], zIndex: [{
|
|
766
|
+
type: Input
|
|
767
|
+
}], interactableId: [{
|
|
768
|
+
type: Input
|
|
769
|
+
}], dragData: [{
|
|
770
|
+
type: Input
|
|
771
|
+
}], enableDragDefault: [{
|
|
772
|
+
type: Input
|
|
773
|
+
}], disabled: [{
|
|
774
|
+
type: Input
|
|
775
|
+
}], dragDisabled: [{
|
|
776
|
+
type: Input
|
|
777
|
+
}], dragConfig: [{
|
|
778
|
+
type: Input
|
|
779
|
+
}], showPlaceholder: [{
|
|
780
|
+
type: Input
|
|
781
|
+
}], dragRoot: [{
|
|
782
|
+
type: Input
|
|
783
|
+
}], dragStart: [{
|
|
784
|
+
type: Output
|
|
785
|
+
}], dragMove: [{
|
|
786
|
+
type: Output
|
|
787
|
+
}], dragInertiaStart: [{
|
|
788
|
+
type: Output
|
|
789
|
+
}], dragEnd: [{
|
|
790
|
+
type: Output
|
|
791
|
+
}], _previewTemplate: [{
|
|
792
|
+
type: ContentChild,
|
|
793
|
+
args: [DragPreviewDirective]
|
|
794
|
+
}] } });
|
|
795
|
+
/**
|
|
796
|
+
* Component utils
|
|
797
|
+
*/
|
|
798
|
+
// create a clone of the component passed in and add it to the root component
|
|
799
|
+
function cloneElement(element) {
|
|
800
|
+
const clone = element.cloneNode(true);
|
|
801
|
+
clone.removeAttribute('id');
|
|
802
|
+
return clone;
|
|
803
|
+
}
|
|
804
|
+
function getPreviewInsertionPoint(documentRef) {
|
|
805
|
+
// We can't use the body if the user is in fullscreen mode,
|
|
806
|
+
// because the preview will render under the fullscreen element.
|
|
807
|
+
return documentRef.fullscreenElement ||
|
|
808
|
+
documentRef.webkitFullscreenElement ||
|
|
809
|
+
documentRef.mozFullScreenElement ||
|
|
810
|
+
documentRef.msFullscreenElement ||
|
|
811
|
+
documentRef.body;
|
|
812
812
|
}
|
|
813
813
|
|
|
814
|
-
/** @dynamic */
|
|
815
|
-
class ResizableDirective {
|
|
816
|
-
|
|
817
|
-
this.
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
this.
|
|
821
|
-
this.
|
|
822
|
-
this.
|
|
823
|
-
this.
|
|
824
|
-
this.
|
|
825
|
-
this.
|
|
826
|
-
this.
|
|
827
|
-
|
|
828
|
-
this.
|
|
829
|
-
this.
|
|
830
|
-
this
|
|
831
|
-
this.
|
|
832
|
-
this.
|
|
833
|
-
this.
|
|
834
|
-
this.
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
this.
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
}
|
|
843
|
-
ngOnInit() {
|
|
844
|
-
this.addResizePropertiesToElement(this.el.nativeElement);
|
|
845
|
-
// we check for a dropzone, we use its id as the registry id if there is on
|
|
846
|
-
// otherwise, we use DEFAULT_REGISTRY_ID as a registry id. This allows us to keep our interactable
|
|
847
|
-
// drag state organized by dropzones.
|
|
848
|
-
this.registryId = this.dropzone_dir?.dropzoneId || DEFAULT_REGISTRY_ID;
|
|
849
|
-
this.interactableId = this.draggable_dir?.interactableId || this.interactService.addDraggableToRegistry(this.registryId, this.interactableId);
|
|
850
|
-
this.interactable = this.initiateResizeEvents({ ...this.defaultConfig, ...this.resizeConfig }, this.el.nativeElement);
|
|
851
|
-
this.alignDimensionsWithInputs(this.width, this.height);
|
|
852
|
-
this.interactableSubscription = this.interactService
|
|
853
|
-
.getInteractableState(this.interactableId, this.registryId)
|
|
854
|
-
.subscribe();
|
|
855
|
-
}
|
|
856
|
-
ngOnChanges(changes) {
|
|
857
|
-
if ((changes.resizeConfig || changes.resizeDisabled) && this.interactable) {
|
|
858
|
-
this.interactable.resizable({ ...this.resizeConfig, enabled: !this.resizeDisabled, });
|
|
859
|
-
}
|
|
860
|
-
if (changes.width || changes.height) {
|
|
861
|
-
this.alignDimensionsWithInputs(this.width, this.height);
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
ngOnDestroy() {
|
|
865
|
-
this.interactableSubscription.unsubscribe();
|
|
866
|
-
this.interactService.destroyInteractable(this.interactableId, this.registryId);
|
|
867
|
-
}
|
|
868
|
-
resizeListener(event) {
|
|
869
|
-
const element = this.el.nativeElement;
|
|
870
|
-
const scale = this.scale;
|
|
871
|
-
const { deltaRect } = event;
|
|
872
|
-
const deltaX = deltaRect.left / scale;
|
|
873
|
-
const deltaY = deltaRect.top / scale;
|
|
874
|
-
// We get the width and height directly from the native element because
|
|
875
|
-
// the event dimension can get out of sync when resizing with autoScroll
|
|
876
|
-
const rect = element.getBoundingClientRect();
|
|
877
|
-
const width = (rect.width + deltaRect.width) / scale;
|
|
878
|
-
const height = (rect.height + deltaRect.height) / scale;
|
|
879
|
-
this.interactService.updateSize(this.interactableId, this.registryId, { deltaX, deltaY, width, height }, this.el.nativeElement);
|
|
880
|
-
}
|
|
881
|
-
/**
|
|
882
|
-
* hook elements into interacts resize event listeners
|
|
883
|
-
* we spread the configs so that the consuming component only overwrites the
|
|
884
|
-
* pieces that it explicitly indicates
|
|
885
|
-
* @param resizeConfig
|
|
886
|
-
* @param nativeElement
|
|
887
|
-
*/
|
|
888
|
-
initiateResizeEvents(resizeConfig, nativeElement) {
|
|
889
|
-
// TODO: This should try and get interactable from tft_draggable if it exists
|
|
890
|
-
const defaultResizeConfig = {
|
|
891
|
-
...resizeConfig,
|
|
892
|
-
enabled: !this.resizeDisabled,
|
|
893
|
-
...(this.auto_scroll_dir && {
|
|
894
|
-
autoScroll: {
|
|
895
|
-
...this.auto_scroll_dir.autoScrollConfig,
|
|
896
|
-
container: this.auto_scroll_dir.el.nativeElement
|
|
897
|
-
}
|
|
898
|
-
})
|
|
899
|
-
};
|
|
900
|
-
const interactable = this.draggable_dir?.interactable || interact(nativeElement);
|
|
901
|
-
return interactable.resizable(defaultResizeConfig)
|
|
902
|
-
.on('resizestart', (event) => {
|
|
903
|
-
this.activeEdges = event.edges;
|
|
904
|
-
if (this.auto_scroll_dir) {
|
|
905
|
-
this.subscribeToScrollEvents();
|
|
906
|
-
}
|
|
907
|
-
this.resizeStart.emit(this.mapResizeEvent(event));
|
|
908
|
-
})
|
|
909
|
-
.on('resizemove', (event) => {
|
|
910
|
-
if (this.enableResizeDefault) {
|
|
911
|
-
this.resizeListener(event);
|
|
912
|
-
}
|
|
913
|
-
const mappedEvent = this.mapResizeEvent(event);
|
|
914
|
-
this.resizeMove.emit(mappedEvent);
|
|
915
|
-
})
|
|
916
|
-
.on('resizeinertiastart', (event) => this.resizeInertiaStart.emit(this.mapResizeEvent(event)))
|
|
917
|
-
.on('resizeend', (event) => {
|
|
918
|
-
if (this.auto_scroll_dir) {
|
|
919
|
-
this.scrollEventsSubscription.unsubscribe();
|
|
920
|
-
}
|
|
921
|
-
this.activeEdges = { left: false, right: false, top: false, bottom: false };
|
|
922
|
-
this.resizeEnd.emit(this.mapResizeEvent(event));
|
|
923
|
-
});
|
|
924
|
-
}
|
|
925
|
-
mapResizeEvent(event) {
|
|
926
|
-
const target = this.el.nativeElement;
|
|
927
|
-
const relatedTarget = this.draggable_dir?.dropzone_dir?.el.nativeElement;
|
|
928
|
-
const scale = this.scale;
|
|
929
|
-
const positionInDropTarget = target && relatedTarget
|
|
930
|
-
? this.interactService.calculatePositionInElement(relatedTarget, target, scale)
|
|
931
|
-
: null;
|
|
932
|
-
return {
|
|
933
|
-
interactEvent: event,
|
|
934
|
-
resizeRef: this,
|
|
935
|
-
dragRef: this.draggable_dir,
|
|
936
|
-
dragOrigin: this.dropzone_dir,
|
|
937
|
-
dropTarget: this.el.nativeElement.dropTarget,
|
|
938
|
-
positionInDropTarget,
|
|
939
|
-
size: {
|
|
940
|
-
width: target.clientWidth / scale,
|
|
941
|
-
height: target.clientHeight / scale
|
|
942
|
-
}
|
|
943
|
-
};
|
|
944
|
-
}
|
|
945
|
-
alignDimensionsWithInputs(width, height) {
|
|
946
|
-
this.interactService.updateSize(this.interactableId, this.registryId, { deltaX: 0, deltaY: 0, width, height }, this.el.nativeElement);
|
|
947
|
-
}
|
|
948
|
-
addResizePropertiesToElement(nativeElement) {
|
|
949
|
-
this.renderer.setProperty(nativeElement, 'resizeRef', this);
|
|
950
|
-
}
|
|
951
|
-
subscribeToScrollEvents() {
|
|
952
|
-
this.scrollEventsSubscription = this.auto_scroll_dir.scrollDeltaObserver.subscribe(({ scrollLeft, scrollTop }) => {
|
|
953
|
-
const scale = this.scale;
|
|
954
|
-
const target = this.el.nativeElement;
|
|
955
|
-
const { width: prevWidth, height: prevHeight } = target.getBoundingClientRect();
|
|
956
|
-
const deltaHeight = scrollTop * (this.activeEdges.top ? -1 : this.activeEdges.bottom ? 1 : 0);
|
|
957
|
-
const deltaWidth = scrollLeft * (this.activeEdges.left ? -1 : this.activeEdges.right ? 1 : 0);
|
|
958
|
-
const height = (prevHeight + deltaHeight) / scale;
|
|
959
|
-
const width = (prevWidth + deltaWidth) / scale;
|
|
960
|
-
const deltaX = this.activeEdges.left ? (scrollLeft / scale) : 0;
|
|
961
|
-
const deltaY = this.activeEdges.top ? (scrollTop / scale) : 0;
|
|
962
|
-
this.interactService.updateSize(this.interactableId, this.registryId, { deltaX, deltaY, width, height }, this.el.nativeElement);
|
|
963
|
-
});
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
969
|
-
type: Directive,
|
|
970
|
-
args: [{
|
|
971
|
-
selector: '[tftResizable]',
|
|
972
|
-
// eslint-disable-next-line @angular-eslint/no-host-metadata-property
|
|
973
|
-
host: {
|
|
974
|
-
// prevents touch events from colliding with with mouse events
|
|
975
|
-
// on touch screen
|
|
976
|
-
'[style.touchAction]': 'this.resizeDisabled ? "auto" : "none"',
|
|
977
|
-
// default to absolute here to accommodate likely use cases
|
|
978
|
-
// consuming component can easily over ride with position input
|
|
979
|
-
'[style.position]': 'position',
|
|
980
|
-
// follows interactjs suggested practices
|
|
981
|
-
'[style.boxSizing]': '"border-box"',
|
|
982
|
-
}
|
|
983
|
-
}]
|
|
984
|
-
}], ctorParameters:
|
|
985
|
-
type: Inject,
|
|
986
|
-
args: [DOCUMENT]
|
|
987
|
-
}] }, { type: InteractService }, { type: i0.Renderer2 }, { type: DragRootDirective, decorators: [{
|
|
988
|
-
type: Optional
|
|
989
|
-
}] }, { type: AccountForScaleDirective, decorators: [{
|
|
990
|
-
type: Optional
|
|
991
|
-
}] }, { type: DraggableDirective, decorators: [{
|
|
992
|
-
type: Optional
|
|
993
|
-
}] }, { type: DropzoneDirective, decorators: [{
|
|
994
|
-
type: Optional
|
|
995
|
-
}, {
|
|
996
|
-
type: SkipSelf
|
|
997
|
-
}] }, { type: AutoScrollDirective, decorators: [{
|
|
998
|
-
type: Optional
|
|
999
|
-
}, {
|
|
1000
|
-
type: SkipSelf
|
|
1001
|
-
}] }]
|
|
1002
|
-
type: Input
|
|
1003
|
-
}], position: [{
|
|
1004
|
-
type: Input
|
|
1005
|
-
}], resizeConfig: [{
|
|
1006
|
-
type: Input
|
|
1007
|
-
}], interactableId: [{
|
|
1008
|
-
type: Input
|
|
1009
|
-
}], width: [{
|
|
1010
|
-
type: Input
|
|
1011
|
-
}], height: [{
|
|
1012
|
-
type: Input
|
|
1013
|
-
}], resizeDisabled: [{
|
|
1014
|
-
type: Input
|
|
1015
|
-
}], resizeStart: [{
|
|
1016
|
-
type: Output
|
|
1017
|
-
}], resizeMove: [{
|
|
1018
|
-
type: Output
|
|
1019
|
-
}], resizeInertiaStart: [{
|
|
1020
|
-
type: Output
|
|
1021
|
-
}], resizeEnd: [{
|
|
1022
|
-
type: Output
|
|
814
|
+
/** @dynamic */
|
|
815
|
+
class ResizableDirective {
|
|
816
|
+
get scale() {
|
|
817
|
+
return this.account_for_scale_dir?.scale || this.drag_root_dir?.account_for_scale_dir?.scale;
|
|
818
|
+
}
|
|
819
|
+
constructor(el, _document, interactService, renderer, drag_root_dir, account_for_scale_dir, draggable_dir, dropzone_dir, auto_scroll_dir) {
|
|
820
|
+
this.el = el;
|
|
821
|
+
this._document = _document;
|
|
822
|
+
this.interactService = interactService;
|
|
823
|
+
this.renderer = renderer;
|
|
824
|
+
this.drag_root_dir = drag_root_dir;
|
|
825
|
+
this.account_for_scale_dir = account_for_scale_dir;
|
|
826
|
+
this.draggable_dir = draggable_dir;
|
|
827
|
+
this.dropzone_dir = dropzone_dir;
|
|
828
|
+
this.auto_scroll_dir = auto_scroll_dir;
|
|
829
|
+
this.enableResizeDefault = true;
|
|
830
|
+
// TODO: should this be an input with default or should consuming user set display in styles each time
|
|
831
|
+
this.position = 'absolute';
|
|
832
|
+
this.resizeDisabled = false;
|
|
833
|
+
this.resizeStart = new EventEmitter();
|
|
834
|
+
this.resizeMove = new EventEmitter();
|
|
835
|
+
this.resizeInertiaStart = new EventEmitter();
|
|
836
|
+
this.resizeEnd = new EventEmitter();
|
|
837
|
+
this.defaultConfig = {
|
|
838
|
+
edges: { left: true, right: true, bottom: true, top: true }
|
|
839
|
+
};
|
|
840
|
+
this.activeEdges = { left: false, right: false, top: false, bottom: false };
|
|
841
|
+
this.dragRootEl = drag_root_dir?.el?.nativeElement || this._document.body;
|
|
842
|
+
}
|
|
843
|
+
ngOnInit() {
|
|
844
|
+
this.addResizePropertiesToElement(this.el.nativeElement);
|
|
845
|
+
// we check for a dropzone, we use its id as the registry id if there is on
|
|
846
|
+
// otherwise, we use DEFAULT_REGISTRY_ID as a registry id. This allows us to keep our interactable
|
|
847
|
+
// drag state organized by dropzones.
|
|
848
|
+
this.registryId = this.dropzone_dir?.dropzoneId || DEFAULT_REGISTRY_ID;
|
|
849
|
+
this.interactableId = this.draggable_dir?.interactableId || this.interactService.addDraggableToRegistry(this.registryId, this.interactableId);
|
|
850
|
+
this.interactable = this.initiateResizeEvents({ ...this.defaultConfig, ...this.resizeConfig }, this.el.nativeElement);
|
|
851
|
+
this.alignDimensionsWithInputs(this.width, this.height);
|
|
852
|
+
this.interactableSubscription = this.interactService
|
|
853
|
+
.getInteractableState(this.interactableId, this.registryId)
|
|
854
|
+
.subscribe();
|
|
855
|
+
}
|
|
856
|
+
ngOnChanges(changes) {
|
|
857
|
+
if ((changes.resizeConfig || changes.resizeDisabled) && this.interactable) {
|
|
858
|
+
this.interactable.resizable({ ...this.resizeConfig, enabled: !this.resizeDisabled, });
|
|
859
|
+
}
|
|
860
|
+
if (changes.width || changes.height) {
|
|
861
|
+
this.alignDimensionsWithInputs(this.width, this.height);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
ngOnDestroy() {
|
|
865
|
+
this.interactableSubscription.unsubscribe();
|
|
866
|
+
this.interactService.destroyInteractable(this.interactableId, this.registryId);
|
|
867
|
+
}
|
|
868
|
+
resizeListener(event) {
|
|
869
|
+
const element = this.el.nativeElement;
|
|
870
|
+
const scale = this.scale;
|
|
871
|
+
const { deltaRect } = event;
|
|
872
|
+
const deltaX = deltaRect.left / scale;
|
|
873
|
+
const deltaY = deltaRect.top / scale;
|
|
874
|
+
// We get the width and height directly from the native element because
|
|
875
|
+
// the event dimension can get out of sync when resizing with autoScroll
|
|
876
|
+
const rect = element.getBoundingClientRect();
|
|
877
|
+
const width = (rect.width + deltaRect.width) / scale;
|
|
878
|
+
const height = (rect.height + deltaRect.height) / scale;
|
|
879
|
+
this.interactService.updateSize(this.interactableId, this.registryId, { deltaX, deltaY, width, height }, this.el.nativeElement);
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* hook elements into interacts resize event listeners
|
|
883
|
+
* we spread the configs so that the consuming component only overwrites the
|
|
884
|
+
* pieces that it explicitly indicates
|
|
885
|
+
* @param resizeConfig
|
|
886
|
+
* @param nativeElement
|
|
887
|
+
*/
|
|
888
|
+
initiateResizeEvents(resizeConfig, nativeElement) {
|
|
889
|
+
// TODO: This should try and get interactable from tft_draggable if it exists
|
|
890
|
+
const defaultResizeConfig = {
|
|
891
|
+
...resizeConfig,
|
|
892
|
+
enabled: !this.resizeDisabled,
|
|
893
|
+
...(this.auto_scroll_dir && {
|
|
894
|
+
autoScroll: {
|
|
895
|
+
...this.auto_scroll_dir.autoScrollConfig,
|
|
896
|
+
container: this.auto_scroll_dir.el.nativeElement
|
|
897
|
+
}
|
|
898
|
+
})
|
|
899
|
+
};
|
|
900
|
+
const interactable = this.draggable_dir?.interactable || interact(nativeElement);
|
|
901
|
+
return interactable.resizable(defaultResizeConfig)
|
|
902
|
+
.on('resizestart', (event) => {
|
|
903
|
+
this.activeEdges = event.edges;
|
|
904
|
+
if (this.auto_scroll_dir) {
|
|
905
|
+
this.subscribeToScrollEvents();
|
|
906
|
+
}
|
|
907
|
+
this.resizeStart.emit(this.mapResizeEvent(event));
|
|
908
|
+
})
|
|
909
|
+
.on('resizemove', (event) => {
|
|
910
|
+
if (this.enableResizeDefault) {
|
|
911
|
+
this.resizeListener(event);
|
|
912
|
+
}
|
|
913
|
+
const mappedEvent = this.mapResizeEvent(event);
|
|
914
|
+
this.resizeMove.emit(mappedEvent);
|
|
915
|
+
})
|
|
916
|
+
.on('resizeinertiastart', (event) => this.resizeInertiaStart.emit(this.mapResizeEvent(event)))
|
|
917
|
+
.on('resizeend', (event) => {
|
|
918
|
+
if (this.auto_scroll_dir) {
|
|
919
|
+
this.scrollEventsSubscription.unsubscribe();
|
|
920
|
+
}
|
|
921
|
+
this.activeEdges = { left: false, right: false, top: false, bottom: false };
|
|
922
|
+
this.resizeEnd.emit(this.mapResizeEvent(event));
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
mapResizeEvent(event) {
|
|
926
|
+
const target = this.el.nativeElement;
|
|
927
|
+
const relatedTarget = this.draggable_dir?.dropzone_dir?.el.nativeElement;
|
|
928
|
+
const scale = this.scale;
|
|
929
|
+
const positionInDropTarget = target && relatedTarget
|
|
930
|
+
? this.interactService.calculatePositionInElement(relatedTarget, target, scale)
|
|
931
|
+
: null;
|
|
932
|
+
return {
|
|
933
|
+
interactEvent: event,
|
|
934
|
+
resizeRef: this,
|
|
935
|
+
dragRef: this.draggable_dir,
|
|
936
|
+
dragOrigin: this.dropzone_dir,
|
|
937
|
+
dropTarget: this.el.nativeElement.dropTarget,
|
|
938
|
+
positionInDropTarget,
|
|
939
|
+
size: {
|
|
940
|
+
width: target.clientWidth / scale,
|
|
941
|
+
height: target.clientHeight / scale
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
alignDimensionsWithInputs(width, height) {
|
|
946
|
+
this.interactService.updateSize(this.interactableId, this.registryId, { deltaX: 0, deltaY: 0, width, height }, this.el.nativeElement);
|
|
947
|
+
}
|
|
948
|
+
addResizePropertiesToElement(nativeElement) {
|
|
949
|
+
this.renderer.setProperty(nativeElement, 'resizeRef', this);
|
|
950
|
+
}
|
|
951
|
+
subscribeToScrollEvents() {
|
|
952
|
+
this.scrollEventsSubscription = this.auto_scroll_dir.scrollDeltaObserver.subscribe(({ scrollLeft, scrollTop }) => {
|
|
953
|
+
const scale = this.scale;
|
|
954
|
+
const target = this.el.nativeElement;
|
|
955
|
+
const { width: prevWidth, height: prevHeight } = target.getBoundingClientRect();
|
|
956
|
+
const deltaHeight = scrollTop * (this.activeEdges.top ? -1 : this.activeEdges.bottom ? 1 : 0);
|
|
957
|
+
const deltaWidth = scrollLeft * (this.activeEdges.left ? -1 : this.activeEdges.right ? 1 : 0);
|
|
958
|
+
const height = (prevHeight + deltaHeight) / scale;
|
|
959
|
+
const width = (prevWidth + deltaWidth) / scale;
|
|
960
|
+
const deltaX = this.activeEdges.left ? (scrollLeft / scale) : 0;
|
|
961
|
+
const deltaY = this.activeEdges.top ? (scrollTop / scale) : 0;
|
|
962
|
+
this.interactService.updateSize(this.interactableId, this.registryId, { deltaX, deltaY, width, height }, this.el.nativeElement);
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: ResizableDirective, deps: [{ token: i0.ElementRef }, { token: DOCUMENT }, { token: InteractService }, { token: i0.Renderer2 }, { token: DragRootDirective, optional: true }, { token: AccountForScaleDirective, optional: true }, { token: DraggableDirective, optional: true }, { token: DropzoneDirective, optional: true, skipSelf: true }, { token: AutoScrollDirective, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
966
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: ResizableDirective, selector: "[tftResizable]", inputs: { enableResizeDefault: "enableResizeDefault", position: "position", resizeConfig: "resizeConfig", interactableId: "interactableId", width: "width", height: "height", resizeDisabled: "resizeDisabled" }, outputs: { resizeStart: "resizeStart", resizeMove: "resizeMove", resizeInertiaStart: "resizeInertiaStart", resizeEnd: "resizeEnd" }, host: { properties: { "style.touchAction": "this.resizeDisabled ? \"auto\" : \"none\"", "style.position": "position", "style.boxSizing": "\"border-box\"" } }, usesOnChanges: true, ngImport: i0 }); }
|
|
967
|
+
}
|
|
968
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: ResizableDirective, decorators: [{
|
|
969
|
+
type: Directive,
|
|
970
|
+
args: [{
|
|
971
|
+
selector: '[tftResizable]',
|
|
972
|
+
// eslint-disable-next-line @angular-eslint/no-host-metadata-property
|
|
973
|
+
host: {
|
|
974
|
+
// prevents touch events from colliding with with mouse events
|
|
975
|
+
// on touch screen
|
|
976
|
+
'[style.touchAction]': 'this.resizeDisabled ? "auto" : "none"',
|
|
977
|
+
// default to absolute here to accommodate likely use cases
|
|
978
|
+
// consuming component can easily over ride with position input
|
|
979
|
+
'[style.position]': 'position',
|
|
980
|
+
// follows interactjs suggested practices
|
|
981
|
+
'[style.boxSizing]': '"border-box"',
|
|
982
|
+
}
|
|
983
|
+
}]
|
|
984
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: Document, decorators: [{
|
|
985
|
+
type: Inject,
|
|
986
|
+
args: [DOCUMENT]
|
|
987
|
+
}] }, { type: InteractService }, { type: i0.Renderer2 }, { type: DragRootDirective, decorators: [{
|
|
988
|
+
type: Optional
|
|
989
|
+
}] }, { type: AccountForScaleDirective, decorators: [{
|
|
990
|
+
type: Optional
|
|
991
|
+
}] }, { type: DraggableDirective, decorators: [{
|
|
992
|
+
type: Optional
|
|
993
|
+
}] }, { type: DropzoneDirective, decorators: [{
|
|
994
|
+
type: Optional
|
|
995
|
+
}, {
|
|
996
|
+
type: SkipSelf
|
|
997
|
+
}] }, { type: AutoScrollDirective, decorators: [{
|
|
998
|
+
type: Optional
|
|
999
|
+
}, {
|
|
1000
|
+
type: SkipSelf
|
|
1001
|
+
}] }], propDecorators: { enableResizeDefault: [{
|
|
1002
|
+
type: Input
|
|
1003
|
+
}], position: [{
|
|
1004
|
+
type: Input
|
|
1005
|
+
}], resizeConfig: [{
|
|
1006
|
+
type: Input
|
|
1007
|
+
}], interactableId: [{
|
|
1008
|
+
type: Input
|
|
1009
|
+
}], width: [{
|
|
1010
|
+
type: Input
|
|
1011
|
+
}], height: [{
|
|
1012
|
+
type: Input
|
|
1013
|
+
}], resizeDisabled: [{
|
|
1014
|
+
type: Input
|
|
1015
|
+
}], resizeStart: [{
|
|
1016
|
+
type: Output
|
|
1017
|
+
}], resizeMove: [{
|
|
1018
|
+
type: Output
|
|
1019
|
+
}], resizeInertiaStart: [{
|
|
1020
|
+
type: Output
|
|
1021
|
+
}], resizeEnd: [{
|
|
1022
|
+
type: Output
|
|
1023
1023
|
}] } });
|
|
1024
1024
|
|
|
1025
|
-
/** @dynamic */
|
|
1026
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1027
|
-
class GesturableDirective {
|
|
1028
|
-
constructor(el, draggable_dir) {
|
|
1029
|
-
this.el = el;
|
|
1030
|
-
this.draggable_dir = draggable_dir;
|
|
1031
|
-
this.gestureDisabled = false;
|
|
1032
|
-
// pipes all interact events to event emitters
|
|
1033
|
-
this.gestureStart = new EventEmitter();
|
|
1034
|
-
this.gestureMove = new EventEmitter();
|
|
1035
|
-
this.gestureEnd = new EventEmitter();
|
|
1036
|
-
}
|
|
1037
|
-
ngOnInit() {
|
|
1038
|
-
this.gesturableId = this.draggable_dir?.interactableId || 'id';
|
|
1039
|
-
this.interactable = this.initiateGestureEvents(this.gestureConfig, this.el.nativeElement);
|
|
1040
|
-
this.setGestureConfig();
|
|
1041
|
-
}
|
|
1042
|
-
// TODO: watch config here as well and update interactable
|
|
1043
|
-
ngOnChanges(changes) {
|
|
1044
|
-
// we do this here instead of using a setter on the input so that it
|
|
1045
|
-
// will only run once when there is a change to x and y
|
|
1046
|
-
if (changes.gestureConfig || changes.gestureDisabled) {
|
|
1047
|
-
if (!this.interactable)
|
|
1048
|
-
return;
|
|
1049
|
-
this.setGestureConfig();
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
setGestureConfig() {
|
|
1053
|
-
const enabled = !this.gestureDisabled;
|
|
1054
|
-
const gestureConfig = { ...this.gestureConfig, enabled };
|
|
1055
|
-
this.interactable.gesturable(gestureConfig);
|
|
1056
|
-
}
|
|
1057
|
-
initiateGestureEvents(gestureConfig, nativeElement) {
|
|
1058
|
-
const defaultConfig = {
|
|
1059
|
-
enabled: !this.gestureDisabled,
|
|
1060
|
-
};
|
|
1061
|
-
const interactable = this.draggable_dir?.interactable || interact(nativeElement);
|
|
1062
|
-
return interactable.gesturable({ ...defaultConfig, ...gestureConfig })
|
|
1063
|
-
.on('gesturestart', (event) => {
|
|
1064
|
-
this.gestureStart.emit({ gestureRef: this, interactEvent: event });
|
|
1065
|
-
})
|
|
1066
|
-
.on('gesturemove', (event) => {
|
|
1067
|
-
this.gestureMove.emit({ gestureRef: this, interactEvent: event });
|
|
1068
|
-
})
|
|
1069
|
-
.on('gestureend', (event) => {
|
|
1070
|
-
this.gestureEnd.emit({ gestureRef: this, interactEvent: event });
|
|
1071
|
-
});
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1077
|
-
type: Directive,
|
|
1078
|
-
args: [{
|
|
1079
|
-
selector: '[tftGesturable]',
|
|
1080
|
-
// eslint-disable-next-line @angular-eslint/no-host-metadata-property
|
|
1081
|
-
host: {
|
|
1082
|
-
// '[style.touchAction]': 'this.gestureDisabled ? "auto" : "none"',
|
|
1083
|
-
'[id]': 'gesturableId',
|
|
1084
|
-
}
|
|
1085
|
-
}]
|
|
1086
|
-
}], ctorParameters:
|
|
1087
|
-
type: Optional
|
|
1088
|
-
}] }]
|
|
1089
|
-
type: Input
|
|
1090
|
-
}], gestureDisabled: [{
|
|
1091
|
-
type: Input
|
|
1092
|
-
}], gestureConfig: [{
|
|
1093
|
-
type: Input
|
|
1094
|
-
}], gestureStart: [{
|
|
1095
|
-
type: Output
|
|
1096
|
-
}], gestureMove: [{
|
|
1097
|
-
type: Output
|
|
1098
|
-
}], gestureEnd: [{
|
|
1099
|
-
type: Output
|
|
1025
|
+
/** @dynamic */
|
|
1026
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1027
|
+
class GesturableDirective {
|
|
1028
|
+
constructor(el, draggable_dir) {
|
|
1029
|
+
this.el = el;
|
|
1030
|
+
this.draggable_dir = draggable_dir;
|
|
1031
|
+
this.gestureDisabled = false;
|
|
1032
|
+
// pipes all interact events to event emitters
|
|
1033
|
+
this.gestureStart = new EventEmitter();
|
|
1034
|
+
this.gestureMove = new EventEmitter();
|
|
1035
|
+
this.gestureEnd = new EventEmitter();
|
|
1036
|
+
}
|
|
1037
|
+
ngOnInit() {
|
|
1038
|
+
this.gesturableId = this.draggable_dir?.interactableId || 'id';
|
|
1039
|
+
this.interactable = this.initiateGestureEvents(this.gestureConfig, this.el.nativeElement);
|
|
1040
|
+
this.setGestureConfig();
|
|
1041
|
+
}
|
|
1042
|
+
// TODO: watch config here as well and update interactable
|
|
1043
|
+
ngOnChanges(changes) {
|
|
1044
|
+
// we do this here instead of using a setter on the input so that it
|
|
1045
|
+
// will only run once when there is a change to x and y
|
|
1046
|
+
if (changes.gestureConfig || changes.gestureDisabled) {
|
|
1047
|
+
if (!this.interactable)
|
|
1048
|
+
return;
|
|
1049
|
+
this.setGestureConfig();
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
setGestureConfig() {
|
|
1053
|
+
const enabled = !this.gestureDisabled;
|
|
1054
|
+
const gestureConfig = { ...this.gestureConfig, enabled };
|
|
1055
|
+
this.interactable.gesturable(gestureConfig);
|
|
1056
|
+
}
|
|
1057
|
+
initiateGestureEvents(gestureConfig, nativeElement) {
|
|
1058
|
+
const defaultConfig = {
|
|
1059
|
+
enabled: !this.gestureDisabled,
|
|
1060
|
+
};
|
|
1061
|
+
const interactable = this.draggable_dir?.interactable || interact(nativeElement);
|
|
1062
|
+
return interactable.gesturable({ ...defaultConfig, ...gestureConfig })
|
|
1063
|
+
.on('gesturestart', (event) => {
|
|
1064
|
+
this.gestureStart.emit({ gestureRef: this, interactEvent: event });
|
|
1065
|
+
})
|
|
1066
|
+
.on('gesturemove', (event) => {
|
|
1067
|
+
this.gestureMove.emit({ gestureRef: this, interactEvent: event });
|
|
1068
|
+
})
|
|
1069
|
+
.on('gestureend', (event) => {
|
|
1070
|
+
this.gestureEnd.emit({ gestureRef: this, interactEvent: event });
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: GesturableDirective, deps: [{ token: i0.ElementRef }, { token: DraggableDirective, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1074
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: GesturableDirective, selector: "[tftGesturable]", inputs: { gesturableId: "gesturableId", gestureDisabled: "gestureDisabled", gestureConfig: "gestureConfig" }, outputs: { gestureStart: "gestureStart", gestureMove: "gestureMove", gestureEnd: "gestureEnd" }, host: { properties: { "id": "gesturableId" } }, usesOnChanges: true, ngImport: i0 }); }
|
|
1075
|
+
}
|
|
1076
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: GesturableDirective, decorators: [{
|
|
1077
|
+
type: Directive,
|
|
1078
|
+
args: [{
|
|
1079
|
+
selector: '[tftGesturable]',
|
|
1080
|
+
// eslint-disable-next-line @angular-eslint/no-host-metadata-property
|
|
1081
|
+
host: {
|
|
1082
|
+
// '[style.touchAction]': 'this.gestureDisabled ? "auto" : "none"',
|
|
1083
|
+
'[id]': 'gesturableId',
|
|
1084
|
+
}
|
|
1085
|
+
}]
|
|
1086
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: DraggableDirective, decorators: [{
|
|
1087
|
+
type: Optional
|
|
1088
|
+
}] }], propDecorators: { gesturableId: [{
|
|
1089
|
+
type: Input
|
|
1090
|
+
}], gestureDisabled: [{
|
|
1091
|
+
type: Input
|
|
1092
|
+
}], gestureConfig: [{
|
|
1093
|
+
type: Input
|
|
1094
|
+
}], gestureStart: [{
|
|
1095
|
+
type: Output
|
|
1096
|
+
}], gestureMove: [{
|
|
1097
|
+
type: Output
|
|
1098
|
+
}], gestureEnd: [{
|
|
1099
|
+
type: Output
|
|
1100
1100
|
}] } });
|
|
1101
1101
|
|
|
1102
|
-
class ApplyScaleDirective {
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
this._scale
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
this.
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1117
|
-
type: Directive,
|
|
1118
|
-
args: [{
|
|
1119
|
-
selector: '[tftApplyScale]'
|
|
1120
|
-
}]
|
|
1121
|
-
}], ctorParameters:
|
|
1122
|
-
type: Input
|
|
1123
|
-
}], fontSize: [{
|
|
1124
|
-
type: HostBinding,
|
|
1125
|
-
args: ['style.fontSize']
|
|
1102
|
+
class ApplyScaleDirective {
|
|
1103
|
+
// this setup allows consumers to set x, y scale independently or just set them both with scale
|
|
1104
|
+
set scale(val) {
|
|
1105
|
+
this._scale;
|
|
1106
|
+
this.fontSize = `${val}px`;
|
|
1107
|
+
}
|
|
1108
|
+
;
|
|
1109
|
+
constructor(el) {
|
|
1110
|
+
this.el = el;
|
|
1111
|
+
this._scale = 1;
|
|
1112
|
+
}
|
|
1113
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: ApplyScaleDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1114
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: ApplyScaleDirective, selector: "[tftApplyScale]", inputs: { scale: "scale" }, host: { properties: { "style.fontSize": "this.fontSize" } }, ngImport: i0 }); }
|
|
1115
|
+
}
|
|
1116
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: ApplyScaleDirective, decorators: [{
|
|
1117
|
+
type: Directive,
|
|
1118
|
+
args: [{
|
|
1119
|
+
selector: '[tftApplyScale]'
|
|
1120
|
+
}]
|
|
1121
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { scale: [{
|
|
1122
|
+
type: Input
|
|
1123
|
+
}], fontSize: [{
|
|
1124
|
+
type: HostBinding,
|
|
1125
|
+
args: ['style.fontSize']
|
|
1126
1126
|
}] } });
|
|
1127
1127
|
|
|
1128
|
-
const EXPORTS = [
|
|
1129
|
-
DraggableDirective,
|
|
1130
|
-
ResizableDirective,
|
|
1131
|
-
DropzoneDirective,
|
|
1132
|
-
GesturableDirective,
|
|
1133
|
-
DragRootDirective,
|
|
1134
|
-
AutoScrollDirective,
|
|
1135
|
-
AccountForScaleDirective,
|
|
1136
|
-
ApplyScaleDirective,
|
|
1137
|
-
DragPreviewDirective,
|
|
1138
|
-
ArrayOfNPipe,
|
|
1139
|
-
];
|
|
1140
|
-
class InteractModule {
|
|
1141
|
-
static forRoot(config) {
|
|
1142
|
-
const defaultConfig = { cssDimensionUnit: 'px' };
|
|
1143
|
-
return {
|
|
1144
|
-
ngModule: InteractModule,
|
|
1145
|
-
providers: [
|
|
1146
|
-
{ provide: INTERACT_ROOT_CONFIG, useValue: { ...defaultConfig, ...config } },
|
|
1147
|
-
InteractService
|
|
1148
|
-
]
|
|
1149
|
-
};
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1174
|
-
type: NgModule,
|
|
1175
|
-
args: [{
|
|
1176
|
-
imports: [CommonModule],
|
|
1177
|
-
// providers: [{ provide: INTERACT_ROOT_CONFIG, useValue: 'px' }],
|
|
1178
|
-
declarations: [
|
|
1179
|
-
...EXPORTS,
|
|
1180
|
-
],
|
|
1181
|
-
exports: [
|
|
1182
|
-
...EXPORTS
|
|
1183
|
-
]
|
|
1184
|
-
}]
|
|
1128
|
+
const EXPORTS = [
|
|
1129
|
+
DraggableDirective,
|
|
1130
|
+
ResizableDirective,
|
|
1131
|
+
DropzoneDirective,
|
|
1132
|
+
GesturableDirective,
|
|
1133
|
+
DragRootDirective,
|
|
1134
|
+
AutoScrollDirective,
|
|
1135
|
+
AccountForScaleDirective,
|
|
1136
|
+
ApplyScaleDirective,
|
|
1137
|
+
DragPreviewDirective,
|
|
1138
|
+
ArrayOfNPipe,
|
|
1139
|
+
];
|
|
1140
|
+
class InteractModule {
|
|
1141
|
+
static forRoot(config) {
|
|
1142
|
+
const defaultConfig = { cssDimensionUnit: 'px' };
|
|
1143
|
+
return {
|
|
1144
|
+
ngModule: InteractModule,
|
|
1145
|
+
providers: [
|
|
1146
|
+
{ provide: INTERACT_ROOT_CONFIG, useValue: { ...defaultConfig, ...config } },
|
|
1147
|
+
InteractService
|
|
1148
|
+
]
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: InteractModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1152
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.9", ngImport: i0, type: InteractModule, declarations: [DraggableDirective,
|
|
1153
|
+
ResizableDirective,
|
|
1154
|
+
DropzoneDirective,
|
|
1155
|
+
GesturableDirective,
|
|
1156
|
+
DragRootDirective,
|
|
1157
|
+
AutoScrollDirective,
|
|
1158
|
+
AccountForScaleDirective,
|
|
1159
|
+
ApplyScaleDirective,
|
|
1160
|
+
DragPreviewDirective,
|
|
1161
|
+
ArrayOfNPipe], imports: [CommonModule], exports: [DraggableDirective,
|
|
1162
|
+
ResizableDirective,
|
|
1163
|
+
DropzoneDirective,
|
|
1164
|
+
GesturableDirective,
|
|
1165
|
+
DragRootDirective,
|
|
1166
|
+
AutoScrollDirective,
|
|
1167
|
+
AccountForScaleDirective,
|
|
1168
|
+
ApplyScaleDirective,
|
|
1169
|
+
DragPreviewDirective,
|
|
1170
|
+
ArrayOfNPipe] }); }
|
|
1171
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: InteractModule, imports: [CommonModule] }); }
|
|
1172
|
+
}
|
|
1173
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: InteractModule, decorators: [{
|
|
1174
|
+
type: NgModule,
|
|
1175
|
+
args: [{
|
|
1176
|
+
imports: [CommonModule],
|
|
1177
|
+
// providers: [{ provide: INTERACT_ROOT_CONFIG, useValue: 'px' }],
|
|
1178
|
+
declarations: [
|
|
1179
|
+
...EXPORTS,
|
|
1180
|
+
],
|
|
1181
|
+
exports: [
|
|
1182
|
+
...EXPORTS
|
|
1183
|
+
]
|
|
1184
|
+
}]
|
|
1185
1185
|
}] });
|
|
1186
1186
|
|
|
1187
|
-
/**
|
|
1188
|
-
* Generated bundle index. Do not edit.
|
|
1187
|
+
/**
|
|
1188
|
+
* Generated bundle index. Do not edit.
|
|
1189
1189
|
*/
|
|
1190
1190
|
|
|
1191
1191
|
export { AccountForScaleDirective, ApplyScaleDirective, ArrayOfNPipe, AutoScrollDirective, DEFAULT_REGISTRY_ID, DragPreviewDirective, DragRootDirective, DraggableDirective, DropzoneDirective, GesturableDirective, INTERACT_ROOT_CONFIG, InteractModule, ResizableDirective, TFT_DRAG_PREVIEW, cloneElement$1 as cloneElement, defaultDelta, defaultPosition, defaultSize, getClosestMatchingAncestor, getRootNode };
|