@vitessce/vit-s 3.8.5 → 3.8.7

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.
@@ -0,0 +1,2 @@
1
+ export function Sidebar(props: any): JSX.Element;
2
+ //# sourceMappingURL=Sidebar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../src/Sidebar.js"],"names":[],"mappings":"AAgCA,iDA+CC"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useCallback } from 'react';
3
+ import { makeStyles, IconButton, Code as CodeIcon, InvertColors as InvertColorsIcon, } from '@vitessce/styles';
4
+ const useStyles = makeStyles()(() => ({
5
+ sidebarContainer: {
6
+ backgroundColor: 'silver',
7
+ width: '30px',
8
+ height: '100%',
9
+ },
10
+ sidebarUl: {
11
+ listStyleType: 'none',
12
+ margin: 0,
13
+ padding: 0,
14
+ },
15
+ sidebarLi: {},
16
+ sidebarIconButton: {
17
+ padding: '3px',
18
+ },
19
+ sidebarIcon: {
20
+ color: 'black',
21
+ width: '24px',
22
+ height: '24px',
23
+ },
24
+ }));
25
+ export function Sidebar(props) {
26
+ const { theme, setTheme, configEditable, themeEditable, } = props;
27
+ const { classes } = useStyles();
28
+ const onToggleTheme = useCallback(() => {
29
+ setTheme(theme === 'dark' ? 'light2' : 'dark');
30
+ }, [theme]);
31
+ return (_jsx("div", { className: classes.sidebarContainer, children: _jsxs("ul", { className: classes.sidebarUl, children: [themeEditable ? (_jsx("li", { className: classes.sidebarLi, children: _jsx(IconButton, { alt: "Change theme", onClick: onToggleTheme, "aria-label": "Change theme", className: classes.sidebarIconButton, children: _jsx(InvertColorsIcon, { className: classes.sidebarIcon }) }) })) : null, configEditable ? (_jsx("li", { className: classes.sidebarLi, children: _jsx(IconButton, { alt: "Edit configuration", onClick: () => { }, "aria-label": "Edit configuration", className: classes.sidebarIconButton, children: _jsx(CodeIcon, { className: classes.sidebarIcon }) }) })) : null] }) }));
32
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"VitS.d.ts","sourceRoot":"","sources":["../src/VitS.js"],"names":[],"mappings":"AAqCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,4BApCG;IAAsB,MAAM,EAApB,MAAM;IAGkB,SAAS,EAAjC,SAAS,GAAC,MAAM;IACF,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IAEU,MAAM;IACN,cAAc;IAEd,cAAc;IAEf,cAAc,EAA7B,OAAO;IAIQ,sBAAsB,EAArC,OAAO;IAGY,GAAG,EAAtB,IAAI,GAAC,MAAM;IAGW,cAAc,EAApC,SAAS,GAAC,IAAI;IAEC,kBAAkB,EAAjC,OAAO;IAEM,SAAS,EAAtB,KAAK;IACQ,SAAS,EAAtB,KAAK;IACQ,cAAc,EAA3B,KAAK;IACQ,iBAAiB,EAA9B,KAAK;IACc,OAAO,EAA1B,IAAI,GAAC,MAAM;IACI,QAAQ,EAAvB,OAAO;IACQ,SAAS,EAAxB,OAAO;IACY,QAAQ,EAA3B,IAAI,GAAC,MAAM;CAErB,eA0PA"}
1
+ {"version":3,"file":"VitS.d.ts","sourceRoot":"","sources":["../src/VitS.js"],"names":[],"mappings":"AAqCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,4BApCG;IAAsB,MAAM,EAApB,MAAM;IAGkB,SAAS,EAAjC,SAAS,GAAC,MAAM;IACF,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IAEU,MAAM;IACN,cAAc;IAEd,cAAc;IAEf,cAAc,EAA7B,OAAO;IAIQ,sBAAsB,EAArC,OAAO;IAGY,GAAG,EAAtB,IAAI,GAAC,MAAM;IAGW,cAAc,EAApC,SAAS,GAAC,IAAI;IAEC,kBAAkB,EAAjC,OAAO;IAEM,SAAS,EAAtB,KAAK;IACQ,SAAS,EAAtB,KAAK;IACQ,cAAc,EAA3B,KAAK;IACQ,iBAAiB,EAA9B,KAAK;IACc,OAAO,EAA1B,IAAI,GAAC,MAAM;IACI,QAAQ,EAAvB,OAAO;IACQ,SAAS,EAAxB,OAAO;IACY,QAAQ,EAA3B,IAAI,GAAC,MAAM;CAErB,eA4PA"}
package/dist-tsc/VitS.js CHANGED
@@ -176,7 +176,7 @@ export function VitS(props) {
176
176
  // Initialize the view config and loaders in the global state.
177
177
  const createViewConfigStoreClosure = useCallback(() => {
178
178
  if (success) {
179
- const loaders = createLoaders(configOrWarning.datasets, configOrWarning.description, fileTypes, coordinationTypes, stores);
179
+ const loaders = createLoaders(configOrWarning.datasets, configOrWarning.description, fileTypes, coordinationTypes, stores, queryClient);
180
180
  return createViewConfigStore(loaders, configOrWarning);
181
181
  }
182
182
  // No config found, so clear the loaders.
@@ -189,5 +189,5 @@ export function VitS(props) {
189
189
  if (debugMode && debugErrors.length > 0) {
190
190
  return (_jsx(CacheProvider, { value: muiCache, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(DebugWindow, { debugErrors: debugErrors }) }) }));
191
191
  }
192
- return success ? (_jsx(CacheProvider, { value: muiCache, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(ViewConfigProvider, { createStore: createViewConfigStoreClosure, children: _jsx(AuxiliaryProvider, { createStore: createAuxiliaryStore, children: _jsxs(AsyncFunctionsContext.Provider, { value: asyncFunctions, children: [_jsx(VitessceGrid, { pageMode: pageMode, success: success, configKey: configKey, viewTypes: viewTypes, fileTypes: fileTypes, coordinationTypes: coordinationTypes, config: configOrWarning, rowHeight: rowHeight, height: height, theme: theme, isBounded: isBounded, stores: stores, children: children }), _jsx(CallbackPublisher, { onWarn: onWarn, onConfigChange: onConfigChange, onLoaderChange: onLoaderChange, validateOnConfigChange: validateOnConfigChange, pluginSpecificConfigSchema: pluginSpecificConfigSchema })] }) }) }, (remountOnUidChange ? configKey : undefined)) }) }) })) : (_jsx(CacheProvider, { value: muiCache, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(Warning, { ...configOrWarning }) }) }));
192
+ return success ? (_jsx(CacheProvider, { value: muiCache, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(ViewConfigProvider, { createStore: createViewConfigStoreClosure, children: _jsx(AuxiliaryProvider, { createStore: createAuxiliaryStore, children: _jsxs(AsyncFunctionsContext.Provider, { value: asyncFunctions, children: [_jsx(VitessceGrid, { pageMode: pageMode, success: success, configKey: configKey, viewTypes: viewTypes, fileTypes: fileTypes, coordinationTypes: coordinationTypes, config: configOrWarning, rowHeight: rowHeight, height: height, theme: theme, isBounded: isBounded, stores: stores, queryClient: queryClient, children: children }), _jsx(CallbackPublisher, { onWarn: onWarn, onConfigChange: onConfigChange, onLoaderChange: onLoaderChange, validateOnConfigChange: validateOnConfigChange, pluginSpecificConfigSchema: pluginSpecificConfigSchema })] }) }) }, (remountOnUidChange ? configKey : undefined)) }) }) })) : (_jsx(CacheProvider, { value: muiCache, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(Warning, { ...configOrWarning }) }) }));
193
193
  }
