Fix live picker sizing and divider detection

This commit is contained in:
Paul Bakaus
2026-06-17 13:10:53 +09:00
parent 4f50db2bca
commit c7539c867d
33 changed files with 437 additions and 174 deletions
+29 -1
View File
@@ -10,6 +10,7 @@ import path from 'path';
import { fileURLToPath } from 'url';
import {
detectHtml,
detectText,
normalizeDesignSystem,
} from '../cli/engine/detect-antipatterns.mjs';
@@ -205,7 +206,7 @@ describe('detectHtml — static HTML/CSS fixtures', () => {
assert.equal(leftFindings.length, 11, `expected 11 border-left findings, got ${leftFindings.length}`);
assert.equal(rightFindings.length, 1, `expected 1 border-right finding, got ${rightFindings.length}`);
// PASS column must contribute zero border findings of either flavor.
// There are 13 pass cases: 6 structural neutrals plus 4 labels (plain
// There are 14 pass cases: 7 structural neutrals plus 4 labels (plain
// inline form label, label with a neutral gray border, label in a form
// row, and a label with a thin 1px colored left border), plus 3 var()
// pass cases (neutral-resolving var, thin var, uniform all-sides var).
@@ -218,6 +219,33 @@ describe('detectHtml — static HTML/CSS fixtures', () => {
);
});
it('modern-color-borders: regex fallback skips neutral 1px oklch dividers', () => {
const css = `
.flag-side-tab {
border-radius: 8px;
border-left: 2px solid oklch(65% 0.12 250);
}
.pass-context-divider {
border-radius: 8px;
border-right: 1px solid oklch(92% 0 0 / 0.12);
}
.pass-neutral-side {
border-radius: 8px;
border-left: 3px solid oklch(80% 0 0);
}
`;
const f = detectText(css, path.join(FIXTURES, 'modern-color-borders-regex.css'));
const sideTabs = f.filter(r => r.antipattern === 'side-tab');
assert.equal(
sideTabs.length,
1,
`expected only the colored 2px side-tab to flag, got: ${sideTabs.map(r => r.snippet).join('; ')}`
);
assert.match(sideTabs[0].snippet, /border-left: 2px solid oklch/);
});
it('typography-should-flag: detects all three issues', async () => {
const f = await detectHtml(path.join(FIXTURES, 'typography-should-flag.html'));
assert.ok(f.some(r => r.antipattern === 'overused-font'));
+7 -2
View File
@@ -136,11 +136,16 @@ describe('detectText — Tailwind side-tab', () => {
expect(f.some(r => r.antipattern === 'side-tab')).toBe(true);
});
test('detects border-l-1 + rounded', () => {
const f = detectText('<div class="border-l-1 border-blue-500 rounded-md">', 'test.html');
test('detects border-l-2 + rounded', () => {
const f = detectText('<div class="border-l-2 border-blue-500 rounded-md">', 'test.html');
expect(f.some(r => r.antipattern === 'side-tab')).toBe(true);
});
test('ignores border-l-1 + rounded', () => {
const f = detectText('<div class="border-l-1 border-blue-500 rounded-md">', 'test.html');
expect(f.filter(r => r.antipattern === 'side-tab')).toHaveLength(0);
});
test('ignores border-l-1 without rounded', () => {
const f = detectText('<div class="border-l-1 border-gray-300">', 'test.html');
expect(f.filter(r => r.antipattern === 'side-tab')).toHaveLength(0);
+9
View File
@@ -264,6 +264,14 @@
border: 3px solid var(--brand);
border-radius: 4px;
}
/* 14: neutral 1px oklch right divider — context-bar hairline, not a side-tab. */
#pass-oklch-neutral-right-divider {
width: 400px;
background: #ffffff;
border-radius: 4px;
border-right: 1px solid oklch(92% 0 0 / 0.12);
}
</style>
</head>
<body>
@@ -319,6 +327,7 @@
<div class="case" id="pass-var-neutral"><h3>var() neutral</h3><p>--line resolves to gray</p></div>
<div class="case" id="pass-var-thin"><h3>var() thin</h3><p>1px too thin to qualify</p></div>
<div class="case" id="pass-var-allsides"><h3>var() all sides</h3><p>uniform, not a side-tab</p></div>
<div class="case" id="pass-oklch-neutral-right-divider"><h3>oklch neutral right divider</h3><p>1px neutral context-bar hairline</p></div>
</div>
</div>
<script src="/js/detect-antipatterns-browser.js"></script>
+20
View File
@@ -175,6 +175,26 @@ describe('live-browser.js regression guards', () => {
/maxWidth: 'calc\(100vw - 16px\)'[\s\S]{0,80}?boxSizing: 'border-box'/,
'global bar should be constrained to the viewport instead of clipping the exit control offscreen',
);
assert.match(
SOURCE,
/globalBarEl = el\('div', \{[\s\S]{0,360}?width: 'max-content'/,
'fixed-position global bar must use max-content sizing before maxWidth clamps it, or narrow panes clip the exit button',
);
assert.match(
SOURCE,
/const inner = el\('div', \{[\s\S]{0,220}?flex: '0 0 auto'/,
'global bar inner controls must not flex-shrink and crop hover labels',
);
assert.match(
SOURCE,
/function makeIconBtn[\s\S]{0,360}?flex: '0 0 auto'[\s\S]{0,80}?minWidth: '30px'/,
'global bar icon buttons must keep stable hitboxes when Steer expands',
);
assert.match(
SOURCE,
/applyGlobalBarLabelState\(expandInactive, pageChatExpanded\)/,
'expanded Steer should force labels closed without shrinking the icons',
);
});
it('does not autofocus the steering chat while a page editable is focused', () => {