Files
paseo/plugin-examples/pdf-panel/client/pdf-panel.tsx
T
Mohamed Boudra dfb6215de0 feat(file-panels): panels read and write through a file handle
The file tab stats the file and mounts its panel without reading it. Every
panel, built-in or plugin, gets a PluginFile handle: readText, readBytes, url,
version-checked writeText/writeBytes (PluginFileConflictError unless force),
and watch. useFileText, useFileBytes and useFileUrl read through it, and
Loading joins @getpaseo/plugin/client/ui. Panels own their loading state.

The host document pipeline, the explorer preview cache and the preview
lifecycle are deleted. The daemon classifies a file version from a bounded
sniff and writes base64 content as bytes behind fileByteWrites.

A deleted file keeps its panel mounted; a read confirms the deletion first,
so a remove-and-rewrite is not reported as one. Native Source decodes with
builtins and highlights in idle-time slices, the lines around the opening
line first, so a large file no longer blocks the JS thread.
2026-10-20 08:02:49 +02:00

42 lines
1.3 KiB
TypeScript

import { type PluginFilePanelProps, useFileUrl } from "@getpaseo/plugin/client";
import { DocumentFrame, Loading } from "@getpaseo/plugin/client/ui";
import { useMemo } from "react";
import { Text, View } from "react-native";
const messageStyle = {
flex: 1,
alignItems: "center",
justifyContent: "center",
padding: 24,
} as const;
export function PdfPanel(props: PluginFilePanelProps) {
if (props.layout.platform === "android") return <AndroidPdf {...props} />;
return <InlinePdf {...props} />;
}
function InlinePdf({ file, theme }: PluginFilePanelProps) {
const url = useFileUrl(file);
const textStyle = useMemo(() => ({ color: theme.colors.statusDanger }), [theme]);
if (url.status === "loading") return <Loading />;
if (url.status === "error") {
return (
<View style={messageStyle}>
<Text style={textStyle}>{url.error.message}</Text>
</View>
);
}
return <DocumentFrame url={url.url} testID="pdf-panel" />;
}
function AndroidPdf({ file, theme }: PluginFilePanelProps) {
const textStyle = useMemo(() => ({ color: theme.colors.foregroundMuted }), [theme]);
return (
<View style={messageStyle}>
<Text style={textStyle}>
{file.name} ({Math.round(file.size / 1024)} KB). Android cannot render PDF inline.
</Text>
</View>
);
}