@loafmarkets/ui 0.1.427 → 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 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: {}, pinned: {}, watermark: null });
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
- pinned: pruneMap(mem.pinned, cutoff),
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) || !isTimestampMap(v.pinned) || !(v.watermark === null || typeof v.watermark === "number" && Number.isFinite(v.watermark))) {
3065
+ if (typeof v !== "object" || v === null || Array.isArray(v) || !isTimestampMap(v.dismissed)) {
3068
3066
  return emptyBreakingMemory();
3069
3067
  }
3070
- return prune({ dismissed: v.dismissed, pinned: v.pinned, watermark: v.watermark ?? null }, now);
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
- return prune(
3078
- {
3079
- dismissed: { ...mem.dismissed, [key]: publishedAtMs },
3080
- pinned: mem.pinned,
3081
- watermark: Math.max(mem.watermark ?? -Infinity, publishedAtMs)
3082
- },
3083
- now
3084
- );
3085
- }
3086
- function recordBreakingPins(mem, pins, now) {
3087
- if (pins.every((p) => mem.pinned[p.key] !== void 0)) return mem;
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);
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);
3091
3079
  }
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), breakingPublishedMs(it))).sort((a, b) => breakingImpact(b) - breakingImpact(a)).slice(0, MAX_PINNED_BREAKING);
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 = () => {