Files
paseo/packages/plugin/src/client/buttons.ts
T
Mohamed Boudra b6dde61a7f feat(plugins): accept inline SVG and component icons (#7368)
Every contribution `icon` now takes a Lucide name, `{ svg }`, or a
component. Attachment sources take only the first two because composer
drafts persist the source icon.

The daemon's provider-icon check and the app's inline-SVG check are the
same function in the shared SDK root, so a plugin sees the same reasons
in both places. The app parses each icon once at registration and fails
the plugin with that reason. Rendering goes through one module that
turns any form into a component, so surfaces never branch on the form.
2026-10-19 15:36:04 +07:00

58 lines
1.8 KiB
TypeScript

import type { ComponentType } from "react";
import type { PluginIconProps } from "../icons.js";
import type { PluginHostProps, PluginIcon } from "./contracts.js";
export type PluginButtonContext =
| { context: "workspace"; workspaceId: string }
| { context: "agent"; workspaceId: string; agentId: string };
export type PluginButtonIconProps = PluginHostProps & PluginButtonContext & PluginIconProps;
export type PluginButtonContentProps = PluginHostProps & PluginButtonContext & { close(): void };
export type PluginButtonIcon = PluginIcon<PluginButtonIconProps>;
export type PluginButtonBehavior =
| { kind: "action"; onPress(): void | Promise<void> }
| { kind: "menu"; items: readonly PluginButtonMenuEntry[] }
| { kind: "popover"; Content: ComponentType<PluginButtonContentProps> };
export type PluginButtonMenuEntry =
| { kind: "separator"; id: string }
| {
kind: "item";
id: string;
title: string;
icon?: PluginButtonIcon;
visible?: boolean;
disabled?: boolean;
behavior: PluginButtonBehavior;
};
export interface PluginButton {
title: string;
icon: PluginButtonIcon;
/** Omit for an icon-only header button. Composer pills use title when omitted. */
label?: string;
visible?: boolean;
disabled?: boolean;
behavior: PluginButtonBehavior;
}
export interface PluginButtonRegistration {
/** Updates presentation in place. Supply a complete behavior to replace it. */
update(patch: Partial<PluginButton>): void;
/** Idempotent. Updates after removal do nothing. */
remove(): void;
}
export interface PluginHeaderButtonContribution {
id: string;
workspaceId: string;
button: PluginButton;
}
export interface PluginComposerPillContribution extends PluginHeaderButtonContribution {
agentId: string;
}