Record PDF Export
Three-step wizard (Select a Template → Preview → PDF) that renders a Docyrus record to PDF with a saved HTML template, previews the server-compiled document in a WebView, and shares or prints the result. Includes the headless useDocyrusRecordPdfExport hook.
Installation
pnpm dlx @docyrus/cli add @docyrus/rn-record-pdf-exportpnpm add @tanstack/react-query @docyrus/api-client react-native-webview 13.x (optional) expo-file-system (optional) expo-sharing (optional) expo-print (optional)This is a Docyrus-connected component. It needs an authenticated RestApiClient and a QueryClientProvider above it.
All native modules are optional peers, loaded lazily:
| Module | Used for | Without it |
|---|---|---|
react-native-webview | The Preview step, and the inline PDF on iOS. | The preview shows an install notice; the PDF step shows the file card. |
expo-file-system | Downloading the signed PDF into the cache directory. | Share has nothing to share. |
expo-sharing | The Share button (share sheet). | Sharing is a no-op. |
expo-print | The Print button, and rendering the compiled HTML to a PDF on the device when the server returns no public URL. | The Print button is hidden. |
Usage
Wizard in a sheet
import { useState } from 'react';
import { useDocyrusClient } from '@docyrus/signin/react-native';
import { AwesomeDialog, AwesomeDialogContent, AwesomeDialogHeader, AwesomeDialogBody } from '@/components/docyrus-native/awesome-dialog';
import { DocyrusRecordPdfExportWizard } from '@/components/docyrus-native/record-pdf-export';
export function ExportOrderPdf({ dataSourceId, recordId }: { dataSourceId: string; recordId: string }) {
const client = useDocyrusClient();
const [open, setOpen] = useState(false);
return (
<AwesomeDialog open={open} onOpenChange={setOpen} container="sheet" side="bottom" size="full">
<AwesomeDialogContent>
<AwesomeDialogHeader title="Export PDF" icon="fal file-pdf" />
<AwesomeDialogBody>
<DocyrusRecordPdfExportWizard
client={client!}
dataSourceId={dataSourceId}
recordId={recordId}
onClose={() => setOpen(false)}
onShare={(result, uri) => console.log('shared', result.path, uri)} />
</AwesomeDialogBody>
</AwesomeDialogContent>
</AwesomeDialog>
);
}Headless: build your own UI
import { useDocyrusRecordPdfExport } from '@/components/docyrus-native/record-pdf-export';
const pdf = useDocyrusRecordPdfExport({ client, dataSourceId, recordId });
// pdf.templates / pdf.setSelectedTemplateId → pick a template
// pdf.previewHtml → render in your own WebView
// await pdf.generatePdf() → server render; pdf.pdfUrl when signed
// await pdf.sharePdf() / pdf.printPdf()How it works
- Resolve. Without
appSlug/dataSourceSlug, the hook resolves them fromGET /v1/dev/data-sources/{id}. - Select a Template. Lists
GET /v1/dev/html-templates?tenantDataSourceId=…. The default template (or the first one) is picked automatically unlessautoSelectDefaultTemplateisfalseorinitialTemplateIdis set. Each row shows the name, a Default badge and page format / orientation. - Preview. Loads the server-compiled document from
GET /v1/apps/{app}/data-sources/{ds}/items/{recordId}/templates/{templateId}/html.previewHtmlcombines it with the template CSS and an A4 preview stylesheet, and the wizard renders it in a WebView. - PDF. Pressing Next on the Preview step calls
generatePdf(), which runsGET …/templates/{templateId}/pdf. The result ({ id, path, fullPath, url?, … }) is surfaced as is. On iOS, a signedurlrenders inline in the WebView. On Android, whose WebView cannot render PDFs, and when there is nourl, a file card appears instead. - Share / Print.
sharePdf()downloads the signedurlinto the cache directory (or, without aurl, renders the compiled HTML on the device withexpo-print) and opens the share sheet.printPdf()opens the system print dialog.
API Reference
DocyrusRecordPdfExportWizardProps
Accepts every useDocyrusRecordPdfExport option plus:
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Root View classes. |
bodyHeight | number | 70% of the window height | Height of the wizard (px). |
onClose | () => void | — | Fired by the footer Done button on the last step. |
hideClose | boolean | false | Hide the Done button. |
onShare | (result: DocyrusRecordPdfResult, uri: string) => void | — | Native: called after the PDF was handed to the share sheet (uri = local file). |
enablePrint | boolean | true | Native: show Print on the PDF step (needs expo-print). |
Options (UseDocyrusRecordPdfExportOptions)
| Option | Type | Default | Description |
|---|---|---|---|
client | RestApiClient | — | Authenticated REST client (required). |
dataSourceId | string | — | tenant_data_source.id of the record's data source (required). |
recordId | string | — | tenant_data_source_item.id of the record (required). |
appSlug | string | — | App slug. Resolved from dataSourceId when omitted. |
dataSourceSlug | string | — | Data source slug. Resolved from dataSourceId when omitted. |
enabled | boolean | true | Toggle all network activity. |
initialTemplateId | string | — | Pre-select a template by id. |
autoSelectDefaultTemplate | boolean | true | Select the default (or first) template once the list loads. |
resolveDataSourceEndpoint | string | '/v1/dev/data-sources/{id}' | Slug resolution endpoint ({id} is replaced). |
listTemplatesEndpoint | string | '/v1/dev/html-templates' | Templates list endpoint. |
Result (UseDocyrusRecordPdfExportResult)
| Field | Type | Description |
|---|---|---|
steps | RecordPdfExportStep[] | ['select', 'preview', 'pdf']. |
step / setStep / stepIndex | RecordPdfExportStep / setter / number | Current step. |
goNext / goBack | () => void | Step navigation. |
canGoNext / canGoBack / isLastStep | boolean | Navigation state. canGoNext needs a selected template (select) or a loaded preview (preview). |
appSlug / dataSourceSlug | string | null | Resolved slugs. |
isResolving / resolveError | boolean / Error | null | Slug resolution state. |
templates | DocyrusHtmlTemplateSummary[] | Templates for the data source. |
isLoadingTemplates / templatesError | boolean / Error | null | Templates state. |
refetchTemplates | () => Promise<unknown> | Invalidate and reload the templates. |
selectedTemplateId / setSelectedTemplateId / selectedTemplate | — | Selection. Changing it resets the PDF result. |
templateDetail | DocyrusHtmlTemplateDetail | null | Server-compiled template (body, header / footer, styles). |
isLoadingTemplateDetail / templateDetailError | boolean / Error | null | Preview state. |
previewHtml | string | Native: full document HTML (compiled body + template CSS + A4 preview CSS) for a WebView. |
generatePdf | () => Promise<DocyrusRecordPdfResult> | Server-side render. |
isGeneratingPdf / pdfResult / pdfUrl / pdfError | — | PDF state. pdfUrl is the signed url when present. |
pdfFileName | string | Suggested file name (always ends in .pdf). |
localPdfUri | string | null | Native: local file:// URI once prepared. |
isPreparingFile / fileError | boolean / Error | null | Native: download / on-device render state. |
prepareFile | () => Promise<string | null> | Native: download the signed url (or render with expo-print) into the cache. |
sharePdf | () => Promise<string | null> | Native: prepare the file if needed and open the share sheet. Resolves the shared URI. |
printPdf | () => Promise<boolean> | Native: open the print dialog. Resolves false without expo-print. |
canPrint | boolean | Native: whether expo-print is installed. |
reset | () => void | Back to the first step and clear the result. |
DocyrusRecordPdfResult
| Field | Type | Description |
|---|---|---|
id | string | Storage record id. |
path | string | Generated file name. |
fullPath | string | Storage object path (not directly fetchable). |
url | string | Signed, fetchable URL (when the server returns one). |
filename | string | File name alias used by some endpoints. |
bucket | string | Storage bucket. |
size | number | File size in bytes. |
Native differences
- No template editing. The web
templateEditablemode (PlateHtmlTemplateEditor) is web-only, sotemplateEditable,templateDetailEndpointand the record / edit state (record,editedHtml,previewEditorProps, …) are not available. - No Email step. There is no native
EmailComposeryet, sosendEmailis not supported.RecordPdfExportStepkeeps'email'for type parity, but native never produces it. - The preview is a WebView (
previewHtml) instead of the HTML Template Editor preview tab. - Native adds
onShare,enablePrint,bodyHeight: numberand the local-file API (prepareFile,sharePdf,printPdf,localPdfUri,canPrint). File writing and sharing use the internallib/native-exporthelpers.
Translation keys
ui.recordPdfExport.*: stepSelect, stepPreview, stepPdf, stepEmail, chooseTemplate, reload, loadingTemplates, noTemplates, default, loadingPreview, webviewMissing, retry, generatingPdf, pdfGenerated, pdfOpenHint, pdfNoUrl, pdfEmpty, back, next, print, share, done.
Components
| Component | Description |
|---|---|
DocyrusRecordPdfExportWizard | The three-step wizard. |
Type Exports
| Type | Description |
|---|---|
DocyrusRecordPdfExportWizardProps | Wizard props. |
UseDocyrusRecordPdfExportOptions | Hook options. |
UseDocyrusRecordPdfExportResult | Hook result. |
RecordPdfExportStep | 'select' | 'preview' | 'pdf' | 'email'. |
DocyrusHtmlTemplateSummary | Template list row. |
DocyrusHtmlTemplateDetail | Template with compiled body, header / footer and styles. |
DocyrusRecordPdfResult | PDF render result. |
RECORD_PDF_EXPORT_STEPS (['select', 'preview', 'pdf']) is exported as a value.
RecordDeleteConfirmDialog
Delete confirmation dialog with cascade relation management for related data.
RecordSharing
Share a record with users, teams, roles or the workspace — staged multi-select search, one batch permission, per-row pending states and a share trigger that opens the panel in a bottom sheet.