Componentes de renderizado de Portable Text

En esta página

Los plugins pueden agregar tipos de bloques personalizados al editor de Portable Text — incrustaciones de YouTube, fragmentos de código, galerías de imágenes, cualquier cosa que no esté cubierta por el conjunto de bloques predeterminado. Los plugins sandboxed pueden declarar la interfaz de edición para estos bloques (usando campos de Block Kit), pero los componentes de Astro que los renderizan en el sitio público deben cargarse en tiempo de compilación desde npm. Esa es la parte que requiere un plugin nativo.

Si tu plugin solo necesita campos del lado de edición y alguien más proporciona los componentes de renderizado (o el sitio los proporciona localmente), puedes permanecer sandboxed. Si el plugin también debe incluir los componentes de renderizado, necesitas ser nativo.

Declarar tipos de bloques

Tanto los plugins sandboxed como los nativos pueden declarar tipos de bloques. Los plugins nativos lo hacen dentro de definePlugin() bajo admin.portableTextBlocks:

admin: {
	portableTextBlocks: [
		{
			type: "youtube",
			label: "YouTube Video",
			icon: "video",                       // video, code, link, link-external
			placeholder: "Paste YouTube URL...",
			fields: [                            // Block Kit fields for the editing UI
				{ type: "text_input", action_id: "id", label: "YouTube URL" },
				{ type: "text_input", action_id: "title", label: "Title" },
				{ type: "text_input", action_id: "poster", label: "Poster Image URL" },
			],
		},
	],
},

Cada tipo de bloque define:

  • type — nombre del tipo de bloque (usado en Portable Text _type).
  • label — nombre para mostrar en el menú de comandos slash del editor.
  • iconvideo, code, link o link-external. Vuelve a un cubo genérico por defecto.
  • placeholder — texto de marcador de posición de entrada.
  • fields — campos de formulario de Block Kit para edición. Si se omite, se muestra una entrada de URL simple.

Renderizado en el sitio público

Para renderizar tipos de bloques en el sitio público, exporta componentes de Astro desde un componentsEntry. El nombre de exportación debe ser blockComponents:

import YouTube from "./YouTube.astro";
import CodePen from "./CodePen.astro";

export const blockComponents = {
	youtube: YouTube,
	codepen: CodePen,
};

Establece componentsEntry en el descriptor:

export function myPlugin(): PluginDescriptor {
	return {
		id: "embeds",
		version: "1.0.0",
		format: "native",
		entrypoint: "@my-org/embeds",
		componentsEntry: "@my-org/embeds/astro",
	};
}

EmDash fusiona los componentes de bloques de plugins en <PortableText> automáticamente — los autores del sitio no necesitan importar nada. Los componentes proporcionados por el usuario (declarados en la prop components del sitio en <PortableText>) tienen precedencia sobre los valores predeterminados del plugin.

Exportaciones de paquetes

Agrega la exportación ./astro a package.json:

{
	"exports": {
		".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
		"./admin": { "types": "./dist/admin.d.ts", "import": "./dist/admin.js" },
		"./astro": { "types": "./dist/astro/index.d.ts", "import": "./dist/astro/index.js" }
	}
}

La exportación ./astro es del lado del servidor (Astro SSR), la exportación ./admin es del lado del navegador (React), y la exportación "." es el descriptor + createPlugin. Manténlos en archivos separados porque se empaquetan para diferentes entornos.

Variantes amigables con sandbox

Si deseas que un plugin sea sandboxed pero aún así proporcione una experiencia de renderizado predeterminada, el patrón habitual es:

  1. Distribuir el plugin sandboxed (solo campos de edición) en el marketplace.
  2. Distribuir un paquete nativo complementario separado en npm que proporcione los componentes de renderizado de Astro.
  3. Documentar ambos: los usuarios finales instalan el plugin sandboxed del marketplace y ejecutan npm install del paquete complementario para el renderizado.

Esto intercambia una instalación de un solo paso por mantener el lado del editor sandboxed. Ser completamente nativo es más simple cuando está involucrado el renderizado de bloques, pero esta división sigue siendo una opción.