@muten/shadcn 0.1.13 → 0.1.15
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/kit.css +1 -1
- package/package.json +1 -1
- package/registry/virtual-window.js +27 -4
package/kit.css
CHANGED
|
@@ -2665,7 +2665,7 @@ a.cx-bc-item:hover { color: var(--foreground); }
|
|
|
2665
2665
|
.cx-hero-blinds { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; min-height: 280px; width: 100%; padding: 40px 20px; border-radius: calc(var(--radius) * 1.6); overflow: hidden; text-align: center; }
|
|
2666
2666
|
.cx-hero-blinds > :not(.cx-blinds) { position: relative; z-index: 1; }
|
|
2667
2667
|
/* NavPill: sticky glass; it firms up as the page scrolls (scroll-driven animation; plain glass where unsupported) */
|
|
2668
|
-
.cx-navpill-wrap { position: sticky; top: 12px; z-index: var(--z-sticky, 20); display: flex; justify-content: center; width: 100%; padding: 0 12px; }
|
|
2668
|
+
.cx-navpill-wrap { position: sticky; top: 12px; z-index: var(--z-sticky, 20); display: flex; flex-direction: row; justify-content: center; width: 100%; padding: 0 12px; }
|
|
2669
2669
|
.cx-navpill { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 16px; width: 100%; max-width: 64rem; padding: 8px 8px 8px 18px; border: 1px solid color-mix(in srgb, var(--border) 70%, transparent); border-radius: 99px; background: color-mix(in srgb, var(--background) 70%, transparent); -webkit-backdrop-filter: blur(14px) saturate(1.4); backdrop-filter: blur(14px) saturate(1.4); }
|
|
2670
2670
|
.cx-navpill a:not(.cn-button) { color: var(--muted-foreground); text-decoration: none; font-size: 14px; }
|
|
2671
2671
|
.cx-navpill a:not(.cn-button):hover { color: var(--foreground); }
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ export function mount(el, inputs, on) {
|
|
|
9
9
|
let from = -1, to = -1, step = 0, raf = 0, list = null, scroller = null, basePad = 0, wired = false;
|
|
10
10
|
// the real height (plus gap, screen px) of every row already drawn, by its place in the list. Rows of very different
|
|
11
11
|
// heights (a group of 2 next to one of 50) no longer move the scrollbar as they come and go: a row seen once keeps its
|
|
12
|
-
// own height, and only rows never drawn use the average.
|
|
12
|
+
// own height, and only rows never drawn use the average. A row is what muten marks as one (title + carousel too)
|
|
13
13
|
let sizes = [];
|
|
14
14
|
el.setAttribute('aria-hidden', 'true');
|
|
15
15
|
|
|
@@ -18,6 +18,19 @@ export function mount(el, inputs, on) {
|
|
|
18
18
|
const gapOf = () => { if (gapNow < 0) gapNow = parseFloat(getComputedStyle(list).rowGap) || 0; return gapNow; };
|
|
19
19
|
// the rows muten drew after the marker (anything else the app puts in the list is left alone)
|
|
20
20
|
const rows = () => { const out = []; for (let n = el.nextElementSibling; n; n = n.nextElementSibling) out.push(n); return out; };
|
|
21
|
+
// THE ROWS AS ROWS. Every row of a muten `each` sits between two markers (<!--row--> … <!--/row-->), and a row may be
|
|
22
|
+
// several elements: a store's group is its title AND its carousel. Measured by element, a two-piece row never had its
|
|
23
|
+
// own height learnt (only the average), so a group leaving above the screen left a gap of the wrong size behind and
|
|
24
|
+
// the page jumped under the finger (CLS 3.8 scrolling a 28-group store). A row is measured from its first piece to its
|
|
25
|
+
// last; an element outside any markers is a row of its own.
|
|
26
|
+
const rowParts = () => {
|
|
27
|
+
const out = []; let cur = null;
|
|
28
|
+
for (let n = el.nextSibling; n; n = n.nextSibling) {
|
|
29
|
+
if (n.nodeType === 8) { if (n.data === 'row') cur = []; else if (n.data === '/row' && cur) { out.push(cur); cur = null; } continue; }
|
|
30
|
+
if (n.nodeType === 1) { if (cur) cur.push(n); else out.push([n]); }
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
};
|
|
21
34
|
// the real height of one row plus its gap, from the rows on screen; the guess until there are some
|
|
22
35
|
const learn = () => {
|
|
23
36
|
const r = rows(); const gap = gapOf() * scale();
|
|
@@ -27,12 +40,22 @@ export function mount(el, inputs, on) {
|
|
|
27
40
|
const n = to > from ? to - from : r.length;
|
|
28
41
|
if (r.length && n > 0) { const a = r[0].getBoundingClientRect(), b = r[r.length - 1].getBoundingClientRect(); const span = b.bottom - a.top; if (span > 0) { const seen = (span + gap) / n; step = step ? step * 0.7 + seen * 0.3 : seen; } }
|
|
29
42
|
if (!step) step = (guess + gapOf()) * scale();
|
|
30
|
-
|
|
43
|
+
const parts = rowParts();
|
|
44
|
+
if (to > from && parts.length === to - from) {
|
|
45
|
+
for (let i = 0; i < parts.length; i++) {
|
|
46
|
+
const shown = parts[i].filter((n) => n.getClientRects().length);
|
|
47
|
+
// a row with nothing shown (an empty group) takes no room and no gap: it is 0, not «unknown»
|
|
48
|
+
if (!shown.length) { sizes[from + i] = 0; continue; }
|
|
49
|
+
const h = shown[shown.length - 1].getBoundingClientRect().bottom - shown[0].getBoundingClientRect().top;
|
|
50
|
+
if (h > 0) sizes[from + i] = h + gap;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
31
53
|
};
|
|
32
54
|
// where row i starts, from the top of row 0 (screen px): the measured rows, the average for the rest
|
|
33
|
-
const
|
|
55
|
+
const size = (j) => (sizes[j] === undefined ? step : sizes[j]);
|
|
56
|
+
const offset = (i) => { let y = 0; for (let j = 0; j < i; j++) y += size(j); return y; };
|
|
34
57
|
// the row at a distance from the top of row 0
|
|
35
|
-
const indexAt = (y) => { let acc = 0; for (let j = 0; j < count; j++) { const h =
|
|
58
|
+
const indexAt = (y) => { let acc = 0; for (let j = 0; j < count; j++) { const h = size(j); if (acc + h > y) return j; acc += h; } return count; };
|
|
36
59
|
// what is on screen: the scroller's box, never past the window (a scroller taller than the screen grew with the rows)
|
|
37
60
|
const view = () => { if (scroller) { const b = scroller.getBoundingClientRect(); return [Math.max(0, b.top), Math.min(innerHeight, b.bottom)]; } return [0, innerHeight]; };
|
|
38
61
|
// a list inside a scaled box (a phone preview drawn at 80 %): what is measured comes in screen px, what is set goes in
|