@e-infra/react-molstar-wrapper 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +94 -0
- package/dist/index.cjs.js +1258 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.cjs2.js +8 -0
- package/dist/index.cjs2.js.map +1 -0
- package/dist/index.cjs3.js +8 -0
- package/dist/index.cjs3.js.map +1 -0
- package/dist/index.es.js +1258 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.es2.js +8 -0
- package/dist/index.es2.js.map +1 -0
- package/dist/index.es3.js +8 -0
- package/dist/index.es3.js.map +1 -0
- package/dist/react-molstar-wrapper.css +32 -0
- package/dist/types/components.d.ts +2 -0
- package/dist/types/core/Manager.d.ts +19 -0
- package/dist/types/core/Manager.d.ts.map +1 -0
- package/dist/types/core/Plugin.d.ts +26 -0
- package/dist/types/core/Plugin.d.ts.map +1 -0
- package/dist/types/core/exceptions.d.ts +8 -0
- package/dist/types/core/exceptions.d.ts.map +1 -0
- package/dist/types/core/tree/chopping.d.ts +13 -0
- package/dist/types/core/tree/chopping.d.ts.map +1 -0
- package/dist/types/core/tree/colors.d.ts +14 -0
- package/dist/types/core/tree/colors.d.ts.map +1 -0
- package/dist/types/core/tree/create-mvs.d.ts +6 -0
- package/dist/types/core/tree/create-mvs.d.ts.map +1 -0
- package/dist/types/core/tree/index.d.ts +2 -0
- package/dist/types/core/tree/index.d.ts.map +1 -0
- package/dist/types/core/tree/rendering.d.ts +6 -0
- package/dist/types/core/tree/rendering.d.ts.map +1 -0
- package/dist/types/core/tree/selectors.d.ts +34 -0
- package/dist/types/core/tree/selectors.d.ts.map +1 -0
- package/dist/types/core/types.d.ts +44 -0
- package/dist/types/core/types.d.ts.map +1 -0
- package/dist/types/hooks.d.ts +2 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/react/ErrorView.d.ts +2 -0
- package/dist/types/react/ErrorView.d.ts.map +1 -0
- package/dist/types/react/LoaderView.d.ts +2 -0
- package/dist/types/react/LoaderView.d.ts.map +1 -0
- package/dist/types/react/Viewer.d.ts +86 -0
- package/dist/types/react/Viewer.d.ts.map +1 -0
- package/dist/types/react/types.d.ts +49 -0
- package/dist/types/react/types.d.ts.map +1 -0
- package/package.json +85 -0
package/dist/index.es.js
ADDED
|
@@ -0,0 +1,1258 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import require$$0, { forwardRef, useRef, useState, useId, useEffect, useImperativeHandle } from "react";
|
|
3
|
+
import "molstar/lib/mol-plugin-ui/skin/light.scss";
|
|
4
|
+
import { loadMVSData } from "molstar/lib/extensions/mvs/components/formats";
|
|
5
|
+
import { Color } from "molstar/lib/mol-util/color";
|
|
6
|
+
import { createPluginUI } from "molstar/lib/mol-plugin-ui";
|
|
7
|
+
import { renderReact18 } from "molstar/lib/mol-plugin-ui/react18";
|
|
8
|
+
import { PluginSpec } from "molstar/lib/mol-plugin/spec";
|
|
9
|
+
import { MolViewSpec } from "molstar/lib/extensions/mvs/behavior";
|
|
10
|
+
import { DefaultPluginUISpec } from "molstar/lib/mol-plugin-ui/spec";
|
|
11
|
+
import { Mat4, Vec3 } from "molstar/lib/mol-math/linear-algebra";
|
|
12
|
+
import { PluginStateObject } from "molstar/lib/mol-plugin-state/objects";
|
|
13
|
+
import { Script } from "molstar/lib/mol-script/script";
|
|
14
|
+
import { StructureSelection, StructureElement } from "molstar/lib/mol-model/structure";
|
|
15
|
+
import { StateTransforms } from "molstar/lib/mol-plugin-state/transforms";
|
|
16
|
+
import { createMVSBuilder } from "molstar/lib/extensions/mvs/tree/mvs/mvs-builder";
|
|
17
|
+
var jsxRuntime = { exports: {} };
|
|
18
|
+
var reactJsxRuntime_production = {};
|
|
19
|
+
var hasRequiredReactJsxRuntime_production;
|
|
20
|
+
function requireReactJsxRuntime_production() {
|
|
21
|
+
if (hasRequiredReactJsxRuntime_production) return reactJsxRuntime_production;
|
|
22
|
+
hasRequiredReactJsxRuntime_production = 1;
|
|
23
|
+
var REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element"), REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment");
|
|
24
|
+
function jsxProd(type, config, maybeKey) {
|
|
25
|
+
var key = null;
|
|
26
|
+
void 0 !== maybeKey && (key = "" + maybeKey);
|
|
27
|
+
void 0 !== config.key && (key = "" + config.key);
|
|
28
|
+
if ("key" in config) {
|
|
29
|
+
maybeKey = {};
|
|
30
|
+
for (var propName in config)
|
|
31
|
+
"key" !== propName && (maybeKey[propName] = config[propName]);
|
|
32
|
+
} else maybeKey = config;
|
|
33
|
+
config = maybeKey.ref;
|
|
34
|
+
return {
|
|
35
|
+
$$typeof: REACT_ELEMENT_TYPE,
|
|
36
|
+
type,
|
|
37
|
+
key,
|
|
38
|
+
ref: void 0 !== config ? config : null,
|
|
39
|
+
props: maybeKey
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
reactJsxRuntime_production.Fragment = REACT_FRAGMENT_TYPE;
|
|
43
|
+
reactJsxRuntime_production.jsx = jsxProd;
|
|
44
|
+
reactJsxRuntime_production.jsxs = jsxProd;
|
|
45
|
+
return reactJsxRuntime_production;
|
|
46
|
+
}
|
|
47
|
+
var reactJsxRuntime_development = {};
|
|
48
|
+
var hasRequiredReactJsxRuntime_development;
|
|
49
|
+
function requireReactJsxRuntime_development() {
|
|
50
|
+
if (hasRequiredReactJsxRuntime_development) return reactJsxRuntime_development;
|
|
51
|
+
hasRequiredReactJsxRuntime_development = 1;
|
|
52
|
+
"production" !== process.env.NODE_ENV && (function() {
|
|
53
|
+
function getComponentNameFromType(type) {
|
|
54
|
+
if (null == type) return null;
|
|
55
|
+
if ("function" === typeof type)
|
|
56
|
+
return type.$$typeof === REACT_CLIENT_REFERENCE ? null : type.displayName || type.name || null;
|
|
57
|
+
if ("string" === typeof type) return type;
|
|
58
|
+
switch (type) {
|
|
59
|
+
case REACT_FRAGMENT_TYPE:
|
|
60
|
+
return "Fragment";
|
|
61
|
+
case REACT_PROFILER_TYPE:
|
|
62
|
+
return "Profiler";
|
|
63
|
+
case REACT_STRICT_MODE_TYPE:
|
|
64
|
+
return "StrictMode";
|
|
65
|
+
case REACT_SUSPENSE_TYPE:
|
|
66
|
+
return "Suspense";
|
|
67
|
+
case REACT_SUSPENSE_LIST_TYPE:
|
|
68
|
+
return "SuspenseList";
|
|
69
|
+
case REACT_ACTIVITY_TYPE:
|
|
70
|
+
return "Activity";
|
|
71
|
+
}
|
|
72
|
+
if ("object" === typeof type)
|
|
73
|
+
switch ("number" === typeof type.tag && console.error(
|
|
74
|
+
"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
|
|
75
|
+
), type.$$typeof) {
|
|
76
|
+
case REACT_PORTAL_TYPE:
|
|
77
|
+
return "Portal";
|
|
78
|
+
case REACT_CONTEXT_TYPE:
|
|
79
|
+
return type.displayName || "Context";
|
|
80
|
+
case REACT_CONSUMER_TYPE:
|
|
81
|
+
return (type._context.displayName || "Context") + ".Consumer";
|
|
82
|
+
case REACT_FORWARD_REF_TYPE:
|
|
83
|
+
var innerType = type.render;
|
|
84
|
+
type = type.displayName;
|
|
85
|
+
type || (type = innerType.displayName || innerType.name || "", type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef");
|
|
86
|
+
return type;
|
|
87
|
+
case REACT_MEMO_TYPE:
|
|
88
|
+
return innerType = type.displayName || null, null !== innerType ? innerType : getComponentNameFromType(type.type) || "Memo";
|
|
89
|
+
case REACT_LAZY_TYPE:
|
|
90
|
+
innerType = type._payload;
|
|
91
|
+
type = type._init;
|
|
92
|
+
try {
|
|
93
|
+
return getComponentNameFromType(type(innerType));
|
|
94
|
+
} catch (x) {
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
function testStringCoercion(value) {
|
|
100
|
+
return "" + value;
|
|
101
|
+
}
|
|
102
|
+
function checkKeyStringCoercion(value) {
|
|
103
|
+
try {
|
|
104
|
+
testStringCoercion(value);
|
|
105
|
+
var JSCompiler_inline_result = false;
|
|
106
|
+
} catch (e) {
|
|
107
|
+
JSCompiler_inline_result = true;
|
|
108
|
+
}
|
|
109
|
+
if (JSCompiler_inline_result) {
|
|
110
|
+
JSCompiler_inline_result = console;
|
|
111
|
+
var JSCompiler_temp_const = JSCompiler_inline_result.error;
|
|
112
|
+
var JSCompiler_inline_result$jscomp$0 = "function" === typeof Symbol && Symbol.toStringTag && value[Symbol.toStringTag] || value.constructor.name || "Object";
|
|
113
|
+
JSCompiler_temp_const.call(
|
|
114
|
+
JSCompiler_inline_result,
|
|
115
|
+
"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
|
|
116
|
+
JSCompiler_inline_result$jscomp$0
|
|
117
|
+
);
|
|
118
|
+
return testStringCoercion(value);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function getTaskName(type) {
|
|
122
|
+
if (type === REACT_FRAGMENT_TYPE) return "<>";
|
|
123
|
+
if ("object" === typeof type && null !== type && type.$$typeof === REACT_LAZY_TYPE)
|
|
124
|
+
return "<...>";
|
|
125
|
+
try {
|
|
126
|
+
var name = getComponentNameFromType(type);
|
|
127
|
+
return name ? "<" + name + ">" : "<...>";
|
|
128
|
+
} catch (x) {
|
|
129
|
+
return "<...>";
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function getOwner() {
|
|
133
|
+
var dispatcher = ReactSharedInternals.A;
|
|
134
|
+
return null === dispatcher ? null : dispatcher.getOwner();
|
|
135
|
+
}
|
|
136
|
+
function UnknownOwner() {
|
|
137
|
+
return Error("react-stack-top-frame");
|
|
138
|
+
}
|
|
139
|
+
function hasValidKey(config) {
|
|
140
|
+
if (hasOwnProperty.call(config, "key")) {
|
|
141
|
+
var getter = Object.getOwnPropertyDescriptor(config, "key").get;
|
|
142
|
+
if (getter && getter.isReactWarning) return false;
|
|
143
|
+
}
|
|
144
|
+
return void 0 !== config.key;
|
|
145
|
+
}
|
|
146
|
+
function defineKeyPropWarningGetter(props, displayName) {
|
|
147
|
+
function warnAboutAccessingKey() {
|
|
148
|
+
specialPropKeyWarningShown || (specialPropKeyWarningShown = true, console.error(
|
|
149
|
+
"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
|
|
150
|
+
displayName
|
|
151
|
+
));
|
|
152
|
+
}
|
|
153
|
+
warnAboutAccessingKey.isReactWarning = true;
|
|
154
|
+
Object.defineProperty(props, "key", {
|
|
155
|
+
get: warnAboutAccessingKey,
|
|
156
|
+
configurable: true
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
function elementRefGetterWithDeprecationWarning() {
|
|
160
|
+
var componentName = getComponentNameFromType(this.type);
|
|
161
|
+
didWarnAboutElementRef[componentName] || (didWarnAboutElementRef[componentName] = true, console.error(
|
|
162
|
+
"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
|
|
163
|
+
));
|
|
164
|
+
componentName = this.props.ref;
|
|
165
|
+
return void 0 !== componentName ? componentName : null;
|
|
166
|
+
}
|
|
167
|
+
function ReactElement(type, key, props, owner, debugStack, debugTask) {
|
|
168
|
+
var refProp = props.ref;
|
|
169
|
+
type = {
|
|
170
|
+
$$typeof: REACT_ELEMENT_TYPE,
|
|
171
|
+
type,
|
|
172
|
+
key,
|
|
173
|
+
props,
|
|
174
|
+
_owner: owner
|
|
175
|
+
};
|
|
176
|
+
null !== (void 0 !== refProp ? refProp : null) ? Object.defineProperty(type, "ref", {
|
|
177
|
+
enumerable: false,
|
|
178
|
+
get: elementRefGetterWithDeprecationWarning
|
|
179
|
+
}) : Object.defineProperty(type, "ref", { enumerable: false, value: null });
|
|
180
|
+
type._store = {};
|
|
181
|
+
Object.defineProperty(type._store, "validated", {
|
|
182
|
+
configurable: false,
|
|
183
|
+
enumerable: false,
|
|
184
|
+
writable: true,
|
|
185
|
+
value: 0
|
|
186
|
+
});
|
|
187
|
+
Object.defineProperty(type, "_debugInfo", {
|
|
188
|
+
configurable: false,
|
|
189
|
+
enumerable: false,
|
|
190
|
+
writable: true,
|
|
191
|
+
value: null
|
|
192
|
+
});
|
|
193
|
+
Object.defineProperty(type, "_debugStack", {
|
|
194
|
+
configurable: false,
|
|
195
|
+
enumerable: false,
|
|
196
|
+
writable: true,
|
|
197
|
+
value: debugStack
|
|
198
|
+
});
|
|
199
|
+
Object.defineProperty(type, "_debugTask", {
|
|
200
|
+
configurable: false,
|
|
201
|
+
enumerable: false,
|
|
202
|
+
writable: true,
|
|
203
|
+
value: debugTask
|
|
204
|
+
});
|
|
205
|
+
Object.freeze && (Object.freeze(type.props), Object.freeze(type));
|
|
206
|
+
return type;
|
|
207
|
+
}
|
|
208
|
+
function jsxDEVImpl(type, config, maybeKey, isStaticChildren, debugStack, debugTask) {
|
|
209
|
+
var children = config.children;
|
|
210
|
+
if (void 0 !== children)
|
|
211
|
+
if (isStaticChildren)
|
|
212
|
+
if (isArrayImpl(children)) {
|
|
213
|
+
for (isStaticChildren = 0; isStaticChildren < children.length; isStaticChildren++)
|
|
214
|
+
validateChildKeys(children[isStaticChildren]);
|
|
215
|
+
Object.freeze && Object.freeze(children);
|
|
216
|
+
} else
|
|
217
|
+
console.error(
|
|
218
|
+
"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
|
|
219
|
+
);
|
|
220
|
+
else validateChildKeys(children);
|
|
221
|
+
if (hasOwnProperty.call(config, "key")) {
|
|
222
|
+
children = getComponentNameFromType(type);
|
|
223
|
+
var keys = Object.keys(config).filter(function(k) {
|
|
224
|
+
return "key" !== k;
|
|
225
|
+
});
|
|
226
|
+
isStaticChildren = 0 < keys.length ? "{key: someKey, " + keys.join(": ..., ") + ": ...}" : "{key: someKey}";
|
|
227
|
+
didWarnAboutKeySpread[children + isStaticChildren] || (keys = 0 < keys.length ? "{" + keys.join(": ..., ") + ": ...}" : "{}", console.error(
|
|
228
|
+
'A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />',
|
|
229
|
+
isStaticChildren,
|
|
230
|
+
children,
|
|
231
|
+
keys,
|
|
232
|
+
children
|
|
233
|
+
), didWarnAboutKeySpread[children + isStaticChildren] = true);
|
|
234
|
+
}
|
|
235
|
+
children = null;
|
|
236
|
+
void 0 !== maybeKey && (checkKeyStringCoercion(maybeKey), children = "" + maybeKey);
|
|
237
|
+
hasValidKey(config) && (checkKeyStringCoercion(config.key), children = "" + config.key);
|
|
238
|
+
if ("key" in config) {
|
|
239
|
+
maybeKey = {};
|
|
240
|
+
for (var propName in config)
|
|
241
|
+
"key" !== propName && (maybeKey[propName] = config[propName]);
|
|
242
|
+
} else maybeKey = config;
|
|
243
|
+
children && defineKeyPropWarningGetter(
|
|
244
|
+
maybeKey,
|
|
245
|
+
"function" === typeof type ? type.displayName || type.name || "Unknown" : type
|
|
246
|
+
);
|
|
247
|
+
return ReactElement(
|
|
248
|
+
type,
|
|
249
|
+
children,
|
|
250
|
+
maybeKey,
|
|
251
|
+
getOwner(),
|
|
252
|
+
debugStack,
|
|
253
|
+
debugTask
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
function validateChildKeys(node) {
|
|
257
|
+
isValidElement(node) ? node._store && (node._store.validated = 1) : "object" === typeof node && null !== node && node.$$typeof === REACT_LAZY_TYPE && ("fulfilled" === node._payload.status ? isValidElement(node._payload.value) && node._payload.value._store && (node._payload.value._store.validated = 1) : node._store && (node._store.validated = 1));
|
|
258
|
+
}
|
|
259
|
+
function isValidElement(object) {
|
|
260
|
+
return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE;
|
|
261
|
+
}
|
|
262
|
+
var React = require$$0, REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = /* @__PURE__ */ Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = /* @__PURE__ */ Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = /* @__PURE__ */ Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = /* @__PURE__ */ Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = /* @__PURE__ */ Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = /* @__PURE__ */ Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = /* @__PURE__ */ Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = /* @__PURE__ */ Symbol.for("react.memo"), REACT_LAZY_TYPE = /* @__PURE__ */ Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = /* @__PURE__ */ Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = /* @__PURE__ */ Symbol.for("react.client.reference"), ReactSharedInternals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
|
|
263
|
+
return null;
|
|
264
|
+
};
|
|
265
|
+
React = {
|
|
266
|
+
react_stack_bottom_frame: function(callStackForError) {
|
|
267
|
+
return callStackForError();
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
var specialPropKeyWarningShown;
|
|
271
|
+
var didWarnAboutElementRef = {};
|
|
272
|
+
var unknownOwnerDebugStack = React.react_stack_bottom_frame.bind(
|
|
273
|
+
React,
|
|
274
|
+
UnknownOwner
|
|
275
|
+
)();
|
|
276
|
+
var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
|
|
277
|
+
var didWarnAboutKeySpread = {};
|
|
278
|
+
reactJsxRuntime_development.Fragment = REACT_FRAGMENT_TYPE;
|
|
279
|
+
reactJsxRuntime_development.jsx = function(type, config, maybeKey) {
|
|
280
|
+
var trackActualOwner = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
|
|
281
|
+
return jsxDEVImpl(
|
|
282
|
+
type,
|
|
283
|
+
config,
|
|
284
|
+
maybeKey,
|
|
285
|
+
false,
|
|
286
|
+
trackActualOwner ? Error("react-stack-top-frame") : unknownOwnerDebugStack,
|
|
287
|
+
trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask
|
|
288
|
+
);
|
|
289
|
+
};
|
|
290
|
+
reactJsxRuntime_development.jsxs = function(type, config, maybeKey) {
|
|
291
|
+
var trackActualOwner = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
|
|
292
|
+
return jsxDEVImpl(
|
|
293
|
+
type,
|
|
294
|
+
config,
|
|
295
|
+
maybeKey,
|
|
296
|
+
true,
|
|
297
|
+
trackActualOwner ? Error("react-stack-top-frame") : unknownOwnerDebugStack,
|
|
298
|
+
trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask
|
|
299
|
+
);
|
|
300
|
+
};
|
|
301
|
+
})();
|
|
302
|
+
return reactJsxRuntime_development;
|
|
303
|
+
}
|
|
304
|
+
var hasRequiredJsxRuntime;
|
|
305
|
+
function requireJsxRuntime() {
|
|
306
|
+
if (hasRequiredJsxRuntime) return jsxRuntime.exports;
|
|
307
|
+
hasRequiredJsxRuntime = 1;
|
|
308
|
+
if (process.env.NODE_ENV === "production") {
|
|
309
|
+
jsxRuntime.exports = requireReactJsxRuntime_production();
|
|
310
|
+
} else {
|
|
311
|
+
jsxRuntime.exports = requireReactJsxRuntime_development();
|
|
312
|
+
}
|
|
313
|
+
return jsxRuntime.exports;
|
|
314
|
+
}
|
|
315
|
+
var jsxRuntimeExports = requireJsxRuntime();
|
|
316
|
+
function LoaderView() {
|
|
317
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
318
|
+
"div",
|
|
319
|
+
{
|
|
320
|
+
style: {
|
|
321
|
+
position: "absolute",
|
|
322
|
+
top: 0,
|
|
323
|
+
left: 0,
|
|
324
|
+
width: "100%",
|
|
325
|
+
height: "100%",
|
|
326
|
+
backdropFilter: "blur(5px)",
|
|
327
|
+
backgroundColor: "#0000000A"
|
|
328
|
+
},
|
|
329
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
330
|
+
"div",
|
|
331
|
+
{
|
|
332
|
+
style: {
|
|
333
|
+
position: "absolute",
|
|
334
|
+
top: "50%",
|
|
335
|
+
left: "50%",
|
|
336
|
+
transform: "translate(-50%, -50%)",
|
|
337
|
+
display: "flex",
|
|
338
|
+
flexDirection: "column",
|
|
339
|
+
alignItems: "center",
|
|
340
|
+
gap: "1rem"
|
|
341
|
+
},
|
|
342
|
+
children: [
|
|
343
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
344
|
+
"div",
|
|
345
|
+
{
|
|
346
|
+
style: {
|
|
347
|
+
width: "48px",
|
|
348
|
+
height: "48px",
|
|
349
|
+
border: "6px solid #e5e7eb",
|
|
350
|
+
borderTopColor: "#3b82f6",
|
|
351
|
+
borderRadius: "50%",
|
|
352
|
+
animation: "spin 0.8s linear infinite"
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
),
|
|
356
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
357
|
+
"p",
|
|
358
|
+
{
|
|
359
|
+
style: {
|
|
360
|
+
margin: 0,
|
|
361
|
+
fontSize: "0.875rem",
|
|
362
|
+
color: "#6b7280",
|
|
363
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
364
|
+
},
|
|
365
|
+
children: "Loading..."
|
|
366
|
+
}
|
|
367
|
+
),
|
|
368
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("style", { children: `
|
|
369
|
+
@keyframes spin {
|
|
370
|
+
to {
|
|
371
|
+
transform: rotate(360deg);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
` })
|
|
375
|
+
]
|
|
376
|
+
}
|
|
377
|
+
)
|
|
378
|
+
}
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
function ErrorView() {
|
|
382
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
383
|
+
"div",
|
|
384
|
+
{
|
|
385
|
+
style: {
|
|
386
|
+
position: "absolute",
|
|
387
|
+
top: 0,
|
|
388
|
+
left: 0,
|
|
389
|
+
width: "100%",
|
|
390
|
+
height: "100%",
|
|
391
|
+
backdropFilter: "blur(5px)",
|
|
392
|
+
backgroundColor: "#0000000A"
|
|
393
|
+
},
|
|
394
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
395
|
+
"div",
|
|
396
|
+
{
|
|
397
|
+
style: {
|
|
398
|
+
position: "absolute",
|
|
399
|
+
top: "50%",
|
|
400
|
+
left: "50%",
|
|
401
|
+
transform: "translate(-50%, -50%)",
|
|
402
|
+
display: "flex",
|
|
403
|
+
flexDirection: "column",
|
|
404
|
+
alignItems: "center",
|
|
405
|
+
gap: "0.75rem",
|
|
406
|
+
padding: "1.5rem"
|
|
407
|
+
},
|
|
408
|
+
children: [
|
|
409
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
410
|
+
"div",
|
|
411
|
+
{
|
|
412
|
+
style: {
|
|
413
|
+
width: "48px",
|
|
414
|
+
height: "48px",
|
|
415
|
+
borderRadius: "50%",
|
|
416
|
+
backgroundColor: "#fef2f2",
|
|
417
|
+
display: "flex",
|
|
418
|
+
alignItems: "center",
|
|
419
|
+
justifyContent: "center"
|
|
420
|
+
},
|
|
421
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
422
|
+
"svg",
|
|
423
|
+
{
|
|
424
|
+
width: "24",
|
|
425
|
+
height: "24",
|
|
426
|
+
viewBox: "0 0 24 24",
|
|
427
|
+
fill: "none",
|
|
428
|
+
stroke: "#ef4444",
|
|
429
|
+
strokeWidth: "2",
|
|
430
|
+
strokeLinecap: "round",
|
|
431
|
+
strokeLinejoin: "round",
|
|
432
|
+
"aria-label": "Error icon",
|
|
433
|
+
children: [
|
|
434
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("title", { children: "Error" }),
|
|
435
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
436
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
|
|
437
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
|
|
438
|
+
]
|
|
439
|
+
}
|
|
440
|
+
)
|
|
441
|
+
}
|
|
442
|
+
),
|
|
443
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { textAlign: "center" }, children: [
|
|
444
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
445
|
+
"p",
|
|
446
|
+
{
|
|
447
|
+
style: {
|
|
448
|
+
margin: 0,
|
|
449
|
+
fontSize: "0.875rem",
|
|
450
|
+
fontWeight: 600,
|
|
451
|
+
color: "#1f2937",
|
|
452
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
453
|
+
},
|
|
454
|
+
children: "Error loading viewer"
|
|
455
|
+
}
|
|
456
|
+
),
|
|
457
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
458
|
+
"p",
|
|
459
|
+
{
|
|
460
|
+
style: {
|
|
461
|
+
margin: "0.25rem 0 0 0",
|
|
462
|
+
fontSize: "0.75rem",
|
|
463
|
+
color: "#6b7280",
|
|
464
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
465
|
+
},
|
|
466
|
+
children: "Please try refreshing the page"
|
|
467
|
+
}
|
|
468
|
+
)
|
|
469
|
+
] })
|
|
470
|
+
]
|
|
471
|
+
}
|
|
472
|
+
)
|
|
473
|
+
}
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
class Plugin {
|
|
477
|
+
plugin;
|
|
478
|
+
objectUrls;
|
|
479
|
+
constructor(plugin) {
|
|
480
|
+
this.plugin = plugin;
|
|
481
|
+
this.objectUrls = /* @__PURE__ */ new Set();
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Create a Plugin by instantiating the underlying PluginUI.
|
|
485
|
+
* We use a static async factory because constructors cannot be async.
|
|
486
|
+
*/
|
|
487
|
+
static async create(container, initialUI) {
|
|
488
|
+
const defaultSpec = DefaultPluginUISpec();
|
|
489
|
+
if (!container.querySelector(".msp-plugin")) {
|
|
490
|
+
container.innerHTML = "";
|
|
491
|
+
}
|
|
492
|
+
const plugin = await createPluginUI({
|
|
493
|
+
target: container,
|
|
494
|
+
render: renderReact18,
|
|
495
|
+
spec: {
|
|
496
|
+
actions: defaultSpec.actions ?? [],
|
|
497
|
+
behaviors: [
|
|
498
|
+
...initialUI !== "minimal" ? defaultSpec.behaviors : [],
|
|
499
|
+
PluginSpec.Behavior(MolViewSpec)
|
|
500
|
+
],
|
|
501
|
+
animations: [...defaultSpec.animations || []],
|
|
502
|
+
layout: {
|
|
503
|
+
initial: {
|
|
504
|
+
showControls: initialUI === "expanded",
|
|
505
|
+
controlsDisplay: "reactive"
|
|
506
|
+
// isExpanded: false,
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
components: {
|
|
510
|
+
...defaultSpec.components
|
|
511
|
+
},
|
|
512
|
+
canvas3d: {
|
|
513
|
+
...defaultSpec.canvas3d,
|
|
514
|
+
camera: {
|
|
515
|
+
...defaultSpec.canvas3d?.camera,
|
|
516
|
+
helper: {
|
|
517
|
+
axes: initialUI === "minimal" ? {
|
|
518
|
+
name: "off",
|
|
519
|
+
params: {}
|
|
520
|
+
} : defaultSpec.canvas3d?.camera?.helper?.axes
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
return new Plugin(plugin);
|
|
527
|
+
}
|
|
528
|
+
dispose() {
|
|
529
|
+
this.plugin.dispose();
|
|
530
|
+
this.cleanupObjectUrls();
|
|
531
|
+
}
|
|
532
|
+
cleanupObjectUrls() {
|
|
533
|
+
for (const url of this.objectUrls) {
|
|
534
|
+
try {
|
|
535
|
+
URL.revokeObjectURL(url);
|
|
536
|
+
} catch (_e) {
|
|
537
|
+
}
|
|
538
|
+
this.objectUrls.delete(url);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
createObjectUrlFromFile(file) {
|
|
542
|
+
const url = URL.createObjectURL(file);
|
|
543
|
+
this.objectUrls.add(url);
|
|
544
|
+
return url;
|
|
545
|
+
}
|
|
546
|
+
clear() {
|
|
547
|
+
this.plugin.clear();
|
|
548
|
+
}
|
|
549
|
+
async loadMvs(mvs) {
|
|
550
|
+
return await loadMVSData(this.plugin, mvs, "mvsj");
|
|
551
|
+
}
|
|
552
|
+
setBackgroundColor(color) {
|
|
553
|
+
const hexString = color.replace("#", "0x");
|
|
554
|
+
this.plugin.canvas3d?.setProps({
|
|
555
|
+
renderer: { backgroundColor: Color.fromHexString(hexString) }
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
setAnimation(type, speed) {
|
|
559
|
+
if (type === "off") {
|
|
560
|
+
this.plugin.canvas3d?.setProps({
|
|
561
|
+
trackball: {
|
|
562
|
+
animate: {
|
|
563
|
+
name: "off",
|
|
564
|
+
params: {}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
const animationParams = type === "spin" ? {
|
|
571
|
+
speed: speed ?? 0.05
|
|
572
|
+
} : {
|
|
573
|
+
speed: speed ?? 0.2,
|
|
574
|
+
angle: 10
|
|
575
|
+
};
|
|
576
|
+
this.plugin.canvas3d?.setProps({
|
|
577
|
+
trackball: {
|
|
578
|
+
animate: {
|
|
579
|
+
name: type,
|
|
580
|
+
params: animationParams
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
async focusOnDomain(domainStart, domainEnd) {
|
|
586
|
+
const state = this.plugin.state.data;
|
|
587
|
+
const structures = state.selectQ(
|
|
588
|
+
(q) => q.rootsOfType(PluginStateObject.Molecule.Structure)
|
|
589
|
+
);
|
|
590
|
+
if (structures.length === 0) {
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
const structureCell = structures[0];
|
|
594
|
+
if (!structureCell?.obj) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
const structureData = structureCell.obj.data;
|
|
598
|
+
const selection = Script.getStructureSelection(
|
|
599
|
+
(Q) => Q.struct.generator.atomGroups({
|
|
600
|
+
"residue-test": Q.core.rel.inRange([
|
|
601
|
+
Q.struct.atomProperty.macromolecular.auth_seq_id(),
|
|
602
|
+
domainStart,
|
|
603
|
+
domainEnd
|
|
604
|
+
])
|
|
605
|
+
}),
|
|
606
|
+
structureData
|
|
607
|
+
);
|
|
608
|
+
const loci = StructureSelection.toLociWithSourceUnits(selection);
|
|
609
|
+
if (!StructureElement.Loci.isEmpty(loci)) {
|
|
610
|
+
await this.plugin.managers.camera.focusLoci(loci);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
async resetView() {
|
|
614
|
+
await this.plugin.managers.camera.reset();
|
|
615
|
+
}
|
|
616
|
+
async updateStructureTransform(structureIndex, translation, rotation) {
|
|
617
|
+
const state = this.plugin.state.data;
|
|
618
|
+
const structures = state.selectQ(
|
|
619
|
+
(q) => q.rootsOfType(PluginStateObject.Molecule.Structure)
|
|
620
|
+
);
|
|
621
|
+
if (structureIndex >= structures.length) {
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
const targetStructure = structures[structureIndex];
|
|
625
|
+
if (!targetStructure) {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
const allCells = state.selectQ((q) => q.root.subtree());
|
|
629
|
+
const transforms = allCells.filter(
|
|
630
|
+
(cell) => cell.transform.transformer === StateTransforms.Model.TransformStructureConformation
|
|
631
|
+
);
|
|
632
|
+
const targetTransform = transforms[structureIndex];
|
|
633
|
+
if (targetTransform) {
|
|
634
|
+
const matrix = Mat4.identity();
|
|
635
|
+
if (rotation) {
|
|
636
|
+
Mat4.setValue(matrix, 0, 0, rotation[0][0]);
|
|
637
|
+
Mat4.setValue(matrix, 0, 1, rotation[0][1]);
|
|
638
|
+
Mat4.setValue(matrix, 0, 2, rotation[0][2]);
|
|
639
|
+
Mat4.setValue(matrix, 1, 0, rotation[1][0]);
|
|
640
|
+
Mat4.setValue(matrix, 1, 1, rotation[1][1]);
|
|
641
|
+
Mat4.setValue(matrix, 1, 2, rotation[1][2]);
|
|
642
|
+
Mat4.setValue(matrix, 2, 0, rotation[2][0]);
|
|
643
|
+
Mat4.setValue(matrix, 2, 1, rotation[2][1]);
|
|
644
|
+
Mat4.setValue(matrix, 2, 2, rotation[2][2]);
|
|
645
|
+
}
|
|
646
|
+
if (translation) {
|
|
647
|
+
Mat4.setTranslation(
|
|
648
|
+
matrix,
|
|
649
|
+
Vec3.create(translation[0], translation[1], translation[2])
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
const update = state.build().to(targetTransform.transform.ref).update(
|
|
653
|
+
StateTransforms.Model.TransformStructureConformation,
|
|
654
|
+
(old) => ({
|
|
655
|
+
...old,
|
|
656
|
+
transform: {
|
|
657
|
+
name: "matrix",
|
|
658
|
+
params: {
|
|
659
|
+
data: matrix,
|
|
660
|
+
transpose: false
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
})
|
|
664
|
+
);
|
|
665
|
+
await this.plugin.runTask(state.updateTree(update));
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
getPluginContext() {
|
|
669
|
+
return this.plugin;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
const PLUGIN_GC_TIMEOUT = 30 * 1e3;
|
|
673
|
+
class Manager {
|
|
674
|
+
static instance;
|
|
675
|
+
initializatingContainers;
|
|
676
|
+
plugins;
|
|
677
|
+
refCount;
|
|
678
|
+
// [count, lastUsedTimestamp]
|
|
679
|
+
timer;
|
|
680
|
+
constructor() {
|
|
681
|
+
this.initializatingContainers = /* @__PURE__ */ new Set();
|
|
682
|
+
this.plugins = /* @__PURE__ */ new Map();
|
|
683
|
+
this.refCount = /* @__PURE__ */ new Map();
|
|
684
|
+
this.timer = void 0;
|
|
685
|
+
this.initGC();
|
|
686
|
+
}
|
|
687
|
+
static getInstance() {
|
|
688
|
+
if (!Manager.instance) {
|
|
689
|
+
Manager.instance = new Manager();
|
|
690
|
+
}
|
|
691
|
+
return Manager.instance;
|
|
692
|
+
}
|
|
693
|
+
cleanup() {
|
|
694
|
+
clearInterval(this.timer);
|
|
695
|
+
}
|
|
696
|
+
initGC() {
|
|
697
|
+
this.timer = setInterval(() => {
|
|
698
|
+
const now = Date.now();
|
|
699
|
+
for (const [plugin, lastActive] of this.refCount) {
|
|
700
|
+
if (lastActive[0] === 0 && now - lastActive[1] > PLUGIN_GC_TIMEOUT) {
|
|
701
|
+
plugin.dispose();
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}, 20 * 1e3);
|
|
705
|
+
}
|
|
706
|
+
async initPlugin(container, initialUI) {
|
|
707
|
+
if (this.plugins.has(container)) {
|
|
708
|
+
return this.plugins.get(container);
|
|
709
|
+
}
|
|
710
|
+
if (container.querySelector(".msp-plugin")) {
|
|
711
|
+
for (const [containerElem, plugin] of this.plugins) {
|
|
712
|
+
if (containerElem.contains(container)) {
|
|
713
|
+
return plugin;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
if (this.initializatingContainers.has(container)) {
|
|
718
|
+
while (this.initializatingContainers.has(container)) {
|
|
719
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
720
|
+
}
|
|
721
|
+
const plugin = this.plugins.get(container);
|
|
722
|
+
if (!plugin) {
|
|
723
|
+
throw new Error("Viewer initialization failed");
|
|
724
|
+
}
|
|
725
|
+
return plugin;
|
|
726
|
+
}
|
|
727
|
+
try {
|
|
728
|
+
this.initializatingContainers.add(container);
|
|
729
|
+
if (!container.querySelector(".msp-plugin")) {
|
|
730
|
+
container.innerHTML = "";
|
|
731
|
+
}
|
|
732
|
+
const instance = await Plugin.create(container, initialUI);
|
|
733
|
+
this.refCount.set(instance, [1, Date.now()]);
|
|
734
|
+
this.plugins.set(container, instance);
|
|
735
|
+
return instance;
|
|
736
|
+
} finally {
|
|
737
|
+
this.initializatingContainers.delete(container);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
getPlugin(container) {
|
|
741
|
+
const plugin = this.plugins.get(container);
|
|
742
|
+
if (plugin) {
|
|
743
|
+
const ref = this.refCount.get(plugin);
|
|
744
|
+
if (ref) {
|
|
745
|
+
ref[0]++;
|
|
746
|
+
ref[1] = Date.now();
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return plugin;
|
|
750
|
+
}
|
|
751
|
+
releasePlugin(plugin) {
|
|
752
|
+
const ref = this.refCount.get(plugin);
|
|
753
|
+
if (!ref) {
|
|
754
|
+
throw new Error("Trying to release a plugin that is not managed");
|
|
755
|
+
}
|
|
756
|
+
ref[0] = Math.max(0, ref[0] - 1);
|
|
757
|
+
ref[1] = Date.now();
|
|
758
|
+
}
|
|
759
|
+
disposePlugin(container) {
|
|
760
|
+
const plugin = this.plugins.get(container);
|
|
761
|
+
if (plugin) {
|
|
762
|
+
plugin.dispose();
|
|
763
|
+
this.plugins.delete(container);
|
|
764
|
+
container.innerHTML = "";
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
function normalizeChoppingData(chopping) {
|
|
769
|
+
if (!chopping) {
|
|
770
|
+
return [];
|
|
771
|
+
}
|
|
772
|
+
return chopping.map((entry) => ({
|
|
773
|
+
label: entry.label,
|
|
774
|
+
showLabel: entry.showLabel,
|
|
775
|
+
ranges: entry.ranges.map((range) => ({
|
|
776
|
+
start: Math.min(range.start, range.end),
|
|
777
|
+
end: Math.max(range.start, range.end)
|
|
778
|
+
})).filter(
|
|
779
|
+
(range) => Number.isFinite(range.start) && Number.isFinite(range.end)
|
|
780
|
+
)
|
|
781
|
+
})).filter((entry) => entry.ranges.length > 0);
|
|
782
|
+
}
|
|
783
|
+
const BASE_COLOR_YELLOW = "#FD9D0D";
|
|
784
|
+
const BASE_COLOR_BLUE = "#0D6EFD";
|
|
785
|
+
const BASE_COLOR_GREY = "#F0F0F0";
|
|
786
|
+
const MULTI_DOMAIN_COLORS = [
|
|
787
|
+
"#4e79a7",
|
|
788
|
+
"#f28e2c",
|
|
789
|
+
"#e15759",
|
|
790
|
+
"#76b7b2",
|
|
791
|
+
"#59a14f",
|
|
792
|
+
"#edc949",
|
|
793
|
+
"#af7aa1",
|
|
794
|
+
"#ff9da7",
|
|
795
|
+
"#9c755f",
|
|
796
|
+
"#bab0ac"
|
|
797
|
+
];
|
|
798
|
+
const MULTI_PROTEIN_OPACITY_MAX = 0.5;
|
|
799
|
+
const MULTI_PROTEIN_OPACITY_MIN = 0.1;
|
|
800
|
+
const ALPHAFOLD_CONFIDENCE_COLORS = {
|
|
801
|
+
veryHigh: "#0053D6",
|
|
802
|
+
confident: "#65CBF3",
|
|
803
|
+
low: "#FFDB13",
|
|
804
|
+
veryLow: "#FF7D45"
|
|
805
|
+
};
|
|
806
|
+
function getBaseColor(colors, index) {
|
|
807
|
+
return colors[index] ?? BASE_COLOR_GREY;
|
|
808
|
+
}
|
|
809
|
+
function getOpacityForProtein(index, totalProteins) {
|
|
810
|
+
if (totalProteins < 3 || index === 0) {
|
|
811
|
+
return void 0;
|
|
812
|
+
}
|
|
813
|
+
const range = MULTI_PROTEIN_OPACITY_MAX - MULTI_PROTEIN_OPACITY_MIN;
|
|
814
|
+
const step = range / (totalProteins - 1);
|
|
815
|
+
return Math.max(
|
|
816
|
+
MULTI_PROTEIN_OPACITY_MIN,
|
|
817
|
+
MULTI_PROTEIN_OPACITY_MAX - (index - 1) * step
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
function applyFlatColor(representation, color, selector) {
|
|
821
|
+
const params = { color };
|
|
822
|
+
if (selector) {
|
|
823
|
+
params.selector = selector;
|
|
824
|
+
}
|
|
825
|
+
representation.color(params);
|
|
826
|
+
}
|
|
827
|
+
function applyAlphaFoldConfidenceColor(struct, component, representation) {
|
|
828
|
+
representation.colorFromSource({
|
|
829
|
+
schema: "all_atomic",
|
|
830
|
+
category_name: "atom_site",
|
|
831
|
+
field_name: "B_iso_or_equiv",
|
|
832
|
+
palette: {
|
|
833
|
+
kind: "discrete",
|
|
834
|
+
mode: "absolute",
|
|
835
|
+
colors: [
|
|
836
|
+
[ALPHAFOLD_CONFIDENCE_COLORS.veryLow, 0],
|
|
837
|
+
[ALPHAFOLD_CONFIDENCE_COLORS.low, 50],
|
|
838
|
+
[ALPHAFOLD_CONFIDENCE_COLORS.confident, 70],
|
|
839
|
+
[ALPHAFOLD_CONFIDENCE_COLORS.veryHigh, 90]
|
|
840
|
+
]
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
component.tooltip({ text: "pLDDT:" });
|
|
844
|
+
struct.tooltipFromSource({
|
|
845
|
+
schema: "all_atomic",
|
|
846
|
+
category_name: "atom_site",
|
|
847
|
+
field_name: "B_iso_or_equiv"
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
function inferColors(count, domains) {
|
|
851
|
+
if (count < 0) {
|
|
852
|
+
throw new Error("Count must be non-negative");
|
|
853
|
+
}
|
|
854
|
+
if (count === 0) {
|
|
855
|
+
return [];
|
|
856
|
+
}
|
|
857
|
+
if (count === 1) {
|
|
858
|
+
return [BASE_COLOR_BLUE];
|
|
859
|
+
}
|
|
860
|
+
if (count === 2) {
|
|
861
|
+
return [BASE_COLOR_BLUE, BASE_COLOR_YELLOW];
|
|
862
|
+
}
|
|
863
|
+
return [BASE_COLOR_YELLOW, ...Array(count - 1).fill(BASE_COLOR_GREY)];
|
|
864
|
+
}
|
|
865
|
+
function createChainSelector(protein) {
|
|
866
|
+
if (!protein.chain) {
|
|
867
|
+
return "all";
|
|
868
|
+
}
|
|
869
|
+
return protein.file ? { label_asym_id: protein.chain } : { auth_asym_id: protein.chain };
|
|
870
|
+
}
|
|
871
|
+
function getRepresentationType(protein, representationType) {
|
|
872
|
+
return representationType ?? protein.representation ?? "cartoon";
|
|
873
|
+
}
|
|
874
|
+
function createRepresentationParams(protein, representationType) {
|
|
875
|
+
const repType = getRepresentationType(protein, representationType);
|
|
876
|
+
if (protein.file) {
|
|
877
|
+
return { size_factor: 1, tubular_helices: false, type: repType };
|
|
878
|
+
}
|
|
879
|
+
return { type: repType };
|
|
880
|
+
}
|
|
881
|
+
function isCartoonLikeRepresentation(repType) {
|
|
882
|
+
return repType === "cartoon" || repType === "backbone";
|
|
883
|
+
}
|
|
884
|
+
function createDomainSelector(protein, seqRange) {
|
|
885
|
+
if (!protein.chain) {
|
|
886
|
+
return seqRange ?? "all";
|
|
887
|
+
}
|
|
888
|
+
const chainId = protein.file ? { label_asym_id: protein.chain } : { auth_asym_id: protein.chain };
|
|
889
|
+
return seqRange ? { ...chainId, ...seqRange } : chainId;
|
|
890
|
+
}
|
|
891
|
+
const REST_OPACITY = 0.15;
|
|
892
|
+
function renderProteinWithoutChopping(struct, protein, proteinIndex, totalProteins, colors) {
|
|
893
|
+
const selector = createChainSelector(protein);
|
|
894
|
+
const comp = struct.component({ selector });
|
|
895
|
+
const repType = getRepresentationType(protein);
|
|
896
|
+
const repr = comp.representation(
|
|
897
|
+
createRepresentationParams(protein, repType)
|
|
898
|
+
);
|
|
899
|
+
if (totalProteins === 1) {
|
|
900
|
+
if (isCartoonLikeRepresentation(repType)) {
|
|
901
|
+
applyAlphaFoldConfidenceColor(struct, comp, repr);
|
|
902
|
+
}
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
if (totalProteins >= 3) {
|
|
906
|
+
if (proteinIndex === 0 && isCartoonLikeRepresentation(repType)) {
|
|
907
|
+
applyAlphaFoldConfidenceColor(struct, comp, repr);
|
|
908
|
+
} else {
|
|
909
|
+
const color2 = getBaseColor(colors, proteinIndex);
|
|
910
|
+
applyFlatColor(repr, color2);
|
|
911
|
+
const opacity2 = getOpacityForProtein(proteinIndex, totalProteins);
|
|
912
|
+
if (opacity2 !== void 0) {
|
|
913
|
+
repr.opacity({ opacity: opacity2 });
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
const color = getBaseColor(colors, proteinIndex);
|
|
919
|
+
applyFlatColor(repr, color);
|
|
920
|
+
const opacity = getOpacityForProtein(proteinIndex, totalProteins);
|
|
921
|
+
if (opacity !== void 0 && opacity < 1) {
|
|
922
|
+
repr.opacity({ opacity });
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
function renderProteinWithChopping(struct, protein, proteinIndex, totalProteins, colors, choppingEntries) {
|
|
926
|
+
if (choppingEntries.length === 0) {
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
const selector = createChainSelector(protein);
|
|
930
|
+
const comp = struct.component({ selector });
|
|
931
|
+
const baseRepr = comp.representation(createRepresentationParams(protein));
|
|
932
|
+
let backgroundColor;
|
|
933
|
+
let restOpacity = REST_OPACITY;
|
|
934
|
+
if (totalProteins === 1 && choppingEntries.length >= 2) {
|
|
935
|
+
backgroundColor = BASE_COLOR_GREY;
|
|
936
|
+
restOpacity = 1;
|
|
937
|
+
} else {
|
|
938
|
+
backgroundColor = getBaseColor(colors, proteinIndex);
|
|
939
|
+
}
|
|
940
|
+
applyFlatColor(baseRepr, backgroundColor);
|
|
941
|
+
baseRepr.opacity({ opacity: restOpacity });
|
|
942
|
+
const useInlineDomainColoring = totalProteins === 1 && choppingEntries.length >= 2;
|
|
943
|
+
let domainPalette;
|
|
944
|
+
if (totalProteins === 1 && choppingEntries.length >= 2) {
|
|
945
|
+
domainPalette = choppingEntries.map(
|
|
946
|
+
(_, index) => MULTI_DOMAIN_COLORS[index % MULTI_DOMAIN_COLORS.length]
|
|
947
|
+
);
|
|
948
|
+
} else if (totalProteins === 2 && choppingEntries.length >= 2) {
|
|
949
|
+
const baseColorForDomains = proteinIndex === 0 ? BASE_COLOR_BLUE : BASE_COLOR_YELLOW;
|
|
950
|
+
domainPalette = Array(choppingEntries.length).fill(baseColorForDomains);
|
|
951
|
+
} else if (totalProteins === 2 && choppingEntries.length === 1) {
|
|
952
|
+
domainPalette = [backgroundColor];
|
|
953
|
+
} else {
|
|
954
|
+
domainPalette = Array(choppingEntries.length).fill(BASE_COLOR_BLUE);
|
|
955
|
+
}
|
|
956
|
+
if (useInlineDomainColoring) {
|
|
957
|
+
choppingEntries.forEach((entry, entryIndex) => {
|
|
958
|
+
applyDomainColor(baseRepr, protein, entry, domainPalette[entryIndex]);
|
|
959
|
+
addDomainLabel(struct, protein, entry);
|
|
960
|
+
});
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
choppingEntries.forEach((entry, entryIndex) => {
|
|
964
|
+
renderDomainEntry(struct, protein, entry, domainPalette[entryIndex]);
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
function applyDomainColor(representation, protein, entry, color) {
|
|
968
|
+
if (entry.ranges.length === 0) {
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
const selectors = entry.ranges.map((range) => {
|
|
972
|
+
const seqRange = {
|
|
973
|
+
beg_auth_seq_id: range.start,
|
|
974
|
+
end_auth_seq_id: range.end
|
|
975
|
+
};
|
|
976
|
+
return createDomainSelector(protein, seqRange);
|
|
977
|
+
});
|
|
978
|
+
const selectorParam = selectors.length === 1 ? selectors[0] : selectors;
|
|
979
|
+
applyFlatColor(representation, color, selectorParam);
|
|
980
|
+
}
|
|
981
|
+
function renderDomainEntry(struct, protein, entry, color) {
|
|
982
|
+
const reprParams = createRepresentationParams(protein);
|
|
983
|
+
entry.ranges.forEach((range) => {
|
|
984
|
+
const seqRange = {
|
|
985
|
+
beg_auth_seq_id: range.start,
|
|
986
|
+
end_auth_seq_id: range.end
|
|
987
|
+
};
|
|
988
|
+
const selector = createDomainSelector(protein, seqRange);
|
|
989
|
+
const domainComp = struct.component({ selector });
|
|
990
|
+
const domainRepr = domainComp.representation(reprParams);
|
|
991
|
+
applyFlatColor(domainRepr, color);
|
|
992
|
+
});
|
|
993
|
+
addDomainLabel(struct, protein, entry);
|
|
994
|
+
}
|
|
995
|
+
function addDomainLabel(struct, protein, entry) {
|
|
996
|
+
if (!entry.showLabel || entry.ranges.length === 0) {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
const labelRange = entry.ranges[Math.floor(entry.ranges.length / 2)] ?? entry.ranges[0];
|
|
1000
|
+
const labelSelector = createDomainSelector(protein, {
|
|
1001
|
+
beg_auth_seq_id: labelRange.start,
|
|
1002
|
+
end_auth_seq_id: labelRange.end
|
|
1003
|
+
});
|
|
1004
|
+
struct.component({ selector: labelSelector }).label({
|
|
1005
|
+
text: entry.label
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
function transposeAndFlatten(matrix) {
|
|
1009
|
+
return matrix[0].flatMap(
|
|
1010
|
+
(_, colIndex) => matrix.map((row) => row[colIndex])
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
const DEFAULT_ROTATION = [
|
|
1014
|
+
[1, 0, 0],
|
|
1015
|
+
[0, 1, 0],
|
|
1016
|
+
[0, 0, 1]
|
|
1017
|
+
];
|
|
1018
|
+
const DEFAULT_TRANSLATION = [0, 0, 0];
|
|
1019
|
+
function prepareModelSourceUrl(protein, modelSourceUrls, plugin) {
|
|
1020
|
+
const defaultModelSourceUrls = {
|
|
1021
|
+
uniProtId: "https://alphafold.ebi.ac.uk/files"
|
|
1022
|
+
};
|
|
1023
|
+
let url;
|
|
1024
|
+
if (protein.file) {
|
|
1025
|
+
if (!plugin) {
|
|
1026
|
+
throw new Error(
|
|
1027
|
+
"Plugin instance is required to create object URL from file"
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1030
|
+
url = plugin.createObjectUrlFromFile(protein.file);
|
|
1031
|
+
} else if (modelSourceUrls.uniProtId !== void 0) {
|
|
1032
|
+
url = modelSourceUrls.uniProtId(protein.uniProtId);
|
|
1033
|
+
} else {
|
|
1034
|
+
url = `${defaultModelSourceUrls.uniProtId}/AF-${protein.uniProtId}-F1-model_v6.cif`;
|
|
1035
|
+
}
|
|
1036
|
+
return url;
|
|
1037
|
+
}
|
|
1038
|
+
function getParseFormat(protein) {
|
|
1039
|
+
if (!protein.file) {
|
|
1040
|
+
return "mmcif";
|
|
1041
|
+
}
|
|
1042
|
+
return protein.file.name.endsWith(".cif") || protein.file.name.endsWith(".mmcif") ? "mmcif" : "pdb";
|
|
1043
|
+
}
|
|
1044
|
+
function processProtein(root, protein, proteinIndex, totalProteins, colors, modelSourceUrls, plugin) {
|
|
1045
|
+
const url = prepareModelSourceUrl(protein, modelSourceUrls, plugin);
|
|
1046
|
+
const download = root.download({ url });
|
|
1047
|
+
const parseFormat = getParseFormat(protein);
|
|
1048
|
+
const parse = download.parse({ format: parseFormat });
|
|
1049
|
+
const struct = parse.modelStructure(
|
|
1050
|
+
protein.file ? { block_header: null, block_index: 0, model_index: 0 } : {}
|
|
1051
|
+
);
|
|
1052
|
+
struct.transform({
|
|
1053
|
+
rotation: transposeAndFlatten(
|
|
1054
|
+
protein.superposition?.rotation ?? DEFAULT_ROTATION
|
|
1055
|
+
),
|
|
1056
|
+
translation: protein.superposition?.translation ?? DEFAULT_TRANSLATION,
|
|
1057
|
+
rotation_center: [0, 0, 0]
|
|
1058
|
+
});
|
|
1059
|
+
const choppingEntries = totalProteins >= 3 ? [] : normalizeChoppingData(protein.chopping);
|
|
1060
|
+
if (choppingEntries.length > 0) {
|
|
1061
|
+
renderProteinWithChopping(
|
|
1062
|
+
struct,
|
|
1063
|
+
protein,
|
|
1064
|
+
proteinIndex,
|
|
1065
|
+
totalProteins,
|
|
1066
|
+
colors,
|
|
1067
|
+
choppingEntries
|
|
1068
|
+
);
|
|
1069
|
+
} else {
|
|
1070
|
+
renderProteinWithoutChopping(
|
|
1071
|
+
struct,
|
|
1072
|
+
protein,
|
|
1073
|
+
proteinIndex,
|
|
1074
|
+
totalProteins,
|
|
1075
|
+
colors
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
function createMVS(proteins, modelSourceUrls, plugin) {
|
|
1080
|
+
const colors = inferColors(proteins.length);
|
|
1081
|
+
const root = createMVSBuilder();
|
|
1082
|
+
for (let i = 0; i < proteins.length; i++) {
|
|
1083
|
+
const protein = proteins[i];
|
|
1084
|
+
processProtein(
|
|
1085
|
+
root,
|
|
1086
|
+
protein,
|
|
1087
|
+
i,
|
|
1088
|
+
proteins.length,
|
|
1089
|
+
colors,
|
|
1090
|
+
modelSourceUrls,
|
|
1091
|
+
plugin
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
return root.getState({
|
|
1095
|
+
title: proteins.length > 1 ? "Protein Comparison" : "Protein Visualization",
|
|
1096
|
+
description: `Visualization of ${proteins.length} protein(s)`
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
const Viewer = forwardRef(function Viewer2({
|
|
1100
|
+
proteins,
|
|
1101
|
+
mvs,
|
|
1102
|
+
modelSourceUrls,
|
|
1103
|
+
initialUI = "standard",
|
|
1104
|
+
bgColor = "#ffffff",
|
|
1105
|
+
spin = false,
|
|
1106
|
+
spinSpeed = 0.05,
|
|
1107
|
+
rock = false,
|
|
1108
|
+
rockSpeed = 0.2,
|
|
1109
|
+
height,
|
|
1110
|
+
className
|
|
1111
|
+
}, ref) {
|
|
1112
|
+
const containerRef = useRef(null);
|
|
1113
|
+
const pluginRef = useRef(null);
|
|
1114
|
+
const proteinsRef = useRef(proteins);
|
|
1115
|
+
const [state, setState] = useState("loading");
|
|
1116
|
+
const id = useId();
|
|
1117
|
+
useEffect(() => {
|
|
1118
|
+
proteinsRef.current = proteins;
|
|
1119
|
+
}, [proteins]);
|
|
1120
|
+
useImperativeHandle(
|
|
1121
|
+
ref,
|
|
1122
|
+
() => ({
|
|
1123
|
+
highlight: async (proteinIndex, label) => {
|
|
1124
|
+
if (!pluginRef.current || proteinsRef.current === void 0 || proteinsRef.current.length <= proteinIndex) {
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
const domain = proteinsRef.current[proteinIndex]?.chopping?.find(
|
|
1128
|
+
(d) => d.label === label
|
|
1129
|
+
);
|
|
1130
|
+
const start = domain?.ranges[0]?.start;
|
|
1131
|
+
const end = domain?.ranges[0]?.end;
|
|
1132
|
+
if (start !== void 0 && end !== void 0) {
|
|
1133
|
+
await pluginRef.current.focusOnDomain(start, end);
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
reset: async () => {
|
|
1137
|
+
if (!pluginRef.current) {
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
await pluginRef.current.resetView();
|
|
1141
|
+
},
|
|
1142
|
+
updateSuperposition: async (proteinIndex, translation, rotation) => {
|
|
1143
|
+
if (!pluginRef.current) {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
await pluginRef.current.updateStructureTransform(
|
|
1147
|
+
proteinIndex,
|
|
1148
|
+
translation,
|
|
1149
|
+
rotation
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
}),
|
|
1153
|
+
[]
|
|
1154
|
+
);
|
|
1155
|
+
useEffect(() => {
|
|
1156
|
+
return () => {
|
|
1157
|
+
pluginRef.current = null;
|
|
1158
|
+
};
|
|
1159
|
+
}, []);
|
|
1160
|
+
useEffect(() => {
|
|
1161
|
+
if (!containerRef.current) {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
if (proteins !== void 0 && mvs !== void 0 || proteins === void 0 && mvs === void 0) {
|
|
1165
|
+
throw new Error(
|
|
1166
|
+
"Either `proteins` or `mvs` must be provided, but not both."
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
setState("loading");
|
|
1170
|
+
let ref2;
|
|
1171
|
+
async function init() {
|
|
1172
|
+
const manager = Manager.getInstance();
|
|
1173
|
+
const el = containerRef.current;
|
|
1174
|
+
if (!el) {
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
let pl = manager.getPlugin(el);
|
|
1178
|
+
if (!pl) {
|
|
1179
|
+
pl = await manager.initPlugin(el, initialUI);
|
|
1180
|
+
}
|
|
1181
|
+
ref2 = pl;
|
|
1182
|
+
pluginRef.current = pl;
|
|
1183
|
+
try {
|
|
1184
|
+
if (mvs === void 0 && proteins === void 0) {
|
|
1185
|
+
throw new Error(
|
|
1186
|
+
"Either `proteins` or `mvs` must be provided, but not both."
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
const proteinsVal = proteins;
|
|
1190
|
+
if (mvs === void 0 && proteinsVal === void 0) {
|
|
1191
|
+
throw new Error("Missing proteins data");
|
|
1192
|
+
}
|
|
1193
|
+
const proteinsArg = proteinsVal;
|
|
1194
|
+
const mvsData = mvs ?? createMVS(proteinsArg, modelSourceUrls ?? {}, pl);
|
|
1195
|
+
await pl.loadMvs(mvsData);
|
|
1196
|
+
} catch (e) {
|
|
1197
|
+
console.error(e);
|
|
1198
|
+
setState("error");
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
setState("success");
|
|
1202
|
+
}
|
|
1203
|
+
init();
|
|
1204
|
+
return () => {
|
|
1205
|
+
if (ref2 !== void 0) {
|
|
1206
|
+
Manager.getInstance().releasePlugin(ref2);
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
}, [proteins, mvs, modelSourceUrls, initialUI]);
|
|
1210
|
+
useEffect(() => {
|
|
1211
|
+
if (state !== "success" || !pluginRef.current) {
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
if (spin) {
|
|
1215
|
+
pluginRef.current.setAnimation("spin", spinSpeed);
|
|
1216
|
+
} else if (rock) {
|
|
1217
|
+
pluginRef.current.setAnimation("rock", rockSpeed);
|
|
1218
|
+
} else {
|
|
1219
|
+
pluginRef.current.setAnimation("off");
|
|
1220
|
+
}
|
|
1221
|
+
}, [state, spin, rock, spinSpeed, rockSpeed]);
|
|
1222
|
+
useEffect(() => {
|
|
1223
|
+
if (state !== "success" || !pluginRef.current) {
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
if (bgColor) {
|
|
1227
|
+
pluginRef.current.setBackgroundColor(bgColor);
|
|
1228
|
+
}
|
|
1229
|
+
}, [state, bgColor]);
|
|
1230
|
+
const styles = {
|
|
1231
|
+
height: height ? `${height}px` : "100%",
|
|
1232
|
+
position: "relative"
|
|
1233
|
+
};
|
|
1234
|
+
const containerClasses = `react-molstar${initialUI === "minimal" ? " no-controls" : ""}`;
|
|
1235
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className, style: styles, children: [
|
|
1236
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1237
|
+
"div",
|
|
1238
|
+
{
|
|
1239
|
+
ref: containerRef,
|
|
1240
|
+
id,
|
|
1241
|
+
className: containerClasses,
|
|
1242
|
+
style: {
|
|
1243
|
+
opacity: state === "success" ? 1 : 0.7,
|
|
1244
|
+
transition: "opacity 0.3s ease-in-out"
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
),
|
|
1248
|
+
state === "loading" && /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderView, {}),
|
|
1249
|
+
state === "error" && /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorView, {})
|
|
1250
|
+
] });
|
|
1251
|
+
});
|
|
1252
|
+
export {
|
|
1253
|
+
Manager,
|
|
1254
|
+
Plugin,
|
|
1255
|
+
Viewer,
|
|
1256
|
+
createMVS
|
|
1257
|
+
};
|
|
1258
|
+
//# sourceMappingURL=index.es.js.map
|