@vitessce/vit-s 3.6.0 → 3.6.2

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.
@@ -1,9 +1,15 @@
1
1
  /* eslint-disable max-len */
2
2
  /* eslint-disable react-refresh/only-export-components */
3
- import { useRef, useCallback, useMemo } from 'react';
4
- import create from 'zustand';
5
- import createContext from 'zustand/context';
6
- import shallow from 'zustand/shallow';
3
+ import React, {
4
+ useCallback,
5
+ useRef,
6
+ useMemo,
7
+ createContext,
8
+ useContext,
9
+ } from 'react';
10
+ import { create, useStore } from 'zustand';
11
+ import { useShallow } from 'zustand/shallow';
12
+ import { subscribeWithSelector } from 'zustand/middleware';
7
13
  import { isMatch, cloneDeep } from 'lodash-es';
8
14
  import { CoordinationType } from '@vitessce/constants-internal';
9
15
  import { capitalize } from '@vitessce/utils';
@@ -13,25 +19,95 @@ import {
13
19
  addImageChannelInMetaCoordinationScopesHelper,
14
20
  } from './spatial-reducers.js';
15
21
 
16
- // Reference: https://github.com/pmndrs/zustand#react-context
17
- // Reference: https://github.com/pmndrs/zustand/blob/e47ea03/tests/context.test.tsx#L60
18
- const {
19
- Provider: ViewConfigProviderLocal,
20
- useStore: useViewConfigStoreLocal,
21
- useStoreApi: useViewConfigStoreApiLocal,
22
- } = createContext();
22
+ // References for Zustand v3:
23
+ // - https://github.com/pmndrs/zustand#react-context
24
+ // - https://github.com/pmndrs/zustand/blob/e47ea03/tests/context.test.tsx#L60
25
+ // References for Zustand v4:
26
+ // - https://github.com/pmndrs/zustand/discussions/1180#discussioncomment-3354713
27
+ // - https://zustand.docs.pmnd.rs/previous-versions/zustand-v3-create-context#migration
28
+ const ViewConfigStoreContext = createContext(null);
29
+ const AuxiliaryStoreContext = createContext(null);
30
+
31
+ export function ViewConfigProvider(props) {
32
+ const {
33
+ createStore,
34
+ children,
35
+ } = props;
36
+
37
+ // Reference: https://github.com/pmndrs/zustand/discussions/1180
38
+ const storeRef = useRef();
39
+ if (!storeRef.current) {
40
+ storeRef.current = createStore();
41
+ }
42
+
43
+ return (
44
+ <ViewConfigStoreContext.Provider value={storeRef.current}>
45
+ {children}
46
+ </ViewConfigStoreContext.Provider>
47
+ );
48
+ }
49
+
50
+ export function useViewConfigStoreApi() {
51
+ const store = useContext(ViewConfigStoreContext);
52
+ if (!store) {
53
+ throw new Error('Missing StoreProvider');
54
+ }
55
+ return store;
56
+ }
57
+ export function useViewConfigStore(selector) {
58
+ const store = useViewConfigStoreApi();
59
+ if (!store) {
60
+ throw new Error('Missing StoreProvider');
61
+ }
62
+ const slice = useStore(store, selector);
63
+ return slice;
64
+ }
65
+
66
+ export function useViewConfigStoreShallow(selector) {
67
+ return useViewConfigStore(useShallow(selector));
68
+ }
69
+
70
+ /* Begin auxiliary store things */
71
+ export function AuxiliaryProvider(props) {
72
+ const {
73
+ createStore,
74
+ children,
75
+ } = props;
76
+
77
+ // Reference: https://github.com/pmndrs/zustand/discussions/1180
78
+ const storeRef = useRef();
79
+ if (!storeRef.current) {
80
+ storeRef.current = createStore();
81
+ }
82
+
83
+ return (
84
+ <AuxiliaryStoreContext.Provider value={storeRef.current}>
85
+ {children}
86
+ </AuxiliaryStoreContext.Provider>
87
+ );
88
+ }
23
89
 
24
- export const ViewConfigProvider = ViewConfigProviderLocal;
25
- export const useViewConfigStore = useViewConfigStoreLocal;
26
- export const useViewConfigStoreApi = useViewConfigStoreApiLocal;
90
+ export function useAuxiliaryStoreApi() {
91
+ const store = useContext(AuxiliaryStoreContext);
92
+ if (!store) {
93
+ throw new Error('Missing StoreProvider');
94
+ }
95
+ return store;
96
+ }
97
+ export function useAuxiliaryStore(selector) {
98
+ const store = useAuxiliaryStoreApi();
99
+ if (!store) {
100
+ throw new Error('Missing StoreProvider');
101
+ }
102
+ const slice = useStore(store, selector);
103
+ return slice;
104
+ }
27
105
 
