@vitessce/launcher 3.8.6

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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -0
  3. package/dist/OrbitControls-BF52POQp.js +18694 -0
  4. package/dist/ReactNeuroglancer-BzSHY22y.js +65780 -0
  5. package/dist/blosc-DvQQ1ST0.js +887 -0
  6. package/dist/chunk-INHXZS53-DHVJiuU3.js +19 -0
  7. package/dist/deflate-CQwOaSLw.js +10 -0
  8. package/dist/higlass-C7qBSekP.js +133163 -0
  9. package/dist/index-B00rYWyD.js +3686 -0
  10. package/dist/index-BIrF4FKE.js +9854 -0
  11. package/dist/index-CYL9MBhI.js +384168 -0
  12. package/dist/index.js +5 -0
  13. package/dist/jpeg-BFml4vEx.js +856 -0
  14. package/dist/lerc-BOiupD76.js +2057 -0
  15. package/dist/lz4-BIbM36RN.js +801 -0
  16. package/dist/lzw-DjHwit8p.js +125 -0
  17. package/dist/packbits-io9qfQZa.js +27 -0
  18. package/dist/pako.esm-SxljTded.js +2216 -0
  19. package/dist/raw-BzEs_FKC.js +9 -0
  20. package/dist/troika-three-text.esm-26C0zM6u.js +5685 -0
  21. package/dist/webimage-CwJqBfRI.js +29 -0
  22. package/dist/zstd-CO575QiM.js +769 -0
  23. package/dist-tsc/ControlledLauncher.d.ts +2 -0
  24. package/dist-tsc/ControlledLauncher.d.ts.map +1 -0
  25. package/dist-tsc/ControlledLauncher.js +129 -0
  26. package/dist-tsc/LauncherStart.d.ts +2 -0
  27. package/dist-tsc/LauncherStart.d.ts.map +1 -0
  28. package/dist-tsc/LauncherStart.js +142 -0
  29. package/dist-tsc/UncontrolledLauncher.d.ts +14 -0
  30. package/dist-tsc/UncontrolledLauncher.d.ts.map +1 -0
  31. package/dist-tsc/UncontrolledLauncher.js +52 -0
  32. package/dist-tsc/index.d.ts +3 -0
  33. package/dist-tsc/index.d.ts.map +1 -0
  34. package/dist-tsc/index.js +2 -0
  35. package/dist-tsc/launcher-styles.d.ts +10 -0
  36. package/dist-tsc/launcher-styles.d.ts.map +1 -0
  37. package/dist-tsc/launcher-styles.js +69 -0
  38. package/dist-tsc/use-hash-param.d.ts +3 -0
  39. package/dist-tsc/use-hash-param.d.ts.map +1 -0
  40. package/dist-tsc/use-hash-param.js +110 -0
  41. package/dist-tsc/use-query-or-hash-param.d.ts +2 -0
  42. package/dist-tsc/use-query-or-hash-param.d.ts.map +1 -0
  43. package/dist-tsc/use-query-or-hash-param.js +51 -0
  44. package/package.json +51 -0
  45. package/src/ControlledLauncher.js +208 -0
  46. package/src/LauncherStart.js +351 -0
  47. package/src/UncontrolledLauncher.js +110 -0
  48. package/src/index.js +2 -0
  49. package/src/launcher-styles.js +71 -0
  50. package/src/use-hash-param.js +124 -0
  51. package/src/use-query-or-hash-param.js +63 -0
