@sesionario/blocks 1.41.0-rc.6 → 1.41.0-rc.8
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/index.cjs +133 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -9
- package/dist/index.d.ts +32 -9
- package/dist/index.js +133 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1174,31 +1174,54 @@ function useZoomPanGestures(options = {}) {
|
|
|
1174
1174
|
clearSnapBack
|
|
1175
1175
|
};
|
|
1176
1176
|
}
|
|
1177
|
+
var STATIC_BLUR_FILTER = "blur(20px)";
|
|
1177
1178
|
function isBrokenImage(img) {
|
|
1178
1179
|
return img.complete && img.naturalWidth === 0;
|
|
1179
1180
|
}
|
|
1181
|
+
function resolveBlurDataUrl(value) {
|
|
1182
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
1183
|
+
}
|
|
1180
1184
|
function SafeImage({
|
|
1181
1185
|
src,
|
|
1182
1186
|
fallback,
|
|
1183
1187
|
alt = "",
|
|
1184
1188
|
onError,
|
|
1189
|
+
onLoad,
|
|
1190
|
+
blurDataUrl,
|
|
1191
|
+
style,
|
|
1185
1192
|
...imgProps
|
|
1186
1193
|
}) {
|
|
1187
1194
|
const [failed, setFailed] = React2.useState(false);
|
|
1195
|
+
const [loaded, setLoaded] = React2.useState(false);
|
|
1188
1196
|
const imgRef = React2.useRef(null);
|
|
1189
1197
|
const resolvedSrc = typeof src === "string" && src.length > 0 ? src : null;
|
|
1198
|
+
const resolvedBlur = resolveBlurDataUrl(blurDataUrl);
|
|
1190
1199
|
React2.useLayoutEffect(() => {
|
|
1191
1200
|
setFailed(false);
|
|
1201
|
+
setLoaded(false);
|
|
1192
1202
|
}, [resolvedSrc]);
|
|
1193
1203
|
React2.useLayoutEffect(() => {
|
|
1194
1204
|
const img = imgRef.current;
|
|
1195
|
-
if (img
|
|
1205
|
+
if (!img) return;
|
|
1206
|
+
if (isBrokenImage(img)) {
|
|
1196
1207
|
setFailed(true);
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
if (resolvedBlur && img.complete && img.naturalWidth > 0) {
|
|
1211
|
+
setLoaded(true);
|
|
1197
1212
|
}
|
|
1198
|
-
}, [resolvedSrc, failed]);
|
|
1213
|
+
}, [resolvedSrc, failed, resolvedBlur]);
|
|
1199
1214
|
if (!resolvedSrc || failed) {
|
|
1200
1215
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
|
|
1201
1216
|
}
|
|
1217
|
+
const paintedStyle = resolvedBlur === null ? style : {
|
|
1218
|
+
...style,
|
|
1219
|
+
backgroundImage: `url(${JSON.stringify(resolvedBlur)})`,
|
|
1220
|
+
backgroundSize: "cover",
|
|
1221
|
+
backgroundPosition: "center",
|
|
1222
|
+
backgroundRepeat: "no-repeat",
|
|
1223
|
+
...loaded || prefersReducedMotion() ? {} : { filter: STATIC_BLUR_FILTER }
|
|
1224
|
+
};
|
|
1202
1225
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1203
1226
|
"img",
|
|
1204
1227
|
{
|
|
@@ -1206,6 +1229,11 @@ function SafeImage({
|
|
|
1206
1229
|
ref: imgRef,
|
|
1207
1230
|
src: resolvedSrc,
|
|
1208
1231
|
alt,
|
|
1232
|
+
style: paintedStyle,
|
|
1233
|
+
onLoad: (event) => {
|
|
1234
|
+
if (resolvedBlur) setLoaded(true);
|
|
1235
|
+
onLoad?.(event);
|
|
1236
|
+
},
|
|
1209
1237
|
onError: (event) => {
|
|
1210
1238
|
setFailed(true);
|
|
1211
1239
|
onError?.(event);
|
|
@@ -1215,6 +1243,7 @@ function SafeImage({
|
|
|
1215
1243
|
}
|
|
1216
1244
|
function ImageLightbox({
|
|
1217
1245
|
images,
|
|
1246
|
+
blurDataUrls,
|
|
1218
1247
|
index,
|
|
1219
1248
|
onIndexChange,
|
|
1220
1249
|
onClose,
|
|
@@ -1340,6 +1369,7 @@ function ImageLightbox({
|
|
|
1340
1369
|
{
|
|
1341
1370
|
src: images[index],
|
|
1342
1371
|
alt: "",
|
|
1372
|
+
blurDataUrl: blurDataUrls?.[index] ?? null,
|
|
1343
1373
|
draggable: false,
|
|
1344
1374
|
className: "max-h-[calc(100dvh-2rem)] max-w-full select-none rounded-lg object-contain",
|
|
1345
1375
|
style: {
|
|
@@ -1472,6 +1502,7 @@ function MediaCarousel({
|
|
|
1472
1502
|
{
|
|
1473
1503
|
src: item.src,
|
|
1474
1504
|
alt: item.alt ?? "",
|
|
1505
|
+
blurDataUrl: item.blurDataUrl,
|
|
1475
1506
|
draggable: false,
|
|
1476
1507
|
className: "max-h-full max-w-full select-none object-contain",
|
|
1477
1508
|
style: {
|
|
@@ -1707,6 +1738,79 @@ function MediaViewerDialog({
|
|
|
1707
1738
|
}
|
|
1708
1739
|
) });
|
|
1709
1740
|
}
|
|
1741
|
+
|
|
1742
|
+
// src/components/media/blurDataUrl.ts
|
|
1743
|
+
var BLUR_LONG_EDGE_PX = 16;
|
|
1744
|
+
var BLUR_DATA_URL_MAX_CHARS = 1024;
|
|
1745
|
+
var JPEG_DATA_URL_PREFIX = "data:image/jpeg;base64,";
|
|
1746
|
+
var JPEG_QUALITIES = [0.7, 0.5, 0.35, 0.2];
|
|
1747
|
+
function longEdgeSteps(start) {
|
|
1748
|
+
const steps = [];
|
|
1749
|
+
let edge = start;
|
|
1750
|
+
while (edge >= 2) {
|
|
1751
|
+
steps.push(edge);
|
|
1752
|
+
edge = Math.floor(edge / 2);
|
|
1753
|
+
}
|
|
1754
|
+
return steps;
|
|
1755
|
+
}
|
|
1756
|
+
function sizeForLongEdge(width, height, longEdge) {
|
|
1757
|
+
const longest = Math.max(width, height);
|
|
1758
|
+
const scale = longEdge / longest;
|
|
1759
|
+
return {
|
|
1760
|
+
width: Math.max(1, Math.round(width * scale)),
|
|
1761
|
+
height: Math.max(1, Math.round(height * scale))
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
function acceptableBlurDataUrl(value) {
|
|
1765
|
+
return value.startsWith(JPEG_DATA_URL_PREFIX) && value.length > JPEG_DATA_URL_PREFIX.length && value.length <= BLUR_DATA_URL_MAX_CHARS;
|
|
1766
|
+
}
|
|
1767
|
+
async function decodeBlob(blob) {
|
|
1768
|
+
if (typeof createImageBitmap !== "function") {
|
|
1769
|
+
throw new Error("createImageBitmap unavailable");
|
|
1770
|
+
}
|
|
1771
|
+
const bitmap = await createImageBitmap(blob);
|
|
1772
|
+
return {
|
|
1773
|
+
source: bitmap,
|
|
1774
|
+
width: bitmap.width,
|
|
1775
|
+
height: bitmap.height,
|
|
1776
|
+
release() {
|
|
1777
|
+
bitmap.close();
|
|
1778
|
+
}
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
async function blurDataUrlFromBlob(blob) {
|
|
1782
|
+
if (typeof document === "undefined") return null;
|
|
1783
|
+
let decoded;
|
|
1784
|
+
try {
|
|
1785
|
+
decoded = await decodeBlob(blob);
|
|
1786
|
+
} catch {
|
|
1787
|
+
return null;
|
|
1788
|
+
}
|
|
1789
|
+
try {
|
|
1790
|
+
if (Math.min(decoded.width, decoded.height) <= 0) return null;
|
|
1791
|
+
const canvas = document.createElement("canvas");
|
|
1792
|
+
for (const edge of longEdgeSteps(BLUR_LONG_EDGE_PX)) {
|
|
1793
|
+
const size = sizeForLongEdge(decoded.width, decoded.height, edge);
|
|
1794
|
+
canvas.width = size.width;
|
|
1795
|
+
canvas.height = size.height;
|
|
1796
|
+
const context = canvas.getContext("2d");
|
|
1797
|
+
if (!context) return null;
|
|
1798
|
+
context.drawImage(decoded.source, 0, 0, size.width, size.height);
|
|
1799
|
+
for (const quality of JPEG_QUALITIES) {
|
|
1800
|
+
let url;
|
|
1801
|
+
try {
|
|
1802
|
+
url = canvas.toDataURL("image/jpeg", quality);
|
|
1803
|
+
} catch {
|
|
1804
|
+
return null;
|
|
1805
|
+
}
|
|
1806
|
+
if (acceptableBlurDataUrl(url)) return url;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
return null;
|
|
1810
|
+
} finally {
|
|
1811
|
+
decoded.release();
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1710
1814
|
var miniMenuContentClassName = "max-h-none overflow-x-visible overflow-y-visible";
|
|
1711
1815
|
var miniMenuContentDefaults = {
|
|
1712
1816
|
sideOffset: 8,
|
|
@@ -5618,6 +5722,7 @@ function matchesQuery(entry, query, getOptionKeywords) {
|
|
|
5618
5722
|
function SearchablePicker(props) {
|
|
5619
5723
|
const {
|
|
5620
5724
|
options,
|
|
5725
|
+
selectedItems: selectedItemsProp,
|
|
5621
5726
|
fetchOptions,
|
|
5622
5727
|
getOptionValue,
|
|
5623
5728
|
getOptionLabel,
|
|
@@ -5676,11 +5781,16 @@ function SearchablePicker(props) {
|
|
|
5676
5781
|
},
|
|
5677
5782
|
[getOptionValue]
|
|
5678
5783
|
);
|
|
5784
|
+
if (options?.length) rememberItems(options);
|
|
5785
|
+
if (selectedItemsProp?.length) rememberItems(selectedItemsProp);
|
|
5786
|
+
if (pinned?.recommended?.length) rememberItems(pinned.recommended);
|
|
5787
|
+
if (pinned?.recent?.length) rememberItems(pinned.recent);
|
|
5679
5788
|
React2.useEffect(() => {
|
|
5680
5789
|
if (options) rememberItems(options);
|
|
5790
|
+
if (selectedItemsProp) rememberItems(selectedItemsProp);
|
|
5681
5791
|
if (pinned?.recommended) rememberItems(pinned.recommended);
|
|
5682
5792
|
if (pinned?.recent) rememberItems(pinned.recent);
|
|
5683
|
-
}, [options, pinned, rememberItems]);
|
|
5793
|
+
}, [options, selectedItemsProp, pinned, rememberItems]);
|
|
5684
5794
|
React2.useEffect(() => {
|
|
5685
5795
|
if (!open) {
|
|
5686
5796
|
setQuery("");
|
|
@@ -5728,7 +5838,7 @@ function SearchablePicker(props) {
|
|
|
5728
5838
|
const selectedItems = React2.useMemo(() => {
|
|
5729
5839
|
const values = mode === "multiple" ? selectedValueKey ? selectedValueKey.split("\0") : [] : selectedValueKey ? [selectedValueKey] : [];
|
|
5730
5840
|
return values.map((value) => knownItemsRef.current.get(value)).filter((item) => item !== void 0);
|
|
5731
|
-
}, [mode, selectedValueKey, options, pinned, remoteItems]);
|
|
5841
|
+
}, [mode, selectedValueKey, options, selectedItemsProp, pinned, remoteItems]);
|
|
5732
5842
|
const queryForFilter = query.trim();
|
|
5733
5843
|
const recommended = React2.useMemo(() => {
|
|
5734
5844
|
if (queryForFilter) return [];
|
|
@@ -5832,13 +5942,27 @@ function SearchablePicker(props) {
|
|
|
5832
5942
|
);
|
|
5833
5943
|
const handleLoadMore = React2.useCallback(async () => {
|
|
5834
5944
|
if (!onLoadMore || isLoadingMore) return;
|
|
5945
|
+
const requestId = requestIdRef.current;
|
|
5835
5946
|
setIsLoadingMore(true);
|
|
5836
5947
|
try {
|
|
5837
|
-
await onLoadMore();
|
|
5948
|
+
const more = await onLoadMore();
|
|
5949
|
+
if (requestIdRef.current !== requestId || !Array.isArray(more)) return;
|
|
5950
|
+
setRemoteItems((prev) => {
|
|
5951
|
+
const seen = new Set(prev.map((item) => getOptionValue(item)));
|
|
5952
|
+
const next = [...prev];
|
|
5953
|
+
for (const item of more) {
|
|
5954
|
+
const value = getOptionValue(item);
|
|
5955
|
+
if (seen.has(value)) continue;
|
|
5956
|
+
seen.add(value);
|
|
5957
|
+
next.push(item);
|
|
5958
|
+
}
|
|
5959
|
+
return next;
|
|
5960
|
+
});
|
|
5961
|
+
rememberItems(more);
|
|
5838
5962
|
} finally {
|
|
5839
|
-
setIsLoadingMore(false);
|
|
5963
|
+
if (requestIdRef.current === requestId) setIsLoadingMore(false);
|
|
5840
5964
|
}
|
|
5841
|
-
}, [onLoadMore, isLoadingMore]);
|
|
5965
|
+
}, [onLoadMore, isLoadingMore, getOptionValue, rememberItems]);
|
|
5842
5966
|
const triggerLabel = React2.useMemo(() => {
|
|
5843
5967
|
if (renderValue) {
|
|
5844
5968
|
if (mode === "multiple") {
|
|
@@ -5972,7 +6096,7 @@ function SearchablePicker(props) {
|
|
|
5972
6096
|
] });
|
|
5973
6097
|
}
|
|
5974
6098
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full items-center gap-1", className), children: [
|
|
5975
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, modal:
|
|
6099
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, modal: false, children: [
|
|
5976
6100
|
/* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: triggerButton }),
|
|
5977
6101
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5978
6102
|
PopoverContent,
|
|
@@ -9084,6 +9208,7 @@ exports.ZOOM_PAN_MIN_SCALE = ZOOM_PAN_MIN_SCALE;
|
|
|
9084
9208
|
exports.ZOOM_PAN_SWIPE_COMMIT_PX = ZOOM_PAN_SWIPE_COMMIT_PX;
|
|
9085
9209
|
exports.ZOOM_PAN_SWIPE_SNAP_MS = ZOOM_PAN_SWIPE_SNAP_MS;
|
|
9086
9210
|
exports.avatarFallbackStyle = avatarFallbackStyle;
|
|
9211
|
+
exports.blurDataUrlFromBlob = blurDataUrlFromBlob;
|
|
9087
9212
|
exports.bubbleVariants = bubbleVariants;
|
|
9088
9213
|
exports.cn = cn;
|
|
9089
9214
|
exports.createSupportChatClient = createSupportChatClient;
|