28
- const {
29
- Provider: AuxiliaryProviderLocal,
30
- useStore: useAuxiliaryStoreLocal,
31
- } = createContext();
106
+ export function useAuxiliaryStoreShallow(selector) {
107
+ return useAuxiliaryStore(useShallow(selector));
108
+ }
109
+ /* end auxiliary store things */
32
110
 
33
- export const AuxiliaryProvider = AuxiliaryProviderLocal;
34
- export const useAuxiliaryStore = useAuxiliaryStoreLocal;
35
111
 
36
112
  /**
37
113
  * Get the "computed" coordinationScopes after accounting for
@@ -160,7 +236,7 @@ export function getParameterScopeBy(
160
236
  * - https://github.com/pmndrs/zustand#using-subscribe-with-selector
161
237
  * @returns {function} The useStore hook.
162
238
  */
163
- export const createViewConfigStore = (initialLoaders, initialConfig) => create(set => ({
239
+ export const createViewConfigStore = (initialLoaders, initialConfig) => create()(subscribeWithSelector(set => ({
164
240
  // State:
165
241
  // The viewConfig is an object which must conform to the schema
166
242
  // found in src/schemas/config.schema.json.
@@ -348,14 +424,14 @@ export const createViewConfigStore = (initialLoaders, initialConfig) => create(s
348
424
  mostRecentConfigSource: 'internal',
349
425
  };
350
426
  }),
351
- }));
427
+ })));
352
428
 
353
429
  /**
354
430
  * Hook for getting components' layout from the view config based on
355
431
  * matching all coordination scopes.
356
432
  * @returns {Object} The components' layout.
357
433
  */
