# Sheet

Extends the dialog to display content that complements the main content of the screen.

- Install: `php artisan blatui:add sheet`
- Source: https://blatui.remix-it.com/r/sheet.json
- Composer: `composer require mallardduck/blade-lucide-icons gehrisandro/tailwind-merge-laravel`
- npm: `npm install -D @alpinejs/focus`

## resources/views/components/ui/sheet.blade.php

```blade
{{--
    Sheet root. Holds the open state.
      open  initial open state
      id    optional — enables "dispatchable" mode: the sheet also opens/closes from
            anywhere via $dispatch('open-sheet-{id}') / $dispatch('close-sheet-{id}').
            Use <x-ui.sheet-trigger for="{id}"> from inside a @foreach/partial.
--}}
@props(['open' => false, 'id' => null])

<div
    data-slot="sheet"
    x-data="{ open: @js((bool) $open) }"
    @if ($id)
        @open-sheet-{{ $id }}.window="open = true"
        @close-sheet-{{ $id }}.window="open = false"
    @endif
    x-id="['blat-sheet']"
    {{ $attributes }}
>
    {{ $slot }}
</div>
```

## resources/views/components/ui/sheet-content.blade.php

```blade
@props([
    'side' => 'right',
    'showClose' => true,
])

@php
    $sideClasses = [
        'right' => 'inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
        'left' => 'inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
        'top' => 'inset-x-0 top-0 h-auto border-b',
        'bottom' => 'inset-x-0 bottom-0 h-auto border-t',
    ];

    $enterStart = [
        'right' => 'translate-x-full',
        'left' => '-translate-x-full',
        'top' => '-translate-y-full',
        'bottom' => 'translate-y-full',
    ];

    $base = 'bg-background fixed z-50 flex flex-col gap-4 shadow-lg';
    $classes = $base.' '.($sideClasses[$side] ?? $sideClasses['right']);
    $start = $enterStart[$side] ?? $enterStart['right'];
@endphp

<template x-teleport="body">
    <div x-show="open" x-cloak class="fixed inset-0 z-50">
        <div
            x-show="open"
            @click="open = false"
            role="presentation"
            aria-hidden="true"
            data-slot="sheet-overlay"
            x-transition:enter="transition ease-out duration-300"
            x-transition:enter-start="opacity-0"
            x-transition:enter-end="opacity-100"
            x-transition:leave="transition ease-in duration-200"
            x-transition:leave-start="opacity-100"
            x-transition:leave-end="opacity-0"
            class="fixed inset-0 z-50 bg-black/50"
        ></div>

        <div
            x-show="open"
            x-trap.noscroll.inert="open"
            @keydown.escape.window="open = false"
            :id="$id('blat-sheet')"
            x-blat-labelledby="{ label: '[data-slot=sheet-title]', description: '[data-slot=sheet-description]' }"
            role="dialog"
            aria-modal="true"
            tabindex="-1"
            data-slot="sheet-content"
            data-side="{{ $side }}"
            x-transition:enter="transition ease-in-out duration-500"
            x-transition:enter-start="{{ $start }}"
            x-transition:enter-end="translate-x-0 translate-y-0"
            x-transition:leave="transition ease-in-out duration-300"
            x-transition:leave-start="translate-x-0 translate-y-0"
            x-transition:leave-end="{{ $start }}"
            {{ $attributes->twMerge($classes) }}
        >
            {{ $slot }}

            @if ($showClose)
                <button
                    type="button"
                    @click="open = false"
                    class="ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none"
                >
                    <x-lucide-x class="size-4" aria-hidden="true" />
                    <span class="sr-only">Close</span>
                </button>
            @endif
        </div>
    </div>
</template>
```

## resources/views/components/ui/sheet-description.blade.php

```blade
<p data-slot="sheet-description" {{ $attributes->twMerge('text-muted-foreground text-sm') }}>{{ $slot }}</p>
```

## resources/views/components/ui/sheet-footer.blade.php

```blade
<div data-slot="sheet-footer" {{ $attributes->twMerge('mt-auto flex flex-col gap-2 p-4') }}>{{ $slot }}</div>
```

## resources/views/components/ui/sheet-header.blade.php

```blade
<div data-slot="sheet-header" {{ $attributes->twMerge('flex flex-col gap-1.5 p-4') }}>{{ $slot }}</div>
```

## resources/views/components/ui/sheet-title.blade.php

```blade
<h2 data-slot="sheet-title" {{ $attributes->twMerge('text-foreground font-semibold') }}>{{ $slot }}</h2>
```

## resources/views/components/ui/sheet-trigger.blade.php

```blade
{{-- for: when set, opens a dispatchable sheet defined elsewhere via
     $dispatch('open-sheet-{for}'). Otherwise opens the sheet in the same scope. --}}
@props(['for' => null])

<span
    @if ($for)
        x-data
        @click="$dispatch('open-sheet-{{ $for }}')"
        aria-haspopup="dialog"
    @else
        @click="open = true"
        x-blat-trigger="{ haspopup: 'dialog', controls: $id('blat-sheet') }"
    @endif
    data-slot="sheet-trigger"
    {{ $attributes->twMerge('inline-block') }}
>
    {{ $slot }}
</span>
```
