@vanduo-oss/framework 1.3.2 → 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 +13 -4
- package/css/components/draggable.css +3 -1
- package/dist/build-info.json +3 -3
- package/dist/vanduo.cjs.js +112 -18
- package/dist/vanduo.cjs.js.map +2 -2
- package/dist/vanduo.cjs.min.js +4 -4
- package/dist/vanduo.cjs.min.js.map +3 -3
- package/dist/vanduo.css +4 -2
- package/dist/vanduo.css.map +1 -1
- package/dist/vanduo.esm.js +112 -18
- package/dist/vanduo.esm.js.map +2 -2
- package/dist/vanduo.esm.min.js +4 -4
- package/dist/vanduo.esm.min.js.map +3 -3
- package/dist/vanduo.js +112 -18
- package/dist/vanduo.js.map +2 -2
- package/dist/vanduo.min.css +2 -2
- package/dist/vanduo.min.css.map +1 -1
- package/dist/vanduo.min.js +4 -4
- package/dist/vanduo.min.js.map +3 -3
- package/js/components/draggable.js +103 -12
- package/js/components/theme-customizer.js +22 -9
- package/js/components/theme-switcher.js +4 -0
- package/package.json +1 -1
package/dist/vanduo.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! Vanduo v1.3.
|
|
1
|
+
/*! Vanduo v1.3.3 | Built: 2026-04-10T21:45:12.664Z | git:281f4f6 | development */
|
|
2
2
|
(() => {
|
|
3
3
|
// js/utils/lifecycle.js
|
|
4
4
|
(function() {
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
// js/vanduo.js
|
|
108
108
|
(function() {
|
|
109
109
|
"use strict";
|
|
110
|
-
const VANDUO_VERSION = true ? "1.3.
|
|
110
|
+
const VANDUO_VERSION = true ? "1.3.3" : "0.0.0-dev";
|
|
111
111
|
const Vanduo2 = {
|
|
112
112
|
version: VANDUO_VERSION,
|
|
113
113
|
components: {},
|
|
@@ -3806,6 +3806,7 @@
|
|
|
3806
3806
|
loadPreferences: function() {
|
|
3807
3807
|
this.state.theme = this.getStorageValue(this.STORAGE_KEYS.THEME, this.DEFAULTS.THEME);
|
|
3808
3808
|
this.state.primary = this.getStorageValue(this.STORAGE_KEYS.PRIMARY, this.getDefaultPrimary(this.state.theme));
|
|
3809
|
+
this._normalizeDefaultPrimaryIfStaleWithStoredTheme();
|
|
3809
3810
|
this.state.neutral = this.getStorageValue(this.STORAGE_KEYS.NEUTRAL, this.DEFAULTS.NEUTRAL);
|
|
3810
3811
|
this.state.radius = this.getStorageValue(this.STORAGE_KEYS.RADIUS, this.DEFAULTS.RADIUS);
|
|
3811
3812
|
this.state.font = this.getStorageValue(this.STORAGE_KEYS.FONT, this.DEFAULTS.FONT);
|
|
@@ -3891,12 +3892,10 @@
|
|
|
3891
3892
|
mode = this.DEFAULTS.THEME;
|
|
3892
3893
|
}
|
|
3893
3894
|
this._isApplying = true;
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
if (newDefault !== this.state.primary) {
|
|
3899
|
-
this.applyPrimary(newDefault);
|
|
3895
|
+
if (this.isUsingDefaultPrimary()) {
|
|
3896
|
+
const expected = this.getDefaultPrimary(mode);
|
|
3897
|
+
if (this.state.primary !== expected) {
|
|
3898
|
+
this.applyPrimary(expected);
|
|
3900
3899
|
}
|
|
3901
3900
|
}
|
|
3902
3901
|
this.state.theme = mode;
|
|
@@ -4138,6 +4137,20 @@
|
|
|
4138
4137
|
isUsingDefaultPrimary: function() {
|
|
4139
4138
|
return this.state.primary === this.DEFAULTS.PRIMARY_LIGHT || this.state.primary === this.DEFAULTS.PRIMARY_DARK;
|
|
4140
4139
|
},
|
|
4140
|
+
/**
|
|
4141
|
+
* When primary is still one of the auto-default palette keys (black/amber) but
|
|
4142
|
+
* localStorage was written under a different theme (or OS changed in system mode),
|
|
4143
|
+
* align in-memory state before applyAllPreferences runs — avoids amber+light / black+dark drift.
|
|
4144
|
+
*/
|
|
4145
|
+
_normalizeDefaultPrimaryIfStaleWithStoredTheme: function() {
|
|
4146
|
+
if (!this.isUsingDefaultPrimary()) {
|
|
4147
|
+
return;
|
|
4148
|
+
}
|
|
4149
|
+
const expected = this.getDefaultPrimary(this.state.theme);
|
|
4150
|
+
if (this.state.primary !== expected) {
|
|
4151
|
+
this.state.primary = expected;
|
|
4152
|
+
}
|
|
4153
|
+
},
|
|
4141
4154
|
bindEvents: function() {
|
|
4142
4155
|
if (this.elements.trigger) {
|
|
4143
4156
|
this.addListener(this.elements.trigger, "click", (e) => {
|
|
@@ -4376,6 +4389,9 @@
|
|
|
4376
4389
|
this._onMediaChange = (_e) => {
|
|
4377
4390
|
if (this.state.preference === "system") {
|
|
4378
4391
|
this.applyTheme();
|
|
4392
|
+
if (window.ThemeCustomizer && typeof window.ThemeCustomizer.applyTheme === "function" && !window.ThemeCustomizer._isApplying) {
|
|
4393
|
+
window.ThemeCustomizer.applyTheme("system");
|
|
4394
|
+
}
|
|
4379
4395
|
}
|
|
4380
4396
|
};
|
|
4381
4397
|
this._mediaQuery.addEventListener("change", this._onMediaChange);
|
|
@@ -5607,6 +5623,8 @@
|
|
|
5607
5623
|
touchState: null,
|
|
5608
5624
|
// Feedback element
|
|
5609
5625
|
feedbackElement: null,
|
|
5626
|
+
// Shared selector used by init and touch reorder
|
|
5627
|
+
containerSelector: ".vd-draggable-container, .vd-draggable-container-vertical",
|
|
5610
5628
|
/**
|
|
5611
5629
|
* Initialize draggable components
|
|
5612
5630
|
*/
|
|
@@ -5618,7 +5636,7 @@
|
|
|
5618
5636
|
}
|
|
5619
5637
|
this.initDraggable(element);
|
|
5620
5638
|
});
|
|
5621
|
-
const containers = document.querySelectorAll(
|
|
5639
|
+
const containers = document.querySelectorAll(this.containerSelector);
|
|
5622
5640
|
containers.forEach((container) => {
|
|
5623
5641
|
if (!this.instances.has(container)) {
|
|
5624
5642
|
this.initContainer(container);
|
|
@@ -5862,10 +5880,16 @@
|
|
|
5862
5880
|
*/
|
|
5863
5881
|
handleTouchStart: function(e, element) {
|
|
5864
5882
|
const touch = e.touches[0];
|
|
5883
|
+
const rect = element.getBoundingClientRect();
|
|
5865
5884
|
this.touchState = {
|
|
5866
5885
|
element,
|
|
5867
5886
|
startX: touch.clientX,
|
|
5868
5887
|
startY: touch.clientY,
|
|
5888
|
+
lastX: touch.clientX,
|
|
5889
|
+
lastY: touch.clientY,
|
|
5890
|
+
// Keep preview anchored to the original grab point.
|
|
5891
|
+
offsetX: touch.clientX - rect.left,
|
|
5892
|
+
offsetY: touch.clientY - rect.top,
|
|
5869
5893
|
startTime: Date.now(),
|
|
5870
5894
|
isDragging: false
|
|
5871
5895
|
};
|
|
@@ -5878,6 +5902,8 @@
|
|
|
5878
5902
|
handleTouchMove: function(e, element) {
|
|
5879
5903
|
if (!this.touchState) return;
|
|
5880
5904
|
const touch = e.touches[0];
|
|
5905
|
+
this.touchState.lastX = touch.clientX;
|
|
5906
|
+
this.touchState.lastY = touch.clientY;
|
|
5881
5907
|
const deltaX = touch.clientX - this.touchState.startX;
|
|
5882
5908
|
const deltaY = touch.clientY - this.touchState.startY;
|
|
5883
5909
|
if (Math.abs(deltaX) > 10 || Math.abs(deltaY) > 10) {
|
|
@@ -5890,7 +5916,10 @@
|
|
|
5890
5916
|
element,
|
|
5891
5917
|
initialPosition: { x: this.touchState.startX, y: this.touchState.startY },
|
|
5892
5918
|
initialBounds: element.getBoundingClientRect(),
|
|
5893
|
-
data: this.getData(element)
|
|
5919
|
+
data: this.getData(element),
|
|
5920
|
+
// Preserve where inside the element the drag started for accurate ghost positioning.
|
|
5921
|
+
offsetX: this.touchState.offsetX,
|
|
5922
|
+
offsetY: this.touchState.offsetY
|
|
5894
5923
|
};
|
|
5895
5924
|
element.dispatchEvent(new CustomEvent("draggable:start", {
|
|
5896
5925
|
bubbles: true,
|
|
@@ -5912,7 +5941,8 @@
|
|
|
5912
5941
|
delta: { x: deltaX, y: deltaY }
|
|
5913
5942
|
}
|
|
5914
5943
|
}));
|
|
5915
|
-
|
|
5944
|
+
this.updateTouchDropZone(touch.clientX, touch.clientY);
|
|
5945
|
+
const container = element.closest(this.containerSelector);
|
|
5916
5946
|
if (container && container.contains(element)) {
|
|
5917
5947
|
this.handleReorder(container, element, touch.clientX, touch.clientY);
|
|
5918
5948
|
}
|
|
@@ -5927,6 +5957,17 @@
|
|
|
5927
5957
|
handleTouchEnd: function(e, element) {
|
|
5928
5958
|
if (this.touchState && this.touchState.isDragging) {
|
|
5929
5959
|
if (e.cancelable) e.preventDefault();
|
|
5960
|
+
const endTouch = e.changedTouches?.[0];
|
|
5961
|
+
const endPosition = {
|
|
5962
|
+
x: endTouch?.clientX ?? this.touchState.lastX ?? this.touchState.startX,
|
|
5963
|
+
y: endTouch?.clientY ?? this.touchState.lastY ?? this.touchState.startY
|
|
5964
|
+
};
|
|
5965
|
+
const dropZone = this.resolveDropZoneAtPoint(endPosition.x, endPosition.y) || this.touchState.overZone;
|
|
5966
|
+
if (dropZone) {
|
|
5967
|
+
this.dispatchDrop(dropZone, endPosition);
|
|
5968
|
+
} else if (this.touchState.overZone) {
|
|
5969
|
+
this.touchState.overZone.classList.remove("is-drag-over");
|
|
5970
|
+
}
|
|
5930
5971
|
element.classList.remove("is-dragging");
|
|
5931
5972
|
element.classList.add("is-dropped");
|
|
5932
5973
|
element.setAttribute("aria-grabbed", "false");
|
|
@@ -5934,7 +5975,6 @@
|
|
|
5934
5975
|
if (this.feedbackElement) {
|
|
5935
5976
|
this.feedbackElement.classList.add("hidden");
|
|
5936
5977
|
}
|
|
5937
|
-
const endTouch = e.changedTouches[0];
|
|
5938
5978
|
const data = this.currentDrag?.data || this.getData(element);
|
|
5939
5979
|
const startX = this.touchState?.startX || 0;
|
|
5940
5980
|
const startY = this.touchState?.startY || 0;
|
|
@@ -5943,10 +5983,10 @@
|
|
|
5943
5983
|
detail: {
|
|
5944
5984
|
element,
|
|
5945
5985
|
data,
|
|
5946
|
-
position:
|
|
5986
|
+
position: endPosition,
|
|
5947
5987
|
delta: {
|
|
5948
|
-
x:
|
|
5949
|
-
y:
|
|
5988
|
+
x: endPosition.x - startX,
|
|
5989
|
+
y: endPosition.y - startY
|
|
5950
5990
|
}
|
|
5951
5991
|
}
|
|
5952
5992
|
}));
|
|
@@ -5987,6 +6027,58 @@
|
|
|
5987
6027
|
*/
|
|
5988
6028
|
handleDrop: function(e, zone) {
|
|
5989
6029
|
e.preventDefault();
|
|
6030
|
+
this.dispatchDrop(zone, { x: e.clientX, y: e.clientY });
|
|
6031
|
+
},
|
|
6032
|
+
/**
|
|
6033
|
+
* Resolve a drop zone from viewport coordinates
|
|
6034
|
+
* @param {number} x
|
|
6035
|
+
* @param {number} y
|
|
6036
|
+
* @returns {HTMLElement|null}
|
|
6037
|
+
*/
|
|
6038
|
+
resolveDropZoneAtPoint: function(x, y) {
|
|
6039
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return null;
|
|
6040
|
+
if (typeof document.elementsFromPoint === "function") {
|
|
6041
|
+
const stacked = document.elementsFromPoint(x, y);
|
|
6042
|
+
for (const element of stacked) {
|
|
6043
|
+
const zone = element.closest(".vd-drop-zone");
|
|
6044
|
+
if (zone) return zone;
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
const target = document.elementFromPoint(x, y);
|
|
6048
|
+
const targetZone = target ? target.closest(".vd-drop-zone") : null;
|
|
6049
|
+
if (targetZone) return targetZone;
|
|
6050
|
+
const zones = document.querySelectorAll(".vd-drop-zone");
|
|
6051
|
+
for (const zone of zones) {
|
|
6052
|
+
const rect = zone.getBoundingClientRect();
|
|
6053
|
+
if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
|
|
6054
|
+
return zone;
|
|
6055
|
+
}
|
|
6056
|
+
}
|
|
6057
|
+
return null;
|
|
6058
|
+
},
|
|
6059
|
+
/**
|
|
6060
|
+
* Track and update active drop-zone hover state on touch devices
|
|
6061
|
+
* @param {number} x
|
|
6062
|
+
* @param {number} y
|
|
6063
|
+
*/
|
|
6064
|
+
updateTouchDropZone: function(x, y) {
|
|
6065
|
+
if (!this.touchState) return;
|
|
6066
|
+
const nextZone = this.resolveDropZoneAtPoint(x, y);
|
|
6067
|
+
const prevZone = this.touchState.overZone || null;
|
|
6068
|
+
if (prevZone && prevZone !== nextZone) {
|
|
6069
|
+
prevZone.classList.remove("is-drag-over");
|
|
6070
|
+
}
|
|
6071
|
+
if (nextZone && nextZone !== prevZone) {
|
|
6072
|
+
nextZone.classList.add("is-drag-over");
|
|
6073
|
+
}
|
|
6074
|
+
this.touchState.overZone = nextZone || null;
|
|
6075
|
+
},
|
|
6076
|
+
/**
|
|
6077
|
+
* Dispatch a normalized drop event for mouse and touch flows
|
|
6078
|
+
* @param {HTMLElement} zone
|
|
6079
|
+
* @param {{x:number, y:number}} position
|
|
6080
|
+
*/
|
|
6081
|
+
dispatchDrop: function(zone, position) {
|
|
5990
6082
|
zone.classList.remove("is-drag-over");
|
|
5991
6083
|
zone.dispatchEvent(new CustomEvent("draggable:drop", {
|
|
5992
6084
|
bubbles: true,
|
|
@@ -5994,7 +6086,7 @@
|
|
|
5994
6086
|
zone,
|
|
5995
6087
|
element: this.currentDrag?.element,
|
|
5996
6088
|
data: this.currentDrag?.data,
|
|
5997
|
-
position
|
|
6089
|
+
position
|
|
5998
6090
|
}
|
|
5999
6091
|
}));
|
|
6000
6092
|
},
|
|
@@ -6095,9 +6187,11 @@
|
|
|
6095
6187
|
this.feedbackElement.innerHTML = "";
|
|
6096
6188
|
const clone = this.currentDrag.element.cloneNode(true);
|
|
6097
6189
|
this.feedbackElement.appendChild(clone);
|
|
6190
|
+
const offsetX = this.currentDrag.offsetX ?? 20;
|
|
6191
|
+
const offsetY = this.currentDrag.offsetY ?? 20;
|
|
6098
6192
|
Object.assign(this.feedbackElement.style, {
|
|
6099
|
-
left: x -
|
|
6100
|
-
top: y -
|
|
6193
|
+
left: x - offsetX + "px",
|
|
6194
|
+
top: y - offsetY + "px",
|
|
6101
6195
|
width: rect.width + "px",
|
|
6102
6196
|
height: rect.height + "px"
|
|
6103
6197
|
});
|