import React from 'react'; /** * SeoErrorBoundary — keeps a crash inside one plugin component from taking the * whole Payload admin down. * * Why this exists: every component this plugin registers is mounted by Payload * itself, from the import map. The plugin never owns the parent, so it cannot be * given an ancestor boundary from the outside — the boundary has to live INSIDE * the module Payload mounts. Each entry point therefore exports a wrapper * (`SeoNavLink`, `MetaTitleField`, …) around an inner component holding the real * implementation. Without it, a single `undefined.map()` in a sidebar nav link * unmounts the entire admin React tree, on every admin page. * * Scope, stated plainly: React error boundaries only catch errors thrown during * RENDER. They do not catch rejected promises in `useEffect` (and these * components fetch a lot), nor errors thrown from event handlers. Those still * need a try/catch at the call site. * * 'use client' is prepended to the whole client bundle by tsup (see * tsup.config.ts), which is why there is no directive here. */ interface SeoErrorBoundaryLabels { /** Heading shown in the default notice. */ title?: string; /** Label of the retry button. */ retry?: string; } interface SeoErrorBoundaryProps { children: React.ReactNode; /** * Rendered instead of the built-in notice. Pass `null` for silent * degradation — used by the components mounted on EVERY admin page, where a * permanent error panel would be worse than a missing widget. */ fallback?: React.ReactNode; /** Prefixes the console error, so the log says which mount blew up. */ viewName?: string; /** * When any of these values changes, the boundary clears its error state and * remounts the subtree. Useful when the crash was caused by a prop (a * document id, a locale) that has since changed. */ resetKeys?: unknown[]; /** Localized strings. English defaults, so a caller without i18n still reads. */ labels?: SeoErrorBoundaryLabels; } interface SeoErrorBoundaryState { hasError: boolean; /** Bumped on every reset — used as a `key` so the subtree fully remounts. */ resetCount: number; /** Serialized `resetKeys` of the last render, to detect a change. */ keySignature: string; } declare class SeoErrorBoundary extends React.Component { constructor(props: SeoErrorBoundaryProps); static getDerivedStateFromError(): Partial; static getDerivedStateFromProps(props: SeoErrorBoundaryProps, state: SeoErrorBoundaryState): Partial | null; componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void; private handleRetry; render(): React.ReactNode; } /** * Wiring between the pure `SeoErrorBoundary` and this plugin's translations. * * Kept apart from ErrorBoundary.tsx on purpose: the boundary itself must stay * free of Payload imports so it can be unit-tested without an admin provider * tree. Everything that needs `useTranslation()` lives here. * * 'use client' is prepended to the whole client bundle by tsup. */ type LocalizedSeoErrorBoundaryProps = Omit; /** * `SeoErrorBoundary` with the plugin's own FR/EN strings wired in. * * Safe to mount above anything: `useTranslation()` is `use(Context)` with a * default `i18n` (language 'en') in @payloadcms/ui, so it never throws outside * a provider — which matters, because nothing catches an error thrown by the * boundary's own wrapper. */ declare function LocalizedSeoErrorBoundary(props: LocalizedSeoErrorBoundaryProps): React.JSX.Element; /** * Wraps a component in a localized boundary, for the entry points Payload * mounts itself from the import map. * * Pass `fallback: null` for anything rendered on EVERY admin page (the sidebar * nav link): a permanent error panel across the whole admin is worse than a * missing link. Omit `fallback` where a visible, retryable notice is the honest * answer (a field, a view). */ declare function withSeoErrorBoundary

(Inner: React.ComponentType

, options: { viewName: string; fallback?: React.ReactNode; }): React.FC

