import { ChevronLeftIcon } from "lucide-react"; import { lazy, useState, type ComponentProps, type ComponentType, type ReactNode } from "react"; import { MENU_BACK_BUTTON_CLASS, MENU_BACK_HEADER_CLASS, MENU_SURFACE_CLASS } from "./menu-styles"; import { cn } from "../lib/cn"; /** * One shell for the composer "+" menu and its drill-ins, regardless of the * kind of resource: the app's one menu surface at a fixed width. */ export const COMPOSER_MENU_PANEL_CLASS = cn( "flex w-[min(24rem,calc(100vw-1.5rem))] max-h-[min(32rem,var(--radix-dropdown-menu-content-available-height))] flex-col overflow-hidden", MENU_SURFACE_CLASS, ); /** The back control of every drill-in header. */ export function MenuBackButton({ label = "Back", className, ...props }: Omit, "children"> & { label?: string }) { return ( ); } /** A drill-in's header: back, the submenu's title, optional trailing control. */ export function ComposerMenuHeader(props: { title: string; leading?: ReactNode | undefined; trailing?: ReactNode | undefined; }) { return (
{props.leading} {/* A menu may only contain menu items: the title stays visual text there. */}

{props.title}

{props.trailing}
); } /** Visual-only form for a row that already owns the accessible toggle action. */ export function ComposerMenuSwitchIndicator({ checked }: { checked: boolean }) { return ( ); } export function ComposerMenuSwitch(props: { checked: boolean; onCheckedChange: (checked: boolean) => void; label: string; disabled?: boolean | undefined; locked?: boolean | undefined; className?: string | undefined; }) { return ( ); } /** * Rows still loading inside a composer menu: the same height as the rows they * stand for, so the menu opens at its final size and nothing jumps when they * arrive. Never a "Loading…" sentence inside an action menu. */ export function ComposerMenuRowsSkeleton({ rows = 3, label, size = "row", }: { rows?: number | undefined; /** Announced to screen readers ("Loading connectors"). */ label: string; /** `row`: 32px menu rows; `tile`: 56px rows with a tile and a second line. */ size?: "row" | "tile" | undefined; }) { return (
{Array.from({ length: rows }, (_, index) => ( ))}
); } const composerMenuPreloads = new Set<() => Promise>(); /** * A composer drill-in whose body loads on demand registers its loader here. * Registering loads nothing; the composer warms every registered drill-in * when "+" is hovered, focused or idle, so opening one never waits on code. */ export function registerComposerMenuPreload(load: () => Promise): void { composerMenuPreloads.add(load); } export function preloadComposerMenuPanels(): void { for (const load of composerMenuPreloads) void load().catch(() => undefined); } /** * `React.lazy` that renders straight away once its code is loaded. Plain lazy * suspends for a frame on its first render even when the module is already * cached, which flashes the loading rows and resizes the menu. The loader is * registered as a composer drill-in preload. Keep a Suspense boundary around * it for the cold case. */ export function lazyComposerPanel

( load: () => Promise>, ): ComponentType

{ let loaded: ComponentType

| null = null; const loadOnce = () => load().then((component) => { loaded = component; return component; }); const Lazy = lazy(() => loadOnce().then((component) => ({ default: component }))); registerComposerMenuPreload(loadOnce); function ComposerPanel(props: P) { // Decided once per mount, so a panel never swaps implementations while open. const [Ready] = useState | null>(() => loaded); const Component = (Ready ?? Lazy) as ComponentType

; return ; } return ComposerPanel; }