@vanduo-oss/framework 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -14
- package/css/components/draggable.css +3 -1
- package/css/components/music-player.css +578 -0
- package/css/vanduo.css +1 -0
- package/dist/build-info.json +3 -3
- package/dist/vanduo.cjs.js +773 -18
- package/dist/vanduo.cjs.js.map +3 -3
- package/dist/vanduo.cjs.min.js +5 -5
- package/dist/vanduo.cjs.min.js.map +4 -4
- package/dist/vanduo.css +511 -2
- package/dist/vanduo.css.map +1 -1
- package/dist/vanduo.esm.js +773 -18
- package/dist/vanduo.esm.js.map +3 -3
- package/dist/vanduo.esm.min.js +5 -5
- package/dist/vanduo.esm.min.js.map +4 -4
- package/dist/vanduo.js +773 -18
- package/dist/vanduo.js.map +3 -3
- package/dist/vanduo.min.css +2 -2
- package/dist/vanduo.min.css.map +1 -1
- package/dist/vanduo.min.js +5 -5
- package/dist/vanduo.min.js.map +4 -4
- package/js/components/draggable.js +103 -12
- package/js/components/music-player.js +848 -0
- package/js/components/theme-customizer.js +22 -9
- package/js/components/theme-switcher.js +4 -0
- package/js/index.js +1 -0
- package/package.json +1 -1
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
touchState: null,
|
|
19
19
|
// Feedback element
|
|
20
20
|
feedbackElement: null,
|
|
21
|
+
// Shared selector used by init and touch reorder
|
|
22
|
+
containerSelector: '.vd-draggable-container, .vd-draggable-container-vertical',
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Initialize draggable components
|
|
@@ -32,7 +34,7 @@
|
|
|
32
34
|
this.initDraggable(element);
|
|
33
35
|
});
|
|
34
36
|
|
|
35
|
-
const containers = document.querySelectorAll(
|
|
37
|
+
const containers = document.querySelectorAll(this.containerSelector);
|
|
36
38
|
containers.forEach(container => {
|
|
37
39
|
if (!this.instances.has(container)) {
|
|
38
40
|
this.initContainer(container);
|
|
@@ -369,10 +371,16 @@
|
|
|
369
371
|
// Don't prevent default here — it blocks scrolling.
|
|
370
372
|
// We only prevent default in touchmove once drag threshold is reached.
|
|
371
373
|
const touch = e.touches[0];
|
|
374
|
+
const rect = element.getBoundingClientRect();
|
|
372
375
|
this.touchState = {
|
|
373
376
|
element: element,
|
|
374
377
|
startX: touch.clientX,
|
|
375
378
|
startY: touch.clientY,
|
|
379
|
+
lastX: touch.clientX,
|
|
380
|
+
lastY: touch.clientY,
|
|
381
|
+
// Keep preview anchored to the original grab point.
|
|
382
|
+
offsetX: touch.clientX - rect.left,
|
|
383
|
+
offsetY: touch.clientY - rect.top,
|
|
376
384
|
startTime: Date.now(),
|
|
377
385
|
isDragging: false
|
|
378
386
|
};
|
|
@@ -387,6 +395,8 @@
|
|
|
387
395
|
if (!this.touchState) return;
|
|
388
396
|
|
|
389
397
|
const touch = e.touches[0];
|
|
398
|
+
this.touchState.lastX = touch.clientX;
|
|
399
|
+
this.touchState.lastY = touch.clientY;
|
|
390
400
|
const deltaX = touch.clientX - this.touchState.startX;
|
|
391
401
|
const deltaY = touch.clientY - this.touchState.startY;
|
|
392
402
|
|
|
@@ -405,7 +415,10 @@
|
|
|
405
415
|
element: element,
|
|
406
416
|
initialPosition: { x: this.touchState.startX, y: this.touchState.startY },
|
|
407
417
|
initialBounds: element.getBoundingClientRect(),
|
|
408
|
-
data: this.getData(element)
|
|
418
|
+
data: this.getData(element),
|
|
419
|
+
// Preserve where inside the element the drag started for accurate ghost positioning.
|
|
420
|
+
offsetX: this.touchState.offsetX,
|
|
421
|
+
offsetY: this.touchState.offsetY
|
|
409
422
|
};
|
|
410
423
|
|
|
411
424
|
// Dispatch event
|
|
@@ -434,8 +447,10 @@
|
|
|
434
447
|
}
|
|
435
448
|
}));
|
|
436
449
|
|
|
450
|
+
this.updateTouchDropZone(touch.clientX, touch.clientY);
|
|
451
|
+
|
|
437
452
|
// Reorder for touch
|
|
438
|
-
const container = element.closest(
|
|
453
|
+
const container = element.closest(this.containerSelector);
|
|
439
454
|
if (container && container.contains(element)) {
|
|
440
455
|
this.handleReorder(container, element, touch.clientX, touch.clientY);
|
|
441
456
|
}
|
|
@@ -451,6 +466,18 @@
|
|
|
451
466
|
handleTouchEnd: function (e, element) {
|
|
452
467
|
if (this.touchState && this.touchState.isDragging) {
|
|
453
468
|
if (e.cancelable) e.preventDefault();
|
|
469
|
+
const endTouch = e.changedTouches?.[0];
|
|
470
|
+
const endPosition = {
|
|
471
|
+
x: endTouch?.clientX ?? this.touchState.lastX ?? this.touchState.startX,
|
|
472
|
+
y: endTouch?.clientY ?? this.touchState.lastY ?? this.touchState.startY
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
const dropZone = this.resolveDropZoneAtPoint(endPosition.x, endPosition.y) || this.touchState.overZone;
|
|
476
|
+
if (dropZone) {
|
|
477
|
+
this.dispatchDrop(dropZone, endPosition);
|
|
478
|
+
} else if (this.touchState.overZone) {
|
|
479
|
+
this.touchState.overZone.classList.remove('is-drag-over');
|
|
480
|
+
}
|
|
454
481
|
|
|
455
482
|
element.classList.remove('is-dragging');
|
|
456
483
|
element.classList.add('is-dropped');
|
|
@@ -463,7 +490,6 @@
|
|
|
463
490
|
}
|
|
464
491
|
|
|
465
492
|
// Dispatch event
|
|
466
|
-
const endTouch = e.changedTouches[0];
|
|
467
493
|
const data = this.currentDrag?.data || this.getData(element);
|
|
468
494
|
const startX = this.touchState?.startX || 0;
|
|
469
495
|
const startY = this.touchState?.startY || 0;
|
|
@@ -473,10 +499,10 @@
|
|
|
473
499
|
detail: {
|
|
474
500
|
element: element,
|
|
475
501
|
data: data,
|
|
476
|
-
position:
|
|
502
|
+
position: endPosition,
|
|
477
503
|
delta: {
|
|
478
|
-
x:
|
|
479
|
-
y:
|
|
504
|
+
x: endPosition.x - startX,
|
|
505
|
+
y: endPosition.y - startY
|
|
480
506
|
}
|
|
481
507
|
}
|
|
482
508
|
}));
|
|
@@ -523,16 +549,79 @@
|
|
|
523
549
|
*/
|
|
524
550
|
handleDrop: function (e, zone) {
|
|
525
551
|
e.preventDefault();
|
|
526
|
-
zone.
|
|
552
|
+
this.dispatchDrop(zone, { x: e.clientX, y: e.clientY });
|
|
553
|
+
},
|
|
527
554
|
|
|
528
|
-
|
|
555
|
+
/**
|
|
556
|
+
* Resolve a drop zone from viewport coordinates
|
|
557
|
+
* @param {number} x
|
|
558
|
+
* @param {number} y
|
|
559
|
+
* @returns {HTMLElement|null}
|
|
560
|
+
*/
|
|
561
|
+
resolveDropZoneAtPoint: function (x, y) {
|
|
562
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return null;
|
|
563
|
+
|
|
564
|
+
// Prefer the full stacking list so overlays/top elements don't hide real drop targets.
|
|
565
|
+
if (typeof document.elementsFromPoint === 'function') {
|
|
566
|
+
const stacked = document.elementsFromPoint(x, y);
|
|
567
|
+
for (const element of stacked) {
|
|
568
|
+
const zone = element.closest('.vd-drop-zone');
|
|
569
|
+
if (zone) return zone;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const target = document.elementFromPoint(x, y);
|
|
574
|
+
const targetZone = target ? target.closest('.vd-drop-zone') : null;
|
|
575
|
+
if (targetZone) return targetZone;
|
|
576
|
+
|
|
577
|
+
// Last-resort fallback for mobile emulation edge cases.
|
|
578
|
+
const zones = document.querySelectorAll('.vd-drop-zone');
|
|
579
|
+
for (const zone of zones) {
|
|
580
|
+
const rect = zone.getBoundingClientRect();
|
|
581
|
+
if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
|
|
582
|
+
return zone;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return null;
|
|
587
|
+
},
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Track and update active drop-zone hover state on touch devices
|
|
591
|
+
* @param {number} x
|
|
592
|
+
* @param {number} y
|
|
593
|
+
*/
|
|
594
|
+
updateTouchDropZone: function (x, y) {
|
|
595
|
+
if (!this.touchState) return;
|
|
596
|
+
|
|
597
|
+
const nextZone = this.resolveDropZoneAtPoint(x, y);
|
|
598
|
+
const prevZone = this.touchState.overZone || null;
|
|
599
|
+
|
|
600
|
+
if (prevZone && prevZone !== nextZone) {
|
|
601
|
+
prevZone.classList.remove('is-drag-over');
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
if (nextZone && nextZone !== prevZone) {
|
|
605
|
+
nextZone.classList.add('is-drag-over');
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
this.touchState.overZone = nextZone || null;
|
|
609
|
+
},
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Dispatch a normalized drop event for mouse and touch flows
|
|
613
|
+
* @param {HTMLElement} zone
|
|
614
|
+
* @param {{x:number, y:number}} position
|
|
615
|
+
*/
|
|
616
|
+
dispatchDrop: function (zone, position) {
|
|
617
|
+
zone.classList.remove('is-drag-over');
|
|
529
618
|
zone.dispatchEvent(new CustomEvent('draggable:drop', {
|
|
530
619
|
bubbles: true,
|
|
531
620
|
detail: {
|
|
532
621
|
zone: zone,
|
|
533
622
|
element: this.currentDrag?.element,
|
|
534
623
|
data: this.currentDrag?.data,
|
|
535
|
-
position:
|
|
624
|
+
position: position
|
|
536
625
|
}
|
|
537
626
|
}));
|
|
538
627
|
},
|
|
@@ -650,9 +739,11 @@
|
|
|
650
739
|
this.feedbackElement.appendChild(clone);
|
|
651
740
|
|
|
652
741
|
// Set styles
|
|
742
|
+
const offsetX = this.currentDrag.offsetX ?? 20;
|
|
743
|
+
const offsetY = this.currentDrag.offsetY ?? 20;
|
|
653
744
|
Object.assign(this.feedbackElement.style, {
|
|
654
|
-
left: (x -
|
|
655
|
-
top: (y -
|
|
745
|
+
left: (x - offsetX) + 'px',
|
|
746
|
+
top: (y - offsetY) + 'px',
|
|
656
747
|
width: rect.width + 'px',
|
|
657
748
|
height: rect.height + 'px'
|
|
658
749
|
});
|