; /** * SEO Plugin — Lightweight i18n translation system. * Provides French (default) and English translations for all plugin views * and all rule messages/labels/tips. * No external dependencies. */ type SeoLocale = 'fr' | 'en'; /** Analysis locale options forwarded from `SeoPluginConfig` to the sidebar field. */ interface SeoAnalysisLocaleOptions { /** `SeoPluginConfig.locale` — overrides everything, as on the server. */ locale?: SeoLocale; /** `SeoPluginConfig.localeMapping` — Payload locale code → analysis locale. */ localeMapping?: Record; } interface SeoAnalyzerFieldProps { /** Client field config; `admin.custom` carries the plugin's locale options (see seoFields()). */ field?: { admin?: { custom?: SeoAnalysisLocaleOptions; }; }; } /** * Registered as the `seoAnalyzer` UI field on every target collection, so * Payload mounts it from the import map inside the document form. The boundary * lives here because the plugin never owns that parent: without it, one bad * analysis result takes down the whole edit screen, sidebar and save button * included. */ declare const SeoAnalyzer: React.FC; declare function SeoView(): React.JSX.Element; /** * Payload mounts this from the import map on EVERY admin page (afterNavLinks), * so a render error here would unmount the whole admin shell everywhere. The * boundary has to live inside this module: the plugin never owns the parent. * * `fallback: null` — the nav link disappears rather than putting a permanent * error panel across the sidebar of every screen. */ declare const SeoNavLink: React.FC; interface AuditItem { id: number | string; collection: string; title: string; slug: string; updatedAt: string; contentLastReviewed: string; daysSinceUpdate: number | null; } declare function ContentDecaySection({ items }: { items: AuditItem[]; }): React.JSX.Element; interface ScoreHistoryChartProps { documentId: string; collection: string; } declare const ScoreHistoryChart: React.FC; declare function SitemapAuditView(): React.JSX.Element | null; declare function SeoConfigView(): React.JSX.Element; interface SeoSocialPreviewProps { metaTitle?: string; metaDescription?: string; imageUrl?: string; hostname?: string; } declare function SeoSocialPreview({ metaTitle, metaDescription, imageUrl, hostname, }: SeoSocialPreviewProps): React.JSX.Element; declare function RedirectManagerView(): React.JSX.Element; declare function CannibalizationView(): React.JSX.Element; declare function SchemaBuilderView(): React.JSX.Element; declare function PerformanceView(): React.JSX.Element; declare function KeywordResearchView(): React.JSX.Element; /** * LinkGraphView — Interactive SVG-based internal link graph visualization. * Uses a force-directed layout (spring simulation) computed on mount. * No external dependencies (no D3.js, no vis.js). */ declare function LinkGraphView(): React.JSX.Element; /** * Options of the meta title / description / image field components. * * metaFields() stores them in the field's `admin.custom`, which Payload hands to * the component as `field.admin.custom` — never as top-level props. Reading only * the props hid the "generate" button and ignored a custom `endpointBasePath`. */ interface MetaFieldCustom { hasGenerateFn?: boolean; basePath?: string; } interface MetaFieldOptionProps { field?: { admin?: { custom?: MetaFieldCustom; }; }; /** Direct props win over `admin.custom`, for hosts that mount the component themselves. */ hasGenerateFn?: boolean; basePath?: string; } /** * MetaTitleField — Custom Payload CMS field component for meta title. * * Adds a character counter (30-60 optimal range) with color indicator, * a progress bar, and an optional "Generate" button that calls the * plugin's generate endpoint to auto-fill the title via user-provided * generate functions. * * This component is registered as a custom Field component on the * `meta.title` field when the SEO Analyzer plugin creates meta fields. */ interface MetaTitleFieldProps extends MetaFieldOptionProps { path: string; } /** * Payload mounts this field from the import map on every edit screen, so the * boundary must live in this module — the plugin never owns the parent form. * A crash here degrades to a retryable notice instead of taking the whole * document editor down. */ declare const MetaTitleField: React.FC; /** * MetaDescriptionField — Custom Payload CMS field component for meta description. * * Adds a character counter (120-160 optimal range) with color indicator, * a progress bar, and an optional "Generate" button that calls the * plugin's generate endpoint to auto-fill the description via user-provided * generate functions. * * This component is registered as a custom Field component on the * `meta.description` field when the SEO Analyzer plugin creates meta fields. */ interface MetaDescriptionFieldProps extends MetaFieldOptionProps { path: string; } /** * Payload mounts this field from the import map on every edit screen, so the * boundary must live in this module — the plugin never owns the parent form. * A crash here degrades to a retryable notice instead of taking the whole * document editor down. */ declare const MetaDescriptionField: React.FC; /** * MetaImageField — Custom Payload CMS field component for meta image. * * Displays a status indicator for the meta image and an optional * "Generate" button that calls the plugin's generate endpoint to * auto-fill the image reference via user-provided generate functions. * * This component does NOT render the actual upload field — Payload * handles that natively. It adds the generate button UI alongside * the native upload field. */ interface MetaImageFieldProps extends MetaFieldOptionProps { path: string; } /** * Payload mounts this field from the import map on every edit screen, so the * boundary must live in this module — the plugin never owns the parent form. * A crash here degrades to a retryable notice instead of taking the whole * document editor down. */ declare const MetaImageField: React.FC; /** * OverviewField — UI-only Payload CMS field that shows meta completeness. * * Displays three indicators (Title, Description, Image) with check/cross * status and a completeness progress bar (0/3 to 3/3). Uses Payload's * `useFormFields` hook to reactively read meta field values from the * current document form state. * * Intended for use in the editor sidebar as a quick glance overview. */ interface OverviewFieldProps { titlePath?: string; descriptionPath?: string; imagePath?: string; } /** * Payload mounts this field from the import map on every edit screen, so the * boundary must live in this module — the plugin never owns the parent form. * A crash here degrades to a retryable notice instead of taking the whole * document editor down. */ declare const OverviewField: React.FC; interface SerpPreviewProps { metaTitle?: string; metaDescription?: string; slug?: string; hostname?: string; favicon?: string; } /** * Payload mounts this field from the import map on every edit screen, so the * boundary must live in this module — the plugin never owns the parent form. * A crash here degrades to a retryable notice instead of taking the whole * document editor down. */ declare const SerpPreview: React.FC; export { CannibalizationView, ContentDecaySection, KeywordResearchView, LinkGraphView, LocalizedSeoErrorBoundary, MetaDescriptionField, MetaImageField, MetaTitleField, OverviewField, PerformanceView, RedirectManagerView, SchemaBuilderView, ScoreHistoryChart, SeoAnalyzer as SeoAnalyzerField, SeoConfigView, SeoErrorBoundary, type SeoErrorBoundaryLabels, type SeoErrorBoundaryProps, SeoNavLink, SeoSocialPreview, SeoView, SerpPreview, SerpPreview as SerpPreviewField, SitemapAuditView, withSeoErrorBoundary };