molstar
Version:
A comprehensive macromolecular library.
91 lines (90 loc) • 5.88 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { BehaviorSubject, distinctUntilChanged, map } from 'rxjs';
import { PluginComponent } from '../../../mol-plugin-state/component';
import { getMVSStoriesContext } from '../context';
import Markdown from 'react-markdown';
import { useBehavior } from '../../../mol-plugin-ui/hooks/use-behavior';
import { createRoot } from 'react-dom/client';
import { MarkdownAnchor } from '../../../mol-plugin-ui/controls';
import { PluginReactContext } from '../../../mol-plugin-ui/base';
export class MVSStoriesSnapshotMarkdownModel extends PluginComponent {
get viewer() {
var _a;
return (_a = this.context.state.viewers.value) === null || _a === void 0 ? void 0 : _a.find(v => { var _a; return ((_a = this.options) === null || _a === void 0 ? void 0 : _a.viewerName) === v.name; });
}
sync() {
var _a, _b, _c;
const mng = (_b = (_a = this.viewer) === null || _a === void 0 ? void 0 : _a.model.plugin) === null || _b === void 0 ? void 0 : _b.managers.snapshot;
this.state.next({
entry: mng === null || mng === void 0 ? void 0 : mng.current,
index: (mng === null || mng === void 0 ? void 0 : mng.current) ? mng === null || mng === void 0 ? void 0 : mng.getIndex(mng.current) : undefined,
all: (_c = mng === null || mng === void 0 ? void 0 : mng.state.entries.toArray()) !== null && _c !== void 0 ? _c : [],
});
}
async mount(root) {
this.root = root;
createRoot(root).render(_jsx(MVSStoriesSnapshotMarkdownUI, { model: this }));
let currentViewer = undefined;
let sub = undefined;
this.subscribe(this.context.state.viewers.pipe(map(xs => xs.find(v => { var _a; return ((_a = this.options) === null || _a === void 0 ? void 0 : _a.viewerName) === v.name; })), distinctUntilChanged((a, b) => (a === null || a === void 0 ? void 0 : a.model) === (b === null || b === void 0 ? void 0 : b.model))), viewer => {
var _a;
if (currentViewer !== viewer) {
currentViewer = viewer === null || viewer === void 0 ? void 0 : viewer.model;
sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
}
if (!viewer)
return;
sub = this.subscribe((_a = viewer.model.plugin) === null || _a === void 0 ? void 0 : _a.managers.snapshot.events.changed, () => {
this.sync();
});
this.sync();
});
this.sync();
}
constructor(options) {
super();
this.options = options;
this.root = undefined;
this.state = new BehaviorSubject({ all: [] });
this.context = getMVSStoriesContext(options === null || options === void 0 ? void 0 : options.context);
}
}
export function MVSStoriesSnapshotMarkdownUI({ model }) {
var _a, _b, _c;
const state = useBehavior(model.state);
const isLoading = useBehavior(model.context.state.isLoading);
const style = { display: 'flex', flexDirection: 'column', height: '100%' };
const className = 'mvs-stories-markdown-explanation';
if (isLoading) {
return _jsx("div", { style: style, className: className, children: _jsx("i", { children: "Loading..." }) });
}
if (state.all.length === 0) {
return _jsx("div", { style: style, className: className, children: _jsx("i", { children: "No snapshot loaded or no description available" }) });
}
return _jsxs("div", { style: style, className: className, children: [_jsxs("div", { style: { display: 'flex', flexDirection: 'row', width: '100%', gap: '8px' }, children: [_jsxs("span", { style: { lineHeight: '38px', minWidth: 60, maxWidth: 60, flexShrink: 0 }, children: [typeof state.index === 'number' ? state.index + 1 : '-', "/", state.all.length] }), _jsx("button", { onClick: () => { var _a, _b; return (_b = (_a = model.viewer) === null || _a === void 0 ? void 0 : _a.model.plugin) === null || _b === void 0 ? void 0 : _b.managers.snapshot.applyNext(-1); }, style: { flexGrow: 1, flexShrink: 0 }, children: "Prev" }), _jsx("button", { onClick: () => { var _a, _b; return (_b = (_a = model.viewer) === null || _a === void 0 ? void 0 : _a.model.plugin) === null || _b === void 0 ? void 0 : _b.managers.snapshot.applyNext(1); }, style: { flexGrow: 1, flexShrink: 0 }, children: "Next" })] }), _jsx("div", { style: { flexGrow: 1, overflow: 'hidden', overflowY: 'auto', position: 'relative' }, children: _jsx("div", { style: { position: 'absolute', inset: 0 }, children: _jsx(PluginReactContext.Provider, { value: (_a = model.viewer) === null || _a === void 0 ? void 0 : _a.model.plugin, children: _jsx(Markdown, { skipHtml: true, components: { a: MarkdownAnchor }, children: (_c = (_b = state.entry) === null || _b === void 0 ? void 0 : _b.description) !== null && _c !== void 0 ? _c : 'Description not available' }) }) }) })] });
}
export class MVSStoriesSnapshotMarkdownViewer extends HTMLElement {
async connectedCallback() {
var _a, _b;
this.model = new MVSStoriesSnapshotMarkdownModel({
context: { name: (_a = this.getAttribute('context-name')) !== null && _a !== void 0 ? _a : undefined },
viewerName: (_b = this.getAttribute('viewer-name')) !== null && _b !== void 0 ? _b : undefined,
});
await this.model.mount(this);
}
disconnectedCallback() {
var _a;
(_a = this.model) === null || _a === void 0 ? void 0 : _a.dispose();
this.model = undefined;
}
constructor() {
super();
this.model = undefined;
}
}
window.customElements.define('mvs-stories-snapshot-markdown', MVSStoriesSnapshotMarkdownViewer);