stitch2 0.24.1 → 0.24.3
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/audit.js +11 -2
- package/dist/canvas.html +16 -6
- package/dist/shots.js +7 -2
- package/package.json +1 -1
- package/skills/stitch2/references/google.md +2 -1
package/dist/audit.js
CHANGED
|
@@ -842,8 +842,17 @@ export async function audit(opts) {
|
|
|
842
842
|
if (!el.matches('nav, [role=navigation], [role=tablist]') && !el.querySelector('nav, [role=navigation], [role=tablist]'))
|
|
843
843
|
continue;
|
|
844
844
|
const items = [...el.querySelectorAll('a[href], button, [role=tab]')].filter((i) => shown(i) && !i.parentElement?.closest('a[href], button, [role=tab]'));
|
|
845
|
-
|
|
846
|
-
|
|
845
|
+
// The destinations stand in one row. A panel above them (a workout that is running, a player) belongs to the bar
|
|
846
|
+
// but is not a destination: the widest row counts.
|
|
847
|
+
const tops = items.map((i) => i.getBoundingClientRect().top).sort((a, b) => a - b);
|
|
848
|
+
let widest = 0;
|
|
849
|
+
for (let from = 0, row = 0; row < tops.length; row++) {
|
|
850
|
+
if (tops[row] - tops[from] > 12)
|
|
851
|
+
from = row;
|
|
852
|
+
widest = Math.max(widest, row - from + 1);
|
|
853
|
+
}
|
|
854
|
+
if (widest > 5)
|
|
855
|
+
push('warning', 'nav-destinations', el, widest + " destinations in the bottom navigation: Material's navigation bar holds 3–5");
|
|
847
856
|
}
|
|
848
857
|
// 6h. Keyboard focus is visible (Material's focus state, web.dev, WCAG 2.4.7): focusing a control changes how
|
|
849
858
|
// it or its frame looks. Transitions are paused so a ring that fades in still counts.
|
package/dist/canvas.html
CHANGED
|
@@ -677,6 +677,10 @@ const frameSrc = (s) => `/${s.path}?pick&canvas=${s.viewportHeight ?? 844}${lang
|
|
|
677
677
|
// The rest show the picture the server renders (/api/shot). Without pictures (no Chromium), frames in view stay
|
|
678
678
|
// live at any zoom, still at most MAX_LIVE. ----
|
|
679
679
|
const LIVE_ZOOM = 0.3, MAX_LIVE = 6, SHOTS_AT_ONCE = 3
|
|
680
|
+
// A picture costs the server a whole page render. A frame narrower than MIN_SHOT_PX on screen shows nothing you could read, so it is not
|
|
681
|
+
// asked for (fit-all with hundreds of screens would otherwise queue a render of every one, and again after every shared file or link change),
|
|
682
|
+
// and at most SHOTS_QUEUED pictures wait at a time, the nearest to the middle first; as they arrive the next ones are asked for.
|
|
683
|
+
const MIN_SHOT_PX = 64, SHOTS_QUEUED = 24
|
|
680
684
|
let shotRev = 0, shotErrors = 0, syncTimer
|
|
681
685
|
const shotsFailed = () => shotErrors > 2
|
|
682
686
|
const scheduleSync = () => { clearTimeout(syncTimer); syncTimer = setTimeout(syncLive, 120) }
|
|
@@ -787,7 +791,11 @@ function syncLive() {
|
|
|
787
791
|
// Keep the page until its picture is loaded; switching zoom must never reveal an empty frame.
|
|
788
792
|
for (const f of frames.values()) if (f.iframe && !live.has(f) && (!visible.has(f) || (f.img.complete && f.img.naturalWidth))) unmount(f)
|
|
789
793
|
for (const f of live) mount(f)
|
|
790
|
-
shotQueue = near
|
|
794
|
+
shotQueue = near
|
|
795
|
+
.filter(({ f }) => f.screen.width * view.z >= MIN_SHOT_PX)
|
|
796
|
+
.map(({ f }) => [f, shotUrl(f.screen)])
|
|
797
|
+
.filter(([f, url]) => f.img.getAttribute('src') !== url)
|
|
798
|
+
.slice(0, SHOTS_QUEUED)
|
|
791
799
|
pumpShots()
|
|
792
800
|
}
|
|
793
801
|
|
|
@@ -1168,12 +1176,14 @@ events.onmessage = async (e) => {
|
|
|
1168
1176
|
// (tokens.tailwind.css), the components.
|
|
1169
1177
|
const shared = paths.some((p) => /\.(css|js|mjs)$/.test(p) || p.startsWith('components/'))
|
|
1170
1178
|
if (shared) shotRev++
|
|
1171
|
-
for
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1179
|
+
// One reflow for all the frames that flash, not one each: approving a version can touch every screen that linked to it.
|
|
1180
|
+
const touched = [...frames.values()].filter((f) => shared || html.includes(f.screen.path))
|
|
1181
|
+
for (const f of touched) {
|
|
1182
|
+
f.iframe?.contentWindow?.location.reload()
|
|
1183
|
+
f.el.classList.remove('changed')
|
|
1176
1184
|
}
|
|
1185
|
+
void viewport.offsetWidth
|
|
1186
|
+
for (const f of touched) f.el.classList.add('changed')
|
|
1177
1187
|
scheduleSync()
|
|
1178
1188
|
}
|
|
1179
1189
|
|
package/dist/shots.js
CHANGED
|
@@ -31,8 +31,13 @@ function sharedStamp() {
|
|
|
31
31
|
if (depth < 4)
|
|
32
32
|
walk(join(dir, e.name), depth + 1);
|
|
33
33
|
}
|
|
34
|
-
else if (!e.name.endsWith('.html') && !(depth === 0 && REPORTS.has(e.name)))
|
|
35
|
-
|
|
34
|
+
else if (!e.name.endsWith('.html') && !(depth === 0 && REPORTS.has(e.name))) {
|
|
35
|
+
// A link to nothing (a symlinked folder that is not there on this machine) is not a file that can change a picture.
|
|
36
|
+
try {
|
|
37
|
+
newest = Math.max(newest, statSync(join(dir, e.name)).mtimeMs);
|
|
38
|
+
}
|
|
39
|
+
catch { }
|
|
40
|
+
}
|
|
36
41
|
}
|
|
37
42
|
};
|
|
38
43
|
walk(ROOT, 0);
|
package/package.json
CHANGED
|
@@ -71,7 +71,8 @@ the rest are judged from the render. Where Google and DESIGN.md disagree, DESIGN
|
|
|
71
71
|
## Components
|
|
72
72
|
|
|
73
73
|
- **Navigation bar:** three to five destinations, each an icon with a one-line label; more destinations go to a
|
|
74
|
-
rail, a drawer or a page **(check: nav-destinations; label-wraps)**.
|
|
74
|
+
rail, a drawer or a page **(check: nav-destinations; label-wraps)**. The check counts the destinations in one row:
|
|
75
|
+
a panel stacked above them in the same bar (a running workout's Resume and Discard, a player) is not a destination.
|
|
75
76
|
- **Button emphasis:** filled for the one main action, tonal or outlined for secondary, text buttons for
|
|
76
77
|
low-emphasis; one floating action button at most.
|
|
77
78
|
- **Icon-only controls have a name** that says what they do ("Share", not "Share button"); repeated items in a
|