Visor PDF.
Patrón canónico de visor pdf para firmas y documentos, scribe, medicamentos y editorial sebastián.
Verlo por niveles
Primero el componente, después la variación de marca y finalmente su uso dentro de una página.
Ver y copiar el código de este render
<figure class="ui-sample ui-embed" data-pdf-viewer="true"><div class="ui-actions" role="toolbar"><button class="btn btn--secondary btn--sm" type="button" disabled="">Página anterior</button><span>Página 1 de 12</span><button class="btn btn--secondary btn--sm" type="button">Página siguiente</button><button class="btn btn--secondary btn--sm" type="button">Zoom 100%</button></div><div class="ui-embed__frame ui-embed__frame--paper"><span>Página 1: partes y objeto del contrato</span></div><figcaption><a href="#descargar-pdf">Descargar PDF firmado</a> <span>SHA-256 disponible</span></figcaption></figure>Variaciones por marca y sitio
Cada cambio visible declara su autoridad; lo que permanece canónico no se vuelve a inventar en el producto.
Firmas y Documentos
Autoridad: Feedback de revisión r14 + cis.document.v1Cambia en esta marca
- Nombre completo con espacios y color café
- Densidad documental y metadatos de autoridad
Permanece canónico
- Firma, digest, versión y recibo no son decoración
- Chrome, foco y controles canónicos
Compañía de Innovación de Santiago
Autoridad: CONSTITUTION.md + LOGOS-CANONICOS.mdCambia en esta marca
- Navegación y contenido propios del servicio
- Acento reservado para acciones y datos
Permanece canónico
- Mark CIS y namebrand de tres líneas
- IBM Plex Sans, foco, espaciado y anatomía
Comparación histórica recuperable
Compara la propuesta con cortes reales del repositorio. La ausencia de una muestra se declara y nunca se reconstruye de memoria.
- Estado actual
- Visor PDF tiene 2 implementaciones observadas en 2 repositorios: cds/cds-sebastian, cochid/cochid-scribe.
- Cambio propuesto
- Publicar en r19 el contrato de Visor PDF para Patrón canónico de visor pdf para firmas y documentos, scribe, medicamentos y editorial sebastián.
- Qué ocurre si respondes No
- No se adopta el contrato r19 de Visor PDF; las 2 implementaciones observadas permanecen sin migración.
Preparando comparación histórica…
Antes / r19
La comparación convierte una regla abstracta en una diferencia visible y verificable.
- Muestra versión, estado, partes y representación verificable.
- Conserva historial, firma y digest fuera del puro tratamiento visual.
- No presentes un borrador como firmado o vigente.
- No alteres la autoridad del contrato documental desde Style.
Responsive
La misma anatomía debe conservar lectura, foco y acciones sin cortar contenido ni crear scroll horizontal en la página.
Cobertura
| Dimensión | Contrato |
|---|---|
| Propietario canónico | Sistema de diseño CIS y Firmas y Documentos · core/core-style |
| Consumidores | Firmas y Documentos, Scribe, Medicamentos y Editorial Sebastián |
| Dependencias | contrato documental, representaciones versionadas |
| Estado | candidato |
Evidencia de adopción
Patrón observado. 2 implementaciones observadas en 2 repositorios.
La observación demuestra uso existente; la aceptación canónica sigue dependiendo de esta ficha y de su propietario.
| Dato | Resultado |
|---|---|
| Clasificación | Patrón observado |
| Implementaciones | 2 implementaciones observadas |
| Repositorios | cds/cds-sebastian, cochid/cochid-scribe |
| Snapshot | kit/componentes/componentes-observados.json |
Consumidores observados
El inventario conserva repositorio, archivo fuente y criterio de asociación. Observar una implementación no la convierte automáticamente en canónica.
Estados
| Estado requerido |
|---|
| borrador |
| en revisión |
| firmado |
| archivado |
Accesibilidad
- Conserva nombre accesible, orden de lectura y foco visible.
- Funciona a 320 px, con zoom de 200% y texto largo.
- El color nunca es la única señal de estado o acción.
- El contenido esencial permanece disponible sin JavaScript.
Código HTML
Copia el bloque completo; después cambia contenido y destinos, no su anatomía.
<figure class="ui-sample ui-embed" data-pdf-viewer="true"><div class="ui-actions" role="toolbar"><button class="btn btn--secondary btn--sm" type="button" disabled="">Página anterior</button><span>Página 1 de 12</span><button class="btn btn--secondary btn--sm" type="button">Página siguiente</button><button class="btn btn--secondary btn--sm" type="button">Zoom 100%</button></div><div class="ui-embed__frame ui-embed__frame--paper"><span>Página 1: partes y objeto del contrato</span></div><figcaption><a href="#descargar-pdf">Descargar PDF firmado</a> <span>SHA-256 disponible</span></figcaption></figure>Código TAILWIND
Copia el bloque completo; después cambia contenido y destinos, no su anatomía.
<figure class="ui-sample ui-embed border border-slate-300 bg-white p-4 text-slate-950 grid gap-3" data-pdf-viewer="true"><div class="ui-actions" role="toolbar"><button class="btn btn--secondary btn--sm border border-slate-950 px-3 py-2 focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed" type="button" disabled="">Página anterior</button><span>Página 1 de 12</span><button class="btn btn--secondary btn--sm border border-slate-950 px-3 py-2 focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed" type="button">Página siguiente</button><button class="btn btn--secondary btn--sm border border-slate-950 px-3 py-2 focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed" type="button">Zoom 100%</button></div><div class="ui-embed__frame ui-embed__frame--paper"><span>Página 1: partes y objeto del contrato</span></div><figcaption class="text-sm text-slate-600"><a class="underline underline-offset-4" href="#descargar-pdf">Descargar PDF firmado</a> <span>SHA-256 disponible</span></figcaption></figure>Código REACT
Copia el bloque completo; después cambia contenido y destinos, no su anatomía.
import type { MouseEventHandler, ReactNode } from "react";
export interface PdfViewerProps {
/** Página visible, desde 1. */
page?: number;
/** Total de páginas del documento. */
pageCount?: number;
/** Texto de posición; por defecto, «Página {page} de {pageCount}». Vacío lo oculta. */
pageLabel?: string;
/** Texto del botón que retrocede una página; vacío oculta el botón. */
previousLabel?: string;
/** Deshabilita el botón de la página anterior; por defecto, en la primera página. */
previousDisabled?: boolean;
onPrevious?: MouseEventHandler<HTMLButtonElement>;
/** Texto del botón que avanza una página; vacío oculta el botón. */
nextLabel?: string;
/** Deshabilita el botón de la página siguiente; por defecto, en la última página. */
nextDisabled?: boolean;
onNext?: MouseEventHandler<HTMLButtonElement>;
/** Escala de la vista, en porcentaje. */
zoom?: number;
/** Texto del botón de escala; por defecto, «Zoom {zoom}%». Vacío oculta el botón. */
zoomLabel?: string;
/** Se llama al pulsar el botón de escala. */
onZoom?: MouseEventHandler<HTMLButtonElement>;
/** Contenido del marco de página (imagen o lienzo de la página); un texto se envuelve en `<span>`. */
children?: ReactNode;
/** Enlace de descarga del PDF; vacío oculta el enlace. */
href?: string;
linkLabel?: string;
/** Texto del pie, al otro extremo del enlace («SHA-256 disponible»); vacío lo oculta. */
detail?: string;
className?: string;
}
/**
* Visor de PDF con barra de página anterior y siguiente, posición, escala, marco de página y enlace de descarga; se usa para leer un documento paginado dentro de la ficha.
*
* El estado llega por props: la página visible (`page`) y la escala (`zoom`) las mantiene quien usa el componente con `onPrevious`, `onNext` y `onZoom`. En la primera página el botón anterior queda deshabilitado y en la última el siguiente; `previousDisabled` y `nextDisabled` cambian eso.
*
* @example <PdfViewer page={2} pageCount={12} onPrevious={anterior} onNext={siguiente} href="/documentos/fyd-184/v4.pdf"><img src="/documentos/fyd-184/v4/2.png" alt="Página 2 del contrato FYD-184" /></PdfViewer>
* @example <PdfViewer page={12} pageCount={12} onPrevious={anterior} detail="SHA-256 b19f…93ce">Página 12: firmas y anexo de datos</PdfViewer>
*/
export function PdfViewer({
page = 1,
pageCount = 12,
pageLabel,
previousLabel = "Página anterior",
previousDisabled = page <= 1,
onPrevious,
nextLabel = "Página siguiente",
nextDisabled = page >= pageCount,
onNext,
zoom = 100,
zoomLabel,
onZoom,
children = "Página 1: partes y objeto del contrato",
href = "#descargar-pdf",
linkLabel = "Descargar PDF firmado",
detail = "SHA-256 disponible",
className,
}: PdfViewerProps) {
const posicion = pageLabel ?? `Página ${page} de ${pageCount}`;
const escala = zoomLabel ?? `Zoom ${zoom}%`;
const enlace = href && linkLabel;
return (
<figure className={["ui-embed", className].filter(Boolean).join(" ")} data-pdf-viewer>
<div className="ui-actions" role="toolbar">
{previousLabel ? <button className="btn btn--secondary btn--sm" type="button" disabled={previousDisabled} onClick={onPrevious}>{previousLabel}</button> : null}
{posicion ? <span>{posicion}</span> : null}
{nextLabel ? <button className="btn btn--secondary btn--sm" type="button" disabled={nextDisabled} onClick={onNext}>{nextLabel}</button> : null}
{escala ? <button className="btn btn--secondary btn--sm" type="button" onClick={onZoom}>{escala}</button> : null}
</div>
<div className="ui-embed__frame ui-embed__frame--paper">
{typeof children === "string" ? (children ? <span>{children}</span> : null) : children}
</div>
{enlace || detail ? (
<figcaption>
{enlace ? <a href={href}>{linkLabel}</a> : null}
{enlace && detail ? " " : null}
{detail ? <span>{detail}</span> : null}
</figcaption>
) : null}
</figure>
);
}