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

Release: Prerelease 8.5.0-beta.3 #30099

Merged
merged 27 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
66fb449
Addon A11y: Refactor results handling and update configuration manage…
valentinpalkovic Dec 16, 2024
d20984e
Merge remote-tracking branch 'origin/next' into valentin/a11y-show-sk…
valentinpalkovic Dec 16, 2024
00c1dac
Addon A11y: Improve accessibility skipped tests label formatting
valentinpalkovic Dec 16, 2024
ec84de9
Fix tests and types
valentinpalkovic Dec 16, 2024
6365116
Fix story
valentinpalkovic Dec 16, 2024
c56e34a
Float context menu button on top of story title and replace transpare…
ghengeveld Dec 16, 2024
15e6aeb
Merge branch 'next' into floating-menu-button
JReinhold Dec 17, 2024
e77bd59
Fix tooltip positioning by absolutely positioning the WithTooltip wra…
ghengeveld Dec 17, 2024
66faa7e
Don't absolutely position status icons
ghengeveld Dec 17, 2024
e4bfa52
Fix default story tags
ghengeveld Dec 18, 2024
0104e15
Merge branch 'next-release' into next
storybook-bot Dec 18, 2024
6603753
use react-confetti source to prevent https://github.com/storybookjs/s…
ndelangen Dec 18, 2024
cc2a84a
Add E2E tests
ndelangen Dec 18, 2024
eed0b8b
Ensure status icon continues to claim space while hidden
ghengeveld Dec 18, 2024
513deda
Merge branch 'next' into valentin/a11y-show-skipped-tests
valentinpalkovic Dec 18, 2024
9a0f2fd
Addon Onboarding: Replace react-confetti with react-confetti-boom
yannbf Dec 18, 2024
3cded02
Add tests
valentinpalkovic Dec 18, 2024
792ac4c
Add a wrapper
yannbf Dec 18, 2024
2a69d26
Merge branch 'next' into norbert/fix-confetti-bundling
yannbf Dec 18, 2024
2b2b54d
rename e2e test
yannbf Dec 18, 2024
4b23a1a
Merge pull request #30077 from storybookjs/valentin/a11y-show-skipped…
valentinpalkovic Dec 18, 2024
441ad86
skip onboarding addon tests for built storybooks
yannbf Dec 18, 2024
717e256
use @neoconfetti/react instead
yannbf Dec 18, 2024
abe4c88
Merge pull request #30080 from storybookjs/floating-menu-button
ghengeveld Dec 18, 2024
f202d2a
Merge pull request #30100 from storybookjs/norbert/fix-confetti-bundl…
yannbf Dec 18, 2024
6f04c27
Merge pull request #30098 from storybookjs/norbert/fix-confetti-bundling
yannbf Dec 19, 2024
f1fee6e
Write changelog for 8.5.0-beta.3 [skip ci]
storybook-bot Dec 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.prerelease.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 8.5.0-beta.3

