@muten/shadcn 0.1.13 → 0.1.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muten/shadcn",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "shadcn-style component registry for muten - own-the-source parts you add with `muten add`.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -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. Only when each row is ONE element (else: the average alone)
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
- if (r.length && to > from && r.length === to - from) for (let i = 0; i < r.length; i++) { const h = r[i].getBoundingClientRect().height; if (h > 0) sizes[from + i] = h + gap; }
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 offset = (i) => { let y = 0; for (let j = 0; j < i; j++) y += sizes[j] || step; return y; };
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 = sizes[j] || step; if (acc + h > y) return j; acc += h; } return count; };
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