Add the surface layout component
Plan step 35: <x-surface level padding corner outlined>, a tonal region in surface or a surface-container step, padded with a spacing token, rounded with a corner token and optionally edged in outline-variant. A pane on a surface keeps its margin again, since the surface is a new edge. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Opus 5
parent
da7a05a619
commit
e99c5993d8
@@ -126,3 +126,19 @@ it('fills a grid with columns of a minimum width, capped by the count', function
|
||||
->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 = '<x-surface id="surface" level="surface-container-high" padding="space300" corner="lg" outlined hide-below="medium">Surface</x-surface>'
|
||||
.'<div id="role" style="background-color: var(--md-sys-color-surface-container-high)"></div>';
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
it('draws a tonal region in surface-container by default, as a div', function () {
|
||||
$root = layoutRoot((string) $this->blade('<x-surface>Content</x-surface>'));
|
||||
|
||||
expect($root)->toMatchArray(['<' => 'div', 'data-md-surface' => 'data-md-surface', 'data-md-level' => 'surface-container'])
|
||||
->not->toHaveKeys(['data-md-padding', 'data-md-corner', 'data-md-outlined', 'data-md-hide-below', 'data-md-hide-from', 'class', 'style']);
|
||||
});
|
||||
|
||||
it('fills the surface with each of M3\'s surface roles, and the default for any other', function () {
|
||||
foreach (['surface', 'surface-dim', 'surface-bright', 'surface-container-lowest', 'surface-container-low', 'surface-container', 'surface-container-high', 'surface-container-highest'] as $level) {
|
||||
expect(layoutRoot((string) $this->blade('<x-surface :level="$level" />', ['level' => $level]))['data-md-level'])->toBe($level);
|
||||
}
|
||||
|
||||
expect(layoutRoot((string) $this->blade('<x-surface level="primary-container" />'))['data-md-level'])->toBe('surface-container');
|
||||
});
|
||||
|
||||
it('pads the surface with a spacing token only, and with none for anything else', function () {
|
||||
expect(layoutRoot((string) $this->blade('<x-surface padding="space300" />'))['data-md-padding'])->toBe('space300');
|
||||
|
||||
foreach (['24px', '3', 'space1000', 'roomy'] as $padding) {
|
||||
expect(layoutRoot((string) $this->blade('<x-surface :padding="$padding" />', ['padding' => $padding]))['data-md-padding'])->toBe('none');
|
||||
}
|
||||
});
|
||||
|
||||
it('rounds the surface with a corner token, and leaves it square for anything else', function () {
|
||||
foreach (['none', 'xs', 'sm', 'md', 'lg', 'lg-increased', 'xl', 'xl-increased', 'xxl', 'full'] as $corner) {
|
||||
expect(layoutRoot((string) $this->blade('<x-surface :corner="$corner" />', ['corner' => $corner]))['data-md-corner'])->toBe($corner);
|
||||
}
|
||||
|
||||
expect(layoutRoot((string) $this->blade('<x-surface corner="huge" />')))->not->toHaveKey('data-md-corner');
|
||||
});
|
||||
|
||||
it('draws an outline only when asked', function () {
|
||||
expect(layoutRoot((string) $this->blade('<x-surface outlined />')))->toHaveKey('data-md-outlined')
|
||||
->and(layoutRoot((string) $this->blade('<x-surface :outlined="false" />')))->not->toHaveKey('data-md-outlined');
|
||||
});
|
||||
|
||||
it('draws the element it is asked for, and a div for one it does not take', function () {
|
||||
expect(layoutRoot((string) $this->blade('<x-surface as="section">Content</x-surface>'))['<'])->toBe('section')
|
||||
->and((string) $this->blade('<x-surface as="section">Content</x-surface>'))->toContain('</section>')
|
||||
->and(layoutRoot((string) $this->blade('<x-surface as="script">Content</x-surface>'))['<'])->toBe('div')
|
||||
->and(layoutRoot((string) $this->blade('<x-surface as="input" />'))['<'])->toBe('div');
|
||||
});
|
||||
|
||||
it('hides below and from a breakpoint, never below or from compact', function () {
|
||||
expect(layoutRoot((string) $this->blade('<x-surface hide-below="expanded" hide-from="extra-large" />')))
|
||||
->toMatchArray(['data-md-hide-below' => 'expanded', 'data-md-hide-from' => 'extra-large']);
|
||||
|
||||
foreach (['compact', 'tablet', 'Medium', '840'] as $breakpoint) {
|
||||
expect(layoutRoot((string) $this->blade('<x-surface :hide-below="$b" :hide-from="$b" />', ['b' => $breakpoint])))
|
||||
->not->toHaveKeys(['data-md-hide-below', 'data-md-hide-from']);
|
||||
}
|
||||
});
|
||||
|
||||
it('puts the caller\'s class and style on the surface untouched', function () {
|
||||
expect(layoutRoot((string) $this->blade('<x-surface class="upload-zone" style="min-height: 12rem" data-test="zone" />')))
|
||||
->toMatchArray(['class' => 'upload-zone', 'style' => 'min-height: 12rem;', 'data-test' => 'zone']);
|
||||
});
|
||||
|
||||
it('draws the surface from a stylesheet in the layout layer, imported by layout.css', function () {
|
||||
$css = (string) file_get_contents(__DIR__.'/../../../resources/css/layout/surface.css');
|
||||
|
||||
expect($css)->toContain('@layer material.layout')
|
||||
->toContain("[data-md-surface][data-md-level='surface-container-high'] {")
|
||||
->toContain('background-color: var(--md-sys-color-surface-container-high);')
|
||||
->toContain('border: 1px solid var(--md-sys-color-outline-variant);')
|
||||
->toContain("@import './spacing.css';")
|
||||
->toContain("@import './visibility.css';")
|
||||
// A pane on a surface keeps its content off the surface's edge again.
|
||||
->toContain("[data-md-surface] > * {\n --md-layout-margin: initial;")
|
||||
->and((string) file_get_contents(__DIR__.'/../../../resources/css/layout.css'))->toContain("@import './layout/surface.css';");
|
||||
});
|
||||
Reference in New Issue
Block a user