Skip to content

Commit

Permalink
Merge branch 'next' into feature/subheading-tag-id
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinpalkovic authored Dec 4, 2023
2 parents 8458221 + a77d915 commit 1ed3441
Show file tree
Hide file tree
Showing 87 changed files with 1,186 additions and 738 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## 7.6.3

- Next.js: Fix next/font/local usage in babel mode - [#25045](https://github.com/storybookjs/storybook/pull/25045), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!

## 7.6.2

- CLI: Improve dependency metadata detection in storybook doctor - [#25037](https://github.com/storybookjs/storybook/pull/25037), thanks [@yannbf](https://github.com/yannbf)!
- React-Docgen: Make error-handling more gentle - [#25055](https://github.com/storybookjs/storybook/pull/25055), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!

## 7.6.1

- Next.js: Fix AppRouterProvider usage - [#25032](https://github.com/storybookjs/storybook/pull/25032), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!
- SvelteKit: Fix HMR not working - [#25031](https://github.com/storybookjs/storybook/pull/25031), thanks [@JReinhold](https://github.com/JReinhold)!
- Test: Downgrade @testing-library/user-event to 14.3.0 - [#25004](https://github.com/storybookjs/storybook/pull/25004), thanks [@kasperpeulen](https://github.com/kasperpeulen)!
- Webpack: Fix exclude regex in react-docgen-loader - [#25030](https://github.com/storybookjs/storybook/pull/25030), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!

## 7.6.0

Storybook 7.6 is here with increased performance and much more!
Expand Down
18 changes: 18 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- [UI layout state has changed shape](#ui-layout-state-has-changed-shape)
- [New UI and props for Button and IconButton components](#new-ui-and-props-for-button-and-iconbutton-components)
- [Icons is deprecated](#icons-is-deprecated)
- [React-docgen component analysis by default](#react-docgen-component-analysis-by-default)
- [From version 7.5.0 to 7.6.0](#from-version-750-to-760)
- [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated)
- [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated)
Expand Down Expand Up @@ -321,6 +322,7 @@
- [Packages renaming](#packages-renaming)
- [Deprecated embedded addons](#deprecated-embedded-addons)


## From version 7.x to 8.0.0

### Implicit actions can not be used during rendering (for example in the play function)
Expand Down Expand Up @@ -442,6 +444,22 @@ The `IconButton` doesn't have any deprecated props but it now uses the new `Butt

In Storybook 8.0 we are introducing a new icon library available with `@storybook/icons`. We are deprecating the `Icons` component in `@storybook/components` and recommend that addon creators and Storybook maintainers use the new `@storybook/icons` component instead.

#### React-docgen component analysis by default

In Storybook 7, we used `react-docgen-typescript` to analyze React component props and auto-generate controls. In Storybook 8, we have moved to `react-docgen` as the new default. `react-docgen` is dramatically more efficient, shaving seconds off of dev startup times. However, it only analyzes basic TypeScript constructs.

We feel `react-docgen` is the right tradeoff for most React projects. However, if you need the full fidelity of `react-docgen-typescript`, you can opt-in using the following setting in `.storybook/main.js`:

```js
export default {
typescript: {
reactDocgen: 'react-docgen-typescript',
}
}
```

For more information see: https://storybook.js.org/docs/react/api/main-config-typescript#reactdocgen

## From version 7.5.0 to 7.6.0

#### CommonJS with Vite is deprecated
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Storybook comes with a lot of [addons](https://storybook.js.org/docs/react/confi

### Community

For additional help, join us in the [Storybook Discord](https://discord.gg/storybook).
For additional help, share your issue in [the repo's GitHub Discussions](https://github.com/storybookjs/storybook/discussions/new?category=help).

## Projects

Expand Down
2 changes: 1 addition & 1 deletion code/addons/controls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Addon-knobs is one of Storybook's most popular addons with over 1M weekly downlo

Therefore, rather than deprecating addon-knobs immediately, we will continue to release knobs with the Storybook core distribution until 7.0. This will give us time to improve Controls based on user feedback, and also give knobs users ample time to migrate.

If you are somehow tied to knobs or prefer the knobs interface, we are happy to take on maintainers for the knobs project. If this interests you, hop on our [Discord](https://discord.gg/storybook).
If you are somehow tied to knobs or prefer the knobs interface, we are happy to take on maintainers for the knobs project. If this interests you, please get in touch with us in the [`#contributing`](https://discord.com/channels/486522875931656193/839297503446695956) Discord channel.

### How do I migrate from addon-knobs?

Expand Down
40 changes: 6 additions & 34 deletions code/addons/docs/react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ To learn more about Storybook Docs, read the [general documentation](../README.m
- [Props tables](#props-tables)
- [MDX](#mdx)
- [Inline stories](#inline-stories)
- [TypeScript props with `react-docgen`](#typescript-props-with-react-docgen)
- [TypeScript props with `react-docgen-typescript`](#typescript-props-with-react-docgen-typescript)
- [More resources](#more-resources)

## Installation
Expand Down Expand Up @@ -108,17 +108,17 @@ To do so for all stories, update `.storybook/preview.js`:
export const parameters = { docs: { story: { inline: false } } };
```

## TypeScript props with `react-docgen`
## TypeScript props with `react-docgen-typescript`

If you're using TypeScript, there are two different options for generating props: `react-docgen-typescript` (default) or `react-docgen`.
If you're using TypeScript, there are two different options for generating props: `react-docgen` (default) or `react-docgen-typescript`.

You can add the following lines to your `.storybook/main.js` to switch between the two (or disable docgen):

```js
export default {
typescript: {
// also valid 'react-docgen-typescript' | false
reactDocgen: 'react-docgen',
// also valid 'react-docgen' | false
reactDocgen: 'react-docgen-typescript',
},
};
```
Expand All @@ -129,7 +129,7 @@ Neither option is perfect, so here's everything you should know if you're thinki
| --------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| **Features** | **Great**. The analysis produces great results which gives the best props table experience. | **OK**. React-docgen produces basic results that are fine for most use cases. |
| **Performance** | **Slow**. It's doing a lot more work to produce those results, and may also have an inefficient implementation. | **Blazing fast**. Adding it to your project increases build time negligibly. |
| **Bugs** | **Many**. There are a lot of corner cases that are not handled properly, and are annoying for developers. | **Few**. But there's a dealbreaker, which is lack for imported types (see below). |
| **Bugs** | **Some**. There are corner cases that are not handled properly, and are annoying for developers. | **Some**. There are corner cases that are not handled properly, and are annoying for developers. |
| **SB docs** | **Good**. Our prop tables have supported `react-docgen-typescript` results from the beginning, so it's relatively stable. | **OK**. There are some obvious improvements to fully support `react-docgen`, and they're coming soon. |

**Performance** is a common question, so here are build times from a random project to quantify. Your mileage may vary:
Expand All @@ -140,34 +140,6 @@ Neither option is perfect, so here's everything you should know if you're thinki
| react-docgen | 29s |
| none | 28s |

The biggest limitation of `react-docgen` is lack of support for imported types. What that means is that when a component uses a type defined in another file or package, `react-docgen` is unable to extract props information for that type.

```tsx
import React, { FC } from 'react';
import SomeType from './someFile';

type NewType = SomeType & { foo: string };
const MyComponent: FC<NewType> = ...
```

So in the previous example, `SomeType` would simply be ignored! There's an [open PR for this in the `react-docgen` repo](https://github.com/reactjs/react-docgen/pull/352) which you can upvote if it affects you.

Another common pitfall when switching to `react-docgen` is [lack of support for `React.FC`](https://github.com/reactjs/react-docgen/issues/387). This means that the following common pattern **DOESN'T WORK**:

```tsx
import React, { FC } from 'react';
interface IProps { ... };
const MyComponent: FC<IProps> = ({ ... }) => ...
```

Fortunately, the following workaround works:

```tsx
const MyComponent: FC<IProps> = ({ ... }: IProps) => ...
```

Please upvote [the issue](https://github.com/reactjs/react-docgen/issues/387) if this is affecting your productivity, or better yet, submit a fix!

## More resources

Want to learn more? Here are some more articles on Storybook Docs:
Expand Down
1 change: 0 additions & 1 deletion code/frameworks/nextjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ The following features are not supported (yet). Support for these features might
- [Support font loaders configuration in next.config.js](https://nextjs.org/docs/basic-features/font-optimization#specifying-a-subset)
- [fallback](https://nextjs.org/docs/api-reference/next/font#fallback) option
- [adjustFontFallback](https://nextjs.org/docs/api-reference/next/font#adjustfontfallback) option
- [declarations](https://nextjs.org/docs/api-reference/next/font#declarations) option
- [preload](https://nextjs.org/docs/api-reference/next/font#preload) option gets ignored. Storybook handles Font loading its own way.
- [display](https://nextjs.org/docs/api-reference/next/font#display) option gets ignored. All fonts are loaded with display set to "block" to make Storybook load the font properly.

Expand Down
12 changes: 12 additions & 0 deletions code/frameworks/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
"require": "./dist/image-context.js",
"import": "./dist/image-context.mjs"
},
"./dist/routing/app-router-provider": {
"types": "./dist/routing/app-router-provider.d.ts",
"require": "./dist/routing/app-router-provider.js",
"import": "./dist/routing/app-router-provider.mjs"
},
"./dist/routing/app-router-provider-mock": {
"types": "./dist/routing/app-router-provider-mock.d.ts",
"require": "./dist/routing/app-router-provider-mock.js",
"import": "./dist/routing/app-router-provider-mock.mjs"
},
"./preset": {
"types": "./dist/preset.d.ts",
"require": "./dist/preset.js"
Expand Down Expand Up @@ -161,6 +171,8 @@
"./src/images/next-future-image.tsx",
"./src/images/next-legacy-image.tsx",
"./src/images/next-image.tsx",
"./src/routing/app-router-provider.tsx",
"./src/routing/app-router-provider-mock.tsx",
"./src/font/webpack/loader/storybook-nextjs-font-loader.ts",
"./src/swc/next-swc-loader-patch.ts"
],
Expand Down
4 changes: 4 additions & 0 deletions code/frameworks/nextjs/src/dependency-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const mapping: Record<string, Record<string, string>> = {
'next/dist/shared/lib/hooks-client-context.shared-runtime':
'next/dist/shared/lib/hooks-client-context',
},
'<13.0.0': {
'@storybook/nextjs/dist/routing/app-router-provider':
'@storybook/nextjs/dist/routing/app-router-provider-mock',
},
'<13.5.0': {
'next/dist/shared/lib/router-context.shared-runtime': 'next/dist/shared/lib/router-context',
'next/dist/shared/lib/head-manager-context.shared-runtime':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ import type { LoaderOptions } from '../types';

type LocalFontSrc = string | Array<{ path: string; weight?: string; style?: string }>;

export async function getFontFaceDeclarations(options: LoaderOptions, rootContext: string) {
export async function getFontFaceDeclarations(
options: LoaderOptions,
rootContext: string,
swcMode: boolean
) {
const localFontSrc = options.props.src as LocalFontSrc;

// Parent folder relative to the root context
const parentFolder = path
.dirname(path.join(getProjectRoot(), options.filename))
.replace(rootContext, '');
const parentFolder = swcMode
? path.dirname(path.join(getProjectRoot(), options.filename)).replace(rootContext, '')
: path.dirname(options.filename).replace(rootContext, '');

const { validateData } = require('../utils/local-font-utils');
const { weight, style, variable } = validateData('', options.props);
const { weight, style, variable, declarations = [] } = validateData('', options.props);

const id = `font-${loaderUtils.getHashDigest(
Buffer.from(JSON.stringify(localFontSrc)),
Expand All @@ -26,6 +30,10 @@ export async function getFontFaceDeclarations(options: LoaderOptions, rootContex
6
)}`;

const fontDeclarations = declarations
.map(({ prop, value }: { prop: string; value: string }) => `${prop}: ${value};`)
.join('\n');

const arePathsWin32Format = /^[a-z]:\\/iu.test(options.filename);
const cleanWin32Path = (pathString: string): string =>
arePathsWin32Format ? pathString.replace(/\\/gu, '/') : pathString;
Expand All @@ -37,6 +45,7 @@ export async function getFontFaceDeclarations(options: LoaderOptions, rootContex
return `@font-face {
font-family: ${id};
src: url(.${localFontPath});
${fontDeclarations}
}`;
}
return localFontSrc
Expand All @@ -48,6 +57,7 @@ export async function getFontFaceDeclarations(options: LoaderOptions, rootContex
src: url(.${localFontPath});
${font.weight ? `font-weight: ${font.weight};` : ''}
${font.style ? `font-style: ${font.style};` : ''}
${fontDeclarations}
}`;
})
.join('');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type FontFaceDeclaration = {

export default async function storybookNextjsFontLoader(this: any) {
const loaderOptions = this.getOptions() as LoaderOptions;
let swcMode = false;
let options;

if (Object.keys(loaderOptions).length > 0) {
Expand All @@ -23,6 +24,7 @@ export default async function storybookNextjsFontLoader(this: any) {
} else {
// handles SWC mode
const importQuery = JSON.parse(this.resourceQuery.slice(1));
swcMode = true;

options = {
filename: importQuery.path,
Expand All @@ -42,7 +44,7 @@ export default async function storybookNextjsFontLoader(this: any) {
}

if (options.source.endsWith('next/font/local') || options.source.endsWith('@next/font/local')) {
fontFaceDeclaration = await getLocalFontFaceDeclarations(options, rootCtx);
fontFaceDeclaration = await getLocalFontFaceDeclarations(options, rootCtx, swcMode);
}

if (typeof fontFaceDeclaration !== 'undefined') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable import/no-mutable-exports */
import dedent from 'ts-dedent';

type FontOptions = {
Expand All @@ -22,30 +21,56 @@ type FontOptions = {
}>;
};

let validateData: (functionName: string, fontData: any) => FontOptions;
const trials = [
{
module: '@next/font/dist/local/utils',
exportName: 'validateData',
description: 'Support @next/font prior to v13.2.5',
},
{
module: '@next/font/dist/local/validate-local-font-function-call',
exportName: 'validateLocalFontFunctionCall',
description: 'Support @next/font since v13.2.5',
},
{
module: 'next/dist/compiled/@next/font/dist/local/utils',
exportName: 'validateData',
description: 'Support next/font prior to v13.2.4',
},
{
module: 'next/dist/compiled/@next/font/dist/local/validate-local-font-function-call',
exportName: 'validateLocalFontFunctionCall',
description: 'Support next/font since v13.2.4',
},
];

// Support @next/font
try {
const fontUtils = require('@next/font/dist/local/utils');
validateData = fontUtils.validateData;
} catch (_) {
// Support next/font prior to v13.2.4
try {
const fontUtils = require('next/dist/compiled/@next/font/dist/local/utils');
validateData = fontUtils.validateData;
} catch (__) {
// Support next/font since v13.2.4
const validateData: (functionName: string, fontData: any) => FontOptions = (() => {
// eslint-disable-next-line no-restricted-syntax
for (const { module, exportName } of trials) {
try {
validateData =
require('next/dist/compiled/@next/font/dist/local/validate-local-font-function-call').validateLocalFontFunctionCall;
} catch (e) {
throw new Error(dedent`
We are unable to load the helper functions to use next/font/local.
Please downgrade Next.js to version 13.2.4 to continue to use next/font/local in Storybook.
Feel free to open a Github Issue!
`);
const loadedModule = require(module);
if (exportName in loadedModule) {
return loadedModule[exportName];
}
} catch {
// Continue to the next trial
}
}
}

// Generate the dynamic error message
const errorDetails = trials
.map(
(trial) =>
`- ${trial.description}: tries to import '${trial.exportName}' from '${trial.module}'`
)
.join('\n');

throw new Error(dedent`
We were unable to load the helper functions to use next/font/local. The code attempted the following scenarios:
${errorDetails}
Please check your Next.js version and the module paths. If you resolve this issue for a version or setup not covered, consider contributing by updating the 'trials' array and making a pull request.
`);
})();

export { validateData };
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';

// The mock is used for Next.js < 13, where the AppRouterProvider doesn't exist
export const AppRouterProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
return <>{children}</>;
};
17 changes: 3 additions & 14 deletions code/frameworks/nextjs/src/routing/decorator.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import * as React from 'react';
import type { Addon_StoryContext } from '@storybook/types';
import { action } from '@storybook/addon-actions';
// @ts-expect-error Using absolute path import to 1) avoid prebundling and 2) being able to substitute the module for Next.js < 13
// eslint-disable-next-line import/no-extraneous-dependencies
import { AppRouterProvider } from '@storybook/nextjs/dist/routing/app-router-provider';
import { PageRouterProvider } from './page-router-provider';
import type { AppRouterProvider as TAppRouterProvider } from './app-router-provider';
import type { RouteParams, NextAppDirectory } from './types';

const defaultRouterParams: RouteParams = {
Expand All @@ -17,19 +19,6 @@ export const RouterDecorator = (
const nextAppDirectory =
(parameters.nextjs?.appDirectory as NextAppDirectory | undefined) ?? false;

const [AppRouterProvider, setAppRouterProvider] = React.useState<
typeof TAppRouterProvider | undefined
>();

React.useEffect(() => {
if (!nextAppDirectory) {
return;
}
import('./app-router-provider').then((exports) =>
setAppRouterProvider(() => exports.AppRouterProvider)
);
}, [nextAppDirectory]);

if (nextAppDirectory) {
if (!AppRouterProvider) {
return null;
Expand Down
Loading

0 comments on commit 1ed3441

Please sign in to comment.