@@ -0,0 +1,110 @@
1
+ /* eslint-disable no-unused-vars */
2
+ /* eslint-disable max-len */
3
+ import React, { useEffect, useState } from 'react';
4
+ import { QueryParamProvider } from 'use-query-params';
5
+ import { useHashOrQueryParam } from './use-query-or-hash-param.js';
6
+ import { ControlledLauncher } from './ControlledLauncher.js';
7
+
8
+
9
+ function UncontrolledLauncherInner(props) {
10
+ const {
11
+ marginTop = 0,
12
+ setIsFooterVisible,
13
+ configUrlParamName = 'config',
14
+ sourceUrlParamName = 'source',
15
+ exampleIdParamName = 'example',
16
+ isEditingParamName = 'edit',
17
+ } = props;
18
+
19
+ const [launcherError, setLauncherError] = useState(null);
20
+
21
+ // Logic for managing state and query/hash params.
22
+ const [exampleId, setExampleId, exampleIdParamError] = useHashOrQueryParam(exampleIdParamName, undefined, 'string');
23
+ // TODO: support vitessce-link code param
24
+ // const wsCodeValue = useHashOrQueryParam('session', undefined, 'string');
25
+ const [configUrl, setConfigUrl, configUrlParamError] = useHashOrQueryParam(configUrlParamName, undefined, 'string');
26
+ const [sourceUrlArr, setSourceUrlArr, sourceUrlArrParamError] = useHashOrQueryParam(sourceUrlParamName, undefined, 'string-array');
27
+ const [isEditingParam, setIsEditing, isEditingParamError] = useHashOrQueryParam(isEditingParamName, undefined, 'boolean');
28
+
29
+ // We need this here since the URL param will not indicate whether local data was dropped.
30
+ // TODO: Store in a cookie/localStorage? Store in a URL param?
31
+ // However if the page changes, we will lose the dropped data anyway...
32
+ const [isUsingLocalFiles, setIsUsingLocalFiles] = useState(false);
33
+
34
+ // Check for parameter errors (e.g., both hash+query for same value) and conflicting parameters.
35
+ const hasNoParamError = !exampleIdParamError && !configUrlParamError && !sourceUrlArrParamError && !isEditingParamError;
36
+ const hasNoConflictingParams = (
37
+ (exampleId ? 1 : 0)
38
+ + (configUrl ? 1 : 0)
39
+ + (sourceUrlArr && sourceUrlArr.length > 0 ? 1 : 0)
40
+ ) <= 1;
41
+ const needsStart = !exampleId && !configUrl && (!sourceUrlArr || (Array.isArray(sourceUrlArr) && sourceUrlArr.length === 0));
42
+
43
+ const isEditing = !isUsingLocalFiles && (isEditingParam === true || needsStart);
44
+
45
+ useEffect(() => {
46
+ if (typeof setIsFooterVisible === 'function') {
47
+ setIsFooterVisible(isEditing);
48
+ }
49
+ }, [isEditing, setIsFooterVisible]);
50
+
51
+ return (
52
+ <ControlledLauncher
53
+ isEditing={isEditing}
54
+ setIsEditing={setIsEditing}
55
+ isUsingLocalFiles={isUsingLocalFiles}
56
+ setIsUsingLocalFiles={setIsUsingLocalFiles}
57
+ configUrl={configUrl}
58
+ setConfigUrl={setConfigUrl}
59
+ sourceUrlArr={sourceUrlArr}
60
+ setSourceUrlArr={setSourceUrlArr}
61
+ marginTop={marginTop}
62
+ launcherError={launcherError}
63
+ setLauncherError={setLauncherError}
64
+ />
65
+ );
66
+ }
67
+
68
+ /**
69
+ *
70
+ * @param {object} props
71
+ * @param {number} [props.marginTop=0] The distance in pixels from the top of the window.
72
+ * This is used to calculate the height of the Vitessce component (100vh minus marginTop).
73
+ * @param {function} [props.setIsFooterVisible] Callback to set whether the footer is visible.
74
+ * Used to hide the footer when Vitessce component is visible.
75
+ * @returns
76
+ */
77
+ export function UncontrolledLauncher(props) {
78
+ const {
79
+ marginTop = 0,
80
+ setIsFooterVisible = null,
81
+ configUrlParamName = 'config',
82
+ sourceUrlParamName = 'source',
83
+ exampleIdParamName = 'example',
84
+ isEditingParamName = 'edit',
85
+ // TODO: Optional mapping from example IDs to their full JSON config, and potentially more values such as PageComponent, Plugins, etc.
86
+ // See https://github.com/vitessce/vitessce/blob/main/sites/demo/src/api.js
87
+ exampleConfigs = null,
88
+ } = props;
89
+
90
+ // TODO: wrap in MUI themeProvider?
91
+ return (
92
+ <QueryParamProvider>
93
+ <div style={{ display: 'none' }}>
94
+ {/* TEMP: links for quick testing */}
95
+ <a href="/">Reset</a>&nbsp;
96
+ <a href="/?source=https://storage.googleapis.com/vitessce-demo-data/maynard-2021/151673.sdata.zarr">SpatialData Example</a>&nbsp;
97
+ <a href="/#?source=https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.4/idr0062A/6001240.zarr$image.ome-zarr">OME-Zarr Example</a>
98
+ </div>
99
+ <UncontrolledLauncherInner
100
+ marginTop={marginTop}
101
+ setIsFooterVisible={setIsFooterVisible}
102
+
103
+ isEditingParamName={isEditingParamName}
104
+ exampleIdParamName={exampleIdParamName}
105
+ configUrlParamName={configUrlParamName}
106
+ sourceUrlParamName={sourceUrlParamName}
107
+ />
108
+ </QueryParamProvider>
109
+ );
110
+ }
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { UncontrolledLauncher } from './UncontrolledLauncher.js';
2
+ export { ControlledLauncher } from './ControlledLauncher.js';
@@ -0,0 +1,71 @@
1
+ import { makeStyles } from '@vitessce/styles';
2
+
3
+
4
+ export const useStyles = makeStyles()(() => ({
5
+ launcher: {
6
+ display: 'flex',
7
+ flexDirection: 'column',
8
+ margin: '0 10px',
9
+ },
10
+ launcherRow: {
11
+ marginTop: '15px',
12
+ marginBottom: '15px',
13
+ },
14
+ launcherRowTitle: {
15
+ marginBottom: 0,
16
+ },
17
+ launcherCardRow: {
18
+ display: 'grid',
19
+ gridTemplateColumns: '1fr 1fr',
20
+ gap: '10px',
21
+ },
22
+ launcherCard: {
23
+ transition: 'opacity 0.3s',
24
+ },
25
+ cardTitle: {
26
+ marginTop: 0,
27
+ },
28
+ cardDashed: {
29
+ display: 'inline-block',
30
+ boxSizing: 'border-box',
31
+ height: '100%',
32
+ width: '100%',
33
+ borderRadius: '4px',
34
+ border: '2px dashed rgba(128, 128, 128, 0.2)',
35
+ },
36
+ cardDim: {
37
+ opacity: 0.2,
38
+ },
39
+ cardContent: {
40
+ display: 'flex',
41
+ flexDirection: 'column',
42
+ height: '100%',
43
+ boxSizing: 'border-box',
44
+ },
45
+ buttonSpacer: {
46
+ flexGrow: 1,
47
+ },
48
+ dataButtonGroup: {
49
+ width: '100%',
50
+ display: 'flex',
51
+ flexDirection: 'row',
52
+ gap: '5px',
53
+ },
54
+ vitessceApp: {
55
+ position: 'relative',
56
+ display: 'flex',
57
+ width: '100%',
58
+ },
59
+ dataUrlTextarea: {
60
+ width: '100%',
61
+ boxSizing: 'border-box',
62
+ },
63
+ textareaAndButton: {
64
+ display: 'flex',
65
+ flexDirection: 'row',
66
+ gap: '5px',
67
+ },
68
+ hiddenFileInput: {
69
+ display: 'none',
70
+ },
71
+ }));
@@ -0,0 +1,124 @@
1
+ /* eslint-disable no-param-reassign */
2
+ // Adapted from https://github.com/hejmsdz/use-hash-param/blob/3fd6818/src/index.js
3
+ import { useState, useEffect, useCallback } from 'react';
4
+
5
+ const getHashSearchParams = (location) => {
6
+ const hash = location.hash.slice(1);
7
+ const [prefix, query] = hash.split('?');
8
+
9
+ return [prefix, new URLSearchParams(query)];
10
+ };
11
+
12
+ const getHashParam = (key, location = window.location) => {
13
+ // eslint-disable-next-line no-unused-vars
14
+ const [_, searchParams] = getHashSearchParams(location);
15
+ return searchParams.get(key);
16
+ };
17
+
18
+ const getAllHashParams = (key, location = window.location) => {
19
+ // eslint-disable-next-line no-unused-vars
20
+ const [_, searchParams] = getHashSearchParams(location);
21
+ return searchParams.getAll(key);
22
+ };
23
+
24
+ const getTypedHashParam = (key, varType) => {
25
+ if (varType === 'string-array') {
26
+ return getAllHashParams(key);
27
+ }
28
+ const val = getHashParam(key);
29
+ let typedVal = val;
30
+ if (varType === 'boolean') {
31
+ try {
32
+ typedVal = JSON.parse(val);
33
+ } catch (e) {
34
+ typedVal = false;
35
+ }
36
+ }
37
+ return typedVal;
38
+ };
39
+
40
+ const setHashParam = (key, value, location = window.location) => {
41
+ const [prefix, searchParams] = getHashSearchParams(location);
42
+
43
+ if (typeof value === 'undefined' || value === '') {
44
+ searchParams.delete(key);
45
+ } else {
46
+ searchParams.set(key, value);
47
+ }
48
+
49
+ const search = searchParams.toString();
50
+ location.hash = search ? `${prefix}?${search}` : prefix;
51
+ };
52
+
53
+ // There is no "pushState" or "replaceState" event on the
54
+ // window, only a "popstate" event. We can add our own
55
+ // pushState and replaceState events by wrapping the
56
+ // methods of the window.history object and dispatching
57
+ // as custom events.
58
+ // Reference: https://stackoverflow.com/a/25673911
59
+ const wrapHistoryMethod = (methodName) => {
60
+ const orig = window.history[methodName];
61
+ window.history.wrapped = true;
62
+ // eslint-disable-next-line func-names
63
+ return function () {
64
+ // eslint-disable-next-line prefer-rest-params
65
+ const rv = orig.apply(this, arguments);
66
+ const e = new Event(methodName);
67
+ // eslint-disable-next-line prefer-rest-params
68
+ e.arguments = arguments;
69
+ window.dispatchEvent(e);
70
+ return rv;
71
+ };
72
+ };
73
+
74
+ export const useHashParam = (key, defaultValue, varType) => {
75
+ const [innerValue, setInnerValue] = useState(getTypedHashParam(key, varType));
76
+
77
+ useEffect(() => {
78
+ let unmounted = false;
79
+
80
+ if (window.history && !window.history.wrapped) {
81
+ window.history.pushState = wrapHistoryMethod('pushState');
82
+ }
83
+
84
+ const handleHashChange = () => {
85
+ if (unmounted) {
86
+ return;
87
+ }
88
+ const nextValue = getTypedHashParam(key, varType);
89
+ setInnerValue(nextValue);
90
+ };
91
+ window.addEventListener('hashchange', handleHashChange);
92
+ window.addEventListener('pushState', handleHashChange);
93
+ return () => {
94
+ unmounted = true;
95
+ window.removeEventListener('hashchange', handleHashChange);
96
+ window.removeEventListener('pushState', handleHashChange);
97
+ };
98
+ }, [key, varType]);
99
+
100
+ const setValue = useCallback((value) => {
101
+ if (typeof value === 'function') {
102
+ setHashParam(key, value(getHashParam(key)));
103
+ } else {
104
+ setHashParam(key, value);
105
+ }
106
+ }, [key]);
107
+
108
+ return [innerValue === undefined ? defaultValue : innerValue, setValue];
109
+ };
110
+
111
+ export const useSetHashParams = () => (values, location = window.location) => {
112
+ const [prefix, searchParams] = getHashSearchParams(location);
113
+
114
+ Object.entries(values).forEach(([key, value]) => {
115
+ if (typeof value === 'undefined' || value === '') {
116
+ searchParams.delete(key);
117
+ } else {
118
+ searchParams.set(key, value);
119
+ }
120
+ });
121
+
122
+ const search = searchParams.toString();
123
+ location.hash = search ? `${prefix}?${search}` : prefix;
124
+ };
@@ -0,0 +1,63 @@
1
+ import {
2
+ useQueryParam,
3
+ StringParam as StringQueryParam,
4
+ ArrayParam as StringArrayQueryParam,
5
+ } from 'use-query-params';
6
+ import { useHashParam } from './use-hash-param.js';
7
+
8
+ const DtypeToParamType = {
9
+ string: StringQueryParam,
10
+ 'string-array': StringArrayQueryParam,
11
+ // Use string param for boolean since use-query-params only supports 0/1.
12
+ boolean: StringQueryParam,
13
+ };
14
+
15
+ function isTruthyString(v) {
16
+ return ['1', 'true'].includes(String(v).toLowerCase());
17
+ }
18
+
19
+ function useHashOrQueryParamAux(paramName, defaultValue, dtype) {
20
+ const [valueQ, setValueQ] = useQueryParam(paramName, DtypeToParamType[dtype]);
21
+ const [valueH, setValueH] = useHashParam(paramName, undefined, dtype);
22
+
23
+ if (dtype === 'boolean') {
24
+ const boolValueQ = valueQ !== undefined ? isTruthyString(valueQ) : undefined;
25
+ const boolValueH = valueH !== undefined ? isTruthyString(valueH) : undefined;
26
+
27
+ return valueQ ? [boolValueQ, setValueQ] : [boolValueH, setValueH];
28
+ }
29
+
30
+ if (dtype === 'string-array') {
31
+ // eslint-disable-next-line max-len
32
+ if (Array.isArray(valueH) && valueH.length > 0 && (!Array.isArray(valueQ) || valueQ.length === 0)) {
33
+ // Check for ; delimiter in individual array values, and split if necessary.
34
+ const splitValues = valueH.map(item => item.split(';')).flat();
35
+ return [splitValues, setValueH];
36
+ // eslint-disable-next-line max-len
37
+ } if (Array.isArray(valueQ) && valueQ.length > 0 && (!Array.isArray(valueH) || valueH.length === 0)) {
38
+ // Check for ; delimiter in individual array values, and split if necessary.
39
+ const splitValues = valueQ.map(item => item.split(';')).flat();
40
+ return [splitValues, setValueQ];
41
+ }
42
+ return [null, setValueH];
43
+ }
44
+ if (Array.isArray(valueQ) || Array.isArray(valueH)) {
45
+ throw new Error(`Expected non-array values for "${paramName}".`);
46
+ }
47
+
48
+
49
+ if (valueQ && valueH) {
50
+ throw new Error(`Both query and hash parameters provided for "${paramName}". Please provide only one.`);
51
+ }
52
+
53
+ return valueQ ? [valueQ, setValueQ] : [valueH, setValueH];
54
+ }
55
+
56
+ export function useHashOrQueryParam(paramName, defaultValue, dtype) {
57
+ const [value, setValue] = useHashOrQueryParamAux(paramName, defaultValue, dtype);
58
+ try {
59
+ return [value, setValue, false];
60
+ } catch (error) {
61
+ return [value, setValue, error.message];
62
+ }
63
+ }