Reticle@etched/reticle 0.0.0

Dropdown

Holds the open state. Contains a DropdownMenuTrigger and a DropdownMenuContent.

Kumo source
import { CaretDownIcon, CopyIcon, PencilSimpleIcon, TrashIcon } from "@phosphor-icons/react";
import { Button } from "@etched/reticle/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@etched/reticle/dropdown";

export function Preview() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger
        render={
          <Button>
            Actions
            <CaretDownIcon />
          </Button>
        }
      />
      <DropdownMenuContent align="start">
        <DropdownMenuItem icon={<PencilSimpleIcon />}>Edit</DropdownMenuItem>
        <DropdownMenuItem icon={<CopyIcon />}>Copy ID</DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem icon={<TrashIcon />} variant="danger">
          Delete
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Installation

import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuLinkItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "@etched/reticle/dropdown";

Examples

Row actions

Run 1,284. Last action: none
import { ArrowBendUpRightIcon, ArrowSquareOutIcon, CopyIcon, DotsThreeIcon, PencilSimpleIcon, TrashIcon } from "@phosphor-icons/react";
import { useState } from "react";
import { Button } from "@etched/reticle/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLinkItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "@etched/reticle/dropdown";

export function RowActions() {
  const [last, setLast] = useState("none");

  return (
    <div className="row">
      <span>Run 1,284. Last action: {last}</span>
      <DropdownMenu>
        <DropdownMenuTrigger
          render={<Button shape="square" variant="ghost" aria-label="Actions for run 1,284" icon={<DotsThreeIcon />} />}
        />
        <DropdownMenuContent align="end">
          <DropdownMenuItem icon={<PencilSimpleIcon />} onClick={() => setLast("Edit")}>
            Edit
            <DropdownMenuShortcut>E</DropdownMenuShortcut>
          </DropdownMenuItem>
          <DropdownMenuItem icon={<CopyIcon />} onClick={() => setLast("Copy ID")}>
            Copy ID
            <DropdownMenuShortcut>⌘C</DropdownMenuShortcut>
          </DropdownMenuItem>
          <DropdownMenuLinkItem icon={<ArrowSquareOutIcon />} href="#dropdown" target="_blank">
            Open in new tab
          </DropdownMenuLinkItem>
          <DropdownMenuSub>
            <DropdownMenuSubTrigger icon={<ArrowBendUpRightIcon />}>Move to bench</DropdownMenuSubTrigger>
            <DropdownMenuSubContent>
              <DropdownMenuItem disabled>A-03 (current)</DropdownMenuItem>
              <DropdownMenuItem onClick={() => setLast("Move to B-14")}>B-14</DropdownMenuItem>
              <DropdownMenuItem onClick={() => setLast("Move to B-15")}>B-15</DropdownMenuItem>
            </DropdownMenuSubContent>
          </DropdownMenuSub>
          <DropdownMenuItem disabled onClick={() => setLast("Retry")}>
            Retry
          </DropdownMenuItem>
          <DropdownMenuSeparator />
          <DropdownMenuItem icon={<TrashIcon />} variant="danger" onClick={() => setLast("Delete")}>
            Delete
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>
    </div>
  );
}

Checkbox and radio items

The menu stays open while you check items.

import { SlidersHorizontalIcon } from "@phosphor-icons/react";
import { useState } from "react";
import { Button } from "@etched/reticle/button";
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@etched/reticle/dropdown";

const columns = { owner: "Owner", site: "Site", started: "Started" };

type Column = keyof typeof columns;

// SAFETY: columns is a literal object, so its keys are Column.
const columnKeys = Object.keys(columns) as Column[];

export function CheckboxAndRadioItems() {
  const [shown, setShown] = useState<Record<Column, boolean>>({ owner: true, site: true, started: false });
  const [sort, setSort] = useState("newest");

  return (
    <div className="row">
      <DropdownMenu>
        <DropdownMenuTrigger render={<Button icon={<SlidersHorizontalIcon />}>View</Button>} />
        <DropdownMenuContent align="start">
          <DropdownMenuGroup>
            <DropdownMenuLabel>Columns</DropdownMenuLabel>
            {columnKeys.map((key) => (
              <DropdownMenuCheckboxItem
                key={key}
                checked={shown[key]}
                onCheckedChange={(checked) => setShown({ ...shown, [key]: checked })}
              >
                {columns[key]}
              </DropdownMenuCheckboxItem>
            ))}
          </DropdownMenuGroup>
          <DropdownMenuSeparator />
          <DropdownMenuRadioGroup value={sort} onValueChange={setSort}>
            <DropdownMenuLabel>Sort by</DropdownMenuLabel>
            <DropdownMenuRadioItem value="newest">Newest first</DropdownMenuRadioItem>
            <DropdownMenuRadioItem value="oldest">Oldest first</DropdownMenuRadioItem>
            <DropdownMenuRadioItem value="status">Status</DropdownMenuRadioItem>
          </DropdownMenuRadioGroup>
        </DropdownMenuContent>
      </DropdownMenu>
    </div>
  );
}

API reference