@masters-union/union-stack 0.3.12 → 0.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdn/loader.v1.global.js +2 -2
- package/dist/cdn/loader.v1.global.js.map +1 -1
- package/dist/{chunk-BLZGF6JP.cjs → chunk-24FXFOLY.cjs} +3 -3
- package/dist/{chunk-BLZGF6JP.cjs.map → chunk-24FXFOLY.cjs.map} +1 -1
- package/dist/{chunk-UPKEFUU6.js → chunk-A6QABSM5.js} +3 -3
- package/dist/{chunk-UPKEFUU6.js.map → chunk-A6QABSM5.js.map} +1 -1
- package/dist/{chunk-XGSFHZSI.js → chunk-LOOZO22K.js} +3 -3
- package/dist/{chunk-XGSFHZSI.js.map → chunk-LOOZO22K.js.map} +1 -1
- package/dist/{chunk-45FKUCRN.cjs → chunk-P32VSH6B.cjs} +7 -7
- package/dist/{chunk-45FKUCRN.cjs.map → chunk-P32VSH6B.cjs.map} +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.js +3 -3
- package/dist/node.cjs +7 -7
- package/dist/node.js +1 -1
- package/dist/picker.cjs +73 -54
- package/dist/picker.cjs.map +1 -1
- package/dist/picker.js +73 -54
- package/dist/picker.js.map +1 -1
- package/dist/react.cjs +3 -3
- package/dist/react.js +2 -2
- package/package.json +1 -1
package/dist/picker.js
CHANGED
|
@@ -660,8 +660,6 @@ var ImageEditor = class {
|
|
|
660
660
|
constructor(opts) {
|
|
661
661
|
this.opts = opts;
|
|
662
662
|
this.cropBox = null;
|
|
663
|
-
// What's currently rendered to the user, sized to fit MAX_DISPLAY.
|
|
664
|
-
this.displayScale = 1;
|
|
665
663
|
// Tracks whether the working canvas has transparency (post-circle), so
|
|
666
664
|
// export() can pick PNG vs JPEG correctly.
|
|
667
665
|
this.hasAlpha = false;
|
|
@@ -673,12 +671,13 @@ var ImageEditor = class {
|
|
|
673
671
|
this.dragStart = null;
|
|
674
672
|
this.onPointerMove = (e) => {
|
|
675
673
|
if (!this.dragKind || !this.dragStart || !this.cropRect) return;
|
|
676
|
-
const
|
|
677
|
-
const
|
|
674
|
+
const m = this.canvasMetrics();
|
|
675
|
+
const dx = (e.clientX - this.dragStart.px) / (m.scaleX || 1);
|
|
676
|
+
const dy = (e.clientY - this.dragStart.py) / (m.scaleY || 1);
|
|
678
677
|
const start = this.dragStart.rect;
|
|
679
|
-
const maxW = this.
|
|
680
|
-
const maxH = this.
|
|
681
|
-
const min =
|
|
678
|
+
const maxW = this.working.width;
|
|
679
|
+
const maxH = this.working.height;
|
|
680
|
+
const min = this.minCropImg();
|
|
682
681
|
if (this.aspect && this.dragKind !== "move") {
|
|
683
682
|
switch (this.dragKind) {
|
|
684
683
|
case "se":
|
|
@@ -874,7 +873,6 @@ var ImageEditor = class {
|
|
|
874
873
|
const dh = Math.max(1, Math.round(wh * scale));
|
|
875
874
|
this.displayCanvas.width = dw;
|
|
876
875
|
this.displayCanvas.height = dh;
|
|
877
|
-
this.displayScale = scale;
|
|
878
876
|
const ctx = this.displayCanvas.getContext("2d");
|
|
879
877
|
if (!ctx) return;
|
|
880
878
|
ctx.clearRect(0, 0, dw, dh);
|
|
@@ -893,43 +891,44 @@ var ImageEditor = class {
|
|
|
893
891
|
this.mode = "crop";
|
|
894
892
|
this.cropTool.dataset.active = "true";
|
|
895
893
|
this.cropTool.innerHTML = `${ICON.check} <span>Apply crop</span>`;
|
|
896
|
-
const
|
|
897
|
-
const
|
|
894
|
+
const iw = this.working.width;
|
|
895
|
+
const ih = this.working.height;
|
|
898
896
|
if (this.aspect) {
|
|
899
897
|
const a = this.aspect;
|
|
900
|
-
|
|
898
|
+
const minImg = this.minCropImg();
|
|
899
|
+
let w = iw;
|
|
901
900
|
let h = w / a;
|
|
902
|
-
if (h >
|
|
903
|
-
h =
|
|
901
|
+
if (h > ih) {
|
|
902
|
+
h = ih;
|
|
904
903
|
w = h * a;
|
|
905
904
|
}
|
|
906
905
|
w = w * 0.9;
|
|
907
906
|
h = w / a;
|
|
908
|
-
if (w <
|
|
909
|
-
w =
|
|
907
|
+
if (w < minImg) {
|
|
908
|
+
w = minImg;
|
|
910
909
|
h = w / a;
|
|
911
910
|
}
|
|
912
|
-
if (h <
|
|
913
|
-
h =
|
|
911
|
+
if (h < minImg) {
|
|
912
|
+
h = minImg;
|
|
914
913
|
w = h * a;
|
|
915
914
|
}
|
|
916
|
-
if (w >
|
|
917
|
-
w =
|
|
915
|
+
if (w > iw) {
|
|
916
|
+
w = iw;
|
|
918
917
|
h = w / a;
|
|
919
918
|
}
|
|
920
|
-
if (h >
|
|
921
|
-
h =
|
|
919
|
+
if (h > ih) {
|
|
920
|
+
h = ih;
|
|
922
921
|
w = h * a;
|
|
923
922
|
}
|
|
924
923
|
this.cropRect = {
|
|
925
|
-
x: Math.round((
|
|
926
|
-
y: Math.round((
|
|
924
|
+
x: Math.round((iw - w) / 2),
|
|
925
|
+
y: Math.round((ih - h) / 2),
|
|
927
926
|
w,
|
|
928
927
|
h
|
|
929
928
|
};
|
|
930
929
|
} else {
|
|
931
|
-
const inset = Math.round(Math.min(
|
|
932
|
-
this.cropRect = { x: inset, y: inset, w:
|
|
930
|
+
const inset = Math.round(Math.min(iw, ih) * 0.1);
|
|
931
|
+
this.cropRect = { x: inset, y: inset, w: iw - inset * 2, h: ih - inset * 2 };
|
|
933
932
|
}
|
|
934
933
|
this.renderCropBox();
|
|
935
934
|
const locked = this.aspect !== null;
|
|
@@ -964,28 +963,28 @@ var ImageEditor = class {
|
|
|
964
963
|
}
|
|
965
964
|
// Push the current crop frame size (in image/output pixels) into the inputs,
|
|
966
965
|
// skipping whichever the user is actively editing so we don't fight typing.
|
|
966
|
+
// cropRect is already in image px, so this is a direct read.
|
|
967
967
|
syncCropDimsInputs() {
|
|
968
968
|
if (!this.cropRect || !this.widthInput || !this.heightInput) return;
|
|
969
|
-
const
|
|
970
|
-
const
|
|
971
|
-
const hImg = Math.max(1, Math.round(this.cropRect.h / s));
|
|
969
|
+
const wImg = Math.max(1, Math.round(this.cropRect.w));
|
|
970
|
+
const hImg = Math.max(1, Math.round(this.cropRect.h));
|
|
972
971
|
if (document.activeElement !== this.widthInput) this.widthInput.value = String(wImg);
|
|
973
972
|
if (document.activeElement !== this.heightInput) this.heightInput.value = String(hImg);
|
|
974
973
|
}
|
|
975
|
-
// Free-form only: resize the crop frame from a typed pixel dimension.
|
|
976
|
-
// at the frame's current top-left and clamped to the
|
|
974
|
+
// Free-form only: resize the crop frame from a typed output-pixel dimension.
|
|
975
|
+
// Anchored at the frame's current top-left and clamped to the image + min size.
|
|
977
976
|
onDimInput(axis) {
|
|
978
977
|
if (this.aspect !== null || !this.cropRect) return;
|
|
979
|
-
const s = this.displayScale || 1;
|
|
980
978
|
const input = axis === "w" ? this.widthInput : this.heightInput;
|
|
981
979
|
const valImg = parseInt(input.value, 10);
|
|
982
980
|
if (!Number.isFinite(valImg) || valImg <= 0) return;
|
|
981
|
+
const min = this.minCropImg();
|
|
983
982
|
if (axis === "w") {
|
|
984
|
-
const maxW = this.
|
|
985
|
-
this.cropRect = { ...this.cropRect, w: clamp(
|
|
983
|
+
const maxW = this.working.width - this.cropRect.x;
|
|
984
|
+
this.cropRect = { ...this.cropRect, w: clamp(valImg, min, maxW) };
|
|
986
985
|
} else {
|
|
987
|
-
const maxH = this.
|
|
988
|
-
this.cropRect = { ...this.cropRect, h: clamp(
|
|
986
|
+
const maxH = this.working.height - this.cropRect.y;
|
|
987
|
+
this.cropRect = { ...this.cropRect, h: clamp(valImg, min, maxH) };
|
|
989
988
|
}
|
|
990
989
|
this.updateCropBox();
|
|
991
990
|
}
|
|
@@ -1008,16 +1007,35 @@ var ImageEditor = class {
|
|
|
1008
1007
|
this.cropBox = box;
|
|
1009
1008
|
this.updateCropBox();
|
|
1010
1009
|
}
|
|
1010
|
+
// The crop rect is stored in IMAGE (working-canvas / output) pixels — the same
|
|
1011
|
+
// space we ultimately crop in — so the on-screen selection always matches the
|
|
1012
|
+
// pixels we extract, regardless of how CSS scales the displayed canvas. These
|
|
1013
|
+
// metrics convert between image px and the canvas's live on-screen size.
|
|
1014
|
+
canvasMetrics() {
|
|
1015
|
+
const c = this.displayCanvas.getBoundingClientRect();
|
|
1016
|
+
const w = this.canvasWrap.getBoundingClientRect();
|
|
1017
|
+
return {
|
|
1018
|
+
scaleX: c.width / (this.working.width || 1),
|
|
1019
|
+
// CSS px per image px
|
|
1020
|
+
scaleY: c.height / (this.working.height || 1),
|
|
1021
|
+
offX: c.left - w.left,
|
|
1022
|
+
// canvas offset inside wrap
|
|
1023
|
+
offY: c.top - w.top
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
// Minimum crop size in IMAGE px, sized so the handles stay ~MIN_CROP px apart
|
|
1027
|
+
// on screen no matter how zoomed the canvas is.
|
|
1028
|
+
minCropImg() {
|
|
1029
|
+
const { scaleX } = this.canvasMetrics();
|
|
1030
|
+
return scaleX > 0 ? MIN_CROP / scaleX : MIN_CROP;
|
|
1031
|
+
}
|
|
1011
1032
|
updateCropBox() {
|
|
1012
1033
|
if (!this.cropBox || !this.cropRect) return;
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
this.cropBox.style.
|
|
1018
|
-
this.cropBox.style.top = `${top}px`;
|
|
1019
|
-
this.cropBox.style.width = `${this.cropRect.w}px`;
|
|
1020
|
-
this.cropBox.style.height = `${this.cropRect.h}px`;
|
|
1034
|
+
const m = this.canvasMetrics();
|
|
1035
|
+
this.cropBox.style.left = `${m.offX + this.cropRect.x * m.scaleX}px`;
|
|
1036
|
+
this.cropBox.style.top = `${m.offY + this.cropRect.y * m.scaleY}px`;
|
|
1037
|
+
this.cropBox.style.width = `${this.cropRect.w * m.scaleX}px`;
|
|
1038
|
+
this.cropBox.style.height = `${this.cropRect.h * m.scaleY}px`;
|
|
1021
1039
|
this.syncCropDimsInputs();
|
|
1022
1040
|
}
|
|
1023
1041
|
// ---- drag handlers (crop) ----------------------------------------------
|
|
@@ -1035,12 +1053,13 @@ var ImageEditor = class {
|
|
|
1035
1053
|
// the ratio exact; both are clamped so the rect stays on-canvas.
|
|
1036
1054
|
lockedRectFromDrag(anchorX, anchorY, desiredW, signX, signY) {
|
|
1037
1055
|
const a = this.aspect;
|
|
1038
|
-
const maxW = this.
|
|
1039
|
-
const maxH = this.
|
|
1040
|
-
|
|
1056
|
+
const maxW = this.working.width;
|
|
1057
|
+
const maxH = this.working.height;
|
|
1058
|
+
const min = this.minCropImg();
|
|
1059
|
+
let w = Math.max(min, desiredW);
|
|
1041
1060
|
let h = w / a;
|
|
1042
|
-
if (h <
|
|
1043
|
-
h =
|
|
1061
|
+
if (h < min) {
|
|
1062
|
+
h = min;
|
|
1044
1063
|
w = h * a;
|
|
1045
1064
|
}
|
|
1046
1065
|
const roomX = signX > 0 ? maxW - anchorX : anchorX;
|
|
@@ -1057,11 +1076,10 @@ var ImageEditor = class {
|
|
|
1057
1076
|
this.exitCropMode();
|
|
1058
1077
|
return;
|
|
1059
1078
|
}
|
|
1060
|
-
const
|
|
1061
|
-
const
|
|
1062
|
-
const
|
|
1063
|
-
const
|
|
1064
|
-
const sh = Math.round(this.cropRect.h / s);
|
|
1079
|
+
const sx = clamp(Math.round(this.cropRect.x), 0, this.working.width - 1);
|
|
1080
|
+
const sy = clamp(Math.round(this.cropRect.y), 0, this.working.height - 1);
|
|
1081
|
+
const sw = clamp(Math.round(this.cropRect.w), 1, this.working.width - sx);
|
|
1082
|
+
const sh = clamp(Math.round(this.cropRect.h), 1, this.working.height - sy);
|
|
1065
1083
|
const next = document.createElement("canvas");
|
|
1066
1084
|
next.width = sw;
|
|
1067
1085
|
next.height = sh;
|
|
@@ -1126,6 +1144,7 @@ var ImageEditor = class {
|
|
|
1126
1144
|
// ---- apply --------------------------------------------------------------
|
|
1127
1145
|
async applyAndClose() {
|
|
1128
1146
|
this.applyBtn.disabled = true;
|
|
1147
|
+
if (this.mode === "crop") this.applyCrop();
|
|
1129
1148
|
try {
|
|
1130
1149
|
const file = await this.exportFile();
|
|
1131
1150
|
this.opts.onApply(file);
|
|
@@ -1384,10 +1403,10 @@ var Picker = class {
|
|
|
1384
1403
|
this.$urlSource = this.renderUrlSource();
|
|
1385
1404
|
body.appendChild(this.$urlSource);
|
|
1386
1405
|
}
|
|
1387
|
-
this.activateSource(sources[0] ?? "device");
|
|
1388
1406
|
this.$list = el2("div", "us-file-list");
|
|
1389
1407
|
body.appendChild(this.$list);
|
|
1390
1408
|
panel.appendChild(body);
|
|
1409
|
+
this.activateSource(sources[0] ?? "device");
|
|
1391
1410
|
const autoUpload = this.opts.autoUpload === true;
|
|
1392
1411
|
const actions = el2("div", "us-actions");
|
|
1393
1412
|
this.$summary = el2("div", "us-actions-summary", "");
|