import { type ComponentType, type ReactNode, useState } from "react"; import "~/features/index.ts"; import { type ActionPosition, type ActionSlot, type PanelPosition, type PanelSlot, type SlotProps, type SlotRegistry, slots, visibleActions, } from "~/lib/slots.ts"; // 插槽挂载点(ADR-006)。功能在 app/features/*.tsx 里注册,这里只负责在页面上渲染;没有注册时什么都不渲染。 /** 面板类插槽:按顺序渲染所有注册的组件 */ export function SlotPanels
({ position, props, registry = slots, }: { position: P; props: SlotProps[P]; registry?: SlotRegistry; }) { const entries = registry.entries(position) as PanelSlot
[];
if (entries.length === 0) return null;
return (
<>
{entries.map(({ id, Component }) => (
( position: P, registry: SlotRegistry = slots, ): { items: (props: SlotProps[P]) => ActionSlot
[]; open: (entry: ActionSlot
, props: SlotProps[P]) => void; dialog: ReactNode; } { const [active, setActive] = useState<{ entry: ActionSlot
; props: SlotProps[P] } | null>(null); // 泛型位置的 props 与 IntrinsicAttributes 交不出来,这里按具体对象渲染 const Dialog = active?.entry.Dialog as ComponentType<{ onClose: () => void }> | undefined; return { items: (props) => visibleActions(registry, position, props), open: (entry, props) => setActive({ entry, props }), dialog: Dialog && active ?