Skip to content

Commit 7a6899f

Browse files
authored
Merge pull request #30099 from storybookjs/version-non-patch-from-8.5.0-beta.2
Release: Prerelease 8.5.0-beta.3
2 parents 1f6fafa + f1fee6e commit 7a6899f

File tree

24 files changed

+252
-271
lines changed

24 files changed

+252
-271
lines changed

CHANGELOG.prerelease.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 8.5.0-beta.3
2+
3+
- Addon A11y: Fix skipped status handling in Testing Module - [#30077](https://github.com/storybookjs/storybook/pull/30077), thanks @valentinpalkovic!
4+
- Core: Float context menu button on top of story titles in sidebar - [#30080](https://github.com/storybookjs/storybook/pull/30080), thanks @ghengeveld!
5+
- Onboarding: Replace `react-confetti` with `@neoconfetti/react` - [#30098](https://github.com/storybookjs/storybook/pull/30098), thanks @ndelangen!
6+
17
## 8.5.0-beta.2
28

39
- Addon Test: Clear coverage data when starting or watching - [#30072](https://github.com/storybookjs/storybook/pull/30072), thanks @ghengeveld!

code/.storybook/preview.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -358,5 +358,6 @@ export const parameters = {
358358
opacity: 0.4,
359359
},
360360
},
361-
tags: ['test', 'vitest', '!a11ytest'],
362361
};
362+
363+
export const tags = ['test', 'vitest', '!a11ytest'];

code/addons/onboarding/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@
4545
"prep": "jiti ../../../scripts/prepare/addon-bundle.ts"
4646
},
4747
"devDependencies": {
48+
"@neoconfetti/react": "^1.0.0",
4849
"@radix-ui/react-dialog": "^1.0.5",
4950
"@storybook/icons": "^1.2.12",
5051
"@storybook/react": "workspace:*",
5152
"framer-motion": "^11.0.3",
5253
"react": "^18.2.0",
53-
"react-confetti": "^6.1.0",
5454
"react-dom": "^18.2.0",
5555
"react-joyride": "^2.8.2",
5656
"react-use-measure": "^2.1.1",

code/addons/onboarding/src/Onboarding.tsx

+1-11
Original file line numberDiff line numberDiff line change
@@ -268,17 +268,7 @@ export default function Onboarding({ api }: { api: API }) {
268268

269269
return (
270270
<ThemeProvider theme={theme}>
271-
{showConfetti && (
272-
<Confetti
273-
numberOfPieces={800}
274-
recycle={false}
275-
tweenDuration={20000}
276-
onConfettiComplete={(confetti) => {
277-
confetti?.reset();
278-
setShowConfetti(false);
279-
}}
280-
/>
281-
)}
271+
{showConfetti && <Confetti />}
282272
{step === '1:Intro' ? (
283273
<SplashScreen onDismiss={() => setStep('2:Controls')} />
284274
) : (

code/addons/onboarding/src/components/Confetti/Confetti.stories.tsx

+11-40
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,19 @@ const meta: Meta<typeof Confetti> = {
88
component: Confetti,
99
parameters: {
1010
chromatic: { disableSnapshot: true },
11+
layout: 'fullscreen',
1112
},
1213
decorators: [
1314
(StoryFn) => (
14-
<div style={{ height: '100vh', width: '100vw' }}>
15-
<button>I am clickable</button>
15+
<div
16+
style={{
17+
height: '100vh',
18+
width: '100vw',
19+
alignContent: 'center',
20+
textAlign: 'center',
21+
}}
22+
>
23+
<span>Falling confetti! 🎉</span>
1624
<StoryFn />
1725
</div>
1826
),
@@ -23,41 +31,4 @@ export default meta;
2331

2432
type Story = StoryObj<typeof Confetti>;
2533

26-
export const Default: Story = {
27-
args: {
28-
recycle: true,
29-
numberOfPieces: 200,
30-
top: undefined,
31-
left: undefined,
32-
width: undefined,
33-
height: undefined,
34-
friction: 0.99,
35-
wind: 0,
36-
gravity: 0.1,
37-
initialVelocityX: 4,
38-
initialVelocityY: 10,
39-
tweenDuration: 5000,
40-
},
41-
};
42-
43-
export const OneTimeConfetti: Story = {
44-
args: {
45-
...Default.args,
46-
numberOfPieces: 800,
47-
recycle: false,
48-
tweenDuration: 20000,
49-
onConfettiComplete: (confetti) => {
50-
confetti?.reset();
51-
},
52-
},
53-
};
54-
55-
export const Positioned: Story = {
56-
args: {
57-
...Default.args,
58-
top: 100,
59-
left: 300,
60-
width: 300,
61-
height: 250,
62-
},
63-
};
34+
export const Default: Story = {};
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,34 @@
1-
import React, { useEffect } from 'react';
2-
import { useState } from 'react';
3-
import { createPortal } from 'react-dom';
1+
import React, { type ComponentProps } from 'react';
42

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

7-
import ReactConfetti from 'react-confetti';
5+
import { Confetti as ReactConfetti } from '@neoconfetti/react';
86

9-
interface ConfettiProps extends Omit<React.ComponentProps<typeof ReactConfetti>, 'drawShape'> {
10-
top?: number;
11-
left?: number;
12-
width?: number;
13-
height?: number;
14-
numberOfPieces?: number;
15-
recycle?: boolean;
16-
colors?: string[];
17-
}
7+
const Wrapper = styled.div({
8+
zIndex: 9999,
9+
position: 'fixed',
10+
top: 0,
11+
left: '50%',
12+
width: '50%',
13+
height: '100%',
14+
});
1815

19-
const Wrapper = styled.div<{
20-
width: number;
21-
height: number;
22-
top: number;
23-
left: number;
24-
}>(({ width, height, left, top }) => ({
25-
width: `${width}px`,
26-
height: `${height}px`,
27-
left: `${left}px`,
28-
top: `${top}px`,
29-
position: 'relative',
30-
overflow: 'hidden',
31-
}));
32-
33-
export function Confetti({
34-
top = 0,
35-
left = 0,
36-
width = window.innerWidth,
37-
height = window.innerHeight,
16+
export const Confetti = React.memo(function Confetti({
17+
timeToFade = 5000,
3818
colors = ['#CA90FF', '#FC521F', '#66BF3C', '#FF4785', '#FFAE00', '#1EA7FD'],
3919
...confettiProps
40-
}: ConfettiProps): React.ReactPortal {
41-
const [confettiContainer] = useState(() => {
42-
const container = document.createElement('div');
43-
container.setAttribute('id', 'confetti-container');
44-
container.setAttribute(
45-
'style',
46-
'position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 9999;'
47-
);
48-
49-
return container;
50-
});
51-
52-
useEffect(() => {
53-
document.body.appendChild(confettiContainer);
54-
55-
return () => {
56-
document.body.removeChild(confettiContainer);
57-
};
58-
}, []);
59-
60-
return createPortal(
61-
<Wrapper top={top} left={left} width={width} height={height}>
62-
<ReactConfetti colors={colors} drawShape={draw} {...confettiProps} />
63-
</Wrapper>,
64-
confettiContainer
20+
}: ComponentProps<typeof ReactConfetti> & { timeToFade?: number }) {
21+
return (
22+
<Wrapper>
23+
<ReactConfetti
24+
colors={colors}
25+
particleCount={200}
26+
duration={5000}
27+
stageHeight={window.innerHeight}
28+
stageWidth={window.innerWidth}
29+
destroyAfterDone
30+
{...confettiProps}
31+
/>
32+
</Wrapper>
6533
);
66-
}
67-
68-
enum ParticleShape {
69-
Circle = 1,
70-
Square = 2,
71-
TShape = 3,
72-
LShape = 4,
73-
Triangle = 5,
74-
QuarterCircle = 6,
75-
}
76-
77-
function getRandomInt(min: number, max: number) {
78-
return Math.floor(Math.random() * (max - min)) + min;
79-
}
80-
81-
function draw(this: any, context: CanvasRenderingContext2D) {
82-
this.shape = this.shape || getRandomInt(1, 6);
83-
84-
switch (this.shape) {
85-
case ParticleShape.Square: {
86-
const cornerRadius = 2;
87-
const width = this.w / 2;
88-
const height = this.h / 2;
89-
90-
context.moveTo(-width + cornerRadius, -height);
91-
context.lineTo(width - cornerRadius, -height);
92-
context.arcTo(width, -height, width, -height + cornerRadius, cornerRadius);
93-
context.lineTo(width, height - cornerRadius);
94-
context.arcTo(width, height, width - cornerRadius, height, cornerRadius);
95-
context.lineTo(-width + cornerRadius, height);
96-
context.arcTo(-width, height, -width, height - cornerRadius, cornerRadius);
97-
context.lineTo(-width, -height + cornerRadius);
98-
context.arcTo(-width, -height, -width + cornerRadius, -height, cornerRadius);
99-
100-
break;
101-
}
102-
case ParticleShape.TShape: {
103-
context.rect(-4, -4, 8, 16);
104-
context.rect(-12, -4, 24, 8);
105-
break;
106-
}
107-
case ParticleShape.LShape: {
108-
context.rect(-4, -4, 8, 16);
109-
context.rect(-4, -4, 24, 8);
110-
break;
111-
}
112-
case ParticleShape.Circle: {
113-
context.arc(0, 0, this.radius, 0, 2 * Math.PI);
114-
break;
115-
}
116-
case ParticleShape.Triangle: {
117-
context.moveTo(16, 4);
118-
context.lineTo(4, 24);
119-
context.lineTo(24, 24);
120-
break;
121-
}
122-
case ParticleShape.QuarterCircle: {
123-
context.arc(4, -4, 4, -Math.PI / 2, 0);
124-
context.lineTo(4, 0);
125-
break;
126-
}
127-
}
128-
129-
context.closePath();
130-
context.fill();
131-
}
34+
});

code/addons/test/src/components/TestProviderRender.stories.tsx

+24
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ const baseState: TestProviderState<Details, Config> = {
5252
coverage: false,
5353
},
5454
details: {
55+
config: {
56+
a11y: false,
57+
coverage: false,
58+
},
5559
testResults: [
5660
{
5761
endTime: 0,
@@ -141,6 +145,10 @@ export const WithCoverageNegative: Story = {
141145
...config,
142146
...baseState,
143147
details: {
148+
config: {
149+
a11y: false,
150+
coverage: true,
151+
},
144152
testResults: [],
145153
coverageSummary: {
146154
percentage: 20,
@@ -162,6 +170,10 @@ export const WithCoverageWarning: Story = {
162170
...baseState,
163171
details: {
164172
testResults: [],
173+
config: {
174+
a11y: false,
175+
coverage: true,
176+
},
165177
coverageSummary: {
166178
percentage: 50,
167179
status: 'warning',
@@ -182,6 +194,10 @@ export const WithCoveragePositive: Story = {
182194
...baseState,
183195
details: {
184196
testResults: [],
197+
config: {
198+
a11y: false,
199+
coverage: true,
200+
},
185201
coverageSummary: {
186202
percentage: 80,
187203
status: 'positive',
@@ -206,6 +222,10 @@ export const Editing: Story = {
206222
},
207223
details: {
208224
testResults: [],
225+
config: {
226+
a11y: false,
227+
coverage: false,
228+
},
209229
},
210230
},
211231
},
@@ -229,6 +249,10 @@ export const EditingAndWatching: Story = {
229249
},
230250
details: {
231251
testResults: [],
252+
config: {
253+
a11y: true,
254+
coverage: true, // should be automatically disabled in the UI
255+
},
232256
},
233257
},
234258
},

code/addons/test/src/components/TestProviderRender.tsx

+22-7
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,14 @@ export const TestProviderRender: FC<
138138
return 'unknown';
139139
}
140140

141-
if (!a11yResults) {
141+
const definedA11yResults = a11yResults?.filter(Boolean) ?? [];
142+
143+
if (!definedA11yResults || definedA11yResults.length === 0) {
142144
return 'unknown';
143145
}
144146

145-
const failed = a11yResults.some((result) => result?.status === 'failed');
146-
const warning = a11yResults.some((result) => result?.status === 'warning');
147+
const failed = definedA11yResults.some((result) => result?.status === 'failed');
148+
const warning = definedA11yResults.some((result) => result?.status === 'warning');
147149

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

157-
const a11yNotPassedAmount = a11yResults?.filter(
158-
(result) => result?.status === 'failed' || result?.status === 'warning'
159-
).length;
159+
const a11yNotPassedAmount = state.config?.a11y
160+
? a11yResults?.filter((result) => result?.status === 'failed' || result?.status === 'warning')
161+
.length
162+
: undefined;
163+
164+
const a11ySkippedAmount =
165+
state.running || !state?.details.config?.a11y || !state.config.a11y
166+
? null
167+
: a11yResults?.filter((result) => !result).length;
168+
169+
const a11ySkippedLabel = a11ySkippedAmount
170+
? a11ySkippedAmount === 1 && isStoryEntry
171+
? '(skipped)'
172+
: `(${a11ySkippedAmount} skipped)`
173+
: '';
160174

161175
const storyId = isStoryEntry ? entryId : undefined;
176+
162177
const results = (state.details?.testResults || [])
163178
.flatMap((test) => {
164179
if (!entryId) {
@@ -333,7 +348,7 @@ export const TestProviderRender: FC<
333348
)}
334349
{isA11yAddon && (
335350
<ListItem
336-
title={<ItemTitle enabled={config.a11y}>Accessibility</ItemTitle>}
351+
title={<ItemTitle enabled={config.a11y}>Accessibility {a11ySkippedLabel}</ItemTitle>}
337352
onClick={
338353
(a11yStatus === 'negative' || a11yStatus === 'warning') && a11yResults.length
339354
? () => {

0 commit comments

Comments
 (0)