tsparticles / react

React tsParticles official component
https://particles.js.org
MIT License
357 stars 24 forks source link

Please fix TypeScript support - object #80

Closed sudsarkar13 closed 5 months ago

sudsarkar13 commented 5 months ago
TypeScript support - object
import { useEffect, useMemo, useState } from "react";
import Particles, { initParticlesEngine } from "@tsparticles/react";
import {
  type Container,
  type ISourceOptions,
  MoveDirection,
  OutMode,
} from "@tsparticles/engine";
// import { loadAll } from "@/tsparticles/all"; // if you are going to use `loadAll`, install the "@tsparticles/all" package too.
// import { loadFull } from "tsparticles"; // if you are going to use `loadFull`, install the "tsparticles" package too.
import { loadSlim } from "@tsparticles/slim"; // if you are going to use `loadSlim`, install the "@tsparticles/slim" package too.
// import { loadBasic } from "@tsparticles/basic"; // if you are going to use `loadBasic`, install the "@tsparticles/basic" package too.

const App = () => {
  const [init, setInit] = useState(false);

  // this should be run only once per application lifetime
  useEffect(() => {
    initParticlesEngine(async (engine) => {
      // you can initiate the tsParticles instance (engine) here, adding custom shapes or presets
      // this loads the tsparticles package bundle, it's the easiest method for getting everything ready
      // starting from v2 you can add only the features you need reducing the bundle size
      //await loadAll(engine);
      //await loadFull(engine);
      await loadSlim(engine);
      //await loadBasic(engine);
    }).then(() => {
      setInit(true);
    });
  }, []);

  const particlesLoaded = async (container?: Container): Promise<void> => {
    console.log(container);
  };

  const options: ISourceOptions = useMemo(
    () => ({
      background: {
        color: {
          value: "#0d47a1",
        },
      },
      fpsLimit: 120,
      interactivity: {
        events: {
          onClick: {
            enable: true,
            mode: "push",
          },
          onHover: {
            enable: true,
            mode: "repulse",
          },
        },
        modes: {
          push: {
            quantity: 4,
          },
          repulse: {
            distance: 200,
            duration: 0.4,
          },
        },
      },
      particles: {
        color: {
          value: "#ffffff",
        },
        links: {
          color: "#ffffff",
          distance: 150,
          enable: true,
          opacity: 0.5,
          width: 1,
        },
        move: {
          direction: MoveDirection.none,
          enable: true,
          outModes: {
            default: OutMode.out,
          },
          random: false,
          speed: 6,
          straight: false,
        },
        number: {
          density: {
            enable: true,
          },
          value: 80,
        },
        opacity: {
          value: 0.5,
        },
        shape: {
          type: "circle",
        },
        size: {
          value: { min: 1, max: 5 },
        },
      },
      detectRetina: true,
    }),
    [],
  );

  if (init) {
    return (
      <Particles
        id="tsparticles"
        particlesLoaded={particlesLoaded}
        options={options}
      />
    );
  }

  return <></>;
};

Errors:

Line-36 options : It looks like there is a type error in your TypeScript code. The issue is with the particles.move.direction property in the options object. The error message indicates that the type of particles.move.direction is incompatible with the expected type. You may need to check the type definition for direction and ensure that it matches the expected type for ISourceOptions.

Line-77 MoveDirection : The issue const enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query occurs when you try to directly use a const enum in a place where it's not allowed in TypeScript. In your case, the error is happening because you're trying to use the MoveDirection enum directly in the move object without referencing a specific property or index.

Line-80 OutMode : The error const enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query is likely occurring because you are trying to use the OutMode const enum in a context where it is not allowed.

matteobruni commented 5 months ago

If enums are returning errors, you can use the string values. Exporting non-const enums wastes a lot of code, increasing the bundle size without a valid reason.

Refer to https://github.com/tsparticles/tsparticles/issues/3073 for an old similar discussion.

sudsarkar13 commented 5 months ago

Thanks it's working currently now

sudsarkar13 commented 5 months ago

Here's the improved code

Hope you would like to test it

TypeScript support - object : Formatted using Prettier
import { useEffect, useMemo, useState } from "react";
import Particles, { initParticlesEngine } from "@tsparticles/react";
// import { loadAll } from "@/tsparticles/all"; // if you are going to use `loadAll`, install the "@tsparticles/all" package too.
// import { loadFull } from "tsparticles"; // if you are going to use `loadFull`, install the "tsparticles" package too.
import { loadSlim } from "@tsparticles/slim"; // if you are going to use `loadSlim`, install the "@tsparticles/slim" package too.
// import { loadBasic } from "@tsparticles/basic"; // if you are going to use `loadBasic`, install the "@tsparticles/basic" package too.
import { Container } from "@tsparticles/engine";

