@masters-union/union-stack 0.3.10 → 0.3.11
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 +14 -2
- package/dist/cdn/loader.v1.global.js.map +1 -1
- package/dist/{chunk-IV76YPDA.cjs → chunk-NIO443GV.cjs} +7 -7
- package/dist/{chunk-IV76YPDA.cjs.map → chunk-NIO443GV.cjs.map} +1 -1
- package/dist/{chunk-F4EVNUJZ.cjs → chunk-NOAB2Q4B.cjs} +3 -3
- package/dist/{chunk-F4EVNUJZ.cjs.map → chunk-NOAB2Q4B.cjs.map} +1 -1
- package/dist/{chunk-IIVRPVNX.js → chunk-SP4HHLZB.js} +3 -3
- package/dist/{chunk-IIVRPVNX.js.map → chunk-SP4HHLZB.js.map} +1 -1
- package/dist/{chunk-MFZ2JGLP.js → chunk-Z5PZQVST.js} +3 -3
- package/dist/{chunk-MFZ2JGLP.js.map → chunk-Z5PZQVST.js.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 +60 -23
- package/dist/picker.cjs.map +1 -1
- package/dist/picker.d.cts +1 -0
- package/dist/picker.d.ts +1 -0
- package/dist/picker.js +60 -23
- 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.d.cts
CHANGED
package/dist/picker.d.ts
CHANGED
package/dist/picker.js
CHANGED
|
@@ -105,6 +105,10 @@ var BASE_CSS = `
|
|
|
105
105
|
.us-picker-backdrop {
|
|
106
106
|
--us-font: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
107
107
|
--us-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
|
|
108
|
+
/* Default to a light color-scheme so native controls never inherit the
|
|
109
|
+
visitor's OS dark mode; picker.ts overrides this to match the resolved
|
|
110
|
+
theme mode on mount. */
|
|
111
|
+
color-scheme: light;
|
|
108
112
|
position: fixed; inset: 0; z-index: 2147483000;
|
|
109
113
|
background: rgba(2, 6, 23, 0.4);
|
|
110
114
|
-webkit-backdrop-filter: blur(8px);
|
|
@@ -277,6 +281,14 @@ var BASE_CSS = `
|
|
|
277
281
|
color: var(--us-muted); font-size: 11px; flex-shrink: 0;
|
|
278
282
|
font-family: var(--us-mono); letter-spacing: 0;
|
|
279
283
|
}
|
|
284
|
+
/* Failure reason \u2014 full-width, danger-colored, wraps. Collapses entirely when
|
|
285
|
+
empty so non-failed rows keep their original height. */
|
|
286
|
+
.us-file-error {
|
|
287
|
+
color: var(--us-danger); font-size: 12px; line-height: 1.35;
|
|
288
|
+
margin-top: 4px; letter-spacing: -0.006em;
|
|
289
|
+
overflow-wrap: anywhere;
|
|
290
|
+
}
|
|
291
|
+
.us-file-error:empty { display: none; }
|
|
280
292
|
|
|
281
293
|
.us-file-progress {
|
|
282
294
|
height: 3px; background: var(--us-border); border-radius: 999px; overflow: hidden;
|
|
@@ -854,21 +866,30 @@ var ImageEditor = class {
|
|
|
854
866
|
const dw = this.displayCanvas.width;
|
|
855
867
|
const dh = this.displayCanvas.height;
|
|
856
868
|
if (this.aspect) {
|
|
869
|
+
const a = this.aspect;
|
|
857
870
|
let w = dw;
|
|
858
|
-
let h = w /
|
|
871
|
+
let h = w / a;
|
|
859
872
|
if (h > dh) {
|
|
860
873
|
h = dh;
|
|
861
|
-
w = h *
|
|
874
|
+
w = h * a;
|
|
875
|
+
}
|
|
876
|
+
w = w * 0.9;
|
|
877
|
+
h = w / a;
|
|
878
|
+
if (w < MIN_CROP) {
|
|
879
|
+
w = MIN_CROP;
|
|
880
|
+
h = w / a;
|
|
881
|
+
}
|
|
882
|
+
if (h < MIN_CROP) {
|
|
883
|
+
h = MIN_CROP;
|
|
884
|
+
w = h * a;
|
|
862
885
|
}
|
|
863
|
-
w = Math.max(MIN_CROP, Math.round(w * 0.9));
|
|
864
|
-
h = Math.max(MIN_CROP, Math.round(w / this.aspect));
|
|
865
886
|
if (w > dw) {
|
|
866
887
|
w = dw;
|
|
867
|
-
h = w /
|
|
888
|
+
h = w / a;
|
|
868
889
|
}
|
|
869
890
|
if (h > dh) {
|
|
870
891
|
h = dh;
|
|
871
|
-
w = h *
|
|
892
|
+
w = h * a;
|
|
872
893
|
}
|
|
873
894
|
this.cropRect = {
|
|
874
895
|
x: Math.round((dw - w) / 2),
|
|
@@ -989,6 +1010,7 @@ var ImageEditor = class {
|
|
|
989
1010
|
this.working = next;
|
|
990
1011
|
this.exitCropMode();
|
|
991
1012
|
this.markEdited(true);
|
|
1013
|
+
this.opts.onAspectReset?.();
|
|
992
1014
|
this.draw();
|
|
993
1015
|
}
|
|
994
1016
|
applyCircle() {
|
|
@@ -1012,11 +1034,13 @@ var ImageEditor = class {
|
|
|
1012
1034
|
this.hasAlpha = true;
|
|
1013
1035
|
this.exitCropMode();
|
|
1014
1036
|
this.markEdited(true);
|
|
1037
|
+
this.opts.onAspectReset?.();
|
|
1015
1038
|
this.draw();
|
|
1016
1039
|
}
|
|
1017
1040
|
async revert() {
|
|
1018
1041
|
await this.loadTrueOriginalIntoWorking();
|
|
1019
1042
|
this.exitCropMode();
|
|
1043
|
+
this.opts.onAspectReset?.();
|
|
1020
1044
|
this.draw();
|
|
1021
1045
|
}
|
|
1022
1046
|
markEdited(edited) {
|
|
@@ -1180,6 +1204,10 @@ var Picker = class {
|
|
|
1180
1204
|
this.editor = null;
|
|
1181
1205
|
this.abortCtrl = new AbortController();
|
|
1182
1206
|
this.uploadStarted = false;
|
|
1207
|
+
// Monotonic counter so a stale image-dimension decode (e.g. one started before
|
|
1208
|
+
// the user edited the file) can't clobber the row's state — only the latest
|
|
1209
|
+
// validation per item is allowed to mutate it.
|
|
1210
|
+
this.validateSeqCounter = 0;
|
|
1183
1211
|
this.resolved = false;
|
|
1184
1212
|
// Element focused before the modal opened, restored on close (a11y).
|
|
1185
1213
|
this.previouslyFocused = null;
|
|
@@ -1227,6 +1255,7 @@ var Picker = class {
|
|
|
1227
1255
|
Object.entries(themeToCssVars(this.opts.theme)).forEach(([k, v]) => {
|
|
1228
1256
|
root.style.setProperty(k, v);
|
|
1229
1257
|
});
|
|
1258
|
+
root.style.colorScheme = this.opts.theme?.mode === "dark" ? "dark" : "light";
|
|
1230
1259
|
root.addEventListener("click", (e) => {
|
|
1231
1260
|
if (e.target === root && !this.uploadStarted) this.cancel();
|
|
1232
1261
|
});
|
|
@@ -1637,6 +1666,9 @@ var Picker = class {
|
|
|
1637
1666
|
const bar = el2("div", "us-file-progress-bar");
|
|
1638
1667
|
progress.appendChild(bar);
|
|
1639
1668
|
main.appendChild(progress);
|
|
1669
|
+
const error = el2("div", "us-file-error");
|
|
1670
|
+
if (item.error) error.textContent = item.error;
|
|
1671
|
+
main.appendChild(error);
|
|
1640
1672
|
row.appendChild(main);
|
|
1641
1673
|
const isImage = item.file.type.startsWith("image/");
|
|
1642
1674
|
const editingEnabled = this.opts.imageEditing !== false;
|
|
@@ -1660,6 +1692,7 @@ var Picker = class {
|
|
|
1660
1692
|
item.$bar = bar;
|
|
1661
1693
|
item.$status = status;
|
|
1662
1694
|
item.$meta = meta;
|
|
1695
|
+
item.$error = error;
|
|
1663
1696
|
item.$thumb = thumb;
|
|
1664
1697
|
this.$list.appendChild(row);
|
|
1665
1698
|
this.updateSummary();
|
|
@@ -1711,6 +1744,11 @@ var Picker = class {
|
|
|
1711
1744
|
onCropApplied: () => {
|
|
1712
1745
|
didRatioCrop = true;
|
|
1713
1746
|
},
|
|
1747
|
+
// Rotating/circling/reverting after a crop changes the working aspect, so
|
|
1748
|
+
// the image is no longer guaranteed to match the locked ratio.
|
|
1749
|
+
onAspectReset: () => {
|
|
1750
|
+
didRatioCrop = false;
|
|
1751
|
+
},
|
|
1714
1752
|
onApply: (edited) => {
|
|
1715
1753
|
const wasEdited = edited !== item.originalFile;
|
|
1716
1754
|
this.replaceItemFile(item, edited, wasEdited);
|
|
@@ -1775,16 +1813,13 @@ var Picker = class {
|
|
|
1775
1813
|
case "uploading":
|
|
1776
1814
|
item.$meta.textContent = `${size} \xB7 ${Math.round(item.progress)}%`;
|
|
1777
1815
|
break;
|
|
1778
|
-
case "done":
|
|
1779
|
-
item.$meta.textContent = size;
|
|
1780
|
-
break;
|
|
1781
|
-
case "failed":
|
|
1782
|
-
item.$meta.textContent = item.error || "Failed";
|
|
1783
|
-
break;
|
|
1784
1816
|
default:
|
|
1785
1817
|
item.$meta.textContent = size;
|
|
1786
1818
|
}
|
|
1787
1819
|
}
|
|
1820
|
+
if (item.$error) {
|
|
1821
|
+
item.$error.textContent = state === "failed" ? item.error || "Upload failed" : "";
|
|
1822
|
+
}
|
|
1788
1823
|
this.updateSummary();
|
|
1789
1824
|
}
|
|
1790
1825
|
updateSummary() {
|
|
@@ -1844,25 +1879,27 @@ var Picker = class {
|
|
|
1844
1879
|
// Decode an image and fail the row if it's below the configured minimum.
|
|
1845
1880
|
// Non-decodable inputs are left queued — we can't prove they're too small.
|
|
1846
1881
|
async validateDimensions(item) {
|
|
1882
|
+
const seq = ++this.validateSeqCounter;
|
|
1883
|
+
item.validateSeq = seq;
|
|
1847
1884
|
const minW = this.opts.minImageWidth ?? 0;
|
|
1848
1885
|
const minH = this.opts.minImageHeight ?? 0;
|
|
1886
|
+
const file = item.file;
|
|
1849
1887
|
let dim = null;
|
|
1850
1888
|
try {
|
|
1851
|
-
dim = await readImageSize(
|
|
1889
|
+
dim = await readImageSize(file);
|
|
1852
1890
|
} catch {
|
|
1853
1891
|
dim = null;
|
|
1854
1892
|
}
|
|
1855
|
-
if (item.
|
|
1856
|
-
item.validating = false;
|
|
1857
|
-
return;
|
|
1858
|
-
}
|
|
1893
|
+
if (item.validateSeq !== seq) return;
|
|
1859
1894
|
item.validating = false;
|
|
1860
|
-
if (
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1895
|
+
if (item.state === "queued") {
|
|
1896
|
+
if (dim && dim.w > 0 && dim.h > 0 && (dim.w < minW || dim.h < minH)) {
|
|
1897
|
+
const need = `${minW || "?"}\xD7${minH || "?"}`;
|
|
1898
|
+
item.error = `Image too small \u2014 needs at least ${need}px (got ${dim.w}\xD7${dim.h})`;
|
|
1899
|
+
this.setItemState(item, "failed");
|
|
1900
|
+
} else {
|
|
1901
|
+
this.updateItemBadge(item);
|
|
1902
|
+
}
|
|
1866
1903
|
}
|
|
1867
1904
|
this.refreshConfirm();
|
|
1868
1905
|
this.maybeAutoUpload();
|