Skip to content

Commit

Permalink
Fix #64
Browse files Browse the repository at this point in the history
  • Loading branch information
sim51 committed Apr 5, 2024
1 parent d665dd7 commit 4aa5226
Show file tree
Hide file tree
Showing 36 changed files with 80 additions and 106 deletions.
26 changes: 8 additions & 18 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

## Version 4.0.0
## Version 4.0.1

### Fixes

- [#64](https://github.com/sim51/react-sigma/issues/64): fail to import in vite project because of lodash

## Version 4.0.0 (not be used !)

### Features

Expand All @@ -17,23 +23,7 @@ const loadGraph = useLoadGraph<{label:string, x:number, y:number}, {label:string

### Breaking changes

- React-sigma doesn't depends anymore to lodash. It was use to make a deep equal on the settings provided to the `SigmaContainer`. Now you have to handle that :

```tsx
// Sigma settings are outside the react lifecycle to avoid the change of its ref at every render
// which triggers a full render of sigma. An other way is to use the `useMemo` hook inside the component.
const sigmaSettings = {
allowInvalidContainer: true,
};

export const Example: FC = () => {
return (
<SigmaContainer settings={sigmaSettings}>
<SampleGraph />
</SigmaContainer>
);
};
```
- React-sigma doesn't depends anymore to lodash.

- The sigma setting `allowInvalidContainer` is no more set per default. You have to pass it to the container (check above).

Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
"@storybook/react": "^8.0.5",
"@storybook/react-vite": "^8.0.5",
"@svgr/rollup": "^8.1.0",
"@types/lodash": "4.17.0",
"@types/node": "^20.11.20",
"@types/react": "^18.2.74",
"@types/react-dom": "^18.2.23",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ export default {
typescript({ tsconfig: "./tsconfig.json", outputToFilesystem: true }),
terser(),
],
external: ["sigma", "graphology", "lodash", "react", "react-dom"],
external: ["sigma", "graphology", "react", "react-dom"],
};

15 changes: 10 additions & 5 deletions packages/core/src/components/SigmaContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import Graph from "graphology";
import { Sigma } from "sigma";
import { Settings } from "sigma/settings";

import { SigmaProvider } from "../hooks/context";
import { SigmaContextInterface, SigmaProvider } from "../hooks/context";
import { isEqual } from "../utils";
import { GraphType } from "../types";
import { Attributes } from "graphology-types";

Expand Down Expand Up @@ -72,6 +73,11 @@ const SigmaContainerComponent = <
const props = { className: `react-sigma ${className ? className : ""}`, id, style };
// Sigma instance
const [sigma, setSigma] = useState<Sigma<N, E, G> | null>(null);
// Sigma settings
const [sigmaSettings, setSigmaSettings] = useState<Partial<Settings<N, E, G>>>(settings || {});
useEffect(() => {
if (!isEqual(sigmaSettings, settings)) setSigmaSettings(settings || {});
}, [settings]);

/**
* When graph or settings changed
Expand All @@ -86,7 +92,7 @@ const SigmaContainerComponent = <
sigGraph = typeof graph === "function" ? new graph() : graph;
}

instance = new Sigma(sigGraph, containerRef.current, settings);
instance = new Sigma(sigGraph, containerRef.current, sigmaSettings);
if (sigma) instance.getCamera().setState(sigma.getCamera().getState());
}
setSigma(instance);
Expand All @@ -97,7 +103,7 @@ const SigmaContainerComponent = <
}
setSigma(null);
};
}, [containerRef, graph, settings]);
}, [containerRef, graph, sigmaSettings]);

/**
* Forward the sigma ref
Expand All @@ -110,7 +116,7 @@ const SigmaContainerComponent = <
const context = useMemo(
() => (sigma && rootRef.current ? { sigma, container: rootRef.current as HTMLElement } : null),
[sigma, rootRef.current],
);
) as SigmaContextInterface | null;

// When context is created we provide it to children
const contents = context !== null ? <SigmaProvider value={context}>{children}</SigmaProvider> : null;
Expand All @@ -129,7 +135,6 @@ const SigmaContainerComponent = <
function fixedForwardRef<T, P = unknown>(
render: (props: P, ref: React.Ref<T>) => ReactElement,
): (props: P & React.RefAttributes<T>) => ReactElement {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return forwardRef(render) as (props: P & React.RefAttributes<T>) => ReactElement;
}

Expand Down
20 changes: 11 additions & 9 deletions packages/core/src/hooks/useCamera.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useCallback, useRef } from "react";
import { isEqual } from "lodash";
import { useCallback, useEffect, useState } from "react";
import { AnimateOptions } from "sigma/utils";
import { CameraState } from "sigma/types";

import { isEqual } from "../utils";
import { useSigma } from "./useSigma";

type CameraOptions = Partial<AnimateOptions> & { factor?: number };
Expand All @@ -25,41 +25,43 @@ export function useCamera(options?: CameraOptions): {
} {
const sigma = useSigma();
// Default camera options
const defaultOptions = useRef<CameraOptions>();
if (!isEqual(defaultOptions.current, options)) defaultOptions.current = options;
const [defaultOptions, setDefaultOptions] = useState<CameraOptions>(options || {});
useEffect(() => {
if (!isEqual(defaultOptions, options || {})) setDefaultOptions(options || {});
}, [options]);

const zoomIn = useCallback(
(options?: CameraOptions) => {
sigma.getCamera().animatedZoom({ ...defaultOptions.current, ...options });
sigma.getCamera().animatedZoom({ ...defaultOptions, ...options });
},
[sigma, defaultOptions],
);

const zoomOut = useCallback(
(options?: CameraOptions) => {
sigma.getCamera().animatedUnzoom({ ...defaultOptions.current, ...options });
sigma.getCamera().animatedUnzoom({ ...defaultOptions, ...options });
},
[sigma, defaultOptions],
);

const reset = useCallback(
(options?: Partial<AnimateOptions>) => {
sigma.getCamera().animatedReset({ ...defaultOptions.current, ...options });
sigma.getCamera().animatedReset({ ...defaultOptions, ...options });
},
[sigma, defaultOptions],
);

const goto = useCallback(
(state: Partial<CameraState>, options?: Partial<AnimateOptions>) => {
sigma.getCamera().animate(state, { ...defaultOptions.current, ...options });
sigma.getCamera().animate(state, { ...defaultOptions, ...options });
},
[sigma, defaultOptions],
);

const gotoNode = useCallback(
(nodeKey: string, options?: Partial<AnimateOptions>) => {
const nodeDisplayData = sigma.getNodeDisplayData(nodeKey);
if (nodeDisplayData) sigma.getCamera().animate(nodeDisplayData, { ...defaultOptions.current, ...options });
if (nodeDisplayData) sigma.getCamera().animate(nodeDisplayData, { ...defaultOptions, ...options });
else console.log(`Node ${nodeKey} not found`);
},
[sigma, defaultOptions],
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ export * from "./components/controls/ZoomControl";
export * from "./components/controls/FullScreenControl";
export * from "./components/controls/SearchControl";
export * from "./types";
export * from "./utils";
26 changes: 23 additions & 3 deletions packages/core/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
export function getUniqueKey(): string {
return Math.random()
.toString(36)
.slice(2);
return Math.random().toString(36).slice(2);
}

export function isEqual(x: unknown, y: unknown): boolean {
// check the ref
if (x === y) return true;
// if both are object
if (typeof x == "object" && x != null && typeof y == "object" && y != null) {
// Check the number of properties
if (Object.keys(x).length != Object.keys(y).length) return false;

// for every props of x
for (const prop in x) {
// prop is missing in y, false
if (!Object.hasOwn(y, prop)) return false;
// prop in y is diff than the one in x, false
if (!isEqual((x as { [key: string]: unknown })[prop], (y as { [key: string]: unknown })[prop])) return false;
}

return true;
}

return false;
}
1 change: 0 additions & 1 deletion packages/layout-circlepack/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export default {
external: [
"sigma",
"graphology",
"lodash",
"react",
"react-dom",
"@react-sigma/layout-core",
Expand Down
1 change: 0 additions & 1 deletion packages/layout-circular/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export default {
external: [
"sigma",
"graphology",
"lodash",
"react",
"react-dom",
"@react-sigma/layout-core",
Expand Down
2 changes: 1 addition & 1 deletion packages/layout-core/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ export default {
typescript({ tsconfig: "./tsconfig.json", outputToFilesystem: true }),
terser(),
],
external: ["sigma", "graphology", "lodash", "react", "react-dom", "@react-sigma/core"],
external: ["sigma", "graphology", "react", "react-dom", "@react-sigma/core"],
};
4 changes: 2 additions & 2 deletions packages/layout-core/src/useLayoutFactory.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { isEqual } from "lodash";
import { useCallback, useRef } from "react";
import Graph from "graphology";

import { useSigma } from "@react-sigma/core";
import { useSigma, isEqual } from "@react-sigma/core";

/**
* Generic type for Graphology layout.
Expand Down Expand Up @@ -32,6 +31,7 @@ export type LayoutHook<T> = (settings?: T) => {
export function useLayoutFactory<T>(layout: GraphologyLayout<T>, defaultSettings: T): LayoutHook<T> {
const hook: LayoutHook<T> = (parameter: T = defaultSettings) => {
const sigma = useSigma();

// Default layout settings
const settings = useRef<T>(defaultSettings);
if (!isEqual(settings.current, parameter)) settings.current = parameter;
Expand Down
3 changes: 1 addition & 2 deletions packages/layout-core/src/useWorkerLayoutFactory.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { isEqual } from "lodash";
import { useCallback, useRef, useState, useEffect } from "react";
import Graph from "graphology";

import { useSigma } from "@react-sigma/core";
import { useSigma, isEqual } from "@react-sigma/core";

export type LayoutWorkerHook<T> = (settings: T) => {
stop: () => void;
Expand Down
1 change: 0 additions & 1 deletion packages/layout-force/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export default {
external: [
"sigma",
"graphology",
"lodash",
"react",
"react-dom",
"@react-sigma/layout-core",
Expand Down
1 change: 0 additions & 1 deletion packages/layout-forceatlas2/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export default {
external: [
"sigma",
"graphology",
"lodash",
"react",
"react-dom",
"@react-sigma/layout-core",
Expand Down
1 change: 0 additions & 1 deletion packages/layout-noverlap/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export default {
external: [
"sigma",
"graphology",
"lodash",
"react",
"react-dom",
"@react-sigma/layout-core",
Expand Down
1 change: 0 additions & 1 deletion packages/layout-random/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export default {
external: [
"sigma",
"graphology",
"lodash",
"react",
"react-dom",
"@react-sigma/layout-core",
Expand Down
3 changes: 2 additions & 1 deletion packages/layout-random/src/useLayoutRandom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ import { useLayoutFactory } from "@react-sigma/layout-core";
*```
* @category Hook
*/
export const useLayoutRandom = useLayoutFactory<RandomLayoutOptions>(random, {});
const defaultRandomLayoutOptions: RandomLayoutOptions = {};
export const useLayoutRandom = useLayoutFactory<RandomLayoutOptions>(random, defaultRandomLayoutOptions);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 1 addition & 6 deletions packages/storybook/stories/Complete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,9 @@ import "@react-sigma/core/lib/react-sigma.min.css";
import { SampleGraph } from "./common/SampleGraph";
import { LayoutsControl } from "./common/LayoutsControl";

// Sigma settings are outside the react lifecycle to avoid the change of its ref at every render
// which triggers a full render of sigma.
// An other way is to use the `useMemo` hook inside the component
const sigmaSettings = { allowInvalidContainer: true };

export const Complete: FC<{ style?: CSSProperties }> = ({ style }) => {
return (
<SigmaContainer settings={sigmaSettings} style={style}>
<SigmaContainer settings={{ allowInvalidContainer: true }} style={style}>
<SampleGraph />
<ControlsContainer position={"bottom-right"}>
<ZoomControl />
Expand Down
7 changes: 1 addition & 6 deletions packages/storybook/stories/CustomRender.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ import { SampleGraph } from "./common/SampleGraph";

import "@react-sigma/core/lib/react-sigma.min.css";

// Sigma settings are outside the react lifecycle to avoid the change of its ref at every render
// which triggers a full render of sigma.
// An other way is to use the `useMemo` hook inside the component
const sigmaSettings = { allowInvalidContainer: true };

export const CustomRender: FC<{ style?: CSSProperties }> = ({ style }) => {
const [faTime, setFaTime] = useState<number>(2000);

Expand All @@ -31,7 +26,7 @@ export const CustomRender: FC<{ style?: CSSProperties }> = ({ style }) => {
}, [window.location]);

return (
<SigmaContainer style={style} settings={sigmaSettings}>
<SigmaContainer style={style} settings={{ allowInvalidContainer: true }}>
<SampleGraph />
<ControlsContainer position={"bottom-right"}>
<ZoomControl labels={{ zoomIn: "PLUS", zoomOut: "MINUS", reset: "RESET" }}>
Expand Down
1 change: 1 addition & 0 deletions packages/storybook/stories/Demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "@react-sigma/core/lib/react-sigma.min.css";

import jsonGraph from "../public/react-sigma/demo/dataset.json";

// Sigma settings
const sigmaSettings = {
allowInvalidContainer: true,
nodeProgramClasses: { image: NodeImageProgram },
Expand Down
6 changes: 1 addition & 5 deletions packages/storybook/stories/DragNdrop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,9 @@ const GraphEvents: React.FC = () => {
return null;
};

const sigmaSettings = {
allowInvalidContainer: true,
};

export const DragNdrop: FC<{ style: CSSProperties }> = ({ style }) => {
return (
<SigmaContainer style={style} settings={sigmaSettings}>
<SigmaContainer style={style} settings={{ allowInvalidContainer: true }}>
<SampleGraph disableHoverEffect />
<GraphEvents />
<ControlsContainer position={"bottom-right"}>
Expand Down
4 changes: 1 addition & 3 deletions packages/storybook/stories/Events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import { SampleGraph } from "./common/SampleGraph";

import "@react-sigma/core/lib/react-sigma.min.css";

// Sigma settings are outside the react lifecycle to avoid the change of its ref at every render
// which triggers a full render of sigma.
// An other way is to use the `useMemo` hook inside the component
// Sigma settings
const sigmaSettings = { allowInvalidContainer: true };

// Create the Component that listen to all events
Expand Down
8 changes: 4 additions & 4 deletions packages/storybook/stories/External.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, useEffect, useMemo, useState, CSSProperties } from "react";
import { FC, useEffect, useState, CSSProperties } from "react";
import Sigma from "sigma";

import { SigmaContainer } from "@react-sigma/core";
Expand All @@ -11,8 +11,6 @@ type EdgeType = { label: string };
export const External: FC<{ style?: CSSProperties }> = ({ style }) => {
// Storing the sigma ref provided by react-sigma
const [sigma, setSigma] = useState<Sigma<NodeType, EdgeType> | null>(null);
// Memo sigma settings to avoid re-render sigma at each component render
const settings = useMemo(() => ({ allowInvalidContainer: true, renderLabels: false }), []);

// When the sigma ref is populated
// => load a graph
Expand All @@ -25,5 +23,7 @@ export const External: FC<{ style?: CSSProperties }> = ({ style }) => {
}
}, [sigma]);

return <SigmaContainer ref={setSigma} settings={settings} style={style} />;
return (
<SigmaContainer ref={setSigma} settings={{ allowInvalidContainer: true, renderLabels: false }} style={style} />
);
};
Loading

0 comments on commit 4aa5226

Please sign in to comment.