// Guide: /docs/creating-components · adapter internals: /docs/zag-adapter
// Authoring rules: notes/component-authoring.md (v2 pattern)
import * as dialogMachine from "@zag-js/dialog";
import type { MachineInput } from "marko-zag";
import Button from "../button/button.marko";
import Icon from "../icon/icon.marko";
import { cn } from "#lib/utils.ts";
import { stripOwnProps } from "#lib/native-attrs.ts";
import { sheet as styles } from "./classes.ts";

// `Own` members SHADOW native attributes of the same name (folded into
// MachineInput's Props argument) instead of intersecting with them: `title`
// on a div is `string | false | null`, so a plain `&` would turn our
// attr-tag `title` into an unsatisfiable type.
export type Own = {
  openChange?: (open: boolean) => void;
  trigger?: Marko.AttrTag<{ content: Marko.Body<[Record<string, unknown>]> }>;
  title?: Marko.AttrTag<{ content: Marko.Body }>;
  description?: Marko.AttrTag<{ content: Marko.Body }>;
  content?: Marko.Body;
  footer?: Marko.AttrTag<{ content: Marko.Body }>;
  /** `"top" | "right" | "bottom" | "left"` — which edge the sheet slides in from. */
  side?: "top" | "right" | "bottom" | "left";
  /** Show the top-right close button. Defaults to true. */
  showCloseButton?: boolean;
};

export type Input = MachineInput<"div", dialogMachine.Props & Own>;

<zag/api=() => dialogMachine from=input
  role="dialog"
/>

<const/nativeAttrs=() =>
  stripOwnProps(
    dialogMachine.splitProps(input)[1],
    "class",
    "openChange",
    "trigger",
    "title",
    "description",
    "content",
    "footer",
    "side",
    "showCloseButton",
  )
>
<const/side=input.side ?? "right"/>
<const/showCloseButton=input.showCloseButton ?? true/>

<div ...nativeAttrs() data-slot="sheet">
  <if=input.trigger>
    <${input.trigger.content}({ ...api().getTriggerProps(), "data-slot": "sheet-trigger" })/>
  </if>
  // NOTE: upstream shadcn sets data-slot="sheet-portal" on Radix's Portal,
  // which renders a real element. marko-zag's <zag-portal> renders a
  // `display:contents` host and does not forward attributes, so the
  // marker never reached the DOM — it was inert, and nothing in this
  // repo's CSS, tests or tooling reads it. Dropped rather than left as
  // dead markup; restore it if <zag-portal> gains attribute forwarding.
  <zag-portal>
    <if=api().open>
      <div
        ...api().getBackdropProps()
        data-slot="sheet-overlay"
        class=styles.overlay
      />
      <div ...api().getPositionerProps() data-slot="sheet-positioner" class=styles.positioner>
        <div
          ...api().getContentProps()
          data-slot="sheet-content"
          data-side=side
          class=cn(styles.content, input.class)
        >
          <if=input.title || input.description>
            <div data-slot="sheet-header" class=styles.header>
              <if=input.title>
                <h2 ...api().getTitleProps() data-slot="sheet-title" class=styles.title>
                  <${input.title.content}/>
                </h2>
              </if>
              <if=input.description>
                <p ...api().getDescriptionProps() data-slot="sheet-description" class=styles.description>
                  <${input.description.content}/>
                </p>
              </if>
            </div>
          </if>
          <${input.content}/>
          <if=input.footer>
            <div data-slot="sheet-footer" class=styles.footer>
              <${input.footer.content}/>
            </div>
          </if>
          <if=showCloseButton>
            <Button type="button"
              ...api().getCloseTriggerProps()
              variant="ghost"
              size="icon-sm"
              data-slot="sheet-close"
              class=styles.close
            >
              <Icon name="XIcon"/>
              <span class=styles.srOnly>Close</span>
            </Button>
          </if>
        </div>
      </div>
    </if>
  </zag-portal>
</div>

<return=api>
