← back to Jutewallpaper
front-page-steward: ux-primitives v1.1.1 — Cody slow-load fix (empty-state retracts on late products; never strands over a populated grid) TK-12031
7d76a7fe6855327750c206b353e0074a575bd27e · 2026-09-22 16:45:46 -0700 · Steve Abrams
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M public/index.htmlM public/ux-primitives.bundle.cssM public/ux-primitives.bundle.js
Diff
commit 7d76a7fe6855327750c206b353e0074a575bd27e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Sep 22 16:45:46 2026 -0700
front-page-steward: ux-primitives v1.1.1 — Cody slow-load fix (empty-state retracts on late products; never strands over a populated grid) TK-12031
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
public/index.html | 4 ++--
public/ux-primitives.bundle.css | 2 +-
public/ux-primitives.bundle.js | 29 ++++++++++++++++++++++-------
3 files changed, 25 insertions(+), 10 deletions(-)
diff --git a/public/index.html b/public/index.html
index 0bcf0b0..b55d4ed 100644
--- a/public/index.html
+++ b/public/index.html
@@ -279,7 +279,7 @@ html.hf-sample [data-f="sample"] { display:none !important }
<!-- noscript fallback is added by set-fb-pixel.sh on flip (omitted here to avoid unflipped img phone-home) -->
<noscript><img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=1431180262113856<!-- End Meta Pixel -->ev=PageView<!-- End Meta Pixel -->noscript=1"/></noscript>
<!-- End Meta Pixel -->
- <!-- ux-primitives.bundle v1.1.0#aeb58948a264 (front-page-steward TK-12031) -->
+ <!-- ux-primitives.bundle v1.1.1#cf1a82202107 (front-page-steward TK-12031) -->
<link rel="stylesheet" href="ux-primitives.bundle.css">
<script src="ux-primitives.bundle.js" defer></script>
</head>
@@ -632,7 +632,7 @@ html.hf-sample [data-f="sample"] { display:none !important }
<button data-sort-col="price">Price <span class="arr"></span></button>
</div>
<div id="rails" style="display:none"></div>
- <div class="grid" id="grid" data-ux-grid data-ux-grid-skeleton="card" data-ux-grid-count="8" data-ux-grid data-ux-grid-skeleton="card" data-ux-grid-count="8"></div>
+ <div class="grid" id="grid" data-ux-grid data-ux-grid-skeleton="card" data-ux-grid-count="8" data-ux-grid data-ux-grid-skeleton="card" data-ux-grid-count="8" data-ux-grid data-ux-grid-skeleton="card" data-ux-grid-count="8"></div>
<div class="loading" id="loading">Loading more…</div>
<div class="sentinel" id="sentinel"></div>
</section>
diff --git a/public/ux-primitives.bundle.css b/public/ux-primitives.bundle.css
index f321f17..4c7a844 100644
--- a/public/ux-primitives.bundle.css
+++ b/public/ux-primitives.bundle.css
@@ -1,4 +1,4 @@
-/* ux-primitives.bundle.css — canonical Bundle-B UX primitives (generated 2026-09-22T22:59:00Z)
+/* ux-primitives.bundle.css — canonical Bundle-B UX primitives (generated 2026-09-22T23:33:51Z)
Shared ux-primitives.css tokens (md5 614018b) included ONCE, then each
primitive's own CSS. All selectors namespaced .ux-* / .ux-bento* / .ux-modal*
so nothing collides with corner-nav (cnav-*), hero-4grid, or site styles.
diff --git a/public/ux-primitives.bundle.js b/public/ux-primitives.bundle.js
index 9d9d0ec..6924a03 100644
--- a/public/ux-primitives.bundle.js
+++ b/public/ux-primitives.bundle.js
@@ -1,4 +1,4 @@
-/* ux-primitives.bundle.js — canonical Bundle-B UX primitives (generated 2026-09-22T22:59:00Z)
+/* ux-primitives.bundle.js — canonical Bundle-B UX primitives (generated 2026-09-22T23:33:51Z)
7 zero-dependency IIFE primitives (window globals Toast, Skeleton, EmptyState,
Copy, CommandPalette, ModalRig, Bento) + ONE idempotent declarative auto-init
(UXPrimitives.init). No-ops on a page using none of them. Globals are distinct
@@ -1210,7 +1210,10 @@
var wantEmpty = (opts.empty !== false) && (c.getAttribute('data-ux-grid-empty') !== 'off');
var toAttr = parseInt(c.getAttribute('data-ux-grid-timeout') || '0', 10);
var skelTimeout = (typeof global.__uxGridTimeout === 'number' ? global.__uxGridTimeout : 0) || opts.skeletonTimeout || toAttr || 8000;
- var hardCap = opts.hardCap || Math.max(15000, skelTimeout + 6000);
+ // hardCap is a LEAK GUARD only — it may disconnect the observer ONLY when no empty-state
+ // is being displayed (see below). It must NEVER tear down the observer while an empty-state
+ // banner is up, or a late-arriving product would be stranded UNDER a permanent "No results".
+ var hardCap = (typeof global.__uxGridHardCap === 'number' ? global.__uxGridHardCap : 0) || opts.hardCap || Math.max(15000, skelTimeout + 6000);
var emptyOpts = {
variant: 'no-results',
title: opts.emptyTitle || c.getAttribute('data-ux-grid-empty-title') || undefined,
@@ -1230,19 +1233,31 @@
if (c.removeAttribute) c.removeAttribute('aria-busy');
c.__uxGridDone = true;
}
+ // The observer is the SINGLE source of truth for "products arrived" and lives until they
+ // do. Products appearing at ANY time (before the skeleton timeout, during an empty-state
+ // banner, or long after hardCap) always clear skeleton + empty-state and finish. This is
+ // what makes empty-state safe: it can NEVER remain stranded over a populated grid.
try {
obs = new MutationObserver(function () {
if (realCount(c) > 0) { clearSkel(c); clearEmpty(c); finish(); }
});
obs.observe(c, { childList: true });
- } catch (e) { /* no MutationObserver → timeout path still clears */ }
+ } catch (e) { /* no MutationObserver → timeout path still clears the skeleton */ }
tSkel = setTimeout(function () {
- clearSkel(c);
+ clearSkel(c); // never leave a skeleton stuck
if (realCount(c) === 0 && wantEmpty && !emptyShown) { showEmpty(c, emptyOpts); emptyShown = true; }
- // keep observing until a late product arrives (removes empty) or hardCap
+ // Do NOT finish here — the observer stays alive so a late product (even a very slow API
+ // or a facet re-query that later returns rows) always retracts the empty-state.
}, skelTimeout);
- tCap = setTimeout(finish, hardCap);
+
+ // Leak guard: disconnect ONLY if we never showed an empty-state (nothing to strand) and the
+ // grid is still empty. If an empty-state IS up, we deliberately keep watching — a stranded
+ // "No results" over real products is a worse failure than one long-lived idle observer on a
+ // grid that receives no mutations (which costs nothing and is GC'd with the element).
+ tCap = setTimeout(function () {
+ if (!emptyShown && realCount(c) === 0) finish();
+ }, hardCap);
return { finish: finish };
}
@@ -1337,6 +1352,6 @@
return true;
}
- global.UXPrimitives = { init: initAll, version: '1.1.0' };
+ global.UXPrimitives = { init: initAll, version: '1.1.1' };
ready(function () { if (global.__uxPrimitivesAutoInit === false) return; try { initAll(doc); } catch (e) { console.warn('[ux-primitives] auto-init', e); } });
})(typeof window !== 'undefined' ? window : this);
← 1244f5b front-page-steward: ux-primitives v1.1.0 lifecycle grid acti
·
back to Jutewallpaper
·
TK-12031: bump ux-primitives bundle to canonical v1.1.1#7d74 714c7a5 →