358
- export const useComponentLayout = (component, scopes, coordinationScopes) => useViewConfigStore(
434
+ export const useComponentLayout = (component, scopes, coordinationScopes) => useViewConfigStoreShallow(
359
435
  state => state.viewConfig.layout.filter(l => l.component === component).filter(
360
436
  l => scopes.every(scope => l.coordinationScopes[scope]
361
437
  === coordinationScopes[scope]),
@@ -455,7 +531,7 @@ const useGridSizeStore = create(set => ({
455
531
  * @returns {object} Object containing all coordination values.
456
532
  */
457
533
  export function useInitialCoordination(parameters, coordinationScopes) {
458
- const values = useViewConfigStore((state) => {
534
+ const values = useViewConfigStoreShallow((state) => {
459
535
  const { coordinationSpace } = state.initialViewConfig;
460
536
  return Object.fromEntries(parameters.map((parameter) => {
461
537
  if (coordinationSpace && coordinationSpace[parameter]) {
@@ -464,7 +540,7 @@ export function useInitialCoordination(parameters, coordinationScopes) {
464
540
  }
465
541
  return [parameter, undefined];
466
542
  }));
467
- }, shallow);
543
+ });
468
544
  return values;
469
545
  }
470
546
 
@@ -487,7 +563,7 @@ export function useInitialCoordination(parameters, coordinationScopes) {
487
563
  export function useCoordination(parameters, coordinationScopes) {
488
564
  const setCoordinationValue = useViewConfigStore(state => state.setCoordinationValue);
489
565
 
490
- const values = useViewConfigStore((state) => {
566
+ const values = useViewConfigStoreShallow((state) => {
491
567
  const { coordinationSpace } = state.viewConfig;
492
568
  return Object.fromEntries(parameters.map((parameter) => {
493
569
  if (coordinationSpace) {
@@ -499,7 +575,7 @@ export function useCoordination(parameters, coordinationScopes) {
499
575
  }
500
576
  return [parameter, undefined];
501
577
  }));
502
- }, shallow);
578
+ });
503
579
 
504
580
  const setters = useMemo(() => Object.fromEntries(parameters.map((parameter) => {
505
581
  const setterName = `set${capitalize(parameter)}`;
@@ -527,10 +603,10 @@ export function useMultiCoordinationScopesNonNull(parameter, coordinationScopes)
527
603
 
528
604
  // Return array of coordination scopes,
529
605
  // but filter out any whose value is null / falsey.
530
- const parameterSpace = useViewConfigStore((state) => {
606
+ const parameterSpace = useViewConfigStoreShallow((state) => {
531
607
  const { coordinationSpace } = state.viewConfig;
532
608
  return coordinationSpace?.[parameter];
533
- }, shallow);
609
+ });
534
610
  const nonNullScopes = useMemo(() => {
535
611
  // Convert a single scope to an array of scopes to be consistent.
536
612
  const scopesArr = Array.isArray(scopes) ? scopes : [scopes];
@@ -580,14 +656,14 @@ export function useMultiCoordinationScopesSecondaryNonNull(
580
656
  ) {
581
657
  const scopes = getParameterScope(byType, coordinationScopes);
582
658
 
583
- const parameterSpace = useViewConfigStore((state) => {
659
+ const parameterSpace = useViewConfigStoreShallow((state) => {
584
660
  const { coordinationSpace } = state.viewConfig;
585
661
  return coordinationSpace?.[parameter];
586
- }, shallow);
587
- const byTypeSpace = useViewConfigStore((state) => {
662
+ });
663
+ const byTypeSpace = useViewConfigStoreShallow((state) => {
588
664
  const { coordinationSpace } = state.viewConfig;
589
665
  return coordinationSpace?.[byType];
590
- }, shallow);
666
+ });
591
667
 
592
668
  return useMemo(() => {
593
669
  if (scopes && coordinationScopesBy?.[byType]?.[parameter]) {
@@ -647,7 +723,7 @@ export function useMultiCoordinationValues(parameter, coordinationScopes) {
647
723
  const scopes = getParameterScope(parameter, coordinationScopes);
648
724
 
649
725
  // Mapping from dataset coordination scope name to dataset uid
650
- const vals = useViewConfigStore((state) => {
726
+ const vals = useViewConfigStoreShallow((state) => {
651
727
  const { coordinationSpace } = state.viewConfig;
652
728
  // Convert a single scope to an array of scopes to be consistent.
653
729
  const scopesArr = Array.isArray(scopes) ? scopes : [scopes];
@@ -659,7 +735,7 @@ export function useMultiCoordinationValues(parameter, coordinationScopes) {
659
735
  return [scope, undefined];
660
736
  // eslint-disable-next-line no-unused-vars
661
737
  }).filter(([k, v]) => v !== undefined));
662
- }, shallow);
738
+ });
663
739
 
664
740
  return vals;
665
741
  }
@@ -692,10 +768,10 @@ export function useComplexCoordination(
692
768
  ) {
693
769
  const setCoordinationValue = useViewConfigStore(state => state.setCoordinationValue);
694
770
 
695
- const parameterSpaces = useViewConfigStore((state) => {
771
+ const parameterSpaces = useViewConfigStoreShallow((state) => {
696
772
  const { coordinationSpace } = state.viewConfig;
697
773
  return parameters.map(parameter => coordinationSpace[parameter]);
698
- }, shallow);
774
+ });
699
775
 
700
776
  const values = useMemo(() => {
701
777
  const typeScopes = getParameterScope(byType, coordinationScopes);
@@ -766,10 +842,10 @@ export function useComplexCoordination(
766
842
  * @returns {object} The coordinationScopes after filling in with meta-coordinationScopes.
767
843
  */
768
844
  export function useCoordinationScopes(coordinationScopes) {
769
- const metaSpace = useViewConfigStore((state) => {
845
+ const metaSpace = useViewConfigStoreShallow((state) => {
770
846
  const { coordinationSpace } = state.viewConfig;
771
847
  return coordinationSpace?.[CoordinationType.META_COORDINATION_SCOPES];
772
- }, shallow);
848
+ });
773
849
  const vals = useMemo(() => {
774
850
  const scopes = getScopes(
775
851
  coordinationScopes,
@@ -790,10 +866,10 @@ export function useCoordinationScopes(coordinationScopes) {
790
866
  * @returns {object} The coordinationScopesBy after filling in with meta-coordinationScopesBy.
791
867
  */
792
868
  export function useCoordinationScopesBy(coordinationScopes, coordinationScopesBy) {
793
- const metaSpaceBy = useViewConfigStore((state) => {
869
+ const metaSpaceBy = useViewConfigStoreShallow((state) => {
794
870
  const { coordinationSpace } = state.viewConfig;
795
871
  return coordinationSpace?.[CoordinationType.META_COORDINATION_SCOPES_BY];
796
- }, shallow);
872
+ });
797
873
  const vals = useMemo(() => {
798
874
  const scopesBy = getScopesBy(
799
875
  coordinationScopes,
@@ -950,7 +1026,7 @@ export function useAuxiliaryCoordination(parameters, coordinationScopes) {
950
1026
  const setCoordinationValue = useAuxiliaryStore(state => state.setCoordinationValue);
951
1027
  const mappedCoordinationScopes = mapCoordinationScopes(coordinationScopes);
952
1028
  const mappedParameters = mapParameters(parameters);
953
- const values = useAuxiliaryStore((state) => {
1029
+ const values = useAuxiliaryStoreShallow((state) => {
954
1030
  const { auxiliaryStore } = state;
955
1031
  return Object.fromEntries(mappedParameters.map((parameter) => {
956
1032
  if (auxiliaryStore && auxiliaryStore[parameter]) {
@@ -959,7 +1035,7 @@ export function useAuxiliaryCoordination(parameters, coordinationScopes) {
959
1035
  }
960
1036
  return [parameter, undefined];
961
1037
  }));
962
- }, shallow);
1038
+ });
963
1039
  const setters = useMemo(() => Object.fromEntries(mappedParameters.map((parameter) => {
964
1040
  const setterName = `set${capitalize(parameter)}`;
965
1041
  const setterFunc = value => setCoordinationValue({