@loafmarkets/ui 0.1.423 → 0.1.425
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.d.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +106 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +106 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2850,7 +2850,6 @@ function MobileDepthRow({
|
|
|
2850
2850
|
);
|
|
2851
2851
|
}
|
|
2852
2852
|
var isHlsManifest = (url) => /\.m3u8(\?|$)/i.test(url);
|
|
2853
|
-
var HLS_MIME = "application/vnd.apple.mpegurl";
|
|
2854
2853
|
var MANIFEST_FAILURES = /* @__PURE__ */ new Set(["manifestLoadError", "manifestLoadTimeOut", "manifestParsingError"]);
|
|
2855
2854
|
var HlsVideo = React9.forwardRef(
|
|
2856
2855
|
({ src, capLevelToPlayerSize = true, onError, ...videoProps }, ref) => {
|
|
@@ -2868,7 +2867,7 @@ var HlsVideo = React9.forwardRef(
|
|
|
2868
2867
|
React9.useEffect(() => {
|
|
2869
2868
|
const video = videoRef.current;
|
|
2870
2869
|
if (!video || !activeSrc) return;
|
|
2871
|
-
if (!isHlsManifest(activeSrc)
|
|
2870
|
+
if (!isHlsManifest(activeSrc)) {
|
|
2872
2871
|
video.src = activeSrc;
|
|
2873
2872
|
return;
|
|
2874
2873
|
}
|
|
@@ -3016,6 +3015,74 @@ var PropertyTour = React9.forwardRef(
|
|
|
3016
3015
|
);
|
|
3017
3016
|
PropertyTour.displayName = "PropertyTour";
|
|
3018
3017
|
|
|
3018
|
+
// src/lib/breaking-dismissals.ts
|
|
3019
|
+
var BREAKING_WINDOW_HOURS = 6;
|
|
3020
|
+
var BREAKING_MEMORY_CAP = 50;
|
|
3021
|
+
var BREAKING_MEMORY_STORAGE_KEY = "loaf:dismissed-breaking";
|
|
3022
|
+
var emptyBreakingMemory = () => ({ dismissed: {}, pinned: {}, watermark: null });
|
|
3023
|
+
var isTimestampMap = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && Object.values(v).every((t) => typeof t === "number" && Number.isFinite(t));
|
|
3024
|
+
var pruneMap = (map, cutoff) => {
|
|
3025
|
+
const fresh = Object.entries(map).filter(([, t]) => t >= cutoff);
|
|
3026
|
+
fresh.sort((a, b) => b[1] - a[1]);
|
|
3027
|
+
return Object.fromEntries(fresh.slice(0, BREAKING_MEMORY_CAP));
|
|
3028
|
+
};
|
|
3029
|
+
var prune = (mem, now) => {
|
|
3030
|
+
const cutoff = now - BREAKING_WINDOW_HOURS * 36e5;
|
|
3031
|
+
return {
|
|
3032
|
+
dismissed: pruneMap(mem.dismissed, cutoff),
|
|
3033
|
+
pinned: pruneMap(mem.pinned, cutoff),
|
|
3034
|
+
// An expired watermark can't block anything (every in-window story is newer).
|
|
3035
|
+
watermark: mem.watermark !== null && mem.watermark >= cutoff ? mem.watermark : null
|
|
3036
|
+
};
|
|
3037
|
+
};
|
|
3038
|
+
function parseBreakingMemory(raw, now) {
|
|
3039
|
+
if (!raw) return emptyBreakingMemory();
|
|
3040
|
+
try {
|
|
3041
|
+
const v = JSON.parse(raw);
|
|
3042
|
+
if (typeof v !== "object" || v === null || Array.isArray(v) || !isTimestampMap(v.dismissed) || !isTimestampMap(v.pinned) || !(v.watermark === null || typeof v.watermark === "number" && Number.isFinite(v.watermark))) {
|
|
3043
|
+
return emptyBreakingMemory();
|
|
3044
|
+
}
|
|
3045
|
+
return prune({ dismissed: v.dismissed, pinned: v.pinned, watermark: v.watermark ?? null }, now);
|
|
3046
|
+
} catch {
|
|
3047
|
+
return emptyBreakingMemory();
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
var serializeBreakingMemory = (mem) => JSON.stringify(mem);
|
|
3051
|
+
function recordBreakingDismissal(mem, key, publishedAtMs, now) {
|
|
3052
|
+
return prune(
|
|
3053
|
+
{
|
|
3054
|
+
dismissed: { ...mem.dismissed, [key]: publishedAtMs },
|
|
3055
|
+
pinned: mem.pinned,
|
|
3056
|
+
watermark: Math.max(mem.watermark ?? -Infinity, publishedAtMs)
|
|
3057
|
+
},
|
|
3058
|
+
now
|
|
3059
|
+
);
|
|
3060
|
+
}
|
|
3061
|
+
function recordBreakingPins(mem, pins, now) {
|
|
3062
|
+
if (pins.every((p) => mem.pinned[p.key] !== void 0)) return mem;
|
|
3063
|
+
const pinned = { ...mem.pinned };
|
|
3064
|
+
for (const p of pins) pinned[p.key] = p.publishedAtMs;
|
|
3065
|
+
return prune({ dismissed: mem.dismissed, pinned, watermark: mem.watermark }, now);
|
|
3066
|
+
}
|
|
3067
|
+
function mayPinBreaking(mem, key, publishedAtMs) {
|
|
3068
|
+
if (mem.dismissed[key] !== void 0) return false;
|
|
3069
|
+
if (mem.watermark === null) return true;
|
|
3070
|
+
return publishedAtMs > mem.watermark || mem.pinned[key] !== void 0;
|
|
3071
|
+
}
|
|
3072
|
+
function loadBreakingMemory(now) {
|
|
3073
|
+
try {
|
|
3074
|
+
return parseBreakingMemory(window.localStorage.getItem(BREAKING_MEMORY_STORAGE_KEY), now);
|
|
3075
|
+
} catch {
|
|
3076
|
+
return emptyBreakingMemory();
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
function saveBreakingMemory(mem) {
|
|
3080
|
+
try {
|
|
3081
|
+
window.localStorage.setItem(BREAKING_MEMORY_STORAGE_KEY, serializeBreakingMemory(mem));
|
|
3082
|
+
} catch {
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3019
3086
|
// src/lib/isSafeUrl.ts
|
|
3020
3087
|
var CONTROL_CHARS = /[\u0000-\u001F\u007F]/g;
|
|
3021
3088
|
function isSafeUrl(url) {
|
|
@@ -3036,13 +3103,27 @@ function matchesTab(item, tab) {
|
|
|
3036
3103
|
if (item.types && item.types.length > 0) return item.types.includes(tab);
|
|
3037
3104
|
return item.type === tab;
|
|
3038
3105
|
}
|
|
3039
|
-
var BREAKING_WINDOW_HOURS = 6;
|
|
3040
3106
|
var MAX_PINNED_BREAKING = 2;
|
|
3041
3107
|
var BREAKING_IMPACT_FLOOR = 8;
|
|
3042
3108
|
var breakingImpact = (it) => typeof it.impactScore === "number" && Number.isFinite(it.impactScore) ? it.impactScore : BREAKING_IMPACT_FLOOR;
|
|
3043
|
-
var
|
|
3044
|
-
var
|
|
3109
|
+
var breakingMemory = null;
|
|
3110
|
+
var getBreakingMemory = () => breakingMemory ??= loadBreakingMemory(Date.now());
|
|
3111
|
+
var commitBreakingMemory = (mem) => {
|
|
3112
|
+
breakingMemory = mem;
|
|
3113
|
+
saveBreakingMemory(mem);
|
|
3114
|
+
};
|
|
3115
|
+
var __resetDismissedBreaking = () => {
|
|
3116
|
+
breakingMemory = null;
|
|
3117
|
+
try {
|
|
3118
|
+
window.localStorage.removeItem(BREAKING_MEMORY_STORAGE_KEY);
|
|
3119
|
+
} catch {
|
|
3120
|
+
}
|
|
3121
|
+
};
|
|
3122
|
+
var __reloadBreakingMemory = () => {
|
|
3123
|
+
breakingMemory = null;
|
|
3124
|
+
};
|
|
3045
3125
|
var breakingKey = (it) => String(it.id ?? it.title);
|
|
3126
|
+
var breakingPublishedMs = (it) => new Date(it.publishedAt).getTime();
|
|
3046
3127
|
var BREAKING_SWIPE_MIN_PX = 80;
|
|
3047
3128
|
var ITEMS_PER_PAGE = 5;
|
|
3048
3129
|
var ITEMS_PER_PAGE_MOBILE = 5;
|
|
@@ -3570,8 +3651,19 @@ var PropertyNewsUpdates = React9.forwardRef(
|
|
|
3570
3651
|
});
|
|
3571
3652
|
};
|
|
3572
3653
|
const pinnedBreaking = React9.useMemo(() => {
|
|
3573
|
-
|
|
3654
|
+
const mem = getBreakingMemory();
|
|
3655
|
+
return breakingEligible.filter((it) => mayPinBreaking(mem, breakingKey(it), breakingPublishedMs(it))).sort((a, b) => breakingImpact(b) - breakingImpact(a)).slice(0, MAX_PINNED_BREAKING);
|
|
3574
3656
|
}, [breakingEligible, dismissedVersion]);
|
|
3657
|
+
React9.useEffect(() => {
|
|
3658
|
+
if (pinnedBreaking.length === 0) return;
|
|
3659
|
+
const mem = getBreakingMemory();
|
|
3660
|
+
const next = recordBreakingPins(
|
|
3661
|
+
mem,
|
|
3662
|
+
pinnedBreaking.map((it) => ({ key: breakingKey(it), publishedAtMs: breakingPublishedMs(it) })),
|
|
3663
|
+
Date.now()
|
|
3664
|
+
);
|
|
3665
|
+
if (next !== mem) commitBreakingMemory(next);
|
|
3666
|
+
}, [pinnedBreaking]);
|
|
3575
3667
|
const breakingRowKeys = React9.useMemo(
|
|
3576
3668
|
() => new Set(breakingEligible.map(breakingKey)),
|
|
3577
3669
|
[breakingEligible]
|
|
@@ -3676,8 +3768,13 @@ var PropertyNewsUpdates = React9.forwardRef(
|
|
|
3676
3768
|
const sentiment = getSentimentInfo(item.sentimentScore);
|
|
3677
3769
|
const k = breakingKey(item);
|
|
3678
3770
|
const dx = breakingSwipe?.key === k ? breakingSwipe.dx : 0;
|
|
3771
|
+
const persistDismissal = () => {
|
|
3772
|
+
commitBreakingMemory(
|
|
3773
|
+
recordBreakingDismissal(getBreakingMemory(), k, breakingPublishedMs(item), Date.now())
|
|
3774
|
+
);
|
|
3775
|
+
};
|
|
3679
3776
|
const finishDismiss = () => {
|
|
3680
|
-
|
|
3777
|
+
persistDismissal();
|
|
3681
3778
|
setDismissingBreakingKey(null);
|
|
3682
3779
|
setDismissedVersion((v) => v + 1);
|
|
3683
3780
|
};
|
|
@@ -3725,7 +3822,7 @@ var PropertyNewsUpdates = React9.forwardRef(
|
|
|
3725
3822
|
const drag = Math.max(0, e.clientX - breakingSwipeStartXRef.current);
|
|
3726
3823
|
const width = e.currentTarget.offsetWidth || 0;
|
|
3727
3824
|
if (drag >= Math.max(BREAKING_SWIPE_MIN_PX, width * 0.3)) {
|
|
3728
|
-
|
|
3825
|
+
persistDismissal();
|
|
3729
3826
|
setDismissedVersion((v) => v + 1);
|
|
3730
3827
|
}
|
|
3731
3828
|
},
|
|
@@ -21947,6 +22044,6 @@ var SparklineChart = React9__default.memo(function SparklineChart2({ data, width
|
|
|
21947
22044
|
);
|
|
21948
22045
|
});
|
|
21949
22046
|
|
|
21950
|
-
export { AssetSelectorBar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ContactPopup, Header, HlsVideo, HousePositionSlider, HousePositionSliderMobile, LoafLiquidityBadge, LoafLiquidityLogo, LoginPopup, MobileTradeNav, OfferingProgressCard, OnboardingGuide, Orderbook, owner_booking_default as OwnerBooking, PaymentPopup, PortfolioActivityPanel, PortfolioSummary, PriceChart, PropertyBuy, PropertyCompareBar, PropertyDocuments, PropertyHeroHeader, PropertyHistory, PropertyInspectionTimes, PropertyMediaRow, PropertyNewsUpdates, PropertyOffers, PropertyOverview, PropertyPhotoGallery, PropertySubheader, PropertyTour, PropertyValuation, SentimentBar, SiteFooter, Skeleton, SlideDigit, SparklineChart, ToastProvider, TradeConfirmationModal, TradingSlider, YourOrders, __resetDismissedBreaking, badgeVariants, buttonVariants, extractSparkline, formatAge, hasPendingActivity, matchesTab, rowAgeLabel, useAdaptivePolling, useToast };
|
|
22047
|
+
export { AssetSelectorBar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ContactPopup, Header, HlsVideo, HousePositionSlider, HousePositionSliderMobile, LoafLiquidityBadge, LoafLiquidityLogo, LoginPopup, MobileTradeNav, OfferingProgressCard, OnboardingGuide, Orderbook, owner_booking_default as OwnerBooking, PaymentPopup, PortfolioActivityPanel, PortfolioSummary, PriceChart, PropertyBuy, PropertyCompareBar, PropertyDocuments, PropertyHeroHeader, PropertyHistory, PropertyInspectionTimes, PropertyMediaRow, PropertyNewsUpdates, PropertyOffers, PropertyOverview, PropertyPhotoGallery, PropertySubheader, PropertyTour, PropertyValuation, SentimentBar, SiteFooter, Skeleton, SlideDigit, SparklineChart, ToastProvider, TradeConfirmationModal, TradingSlider, YourOrders, __reloadBreakingMemory, __resetDismissedBreaking, badgeVariants, buttonVariants, extractSparkline, formatAge, hasPendingActivity, matchesTab, rowAgeLabel, useAdaptivePolling, useToast };
|
|
21951
22048
|
//# sourceMappingURL=index.mjs.map
|
|
21952
22049
|
//# sourceMappingURL=index.mjs.map
|