# Sheet

Edge-anchored overlay surface that extends Dialog into a side panel. The Sheet slides in from the top, right, bottom, or left edge of the viewport and is backed by CDK Overlay plus FocusTrap.

## Import

```ts
import {
  SheetCloseDirective,
  SheetComponent,
  SheetContentComponent,
  SheetDescriptionComponent,
  SheetFooterComponent,
  SheetHeaderComponent,
  SheetTitleComponent,
} from '@edsis/component/sheet';
```

## Composition

```text
button[Button] (external trigger; sets the open signal)
Sheet
├── built-in close button (optional)
├── SheetHeader
│   ├── SheetTitle
│   └── SheetDescription
├── SheetContent (optional body / scroll region)
└── SheetFooter
    └── button[SheetClose] (optional custom close action)
```

The Angular surface intentionally keeps the trigger outside the overlay component. Instead of a JSX-style `SheetTrigger`, you open the sheet by setting the bound `open` signal from a regular button or link.

## Basic Usage

```ts
import { signal } from '@angular/core';
```

```html
<button type="button" Button variant="outline" (click)="open.set(true)">Edit profile</button>

<Sheet
  [(open)]="open"
  aria-labelledby="sheet-title"
  aria-describedby="sheet-description"
  class="sm:max-w-md"
>
  <SheetHeader>
    <SheetTitle id="sheet-title">Edit profile</SheetTitle>
    <SheetDescription id="sheet-description">
      Make changes to your profile here. Click save when you are done.
    </SheetDescription>
  </SheetHeader>

  <SheetContent class="grid gap-4 py-4">
    <div class="grid gap-2">
      <label Label for="sheet-name">Name</label>
      <input Input id="sheet-name" value="Pedro Duarte" />
    </div>
    <div class="grid gap-2">
      <label Label for="sheet-username">Username</label>
      <input Input id="sheet-username" value="@peduarte" />
    </div>
  </SheetContent>

  <SheetFooter>
    <button type="button" Button variant="outline" SheetClose>Cancel</button>
    <button type="button" Button (click)="open.set(false)">Save changes</button>
  </SheetFooter>
</Sheet>
```

## Common Patterns

### Side selection

Use `side` to choose where the surface enters from. Right is the default for `Sheet`, while the `Drawer` alias defaults to bottom.

```html
<button type="button" Button variant="outline" (click)="rightOpen.set(true)">Right</button>
<button type="button" Button variant="outline" (click)="leftOpen.set(true)">Left</button>

<Sheet [(open)]="rightOpen" side="right" class="sm:max-w-md">...</Sheet>
<Sheet [(open)]="leftOpen" side="left" class="sm:max-w-md">...</Sheet>
```

For `top` and `bottom`, add a height constraint such as `class="max-h-[55vh]"` when the body content can grow on shorter screens.

### No close button

Hide the default corner close affordance with `[showCloseButton]="false"` and own dismissal explicitly through the footer or body.

```html
<Sheet [(open)]="noCloseOpen" [showCloseButton]="false" class="sm:max-w-sm">
  <SheetHeader>
    <SheetTitle>No Close Button</SheetTitle>
    <SheetDescription>
      Hide the top-right control when dismissal should stay in the footer.
    </SheetDescription>
  </SheetHeader>

  <SheetFooter class="sm:justify-start">
    <button type="button" Button variant="outline" SheetClose>Close</button>
  </SheetFooter>
</Sheet>
```

### RTL

Because the overlay surface renders through CDK Overlay, set `dir="rtl"` on projected content inside the sheet when the direction should be scoped to the open panel.

