



<Preview className="min-h-[560px]">
  <FilesDetailsPanelConsumerExample />
</Preview>

This example keeps `Files.Details` focused on metadata display and inline rename
mechanics. The consumer owns the file collection, selected IDs, rename mutation,
product-specific metadata, and the surrounding split layout.

```tsx title="components/files-details-panel/index.tsx"
import { useMemo, useState } from "react";
import {
  Files,
  type FilesItem,
} from "@tilt-legal/cubitt-components/files";
import { Separator } from "@tilt-legal/cubitt-components/separator";
import { toast } from "@tilt-legal/cubitt-components/toast";
import { formatPlural } from "@tilt-legal/cubitt-components/utilities/formatters";
import { MatterFileDetailsPanel } from "@/components/files-details-panel/details-sidebar";
import {
  matterFiles,
  type MatterFileSource,
} from "@/components/files-details-panel/data";

function sleep(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

export function FilesDetailsPanel() {
  const [items, setItems] = useState(matterFiles);
  const [selectedIds, setSelectedIds] = useState<string[]>([
    "financial-report",
  ]);

  const selectedItems = useMemo(
    () =>
      selectedIds
        .map((id) => items.find((item) => item.id === id))
        .filter((item): item is FilesItem<MatterFileSource> => Boolean(item)),
    [items, selectedIds],
  );
  const currentDetailsItem = useMemo<FilesItem<MatterFileSource>>(
    () => ({
      id: "current-files",
      kind: "folder",
      name: "Files",
      description: formatPlural(items.length, "item"),
      source: {
        matter: "Bennett v Carter",
        owner: "Matter team",
        status: "Reviewed",
        updatedLabel: "Today",
      },
    }),
    [items.length],
  );
  const detailsItems =
    selectedItems.length > 0 ? selectedItems : [currentDetailsItem];

  async function renameItem(item: FilesItem<MatterFileSource>, name: string) {
    await sleep(300);
    setItems((currentItems) =>
      currentItems.map((currentItem) =>
        currentItem.id === item.id ? { ...currentItem, name } : currentItem,
      ),
    );
    toast.success("File renamed", { description: name });
  }

  return (
    <Files
      className="h-[420px] w-full max-w-4xl flex-row gap-6"
      canRename={(item) => item.id !== currentDetailsItem.id}
      detailsItem={currentDetailsItem}
      items={items}
      onRename={renameItem}
      onSelectedIdsChange={setSelectedIds}
      selectedIds={selectedIds}
      selectionMode="multiple"
    >
      <Files.Content className="overflow-auto">
        <Files.List>
          {items.map((item) => (
            <Files.Item item={item} key={item.id} />
          ))}
        </Files.List>
      </Files.Content>
      <Separator orientation="vertical" />
      <MatterFileDetailsPanel
        className="min-h-0 min-w-[400px] basis-[400px] shrink-0"
        selectedItems={detailsItems}
      />
    </Files>
  );
}
```

