*/ function gridColumns(string $html): array { preg_match_all('/--md-columns-([a-z-]+): (\d+);/', layoutRoot($html)['style'] ?? '', $matches, PREG_SET_ORDER); return collect($matches)->mapWithKeys(fn (array $match): array => [$match[1] => $match[2]])->all(); } it('writes all five column counts on every grid, one column when given none', function () { $html = (string) $this->blade('
One
'); expect(layoutRoot($html))->toMatchArray(['<' => 'div', 'data-md-grid' => 'data-md-grid']) ->not->toHaveKeys(['data-md-gap', 'data-md-min-item', 'data-md-columns']) ->and(gridColumns($html))->toBe(['compact' => '1', 'medium' => '1', 'expanded' => '1', 'large' => '1', 'extra-large' => '1']); }); it('fills each breakpoint left out from the nearest smaller one', function () { expect(gridColumns((string) $this->blade(''))) ->toBe(['compact' => '1', 'medium' => '2', 'expanded' => '2', 'large' => '4', 'extra-large' => '4']) ->and(gridColumns((string) $this->blade(''))) ->toBe(['compact' => '3', 'medium' => '3', 'expanded' => '3', 'large' => '3', 'extra-large' => '3']) // A count that is not a whole number from 1 keeps the one before it. ->and(gridColumns((string) $this->blade(''))) ->toBe(['compact' => '2', 'medium' => '2', 'expanded' => '2', 'large' => '5', 'extra-large' => '5']); expect(Layout::columns(['extra-large' => 6]))->toBe(['compact' => 1, 'medium' => 1, 'expanded' => 1, 'large' => 1, 'extra-large' => 6]); }); it('spaces the columns with a spacing token only, and with none for anything else', function () { expect(layoutRoot((string) $this->blade(''))['data-md-gap'])->toBe('space300') ->and(layoutRoot((string) $this->blade(''))['data-md-gap'])->toBe('none'); }); it('fills a row with columns of a minimum width, capped by the counts when both are given', function () { $fill = layoutRoot((string) $this->blade('')); $capped = layoutRoot((string) $this->blade('')); expect($fill)->toHaveKey('data-md-min-item')->not->toHaveKey('data-md-columns') ->and($fill['style'])->toContain('--md-min-item: 280px;') ->and($capped)->toHaveKeys(['data-md-min-item', 'data-md-columns']) ->and($capped['style'])->toContain('--md-min-item: 18rem;'); foreach (['240' => '240px', '20ch' => '20ch', '12.5em' => '12.5em'] as $given => $length) { expect(layoutRoot((string) $this->blade('', ['m' => $given]))['style'])->toContain("--md-min-item: {$length};"); } foreach (['wide', '50%', 'calc(10px + 1rem)', '0'] as $given) { expect(layoutRoot((string) $this->blade('', ['m' => $given])))->not->toHaveKey('data-md-min-item') ->and((string) $this->blade('', ['m' => $given]))->not->toContain('--md-min-item'); } }); it('takes the element, the visibility props, and the caller\'s class and style after its own', function () { $root = layoutRoot((string) $this->blade('')); expect($root)->toMatchArray(['<' => 'ul', 'data-md-hide-below' => 'expanded', 'class' => 'gallery']) ->and($root['style'])->toEndWith('--md-columns-extra-large: 1; align-items: start;'); }); it('reads its own column count at each breakpoint in the layout layer', function () { $css = (string) file_get_contents(__DIR__.'/../../../resources/css/layout/grid.css'); expect($css)->toContain('@layer material.layout') ->toContain('grid-template-columns: repeat(var(--md-columns), minmax(0, 1fr));'); foreach (['medium' => 600, 'expanded' => 840, 'large' => 1200, 'extra-large' => 1600] as $breakpoint => $width) { expect($css)->toContain("@media (width >= {$width}px) {\n --md-columns: var(--md-columns-{$breakpoint}, 1);"); } expect((string) file_get_contents(__DIR__.'/../../../resources/css/layout.css'))->toContain("@import './layout/grid.css';"); });