get($path, fn () => Blade::render(<< @vite(config('livewire-material.showcase.vite')) @livewireStyles {$body} @livewireScripts BLADE)); return layoutReady(visit($path)->resize($width, $height)); } function layoutReady(mixed $page): mixed { return $page->waitForEvent('networkidle') ->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined' && typeof window.Livewire !== 'undefined'"); } /** A computed style of the element matching the selector. */ function layoutStyle(string $selector, string $property): string { return "getComputedStyle(document.querySelector('{$selector}')).{$property}"; } /** A side of the element's box, rounded to the pixel. */ function layoutRect(string $selector, string $side): string { return "Math.round(document.querySelector('{$selector}').getBoundingClientRect().{$side})"; } /** How many column tracks a grid has. */ function layoutColumns(string $selector): string { return layoutStyle($selector, 'gridTemplateColumns').".split(' ').length"; } it('spaces a stack with its token, never with its parent\'s, and hides it from a breakpoint over its own display', function () { $body = '

One

Two

Three

' .'

Compact only

'; layoutPage($body, 599) ->assertScript(layoutStyle('#outer', 'flexDirection')." === 'column'") ->assertScript(layoutStyle('#outer', 'rowGap')." === '24px'") ->assertScript(layoutStyle('#inner', 'rowGap')." === '0px'") ->assertScript(layoutStyle('#hidden-from', 'display')." === 'flex'"); layoutPage($body, 600) ->assertScript(layoutStyle('#hidden-from', 'display')." === 'none'"); }); it('stacks a row below its breakpoint and lays it side by side from it', function () { $body = 'OneTwo' .'One' .'Medium and up'; layoutPage($body, 599) ->assertScript(layoutStyle('#row', 'flexDirection')." === 'column'") ->assertScript(layoutStyle('#row', 'alignItems')." === 'stretch'") ->assertScript(layoutStyle('#aligned', 'alignItems')." === 'flex-start'") ->assertScript(layoutStyle('#row', 'rowGap')." === '16px'") ->assertScript(layoutStyle('#hidden', 'display')." === 'none'"); layoutPage($body, 600) ->assertScript(layoutStyle('#row', 'flexDirection')." === 'row'") ->assertScript(layoutStyle('#row', 'alignItems')." === 'center'") ->assertScript(layoutStyle('#hidden', 'display')." === 'flex'"); }); it('mirrors a row in a right-to-left document', function () { layoutPage('FirstSecond', 800, 600, 'rtl') ->assertScript(layoutRect('#first', 'left').' > '.layoutRect('#second', 'left')); }); it('gives a grid its columns per breakpoint, and a nested grid its own', function () { $body = <<<'BLADE'
A
B
2
3
4
BLADE; layoutPage($body, 599) ->assertScript(layoutColumns('#outer').' === 1') ->assertScript(layoutColumns('#inner').' === 1'); layoutPage($body, 600) ->assertScript(layoutColumns('#outer').' === 3') ->assertScript(layoutStyle('#outer', 'columnGap')." === '16px'") // The parent's three never reach the grid inside it. ->assertScript(layoutColumns('#inner').' === 1'); layoutPage($body, 1199)->assertScript(layoutColumns('#outer').' === 3'); layoutPage($body, 1200)->assertScript(layoutColumns('#outer').' === 4'); }); it('fills a grid with columns of a minimum width, capped by the count', function () { $body = '
1
2
3
4
' .'
1
2
3
4
'; layoutPage($body, 800) ->assertScript(layoutColumns('#fill').' === 3') ->assertScript(layoutColumns('#capped').' === 2'); }); it('draws a surface in its role, padding and corner, and hides it below a breakpoint', function () { $body = 'Surface' .'
'; layoutPage($body, 599) ->assertScript(layoutStyle('#surface', 'display')." === 'none'"); layoutPage($body, 600) ->assertScript(layoutStyle('#surface', 'display')." === 'block'") ->assertScript(layoutStyle('#surface', 'backgroundColor').' === '.layoutStyle('#role', 'backgroundColor')) ->assertScript(layoutStyle('#surface', 'paddingTop')." === '24px'") ->assertScript(layoutStyle('#surface', 'borderTopLeftRadius')." === '16px'") ->assertScript(layoutStyle('#surface', 'borderTopWidth')." === '1px'") ->assertNoJavaScriptErrors(); }); it('keeps M3\'s margin in a pane, once, with its app bar across the whole pane', function () { $body = <<<'BLADE'

Body

Nested

On a surface

Narrow

BLADE; layoutPage($body, 599) ->assertScript(layoutRect('#text', 'left').' === 16') ->assertScript(layoutRect('#pane [data-md-pane-bar]', 'width').' === '.layoutRect('#pane', 'width')) ->assertScript(layoutStyle('#inner [data-md-pane-body]', 'paddingLeft')." === '0px'"); layoutPage($body, 600) ->assertScript(layoutRect('#text', 'left').' === 24') ->assertScript(layoutRect('#pane [data-md-pane-bar]', 'left').' === 0') ->assertScript(layoutStyle('#inner [data-md-pane-body]', 'paddingLeft')." === '0px'") // A surface is a new edge, so a pane on it keeps its margin again. ->assertScript(layoutRect('#surface-text', 'left').' - '.layoutRect('#card', 'left').' === 24'); layoutPage($body, 1200) ->assertScript(layoutRect('#narrow', 'width').' === 640') ->assertScript(layoutRect('#narrow', 'left').' === 280') ->assertNoJavaScriptErrors(); });