```tsx title="components/files-details-panel/details-sidebar.tsx"
import {
  Files,
  type FilesItem,
} from "@tilt-legal/cubitt-components/files";
import { Separator } from "@tilt-legal/cubitt-components/separator";
import {
  formatBytes,
  formatPlural,
} from "@tilt-legal/cubitt-components/utilities/formatters";
import type { MatterFileSource } from "@/components/files-details-panel/data";

type Props = {
  className?: string;
  selectedItems: FilesItem<MatterFileSource>[];
};

export function MatterFileDetailsPanel({
  className,
  selectedItems,
}: Props) {
  const singleItem = selectedItems.length === 1 ? selectedItems[0] : null;
  const matterCount = new Set(
    selectedItems.map((item) => item.source?.matter).filter(Boolean),
  ).size;
  const ownerCount = new Set(
    selectedItems.map((item) => item.source?.owner).filter(Boolean),
  ).size;
  const selectedTotalSizeLabel = selectedItems.every(
    (item) => typeof item.size === "number",
  )
    ? formatBytes(
        selectedItems.reduce(
          (totalSize, item) => totalSize + (item.size ?? 0),
          0,
        ),
      )
    : null;

  return (
    <Files.Details className={className}>
      <Files.Details.Icon />
      <Files.Details.Header>
        <Files.Details.Heading>
          <Files.Details.Name />
          <Files.Details.Type />
        </Files.Details.Heading>
        <Files.Details.EditNameButton />
      </Files.Details.Header>
      <Files.Details.Panels>
        <Files.Details.Panel label="Details" value="details">
          <Separator />
          <Files.Details.Properties>
            {singleItem?.source?.matter ? (
              <Files.Details.Property>
                <Files.Details.Property.Label>
                  Matter
                </Files.Details.Property.Label>
                <Files.Details.Property.Value>
                  {singleItem.source.matter}
                </Files.Details.Property.Value>
              </Files.Details.Property>
            ) : null}
            {singleItem?.source?.owner ? (
              <Files.Details.Property>
                <Files.Details.Property.Label>
                  Owner
                </Files.Details.Property.Label>
                <Files.Details.Property.Value>
                  {singleItem.source.owner}
                </Files.Details.Property.Value>
              </Files.Details.Property>
            ) : null}
            {singleItem?.source?.status ? (
              <Files.Details.Property>
                <Files.Details.Property.Label>
                  Status
                </Files.Details.Property.Label>
                <Files.Details.Property.Value>
                  {singleItem.source.status}
                </Files.Details.Property.Value>
              </Files.Details.Property>
            ) : null}
            {singleItem?.source?.updatedLabel ? (
              <Files.Details.Property>
                <Files.Details.Property.Label>
                  Updated
                </Files.Details.Property.Label>
                <Files.Details.Property.Value>
                  {singleItem.source.updatedLabel}
                </Files.Details.Property.Value>
              </Files.Details.Property>
            ) : null}
            {singleItem?.sizeLabel ? (
              <Files.Details.Property>
                <Files.Details.Property.Label>
                  Size
                </Files.Details.Property.Label>
                <Files.Details.Property.Value>
                  {singleItem.sizeLabel}
                </Files.Details.Property.Value>
              </Files.Details.Property>
            ) : null}
            {selectedItems.length > 1 ? (
              <Files.Details.Property>
                <Files.Details.Property.Label>
                  Files selected
                </Files.Details.Property.Label>
                <Files.Details.Property.Value>
                  {selectedItems.length}
                </Files.Details.Property.Value>
              </Files.Details.Property>
            ) : null}
            {selectedItems.length > 1 && selectedTotalSizeLabel ? (
              <Files.Details.Property>
                <Files.Details.Property.Label>
                  Total size
                </Files.Details.Property.Label>
                <Files.Details.Property.Value>
                  {selectedTotalSizeLabel}
                </Files.Details.Property.Value>
              </Files.Details.Property>
            ) : null}
            {selectedItems.length > 1 ? (
              <Files.Details.Property>
                <Files.Details.Property.Label>
                  Matters
                </Files.Details.Property.Label>
                <Files.Details.Property.Value>
                  {formatPlural(matterCount, "matter")}
                </Files.Details.Property.Value>
              </Files.Details.Property>
            ) : null}
            {selectedItems.length > 1 ? (
              <Files.Details.Property>
                <Files.Details.Property.Label>
                  Owners
                </Files.Details.Property.Label>
                <Files.Details.Property.Value>
                  {formatPlural(ownerCount, "owner")}
                </Files.Details.Property.Value>
              </Files.Details.Property>
            ) : null}
          </Files.Details.Properties>
        </Files.Details.Panel>
      </Files.Details.Panels>
    </Files.Details>
  );
}
```

```typescript title="components/files-details-panel/data.ts"
import type { FilesItem } from "@tilt-legal/cubitt-components/files";

export type MatterFileSource = {
  matter: string;
  owner: string;
  status: "Draft" | "Reviewed" | "Filed";
  updatedLabel: string;
};

export const matterFiles: FilesItem<MatterFileSource>[] = [
  {
    id: "financial-report",
    kind: "file",
    name: "Q4FinancialReportBennettVCarterLitigationBudgetAndSettlementExposureAnalysisFinalReviewedCopy.pdf",
    mediaType: "application/pdf",
    size: 2_458_624,
    sizeLabel: "2.4 MB",
    description: "Sarah Chen",
    source: {
      matter: "Bennett v Carter",
      owner: "Sarah Chen",
      status: "Reviewed",
      updatedLabel: "2 days ago",
    },
  },
  {
    id: "deposition-outline",
    kind: "file",
    name: "Deposition Outline.docx",
    mediaType:
      "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    size: 884_736,
    sizeLabel: "864 KB",
    description: "Ava Johnson",
    source: {
      matter: "Hudson Contract Review",
      owner: "Ava Johnson",
      status: "Draft",
      updatedLabel: "Apr 18",
    },
  },
  {
    id: "folder-discovery",
    kind: "folder",
    name: "Discovery",
    description: "12 items",
    source: {
      matter: "Bennett v Carter",
      owner: "Sarah Chen",
      status: "Draft",
      updatedLabel: "Today",
    },
  },
];
```
