From 4770c35f92c80287980b015772614edce59f50d5 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Fri, 26 May 2023 13:08:48 +0200 Subject: [PATCH 1/2] Implement bare minimum confetti component --- package.json | 5 +- src/components/confetti/Confetti.stories.tsx | 33 ++++++++++++ src/components/confetti/Confetti.tsx | 56 ++++++++++++++++++++ yarn.lock | 12 +++++ 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 src/components/confetti/Confetti.stories.tsx create mode 100644 src/components/confetti/Confetti.tsx diff --git a/package.json b/package.json index 92cc3ce..8233543 100644 --- a/package.json +++ b/package.json @@ -107,5 +107,8 @@ "url": "https://github.com/storybookjs/addon-onboarding/issues" }, "readme": "ERROR: No README data found!", - "homepage": "https://github.com/storybookjs/addon-onboarding#readme" + "homepage": "https://github.com/storybookjs/addon-onboarding#readme", + "dependencies": { + "react-confetti": "^6.1.0" + } } diff --git a/src/components/confetti/Confetti.stories.tsx b/src/components/confetti/Confetti.stories.tsx new file mode 100644 index 0000000..ab8eec5 --- /dev/null +++ b/src/components/confetti/Confetti.stories.tsx @@ -0,0 +1,33 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { Confetti } from "./Confetti"; +import React from "react"; + +const meta: Meta = { + component: Confetti, + parameters: { + chromatic: { disableSnapshot: true }, + }, + decorators: [ + (StoryFn) => ( +
+ + +
+ ), + ], +}; + +export default meta; + +type Story = StoryObj; + +export const FullWidth: Story = {}; + +export const Positioned: Story = { + args: { + top: 100, + left: 300, + width: 300, + height: 250, + }, +}; diff --git a/src/components/confetti/Confetti.tsx b/src/components/confetti/Confetti.tsx new file mode 100644 index 0000000..a58ee48 --- /dev/null +++ b/src/components/confetti/Confetti.tsx @@ -0,0 +1,56 @@ +import ReactConfetti from "react-confetti"; +import React, { useEffect } from "react"; +import { styled } from "@storybook/theming"; +import { createPortal } from "react-dom"; + +interface ConfettiProps + extends Omit, "drawShape"> { + top: number; + left: number; + width: number; + height: number; +} + +const confettiContainer = document.createElement("div"); +confettiContainer.setAttribute("id", "confetti-container"); +confettiContainer.setAttribute( + "style", + "position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 9999;" +); + +const Wrapper = styled.div<{ + width: number; + height: number; + top: number; + left: number; +}>(({ width, height, left, top }) => ({ + width: `${width}px`, + height: `${height}px`, + left: `${left}px`, + top: `${top}px`, + position: "relative", + overflow: "hidden", +})); + +export function Confetti({ + top = 0, + left = 0, + width = window.innerWidth, + height = window.innerHeight, + ...confettiProps +}: ConfettiProps) { + useEffect(() => { + document.body.appendChild(confettiContainer); + + return () => { + document.body.removeChild(confettiContainer); + }; + }, []); + + return createPortal( + + + , + confettiContainer + ); +} diff --git a/yarn.lock b/yarn.lock index a8c179e..2ec2b04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7112,6 +7112,13 @@ react-colorful@^5.1.2: resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.6.1.tgz#7dc2aed2d7c72fac89694e834d179e32f3da563b" integrity sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw== +react-confetti@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/react-confetti/-/react-confetti-6.1.0.tgz#03dc4340d955acd10b174dbf301f374a06e29ce6" + integrity sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw== + dependencies: + tween-functions "^1.2.0" + react-docgen-typescript@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz#4611055e569edc071204aadb20e1c93e1ab1659c" @@ -8197,6 +8204,11 @@ tunnel@^0.0.6: resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== +tween-functions@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tween-functions/-/tween-functions-1.2.0.tgz#1ae3a50e7c60bb3def774eac707acbca73bbc3ff" + integrity sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA== + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" From 679dfa7b115667a8e87e3f4eb84608af1c959c71 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Tue, 30 May 2023 08:53:31 +0200 Subject: [PATCH 2/2] Move div creation for confetti container into component --- src/components/confetti/Confetti.tsx | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/components/confetti/Confetti.tsx b/src/components/confetti/Confetti.tsx index a58ee48..dc94f8e 100644 --- a/src/components/confetti/Confetti.tsx +++ b/src/components/confetti/Confetti.tsx @@ -1,7 +1,8 @@ import ReactConfetti from "react-confetti"; -import React, { useEffect } from "react"; +import React, { useEffect, useRef } from "react"; import { styled } from "@storybook/theming"; import { createPortal } from "react-dom"; +import { useState } from "react"; interface ConfettiProps extends Omit, "drawShape"> { @@ -11,13 +12,6 @@ interface ConfettiProps height: number; } -const confettiContainer = document.createElement("div"); -confettiContainer.setAttribute("id", "confetti-container"); -confettiContainer.setAttribute( - "style", - "position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 9999;" -); - const Wrapper = styled.div<{ width: number; height: number; @@ -39,6 +33,17 @@ export function Confetti({ height = window.innerHeight, ...confettiProps }: ConfettiProps) { + const [confettiContainer] = useState(() => { + const container = document.createElement("div"); + container.setAttribute("id", "confetti-container"); + container.setAttribute( + "style", + "position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 9999;" + ); + + return container; + }); + useEffect(() => { document.body.appendChild(confettiContainer);