@blokkli/editor 1.0.4 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +345 -16
  3. package/dist/runtime/adapter/drupal/graphql/base.graphql +2 -1
  4. package/dist/runtime/adapter/drupal/graphqlMiddleware.js +4 -1
  5. package/dist/runtime/adapter/index.d.ts +12 -1
  6. package/dist/runtime/blokkliPlugins/Sidebar/Detached/index.vue +41 -39
  7. package/dist/runtime/blokkliPlugins/Sidebar/index.vue +10 -16
  8. package/dist/runtime/blokkliPlugins/ViewOption/index.vue +2 -0
  9. package/dist/runtime/components/BlokkliField.vue +75 -17
  10. package/dist/runtime/components/BlokkliItem.vue +34 -6
  11. package/dist/runtime/components/BlokkliProvider.vue +18 -1
  12. package/dist/runtime/components/Edit/BlockProxy/index.vue +102 -0
  13. package/dist/runtime/components/Edit/DragInteractions/index.vue +49 -25
  14. package/dist/runtime/components/Edit/DraggableList.vue +140 -30
  15. package/dist/runtime/components/Edit/EditProvider.vue +4 -0
  16. package/dist/runtime/components/Edit/Features/AddList/index.vue +3 -0
  17. package/dist/runtime/components/Edit/Features/Artboard/Overview/index.vue +111 -0
  18. package/dist/runtime/components/Edit/Features/Artboard/Scrollbar/index.vue +47 -0
  19. package/dist/runtime/components/Edit/Features/Artboard/index.vue +301 -9
  20. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +29 -4
  21. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +3 -4
  22. package/dist/runtime/components/Edit/Features/Debug/Rects/index.vue +27 -0
  23. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +24 -3
  24. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/fragment.glsl +56 -24
  25. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +184 -29
  26. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/vertex.glsl +36 -16
  27. package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +4 -0
  28. package/dist/runtime/components/Edit/Features/Duplicate/index.vue +1 -13
  29. package/dist/runtime/components/Edit/Features/EditableMask/index.vue +2 -2
  30. package/dist/runtime/components/Edit/Features/History/index.vue +1 -1
  31. package/dist/runtime/components/Edit/Features/Options/Form/Checkbox/index.vue +2 -2
  32. package/dist/runtime/components/Edit/Features/Options/Form/Checkboxes/index.vue +28 -25
  33. package/dist/runtime/components/Edit/Features/Options/Form/Color/index.vue +1 -1
  34. package/dist/runtime/components/Edit/Features/Options/Form/Item.vue +67 -39
  35. package/dist/runtime/components/Edit/Features/Options/Form/Number/index.vue +6 -2
  36. package/dist/runtime/components/Edit/Features/Options/Form/Radios/index.vue +1 -1
  37. package/dist/runtime/components/Edit/Features/Options/Form/Range/index.vue +2 -2
  38. package/dist/runtime/components/Edit/Features/Options/Form/Text/index.vue +2 -1
  39. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +83 -33
  40. package/dist/runtime/components/Edit/Features/ProxyView/index.vue +38 -0
  41. package/dist/runtime/components/Edit/Features/Publish/index.vue +53 -6
  42. package/dist/runtime/components/Edit/Features/Search/Overlay/index.vue +3 -13
  43. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +1 -1
  44. package/dist/runtime/components/Edit/Features/Settings/Dialog/index.vue +2 -0
  45. package/dist/runtime/components/Edit/Features/Structure/List/Field/index.vue +3 -3
  46. package/dist/runtime/components/Edit/Features/Structure/index.vue +3 -3
  47. package/dist/runtime/components/Edit/ScrollBoundary/index.vue +24 -0
  48. package/dist/runtime/components/Edit/index.d.ts +2 -1
  49. package/dist/runtime/components/Edit/index.js +3 -1
  50. package/dist/runtime/composables/defineBlokkli.js +10 -5
  51. package/dist/runtime/constants/index.d.ts +1 -1
  52. package/dist/runtime/constants/index.js +6 -1
  53. package/dist/runtime/css/output.css +1 -1
  54. package/dist/runtime/helpers/animationProvider.js +10 -4
  55. package/dist/runtime/helpers/domProvider.d.ts +12 -4
  56. package/dist/runtime/helpers/domProvider.js +70 -26
  57. package/dist/runtime/helpers/featuresProvider.d.ts +1 -1
  58. package/dist/runtime/helpers/runtimeHelpers/index.d.ts +6 -0
  59. package/dist/runtime/helpers/runtimeHelpers/index.js +25 -0
  60. package/dist/runtime/helpers/selectionProvider.d.ts +2 -1
  61. package/dist/runtime/helpers/selectionProvider.js +7 -8
  62. package/dist/runtime/helpers/symbols.d.ts +7 -0
  63. package/dist/runtime/helpers/symbols.js +7 -0
  64. package/dist/runtime/helpers/typesProvider.d.ts +1 -1
  65. package/dist/runtime/helpers/uiProvider.d.ts +1 -0
  66. package/dist/runtime/helpers/uiProvider.js +16 -3
  67. package/dist/runtime/helpers/webgl/index.d.ts +6 -1
  68. package/dist/runtime/helpers/webgl/index.js +38 -5
  69. package/dist/runtime/icons/eye.svg +1 -0
  70. package/dist/runtime/types/generatedModuleTypes.d.ts +12 -4
  71. package/dist/runtime/types/index.d.ts +30 -1
  72. package/package.json +7 -5
  73. package/dist/runtime/components/Edit/Features/Artboard/Manager/Artboard.d.ts +0 -204
  74. package/dist/runtime/components/Edit/Features/Artboard/Manager/Artboard.js +0 -748
  75. package/dist/runtime/components/Edit/Features/Artboard/Manager/Scrollbar/index.vue +0 -176
  76. package/dist/runtime/components/Edit/Features/Artboard/Manager/index.vue +0 -317
  77. package/dist/runtime/helpers/Artboard/index.d.ts +0 -16
  78. package/dist/runtime/helpers/Artboard/index.js +0 -20
