diff --git a/resources/css/components/datepicker.css b/resources/css/components/datepicker.css index 1a077731..93f65fb2 100644 --- a/resources/css/components/datepicker.css +++ b/resources/css/components/datepicker.css @@ -33,16 +33,17 @@ * [data-md-datepicker-entry] the text field(s) of the modal input * [data-md-datepicker-actions] Cancel and OK * - * Cancel, OK and the icon buttons in the app bar and the nav are , which draws its own - * state layer and focus ring from the foundation classes. The day, the year, the menu button and - * the list option keep their own hand-rolled state layer and focus ring, as `data-md-field-button` - * does (field.css): each interactive box is bigger than the round indicator drawn inside it (a - * day's cell is 48px, its indicator 40px; a menu button and an option are full rows), which the - * foundation's classes, fixed to the element they are on, cannot draw — and `:focus-visible` only - * ever matches the element actually focused, never a smaller child inside it. + * The year, the menu buttons and the docked lists' options render the foundation's `md-state-layer` + * and `md-focus-ring` (foundation/interaction.css): each draws its layer in its own ink and its + * ring round itself, so the classes need one refinement only — an option's ring sits inside its + * full-width row. Cancel, OK and the icon buttons are , which renders the classes too. + * The day alone keeps a state layer and ring of its own: the element focused and pressed is the + * 48px cell, while both are drawn on the 40px round indicator inside it, which a class drawn on the + * element it sits on cannot do, and `:focus-visible` never matches that child. Its layer takes + * M3's state opacities (tokens/state.css) and is gone from a disabled or blank day. * - * Every state layer here is the content colour at 8% on hover (only where a pointer can hover) and - * 10% on focus and press; keyboard focus adds the package's 3px secondary ring. + * Lengths are px, and spacing is the measurement tokens: M3 gives every size here in dp. A + * disabled day or option is on-surface at M3's 38% content opacity. */ @layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility; @@ -56,7 +57,7 @@ /* The padding is on the lines, not the box, so a box with nothing to say takes no room. */ [data-md-datepicker-support] { - --datepicker-pad: 1rem; + --datepicker-pad: var(--md-sys-measurement-space200); color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-sm); @@ -64,15 +65,15 @@ } [data-md-datepicker-support] > * { - padding: 0.25rem var(--datepicker-pad) 0; + padding: var(--md-sys-measurement-space50) var(--datepicker-pad) 0; } [data-md-datepicker-support][data-md-size='sm'] { - --datepicker-pad: 0.75rem; + --datepicker-pad: 12px; } [data-md-datepicker-support][data-md-size='xs'] { - --datepicker-pad: 0.625rem; + --datepicker-pad: var(--md-sys-measurement-space125); } [data-md-datepicker-error] { @@ -83,9 +84,9 @@ [data-md-datepicker-picker] { inset: auto; - width: 22.5rem; - max-width: calc(100vw - 1rem); - max-height: calc(100dvh - 1rem); + width: 360px; + max-width: calc(100vw - var(--md-sys-measurement-space200)); + max-height: calc(100dvh - var(--md-sys-measurement-space200)); margin: 0; padding: 0; overflow: visible; @@ -97,7 +98,7 @@ [data-md-datepicker-picker]:popover-open { top: anchor(bottom); left: anchor(left); - margin-block: 0.25rem; + margin-block: var(--md-sys-measurement-space50); position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline; opacity: 1; transition-property: opacity; @@ -184,22 +185,22 @@ display: flex; align-items: center; justify-content: space-between; - gap: 0.5rem; - height: 4rem; - padding-inline: 0.25rem 0.75rem; + gap: var(--md-sys-measurement-space100); + height: 64px; + padding-inline: var(--md-sys-measurement-space50) 12px; } [data-md-datepicker-app-bar-actions] { display: flex; align-items: center; - gap: 0.25rem; + gap: var(--md-sys-measurement-space50); } [data-md-datepicker-full-headline] { display: flex; flex-direction: column; - gap: 0.25rem; - padding: 0 1.5rem 1rem; + gap: var(--md-sys-measurement-space50); + padding: 0 var(--md-sys-measurement-space300) var(--md-sys-measurement-space200); } /* The calendar is the only part that scrolls, with the weekday header held at its top. */ @@ -218,11 +219,11 @@ } [data-md-datepicker-picker][data-md-presentation='full'] [data-md-datepicker-day] { - scroll-margin-block: 3rem; + scroll-margin-block: 48px; } [data-md-datepicker-month-label] { - padding: 1.25rem 0 0.5rem; + padding: 20px 0 var(--md-sys-measurement-space100); color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-title-sm); letter-spacing: var(--md-sys-typescale-title-sm-tracking); @@ -236,17 +237,17 @@ flex-direction: column; justify-content: space-between; flex: none; - min-height: 7.5rem; + min-height: 120px; border-bottom: 1px solid var(--md-sys-color-outline-variant); color: var(--md-sys-color-on-surface-variant); } [data-md-datepicker-header][data-md-range] { - min-height: 8rem; + min-height: 128px; } [data-md-datepicker-title] { - padding: 1rem 0.75rem 0 1.5rem; + padding: var(--md-sys-measurement-space200) 12px 0 var(--md-sys-measurement-space300); font: var(--md-sys-typescale-label-lg); letter-spacing: var(--md-sys-typescale-label-lg-tracking); } @@ -255,8 +256,8 @@ display: flex; align-items: center; justify-content: space-between; - gap: 0.5rem; - padding: 0 0.75rem 0.75rem 1.5rem; + gap: var(--md-sys-measurement-space100); + padding: 0 12px 12px var(--md-sys-measurement-space300); } [data-md-datepicker-headline] { @@ -280,14 +281,14 @@ flex: none; align-items: center; justify-content: space-between; - height: 3.5rem; - padding-inline: 0.75rem; + height: 56px; + padding-inline: 12px; color: var(--md-sys-color-on-surface-variant); } [data-md-datepicker-nav][data-md-docked] { - height: 4rem; - padding-inline: 0.25rem; + height: 64px; + padding-inline: var(--md-sys-measurement-space50); } [data-md-datepicker-stepper], @@ -302,25 +303,22 @@ } [data-md-datepicker-menu-button] { - position: relative; display: inline-flex; align-items: center; - gap: 0.5rem; - height: 2.5rem; - padding-inline: 0.75rem 0.5rem; + gap: var(--md-sys-measurement-space100); + height: 40px; + padding-inline: 12px var(--md-sys-measurement-space100); border-radius: var(--md-sys-shape-corner-full); color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-label-lg); letter-spacing: var(--md-sys-typescale-label-lg-tracking); white-space: nowrap; cursor: pointer; - outline: none; - isolation: isolate; } [data-md-datepicker-nav][data-md-docked] [data-md-datepicker-menu-button] { - padding-inline: 0.5rem 0.25rem; - gap: 0.25rem; + padding-inline: var(--md-sys-measurement-space100) var(--md-sys-measurement-space50); + gap: var(--md-sys-measurement-space50); } [data-md-datepicker-menu-arrow] { @@ -331,66 +329,17 @@ rotate: 180deg; } - /* ---- State layers shared by days, years, menu buttons and list rows ------------------------ */ - - [data-md-datepicker-menu-button]::before, - [data-md-datepicker-day] > span::before, - [data-md-datepicker-year]::before, - [data-md-datepicker-option]::before { - content: ''; - position: absolute; - inset: 0; - z-index: -1; - border-radius: inherit; - background-color: var(--datepicker-layer, currentColor); - opacity: 0; - pointer-events: none; - transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); - } - - @media (hover: hover) { - [data-md-datepicker-menu-button]:hover::before, - [data-md-datepicker-day]:not([aria-disabled='true'], [data-md-blank]):hover > span::before, - [data-md-datepicker-year]:hover::before, - [data-md-datepicker-option]:not([aria-disabled='true']):hover::before { - opacity: 0.08; - } - } - - [data-md-datepicker-menu-button]:focus-visible::before, - [data-md-datepicker-menu-button]:active::before, - [data-md-datepicker-day]:focus-visible > span::before, - [data-md-datepicker-day]:not([aria-disabled='true'], [data-md-blank]):active > span::before, - [data-md-datepicker-year]:focus-visible::before, - [data-md-datepicker-year]:active::before, - [data-md-datepicker-option]:focus-visible::before, - [data-md-datepicker-option]:not([aria-disabled='true']):active::before { - opacity: 0.1; - } - - [data-md-datepicker-menu-button]:focus-visible, - [data-md-datepicker-day]:focus-visible > span, - [data-md-datepicker-year]:focus-visible { - outline: 3px solid var(--md-sys-color-secondary); - outline-offset: 2px; - } - - [data-md-datepicker-option]:focus-visible { - outline: 3px solid var(--md-sys-color-secondary); - outline-offset: -3px; - } - /* ---- The days ----------------------------------------------------------------------------- */ [data-md-datepicker-grid] { - width: calc(100% - 1.5rem); - margin-inline: 0.75rem; + width: calc(100% - 24px); + margin-inline: 12px; border-collapse: collapse; table-layout: fixed; } [data-md-datepicker-grid] th { - height: 3rem; + height: 48px; padding: 0; color: var(--md-sys-color-on-surface); font: var(--md-sys-typescale-body-lg); @@ -402,7 +351,7 @@ --datepicker-layer: var(--md-sys-color-on-surface-variant); position: relative; - height: 3rem; + height: 48px; padding: 0; color: var(--md-sys-color-on-surface); font: var(--md-sys-typescale-body-lg); @@ -414,17 +363,56 @@ -webkit-tap-highlight-color: transparent; } + /* The 40px indicator, its own stacking context so the state layer lies over a chosen day's + primary fill rather than under it. */ [data-md-datepicker-day] > span { position: relative; display: grid; place-items: center; - width: 2.5rem; - height: 2.5rem; + width: 40px; + height: 40px; margin: auto; border-radius: var(--md-sys-shape-corner-full); + isolation: isolate; transition: background-color var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); } + /* The day's state layer and focus ring, on the indicator (see the header). */ + [data-md-datepicker-day] > span::before { + content: ''; + position: absolute; + inset: 0; + z-index: -1; + border-radius: inherit; + background-color: var(--datepicker-layer); + opacity: 0; + pointer-events: none; + transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); + } + + @media (hover: hover) { + [data-md-datepicker-day]:hover > span::before { + opacity: var(--md-sys-state-hover-state-layer-opacity); + } + } + + [data-md-datepicker-day]:focus-visible > span::before { + opacity: var(--md-sys-state-focus-state-layer-opacity); + } + + [data-md-datepicker-day]:active > span::before { + opacity: var(--md-sys-state-pressed-state-layer-opacity); + } + + [data-md-datepicker-day]:is([aria-disabled='true'], [data-md-blank]) > span::before { + display: none; + } + + [data-md-datepicker-day]:focus-visible > span { + outline: 3px solid var(--md-sys-color-secondary); + outline-offset: 2px; + } + [data-md-datepicker-day][data-md-blank] { cursor: default; } @@ -450,7 +438,7 @@ [data-md-datepicker-day][data-md-end]::before { content: ''; position: absolute; - inset-block: 0.25rem; + inset-block: var(--md-sys-measurement-space50); inset-inline: 0; z-index: -1; background-color: var(--md-sys-color-secondary-container); @@ -482,12 +470,12 @@ } [data-md-datepicker-day][aria-disabled='true'] { - color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent); + color: color-mix(in srgb, var(--md-sys-color-on-surface) calc(var(--md-sys-state-disabled-content-opacity) * 100%), transparent); cursor: default; } [data-md-datepicker-day][aria-disabled='true'][data-md-today] > span { - box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--md-sys-color-on-surface) calc(var(--md-sys-state-disabled-content-opacity) * 100%), transparent); } /* ---- The modal year grid ----------------------------------------------------------------- */ @@ -497,40 +485,31 @@ grid-template-columns: repeat(3, 1fr); align-content: start; justify-items: center; - row-gap: 1rem; - height: 20.9375rem; - padding: 0.5rem 0.75rem; + row-gap: var(--md-sys-measurement-space200); + height: 335px; + padding: var(--md-sys-measurement-space100) 12px; overflow-y: auto; overscroll-behavior: contain; border-bottom: 1px solid var(--md-sys-color-outline-variant); } [data-md-datepicker-year] { - --datepicker-layer: var(--md-sys-color-on-surface-variant); - - position: relative; - width: 4.5rem; - height: 2.25rem; + width: 72px; + height: 36px; border-radius: var(--md-sys-shape-corner-full); color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-lg); letter-spacing: var(--md-sys-typescale-body-lg-tracking); cursor: pointer; - outline: none; - isolation: isolate; - scroll-margin-block: 0.5rem; + scroll-margin-block: var(--md-sys-measurement-space100); } [data-md-datepicker-year][data-md-current] { - --datepicker-layer: var(--md-sys-color-primary); - color: var(--md-sys-color-primary); box-shadow: inset 0 0 0 1px var(--md-sys-color-primary); } [data-md-datepicker-year][aria-selected='true'] { - --datepicker-layer: var(--md-sys-color-on-primary); - background-color: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary); box-shadow: none; @@ -539,30 +518,30 @@ /* ---- The docked month and year lists ------------------------------------------------------ */ [data-md-datepicker-menu] { - height: 21.5rem; - padding-block: 0.5rem; + height: 344px; + padding-block: var(--md-sys-measurement-space100); overflow-y: auto; overscroll-behavior: contain; border-top: 1px solid var(--md-sys-color-outline-variant); } [data-md-datepicker-option] { - --datepicker-layer: var(--md-sys-color-on-surface); - - position: relative; display: flex; align-items: center; - gap: 1rem; + gap: var(--md-sys-measurement-space200); width: 100%; - height: 3rem; - padding-inline: 1rem; + height: 48px; + padding-inline: var(--md-sys-measurement-space200); color: var(--md-sys-color-on-surface); font: var(--md-sys-typescale-body-lg); letter-spacing: var(--md-sys-typescale-body-lg-tracking); text-align: start; cursor: pointer; - outline: none; - isolation: isolate; + } + + /* The foundation's ring, drawn inside the full-width row rather than round it. */ + [data-md-datepicker-option]:focus-visible { + outline-offset: -3px; } [data-md-datepicker-option][aria-selected='true'] { @@ -570,7 +549,7 @@ } [data-md-datepicker-option][aria-disabled='true'] { - color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent); + color: color-mix(in srgb, var(--md-sys-color-on-surface) calc(var(--md-sys-state-disabled-content-opacity) * 100%), transparent); cursor: default; } @@ -585,29 +564,13 @@ /* ---- The modal input ------------------------------------------------------------------------ */ [data-md-datepicker-entry] { - padding: 0.625rem 1.5rem 1rem; + padding: var(--md-sys-measurement-space125) var(--md-sys-measurement-space300) var(--md-sys-measurement-space200); } [data-md-datepicker-entry-fields][data-md-range] { display: grid; grid-template-columns: 1fr 1fr; - gap: 0.5rem; - } - - /* ---- The month announcement, spoken but not drawn -------------------------------------------- */ - - /* Same clip as the text classes' `md-visually-hidden`, kept as a hook because a package view - writes no class but the interaction classes (plan step 36). */ - [data-md-datepicker-month-live] { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip-path: inset(50%); - white-space: nowrap; - border-width: 0; + gap: var(--md-sys-measurement-space100); } /* ---- Cancel and OK ---------------------------------------------------------------------------- */ @@ -618,7 +581,7 @@ flex-wrap: wrap; align-items: center; justify-content: flex-end; - gap: 0.5rem; - padding: 0.25rem 0.375rem 0.5rem 0.75rem; + gap: var(--md-sys-measurement-space100); + padding: var(--md-sys-measurement-space50) var(--md-sys-measurement-space75) var(--md-sys-measurement-space100) 12px; } } diff --git a/resources/views/components/datepicker.blade.php b/resources/views/components/datepicker.blade.php index b7dfb116..d265953f 100644 --- a/resources/views/components/datepicker.blade.php +++ b/resources/views/components/datepicker.blade.php @@ -5,7 +5,8 @@ - `docked` (the default): a text field that takes a typed date in the locale's numeric format (`13.09.2026` in `de`, `09/13/2026` in `en-US`), with the calendar dropping open under it — on a press of the field, its calendar button, or ArrowDown. On a compact window (below - `sm`) the calendar opens as the modal picker instead, where a docked one would not fit. + 600px, `medium`) the calendar opens as the modal picker instead, where a docked one would not + fit. - `modal`: the field only shows the date; pressing it (or Enter, Space, ArrowDown) opens the calendar in a dialog, with a pencil to switch to typing. - `input`: the same dialog, opened on its text field, with a calendar icon to switch back. @@ -47,7 +48,9 @@ material-web's md-comp-date-picker-docked tokens, v0_192, as Compose has none; all Apache-2.0): surface-container-high at elevation 3, 360px wide, the extra-large corner (modal) or large (docked), 40px days in 48px cells, today outlined in primary, the chosen day in primary and a - range's middle in secondary-container. The styles are resources/css/components/datepicker.css. --}} + range's middle in secondary-container. The styles are resources/css/components/datepicker.css; + the year, the menu buttons and the list options render `md-state-layer md-focus-ring`, the + month's announcement `md-visually-hidden`, and nothing else here writes a class. --}} @props([ 'label' => null, @@ -314,11 +317,12 @@
- +
@@ -439,6 +446,7 @@ x-bind:aria-disabled="month.disabled ? 'true' : null" x-bind:tabindex="month.selected ? 0 : -1" x-on:click="month.disabled || showMonthOf(+shown.slice(0, 4), month.value)" + class="md-state-layer md-focus-ring" data-md-datepicker-option > @@ -455,6 +463,7 @@ x-bind:aria-selected="year.selected.toString()" x-bind:tabindex="year.selected ? 0 : -1" x-on:click="showMonthOf(year.value, +shown.slice(5, 7))" + class="md-state-layer md-focus-ring" data-md-datepicker-option > diff --git a/tests/Browser/DatepickerTest.php b/tests/Browser/DatepickerTest.php index 034f07a6..da1fd93f 100644 --- a/tests/Browser/DatepickerTest.php +++ b/tests/Browser/DatepickerTest.php @@ -181,7 +181,7 @@ it('opens the docked picker under its field and walks the grid from the keyboard $page = dateProbe() ->click('[aria-controls="expires-field-picker"][data-md-datepicker-toggle]') - ->assertScript("{$picker}.matches(':popover-open') && {$picker}.dataset.presentation === 'docked'") + ->assertScript("{$picker}.matches(':popover-open') && {$picker}.dataset.mdPresentation === 'docked'") ->assertAttribute('#expires-field', 'aria-expanded', 'true') ->assertScript("(() => { const field = document.querySelector('#expires-field').closest('[data-md-field-box]').getBoundingClientRect(); const box = {$picker}.getBoundingClientRect(); return Math.abs(box.top - field.bottom - 4) < 2 && Math.abs(box.left - field.left) < 2; })()") ->assertScript(focusedDay('2026-09-13')); @@ -212,8 +212,8 @@ it('keeps focus and choice inside min and max', function () { $page->assertAttribute(day('expires-field', '2026-09-09'), 'aria-disabled', 'true') ->script("document.querySelector('".day('expires-field', '2026-09-09')."').click()"); - $page->assertScript("! document.querySelector('".day('expires-field', '2026-09-09')."').hasAttribute('data-selected')") - ->assertScript("document.querySelector('".day('expires-field', '2026-09-13')."').hasAttribute('data-selected')"); + $page->assertScript("! document.querySelector('".day('expires-field', '2026-09-09')."').hasAttribute('data-md-selected')") + ->assertScript("document.querySelector('".day('expires-field', '2026-09-13')."').hasAttribute('data-md-selected')"); $page->keys(':focus', 'PageUp')->assertScript(focusedDay('2026-09-10')); $page->keys(':focus', 'ArrowLeft')->assertScript(focusedDay('2026-09-10')); @@ -327,12 +327,12 @@ it('picks a range: a start, an end, and the days between', function () { ->assertAttribute(day('trip-field', '2026-09-14'), 'aria-selected', 'true'); $page->click(day('trip-field', '2026-09-20')) - ->assertScript("document.querySelector('".day('trip-field', '2026-09-20')."').hasAttribute('data-selected')") - ->assertScript("! document.querySelector('".day('trip-field', '2026-09-14')."').hasAttribute('data-between')"); + ->assertScript("document.querySelector('".day('trip-field', '2026-09-20')."').hasAttribute('data-md-selected')") + ->assertScript("! document.querySelector('".day('trip-field', '2026-09-14')."').hasAttribute('data-md-between')"); $page->click(day('trip-field', '2026-09-24')) ->assertScript("[...document.querySelectorAll('#trip-field-picker [data-md-between]')].map((cell) => cell.dataset.mdValue).join() === '2026-09-21,2026-09-22,2026-09-23'") - ->assertScript("document.querySelector('".day('trip-field', '2026-09-20')."').hasAttribute('data-start') && document.querySelector('".day('trip-field', '2026-09-24')."').hasAttribute('data-end')") + ->assertScript("document.querySelector('".day('trip-field', '2026-09-20')."').hasAttribute('data-md-start') && document.querySelector('".day('trip-field', '2026-09-24')."').hasAttribute('data-md-end')") ->assertSeeIn('#trip', '2026-09-15'); $page->click('#trip-field-picker [data-md-datepicker-confirm]') diff --git a/tests/Feature/Components/DatepickerTest.php b/tests/Feature/Components/DatepickerTest.php index 226e14f7..ce39c4a0 100644 --- a/tests/Feature/Components/DatepickerTest.php +++ b/tests/Feature/Components/DatepickerTest.php @@ -3,6 +3,7 @@ use Carbon\CarbonImmutable; use Livewire\Component; use Livewire\Livewire; +use NoNameWeb\LivewireMaterial\Tests\Support\ComponentStylesheet; /** * The JSON config handed to `materialDatepicker(…)`, decoded. @@ -97,6 +98,35 @@ it('names each dropdown so Shift+M and Shift+Y can reach it', function () { ->toContain('data-md-datepicker-menu-button="years"'); }); +it('draws the year, the menu buttons and the list options from the interaction classes', function () { + $html = (string) $this->blade(''); + $css = ComponentStylesheet::read('datepicker'); + + expect(preg_match_all('/class="md-state-layer md-focus-ring"\s+data-md-datepicker-menu-button=/', $html))->toBe(3) + ->and(preg_match_all('/class="md-state-layer md-focus-ring"\s+data-md-datepicker-year\b/', $html))->toBe(1) + ->and(preg_match_all('/class="md-state-layer md-focus-ring"\s+data-md-datepicker-option\b/', $html))->toBe(2) + ->and($html)->toContain('') + // Nothing in the stylesheet takes back what the classes draw… + ->and($css->declarations('[data-md-datepicker-menu-button]'))->not->toHaveKeys(['position', 'isolation', 'outline']) + ->and($css->declarations('[data-md-datepicker-year]'))->not->toHaveKeys(['position', 'isolation', 'outline']) + ->and($css->declarations('[data-md-datepicker-option]'))->not->toHaveKeys(['position', 'isolation', 'outline']) + // …but the option's ring, which sits inside its full-width row. + ->and($css->declarations('[data-md-datepicker-option]:focus-visible'))->toBe(['outline-offset' => '-3px']); +}); + +it('draws the day\'s state layer on its indicator at M3\'s state opacities, and none on a disabled day', function () { + $css = ComponentStylesheet::read('datepicker'); + + expect($css->declarations('[data-md-datepicker-day] > span::before'))->toMatchArray(['background-color' => 'var(--datepicker-layer)', 'opacity' => '0', 'z-index' => '-1']) + ->and($css->declarations('[data-md-datepicker-day] > span'))->toMatchArray(['width' => '40px', 'height' => '40px', 'isolation' => 'isolate']) + ->and($css->declarations('[data-md-datepicker-day]:hover > span::before', ['@media (hover: hover)']))->toBe(['opacity' => 'var(--md-sys-state-hover-state-layer-opacity)']) + ->and($css->declarations('[data-md-datepicker-day]:focus-visible > span::before'))->toBe(['opacity' => 'var(--md-sys-state-focus-state-layer-opacity)']) + ->and($css->declarations('[data-md-datepicker-day]:active > span::before'))->toBe(['opacity' => 'var(--md-sys-state-pressed-state-layer-opacity)']) + ->and($css->declarations("[data-md-datepicker-day]:is([aria-disabled='true'], [data-md-blank]) > span::before"))->toBe(['display' => 'none']) + ->and($css->declarations('[data-md-datepicker-day]:focus-visible > span'))->toBe(['outline' => '3px solid var(--md-sys-color-secondary)', 'outline-offset' => '2px']) + ->and($css->declarations('[data-md-datepicker-day]'))->toMatchArray(['height' => '48px']); +}); + it('falls back to the docked picker for an unknown mode', function () { expect(datepickerConfig((string) $this->blade(''))['mode'])->toBe('docked'); });