3-ai-native-e2e-sample/frontend/src/components/molecule-viewer.tsx (56 lines of code) (raw):

"use client"; import React, { useEffect, useRef } from 'react'; // Access 3Dmol from window object since it's loaded via CDN declare global { interface Window { $3Dmol: { createViewer: (element: HTMLElement, options: { backgroundColor: string; id: string }) => Viewer; }; } interface Viewer { addModel: (data: string, format: string) => Model; zoomTo: () => void; render: () => void; clear: () => void; } interface Model { setStyle: (style: { stick: object }) => void; } } interface MoleculeViewerProps { smiles: string; width?: string; height?: string; style?: React.CSSProperties; className?: string; } export function MoleculeViewer({ smiles, width = '100%', height = '400px', style, className, }: MoleculeViewerProps) { const viewerRef = useRef<HTMLDivElement>(null); const viewerInstanceRef = useRef<Viewer | null>(null); useEffect(() => { if (!viewerRef.current || !smiles || !window.$3Dmol) return; const viewer = window.$3Dmol.createViewer(viewerRef.current, { backgroundColor: 'black', id: `viewer-${Math.random()}`, }); viewerInstanceRef.current = viewer; const mol = viewer.addModel(smiles, "smi"); mol.setStyle({stick: {}}); viewer.zoomTo(); viewer.render(); return () => { if (viewerInstanceRef.current) { viewerInstanceRef.current.clear(); } }; }, [smiles]); return ( <div ref={viewerRef} style={{ width, height, ...style }} className={className} /> ); }