diff --git a/resources/css/components.css b/resources/css/components.css index 50ca58df..3a6a7615 100644 --- a/resources/css/components.css +++ b/resources/css/components.css @@ -14,6 +14,7 @@ /* Actions and communication */ /* Inputs, selection and data */ +@import './components/form.css'; /* Containment */ diff --git a/resources/css/components/form.css b/resources/css/components/form.css new file mode 100644 index 00000000..80747a2f --- /dev/null +++ b/resources/css/components/form.css @@ -0,0 +1,37 @@ +/* + * : its fields in one column, and its actions at the foot + * (resources/views/components/form.blade.php). + * + * The column is a one-track grid whose track is `minmax(0, 1fr)`: a bare grid's implicit column + * floors at its content's min-content, so on a phone a wide field would push the form past its + * pane. Rows take their content's height. 16px (`space200`) between fields, because a text field + * floats its label half above its outline and any less lets the hint under one field run into the + * label of the next. + * + * The actions wrap, end-aligned, 8px (`space100`) apart — M3's gap between buttons in a row. A + * caller's class on the `actions` slot lands on the row and outranks this layer. + * + * [data-md-form] the
+ * [data-md-form-actions] the row of actions, under the divider when `separator` asks for one + */ + +@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility; + +/* TODO(step 36): @import './divider.css' once leaves Tailwind (containment stream). */ + +@layer material.components { + [data-md-form] { + display: grid; + grid-template-columns: minmax(0, 1fr); + grid-auto-rows: min-content; + gap: var(--md-sys-measurement-space200); + } + + [data-md-form-actions] { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: flex-end; + gap: var(--md-sys-measurement-space100); + } +} diff --git a/resources/views/components/form.blade.php b/resources/views/components/form.blade.php index abab70cc..46592455 100644 --- a/resources/views/components/form.blade.php +++ b/resources/views/components/form.blade.php @@ -1,17 +1,15 @@ {{-- A form: its fields in one column, and its actions at the foot. - `gap-4` between fields, because a text field floats its label half above its outline: any less - and the hint under one field runs into the label of the next. The `actions` slot takes a class - of its own; `separator` draws a divider above it. - - `grid-cols-1`, because a bare `grid` has no columns and its implicit one floors at the - content's min-content: on a phone a wide field would push the form past its column. --}} + 16px between fields, because a text field floats its label half above its outline: any less + and the hint under one field runs into the label of the next. The `actions` slot takes + attributes of its own (a `class` from the call site lands on the row untouched); `separator` + draws a divider above it. The column is resources/css/components/form.css. --}} @props([ 'separator' => false, ]) -class(['grid grid-cols-1 auto-rows-min gap-4']) }}> + {{ $slot }} @isset($actions) @@ -19,7 +17,7 @@ @endif -
attributes->class(['flex flex-wrap items-center justify-end gap-2']) }}> +
attributes }}> {{ $actions }}
@endisset diff --git a/tests/Feature/Components/FieldTest.php b/tests/Feature/Components/FieldTest.php index 10291775..25d945a3 100644 --- a/tests/Feature/Components/FieldTest.php +++ b/tests/Feature/Components/FieldTest.php @@ -189,10 +189,20 @@ it('lays out a form with its actions under an optional divider', function () { BLADE); expect($html) - ->toContain('') + ->toContain('') ->toContain('role="separator"') - ->toContain('justify-between') + ->toContain('
') + ->not->toContain('grid-cols-1') ->toContain('') ->and((string) $this->blade('')) ->not->toContain('role="separator"'); }); + +it('draws a form\'s column and its actions from its stylesheet', function () { + $css = (string) file_get_contents(__DIR__.'/../../../resources/css/components/form.css'); + + expect($css)->toContain('@layer material.components') + ->toContain('grid-template-columns: minmax(0, 1fr);') + ->toContain('gap: var(--md-sys-measurement-space200);') + ->and((string) file_get_contents(__DIR__.'/../../../resources/css/components.css'))->toContain("@import './components/form.css';"); +});