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