Only a subtitle<\/p>/');
});
it('pins a dialog\'s headline and actions and scrolls only the body between them', function () {
$html = (string) $this->blade('Body');
expect($html)
->toContain('overflow-hidden rounded-corner-xl bg-surface-container-high shadow-elevation-3')
->not->toContain('overflow-y-auto rounded-corner-xl')
->toContain('
')
->toMatch('/
/')
->toContain('flex shrink-0 flex-wrap items-center justify-end gap-2 px-6 pt-6 pb-6')
->and(substr_count($html, 'role="separator"'))->toBe(2);
});
it('is an alert dialog when it interrupts, and describes itself by its subtitle', function () {
$alert = (string) $this->blade('This cannot be undone.');
preg_match('/id="(material-dialog-[a-z0-9]+)"/', $alert, $id);
expect($alert)
->toContain('role="alertdialog"')
->toContain("aria-describedby=\"{$id[1]}-subtitle {$id[1]}-body\"")
->and((string) $this->blade('Body'))
->not->toContain('role="alertdialog"')
->toMatch('/aria-describedby="material-dialog-[a-z0-9]+-subtitle"/')
->and((string) $this->blade('Body'))
->not->toContain('aria-describedby');
});
it('gives a full-screen dialog M3\'s 56px header and action bar', function () {
expect((string) $this->blade('Body'))
->toContain('flex h-14 shrink-0 items-center gap-1 px-1 medium:hidden')
->toContain('max-medium:min-h-14 max-medium:border-t max-medium:border-outline-variant max-medium:pt-2 max-medium:pb-2');
});
it('leaves a pane open on Escape unless it is asked to close then too', function () {
expect((string) $this->blade('Body'))
->toContain('x-on:keydown.window.escape="if (open && ! wide) close()"')
->and((string) $this->blade('Body'))
->toContain('x-on:keydown.window.escape="if (open) close()"')
->and((string) $this->blade('Body'))
->not->toContain('keydown.window.escape');
});
it('always offers a way out of a side sheet, as M3 requires', function () {
expect((string) $this->blade('Body'))->toContain('aria-label="Close"')
->and((string) $this->blade('Body'))->not->toContain('aria-label="Close"')
->and((string) $this->blade('Body'))->toContain('aria-label="Close"')
->and((string) $this->blade('Body'))->toContain('aria-label="Close"')
->and((string) $this->blade('Body'))->toContain('aria-label="Close"')
->and((string) $this->blade('Body'))->not->toContain('aria-label="Close"');
});
it('puts a side sheet\'s actions on the left, in M3\'s 72dp row', function () {
expect((string) $this->blade('Body'))
->toContain('flex min-h-18 shrink-0 flex-wrap items-center justify-start gap-2 pt-4');
});
it('slides a side sheet in from either edge, and is a pane from expanded when asked', function () {
expect((string) $this->blade('Body'))
->toContain('x-trap.inert.noscroll="open && ! wide"')
->toContain('end-0 medium:rounded-s-corner-lg')
->toContain('bg-surface-container-low')
->toContain('role="dialog"')
->toContain('aria-label="Close"')
->and((string) $this->blade('Body'))->toContain('start-0 medium:rounded-e-corner-lg')
->and((string) $this->blade('Body'))
->toContain('data-pane')
->toContain('--pane-width: 28rem')
->toContain("matchMedia('(width >= 52.5rem)')");
});
it('draws a modal bottom sheet with a drag handle, or a standard one without a scrim', function () {
expect((string) $this->blade('Body'))
->toContain('...materialBottomSheet(false)')
->toContain('bg-scrim/32')
->toContain('x-trap.inert.noscroll="open"')
->toContain('rounded-t-corner-xl bg-surface-container-low')
->toContain('data-drag-handle')
->toContain('aria-modal="true"')
->toContain('py-5.5')
->toContain('touch-target h-1 w-8 rounded-corner-full bg-on-surface-variant ')
->toContain('--sheet-max-height: min(50dvh, calc(100dvh - 72px))')
->and((string) $this->blade('Body'))
->toContain('...materialBottomSheet(true)')
->not->toContain('bg-scrim/32')
->not->toContain('aria-modal')
->and((string) $this->blade('Body'))
->toContain('--sheet-max-height: min(90dvh, calc(100dvh - 72px))');
});