.agents/skills/plate-ui/SKILL.md
Repo-specific companion to the shadcn skill.
Use the shadcn skill for CLI, upstream docs, and generic shadcn/ui rules.
Use this skill for Plate-specific component authorship: open-code preservation,
package extraction boundaries, base/live kit split, cross-platform layering,
and registry wiring.
apps/www/src/registry/ui — live component and node renderersapps/www/src/registry/components/editor/plugins — base/live kit wiringapps/www/src/registry/registry-*.ts — registry metadata and dependenciespackages/* — durable transforms, queries, controllers, and public hookspackages/*/src/lib owns semantic core: transforms, queries, schemas, serialization, controllers, command/state contracts.packages/*/src/react is a thin adapter layer only.useElement() or usePath() when they are in element context.editor.getApi(plugin) / editor.getTransforms(plugin) or useEditorPlugin(plugin) over local wrapper helpers.PlateElement or SlateElement, keep the full incoming props object intact. Read from props, but do not destructure away editor, element, or other required fields and then spread only a partial object into the renderer.>=19.2. Do not preserve React 18 compatibility patterns unless the user explicitly asks.registry-kits.ts, registry-ui.ts, and registry-examples.ts together.registryDependencies for every shared UI/style dependency.asChild, data-slot, data-state, variants, and file shape recognizable.For the future redesign, use this as the default:
Package React hooks that mainly return renderer-specific UI props/state should be deprecated and moved app-local. Package layers keep cross-platform semantic/view-model contracts only.
If an existing hook breaks this law, do not copy it into new work just because it already exists.
Extract to a package only if at least one is true:
Keep it local if any of these are true:
// Good: package owns stable semantics, UI composes locally.
const { align, focused, readOnly, selected } = useMediaState();
return (
<MediaToolbar plugin={ImagePlugin}>
<PlateElement {...props}>...</PlateElement>
</MediaToolbar>
);
// Good: direct plugin access, no local wrapper layer.
const api = editor.getApi(CommentPlugin).comment;
const tf = editor.getTransforms(CommentPlugin).comment;
// Good: package core owns commands/state, platform UI composes locally.
const canToggleBold = bridgeState.canToggleBold;
const onPress = () => editor.toggleBold();
return <Button disabled={!canToggleBold}>Bold</Button>;
// Good: base/live split stays explicit.
export const BaseFootnoteKit = [
BaseFootnoteReferencePlugin.withComponent(FootnoteReferenceElementStatic),
BaseFootnoteDefinitionPlugin.withComponent(FootnoteDefinitionElementStatic),
];
export const FootnoteKit = [
FootnoteInputPlugin.withComponent(FootnoteInputElement),
FootnoteReferencePlugin.withComponent(FootnoteReferenceElement),
FootnoteDefinitionPlugin.withComponent(FootnoteDefinitionElement),
];
// Bad: package hook exists only to feed one shadcn component's local UI.
const state = useSingleComponentOnlyState();
return <Popover open={state.open}>...</Popover>;
// Bad: React-only package hook that mainly returns renderer glue.
const {
dialogTitle,
menuItems,
onOpenChange,
popoverOpen,
} = useToolbarMenuState();
shadcn skill. Run the normal shadcn docs/search workflow first.apps/www/src/registry/ui, apps/www/src/registry/components/editor/plugins, and the relevant packages/*.pnpm brl.