@@ -1 +1 @@
1
- {"version":3,"file":"VitessceGrid.d.ts","sourceRoot":"","sources":["../src/VitessceGrid.js"],"names":[],"mappings":"AA+BA;;;;;;;;;;;;GAYG;AACH,4CAVG;IAAsB,SAAS,EAAvB,MAAM;IACQ,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,MAAM,EAApB,MAAM;IACU,MAAM;IACE,SAAS,EAAjC,cAAc,EAAE;IACQ,SAAS,EAAjC,cAAc,EAAE;IACgB,iBAAiB,EAAjD,sBAAsB,EAAE;IACT,QAAQ,EAAvB,OAAO;CACjB,eAsGA"}
1
+ {"version":3,"file":"VitessceGrid.d.ts","sourceRoot":"","sources":["../src/VitessceGrid.js"],"names":[],"mappings":"AA+BA;;;;;;;;;;;;GAYG;AACH,4CAVG;IAAsB,SAAS,EAAvB,MAAM;IACQ,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,MAAM,EAApB,MAAM;IACU,MAAM;IACE,SAAS,EAAjC,cAAc,EAAE;IACQ,SAAS,EAAjC,cAAc,EAAE;IACgB,iBAAiB,EAAjD,sBAAsB,EAAE;IACT,QAAQ,EAAvB,OAAO;CACjB,eAwGA"}
@@ -25,7 +25,7 @@ const margin = 5;
25
25
  * @param {boolean} props.pageMode