@@ -1,748 +0,0 @@
1
- import { easeOutQuad } from "#blokkli/helpers/easing";
2
- import { lerp, calculateCenterPosition } from "#blokkli/helpers";
3
- class Queue {
4
- queue = [];
5
- timeQueue = [];
6
- reset() {
7
- this.queue.splice(0);
8
- this.timeQueue.splice(0);
9
- }
10
- pruneQueue(ms) {
11
- while (this.timeQueue.length && this.timeQueue[0] < Date.now() - ms) {
12
- this.timeQueue.shift();
13
- this.queue.shift();
14
- }
15
- }
16
- add(position) {
17
- this.queue.push(position);
18
- this.timeQueue.push(Date.now());
19
- this.pruneQueue(50);
20
- }
21
- }
22
- class VelocityQueue extends Queue {
23
- max;
24
- constructor(max) {
25
- super();
26
- this.max = max;
27
- }
28
- getVelocity() {
29
- this.pruneQueue(1e3);
30
- const length = this.timeQueue.length;
31
- if (length < 2) return { x: 0, y: 0 };
32
- const distanceX = this.queue[length - 1].x - this.queue[0].x;
33
- const distanceY = this.queue[length - 1].y - this.queue[0].y;
34
- const time = (this.timeQueue[length - 1] - this.timeQueue[0]) / 1e3;
35
- const x = this.limit(distanceX / time * 0.03);
36
- const y = this.limit(distanceY / time * 0.03);
37
- return { x, y };
38
- }
39
- limit(v) {
40
- return Math.min(Math.max(v, -this.max), this.max);
41
- }
42
- }
43
- class ScaleVelocityQueue extends Queue {
44
- getVelocity() {
45
- this.pruneQueue(1e3);
46
- const length = this.timeQueue.length;
47
- if (length < 2) return 0;
48
- const distance = this.queue[length - 1] - this.queue[0];
49
- const time = (this.timeQueue[length - 1] - this.timeQueue[0]) / 1e3;
50
- return distance / time * 0.03;
51
- }
52
- }
53
- function applyRubberBandEffect(value, min, max, factor = 0.5) {
54
- if (value < min) {
55
- return min - (min - value) * factor;
56
- } else if (value > max) {
57
- return max + (value - max) * factor;
58
- }
59
- return value;
60
- }
61
- export class Artboard {
62
- /**
63
- * The element containing the artboard that can be moved and zoomed.
64
- */
65
- artboardEl;
66
- /**
67
- * The parent/root element that defines the area in which the artboard can be interacted with.
68
- */
69
- rootEl;
70
- /**
71
- * The minimum scale amount.
72
- */
73
- minScale = 0.1;
74
- /**
75
- * The maximum scale amount.
76
- */
77
- maxScale = 3;
78
- /**
79
- * The maximum move velocity.
80
- */
81
- maxVelocity = 200;
82
- /**
83
- * The current scale of the artboard.
84
- */
85
- scale = 1;
86
- /**
87
- * The padding area inside the root element.
88
- */
89
- padding = 20;
90
- /**
91
- * The multiplier for scrolling using the mouse wheel.
92
- */
93
- scrollSpeed = 1;
94
- /**
95
- * The current arboard offset/translation.
96
- */
97
- offset;
98
- /**
99
- * The native size of the artboard (without any scaling).
100
- */
101
- artboardSize;
102
- /**
103
- * The native size of the root element.
104
- */
105
- rootSize;
106
- /**
107
- * The target state for the current animation.
108
- */
109
- animationTarget = null;
110
- /**
111
- * The last touch coordinate (or the midpoint of two touches when scaling).
112
- */
113
- lastTouch;
114
- /**
115
- * Whether the user is currently dragging the artboard.
116
- */
117
- isDragging = false;
118
- /**
119
- * Whether the user is currently scaling the artboard using touch gestures.
120
- */
121
- isScaling = false;
122
- /**
123
- * The calculated velocity of a drag gesture.
124
- */
125
- velocity = { x: 0, y: 0 };
126
- /**
127
- * The queue containing the last touches to calculate the velocity.
128
- */
129
- velocityQueue;
130
- /**
131
- * The calculated scale velocity.
132
- */
133
- scaleVelocity = 0;
134
- /**
135
- * The queue containing the last scaling values during a scale gesture.
136
- */
137
- scaleVelocityQueue;
138
- /**
139
- * Whether the animation loop is performing momentum scrolling.
140
- */
141
- isMomentumScrolling = false;
142
- /**
143
- * The detected touch direction.
144
- */
145
- touchDirection = "none";
146
- /**
147
- * The coordinate at which the first touch event fired.
148
- */
149
- initialTouchPoint = null;
150
- /**
151
- * The offset at the time the first touch event fired.
152
- */
153
- initialOffset = { x: 0, y: 0 };
154
- scaleMidpoint = null;
155
- initialTouchDistance = 0;
156
- initialScale = 1;
157
- moveStartOffset = null;
158
- moveStartCoords = null;
159
- isPressingSpace = false;
160
- /**
161
- * Whether the user is currently touching the artboard with at least one finger.
162
- */
163
- isTouching = false;
164
- getBlockingRects = null;
165
- listeners = {};
166
- resizeObserver;
167
- scaleStartCoords = null;
168
- lastScaleTimestamp = 0;
169
- /**
170
- * The timestamp of the last call to animateTo().
171
- */
172
- lastAnimateToTimestamp = 0;
173
- /**
174
- * Construct a new Artboard.
175
- */
176
- constructor(el, rootEl, options) {
177
- this.artboardEl = el;
178
- this.rootEl = rootEl;
179
- this.offset = {
180
- x: options?.x || 0,
181
- y: options?.y || 0
182
- };
183
- this.lastTouch = null;
184
- this.artboardSize = {
185
- width: el.offsetWidth,
186
- height: el.offsetHeight
187
- };
188
- this.velocityQueue = new VelocityQueue(200);
189
- this.scaleVelocityQueue = new ScaleVelocityQueue();
190
- this.rootSize = {
191
- width: window.innerWidth,
192
- height: window.innerHeight
193
- };
194
- if (options) {
195
- this.setOptions(options);
196
- }
197
- this.resizeObserver = new ResizeObserver((entries) => {
198
- for (const entry of entries) {
199
- if (entry.target === el) {
200
- const size = entry.contentBoxSize[0];
201
- if (!size) {
202
- return;
203
- }
204
- this.artboardSize.width = size.inlineSize;
205
- this.artboardSize.height = size.blockSize;
206
- } else if (entry.target === rootEl) {
207
- const size = entry.contentBoxSize[0];
208
- if (!size) {
209
- return;
210
- }
211
- this.rootSize.width = size.inlineSize;
212
- this.rootSize.height = size.blockSize;
213
- }
214
- }
215
- });
216
- this.resizeObserver.observe(this.artboardEl);
217
- this.resizeObserver.observe(this.rootEl);
218
- this.initListeners();
219
- }
220
- setOptions(options) {
221
- if (options.scrollSpeed) {
222
- this.scrollSpeed = options.scrollSpeed;
223
- }
224
- if (options.padding) {
225
- this.padding = options.padding;
226
- }
227
- if (options.scale) {
228
- this.scale = options.scale;
229
- }
230
- if (options.minScale) {
231
- this.minScale = options.minScale;
232
- }
233
- if (options.maxScale) {
234
- this.maxScale = options.maxScale;
235
- }
236
- if (options.getBlockingRects) {
237
- this.getBlockingRects = options.getBlockingRects;
238
- }
239
- if (options.maxVelocity) {
240
- this.maxVelocity = options.maxVelocity;
241
- }
242
- }
243
- initListeners() {
244
- this.listeners.onWheel = this.onWheel.bind(this);
245
- document.documentElement.addEventListener("wheel", this.listeners.onWheel, {
246
- passive: false
247
- });
248
- this.listeners.onTouchStart = this.onTouchStart.bind(this);
249
- this.rootEl.addEventListener("touchstart", this.listeners.onTouchStart, {
250
- passive: false
251
- });
252
- this.listeners.onTouchMove = this.onTouchMove.bind(this);
253
- this.rootEl.addEventListener("touchmove", this.listeners.onTouchMove, {
254
- passive: false
255
- });
256
- this.listeners.onTouchEnd = this.onTouchEnd.bind(this);
257
- this.rootEl.addEventListener("touchend", this.listeners.onTouchEnd, {
258
- passive: false,
259
- capture: true
260
- });
261
- this.listeners.onMouseDown = this.onMouseDown.bind(this);
262
- this.rootEl.addEventListener("mousedown", this.listeners.onMouseDown, {
263
- passive: false,
264
- capture: true
265
- });
266
- this.listeners.onMouseUp = this.onMouseUp.bind(this);
267
- this.rootEl.addEventListener("mouseup", this.listeners.onMouseUp, {
268
- passive: false
269
- });
270
- this.listeners.onKeyDown = this.onKeyDown.bind(this);
271
- document.addEventListener("keydown", this.listeners.onKeyDown, {
272
- passive: false
273
- });
274
- this.listeners.onKeyUp = this.onKeyUp.bind(this);
275
- document.addEventListener("keyup", this.listeners.onKeyUp, {
276
- passive: false
277
- });
278
- }
279
- onKeyDown(e) {
280
- if (e.code === "Space" && !this.isPressingSpace) {
281
- this.isPressingSpace = true;
282
- }
283
- }
284
- onKeyUp() {
285
- this.isPressingSpace = false;
286
- this.moveStartOffset = null;
287
- this.moveStartCoords = null;
288
- }
289
- onMouseDown(e) {
290
- if (this.isMomentumScrolling || this.isPressingSpace) {
291
- e.preventDefault();
292
- e.stopPropagation();
293
- }
294
- this.isMomentumScrolling = false;
295
- if (e.buttons === 1 && this.isPressingSpace || e.buttons === 2 && !this.isPressingSpace) {
296
- e.preventDefault();
297
- this.onDragStart([e]);
298
- this.listeners.onMouseMove = this.onMouseMove.bind(this);
299
- document.removeEventListener("mousemove", this.listeners.onMouseMove);
300
- document.addEventListener("mousemove", this.listeners.onMouseMove);
301
- }
302
- }
303
- onMouseUp() {
304
- document.removeEventListener("mousemove", this.listeners.onMouseMove);
305
- this.onDragEnd();
306
- }
307
- onMouseMove(e) {
308
- if (!this.isPressingSpace) {
309
- this.onDragEnd();
310
- document.removeEventListener("mousemove", this.listeners.onMouseMove);
311
- return;
312
- }
313
- this.onDragMove([e]);
314
- }
315
- getDistance(a, b) {
316
- const dx = a.x - b.x;
317
- const dy = a.y - b.y;
318
- return Math.sqrt(dx * dx + dy * dy);
319
- }
320
- getTouchDistance(touches) {
321
- return this.getDistance(
322
- {
323
- x: touches[0].clientX,
324
- y: touches[0].clientY
325
- },
326
- {
327
- x: touches[1].clientX,
328
- y: touches[1].clientY
329
- }
330
- );
331
- }
332
- getMidpoint(touches) {
333
- const x = touches[0].clientX;
334
- const y = touches[0].clientY;
335
- if (touches.length === 1) {
336
- return {
337
- x,
338
- y
339
- };
340
- }
341
- return {
342
- x: (x + touches[1].clientX) / 2,
343
- y: (y + touches[1].clientY) / 2
344
- };
345
- }
346
- onDragStart(touches) {
347
- this.animationTarget = null;
348
- this.lastTouch = {
349
- x: touches[0].clientX,
350
- y: touches[0].clientY
351
- };
352
- this.initialTouchPoint = { ...this.lastTouch };
353
- this.touchDirection = "none";
354
- this.initialOffset = { ...this.offset };
355
- this.velocity = { x: 0, y: 0 };
356
- this.velocityQueue.reset();
357
- this.scaleVelocityQueue.reset();
358
- this.scaleVelocity = 0;
359
- }
360
- onDragMove(touches) {
361
- if (!this.lastTouch || !this.initialTouchPoint) {
362
- this.onDragStart(touches);
363
- return;
364
- }
365
- const midpoint = this.getMidpoint(touches);
366
- const focalPoint = {
367
- x: (midpoint.x - this.offset.x) / this.scale,
368
- y: (midpoint.y - this.offset.y) / this.scale
369
- };
370
- this.velocityQueue.add(midpoint);
371
- if (touches.length === 2) {
372
- this.isDragging = false;
373
- if (!this.scaleStartCoords) {
374
- this.scaleStartCoords = { ...this.lastTouch };
375
- }
376
- if (!this.isScaling) {
377
- this.isScaling = true;
378
- this.lastTouch = { x: midpoint.x, y: midpoint.y };
379
- }
380
- this.velocityQueue.reset();
381
- const newTouchDistance = this.getTouchDistance(touches);
382
- const scaleFactor = newTouchDistance / this.initialTouchDistance;
383
- const newScale = this.initialScale * scaleFactor;
384
- this.scaleVelocityQueue.add(newScale);
385
- this.setScale(newScale);
386
- const diffX2 = midpoint.x - this.lastTouch.x;
387
- const diffY2 = midpoint.y - this.lastTouch.y;
388
- const newOffsetX = midpoint.x - focalPoint.x * this.scale;
389
- const newOffsetY = midpoint.y - focalPoint.y * this.scale;
390
- this.scaleMidpoint = {
391
- x: midpoint.x,
392
- y: midpoint.y
393
- };
394
- this.setOffset(newOffsetX + diffX2, newOffsetY + diffY2);
395
- this.lastTouch = { x: midpoint.x, y: midpoint.y };
396
- this.lastScaleTimestamp = Date.now();
397
- return;
398
- }
399
- if (this.isScaling) {
400
- if (Date.now() - this.lastScaleTimestamp < 200) {
401
- return;
402
- }
403
- this.isScaling = false;
404
- this.touchDirection = "none";
405
- this.isMomentumScrolling = false;
406
- this.initialTouchPoint = { ...midpoint };
407
- this.initialOffset = { ...this.offset };
408
- this.lastTouch = { ...midpoint };
409
- return;
410
- }
411
- this.scaleStartCoords = null;
412
- this.isScaling = false;
413
- this.isDragging = true;
414
- const diffX = midpoint.x - this.initialTouchPoint.x;
415
- const diffY = midpoint.y - this.initialTouchPoint.y;
416
- if (this.touchDirection === "none") {
417
- const deltaX = Math.abs(midpoint.x - this.initialTouchPoint.x);
418
- const deltaY = Math.abs(midpoint.y - this.initialTouchPoint.y);
419
- const thresholdRatio = 0.9;
420
- const ratio = deltaY > 0 ? deltaX / deltaY : deltaX;
421
- if (ratio > 1 + thresholdRatio) {
422
- this.touchDirection = "horizontal";
423
- } else if (ratio < 1 - thresholdRatio) {
424
- this.touchDirection = "vertical";
425
- } else {
426
- this.touchDirection = "both";
427
- }
428
- }
429
- let moveX = 0;
430
- let moveY = 0;
431
- switch (this.touchDirection) {
432
- case "horizontal":
433
- moveX = diffX;
434
- break;
435
- case "vertical":
436
- moveY = diffY;
437
- break;
438
- case "both":
439
- moveX = diffX;
440
- moveY = diffY;
441
- break;
442
- }
443
- this.setOffset(this.initialOffset.x + moveX, this.initialOffset.y + moveY);
444
- this.lastTouch = { x: midpoint.x, y: midpoint.y };
445
- }
446
- resetDraggingState() {
447
- this.isDragging = false;
448
- this.isScaling = false;
449
- }
450
- onDragEnd() {
451
- this.resetDraggingState();
452
- if (!this.initialTouchPoint || !this.lastTouch) {
453
- return;
454
- }
455
- const velocity = this.velocityQueue.getVelocity();
456
- const totalVelocity = Math.abs(velocity.x) + Math.abs(velocity.y);
457
- if (totalVelocity < 40) {
458
- this.velocity = { x: 0, y: 0 };
459
- this.isMomentumScrolling = false;
460
- } else {
461
- if (this.touchDirection === "horizontal" || this.touchDirection === "both") {
462
- this.velocity.x = velocity.x;
463
- }
464
- if (this.touchDirection === "vertical" || this.touchDirection === "both") {
465
- this.velocity.y = velocity.y;
466
- }
467
- this.isMomentumScrolling = true;
468
- }
469
- const scaleVelocity = this.scaleVelocityQueue.getVelocity() / 7;
470
- if (scaleVelocity > 0.01) {
471
- this.scaleVelocity = scaleVelocity;
472
- this.isMomentumScrolling = false;
473
- }
474
- this.initialTouchPoint = null;
475
- }
476
- onTouchStart(e) {
477
- this.isTouching = true;
478
- if (e.touches.length === 1) {
479
- this.onDragStart(e.touches);
480
- }
481
- if (e.touches.length === 2) {
482
- this.initialTouchDistance = this.getTouchDistance(e.touches);
483
- this.initialScale = this.scale;
484
- }
485
- }
486
- onTouchMove(e) {
487
- e.preventDefault();
488
- e.stopPropagation();
489
- this.onDragMove(e.touches);
490
- }
491
- onTouchEnd(e) {
492
- if (this.isDragging || this.isMomentumScrolling) {
493
- e.preventDefault();
494
- e.stopImmediatePropagation();
495
- }
496
- if (e.touches.length === 0) {
497
- this.isTouching = false;
498
- this.onDragEnd();
499
- }
500
- }
501
- destroy() {
502
- this.artboardEl.style.transform = "";
503
- this.resizeObserver.disconnect();
504
- this.rootEl.removeEventListener("touchstart", this.listeners.onTouchStart);
505
- this.rootEl.removeEventListener("touchmove", this.listeners.onTouchMove);
506
- this.rootEl.removeEventListener("touchend", this.listeners.onTouchEnd, {
507
- capture: true
508
- });
509
- this.rootEl.removeEventListener("mousedown", this.listeners.onMouseDown);
510
- this.rootEl.removeEventListener("mouseup", this.listeners.onMouseUp);
511
- document.documentElement.removeEventListener(
512
- "wheel",
513
- this.listeners.onWheel
514
- );
515
- document.removeEventListener("keydown", this.listeners.onKeyDown);
516
- document.removeEventListener("keyup", this.listeners.onKeyUp);
517
- document.removeEventListener("mousemove", this.listeners.onMouseMove);
518
- }
519
- loop() {
520
- if (this.isMomentumScrolling && !this.isDragging) {
521
- const deceleration = 0.95;
522
- let stopMomentumX = false;
523
- let stopMomentumY = false;
524
- const boundaries = this.getBoundaries();
525
- const isOutsideY = boundaries.yMax - this.offset.y < -1 || boundaries.yMin - this.offset.y > 1;
526
- const isOutsideX = boundaries.xMax - this.offset.x < -1 || boundaries.xMin - this.offset.x > 1;
527
- if (this.touchDirection === "horizontal" || this.touchDirection === "both") {
528
- this.velocity.x *= deceleration;
529
- if (Math.abs(this.velocity.x) < 0.01) {
530
- stopMomentumX = true;
531
- }
532
- }
533
- if (this.touchDirection === "vertical" || this.touchDirection === "both") {
534
- this.velocity.y *= deceleration;
535
- if (Math.abs(this.velocity.y) < 0.01) {
536
- stopMomentumY = true;
537
- }
538
- }
539
- this.setOffset(
540
- this.offset.x + this.velocity.x,
541
- this.offset.y + this.velocity.y
542
- );
543
- if (!isOutsideY && !isOutsideX && (stopMomentumX || this.touchDirection !== "horizontal" && this.touchDirection !== "both") && (stopMomentumY || this.touchDirection !== "vertical" && this.touchDirection !== "both")) {
544
- this.isMomentumScrolling = false;
545
- this.velocity = { x: 0, y: 0 };
546
- this.touchDirection = "none";
547
- }
548
- } else if (this.animationTarget) {
549
- const easedAlpha = easeOutQuad(this.animationTarget.alpha);
550
- const x = lerp(this.offset.x, this.animationTarget.x, easedAlpha);
551
- const y = lerp(this.offset.y, this.animationTarget.y, easedAlpha);
552
- this.setOffset(x, y);
553
- const newScale = lerp(this.scale, this.animationTarget.scale, easedAlpha);
554
- this.scale = newScale;
555
- if (this.animationTarget.alpha < 1) {
556
- this.animationTarget.alpha += this.animationTarget.speed;
557
- }
558
- if (Math.abs(this.offset.x - this.animationTarget.x) < 1 && Math.abs(this.offset.y - this.animationTarget.y) < 1 && Math.abs(this.scale - this.animationTarget.scale) < 0.02) {
559
- this.offset.x = this.animationTarget.x;
560
- this.offset.y = this.animationTarget.y;
561
- this.scale = this.animationTarget.scale;
562
- this.animationTarget = null;
563
- }
564
- } else if (this.scaleVelocity && this.scaleMidpoint) {
565
- }
566
- if (!this.isScaling && this.scaleMidpoint) {
567
- const x = this.scaleMidpoint.x;
568
- const y = this.scaleMidpoint.y;
569
- const targetX = (x - this.offset.x) / this.scale;
570
- const targetY = (y - this.offset.y) / this.scale;
571
- if (Math.abs(this.scale - this.maxScale) > 0.01 && Math.abs(this.scale - this.minScale) > 0.01) {
572
- const newScale = applyRubberBandEffect(
573
- this.scale,
574
- this.minScale,
575
- this.maxScale,
576
- 0.7
577
- );
578
- this.scale = newScale;
579
- this.setOffset(-targetX * this.scale + x, -targetY * this.scale + y);
580
- } else {
581
- this.isScaling = false;
582
- if (this.scale > this.maxScale) {
583
- this.scale = this.maxScale;
584
- } else if (this.scale < this.minScale) {
585
- this.scale = this.minScale;
586
- }
587
- this.setOffset(-targetX * this.scale + x, -targetY * this.scale + y);
588
- }
589
- }
590
- this.updateStyles();
591
- }
592
- getCenterX(targetScale) {
593
- const scaleToUse = targetScale || this.scale;
594
- const blockingRects = this.getBlockingRects ? this.getBlockingRects() : [];
595
- return calculateCenterPosition(
596
- blockingRects,
597
- { ...this.rootSize, x: 0, y: 0 },
598
- this.artboardEl.offsetWidth * scaleToUse
599
- );
600
- }
601
- animateTo(x, y, targetScale) {
602
- this.isMomentumScrolling = false;
603
- this.lastTouch = null;
604
- this.initialTouchPoint = null;
605
- this.isScaling = false;
606
- this.animationTarget = {
607
- x,
608
- y,
609
- scale: targetScale || this.scale,
610
- alpha: 0,
611
- speed: 0.01
612
- };
613
- }
614
- getEndY() {
615
- const v = this.artboardSize.height * this.scale;
616
- return -v + this.rootSize.height - this.padding;
617
- }
618
- animateOrJumpBy(y) {
619
- const diff = Date.now() - this.lastAnimateToTimestamp;
620
- if (diff < 300) {
621
- this.setOffset(
622
- this.offset.x,
623
- (this.animationTarget?.y || this.offset.y) + y
624
- );
625
- this.animationTarget = null;
626
- } else {
627
- this.animateTo(this.offset.x, this.offset.y + y);
628
- }
629
- this.lastAnimateToTimestamp = Date.now();
630
- }
631
- animateOrJumpTo(y) {
632
- const diff = Date.now() - this.lastAnimateToTimestamp;
633
- if (diff < 300) {
634
- this.setOffset(
635
- this.offset.x,
636
- (this.animationTarget?.y || this.offset.y) + y
637
- );
638
- this.animationTarget = null;
639
- } else {
640
- this.animateTo(this.offset.x, y);
641
- }
642
- this.lastAnimateToTimestamp = Date.now();
643
- }
644
- scrollPageUp() {
645
- this.animateOrJumpBy(this.rootSize.height);
646
- }
647
- scrollPageDown() {
648
- this.animateOrJumpBy(-this.rootSize.height);
649
- }
650
- scrollPageLeft() {
651
- this.animateOrJumpTo(
652
- Math.min(this.offset.y + this.rootSize.height, this.padding)
653
- );
654
- }
655
- scrollPageRight() {
656
- this.animateOrJumpTo(
657
- Math.max(this.offset.y - this.rootSize.height, this.getEndY())
658
- );
659
- }
660
- scrollToTop() {
661
- this.animateOrJumpTo(this.padding * 2);
662
- }
663
- scrollToEnd() {
664
- this.animateOrJumpTo(this.getEndY());
665
- }
666
- scaleToFit() {
667
- const targetScale = (this.rootSize.height - this.padding) / this.artboardSize.height;
668
- this.animateTo(this.getCenterX(targetScale), this.padding / 2, targetScale);
669
- }
670
- resetZoom() {
671
- const viewportCenterY = this.rootSize.height / 2;
672
- const currentCenterOnArtboard = (-this.offset.y + viewportCenterY) / this.scale;
673
- if (this.artboardSize.height < this.rootSize.height) {
674
- const newYOffset2 = this.rootSize.height / 2 - this.artboardSize.height / 2;
675
- return this.animateTo(this.getCenterX(1), newYOffset2, 1);
676
- }
677
- const newYOffset = Math.min(
678
- Math.max(
679
- -currentCenterOnArtboard + viewportCenterY,
680
- -this.artboardSize.height + this.rootSize.height - this.padding
681
- ),
682
- this.padding * 2
683
- );
684
- this.animateTo(this.getCenterX(1), newYOffset, 1);
685
- }
686
- updateStyles() {
687
- this.artboardEl.style.transform = `translate3d(${Math.round(this.offset.x * 10) / 10}px, ${Math.round(this.offset.y * 10) / 10}px, 0px) scale(${this.scale.toString()}) `;
688
- }
689
- getBoundaries(providedScale) {
690
- const targetScale = providedScale || this.scale;
691
- const artboardWidth = this.artboardSize.width * targetScale;
692
- const artboardHeight = this.artboardSize.height * targetScale;
693
- const xMin = -artboardWidth + 100 + 70;
694
- const xMax = this.rootSize.width - 50 - 100;
695
- const yMin = -artboardHeight;
696
- const yMax = this.rootSize.height - 50;
697
- return { xMin, xMax, yMin, yMax };
698
- }
699
- setScale(newScale) {
700
- this.scale = applyRubberBandEffect(
701
- newScale,
702
- this.minScale,
703
- this.maxScale,
704
- 0.2
705
- );
706
- }
707
- setOffset(x, y) {
708
- const { xMin, xMax, yMin, yMax } = this.getBoundaries();
709
- const adjustedX = applyRubberBandEffect(x, xMin, xMax);
710
- const adjustedY = applyRubberBandEffect(y, yMin, yMax);
711
- if (this.rootSize.width < 500) {
712
- this.offset.x = this.rootSize.width / 2 - this.artboardSize.width * this.scale / 2;
713
- } else {
714
- this.offset.x = adjustedX;
715
- }
716
- this.offset.y = adjustedY;
717
- }
718
- stopAnimate() {
719
- this.animationTarget = null;
720
- this.isMomentumScrolling = false;
721
- this.velocity = { x: 0, y: 0 };
722
- }
723
- scaleAroundPoint(x, y, newScale) {
724
- const targetX = (x - this.offset.x) / this.scale;
725
- const targetY = (y - this.offset.y) / this.scale;
726
- this.setScale(newScale);
727
- this.setOffset(-targetX * this.scale + x, -targetY * this.scale + y);
728
- }
729
- doZoom(x, y, delta) {
730
- const SCALE_BASE = 1.1;
731
- const scaleFactor = Math.pow(SCALE_BASE, -Math.sign(delta) / 1.25);
732
- const newScale = this.scale * scaleFactor;
733
- this.scaleAroundPoint(x, y, newScale);
734
- }
735
- onWheel(e) {
736
- this.stopAnimate();
737
- e.preventDefault();
738
- e.stopPropagation();
739
- if (e.ctrlKey) {
740
- this.doZoom(e.pageX, e.pageY, e.deltaY);
741
- } else {
742
- this.setOffset(
743
- this.offset.x + -(e.deltaX * this.scrollSpeed),
744
- this.offset.y + -(e.deltaY * this.scrollSpeed)
745
- );
746
- }
747
- }
748
- }