Expressive deprecates the divided style, so the results lose their divider; the full-screen layout takes its own surface-container-low, one step from the docked one; the docked view opens over a scrim, as M3's variants table says it does; and the bar is bounded at M3's 720px, grows to that width while focused, and rests with the 24px leading and trailing padding the specs table gives an unfocused bar. --search-width sets the resting width for M3's 360px bar. Plan step 20, findings IN-07, IN-08, IN-09, IN-20 and IN-21. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
60 lines
2.5 KiB
PHP
60 lines
2.5 KiB
PHP
<?php
|
|
|
|
it('draws a search bar whose combobox controls the view', function () {
|
|
$html = (string) $this->blade('<x-search id="find" placeholder="Search shares" wire:model.live.debounce.300ms="query" />');
|
|
|
|
expect($html)
|
|
->toContain('data-search')
|
|
->toContain('role="search"')
|
|
->toContain('type="search"')
|
|
->toContain('placeholder="Search shares"')
|
|
->toContain('aria-label="Search shares"')
|
|
->toContain('role="combobox"')
|
|
->toContain('aria-haspopup="dialog"')
|
|
->toContain('aria-controls="find-view"')
|
|
->toContain('aria-expanded="false"')
|
|
->toContain('wire:model.live.debounce.300ms="query"')
|
|
->toContain('id="find-view"')
|
|
->toContain('data-search-clear')
|
|
->toContain('data-search-scrim')
|
|
->toContain('aria-label="Back"')
|
|
->toContain('materialSearch(false,')
|
|
->not->toContain('data-search-results');
|
|
|
|
// The state belongs to the combobox, never to the bare textbox ARIA gives it to.
|
|
expect($html)->toMatch('/<span\s+data-search-field[^>]*aria-expanded/s');
|
|
expect($html)->not->toMatch('/<input[^>]*aria-expanded/s');
|
|
});
|
|
|
|
it('announces how many results there are, politely', function () {
|
|
$html = (string) $this->blade('<x-search />');
|
|
|
|
expect($html)
|
|
->toContain('data-search-status')
|
|
->toContain('aria-live="polite"')
|
|
->toContain('aria-atomic="true"')
|
|
->toContain('No results')
|
|
->toContain('1 result')
|
|
->toContain(':count results');
|
|
});
|
|
|
|
it('shows the results as a list, or what to say when there are none', function () {
|
|
expect((string) $this->blade('<x-search><a href="/shares/1">holiday.zip</a></x-search>'))
|
|
->toContain('data-search-results role="list"')
|
|
->toContain('<a href="/shares/1">holiday.zip</a>')
|
|
->and((string) $this->blade('<x-search><x-slot:empty>No shares match.</x-slot:empty></x-search>'))
|
|
->toContain('No shares match.')
|
|
->not->toContain('data-search-results role="list"');
|
|
});
|
|
|
|
it('names the input, trails the bar, and stays docked on request', function () {
|
|
$html = (string) $this->blade('<x-search label="Search your shares" icon="travel_explore" docked><x-slot:trailing><button>AR</button></x-slot:trailing></x-search>');
|
|
|
|
expect($html)
|
|
->toContain('placeholder="Search"')
|
|
->toContain('aria-label="Search your shares"')
|
|
->toContain('data-search-trailing')
|
|
->toContain('<button>AR</button>')
|
|
->toContain('materialSearch(true,');
|
|
});
|