@loafmarkets/ui 0.1.426 → 0.1.428
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.js +33 -43
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +33 -43
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3044,7 +3044,7 @@ PropertyTour.displayName = "PropertyTour";
|
|
|
3044
3044
|
var BREAKING_WINDOW_HOURS = 6;
|
|
3045
3045
|
var BREAKING_MEMORY_CAP = 50;
|
|
3046
3046
|
var BREAKING_MEMORY_STORAGE_KEY = "loaf:dismissed-breaking";
|
|
3047
|
-
var emptyBreakingMemory = () => ({ dismissed: {},
|
|
3047
|
+
var emptyBreakingMemory = () => ({ dismissed: {}, blocked: {} });
|
|
3048
3048
|
var isTimestampMap = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && Object.values(v).every((t) => typeof t === "number" && Number.isFinite(t));
|
|
3049
3049
|
var pruneMap = (map, cutoff) => {
|
|
3050
3050
|
const fresh = Object.entries(map).filter(([, t]) => t >= cutoff);
|
|
@@ -3055,44 +3055,30 @@ var prune = (mem, now) => {
|
|
|
3055
3055
|
const cutoff = now - BREAKING_WINDOW_HOURS * 36e5;
|
|
3056
3056
|
return {
|
|
3057
3057
|
dismissed: pruneMap(mem.dismissed, cutoff),
|
|
3058
|
-
|
|
3059
|
-
// An expired watermark can't block anything (every in-window story is newer).
|
|
3060
|
-
watermark: mem.watermark !== null && mem.watermark >= cutoff ? mem.watermark : null
|
|
3058
|
+
blocked: pruneMap(mem.blocked, cutoff)
|
|
3061
3059
|
};
|
|
3062
3060
|
};
|
|
3063
3061
|
function parseBreakingMemory(raw, now) {
|
|
3064
3062
|
if (!raw) return emptyBreakingMemory();
|
|
3065
3063
|
try {
|
|
3066
3064
|
const v = JSON.parse(raw);
|
|
3067
|
-
if (typeof v !== "object" || v === null || Array.isArray(v) || !isTimestampMap(v.dismissed)
|
|
3065
|
+
if (typeof v !== "object" || v === null || Array.isArray(v) || !isTimestampMap(v.dismissed)) {
|
|
3068
3066
|
return emptyBreakingMemory();
|
|
3069
3067
|
}
|
|
3070
|
-
|
|
3068
|
+
const blocked = isTimestampMap(v.blocked) ? v.blocked : {};
|
|
3069
|
+
return prune({ dismissed: v.dismissed, blocked }, now);
|
|
3071
3070
|
} catch {
|
|
3072
3071
|
return emptyBreakingMemory();
|
|
3073
3072
|
}
|
|
3074
3073
|
}
|
|
3075
3074
|
var serializeBreakingMemory = (mem) => JSON.stringify(mem);
|
|
3076
|
-
function recordBreakingDismissal(mem, key, publishedAtMs, now) {
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
pinned: mem.pinned,
|
|
3081
|
-
watermark: Math.max(mem.watermark ?? -Infinity, publishedAtMs)
|
|
3082
|
-
},
|
|
3083
|
-
now
|
|
3084
|
-
);
|
|
3075
|
+
function recordBreakingDismissal(mem, key, publishedAtMs, now, waiting = []) {
|
|
3076
|
+
const blocked = { ...mem.blocked };
|
|
3077
|
+
for (const w of waiting) blocked[w.key] = w.publishedAtMs;
|
|
3078
|
+
return prune({ dismissed: { ...mem.dismissed, [key]: publishedAtMs }, blocked }, now);
|
|
3085
3079
|
}
|
|
3086
|
-
function
|
|
3087
|
-
|
|
3088
|
-
const pinned = { ...mem.pinned };
|
|
3089
|
-
for (const p of pins) pinned[p.key] = p.publishedAtMs;
|
|
3090
|
-
return prune({ dismissed: mem.dismissed, pinned, watermark: mem.watermark }, now);
|
|
3091
|
-
}
|
|
3092
|
-
function mayPinBreaking(mem, key, publishedAtMs) {
|
|
3093
|
-
if (mem.dismissed[key] !== void 0) return false;
|
|
3094
|
-
if (mem.watermark === null) return true;
|
|
3095
|
-
return publishedAtMs > mem.watermark || mem.pinned[key] !== void 0;
|
|
3080
|
+
function mayPinBreaking(mem, key) {
|
|
3081
|
+
return mem.dismissed[key] === void 0 && mem.blocked[key] === void 0;
|
|
3096
3082
|
}
|
|
3097
3083
|
function loadBreakingMemory(now) {
|
|
3098
3084
|
try {
|
|
@@ -3677,18 +3663,8 @@ var PropertyNewsUpdates = React9__namespace.forwardRef(
|
|
|
3677
3663
|
};
|
|
3678
3664
|
const pinnedBreaking = React9__namespace.useMemo(() => {
|
|
3679
3665
|
const mem = getBreakingMemory();
|
|
3680
|
-
return breakingEligible.filter((it) => mayPinBreaking(mem, breakingKey(it)
|
|
3666
|
+
return breakingEligible.filter((it) => mayPinBreaking(mem, breakingKey(it))).sort((a, b) => breakingImpact(b) - breakingImpact(a)).slice(0, MAX_PINNED_BREAKING);
|
|
3681
3667
|
}, [breakingEligible, dismissedVersion]);
|
|
3682
|
-
React9__namespace.useEffect(() => {
|
|
3683
|
-
if (pinnedBreaking.length === 0) return;
|
|
3684
|
-
const mem = getBreakingMemory();
|
|
3685
|
-
const next = recordBreakingPins(
|
|
3686
|
-
mem,
|
|
3687
|
-
pinnedBreaking.map((it) => ({ key: breakingKey(it), publishedAtMs: breakingPublishedMs(it) })),
|
|
3688
|
-
Date.now()
|
|
3689
|
-
);
|
|
3690
|
-
if (next !== mem) commitBreakingMemory(next);
|
|
3691
|
-
}, [pinnedBreaking]);
|
|
3692
3668
|
const breakingRowKeys = React9__namespace.useMemo(
|
|
3693
3669
|
() => new Set(breakingEligible.map(breakingKey)),
|
|
3694
3670
|
[breakingEligible]
|
|
@@ -3794,8 +3770,10 @@ var PropertyNewsUpdates = React9__namespace.forwardRef(
|
|
|
3794
3770
|
const k = breakingKey(item);
|
|
3795
3771
|
const dx = breakingSwipe?.key === k ? breakingSwipe.dx : 0;
|
|
3796
3772
|
const persistDismissal = () => {
|
|
3773
|
+
const holding = new Set(pinnedBreaking);
|
|
3774
|
+
const waiting = breakingEligible.filter((c) => !holding.has(c)).map((c) => ({ key: breakingKey(c), publishedAtMs: breakingPublishedMs(c) }));
|
|
3797
3775
|
commitBreakingMemory(
|
|
3798
|
-
recordBreakingDismissal(getBreakingMemory(), k, breakingPublishedMs(item), Date.now())
|
|
3776
|
+
recordBreakingDismissal(getBreakingMemory(), k, breakingPublishedMs(item), Date.now(), waiting)
|
|
3799
3777
|
);
|
|
3800
3778
|
};
|
|
3801
3779
|
const finishDismiss = () => {
|
|
@@ -10822,6 +10800,7 @@ function GalleryMapSection({
|
|
|
10822
10800
|
const [showVideo, setShowVideo] = React9.useState(false);
|
|
10823
10801
|
const [autoPlaying, setAutoPlaying] = React9.useState(autoPlay);
|
|
10824
10802
|
const [showFullMap, setShowFullMap] = React9.useState(false);
|
|
10803
|
+
const [fullMapMountedFor, setFullMapMountedFor] = React9.useState(null);
|
|
10825
10804
|
const [showFullVideo, setShowFullVideo] = React9.useState(false);
|
|
10826
10805
|
const isMobile = useMaxWidth(768);
|
|
10827
10806
|
const resolvedMapUrl = mapUrl ?? (tokenName ? `/map/${tokenName}?embed=true&zoom=14&hideOthers=true` : "about:blank");
|
|
@@ -10939,7 +10918,10 @@ function GalleryMapSection({
|
|
|
10939
10918
|
] }),
|
|
10940
10919
|
/* @__PURE__ */ jsxRuntime.jsxs(MapHeaderRight, { children: [
|
|
10941
10920
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: propertyLocation }),
|
|
10942
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", onClick: () =>
|
|
10921
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", onClick: () => {
|
|
10922
|
+
setFullMapMountedFor(resolvedMapUrl);
|
|
10923
|
+
setShowFullMap(true);
|
|
10924
|
+
}, children: [
|
|
10943
10925
|
/* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", style: { width: 14, height: 14 }, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 3H5a2 2 0 00-2 2v3m18 0V5a2 2 0 00-2-2h-3m0 18h3a2 2 0 002-2v-3M3 16v3a2 2 0 002 2h3" }) }),
|
|
10944
10926
|
"Full Screen"
|
|
10945
10927
|
] })
|
|
@@ -10988,7 +10970,7 @@ function GalleryMapSection({
|
|
|
10988
10970
|
] }),
|
|
10989
10971
|
/* @__PURE__ */ jsxRuntime.jsx(SuburbDesc, { children: "One of Sydney's most prestigious harbourside suburbs, consistently ranked among Australia's highest-value residential markets. Strong capital growth driven by limited supply, heritage conservation overlays, and international buyer demand." })
|
|
10990
10972
|
] }),
|
|
10991
|
-
|
|
10973
|
+
fullMapMountedFor === resolvedMapUrl && !hideMap && /* @__PURE__ */ jsxRuntime.jsx(FullMapPopup, { hidden: !showFullMap, onClose: () => setShowFullMap(false), mapUrl: resolvedMapUrl }),
|
|
10992
10974
|
showFullVideo && videoUrl && /* @__PURE__ */ jsxRuntime.jsxs(FullVideoOverlay, { onClick: () => setShowFullVideo(false), children: [
|
|
10993
10975
|
/* @__PURE__ */ jsxRuntime.jsx(FullVideoClose, { onClick: () => setShowFullVideo(false), "aria-label": "Close video", children: "\u2715" }),
|
|
10994
10976
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -11118,21 +11100,23 @@ function StackedGallery({ images, onPhotoClick }) {
|
|
|
11118
11100
|
}) })
|
|
11119
11101
|
] });
|
|
11120
11102
|
}
|
|
11121
|
-
function FullMapPopup({ onClose, mapUrl }) {
|
|
11103
|
+
function FullMapPopup({ onClose, mapUrl, hidden = false }) {
|
|
11122
11104
|
React9.useEffect(() => {
|
|
11105
|
+
if (hidden) return;
|
|
11123
11106
|
const handleEsc = (e) => {
|
|
11124
11107
|
if (e.key === "Escape") onClose();
|
|
11125
11108
|
};
|
|
11126
11109
|
window.addEventListener("keydown", handleEsc);
|
|
11127
11110
|
return () => window.removeEventListener("keydown", handleEsc);
|
|
11128
|
-
}, [onClose]);
|
|
11111
|
+
}, [onClose, hidden]);
|
|
11129
11112
|
React9.useEffect(() => {
|
|
11113
|
+
if (hidden) return;
|
|
11130
11114
|
const handleMessage = (e) => {
|
|
11131
11115
|
if (e.data === "loaf:close-embed") onClose();
|
|
11132
11116
|
};
|
|
11133
11117
|
window.addEventListener("message", handleMessage);
|
|
11134
11118
|
return () => window.removeEventListener("message", handleMessage);
|
|
11135
|
-
}, [onClose]);
|
|
11119
|
+
}, [onClose, hidden]);
|
|
11136
11120
|
const iframeRef = React9.useCallback((node) => {
|
|
11137
11121
|
if (!node) return;
|
|
11138
11122
|
const handleLoad = () => {
|
|
@@ -11148,7 +11132,7 @@ function FullMapPopup({ onClose, mapUrl }) {
|
|
|
11148
11132
|
};
|
|
11149
11133
|
node.addEventListener("load", handleLoad);
|
|
11150
11134
|
}, [onClose]);
|
|
11151
|
-
return /* @__PURE__ */ jsxRuntime.jsx(FullMapOverlay, { onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(FullMapPanel, { onClick: (e) => e.stopPropagation(), children: [
|
|
11135
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FullMapOverlay, { onClick: onClose, hidden, children: /* @__PURE__ */ jsxRuntime.jsxs(FullMapPanel, { onClick: (e) => e.stopPropagation(), children: [
|
|
11152
11136
|
/* @__PURE__ */ jsxRuntime.jsxs(FullMapHeader, { children: [
|
|
11153
11137
|
/* @__PURE__ */ jsxRuntime.jsxs(FullMapTitle, { children: [
|
|
11154
11138
|
/* @__PURE__ */ jsxRuntime.jsx(bi.BiMap, {}),
|
|
@@ -11444,6 +11428,12 @@ var FullMapOverlay = styled10__default.default.div`
|
|
|
11444
11428
|
align-items: center;
|
|
11445
11429
|
justify-content: center;
|
|
11446
11430
|
backdrop-filter: blur(4px);
|
|
11431
|
+
|
|
11432
|
+
/* Kept mounted between opens (see fullMapMountedFor); \`display: flex\` above would
|
|
11433
|
+
otherwise beat the UA's [hidden] rule. */
|
|
11434
|
+
&[hidden] {
|
|
11435
|
+
display: none;
|
|
11436
|
+
}
|
|
11447
11437
|
`;
|
|
11448
11438
|
var FullVideoOverlay = styled10__default.default.div`
|
|
11449
11439
|
position: fixed;
|