mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-27 03:32:55 +00:00
* feat(plugins): add React Native UI primitives Give client plugins host-owned adaptive UI without exposing app internals. Preserve plugin runtime contexts when modal content moves through the compact portal host. * docs(plugins): clarify host UI reference * refactor(plugins): harden host UI boundary Replace mocked pass-through coverage with a real browser plugin journey, keep host runtime ownership inside the evaluator, preserve toast context across compact portals, and expose modal content as a compound component. * fix(plugins): defer native UI presentation runtime Loading the plugin evaluator initialized the modal and toast presentation stacks even when no plugin requested host UI. Keep the capability stable while delaying platform-heavy presentation code until Modal.Content renders. * refactor(plugins): move modal metadata to root Keep Modal.Content body-only while the top-level Modal owns the host-rendered title and leading icon. This leaves presentation metadata stable as the compound API gains future regions.
104 lines
3.5 KiB
TypeScript
104 lines
3.5 KiB
TypeScript
import { PluginAttachmentSearchPayloadSchema } from "./attachments.js";
|
|
export { PluginClientStateProvider, type PluginClientStateSource } from "./client-state.js";
|
|
export {
|
|
usePluginRuntimeContextBridge,
|
|
type PluginRuntimeContextBridge,
|
|
} from "./runtime-context-bridge.js";
|
|
import type {
|
|
PluginAttachmentSourceContribution,
|
|
PluginCommandCenterItemContribution,
|
|
PluginClientContribution,
|
|
PluginContext,
|
|
PluginSidebarContribution,
|
|
PluginSurfaceContribution,
|
|
PluginSurfaceProps,
|
|
PluginThemeContribution,
|
|
PluginTimelineRendererContribution,
|
|
PluginTimelineTransformerContribution,
|
|
PluginWorkspacePanelContribution,
|
|
} from "./contracts.js";
|
|
import { PluginRpcProvider } from "./rpc-context.js";
|
|
import { PaseoApiProvider } from "./paseo-context.js";
|
|
import { callPluginRpc } from "./rpc.js";
|
|
import type { ComponentType } from "react";
|
|
|
|
interface PluginCollector {
|
|
addSurface(id: string, Component: ComponentType<PluginSurfaceProps>): void;
|
|
addSidebarItem(contribution: PluginSidebarContribution): void;
|
|
addWorkspacePanel(contribution: PluginWorkspacePanelContribution): void;
|
|
addCommandCenterItem(contribution: PluginCommandCenterItemContribution): void;
|
|
addClientSide(contribution: PluginClientContribution): void;
|
|
addAttachmentSource(contribution: PluginAttachmentSourceContribution): void;
|
|
addTheme(contribution: PluginThemeContribution): void;
|
|
addTimelineTransformer(contribution: PluginTimelineTransformerContribution): void;
|
|
addTimelineRenderer(contribution: PluginTimelineRendererContribution): void;
|
|
}
|
|
|
|
export interface PluginRegistrationCollector {
|
|
surfaces: PluginSurfaceContribution[];
|
|
sidebarItems: PluginSidebarContribution[];
|
|
workspacePanels: PluginWorkspacePanelContribution[];
|
|
commandCenterItems: PluginCommandCenterItemContribution[];
|
|
clientSide: PluginClientContribution | null;
|
|
attachmentSources: PluginAttachmentSourceContribution[];
|
|
themes: PluginThemeContribution[];
|
|
timelineTransformers: PluginTimelineTransformerContribution[];
|
|
timelineRenderers: PluginTimelineRendererContribution[];
|
|
}
|
|
|
|
export function createPluginContext(
|
|
collector: PluginCollector,
|
|
): Pick<
|
|
PluginContext,
|
|
| "addSurface"
|
|
| "addSidebarItem"
|
|
| "addWorkspacePanel"
|
|
| "addCommandCenterItem"
|
|
| "addClientSide"
|
|
| "addAttachmentSource"
|
|
| "addTheme"
|
|
| "addTimelineTransformer"
|
|
| "addTimelineRenderer"
|
|
> {
|
|
return {
|
|
addSurface(id, Component) {
|
|
collector.addSurface(id, Component);
|
|
},
|
|
addSidebarItem(contribution) {
|
|
collector.addSidebarItem(contribution);
|
|
},
|
|
addWorkspacePanel(contribution) {
|
|
collector.addWorkspacePanel(contribution);
|
|
},
|
|
addCommandCenterItem(contribution) {
|
|
collector.addCommandCenterItem(contribution);
|
|
},
|
|
addClientSide(contribution) {
|
|
collector.addClientSide(contribution);
|
|
},
|
|
addAttachmentSource(contribution) {
|
|
collector.addAttachmentSource(contribution);
|
|
},
|
|
addTheme(contribution) {
|
|
collector.addTheme(contribution);
|
|
},
|
|
addTimelineTransformer(contribution) {
|
|
collector.addTimelineTransformer(contribution);
|
|
},
|
|
addTimelineRenderer(contribution) {
|
|
collector.addTimelineRenderer(contribution);
|
|
},
|
|
};
|
|
}
|
|
|
|
export async function searchPluginAttachments(
|
|
source: PluginAttachmentSourceContribution,
|
|
invoke: (method: string, input: unknown) => Promise<unknown>,
|
|
query: string,
|
|
) {
|
|
const output = await callPluginRpc(source.search, invoke, { query });
|
|
return PluginAttachmentSearchPayloadSchema.parseAsync(output);
|
|
}
|
|
|
|
export { callPluginRpc, PaseoApiProvider, PluginRpcProvider };
|