Skip to content
Components

Item grid

A backpack you can drive from the keyboard: footprints, stacks, a drop ghost that says why not, and equipment slots.

TS
import { โ€ฆ } from "@fungi.computer/caps/components/item-grid";

Backpack

TSX
import {
ItemGrid,
type ItemGridItem,
} from "@fungi.computer/caps/components/item-grid";
const items: ItemGridItem[] = [
{ id: "axe", label: "Axe", x: 0, y: 0, h: 2, icon: "๐Ÿช“" },
{ id: "log", label: "Oak log", x: 1, y: 0, quantity: 3, icon: "๐Ÿชต" },
{ id: "bread", label: "Bread", x: 2, y: 0, quantity: 2, icon: "๐Ÿž" },
{ id: "spores", label: "Spore syringe", x: 1, y: 1, icon: "๐Ÿงช" },
];
export default function Backpack() {
return <ItemGrid label="Backpack" columns={4} rows={2} items={items} />;
}

Equipment slots

TSX
import { ItemSlot } from "@fungi.computer/caps/components/item-grid";
export default function EquipmentSlots() {
return (
<div className="flex flex-wrap gap-2">
<ItemSlot label="Head" item={{ label: "Straw hat", icon: "๐Ÿ‘’" }} />
<ItemSlot label="Main hand" item={{ label: "Axe", icon: "๐Ÿช“" }} />
<ItemSlot label="Pack" state="legal" placeholder="๐Ÿ“ฆ" />
<ItemSlot label="Belt" state="illegal" />
<ItemSlot label="Feet" disabled />
</div>
);
}

Drop ghost

TSX
import {
ItemGrid,
type ItemGridItem,
} from "@fungi.computer/caps/components/item-grid";
import { useState } from "react";
const items: ItemGridItem[] = [
{ id: "log", label: "Oak log", x: 0, y: 0, h: 2, icon: "๐Ÿชต" },
];
export default function DropGhost() {
const [message, setMessage] = useState("Hover a cell to preview a drop.");
return (
<div className="flex flex-col gap-2">
<ItemGrid
label="Shelf"
columns={4}
rows={2}
items={items}
onCellHover={(cell) => {
if (!cell) return;
setMessage(
cell.item
? `${cell.item.label} is here already.`
: "That cell is free.",
);
}}
/>
<p role="status">{message}</p>
</div>
);
}

Props

ItemGridProps

PropTypeDescription
labelstringAccessible name of the container, e.g. "Backpack".
columnsnumber
rowsnumber
itemsreadonly ItemGridItem[]
ghost?ItemGridGhost | null
cellSize?"sm" | "md" | "lg"
activeCell?objectControlled keyboard cursor. Omit to let the grid keep its own.
activeCell.xnumber
activeCell.ynumber
onActiveCellChange()?(cell) => voidThe keyboard cursor moved to another cell.
onCellActivate()?(cell) => voidClick, Enter or Space on a cell. The host decides pick up, drop or use.
onCellHover()?(cell) => voidPointer over a cell, or null on leaving the grid; for drag ghosts.
  • labelstring

    Accessible name of the container, e.g. "Backpack".

  • columnsnumber
  • rowsnumber
  • itemsreadonly ItemGridItem[]
  • ghost?ItemGridGhost | null
  • cellSize?"sm" | "md" | "lg"
  • activeCell?object

    Controlled keyboard cursor. Omit to let the grid keep its own.

  • activeCell.xnumber
  • activeCell.ynumber
  • onActiveCellChange()?(cell) => void

    The keyboard cursor moved to another cell.

  • onCellActivate()?(cell) => void

    Click, Enter or Space on a cell. The host decides pick up, drop or use.

  • onCellHover()?(cell) => void

    Pointer over a cell, or null on leaving the grid; for drag ghosts.

ItemSlotProps

PropTypeDescription
labelstringSlot name, e.g. "Head" or "Main hand".
item?{ label: string; icon?: ReactNode; } | nullThe equipped item, if any.
placeholder?ReactNodeFaint outline art shown while the slot is empty.
state?"idle" | "legal" | "illegal"
  • labelstring

    Slot name, e.g. "Head" or "Main hand".

  • item?{ label: string; icon?: ReactNode; } | null

    The equipped item, if any.

  • placeholder?ReactNode

    Faint outline art shown while the slot is empty.

  • state?"idle" | "legal" | "illegal"

Full types: API reference.