```html
<Sheet [(open)]="rtlOpen" [showCloseButton]="false" side="left" class="sm:max-w-md">
  <div dir="rtl" lang="ar" class="flex flex-1 flex-col gap-4 text-right">
    <SheetHeader>
      <SheetTitle>تعديل الملف الشخصي</SheetTitle>
      <SheetDescription>قم بإجراء تغييرات على ملفك الشخصي هنا ثم احفظها.</SheetDescription>
    </SheetHeader>

    <SheetContent class="grid gap-4 py-4">
      <div class="grid gap-2">
        <label Label for="sheet-rtl-name">الاسم</label>
        <input Input id="sheet-rtl-name" value="بيدرو دوارتي" />
      </div>
    </SheetContent>

    <SheetFooter class="sm:justify-start">
      <button type="button" Button variant="outline" SheetClose>إغلاق</button>
      <button type="button" Button (click)="rtlOpen.set(false)">حفظ التغييرات</button>
    </SheetFooter>
  </div>
</Sheet>
```

## API Reference

| Input | Type | Default |
| ---------------------- | --------------- | ---------- | ----------- | ------- | ---------------------------------------------- |
| `open` | `boolean` model | `false` |
| `side` | `'top' \\       | 'right' \\ | 'bottom' \\ | 'left'` | `'right'` for `Sheet`, `'bottom'` for `Drawer` |
| `closeOnEscape` | `boolean` | `true` |
| `closeOnBackdropClick` | `boolean` | `true` |
| `showCloseButton` | `boolean` | `true` |
| `closeButtonLabel` | `string` | `'Close'` |
| `aria-labelledby` | `string \\      | null` | `null` |
| `aria-describedby` | `string \\      | null` | `null` |
| `class` | `string` | `''` |

| Part                 | Purpose                                                        |
| -------------------- | -------------------------------------------------------------- |
| `SheetHeader`        | Title and supporting description wrapper                       |
| `SheetTitle`         | Visible, accessible sheet title                                |
| `SheetDescription`   | Supporting copy that can be referenced from `aria-describedby` |
| `SheetContent`       | Optional body wrapper for forms, spacing, and scroll regions   |
| `SheetFooter`        | Action row for primary and secondary controls                  |
| `button[SheetClose]` | Angular-friendly equivalent of shadcn `SheetClose`             |

## Styling And Theming

- The surface uses theme border tokens such as `border-border` on its edge divider so it stays aligned with the current theme.
- Left and right sheets default to `w-3/4 sm:max-w-sm`; add width utilities through the `class` input when a broader side panel is needed.
- Top and bottom sheets stretch across the viewport edge. Use `max-h-*` or spacing utilities on the root `class` input when the body can grow.
- `SheetContent` is the best place for internal scroll handling. Keep footer actions outside that overflow region when they must stay visible.
- Entry animation comes from `--sheet-from` and automatically collapses to zero duration under `prefers-reduced-motion`.

## Accessibility

- The surface renders with `role="dialog"` and `aria-modal="true"`.
- Focus is trapped with `FocusTrap` and restored to the previously focused element on close.
- `Escape` and backdrop click close the sheet by default and can be disabled independently.
- Use stable IDs for the visible title and description when the sheet contains forms or longer instructional copy.

## Keyboard Interactions

- `Tab` and `Shift+Tab` move focus within the trapped overlay.
- `Escape` closes the sheet unless `closeOnEscape` is disabled.
- `Enter` and `Space` activate the trigger, footer actions, and custom `SheetClose` controls through native button behavior.

## Angular Notes

- `Sheet` combines the upstream `Sheet` root and `SheetContent` overlay surface into a single Angular component.
- `SheetContent` remains available as an internal body wrapper for layout, padding, and scroll regions.
- `Drawer` is exported as a bottom-first alias over the same primitive when the interaction reads more naturally as a drawer.
- `button[SheetClose]` and `a[SheetClose]` are the Angular-friendly equivalents of shadcn `SheetClose` for internal dismissal actions.

## Source Parity

The local Sheet follows the shadcn component information architecture and behavior, but translates trigger ownership to an external signal instead of a `SheetTrigger` child component. Lower-level dialog semantics and API expectations still map closely to the Radix Dialog reference at https://www.radix-ui.com/primitives/docs/components/dialog#api-reference.
