Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Onboarding: Replace react-confetti with @neoconfetti/react #30098

Merged
merged 9 commits into from
Dec 19, 2024
2 changes: 1 addition & 1 deletion code/addons/onboarding/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"@storybook/react": "workspace:*",
"framer-motion": "^11.0.3",
"react": "^18.2.0",
"react-confetti": "^6.1.0",
"react-confetti-boom": "^1.1.0",
"react-dom": "^18.2.0",
"react-joyride": "^2.8.2",
"react-use-measure": "^2.1.1",
Expand Down
12 changes: 1 addition & 11 deletions code/addons/onboarding/src/Onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,17 +268,7 @@ export default function Onboarding({ api }: { api: API }) {

return (
<ThemeProvider theme={theme}>
{showConfetti && (
<Confetti
numberOfPieces={800}
recycle={false}
tweenDuration={20000}
onConfettiComplete={(confetti) => {
confetti?.reset();
setShowConfetti(false);
}}
/>
)}
{showConfetti && <Confetti />}
{step === '1:Intro' ? (
<SplashScreen onDismiss={() => setStep('2:Controls')} />
) : (
Expand Down
51 changes: 11 additions & 40 deletions code/addons/onboarding/src/components/Confetti/Confetti.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,19 @@ const meta: Meta<typeof Confetti> = {
component: Confetti,
parameters: {
chromatic: { disableSnapshot: true },
layout: 'fullscreen',
},
decorators: [
(StoryFn) => (
<div style={{ height: '100vh', width: '100vw' }}>
<button>I am clickable</button>
<div
style={{
height: '100vh',
width: '100vw',
alignContent: 'center',
textAlign: 'center',
}}
>
<span>Falling confetti! 🎉</span>
<StoryFn />
</div>
),
Expand All @@ -23,41 +31,4 @@ export default meta;

type Story = StoryObj<typeof Confetti>;

export const Default: Story = {
args: {
recycle: true,
numberOfPieces: 200,
top: undefined,
left: undefined,
width: undefined,
height: undefined,
friction: 0.99,
wind: 0,
gravity: 0.1,
initialVelocityX: 4,
initialVelocityY: 10,
tweenDuration: 5000,
},
};

export const OneTimeConfetti: Story = {
args: {
...Default.args,
numberOfPieces: 800,
recycle: false,
tweenDuration: 20000,
onConfettiComplete: (confetti) => {
confetti?.reset();
},
},
};

export const Positioned: Story = {
args: {
...Default.args,
top: 100,
left: 300,
width: 300,
height: 250,
},
};
export const Default: Story = {};
145 changes: 30 additions & 115 deletions code/addons/onboarding/src/components/Confetti/Confetti.tsx
Original file line number Diff line number Diff line change
@@ -1,131 +1,46 @@
import React, { useEffect } from 'react';
import React, { type ComponentProps, useEffect } from 'react';
import { useState } from 'react';
import { createPortal } from 'react-dom';

import { styled } from 'storybook/internal/theming';

import ReactConfetti from 'react-confetti';
import ReactConfetti from 'react-confetti-boom';

interface ConfettiProps extends Omit<React.ComponentProps<typeof ReactConfetti>, 'drawShape'> {
top?: number;
left?: number;
width?: number;
height?: number;
numberOfPieces?: number;
recycle?: boolean;
colors?: string[];
}

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',
}));
const Wrapper = styled.div({
zIndex: 9999,
position: 'fixed',
top: 0,
left: 0,
bottom: 0,
right: 0,
});

export function Confetti({
top = 0,
left = 0,
width = window.innerWidth,
height = window.innerHeight,
timeToFade = 5000,
colors = ['#CA90FF', '#FC521F', '#66BF3C', '#FF4785', '#FFAE00', '#1EA7FD'],
...confettiProps
}: ConfettiProps): React.ReactPortal {
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;
});
}: ComponentProps<typeof ReactConfetti> & { timeToFade?: number }) {
const [particleCount, setParticleCount] = useState(42);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: initial particleCount of 42 seems arbitrary and much lower than original implementation which could affect visual impact

useEffect(() => {
document.body.appendChild(confettiContainer);
const timeout = setTimeout(() => {
setParticleCount(0);
}, timeToFade);

return () => {
document.body.removeChild(confettiContainer);
clearTimeout(timeout);
};
}, []);

return createPortal(
<Wrapper top={top} left={left} width={width} height={height}>
<ReactConfetti colors={colors} drawShape={draw} {...confettiProps} />
</Wrapper>,
confettiContainer
}, [timeToFade]);

return (
<Wrapper>
<ReactConfetti
mode="fall"
colors={colors}
shapeSize={14}
particleCount={particleCount}
fadeOutHeight={10}
{...confettiProps}
/>
</Wrapper>
);
}

enum ParticleShape {
Circle = 1,
Square = 2,
TShape = 3,
LShape = 4,
Triangle = 5,
QuarterCircle = 6,
}

function getRandomInt(min: number, max: number) {
return Math.floor(Math.random() * (max - min)) + min;
}

