ui: the Files filter's clear button rejoins its input (#650)

The clear button sat detached from the filter field and 11px below it, and it
dragged the collapse-all button out of line with both.

One stale rule did all of that.  `.search-clear { margin: 0.625rem }` is left
over from the Semantic-era filter, where the clear button was a sibling of the
input and needed the gap.  It is now ActionInput's action, which joins the two
by dropping the input's right border -- so the margin reopened the seam the
component exists to close, pushed the button down by its own top margin, and,
because a flex line is as tall as its tallest item plus that item's margins,
stretched the wrapper to 62px around a 40px field.  The collapse-all button
beside it was centred in that 62px, which is why it looked wrong too.

Removing the rule fixes all three: the button abuts the field and shares its
outline, like the filters on Videos and Archives, and the row is one height.
The class had exactly one user left, so the rule goes with it.

The test asserts the button is inside ActionInput's wrapper, and that no rule
reintroduces a margin on it -- jsdom applies no stylesheet, so the geometry
itself cannot be measured there.  Confirmed it fails when the rule is put back.
This commit is contained in:
lrnselfreliance 2026-08-08 17:16:00 -06:00 • committed by Roland
parent eaa8b83e54
commit 7e63bbb3e2
No known key found for this signature in database
GPG key ID: 1BA620CE6C9A4680
3 changed files with 24 additions and 5 deletions

View file

@ -361,10 +361,6 @@ textarea.otp {
flex-grow: 1;
}
.search-clear {
margin: 0.625rem;
}
.video-player {
display: block;
margin: 0 auto; /* Center the video horizontally */

View file

@ -561,7 +561,6 @@ export function FileBrowser() {
type='button'
onClick={() => setFilterStr('')}
disabled={!filterStr}
className='search-clear'
label='Clear filter'
/>}
/>

View file

@ -1,3 +1,5 @@
import fs from 'fs';
import path from 'path';
import React from 'react';
import {act, fireEvent, screen, waitFor} from '@testing-library/react';
import {FileBrowser, filterBrowseFiles} from './FileBrowser';
@ -492,6 +494,28 @@ describe('FileBrowser', () => {
});
describe('Filter', () => {
it('joins the clear button to the input, and keeps the row aligned', () => {
/*
* The clear button belongs INSIDE ActionInput's wrapper, which is what removes
* the input's right border so the pair reads as one control -- the same joined
* look the Videos and Archives filters have.
*
* It used to carry `search-clear`, a class left over from Semantic whose
* `margin: 0.625rem` did three things at once: opened a gap so the button read
* as detached, pushed it 11px below the input, and stretched the wrapper to
* 62px against a 40px field, which threw the collapse-all button out of line
* too. jsdom applies no stylesheet, so the guard is that no rule reintroduces
* a margin on a control inside the wrapper.
*/
renderFileBrowser(<FileBrowser browseFiles={mockBrowseFiles}/>);
const clear = screen.getByRole('button', {name: 'Clear filter'});
expect(clear.closest('.wrolpi-action-input')).not.toBeNull();
const css = fs.readFileSync(path.join(__dirname, '..', 'App.css'), 'utf8');
expect(css).not.toMatch(/\.search-clear\s*{/);
});
// foo/ and bar/ are open, their children are loaded.
const nestedBrowseFiles = [
{