@medicaresoft/dicom-viewer
v0.1.1
Published
Visor DICOM reutilizable basado en Cornerstone v2. Núcleo de visualización sin lógica de negocio ni permisos: el host inyecta datos, acciones y branding.
Maintainers
Readme
@medicaresoft/dicom-viewer
Visor DICOM reutilizable para React, basado en Cornerstone v2 (core/tools/wado-image-loader). Es el núcleo de visualización de un PACS: sin lógica de negocio, sin permisos, sin router y sin HTTP propio. Todo lo específico del host se inyecta por props.
Instalación
npm install @medicaresoft/dicom-viewerPeer dependencies: react y react-dom (>= 18).
Uso mínimo
import { DicomViewer } from "@medicaresoft/dicom-viewer";
import "@medicaresoft/dicom-viewer/style.css"; // si tu host NO compila Tailwind sobre el paquete
export function App() {
return (
<DicomViewer
study={study} // metadatos (ver DicomStudy)
getDicomFile={(uid) => fetchMyDicom(uid)} // (instanceUid) => Promise<Blob>
/>
);
}El host decide de dónde salen los bytes: API propia, DICOMweb, disco local
(Wails), etc. El visor solo pide (instanceUid) => Blob.
Props principales
| Prop | Tipo | Descripción |
| --- | --- | --- |
| study | DicomStudy | Metadatos del estudio (paciente + series + files con instanceUid) |
| getDicomFile | (instanceUid) => Promise<Blob \| ArrayBuffer> | Fuente de bytes DICOM (requerido) |
| getThumbnailUrl | (instanceUid) => string | Miniaturas de series (opcional) |
| presets | Record<string, Record<string, { W; C }>> | Presets de ventana por modalidad (opcional) |
| maxConcurrentDownloads | number | Límite global de descargas concurrentes (default 12) |
| branding | { logo?, name? } | Logo/nombre en overlays |
| onBack | () => void | Si se define, muestra botón volver |
| actions | ReactNode | <Action/> inyectadas en slots |
| modals | ReactNode | <ViewerModal/> inyectados |
| theme | DicomViewerTheme | Colores primario/secundario + contrastes y superficies |
Tema (theme)
El visor se personaliza en runtime sin recompilar estilos:
<DicomViewer
study={study}
getDicomFile={fetcher}
theme={{
primary: "#0a5f8a",
primaryForeground: "#ffffff",
secondary: "#e63946",
secondaryForeground: "#ffffff",
// superficies opcionales (tema oscuro completo):
background: "#0e1017",
chrome: "#060608",
panel: "#1a1d27",
panelHover: "#202432",
border: "#242735",
// ...
}}
/>El prop se inyecta como variables CSS (--dv-*) en el elemento raíz del
visor — alcance por instancia, sin contaminar el :root del host. Todos los
campos son opcionales; los no definidos usan los defaults del paquete (o el
tema del host, en el caso de Symphony).
También puedes sobreescribir las variables globalmente en tu CSS:
:root {
--dv-secondary: #e63946;
--dv-primary: #0a5f8a;
}Acciones y modales (slots)
El visor reserva zonas (toolbar/sidebar/footer) donde el host inyecta sus botones; los permisos viven en el host:
import { DicomViewer, Action, ViewerModal } from "@medicaresoft/dicom-viewer";
<DicomViewer study={study} getDicomFile={fetcher}>
<Action
placement="sidebar"
id="reports"
label="Informes"
icon={<FileText size={16} />}
visible={() => user.can("reports.view")} // permisos del host
onClick={(ctx) => setShowReports(true)} // ctx: { study, activeSeriesIndex }
/>
<ViewerModal id="reports" open={showReports}>
<MyReportsModal onClose={() => setShowReports(false)} />
</ViewerModal>
</DicomViewer>actions y modals también aceptan arrays de <Action/>/<ViewerModal/>.
Si una acción trae children, se renderiza tal cual (botón 100% custom del
host).
Skeleton ligero
Subpath sin Cornerstone para usar como fallback mientras se carga el visor:
import { lazy, Suspense } from "react";
import { DicomViewerSkeleton } from "@medicaresoft/dicom-viewer/skeleton";
const DicomViewer = lazy(() =>
import("@medicaresoft/dicom-viewer").then((m) => ({ default: m.DicomViewer })),
);
<Suspense fallback={<DicomViewerSkeleton />}>
<DicomViewer study={study} getDicomFile={fetcher} />
</Suspense>Estilos
- Host con Tailwind v4: agrega el paquete a tu contenido
(
@source "../node_modules/@medicaresoft/dicom-viewer/dist";) y sobreescribe las variables--dv-primary/--dv-secondarypara tu marca. - Host sin Tailwind: importa
@medicaresoft/dicom-viewer/style.css.
Tipos
interface DicomStudy {
id: string;
studyInstanceUid: string;
patientName: string;
patientId: string;
patientBirthDate?: string;
patientAge?: string;
patientSex?: string;
studyDate?: string;
studyTime?: string;
studyDescription?: string;
series: Array<{
id: string;
seriesInstanceUid: string;
modality: string;
name: string;
files: Array<{ position: number; instanceUid: string }>;
}>;
}El objeto de estudio de tu app es compatible por asignación estructural (campos extra permitidos).
Notas
- Basado en la generación legacy de Cornerstone (v2); migración a Cornerstone3D prevista como fase posterior, sin cambios de API.
- El visor asigna dependencias a
window(cornerstone, hammerjs) al inicializarse — requerido por las libs legacy.