- Addon A11y: Fix skipped status handling in Testing Module - [#30077](https://github.com/storybookjs/storybook/pull/30077), thanks @valentinpalkovic!
- Core: Float context menu button on top of story titles in sidebar - [#30080](https://github.com/storybookjs/storybook/pull/30080), thanks @ghengeveld!
- Onboarding: Replace `react-confetti` with `@neoconfetti/react` - [#30098](https://github.com/storybookjs/storybook/pull/30098), thanks @ndelangen!

## 8.5.0-beta.2

- Addon Test: Clear coverage data when starting or watching - [#30072](https://github.com/storybookjs/storybook/pull/30072), thanks @ghengeveld!
Expand Down
3 changes: 2 additions & 1 deletion code/.storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -358,5 +358,6 @@ export const parameters = {
opacity: 0.4,
},
},
tags: ['test', 'vitest', '!a11ytest'],
};

export const tags = ['test', 'vitest', '!a11ytest'];
2 changes: 1 addition & 1 deletion code/addons/onboarding/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@
"prep": "jiti ../../../scripts/prepare/addon-bundle.ts"
},
"devDependencies": {
"@neoconfetti/react": "^1.0.0",
"@radix-ui/react-dialog": "^1.0.5",
"@storybook/icons": "^1.2.12",
"@storybook/react": "workspace:*",
"framer-motion": "^11.0.3",
"react": "^18.2.0",
"react-confetti": "^6.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 = {};
149 changes: 26 additions & 123 deletions code/addons/onboarding/src/components/Confetti/Confetti.tsx
Original file line number Diff line number Diff line change
@@ -1,131 +1,34 @@
import React, { useEffect } from 'react';
import { useState } from 'react';
import { createPortal } from 'react-dom';
import React, { type ComponentProps } from 'react';

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

import ReactConfetti from 'react-confetti';
import { Confetti as ReactConfetti } from '@neoconfetti/react';

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({
zIndex: 9999,
position: 'fixed',
top: 0,
left: '50%',
width: '50%',
height: '100%',
});

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,
export const Confetti = React.memo(function Confetti({
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;
});

useEffect(() => {
document.body.appendChild(confettiContainer);

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

return createPortal(
<Wrapper top={top} left={left} width={width} height={height}>
<ReactConfetti colors={colors} drawShape={draw} {...confettiProps} />
</Wrapper>,
confettiContainer
}: ComponentProps<typeof ReactConfetti> & { timeToFade?: number }) {
return (
<Wrapper>
<ReactConfetti
colors={colors}
particleCount={200}
duration={5000}
stageHeight={window.innerHeight}
stageWidth={window.innerWidth}
destroyAfterDone
{...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();
}
});
24 changes: 24 additions & 0 deletions code/addons/test/src/components/TestProviderRender.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ const baseState: TestProviderState<Details, Config> = {
coverage: false,
},
details: {
config: {
a11y: false,
coverage: false,
},
testResults: [
{
endTime: 0,
Expand Down Expand Up @@ -141,6 +145,10 @@ export const WithCoverageNegative: Story = {
...config,
...baseState,
details: {
config: {
a11y: false,
coverage: true,
},
testResults: [],
coverageSummary: {
percentage: 20,
Expand All @@ -162,6 +170,10 @@ export const WithCoverageWarning: Story = {
...baseState,
details: {
testResults: [],
config: {
a11y: false,
coverage: true,
},
coverageSummary: {
percentage: 50,
status: 'warning',
Expand All @@ -182,6 +194,10 @@ export const WithCoveragePositive: Story = {
...baseState,
details: {
testResults: [],
config: {
a11y: false,
coverage: true,
},
coverageSummary: {
percentage: 80,
status: 'positive',
Expand All @@ -206,6 +222,10 @@ export const Editing: Story = {
},
details: {
testResults: [],
config: {
a11y: false,
coverage: false,
},
},
},
},
Expand All @@ -229,6 +249,10 @@ export const EditingAndWatching: Story = {
},
details: {
testResults: [],
config: {
a11y: true,
coverage: true, // should be automatically disabled in the UI
},
},
},
},
Expand Down
29 changes: 22 additions & 7 deletions code/addons/test/src/components/TestProviderRender.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,14 @@ export const TestProviderRender: FC<
return 'unknown';
}

if (!a11yResults) {
const definedA11yResults = a11yResults?.filter(Boolean) ?? [];

if (!definedA11yResults || definedA11yResults.length === 0) {
return 'unknown';
}

const failed = a11yResults.some((result) => result?.status === 'failed');
const warning = a11yResults.some((result) => result?.status === 'warning');
const failed = definedA11yResults.some((result) => result?.status === 'failed');
const warning = definedA11yResults.some((result) => result?.status === 'warning');

if (failed) {
return 'negative';
Expand All @@ -154,11 +156,24 @@ export const TestProviderRender: FC<
return 'positive';
}, [state.running, isA11yAddon, config.a11y, a11yResults]);

const a11yNotPassedAmount = a11yResults?.filter(
(result) => result?.status === 'failed' || result?.status === 'warning'
).length;
const a11yNotPassedAmount = state.config?.a11y
? a11yResults?.filter((result) => result?.status === 'failed' || result?.status === 'warning')
.length
: undefined;

const a11ySkippedAmount =
state.running || !state?.details.config?.a11y || !state.config.a11y
? null
: a11yResults?.filter((result) => !result).length;

const a11ySkippedLabel = a11ySkippedAmount
? a11ySkippedAmount === 1 && isStoryEntry
? '(skipped)'
: `(${a11ySkippedAmount} skipped)`
: '';

const storyId = isStoryEntry ? entryId : undefined;

const results = (state.details?.testResults || [])
.flatMap((test) => {
if (!entryId) {
Expand Down Expand Up @@ -333,7 +348,7 @@ export const TestProviderRender: FC<
)}
{isA11yAddon && (
<ListItem
title={<ItemTitle enabled={config.a11y}>Accessibility</ItemTitle>}
title={<ItemTitle enabled={config.a11y}>Accessibility {a11ySkippedLabel}</ItemTitle>}
onClick={
(a11yStatus === 'negative' || a11yStatus === 'warning') && a11yResults.length
? () => {
Expand Down
Loading
Loading