26
26
  */
27
27
  export default function VitessceGrid(props) {
28
- const { success, configKey, rowHeight: initialRowHeight, config, theme, height, isBounded, viewTypes, fileTypes, coordinationTypes, stores, pageMode, children, } = props;
28
+ const { success, configKey, rowHeight: initialRowHeight, config, theme, height, isBounded, viewTypes, fileTypes, coordinationTypes, stores, pageMode, children, queryClient, } = props;
29
29
  const [rowHeight, containerRef] = useRowHeight(config, initialRowHeight, height, margin, padding);
30
30
  const onResize = useEmitGridResize();
31
31
  const [componentWidth] = useClosestVitessceContainerSize(containerRef);
@@ -55,7 +55,7 @@ export default function VitessceGrid(props) {
55
55
  let newLoaders = null;
56
56
  let newConfig = null;
57
57
  if (success) {
58
- newLoaders = createLoaders(config.datasets, config.description, fileTypes, coordinationTypes, stores);
58
+ newLoaders = createLoaders(config.datasets, config.description, fileTypes, coordinationTypes, stores, queryClient);
59
59
  newConfig = config;
60
60
  }
61
61
  setViewConfig(newConfig);
@@ -39,7 +39,7 @@ export function useUrls(urls: (null | object[])[]): array;
39
39
  * @returns {array} `[width, height]` where width and height
40
40
  * are numbers.
41
41
  */
42
- export function useClosestVitessceContainerSize(ref: Ref): array;
42
+ export function useClosestVitessceContainerSize(ref: Ref, sidebarWidth: any): array;
43
43
  /**
44
44
  * Normalize an obsFeatureMatrix to a Uint8Array.
45
45
  * @param {object} params
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.js"],"names":[],"mappings":"AAqBA,oDAOC;AAED;;;;GAIG;AACH,uCAHa,KAAK,CAmBjB;AAED;;;;GAIG;AACH,mCAHa,KAAK,CAoCjB;AAED;;;;;GAKG;AACH,qCAJa,KAAK,CAqCjB;AAED;;;;;;GAMG;AACH,uCAHW,MAAM,EAAE,GACN,OAAO,CAOnB;AAED;;;;GAIG;AACH,8BAHW,CAAC,IAAI,GAAC,MAAM,EAAE,CAAC,EAAE,GACf,KAAK,CAYjB;AAED;;;;;;GAMG;AACH,qDAJW,GAAG,GACD,KAAK,CA0BjB;AAED;;;;;;;;;;GAUG;AACH,+DARG;IAAuB,gBAAgB,EAA/B,MAAM;CAEd,GAAU,KAAK,CAmBjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,yDAbW,YAAY,EAAE,GAAG,IAAI,GAInB;IACZ,QAAW,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IACjC,OAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC;IACtC,OAAU,EAAE,MAAM,EAAE,CAAA;CACjB,CAwBH;AAED;;;;QA2BC;AAED,iEAOC;AAED,kHA4BC;AAED;;;;;;;;;;GAUG;AACH,yDALW,MAAM,oBACN,gBAAI,IAAI,iBAEN;IAAE,kBAAkB,EAAE,OAAO,CAAA;CAAE,GAAC,IAAI,CAkChD;AAED;;;;;;;GAOG;AACH,6CALW,GAAC,YACD,CAAC,OAAO,CAAC,GAEP,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA8BlC"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.js"],"names":[],"mappings":"AAqBA,oDAOC;AAED;;;;GAIG;AACH,uCAHa,KAAK,CAmBjB;AAED;;;;GAIG;AACH,mCAHa,KAAK,CAoCjB;AAED;;;;;GAKG;AACH,qCAJa,KAAK,CAqCjB;AAED;;;;;;GAMG;AACH,uCAHW,MAAM,EAAE,GACN,OAAO,CAOnB;AAED;;;;GAIG;AACH,8BAHW,CAAC,IAAI,GAAC,MAAM,EAAE,CAAC,EAAE,GACf,KAAK,CAYjB;AAED;;;;;;GAMG;AACH,qDAJW,GAAG,sBACD,KAAK,CA0BjB;AAED;;;;;;;;;;GAUG;AACH,+DARG;IAAuB,gBAAgB,EAA/B,MAAM;CAEd,GAAU,KAAK,CAmBjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,yDAbW,YAAY,EAAE,GAAG,IAAI,GAInB;IACZ,QAAW,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IACjC,OAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC;IACtC,OAAU,EAAE,MAAM,EAAE,CAAA;CACjB,CAwBH;AAED;;;;QA2BC;AAED,iEAOC;AAED,kHA4BC;AAED;;;;;;;;;;GAUG;AACH,yDALW,MAAM,oBACN,gBAAI,IAAI,iBAEN;IAAE,kBAAkB,EAAE,OAAO,CAAA;CAAE,GAAC,IAAI,CAkChD;AAED;;;;;;;GAOG;AACH,6CALW,GAAC,YACD,CAAC,OAAO,CAAC,GAEP,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA8BlC"}
package/dist-tsc/hooks.js CHANGED
@@ -141,14 +141,14 @@ export function useUrls(urls) {
141
141
  * @returns {array} `[width, height]` where width and height
142
142
  * are numbers.
143
143
  */
144
- export function useClosestVitessceContainerSize(ref) {
144
+ export function useClosestVitessceContainerSize(ref, sidebarWidth) {
145
145
  const [height, setHeight] = useState();
146
146
  const [width, setWidth] = useState();
147
147
  useEffect(() => {
148
148
  function onWindowResize() {
149
149
  if (ref.current) {
150
150
  const { clientHeight: componentHeight, clientWidth: componentWidth, } = ref.current.closest(`.${VITESSCE_CONTAINER}`);
151
- setWidth(componentWidth);
151
+ setWidth(componentWidth - sidebarWidth);
152
152
  setHeight(componentHeight);
153
153
  }
154
154
  }
@@ -5,6 +5,7 @@ export { PopperMenu } from "./shared-mui/components.js";
5
5
  export { useHasLoader } from "./data-hook-utils.js";
6
6
  export { logConfig } from "./view-config-utils.js";
7
7
  export { createLoaders } from "./vitessce-grid-utils.js";
8
+ export { createOnDrop } from "./on-drop.js";
8
9
  export { useReady, useUrls, useVitessceContainer, useDeckCanvasSize, useUint8ObsFeatureMatrix, useUint8FeatureSelection, useExpressionValueGetter, useGetObsMembership, useGetObsInfo, useClosestVitessceContainerSize, useWindowDimensions, useGridItemSize, useExpandedFeatureLabelsMap, useColumnNameMapping } from "./hooks.js";
9
10
  export { useCoordinationScopes, useCoordinationScopesBy, useInitialCoordination, useCoordination, useComplexCoordination, useComplexCoordinationSecondary, useMultiCoordinationScopes, useMultiCoordinationScopesNonNull, useMultiCoordinationScopesSecondary, useMultiCoordinationScopesSecondaryNonNull, useMultiCoordinationValues, useMultiDatasetCoordination, useDatasetUids, useLoaders, useMergeCoordination, useMatchingLoader, useViewConfigStore, useViewConfigStoreApi, useViewConfig, useSetViewConfig, useComponentHover, useSetComponentHover, useComponentViewInfo, useSetComponentViewInfo, useWarning, useSetWarning, useAuxiliaryCoordination, useComponentLayout, useRemoveImageChannelInMetaCoordinationScopes, useAddImageChannelInMetaCoordinationScopes } from "./state/hooks.js";
10
11
  export { useDescription, useImageData, useObsSetsData, useObsEmbeddingData, useFeatureSelection, useObsFeatureMatrixIndices, useSampleSetsData, useSampleEdgesData, useMultiObsLabels, useMultiObsSpots, useMultiObsPoints, useSpotMultiObsSets, useSpotMultiFeatureLabels, useMultiObsSegmentations, useMultiImages, useObsSpotsData, useObsPointsData, useObsLocationsData, useObsSegmentationsData, useNeighborhoodsData, useObsLabelsData, useObsFeatureMatrixData, useFeatureLabelsData, useGenomicProfilesData, useComparisonMetadata, useFeatureStatsData, useFeatureSetStatsData, useObsSetStatsData } from "./data-hooks.js";
package/dist-tsc/index.js CHANGED
@@ -12,3 +12,4 @@ export { CellColorEncodingOption, OptionsContainer, OptionSelect, usePlotOptions
12
12
  export { logConfig } from './view-config-utils.js';
13
13
  export { useAsyncFunction, usePageModeView } from './contexts.js';
14
14
  export { createLoaders } from './vitessce-grid-utils.js';
15
+ export { createOnDrop } from './on-drop.js';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Create an event handler for either dropzone or input type="file" elements.
3
+ * @param {object} setters - The parameters for the drop event handler.
4
+ * @param {function} setters.setViewConfig - A function to set the view config.
5
+ * @param {function} setters.setStores - A function to set the stores.
6
+ * @param {boolean} isFileInput - Whether the drop zone is for file input.
7
+ * By default, false.
8
+ * @param {boolean} isConfigInput - Whether the drop zone is for config input.
9
+ * By default, false.
10
+ * @returns A drop event handler async function.
11
+ */
12
+ export function createOnDrop(setters: {
13
+ setViewConfig: Function;
14
+ setStores: Function;
15
+ }, isFileInput?: boolean, isConfigInput?: boolean): (e: any) => Promise<void>;
16
+ //# sourceMappingURL=on-drop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"on-drop.d.ts","sourceRoot":"","sources":["../src/on-drop.js"],"names":[],"mappings":"AAoEA;;;;;;;;;;GAUG;AACH,sCARG;IAA0B,aAAa;IACb,SAAS;CACnC,gBAAQ,OAAO,kBAEP,OAAO,6BAyHjB"}
@@ -0,0 +1,180 @@
1
+ import { getFilesFromDataTransferItems } from '@placemarkio/flat-drop-files';
2
+ import { generateConfigAlt as generateConfig, parseUrlsFromString } from '@vitessce/config';
3
+ // Stores
4
+ // This "flat" store can be slow to initialize when the Zarr store contains many files.
5
+ class FlatFileSystemStore {
6
+ constructor(files) {
7
+ this.files = files;
8
+ }
9
+ async get(key) {
10
+ // The list of files does not prefix its paths with slashes.
11
+ const file = this.files.find(f => `/${f.relpath}` === key);
12
+ if (!file)
13
+ return undefined;
14
+ const buffer = await file.arrayBuffer();
15
+ return new Uint8Array(buffer);
16
+ }
17
+ }
18
+ /*
19
+ // Get a file handle to a file in a directory.
20
+ async function resolveFileHandleForPath(
21
+ root, // A root directory from the Web File System API.
22
+ path, // A key to a file in the root directory.
23
+ ) {
24
+ const dirs = path.split('/');
25
+ const fname = dirs.pop();
26
+ if (!fname) {
27
+ throw new Error('Invalid path');
28
+ }
29
+ for (const dir of dirs) {
30
+ root = await root.getDirectoryHandle(dir);
31
+ }
32
+ // Returns a file handle to the file.
33
+ return root.getFileHandle(fname);
34
+ }
35
+
36
+ // TODO: use this hierarchical store to avoid the issues with flattening the file tree up-front,
37
+ // as this store only traverses/accesses the parts of the tree that are needed.
38
+ class HierarchicalFileSystemStore {
39
+ constructor(root) {
40
+ // root is a FileSystemDirectoryHandle
41
+ this.root = root;
42
+ }
43
+
44
+ async get(key) {
45
+ // TODO: better error handling
46
+ // I believe a missing file will trigger an error here, which we should explicitly
47
+ // catch and return `undefined`
48
+ const fh = await resolveFileHandleForPath(this.root, key.slice(1)).catch(
49
+ () => undefined,
50
+ );
51
+ if (!fh) {
52
+ return undefined;
53
+ }
54
+
55
+ const file = await fh.getFile();
56
+ return file.arrayBuffer();
57
+ }
58
+
59
+ // TODO: implement getRange
60
+ }
61
+ */
62
+ /**
63
+ * Create an event handler for either dropzone or input type="file" elements.
64
+ * @param {object} setters - The parameters for the drop event handler.
65
+ * @param {function} setters.setViewConfig - A function to set the view config.
66
+ * @param {function} setters.setStores - A function to set the stores.
67
+ * @param {boolean} isFileInput - Whether the drop zone is for file input.
68
+ * By default, false.
69
+ * @param {boolean} isConfigInput - Whether the drop zone is for config input.
70
+ * By default, false.
71
+ * @returns A drop event handler async function.
72
+ */
73
+ export function createOnDrop(setters, isFileInput = false, isConfigInput = false) {
74
+ return async (e) => {
75
+ const { setViewConfig, setStores } = setters;
76
+ let topLevelEntries;
77
+ let files;
78
+ if (isFileInput) {
79
+ // Reference: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop
80
+ // Note: e.target.files is a FileList, not an array.
81
+ // If we use the spread operator, the methods like file.arrayBuffer() get lost.
82
+ files = Array.from(e.target.files);
83
+ // Here, we use files.forEach rather than files = files.map
84
+ // so that we can modify the original array in place.
85
+ files.forEach((f, i) => {
86
+ if (!f.path) {
87
+ // eslint-disable-next-line no-param-reassign
88
+ files[i].path = files[i].webkitRelativePath;
89
+ }
90
+ });
91
+ // When a user selects a directory via a file picker dialog,
92
+ // we get only a flat list of files.
93
+ // In order to match e.dataTransfer.items behavior,
94
+ // we create fake top-level entries for each unique directory/file name.
95
+ const dirNames = new Set();
96
+ topLevelEntries = [];
97
+ Array.from(files).forEach((file) => {
98
+ const dirName = file.path.split('/')[0];
99
+ if (dirName) {
100
+ dirNames.add(dirName);
101
+ }
102
+ // If the file is at the top level (no directory),
103
+ // we need to add a top-level entry for it.
104
+ if (dirName === file.name) {
105
+ topLevelEntries.push({
106
+ isDirectory: false,
107
+ name: file.name,
108
+ });
109
+ }
110
+ });
111
+ topLevelEntries = topLevelEntries.concat(Array.from(dirNames).map(name => ({
112
+ isDirectory: true,
113
+ name,
114
+ })));
115
+ }
116
+ else {
117
+ topLevelEntries = Object.values(e.dataTransfer.items)
118
+ .map(item => item.webkitGetAsEntry());
119
+ files = await getFilesFromDataTransferItems(e.dataTransfer.items);
120
+ }
121
+ if (isConfigInput) {
122
+ // We expect a single file which contains the config JSON.
123
+ if (files.length === 1) {
124
+ const file = files[0];
125
+ if (file.name.endsWith('.json')) {
126
+ const content = await file.arrayBuffer();
127
+ // Alternatively, use the FileReader API.
128
+ const json = JSON.parse(new TextDecoder().decode(content));
129
+ setViewConfig(json);
130
+ return;
131
+ }
132
+ }
133
+ }
134
+ // TODO: implement an alternative approach that does not first flatten the file tree,
135
+ // since it can be very large.
136
+ // See https://github.com/manzt/zarrita.js/pull/161/files
137
+ const stores = topLevelEntries.map((entry) => {
138
+ if (entry.isDirectory) {
139
+ // TODO: optimize by using a single loop for filter+map,
140
+ // and by using .substring (rather than split+slice+join).
141
+ const dirFiles = files
142
+ .filter(f => f.path.split('/')?.[0] === entry.name)
143
+ .map((f) => {
144
+ // eslint-disable-next-line no-param-reassign
145
+ f.relpath = f.path.split('/')?.slice(1).join('/');
146
+ return f;
147
+ });
148
+ // Create a store for each top-level item of e.dataTransfer.items.
149
+ const store = new FlatFileSystemStore(dirFiles);
150
+ return [entry.name, store];
151
+ }
152
+ // This is a single file. Check extension to determine how to create a store.
153
+ if (entry.name.endsWith('.zip')) {
154
+ // Create a zip store.
155
+ // TODO
156
+ }
157
+ else if (entry.name.endsWith('.tif') || entry.name.endsWith('.tiff')) {
158
+ // Create an OME-TIFF-as-NGFF store?
159
+ // TODO
160
+ }
161
+ else if (entry.name.endsWith('.csv')) {
162
+ // Create a CSV store?
163
+ // TODO
164
+ }
165
+ else {
166
+ // Throw?
167
+ // TODO
168
+ }
169
+ return [entry.name, null];
170
+ });
171
+ const parsedUrls = stores.map(([name, store]) => ({
172
+ ...parseUrlsFromString(name)[0],
173
+ store,
174
+ }));
175
+ const { config, stores: storesForConfig } = await generateConfig(parsedUrls);
176
+ const newConfig = config.toJSON();
177
+ setViewConfig(newConfig);
178
+ setStores(storesForConfig);
179
+ };
180
+ }
@@ -7,8 +7,9 @@ export function useRowHeight(config: any, initialRowHeight: any, height: any, ma
7
7
  * @param {PluginFileType[]} fileTypes
8
8
  * @param {PluginCoordinationType[]} coordinationTypes
9
9
  * @param {object} stores Optional mapping from URLs to Zarrita stores.
10
+ * @param {QueryClient} queryClient A react-query QueryClient instance.
10
11
  * @returns {object} Mapping from dataset ID to data type to loader
11
12
  * instance.
12
13
  */
13
- export function createLoaders(datasets: object[], configDescription: string, fileTypes: PluginFileType[], coordinationTypes: PluginCoordinationType[], stores: object): object;
14
+ export function createLoaders(datasets: object[], configDescription: string, fileTypes: PluginFileType[], coordinationTypes: PluginCoordinationType[], stores: object, queryClient: QueryClient): object;
14
15
  //# sourceMappingURL=vitessce-grid-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vitessce-grid-utils.d.ts","sourceRoot":"","sources":["../src/vitessce-grid-utils.js"],"names":[],"mappings":"AAyCA,gHA6CC;AA4BD;;;;;;;;;;GAUG;AACH,wCATW,MAAM,EAAE,qBACR,MAAM,aAEN,cAAc,EAAE,qBAChB,sBAAsB,EAAE,UACxB,MAAM,GACJ,MAAM,CAmElB"}
1
+ {"version":3,"file":"vitessce-grid-utils.d.ts","sourceRoot":"","sources":["../src/vitessce-grid-utils.js"],"names":[],"mappings":"AAyCA,gHA6CC;AA4BD;;;;;;;;;;;GAWG;AACH,wCAVW,MAAM,EAAE,qBACR,MAAM,aAEN,cAAc,EAAE,qBAChB,sBAAsB,EAAE,UACxB,MAAM,eACN,WAAW,GACT,MAAM,CA2ElB"}
@@ -103,10 +103,11 @@ function withDefaults(coordinationValues, dataType, fileType, datasetUid, defaul
103
103
  * @param {PluginFileType[]} fileTypes
104
104
  * @param {PluginCoordinationType[]} coordinationTypes
105
105
  * @param {object} stores Optional mapping from URLs to Zarrita stores.
106
+ * @param {QueryClient} queryClient A react-query QueryClient instance.
106
107
  * @returns {object} Mapping from dataset ID to data type to loader
107
108
  * instance.
108
109
  */
109
- export function createLoaders(datasets, configDescription, fileTypes, coordinationTypes, stores) {
110
+ export function createLoaders(datasets, configDescription, fileTypes, coordinationTypes, stores, queryClient) {
110
111
  const result = {};
111
112
  const dataSources = new InternMap([], JSON.stringify);
112
113
  const defaultCoordinationValues = Object.fromEntries(coordinationTypes.map(ct => ([ct.name, ct.defaultValue])));
@@ -142,6 +143,7 @@ export function createLoaders(datasets, configDescription, fileTypes, coordinati
142
143
  // Optionally, pass a Zarrita store to the data source,
143
144
  // if one was mapped to this URL.
144
145
  store: stores?.[url],
146
+ queryClient,
145
147
  }));
146
148
  }
147
149
  const loader = new LoaderClass(dataSources.get(dataSourceKey), file);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitessce/vit-s",
3
- "version": "3.8.5",
3
+ "version": "3.8.7",
4
4
  "author": "HIDIVE Lab at HMS",
5
5
  "homepage": "http://vitessce.io",
6
6
  "repository": {
@@ -28,16 +28,18 @@
28
28
  "zustand": "^5.0.4",
29
29
  "react-aria": "^3.28.0",
30
30
  "react-error-boundary": "^5.0.0",
31
- "@vitessce/styles": "3.8.5",
32
- "@vitessce/abstract": "3.8.5",
33
- "@vitessce/error": "3.8.5",
34
- "@vitessce/constants-internal": "3.8.5",
35
- "@vitessce/plugins": "3.8.5",
36
- "@vitessce/schemas": "3.8.5",
37
- "@vitessce/utils": "3.8.5",
38
- "@vitessce/sets-utils": "3.8.5",
39
- "@vitessce/config": "3.8.5",
40
- "@vitessce/globals": "3.8.5"
31
+ "@placemarkio/flat-drop-files": "^1.0.2",
32
+ "zarrita": "0.5.4",
33
+ "@vitessce/styles": "3.8.7",
34
+ "@vitessce/abstract": "3.8.7",
35
+ "@vitessce/error": "3.8.7",
36
+ "@vitessce/constants-internal": "3.8.7",
37
+ "@vitessce/plugins": "3.8.7",
38
+ "@vitessce/schemas": "3.8.7",
39
+ "@vitessce/utils": "3.8.7",
40
+ "@vitessce/sets-utils": "3.8.7",
41
+ "@vitessce/config": "3.8.7",
42
+ "@vitessce/globals": "3.8.7"
41
43
  },
42
44
  "devDependencies": {
43
45
  "@testing-library/jest-dom": "^6.6.3",
@@ -46,7 +48,7 @@
46
48
  "react-dom": "18.3.1",
47
49
  "vite": "^7.0.0",
48
50
  "vitest": "^3.1.4",
49
- "@vitessce/types": "3.8.5"
51
+ "@vitessce/types": "3.8.7"
50
52
  },
51
53
  "peerDependencies": {
52
54
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
package/src/Sidebar.js ADDED
@@ -0,0 +1,80 @@
1
+ import React, { useCallback } from 'react';
2
+ import {
3
+ makeStyles,
4
+ IconButton,
5
+ Code as CodeIcon,
6
+ InvertColors as InvertColorsIcon,
7
+ } from '@vitessce/styles';
8
+
9
+ const useStyles = makeStyles()(() => ({
10
+ sidebarContainer: {
11
+ backgroundColor: 'silver',
12
+ width: '30px',
13
+ height: '100%',
14
+ },
15
+ sidebarUl: {
16
+ listStyleType: 'none',
17
+ margin: 0,
18
+ padding: 0,
19
+ },
20
+ sidebarLi: {
21
+
22
+ },
23
+ sidebarIconButton: {
24
+ padding: '3px',
25
+ },
26
+ sidebarIcon: {
27
+ color: 'black',
28
+ width: '24px',
29
+ height: '24px',
30
+ },
31
+ }));
32
+
33
+ export function Sidebar(props) {
34
+ const {
35
+ theme,
36
+ setTheme,
37
+ configEditable,
38
+ themeEditable,
39
+ } = props;
40
+ const { classes } = useStyles();
41
+
42
+ const onToggleTheme = useCallback(() => {
43
+ setTheme(theme === 'dark' ? 'light2' : 'dark');
44
+ }, [theme]);
45
+
46
+ return (
47
+ <div className={classes.sidebarContainer}>
48
+ <ul className={classes.sidebarUl}>
49
+ {themeEditable ? (
50
+ <li className={classes.sidebarLi}>
51
+ <IconButton
52
+ alt="Change theme"
53
+ onClick={onToggleTheme}
54
+ aria-label="Change theme"
55
+ className={classes.sidebarIconButton}
56
+ >
57
+ <InvertColorsIcon
58
+ className={classes.sidebarIcon}
59
+ />
60
+ </IconButton>
61
+ </li>
62
+ ) : null}
63
+ {configEditable ? (
64
+ <li className={classes.sidebarLi}>
65
+ <IconButton
66
+ alt="Edit configuration"
67
+ onClick={() => {}}
68
+ aria-label="Edit configuration"
69
+ className={classes.sidebarIconButton}
70
+ >
71
+ <CodeIcon
72
+ className={classes.sidebarIcon}
73
+ />
74
+ </IconButton>
75
+ </li>
76
+ ) : null}
77
+ </ul>
78
+ </div>
79
+ );
80
+ }
package/src/VitS.js CHANGED
@@ -257,6 +257,7 @@ export function VitS(props) {
257
257
  fileTypes,
258
258
  coordinationTypes,
259
259
  stores,
260
+ queryClient,
260
261
  );
261
262
  return createViewConfigStore(loaders, configOrWarning);
262
263
  }
@@ -300,6 +301,7 @@ export function VitS(props) {
300
301
  theme={theme}
301
302
  isBounded={isBounded}
302
303
  stores={stores}
304
+ queryClient={queryClient}
303
305
  >
304
306
  {children}
305
307
  </VitessceGrid>
@@ -57,6 +57,7 @@ export default function VitessceGrid(props) {
57
57
  stores,
58
58
  pageMode,
59
59
  children,
60
+ queryClient,
60
61
  } = props;
61
62
 
62
63
  const [rowHeight, containerRef] = useRowHeight(config, initialRowHeight, height, margin, padding);
@@ -101,6 +102,7 @@ export default function VitessceGrid(props) {
101
102
  fileTypes,
102
103
  coordinationTypes,
103
104
  stores,
105
+ queryClient,
104
106
  );
105
107
  newConfig = config;
106
108
  }
package/src/hooks.js CHANGED
@@ -170,7 +170,7 @@ export function useUrls(urls) {
170
170
  * @returns {array} `[width, height]` where width and height
171
171
  * are numbers.
172
172
  */
173
- export function useClosestVitessceContainerSize(ref) {
173
+ export function useClosestVitessceContainerSize(ref, sidebarWidth) {
174
174
  const [height, setHeight] = useState();
175
175
  const [width, setWidth] = useState();
176
176
 
@@ -180,7 +180,7 @@ export function useClosestVitessceContainerSize(ref) {
180
180
  const {
181
181
  clientHeight: componentHeight, clientWidth: componentWidth,
182
182
  } = ref.current.closest(`.${VITESSCE_CONTAINER}`);
183
- setWidth(componentWidth);
183
+ setWidth(componentWidth - sidebarWidth);
184
184
  setHeight(componentHeight);
185
185
  }
186
186
  }
package/src/index.js CHANGED
@@ -105,3 +105,4 @@ export {
105
105
  export { logConfig } from './view-config-utils.js';
106
106
  export { useAsyncFunction, usePageModeView } from './contexts.js';
107
107
  export { createLoaders } from './vitessce-grid-utils.js';
108
+ export { createOnDrop } from './on-drop.js';