Migrate to nanostores (#779)

Ref https://github.com/nanostores/nanostores

Nanostores is another open source implementation of reactive states.
Supports a lot of frameworks and provides useful utilities like computed
stores. Api is slightly different

```
store.get(): Value
store.set(value: Value)
```

`useStore` resolves only value so I temporary added custom `useValue` to
not rewrite whole project. Since we gonna use computed atoms it makes
more sense to invoke useStore where atom value is used instead of
reusable hook.
This commit is contained in:
Bogdan Chadkin authored and GitHub committed 2023-01-13 15:13:40 +03:00
1 parent 44a7083fde
commit 3abb54a875
17 files changed
+136 -110

No files matched your search

+3 -3
View File
@@ -17,7 +17,6 @@ import { useShortcuts } from "./shared/use-shortcuts";
import {
useDeleteInstance,
useInsertInstance,
usePopulateRootInstance,
usePublishSelectedInstanceData,
usePublishTextEditingInstanceId,
useReparentInstance,
@@ -38,6 +37,7 @@ import {
useBreakpoints,
useRootInstance,
useSetPresetStyles,
useSetRootInstance,
useSetStyles,
useSubscribeScrollState,
} from "~/shared/nano-states";
@@ -105,7 +105,7 @@ const useAssets = (initialAssets: Array<Asset>) => {
const useCopyPaste = () => {
const [instance] = useSelectedInstance();
const [allUserProps] = useAllUserProps();
const allUserProps = useAllUserProps();
const selectedInstanceData = useMemo(
() => instance && { instance, props: allUserProps[instance.id]?.props },
@@ -172,7 +172,7 @@ export const Canvas = ({ data }: CanvasProps): JSX.Element | null => {
useAllUserProps(data.props);
useSetPresetStyles(data.tree.presetStyles);
useSetStyles(data.tree.styles);
usePopulateRootInstance(data.tree);
useSetRootInstance(data.tree.root);
setParams(data.params ?? null);
useCanvasStore(publish);
@@ -59,7 +59,7 @@ export const WrapperComponentDev = ({
useTextEditingInstanceId();
const [selectedInstance] = useSelectedInstance();
const [allUserProps] = useAllUserProps();
const allUserProps = useAllUserProps();
const instanceProps = allUserProps[instance.id];
const userProps = useMemo(() => {
const result: UserProps = {};
+4 -13
View File
@@ -1,8 +1,7 @@
import { useEffect, useState } from "react";
import { useEffect } from "react";
import {
type Instance,
type UserProp,
type Tree,
getComponentMeta,
allUserPropsContainer,
} from "@webstudio-is/react-sdk";
@@ -38,12 +37,6 @@ declare module "~/shared/pubsub" {
}
}
export const usePopulateRootInstance = (tree: Tree) => {
useState(() => {
rootInstanceContainer.value = tree.root;
});
};
export const findInsertLocation = (
rootInstance: Instance,
selectedInstanceId: Instance["id"] | undefined
@@ -119,13 +112,11 @@ export const useReparentInstance = () => {
);
});
const rootInstance = rootInstanceContainer.get();
// Make the drag item the selected instance
if (
selectedInstance?.id !== instanceId &&
rootInstanceContainer.value !== undefined
) {
if (selectedInstance?.id !== instanceId && rootInstance !== undefined) {
setSelectedInstance(
utils.tree.findInstanceById(rootInstanceContainer.value, instanceId)
utils.tree.findInstanceById(rootInstance, instanceId)
);
}
});
@@ -1,7 +1,11 @@
import { createValueContainer, useValue } from "react-nano-state";
import { atom, type WritableAtom } from "nanostores";
import { useStore } from "@nanostores/react";
import { type Instance } from "@webstudio-is/react-sdk";
export const selectedInstanceContainer = createValueContainer<
Instance | undefined
>();
const useValue = <T>(atom: WritableAtom<T>) => {
const value = useStore(atom);
return [value, atom.set] as const;
};
export const selectedInstanceContainer = atom<Instance | undefined>();
export const useSelectedInstance = () => useValue(selectedInstanceContainer);
@@ -1,5 +1,6 @@
import { useEffect, useState } from "react";
import { createValueContainer, useValue } from "react-nano-state";
import { atom } from "nanostores";
import { useStore } from "@nanostores/react";
import { sentryMessage } from "~/shared/sentry";
import * as config from "./config";
@@ -72,24 +73,24 @@ export const setSetting = (name: Name, value: Value) => {
}
};
const settingsContainer = createValueContainer<Settings>(defaultSettings);
const settingsContainer = atom<Settings>(defaultSettings);
export const useClientSettings = (): [Settings, typeof setSetting, boolean] => {
const [settings, setSettings] = useValue(settingsContainer);
const settings = useStore(settingsContainer);
// We need to know if the settings were loaded from local storage.
// E.g. to decide if we should wait till the actual setting is loaded or use the default.
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
setSettings(read());
settingsContainer.set(read());
setIsLoaded(true);
}, [setSettings]);
}, []);
const setSettingValue = (name: Name, value: Value) => {
if (settings[name] === value) {
return;
}
setSettings({ ...settings, [name]: value });
settingsContainer.set({ ...settings, [name]: value });
setSetting(name, value);
};
return [settings, setSettingValue, isLoaded];
@@ -1,4 +1,5 @@
import { createValueContainer, useValue } from "react-nano-state";
import { atom } from "nanostores";
import { useStore } from "@nanostores/react";
import { Box, Flex, Text, Collapsible } from "@webstudio-is/design-system";
import { ChevronLeftIcon, ChevronRightIcon } from "@webstudio-is/icons";
@@ -10,17 +11,17 @@ type CollapsibleSectionProps = {
rightSlot?: JSX.Element;
};
const stateContainer = createValueContainer<{ [label: string]: boolean }>({});
const stateContainer = atom<{ [label: string]: boolean }>({});
// Preserves the open/close state even when component gets unmounted
const useOpenState = (
label: string,
initialValue: boolean
): [boolean, (value: boolean) => void] => {
const [state, setState] = useValue(stateContainer);
const state = useStore(stateContainer);
const isOpen = label in state ? state[label] : initialValue;
const setIsOpen = (isOpen: boolean) => {
setState({ ...state, [label]: isOpen });
stateContainer.set({ ...state, [label]: isOpen });
};
return [isOpen, setIsOpen];
};
@@ -1,4 +1,5 @@
import { createValueContainer, useValue } from "react-nano-state";
import { atom, type WritableAtom } from "nanostores";
import { useStore } from "@nanostores/react";
import { type Breakpoint } from "@webstudio-is/css-data";
import {
type SelectedInstanceData,
@@ -8,55 +9,54 @@ import { type SyncStatus } from "~/shared/sync";
import { type Pages, type Project } from "@webstudio-is/project";
import type { AssetContainer, DeletingAssetContainer } from "../assets";
const selectedInstanceDataContainer = createValueContainer<
SelectedInstanceData | undefined
>();
const useValue = <T>(atom: WritableAtom<T>) => {
const value = useStore(atom);
return [value, atom.set] as const;
};
const selectedInstanceDataContainer = atom<SelectedInstanceData | undefined>();
export const useSelectedInstanceData = () =>
useValue(selectedInstanceDataContainer);
const hoveredInstanceDataContainer = createValueContainer<
HoveredInstanceData | undefined
>();
const hoveredInstanceDataContainer = atom<HoveredInstanceData | undefined>();
export const useHoveredInstanceData = () =>
useValue(hoveredInstanceDataContainer);
const isShareDialogOpenContainer = createValueContainer<boolean>(false);
const isShareDialogOpenContainer = atom<boolean>(false);
export const useIsShareDialogOpen = () => useValue(isShareDialogOpenContainer);
const isPublishDialogOpenContainer = createValueContainer<boolean>(false);
const isPublishDialogOpenContainer = atom<boolean>(false);
export const useIsPublishDialogOpen = () =>
useValue(isPublishDialogOpenContainer);
const selectedBreakpointContainer = createValueContainer<
Breakpoint | undefined
>();
const selectedBreakpointContainer = atom<Breakpoint | undefined>();
export const useSelectedBreakpoint = () =>
useValue(selectedBreakpointContainer);
const zoomContainer = createValueContainer<number>(100);
const zoomContainer = atom<number>(100);
export const useZoom = () => useValue(zoomContainer);
const canvasWidthContainer = createValueContainer<number>(0);
const canvasWidthContainer = atom<number>(0);
export const useCanvasWidth = () => useValue(canvasWidthContainer);
const canvasRectContainer = createValueContainer<DOMRect | undefined>();
const canvasRectContainer = atom<DOMRect | undefined>();
export const useCanvasRect = () => useValue(canvasRectContainer);
const syncStatusContainer = createValueContainer<SyncStatus>("idle");
const syncStatusContainer = atom<SyncStatus>("idle");
export const useSyncStatus = () => useValue(syncStatusContainer);
const assetsContainer = createValueContainer<
Array<AssetContainer | DeletingAssetContainer>
>([]);
const assetsContainer = atom<Array<AssetContainer | DeletingAssetContainer>>(
[]
);
export const useAssetsContainer = () => useValue(assetsContainer);
const pagesContainer = createValueContainer<Pages | undefined>();
const pagesContainer = atom<Pages | undefined>();
export const usePages = () => useValue(pagesContainer);
const currentPageIdContainer = createValueContainer<string | undefined>();
const currentPageIdContainer = atom<string | undefined>();
export const useCurrentPageId = () => useValue(currentPageIdContainer);
const projectContainer = createValueContainer<Project | undefined>();
const projectContainer = atom<Project | undefined>();
export const useProject = () => useValue(projectContainer);
export type TextToolbarState = {
@@ -68,5 +68,5 @@ export type TextToolbarState = {
isLink: boolean;
isSpan: boolean;
};
const textToolbarState = createValueContainer<undefined | TextToolbarState>();
const textToolbarState = atom<undefined | TextToolbarState>();
export const useTextToolbarState = () => useValue(textToolbarState);
@@ -1,4 +1,5 @@
import { createValueContainer, useValue } from "react-nano-state";
import { atom, type WritableAtom } from "nanostores";
import { useStore } from "@nanostores/react";
import type { Instance, PresetStyles, Styles } from "@webstudio-is/react-sdk";
import type {
DropTargetChangePayload,
@@ -8,34 +9,42 @@ import type { Breakpoint } from "@webstudio-is/css-data";
import type { DesignToken } from "@webstudio-is/design-tokens";
import { useSyncInitializeOnce } from "../hook-utils";
export const rootInstanceContainer = createValueContainer<
Instance | undefined
>();
export const useRootInstance = () => useValue(rootInstanceContainer);
const useValue = <T>(atom: WritableAtom<T>) => {
const value = useStore(atom);
return [value, atom.set] as const;
};
export const presetStylesContainer = createValueContainer<PresetStyles>([]);
export const rootInstanceContainer = atom<Instance | undefined>();
export const useRootInstance = () => useValue(rootInstanceContainer);
export const useSetRootInstance = (root: Instance) => {
useSyncInitializeOnce(() => {
rootInstanceContainer.set(root);
});
};
export const presetStylesContainer = atom<PresetStyles>([]);
export const usePresetStyles = () => useValue(presetStylesContainer);
export const useSetPresetStyles = (presetStyles: PresetStyles) => {
useSyncInitializeOnce(() => {
presetStylesContainer.value = presetStyles;
presetStylesContainer.set(presetStyles);
});
};
export const stylesContainer = createValueContainer<Styles>([]);
export const stylesContainer = atom<Styles>([]);
export const useStyles = () => useValue(stylesContainer);
export const useSetStyles = (styles: Styles) => {
useSyncInitializeOnce(() => {
stylesContainer.value = styles;
stylesContainer.set(styles);
});
};
export const breakpointsContainer = createValueContainer<Array<Breakpoint>>([]);
export const breakpointsContainer = atom<Array<Breakpoint>>([]);
export const useBreakpoints = () => useValue(breakpointsContainer);
const isPreviewModeContainer = createValueContainer<boolean>(false);
const isPreviewModeContainer = atom<boolean>(false);
export const useIsPreviewMode = () => useValue(isPreviewModeContainer);
const selectedInstanceOutlineContainer = createValueContainer<{
const selectedInstanceOutlineContainer = atom<{
visible: boolean;
rect?: DOMRect;
}>({
@@ -45,19 +54,15 @@ const selectedInstanceOutlineContainer = createValueContainer<{
export const useSelectedInstanceOutline = () =>
useValue(selectedInstanceOutlineContainer);
const hoveredInstanceRectContainer = createValueContainer<
DOMRect | undefined
>();
const hoveredInstanceRectContainer = atom<DOMRect | undefined>();
export const useHoveredInstanceRect = () =>
useValue(hoveredInstanceRectContainer);
const isScrollingContainer = createValueContainer<boolean>(false);
const isScrollingContainer = atom<boolean>(false);
export const useIsScrolling = () => useValue(isScrollingContainer);
// We are editing the text of that instance in text editor.
const textEditingInstanceIdContainer = createValueContainer<
Instance["id"] | undefined
>();
const textEditingInstanceIdContainer = atom<Instance["id"] | undefined>();
export const useTextEditingInstanceId = () =>
useValue(textEditingInstanceIdContainer);
@@ -67,12 +72,10 @@ export type DragAndDropState = {
dropTarget?: DropTargetChangePayload;
dragItem?: DragStartPayload["dragItem"];
};
const dragAndDropStateContainer = createValueContainer<DragAndDropState>({
const dragAndDropStateContainer = atom<DragAndDropState>({
isDragging: false,
});
export const useDragAndDropState = () => useValue(dragAndDropStateContainer);
export const designTokensContainer = createValueContainer<Array<DesignToken>>(
[]
);
export const designTokensContainer = atom<Array<DesignToken>>([]);
export const useDesignTokens = () => useValue(designTokensContainer);
+2 -2
View File
@@ -76,7 +76,7 @@ export const useCanvasStore = (publish: Publish) => {
for (const [namespace, container] of store.containers) {
data.push({
namespace,
value: container.value,
value: container.get(),
});
}
publish({
@@ -96,7 +96,7 @@ export const useDesignerStore = (publish: Publish) => {
for (const { namespace, value } of data) {
const container = store.containers.get(namespace);
if (container) {
container.dispatch(value);
container.set(value);
}
}
});
+3 -2
View File
@@ -23,6 +23,7 @@
"@lexical/react": "^0.6.0",
"@lexical/selection": "^0.6.0",
"@lexical/utils": "^0.6.0",
"@nanostores/react": "^0.4.1",
"@radix-ui/react-select": "^1.0.0",
"@radix-ui/react-tooltip": "^1.0.0",
"@remix-run/node": "1.9.0",
@@ -55,7 +56,7 @@
"fast-deep-equal": "3.1.3",
"hyphenate-style-name": "^1.0.4",
"immer": "^9.0.12",
"immerhin": "^0.3.1",
"immerhin": "^0.4.0",
"lexical": "^0.6.0",
"lodash": "4.17.21",
"lodash.capitalize": "^4.2.1",
@@ -67,13 +68,13 @@
"match-sorter": "^6.3.1",
"mitt": "^3.0.0",
"nanoid": "^3.2.0",
"nanostores": "^0.7.1",
"pretty-bytes": "^6.0.0",
"react": "^17.0.2",
"react-color": "^2.19.3",
"react-dom": "^17.0.2",
"react-error-boundary": "^3.1.4",
"react-hotkeys-hook": "^3.4.7",
"react-nano-state": "^0.4.0",
"react-router-dom": "^6.5.0",
"react-use": "^17.3.2",
"remix-auth": "^3.2.2",
+7 -1
View File
@@ -12,7 +12,13 @@ module.exports = {
// This makes sure remix bundles monorepo packages which are always
// sym-linked and can't be hoisted. You could also manually name packages
// e.g. ["@webstudio-is/ui", ...]
serverDependenciesToBundle: [/@webstudio-is\/.*/, "pretty-bytes", "djb2a"],
serverDependenciesToBundle: [
/@webstudio-is\/.*/,
"pretty-bytes",
"djb2a",
"nanostores",
"@nanostores/react",
],
// appDirectory: "app",
// assetsBuildDirectory: "public/build",
serverBuildPath: "api/index.js",
+1 -1
View File
@@ -89,7 +89,7 @@ const InstanceDbOut = z.lazy(() =>
id: z.string(),
component: z.string(),
children: z.array(z.union([InstanceDbOut, Text])),
cssRules: z.array(CssRuleDbOut),
cssRules: z.optional(z.array(CssRuleDbOut)),
})
) as z.ZodType<Instance>;
+2 -2
View File
@@ -53,6 +53,7 @@
"zod": "^3.19.1"
},
"dependencies": {
"@nanostores/react": "^0.4.1",
"@webstudio-is/asset-uploader": "workspace:^",
"@webstudio-is/css-data": "workspace:^",
"@webstudio-is/design-tokens": "workspace:^",
@@ -60,9 +61,8 @@
"@webstudio-is/image": "workspace:^",
"@webstudio-is/prisma-client": "workspace:^",
"detect-font": "^0.1.5",
"immer": "^9.0.12",
"mitt": "^3.0.0",
"react-nano-state": "^0.4.0",
"nanostores": "^0.7.1",
"warn-once": "^0.1.1"
},
"exports": {
@@ -1,10 +1,11 @@
import { useRef } from "react";
import { createValueContainer, useValue } from "react-nano-state";
import { atom } from "nanostores";
import { useStore } from "@nanostores/react";
import type { InstanceProps, Instance } from "../db";
export type AllUserProps = { [id: Instance["id"]]: InstanceProps };
export const allUserPropsContainer = createValueContainer<AllUserProps>({});
export const allUserPropsContainer = atom<AllUserProps>({});
export const useAllUserProps = (initialUserProps?: Array<InstanceProps>) => {
// @todo ssr workaround for https://github.com/webstudio-is/webstudio-designer/issues/213
@@ -15,8 +16,8 @@ export const useAllUserProps = (initialUserProps?: Array<InstanceProps>) => {
propsMap[props.instanceId] = props;
}
//We don't need to trigger rerender when setting the initial value
allUserPropsContainer.value = propsMap;
allUserPropsContainer.set(propsMap);
ref.current = true;
}
return useValue(allUserPropsContainer);
return useStore(allUserPropsContainer);
};
@@ -11,7 +11,7 @@ export const useUserPropsAsset = (
instanceId: Instance["id"],
propName: UserProp["prop"]
): Asset | undefined => {
const [allUserProps] = useAllUserProps();
const allUserProps = useAllUserProps();
const propsData = allUserProps[instanceId];
const asset = useMemo(() => {
@@ -10,7 +10,7 @@ type UserProps = { [prop: UserProp["prop"]]: string | number | boolean };
* up to date with props panel.
*/
export const useUserProps = (instanceId: Instance["id"]) => {
const [allUserProps] = useAllUserProps();
const allUserProps = useAllUserProps();
const propsData = allUserProps[instanceId];
const props = useMemo(() => {
+37 -19
View File
@@ -48,6 +48,7 @@ importers:
'@lexical/react': ^0.6.0
'@lexical/selection': ^0.6.0
'@lexical/utils': ^0.6.0
'@nanostores/react': ^0.4.1
'@radix-ui/react-select': ^1.0.0
'@radix-ui/react-tooltip': ^1.0.0
'@remix-run/dev': 1.9.0
@@ -109,7 +110,7 @@ importers:
fast-deep-equal: 3.1.3
hyphenate-style-name: ^1.0.4
immer: ^9.0.12
immerhin: ^0.3.1
immerhin: ^0.4.0
jest: ^29.3.1
lexical: ^0.6.0
lodash: 4.17.21
@@ -122,6 +123,7 @@ importers:
match-sorter: ^6.3.1
mitt: ^3.0.0
nanoid: ^3.2.0
nanostores: ^0.7.1
prettier: ^2.6.2
pretty-bytes: ^6.0.0
react: ^17.0.2
@@ -129,7 +131,6 @@ importers:
react-dom: 17.0.2
react-error-boundary: ^3.1.4
react-hotkeys-hook: ^3.4.7
react-nano-state: ^0.4.0
react-router-dom: ^6.5.0
react-test-renderer: ^17.0.2
react-use: ^17.3.2
@@ -152,6 +153,7 @@ importers:
'@lexical/react': 0.6.0_p7mvqmjvwf4nexue7sv3sfptum
'@lexical/selection': 0.6.0_lexical@0.6.0
'@lexical/utils': 0.6.0_lexical@0.6.0
'@nanostores/react': 0.4.1_hn2jst675metodsznud55jugtu
'@radix-ui/react-select': 1.0.0_nn45z5sr7igu7sfun6tiae5hx4
'@radix-ui/react-tooltip': 1.0.0_nn45z5sr7igu7sfun6tiae5hx4
'@remix-run/node': 1.9.0_sfoxds7t5ydpegc3knd667wn6m
@@ -184,7 +186,7 @@ importers:
fast-deep-equal: 3.1.3
hyphenate-style-name: 1.0.4
immer: 9.0.15
immerhin: 0.3.1
immerhin: 0.4.0
lexical: 0.6.0
lodash: 4.17.21
lodash.capitalize: 4.2.1
@@ -196,13 +198,13 @@ importers:
match-sorter: 6.3.1
mitt: 3.0.0
nanoid: 3.3.4
nanostores: 0.7.1
pretty-bytes: 6.0.0
react: 17.0.2
react-color: 2.19.3_react@17.0.2
react-dom: 17.0.2_react@17.0.2
react-error-boundary: 3.1.4_react@17.0.2
react-hotkeys-hook: 3.4.7_sfoxds7t5ydpegc3knd667wn6m
react-nano-state: 0.4.0_react@17.0.2
react-router-dom: 6.5.0_sfoxds7t5ydpegc3knd667wn6m
react-use: 17.4.0_sfoxds7t5ydpegc3knd667wn6m
remix-auth: 3.2.2_@remix-run+react@1.9.0
@@ -768,6 +770,7 @@ importers:
'@babel/core': ^7.20.2
'@esbuild-kit/esm-loader': ^2.4.2
'@jest/globals': ^29.3.1
'@nanostores/react': ^0.4.1
'@remix-run/node': 1.9.0
'@remix-run/react': 1.9.0
'@remix-run/server-runtime': 1.9.0
@@ -791,18 +794,18 @@ importers:
detect-font: ^0.1.5
esbuild: 0.15.13
esbuild-node-externals: ^1.4.1
immer: ^9.0.12
jest: ^29.3.1
mitt: ^3.0.0
nanostores: ^0.7.1
react: ^17.0.2
react-dom: 17.0.2
react-nano-state: ^0.4.0
remix-utils: ^4.1.0
tsx: ^3.9.0
typescript: 4.7.4
warn-once: ^0.1.1
zod: ^3.19.1
dependencies:
'@nanostores/react': 0.4.1_hn2jst675metodsznud55jugtu
'@webstudio-is/asset-uploader': link:../asset-uploader
'@webstudio-is/css-data': link:../css-data
'@webstudio-is/design-tokens': link:../design-tokens
@@ -810,9 +813,8 @@ importers:
'@webstudio-is/image': link:../image
'@webstudio-is/prisma-client': link:../prisma-client
detect-font: 0.1.5
immer: 9.0.15
mitt: 3.0.0
react-nano-state: 0.4.0_react@17.0.2
nanostores: 0.7.1
warn-once: 0.1.1
devDependencies:
'@babel/core': 7.20.2
@@ -4882,6 +4884,18 @@ packages:
glob-to-regexp: 0.3.0
dev: true
/@nanostores/react/0.4.1_hn2jst675metodsznud55jugtu:
resolution: {integrity: sha512-lsv0CYrMxczbXtoV/mxFVEoL/uVjEjseoP89srO/5yNAOkJka+dSFS7LYyWEbuvCPO7EgbtkvRpO5V+OztKQOw==}
engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
peerDependencies:
nanostores: ^0.7.0
react: '>=18.0.0'
dependencies:
nanostores: 0.7.1
react: 17.0.2
use-sync-external-store: 1.2.0_react@17.0.2
dev: false
/@nodelib/fs.scandir/2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -14942,8 +14956,8 @@ packages:
resolution: {integrity: sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==}
dev: false
/immerhin/0.3.1:
resolution: {integrity: sha512-ZWO7lR+WPHJRUxNpNw76K6+YQKnAEnWFZcCFKqWfYHg0lyVxs+D7k72NSe92GGwyr9gH7Yj6HbMaKXfgArYpyw==}
/immerhin/0.4.0:
resolution: {integrity: sha512-o/nh3n80wd/Iku33thGAovobcnCfYHuoxDFY1dDijIX4xppd4Hb3KdfwJDdq99kF8iqCHJjUhEx/iYTiqz1pqw==}
dependencies:
bson-objectid: 2.0.4
immer: 9.0.15
@@ -17487,6 +17501,11 @@ packages:
transitivePeerDependencies:
- supports-color
/nanostores/0.7.1:
resolution: {integrity: sha512-7HenoVpZOjRudHCmAVWKloBTk3+Ozw49KuRWq/pNlEIIVS3x9dID+I5z3Rhjxl1muhHwv4dFhpT+0FebT9jvaA==}
engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
dev: false
/napi-build-utils/1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
dev: false
@@ -18899,15 +18918,6 @@ packages:
resolution: {integrity: sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==}
dev: false
/react-nano-state/0.4.0_react@17.0.2:
resolution: {integrity: sha512-SqSNd9Y5scLhaMpD0tqMcCl3nijFlPFJzOmOFc4ITuhjjbsyKHcdjv02tamI88fCt8bAcjWA/It0k/+QP61w9w==}
engines: {node: '>=13.2.0'}
peerDependencies:
react: '>=16.8'
dependencies:
react: 17.0.2
dev: false
/react-refresh/0.11.0:
resolution: {integrity: sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==}
engines: {node: '>=0.10.0'}
@@ -21563,6 +21573,14 @@ packages:
tslib: 2.4.0
dev: false
/use-sync-external-store/1.2.0_react@17.0.2:
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
react: 17.0.2
dev: false
/use/3.1.1:
resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==}
engines: {node: '>=0.10.0'}