const Particle = () => {
    const [init, setInit] = useState(false);

    // this should be run only once per application lifetime
    useEffect(() => {
        initParticlesEngine(async (engine) => {
            // you can initiate the tsParticles instance (engine) here, adding custom shapes or presets
            // this loads the tsparticles package bundle, it's the easiest method for getting everything ready
            // starting from v2 you can add only the features you need reducing the bundle size
            //await loadAll(engine);
            //await loadFull(engine);
            await loadSlim(engine);
            //await loadBasic(engine);
        }).then(() => {
            setInit(true);
        });
    }, []);

    const particlesLoaded = (container?: Container) => {
        return new Promise<void>((resolve) => {
            console.log(container);
            resolve();
        });
    };

    const options = useMemo(
        () => ({
            fpsLimit: 120,
            interactivity: {
                events: {
                    onClick: {
                        enable: true,
                        mode: "push",
                    },
                    onHover: {
                        enable: true,
                        mode: "repulse",
                    },
                },
                modes: {
                    push: {
                        quantity: 4,
                    },
                    repulse: {
                        distance: 200,
                        duration: 0.4,
                    },
                },
            },
            particles: {
                color: {
                    value: "#ffffff",
                },
                links: {
                    color: "#ffffff",
                    distance: 150,
                    enable: true,
                    opacity: 0.5,
                    width: 1,
                },
                move: {
                    direction: "none" as const,
                    enable: true,
                    outModes: {
                        default: "bounce" as const,
                    },
                    random: false,
                    speed: 6,
                    straight: false,
                },
                number: {
                    density: {
                        enable: true,
                    },
                    value: 80,
                },
                opacity: {
                    value: 0.5,
                },
                shape: {
                    type: "circle",
                },
                size: {
                    value: { min: 1, max: 5 },
                },
            },
            detectRetina: true,
        }),
        []
    );

    if (init) {
        return (
            <Particles
                id='tsparticles'
                particlesLoaded={particlesLoaded}
                options={options}
            />
        );
    }

    return <></>;
};

export default Particle;

Changelogs

Particle Component Changes

Problem

Type '{ fpsLimit: number; interactivity: { events: { onClick: { enable: boolean; mode: string; }; onHover: { enable: boolean; mode: string; }; }; modes: { push: { quantity: number; }; repulse: { distance: number; duration: number; }; }; }; particles: { ...; }; detectRetina: boolean; }' is not assignable to type 'RecursivePartial'. The types of 'particles.move.outModes' are incompatible between these types. Type '{ default: string; }' is not assignable to type '"none" | "bounce" | "split" | IOutModes | OutMode | "bounceHorizontal" | "bounceVertical" | "out" | "destroy" | OutModeAlt | undefined'. Type '{ default: string; }' is not assignable to type 'IOutModes'. Types of property 'default' are incompatible. Type 'string' is not assignable to type '"none" | "bounce" | "split" | OutMode | "bounceHorizontal" | "bounceVertical" | "out" | "destroy" | OutModeAlt'.ts(2322) IParticlesProps.d.ts(5, 5): The expected type comes from property 'options' which is declared here on type 'IntrinsicAttributes & IParticlesProps'

Solution

Adjust the type of outModes to match the required type in IParticlesProps. Specifically, ensure that the default property of outModes is assigned a value of type "bounce" as const instead of a plain string.

Updated Code

const options = useMemo(
  () => ({
    fpsLimit: 120,
    interactivity: {
      events: {
        onClick: {
          enable: true,
          mode: "push",
        },
        onHover: {
          enable: true,
          mode: "repulse",
        },
      },
      modes: {
        push: {
          quantity: 4,
        },
        repulse: {
          distance: 200,
          duration: 0.4,
        },
      },
    },
    particles: {
      color: {
        value: "#ffffff",
      },
      links: {
        color: "#ffffff",
        distance: 150,
        enable: true,
        opacity: 0.5,
        width: 1,
      },
      move: {
        direction: "none" as const,
        enable: true,
        outModes: {
          default: "bounce" as const,
        },
        random: false,
        speed: 6,
        straight: false,
      },
      number: {
        density: {
          enable: true,
        },
        value: 80,
      },
      opacity: {
        value: 0.5,
      },
      shape: {
        type: "circle",
      },
      size: {
        value: { min: 1, max: 5 },
      },
    },
    detectRetina: true,
  }),
  []
);
sudsarkar13 commented 5 months ago

If enums are returning errors, you can use the string values. Exporting non-const enums wastes a lot of code, increasing the bundle size without a valid reason.

Refer to tsparticles/tsparticles#3073 for an old similar discussion.

Well I have provide a better solution, Please kindly check it out. and reply as soon as possible.

matteobruni commented 5 months ago

No changes will be done on the codebase. The types are good and the default values too.

sudsarkar13 commented 5 months ago

Ok thanks, for your reply it means a lot. Happy Coding!!!