function draw(this: any, context: CanvasRenderingContext2D) {
this.shape = this.shape || getRandomInt(1, 6);

switch (this.shape) {
case ParticleShape.Square: {
const cornerRadius = 2;
const width = this.w / 2;
const height = this.h / 2;

context.moveTo(-width + cornerRadius, -height);
context.lineTo(width - cornerRadius, -height);
context.arcTo(width, -height, width, -height + cornerRadius, cornerRadius);
context.lineTo(width, height - cornerRadius);
context.arcTo(width, height, width - cornerRadius, height, cornerRadius);
context.lineTo(-width + cornerRadius, height);
context.arcTo(-width, height, -width, height - cornerRadius, cornerRadius);
context.lineTo(-width, -height + cornerRadius);
context.arcTo(-width, -height, -width + cornerRadius, -height, cornerRadius);

break;
}
case ParticleShape.TShape: {
context.rect(-4, -4, 8, 16);
context.rect(-12, -4, 24, 8);
break;
}
case ParticleShape.LShape: {
context.rect(-4, -4, 8, 16);
context.rect(-4, -4, 24, 8);
break;
}
case ParticleShape.Circle: {
context.arc(0, 0, this.radius, 0, 2 * Math.PI);
break;
}
case ParticleShape.Triangle: {
context.moveTo(16, 4);
context.lineTo(4, 24);
context.lineTo(24, 24);
break;
}
case ParticleShape.QuarterCircle: {
context.arc(4, -4, 4, -Math.PI / 2, 0);
context.lineTo(4, 0);
break;
}
}

context.closePath();
context.fill();
}
2 changes: 1 addition & 1 deletion code/core/assets/server/addon.tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
"jsx": "react",
"jsxImportSource": "react"
}
}
}
51 changes: 51 additions & 0 deletions code/e2e-tests/addon-onboarding.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { expect, test } from '@playwright/test';
import process from 'process';

import { SbPage } from './util';

const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';
const templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';

const supportsOnboarding =
templateName.includes('react') ||
templateName.includes('vue3') ||
templateName.includes('angular') ||
templateName.includes('next');

test.describe('addon-onboarding', () => {
test.skip(
!supportsOnboarding,
`Skipping ${templateName}, which does not have addon-onboarding set up.`
);
test('the onboarding flow', async ({ page }) => {
await page.goto(`${storybookUrl}/?path=/onboarding`);
const sbPage = new SbPage(page, expect);
await sbPage.waitUntilLoaded();

await expect(page.getByRole('heading', { name: 'Meet your new frontend' })).toBeVisible();
await page.locator('#storybook-addon-onboarding').getByRole('button').click();

await expect(page.getByText('Interactive story playground')).toBeVisible();
await page.getByLabel('Next').click();

await expect(page.getByText('Save your changes as a new')).toBeVisible();
await page.getByLabel('Next').click();

await expect(page.getByRole('heading', { name: 'Create new story' })).toBeVisible();
await page.getByPlaceholder('Story export name').click();

// this is needed because the e2e test will generate a new file in the system
// which we don't know of its location (it runs in different sandboxes)
// so we just create a random id to make it easier to run tests
const id = Math.random().toString(36).substring(7);
await page.getByPlaceholder('Story export name').fill('Test-' + id);
await page.getByRole('button', { name: 'Create' }).click();

await expect(page.getByText('You just added your first')).toBeVisible();
await page.getByLabel('Last').click();

await expect(
sbPage.previewIframe().getByRole('heading', { name: 'Configure your project' })
).toBeVisible();
});
});
32 changes: 7 additions & 25 deletions code/frameworks/angular/src/builders/build-storybook/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,27 +67,18 @@
"compodocArgs": {
"type": "array",
"description": "Compodoc options : https://compodoc.app/guides/options.html. Options `-p` with tsconfig path and `-d` with workspace root is always given.",
"default": [
"-e",
"json"
],
"default": ["-e", "json"],
"items": {
"type": "string"
}
},
"webpackStatsJson": {
"type": [
"boolean",
"string"
],
"type": ["boolean", "string"],
"description": "Write Webpack Stats JSON to disk",
"default": false
},
"statsJson": {
"type": [
"boolean",
"string"
],
"type": ["boolean", "string"],
"description": "Write stats JSON to disk",
"default": false
},
Expand Down Expand Up @@ -127,10 +118,7 @@
}
},
"sourceMap": {
"type": [
"boolean",
"object"
],
"type": ["boolean", "object"],
"description": "Configure sourcemaps. See: https://angular.io/guide/workspace-config#source-map-configuration",
"default": false
}
Expand Down Expand Up @@ -168,11 +156,7 @@
}
},
"additionalProperties": false,
"required": [
"glob",
"input",
"output"
]
"required": ["glob", "input", "output"]
},
{
"type": "string"
Expand Down Expand Up @@ -200,9 +184,7 @@
}
},
"additionalProperties": false,
"required": [
"input"
]
"required": ["input"]
},
{
"type": "string",
Expand All @@ -211,4 +193,4 @@
]
}
}
}
}
Loading
Loading