molstar
Version:
A comprehensive macromolecular library.
145 lines (144 loc) • 6.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefaultMarkdownExtensionRenderers = void 0;
exports.Markdown = Markdown;
exports.MarkdownAudioPlayer = MarkdownAudioPlayer;
exports.MarkdownImg = MarkdownImg;
exports.MarkdownAnchor = MarkdownAnchor;
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
/**
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
const react_1 = require("react");
const react_markdown_1 = tslib_1.__importDefault(require("react-markdown"));
const remark_gfm_1 = tslib_1.__importDefault(require("remark-gfm"));
const base_1 = require("../base.js");
const lists_1 = require("../../mol-util/color/lists.js");
const utils_1 = require("../../mol-util/color/utils.js");
const use_behavior_1 = require("../hooks/use-behavior.js");
function Markdown({ children, components }) {
return (0, jsx_runtime_1.jsxs)("div", { className: 'msp-markdown', children: [(0, jsx_runtime_1.jsx)(MarkdownAudioPlayer, {}), (0, jsx_runtime_1.jsx)(react_markdown_1.default, { skipHtml: true, components: { a: MarkdownAnchor, img: MarkdownImg, ...components }, remarkPlugins: [remark_gfm_1.default], children: children })] });
}
function MarkdownAudioPlayer() {
const parent = (0, react_1.useRef)(null);
const plugin = (0, react_1.useContext)(base_1.PluginReactContext);
const audio = (0, use_behavior_1.useBehavior)(plugin === null || plugin === void 0 ? void 0 : plugin.managers.markdownExtensions.state.audioPlayer);
(0, react_1.useEffect)(() => {
if (!parent.current)
return;
parent.current.appendChild(audio);
return () => { audio === null || audio === void 0 ? void 0 : audio.remove(); };
}, [audio]);
if (!audio)
return null;
return (0, jsx_runtime_1.jsx)("div", { className: 'msp-markdown-audio-player', ref: parent });
}
function MarkdownImg({ src, element, alt }) {
const plugin = (0, react_1.useContext)(base_1.PluginReactContext);
if (!src)
return element;
warnMissingPlugin(plugin);
const args = plugin === null || plugin === void 0 ? void 0 : plugin.managers.markdownExtensions.parseArgs(src);
if (args) {
const result = plugin === null || plugin === void 0 ? void 0 : plugin.managers.markdownExtensions.tryRender(args, exports.DefaultMarkdownExtensionRenderers);
return result !== null && result !== void 0 ? result : element;
}
else {
const data = plugin === null || plugin === void 0 ? void 0 : plugin.managers.markdownExtensions.tryResolveUri(src);
if (typeof (data === null || data === void 0 ? void 0 : data.then) === 'function') {
return (0, jsx_runtime_1.jsx)(LazyStaticImg, { alt: alt, data: data });
}
else if (typeof data === 'string' && data) {
return (0, jsx_runtime_1.jsx)("img", { src: data, alt: alt });
}
}
return (0, jsx_runtime_1.jsx)("img", { src: src, alt: alt });
}
function LazyStaticImg({ alt, data }) {
const [src, setSrc] = (0, react_1.useState)(undefined);
(0, react_1.useEffect)(() => {
let mounted = true;
data.then(d => {
if (mounted)
setSrc(d);
}).catch(e => {
console.error('Failed to load static image', e);
if (mounted)
setSrc(undefined);
});
return () => { mounted = false; };
}, [data]);
if (!src)
return null;
return (0, jsx_runtime_1.jsx)("img", { src: src, alt: alt });
}
exports.DefaultMarkdownExtensionRenderers = [
{
name: 'color-swatch',
reactRenderFn: ({ args }) => {
const color = args['color-swatch'];
if (!color)
return null;
return (0, jsx_runtime_1.jsx)("span", { style: { display: 'inline-block', width: '0.75em', height: '0.75em', backgroundColor: color, borderRadius: '25%' } });
}
},
{
name: 'color-palette',
reactRenderFn: ({ args }) => {
var _a, _b, _c;
const name = args['color-palette-name'];
const colors = args['color-palette-colors'];
const minWidth = (_a = args['color-palette-width']) !== null && _a !== void 0 ? _a : '150px';
const height = (_b = args['color-palette-height']) !== null && _b !== void 0 ? _b : '0.5em';
const discrete = 'color-palette-discrete' in args;
if (!name && !colors)
return null;
const list = colors
? (0, utils_1.parseColorList)(colors)
: (_c = lists_1.ColorLists[name.toLowerCase()]) === null || _c === void 0 ? void 0 : _c.list;
if (!(list === null || list === void 0 ? void 0 : list.length)) {
console.warn(`Color palette could not be resolved.`, args);
return null;
}
return (0, jsx_runtime_1.jsx)("span", { style: {
display: 'inline-block',
minWidth,
height,
background: (discrete ? utils_1.getColorGradientBanded : utils_1.getColorGradient)(list),
borderRadius: '2px'
} });
}
}
];
function MarkdownAnchor({ href, children, element }) {
const plugin = (0, react_1.useContext)(base_1.PluginReactContext);
if (!href)
return element;
warnMissingPlugin(plugin);
const args = plugin === null || plugin === void 0 ? void 0 : plugin.managers.markdownExtensions.parseArgs(href);
if (args) {
return (0, jsx_runtime_1.jsx)("a", { href: '#', onClick: (e) => {
e.preventDefault();
plugin === null || plugin === void 0 ? void 0 : plugin.managers.markdownExtensions.tryExecute('click', args);
}, onMouseEnter: () => plugin === null || plugin === void 0 ? void 0 : plugin.managers.markdownExtensions.tryExecute('mouse-enter', args), onMouseLeave: () => plugin === null || plugin === void 0 ? void 0 : plugin.managers.markdownExtensions.tryExecute('mouse-leave', args), children: children });
}
else if (href[0] === '#') {
warnMissingPlugin(plugin);
return (0, jsx_runtime_1.jsx)("a", { href: '#', onClick: (e) => {
e.preventDefault();
plugin === null || plugin === void 0 ? void 0 : plugin.managers.snapshot.applyKey(href.substring(1));
}, children: children });
}
else if (href) {
return (0, jsx_runtime_1.jsxs)("a", { href: href, target: '_blank', rel: 'noopener noreferrer', children: [children, "\u2934"] });
}
return children;
}
function warnMissingPlugin(plugin) {
if (plugin)
return;
console.warn('Markdown component requires a PluginReactContext to be set.');
}