Merge branch 'next' into fix/stats-json-in-angular-executor

This commit is contained in:
Yann Braga 2024-11-04 09:33:51 +01:00 committed by GitHub
commit 30293dd3de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
125 changed files with 1147 additions and 451 deletions

View File

@ -19,6 +19,7 @@ Thank you for contributing to Storybook! Please submit all PRs to the `next` bra
<!-- Please check (put an "x" inside the "[ ]") the applicable items below to communicate how to test your changes -->
#### The changes in this PR are covered in the following automated tests:
- [ ] stories
- [ ] unit tests
- [ ] integration tests
@ -46,21 +47,21 @@ _This section is mandatory for all contributions. If you believe no manual test
## Checklist for Maintainers
- [ ] When this PR is ready for testing, make sure to add `ci:normal`, `ci:merged` or `ci:daily` GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in `code/lib/cli/src/sandbox-templates.ts`
- [ ] When this PR is ready for testing, make sure to add `ci:normal`, `ci:merged` or `ci:daily` GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in `code/lib/cli-storybook/src/sandbox-templates.ts`
- [ ] Make sure this PR contains **one** of the labels below:
<details>
<summary>Available labels</summary>
- `bug`: Internal changes that fixes incorrect behavior.
- `maintenance`: User-facing maintenance tasks.
- `dependencies`: Upgrading (sometimes downgrading) dependencies.
- `build`: Internal-facing build tooling & test updates. Will not show up in release changelog.
- `cleanup`: Minor cleanup style change. Will not show up in release changelog.
- `documentation`: Documentation **only** changes. Will not show up in release changelog.
- `feature request`: Introducing a new feature.
- `BREAKING CHANGE`: Changes that break compatibility in some way with current major version.
- `other`: Changes that don't fit in the above categories.
- `bug`: Internal changes that fixes incorrect behavior.
- `maintenance`: User-facing maintenance tasks.
- `dependencies`: Upgrading (sometimes downgrading) dependencies.
- `build`: Internal-facing build tooling & test updates. Will not show up in release changelog.
- `cleanup`: Minor cleanup style change. Will not show up in release changelog.
- `documentation`: Documentation **only** changes. Will not show up in release changelog.
- `feature request`: Introducing a new feature.
- `BREAKING CHANGE`: Changes that break compatibility in some way with current major version.
- `other`: Changes that don't fit in the above categories.
</details>
### 🦋 Canary release
@ -74,4 +75,4 @@ _core team members can create a canary release [here](https://github.com/storybo
<!-- CANARY_RELEASE_SECTION -->
<!-- BENCHMARK_SECTION -->
<!-- BENCHMARK_SECTION -->
<!-- BENCHMARK_SECTION -->

View File

@ -1,3 +1,75 @@
## 8.4.1
- Core: Relax peer dep constraint of shim packages - [#29503](https://github.com/storybookjs/storybook/pull/29503), thanks @kasperpeulen!
## 8.4.0
Storybook 8.4 comes with a ton of exciting new features designed to give you the best experience developing, testing, and debugging tests in the browser!
- ▶️ **Unified UI** for component testing
- 5 **Svelte 5** and Svelte CSF support
- ⚛️ **React Native Storybook 8** release
- 🏷️ **Tags-based filtering** to organize your Storybook
- 🫧 **Dependency cleanup** to reduce install footprint
- 💯 **Hundreds** more improvements
<details>
<summary>List of all updates</summary>
- Addon Test: Adjust file exports to be ESM/CJS compatible - [#29471](https://github.com/storybookjs/storybook/pull/29471), thanks @valentinpalkovic!
- Addon Test: Error when addon interactions exists - [#29434](https://github.com/storybookjs/storybook/pull/29434), thanks @valentinpalkovic!
- Addon Test: Escape XML when converting ANSI to HTML in test errors - [#29446](https://github.com/storybookjs/storybook/pull/29446), thanks @ghengeveld!
- Addon Test: Fix hiding stacktrace for assertion errors in test panel - [#29458](https://github.com/storybookjs/storybook/pull/29458), thanks @ghengeveld!
- Addon Test: Improve Error Handling - [#29476](https://github.com/storybookjs/storybook/pull/29476), thanks @valentinpalkovic!
- Addon Test: Improve postinstall script - [#29479](https://github.com/storybookjs/storybook/pull/29479), thanks @yannbf!
- Addon Test: Improve unsupported vitest message - [#29486](https://github.com/storybookjs/storybook/pull/29486), thanks @valentinpalkovic!
- Addon Test: Only register testing module in Vite projects - [#29472](https://github.com/storybookjs/storybook/pull/29472), thanks @yannbf!
- Addon Test: Throttle Vitest progress updates more heavily - [#29482](https://github.com/storybookjs/storybook/pull/29482), thanks @ghengeveld!
- Addon-docs, blocks: Prebundle dependencies - [#29301](https://github.com/storybookjs/storybook/pull/29301), thanks @JReinhold!
- Addon-Test: Support for `@vitest/browser` v2.1.2 - [#29407](https://github.com/storybookjs/storybook/pull/29407), thanks @strozw!
- Blocks: Prebundle `es-toolkit` - [#29259](https://github.com/storybookjs/storybook/pull/29259), thanks @JReinhold!
- Builder-vite: Replace .at() call with [] in codegen - [#29048](https://github.com/storybookjs/storybook/pull/29048), thanks @Chudesnov!
- CLI: Don't add `@storybook/addon-links` by default - [#29177](https://github.com/storybookjs/storybook/pull/29177), thanks @tobiasdiez!
- CLI: Ensure `.gitignore` updated via CLI ends with a newline - [#29124](https://github.com/storybookjs/storybook/pull/29124), thanks @3w36zj6!
- CLI: Fix `yarn` detection - [#29448](https://github.com/storybookjs/storybook/pull/29448), thanks @ndelangen!
- CLI: Migrate from `chalk` to `picocolors` - [#28262](https://github.com/storybookjs/storybook/pull/28262), thanks @43081j!
- CLI: Refactor NPMProxy error parsing logic - [#29459](https://github.com/storybookjs/storybook/pull/29459), thanks @yannbf!
- ConfigFile: Fix `export { X }` parsing - [#29344](https://github.com/storybookjs/storybook/pull/29344), thanks @vctqs1!
- Core: Add unified UI Testing Module - [#29241](https://github.com/storybookjs/storybook/pull/29241), thanks @yannbf!
- Core: Close story status menu when selecting an item - [#29455](https://github.com/storybookjs/storybook/pull/29455), thanks @ghengeveld!
- Core: Fix building Storybook deleting project root files - [#29371](https://github.com/storybookjs/storybook/pull/29371), thanks @JReinhold!
- Core: Fix race condition during empty folder init - [#29490](https://github.com/storybookjs/storybook/pull/29490), thanks @valentinpalkovic!
- Core: Make `prettier` an optional peer dependency - [#29223](https://github.com/storybookjs/storybook/pull/29223), thanks @JReinhold!
- Core: Migrate from `express` to `polka` - [#29230](https://github.com/storybookjs/storybook/pull/29230), thanks @43081j!
- Core: Migrate from `qs` to `picoquery` - [#28315](https://github.com/storybookjs/storybook/pull/28315), thanks @43081j!
- Core: Open 'Component tests' addon panel when clicking a story status - [#29456](https://github.com/storybookjs/storybook/pull/29456), thanks @ghengeveld!
- Core: Remove `handlebars` usage - [#29208](https://github.com/storybookjs/storybook/pull/29208), thanks @ndelangen!
- Core: Remove dependence on `file-system-cache` - [#29256](https://github.com/storybookjs/storybook/pull/29256), thanks @ndelangen!
- Core: Replace `fs-extra` with the native APIs - [#29126](https://github.com/storybookjs/storybook/pull/29126), thanks @ziebam!
- Core: Replace `lodash` with `es-toolkit` - [#28981](https://github.com/storybookjs/storybook/pull/28981), thanks @ndelangen!
- Core: Show checkmark icon in story status dropdown and update status label for component tests - [#29451](https://github.com/storybookjs/storybook/pull/29451), thanks @ghengeveld!
- Core: Show tooltip on filter toggles to clarify their purpose - [#29447](https://github.com/storybookjs/storybook/pull/29447), thanks @ghengeveld!
- Core: Track test provider state in sessionStorage - [#29450](https://github.com/storybookjs/storybook/pull/29450), thanks @ghengeveld!
- Core: Upgrade `esbuild`, broadening version range - [#29254](https://github.com/storybookjs/storybook/pull/29254), thanks @ndelangen!
- Dependencies: Upgrade VTA to v3.1.0 - [#29449](https://github.com/storybookjs/storybook/pull/29449), thanks @ghengeveld!
- Dependencies: Upgrade VTA to v3.2.0 to resolve peerDep conflict - [#29461](https://github.com/storybookjs/storybook/pull/29461), thanks @ghengeveld!
- Interactions: Escape xml of interactions errors - [#29414](https://github.com/storybookjs/storybook/pull/29414), thanks @kasperpeulen!
- Maintenance: Fix broken and outdated documentation links - [#29412](https://github.com/storybookjs/storybook/pull/29412), thanks @jonniebigodes!
- Manager: Add tags property to ComponentEntry objects - [#29343](https://github.com/storybookjs/storybook/pull/29343), thanks @Sidnioulz!
- React: Prebundle all of `renderers/react`'s dependencies - [#29298](https://github.com/storybookjs/storybook/pull/29298), thanks @ndelangen!
- Svelte: Improve argTypes inference with `svelte2tsx` - support runes - [#29423](https://github.com/storybookjs/storybook/pull/29423), thanks @JReinhold!
- Test: Remove unused `util` dependency - [#29310](https://github.com/storybookjs/storybook/pull/29310), thanks @JReinhold!
- UI: Brand image css class conflict causes image to resize on hot reloads - [#29129](https://github.com/storybookjs/storybook/pull/29129), thanks @ShreySinha02!
- UI: Fix RefIndicator to use CheckIcon instead of string - [#29209](https://github.com/storybookjs/storybook/pull/29209), thanks @JSMike!
- UI: Simple tag filtering - [#29333](https://github.com/storybookjs/storybook/pull/29333), thanks @shilman!
- UI: Use production-mode `react` in manager - [#29197](https://github.com/storybookjs/storybook/pull/29197), thanks @ndelangen!
- Viewport-addon: Add InitialViewportKeys type to viewport addon - [#29182](https://github.com/storybookjs/storybook/pull/29182), thanks @hyeongrok7874!
- Vite: Add jsdoc-type-pratt-parser to `optimizeDeps` - [#29179](https://github.com/storybookjs/storybook/pull/29179), thanks @tobiasdiez!
- Vite: Cleanup and prebundle dependencies - [#29302](https://github.com/storybookjs/storybook/pull/29302), thanks @JReinhold!
- Webpack: Fix export 'act' (imported as 'React4') was not found in 'react' errors in webpack - [#29235](https://github.com/storybookjs/storybook/pull/29235), thanks @kasperpeulen!
</details>
## 8.3.6
- CLI: Install Svelte CSF v5 in Svelte5 projects - [#29323](https://github.com/storybookjs/storybook/pull/29323), thanks @shilman!

View File

@ -1,3 +1,34 @@
## 8.5.0-alpha.2
- Addon Test: Only render the TestingModule component in development mode - [#29501](https://github.com/storybookjs/storybook/pull/29501), thanks @yannbf!
- CLI: Fix Solid init by installing `@storybook/test` - [#29514](https://github.com/storybookjs/storybook/pull/29514), thanks @shilman!
- Core: Add bun support with npm fallback - [#29267](https://github.com/storybookjs/storybook/pull/29267), thanks @stephenjason89!
- Core: Shim CJS-only globals in ESM output - [#29157](https://github.com/storybookjs/storybook/pull/29157), thanks @valentinpalkovic!
- Next.js: Fix bundled react and react-dom in monorepos - [#29444](https://github.com/storybookjs/storybook/pull/29444), thanks @sentience!
- Next.js: Upgrade sass-loader from ^13.2.0 to ^14.2.1 - [#29264](https://github.com/storybookjs/storybook/pull/29264), thanks @HoncharenkoZhenya!
- UI: Add support for groups to `TooltipLinkList` and use it in main menu - [#29507](https://github.com/storybookjs/storybook/pull/29507), thanks @ghengeveld!
## 8.5.0-alpha.1
- Core: Relax peer dep constraint of shim packages - [#29503](https://github.com/storybookjs/storybook/pull/29503), thanks @kasperpeulen!
## 8.5.0-alpha.0
## 8.4.0-beta.5
- Addon Test: Improve unsupported vitest message - [#29486](https://github.com/storybookjs/storybook/pull/29486), thanks @valentinpalkovic!
- Core: Fix race condition during empty folder init - [#29490](https://github.com/storybookjs/storybook/pull/29490), thanks @valentinpalkovic!
## 8.4.0-beta.4
- Addon Test: Improve Error Handling - [#29476](https://github.com/storybookjs/storybook/pull/29476), thanks @valentinpalkovic!
- Addon Test: Improve postinstall script - [#29479](https://github.com/storybookjs/storybook/pull/29479), thanks @yannbf!
- Addon Test: Throttle Vitest progress updates more heavily - [#29482](https://github.com/storybookjs/storybook/pull/29482), thanks @ghengeveld!
- CLI: Refactor NPMProxy error parsing logic - [#29459](https://github.com/storybookjs/storybook/pull/29459), thanks @yannbf!
- Core: Track test provider state in sessionStorage - [#29450](https://github.com/storybookjs/storybook/pull/29450), thanks @ghengeveld!
- Dependencies: Upgrade VTA to v3.2.0 to resolve peerDep conflict - [#29461](https://github.com/storybookjs/storybook/pull/29461), thanks @ghengeveld!
## 8.4.0-beta.3
- Addon Test: Only register testing module in Vite projects - [#29472](https://github.com/storybookjs/storybook/pull/29472), thanks @yannbf!

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-a11y",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Test component compliance with web accessibility standards",
"keywords": [
"a11y",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-actions",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Get UI feedback when an action is performed on an interactive element",
"keywords": [
"storybook",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-backgrounds",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Switch backgrounds to view components in different settings",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-controls",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Interact with component inputs dynamically in the Storybook UI",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-docs",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Document component usage and properties in Markdown",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-essentials",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Curated addons to bring out the best of Storybook",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-mdx-gfm",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "GitHub Flavored Markdown in Storybook",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-highlight",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Highlight DOM nodes within your stories",
"keywords": [
"storybook-addons",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-interactions",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Automate, test and debug user interactions",
"keywords": [
"storybook-addons",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-jest",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "React storybook addon that show component jest report",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-links",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Link stories together to build demos and prototypes with your UI components",
"keywords": [
"storybook-addons",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-measure",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Inspect layouts by visualizing the box model",
"keywords": [
"storybook-addons",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-onboarding",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook Addon Onboarding - Introduces a new onboarding experience",
"keywords": [
"storybook-addons",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-outline",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Outline all elements with CSS to help with layout placement and alignment",
"keywords": [
"storybook-addons",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-storysource",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "View a storys source code to see how it works and paste into your app",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/experimental-addon-test",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Integrate Vitest with Storybook",
"keywords": [
"storybook-addons",

View File

@ -88,7 +88,7 @@ export default async function postInstall(options: PostinstallOptions) {
if (coercedVitestVersion && !satisfies(coercedVitestVersion, '>=2.1.0')) {
reasons.push(dedent`
The addon requires Vitest 2.1.0 or later. You are currently using ${picocolors.bold(vitestVersionSpecifier)}.
Please update your ${picocolors.bold(colors.pink('vitest'))} dependency and try again.
Please update all of your Vitest dependencies and try again.
`);
}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-themes",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Switch between multiple themes for you components in Storybook",
"keywords": [
"css",

View File

@ -5,6 +5,7 @@ const PACKAGE_MANAGER_TO_COMMAND = {
pnpm: ['pnpm', 'dlx'],
yarn1: ['npx'],
yarn2: ['yarn', 'dlx'],
bun: ['bunx'],
};
const selectPackageManagerCommand = (packageManager) => PACKAGE_MANAGER_TO_COMMAND[packageManager];

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-toolbars",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Create your own toolbar items that control story rendering",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-viewport",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Build responsive components by adjusting Storybooks viewport size and orientation",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/builder-vite",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "A plugin to run and build Storybooks with Vite",
"homepage": "https://github.com/storybookjs/storybook/tree/next/code/builders/builder-vite/#readme",
"bugs": {

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/builder-webpack5",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/core",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"

View File

@ -0,0 +1,332 @@
import { existsSync, readFileSync } from 'node:fs';
import { platform } from 'node:os';
import { join } from 'node:path';
import { logger } from '@storybook/core/node-logger';
import { FindPackageVersionsError } from '@storybook/core/server-errors';
import { findUp } from 'find-up';
import sort from 'semver/functions/sort.js';
import { dedent } from 'ts-dedent';
import { createLogStream } from '../utils/cli';
import { JsPackageManager } from './JsPackageManager';
import type { PackageJson } from './PackageJson';
import type { InstallationMetadata, PackageMetadata } from './types';
type NpmDependency = {
version: string;
resolved?: string;
overridden?: boolean;
dependencies?: NpmDependencies;
};
type NpmDependencies = {
[key: string]: NpmDependency;
};
export type NpmListOutput = {
dependencies: NpmDependencies;
};
const NPM_ERROR_REGEX = /npm ERR! code (\w+)/;
const NPM_ERROR_CODES = {
E401: 'Authentication failed or is required.',
E403: 'Access to the resource is forbidden.',
E404: 'Requested resource not found.',
EACCES: 'Permission issue.',
EAI_FAIL: 'DNS lookup failed.',
EBADENGINE: 'Engine compatibility check failed.',
EBADPLATFORM: 'Platform not supported.',
ECONNREFUSED: 'Connection refused.',
ECONNRESET: 'Connection reset.',
EEXIST: 'File or directory already exists.',
EINVALIDTYPE: 'Invalid type encountered.',
EISGIT: 'Git operation failed or conflicts with an existing file.',
EJSONPARSE: 'Error parsing JSON data.',
EMISSINGARG: 'Required argument missing.',
ENEEDAUTH: 'Authentication needed.',
ENOAUDIT: 'No audit available.',
ENOENT: 'File or directory does not exist.',
ENOGIT: 'Git not found or failed to run.',
ENOLOCK: 'Lockfile missing.',
ENOSPC: 'Insufficient disk space.',
ENOTFOUND: 'Resource not found.',
EOTP: 'One-time password required.',
EPERM: 'Permission error.',
EPUBLISHCONFLICT: 'Conflict during package publishing.',
ERESOLVE: 'Dependency resolution error.',
EROFS: 'File system is read-only.',
ERR_SOCKET_TIMEOUT: 'Socket timed out.',
ETARGET: 'Package target not found.',
ETIMEDOUT: 'Operation timed out.',
ETOOMANYARGS: 'Too many arguments provided.',
EUNKNOWNTYPE: 'Unknown type encountered.',
};
export class BUNProxy extends JsPackageManager {
readonly type = 'bun';
installArgs: string[] | undefined;
async initPackageJson() {
await this.executeCommand({ command: 'bun', args: ['init'] });
}
getRunStorybookCommand(): string {
return 'bun run storybook';
}
getRunCommand(command: string): string {
return `bun run ${command}`;
}
getRemoteRunCommand(): string {
return 'bunx';
}
public async getPackageJSON(
packageName: string,
basePath = this.cwd
): Promise<PackageJson | null> {
const packageJsonPath = await findUp(
(dir) => {
const possiblePath = join(dir, 'node_modules', packageName, 'package.json');
return existsSync(possiblePath) ? possiblePath : undefined;
},
{ cwd: basePath }
);
if (!packageJsonPath) {
return null;
}
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
return packageJson;
}
getInstallArgs(): string[] {
if (!this.installArgs) {
this.installArgs = [];
}
return this.installArgs;
}
public runPackageCommandSync(
command: string,
args: string[],
cwd?: string,
stdio?: 'pipe' | 'inherit'
): string {
return this.executeCommandSync({
command: 'bun',
args: ['run', command, ...args],
cwd,
stdio,
});
}
public async runPackageCommand(command: string, args: string[], cwd?: string): Promise<string> {
return this.executeCommand({
command: 'bun',
args: ['run', command, ...args],
cwd,
});
}
public async findInstallations(pattern: string[], { depth = 99 }: { depth?: number } = {}) {
const exec = async ({ packageDepth }: { packageDepth: number }) => {
const pipeToNull = platform() === 'win32' ? '2>NUL' : '2>/dev/null';
return this.executeCommand({
command: 'npm',
args: ['ls', '--json', `--depth=${packageDepth}`, pipeToNull],
env: {
FORCE_COLOR: 'false',
},
});
};
try {
const commandResult = await exec({ packageDepth: depth });
const parsedOutput = JSON.parse(commandResult);
return this.mapDependencies(parsedOutput, pattern);
} catch (e) {
// when --depth is higher than 0, npm can return a non-zero exit code
// in case the user's project has peer dependency issues. So we try again with no depth
try {
const commandResult = await exec({ packageDepth: 0 });
const parsedOutput = JSON.parse(commandResult);
return this.mapDependencies(parsedOutput, pattern);
} catch (err) {
logger.warn(`An issue occurred while trying to find dependencies metadata using npm.`);
return undefined;
}
}
}
protected getResolutions(packageJson: PackageJson, versions: Record<string, string>) {
return {
overrides: {
...packageJson.overrides,
...versions,
},
};
}
protected async runInstall() {
await this.executeCommand({
command: 'bun',
args: ['install', ...this.getInstallArgs()],
stdio: 'inherit',
});
}
public async getRegistryURL() {
const res = await this.executeCommand({
command: 'npm',
// "npm config" commands are not allowed in workspaces per default
// https://github.com/npm/cli/issues/6099#issuecomment-1847584792
args: ['config', 'get', 'registry', '-ws=false', '-iwr'],
});
const url = res.trim();
return url === 'undefined' ? undefined : url;
}
protected async runAddDeps(dependencies: string[], installAsDevDependencies: boolean) {
const { logStream, readLogFile, moveLogFile, removeLogFile } = await createLogStream();
let args = [...dependencies];
if (installAsDevDependencies) {
args = ['-D', ...args];
}
try {
await this.executeCommand({
command: 'bun',
args: ['add', ...args, ...this.getInstallArgs()],
stdio: process.env.CI ? 'inherit' : ['ignore', logStream, logStream],
});
} catch (err) {
const stdout = await readLogFile();
const errorMessage = this.parseErrorFromLogs(stdout);
await moveLogFile();
throw new Error(
dedent`${errorMessage}
Please check the logfile generated at ./storybook.log for troubleshooting and try again.`
);
}
await removeLogFile();
}
protected async runRemoveDeps(dependencies: string[]) {
const args = [...dependencies];
await this.executeCommand({
command: 'bun',
args: ['remove', ...args, ...this.getInstallArgs()],
stdio: 'inherit',
});
}
protected async runGetVersions<T extends boolean>(
packageName: string,
fetchAllVersions: T
): Promise<T extends true ? string[] : string> {
const args = [fetchAllVersions ? 'versions' : 'version', '--json'];
try {
const commandResult = await this.executeCommand({
command: 'npm',
args: ['info', packageName, ...args],
});
const parsedOutput = JSON.parse(commandResult);
if (parsedOutput.error?.summary) {
// this will be handled in the catch block below
throw parsedOutput.error.summary;
}
return parsedOutput;
} catch (error) {
throw new FindPackageVersionsError({
error,
packageManager: 'NPM',
packageName,
});
}
}
/**
* @param input The output of `npm ls --json`
* @param pattern A list of package names to filter the result. * can be used as a placeholder
*/
protected mapDependencies(input: NpmListOutput, pattern: string[]): InstallationMetadata {
const acc: Record<string, PackageMetadata[]> = {};
const existingVersions: Record<string, string[]> = {};
const duplicatedDependencies: Record<string, string[]> = {};
const recurse = ([name, packageInfo]: [string, NpmDependency]): void => {
// transform pattern into regex where `*` is replaced with `.*`
if (!name || !pattern.some((p) => new RegExp(`^${p.replace(/\*/g, '.*')}$`).test(name))) {
return;
}
const value = {
version: packageInfo.version,
location: '',
};
if (!existingVersions[name]?.includes(value.version)) {
if (acc[name]) {
acc[name].push(value);
} else {
acc[name] = [value];
}
existingVersions[name] = sort([...(existingVersions[name] || []), value.version]);
if (existingVersions[name].length > 1) {
duplicatedDependencies[name] = existingVersions[name];
}
}
if (packageInfo.dependencies) {
Object.entries(packageInfo.dependencies).forEach(recurse);
}
};
Object.entries(input.dependencies).forEach(recurse);
return {
dependencies: acc,
duplicatedDependencies,
infoCommand: 'npm ls --depth=1',
dedupeCommand: 'npm dedupe',
};
}
public parseErrorFromLogs(logs: string): string {
let finalMessage = 'NPM error';
const match = logs.match(NPM_ERROR_REGEX);
if (match) {
const errorCode = match[1] as keyof typeof NPM_ERROR_CODES;
if (errorCode) {
finalMessage = `${finalMessage} ${errorCode}`;
}
const errorMessage = NPM_ERROR_CODES[errorCode];
if (errorMessage) {
finalMessage = `${finalMessage} - ${errorMessage}`;
}
}
return finalMessage.trim();
}
}

View File

@ -16,7 +16,7 @@ import type { InstallationMetadata } from './types';
const logger = console;
export type PackageManagerName = 'npm' | 'yarn1' | 'yarn2' | 'pnpm';
export type PackageManagerName = 'npm' | 'yarn1' | 'yarn2' | 'pnpm' | 'bun';
type StorybookPackage = keyof typeof storybookPackagesVersions;

View File

@ -5,6 +5,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
import { sync as spawnSync } from 'cross-spawn';
import { findUpSync } from 'find-up';
import { BUNProxy } from './BUNProxy';
import { JsPackageManagerFactory } from './JsPackageManagerFactory';
import { NPMProxy } from './NPMProxy';
import { PNPMProxy } from './PNPMProxy';
@ -354,6 +355,91 @@ describe('CLASS: JsPackageManagerFactory', () => {
});
});
describe('Yarn 2 proxy', () => {
it('FORCE: it should return a Yarn2 proxy when `force` option is `yarn2`', () => {
expect(JsPackageManagerFactory.getPackageManager({ force: 'yarn2' })).toBeInstanceOf(
Yarn2Proxy
);
});
it('USER AGENT: it should infer yarn2 from the user agent', () => {
process.env.npm_config_user_agent = 'yarn/2.2.10';
expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn2Proxy);
});
it('ONLY YARN 2: when Yarn command is ok, Yarn version is >=2, NPM is ko, PNPM is ko', () => {
spawnSyncMock.mockImplementation((command) => {
// Yarn is ok
if (command === 'yarn') {
return {
status: 0,
output: '2.0.0-rc.33',
};
}
// NPM is ko
if (command === 'npm') {
return {
status: 1,
};
}
// PNPM is ko
if (command === 'pnpm') {
return {
status: 1,
};
}
// Unknown package manager is ko
return {
status: 1,
} as any;
});
expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn2Proxy);
});
it('when Yarn command is ok, Yarn version is >=2, NPM and PNPM are ok, there is a `yarn.lock` file', () => {
spawnSyncMock.mockImplementation((command) => {
// Yarn is ok
if (command === 'yarn') {
return {
status: 0,
output: '2.0.0-rc.33',
};
}
// NPM is ok
if (command === 'npm') {
return {
status: 0,
output: '6.5.12',
};
}
// PNPM is ok
if (command === 'pnpm') {
return {
status: 0,
output: '7.9.5',
};
}
if (command === 'bun') {
return {
status: 0,
output: '1.0.0',
};
}
// Unknown package manager is ko
return {
status: 1,
} as any;
});
// There is a yarn.lock
findUpSyncMock.mockImplementation(() => '/Users/johndoe/Documents/bun.lockb');
expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(BUNProxy);
});
});
it('throws an error if Yarn, NPM, and PNPM are not found', () => {
spawnSyncMock.mockReturnValue({ status: 1 } as any);
expect(() => JsPackageManagerFactory.getPackageManager()).toThrow();

View File

@ -3,6 +3,7 @@ import { basename, parse, relative } from 'node:path';
import { sync as spawnSync } from 'cross-spawn';
import { findUpSync } from 'find-up';
import { BUNProxy } from './BUNProxy';
import type { JsPackageManager, PackageManagerName } from './JsPackageManager';
import { NPMProxy } from './NPMProxy';
import { PNPMProxy } from './PNPMProxy';
@ -12,12 +13,14 @@ import { Yarn2Proxy } from './Yarn2Proxy';
const NPM_LOCKFILE = 'package-lock.json';
const PNPM_LOCKFILE = 'pnpm-lock.yaml';
const YARN_LOCKFILE = 'yarn.lock';
const BUN_LOCKFILE = 'bun.lockb';
type PackageManagerProxy =
| typeof NPMProxy
| typeof PNPMProxy
| typeof Yarn1Proxy
| typeof Yarn2Proxy;
| typeof Yarn2Proxy
| typeof BUNProxy;
export class JsPackageManagerFactory {
public static getPackageManager(
@ -33,6 +36,7 @@ export class JsPackageManagerFactory {
findUpSync(YARN_LOCKFILE, { cwd }),
findUpSync(PNPM_LOCKFILE, { cwd }),
findUpSync(NPM_LOCKFILE, { cwd }),
findUpSync(BUN_LOCKFILE, { cwd }),
]
.filter(Boolean)
.sort((a, b) => {
@ -59,6 +63,7 @@ export class JsPackageManagerFactory {
const hasNPMCommand = hasNPM(cwd);
const hasPNPMCommand = hasPNPM(cwd);
const hasBunCommand = hasBun(cwd);
const yarnVersion = getYarnVersion(cwd);
if (yarnVersion && (closestLockfile === YARN_LOCKFILE || (!hasNPMCommand && !hasPNPMCommand))) {
@ -73,6 +78,10 @@ export class JsPackageManagerFactory {
return new NPMProxy({ cwd });
}
if (hasBunCommand && closestLockfile === BUN_LOCKFILE) {
return new BUNProxy({ cwd });
}
// Option 3: If the user is running a command via npx/pnpx/yarn create/etc, we infer the package manager from the command
const inferredPackageManager = this.inferPackageManagerFromUserAgent();
if (inferredPackageManager && inferredPackageManager in this.PROXY_MAP) {
@ -94,6 +103,7 @@ export class JsPackageManagerFactory {
pnpm: PNPMProxy,
yarn1: Yarn1Proxy,
yarn2: Yarn2Proxy,
bun: BUNProxy,
};
/**
@ -136,6 +146,18 @@ function hasNPM(cwd?: string) {
return npmVersionCommand.status === 0;
}
function hasBun(cwd?: string) {
const pnpmVersionCommand = spawnSync('bun', ['--version'], {
cwd,
shell: true,
env: {
...process.env,
COREPACK_ENABLE_STRICT: '0',
},
});
return pnpmVersionCommand.status === 0;
}
function hasPNPM(cwd?: string) {
const pnpmVersionCommand = spawnSync('pnpm', ['--version'], {
cwd,

View File

@ -85,10 +85,6 @@ export class NPMProxy extends JsPackageManager {
return 'npx';
}
async getNpmVersion(): Promise<string> {
return this.executeCommand({ command: 'npm', args: ['--version'] });
}
public async getPackageJSON(
packageName: string,
basePath = this.cwd

View File

@ -85,6 +85,7 @@ export class FileSystemCache {
orgOpts: CacheSetOptions | number = {}
): Promise<void> {
const opts: CacheSetOptions = typeof orgOpts === 'number' ? { ttl: orgOpts } : orgOpts;
mkdirSync(this.cache_dir, { recursive: true });
await writeFile(this.generateHash(name), this.parseSetData(name, data, opts), {
encoding: opts.encoding || 'utf8',
});
@ -92,6 +93,7 @@ export class FileSystemCache {
public setSync<T>(name: string, data: T, orgOpts: CacheSetOptions | number = {}): void {
const opts: CacheSetOptions = typeof orgOpts === 'number' ? { ttl: orgOpts } : orgOpts;
mkdirSync(this.cache_dir, { recursive: true });
writeFileSync(this.generateHash(name), this.parseSetData(name, data, opts), {
encoding: opts.encoding || 'utf8',
});

View File

@ -1,87 +1,87 @@
// auto generated file, do not edit
export default {
'@storybook/addon-a11y': '8.4.0-beta.3',
'@storybook/addon-actions': '8.4.0-beta.3',
'@storybook/addon-backgrounds': '8.4.0-beta.3',
'@storybook/addon-controls': '8.4.0-beta.3',
'@storybook/addon-docs': '8.4.0-beta.3',
'@storybook/addon-essentials': '8.4.0-beta.3',
'@storybook/addon-mdx-gfm': '8.4.0-beta.3',
'@storybook/addon-highlight': '8.4.0-beta.3',
'@storybook/addon-interactions': '8.4.0-beta.3',
'@storybook/addon-jest': '8.4.0-beta.3',
'@storybook/addon-links': '8.4.0-beta.3',
'@storybook/addon-measure': '8.4.0-beta.3',
'@storybook/addon-onboarding': '8.4.0-beta.3',
'@storybook/addon-outline': '8.4.0-beta.3',
'@storybook/addon-storysource': '8.4.0-beta.3',
'@storybook/experimental-addon-test': '8.4.0-beta.3',
'@storybook/addon-themes': '8.4.0-beta.3',
'@storybook/addon-toolbars': '8.4.0-beta.3',
'@storybook/addon-viewport': '8.4.0-beta.3',
'@storybook/builder-vite': '8.4.0-beta.3',
'@storybook/builder-webpack5': '8.4.0-beta.3',
'@storybook/core': '8.4.0-beta.3',
'@storybook/builder-manager': '8.4.0-beta.3',
'@storybook/channels': '8.4.0-beta.3',
'@storybook/client-logger': '8.4.0-beta.3',
'@storybook/components': '8.4.0-beta.3',
'@storybook/core-common': '8.4.0-beta.3',
'@storybook/core-events': '8.4.0-beta.3',
'@storybook/core-server': '8.4.0-beta.3',
'@storybook/csf-tools': '8.4.0-beta.3',
'@storybook/docs-tools': '8.4.0-beta.3',
'@storybook/manager': '8.4.0-beta.3',
'@storybook/manager-api': '8.4.0-beta.3',
'@storybook/node-logger': '8.4.0-beta.3',
'@storybook/preview': '8.4.0-beta.3',
'@storybook/preview-api': '8.4.0-beta.3',
'@storybook/router': '8.4.0-beta.3',
'@storybook/telemetry': '8.4.0-beta.3',
'@storybook/theming': '8.4.0-beta.3',
'@storybook/types': '8.4.0-beta.3',
'@storybook/angular': '8.4.0-beta.3',
'@storybook/ember': '8.4.0-beta.3',
'@storybook/experimental-nextjs-vite': '8.4.0-beta.3',
'@storybook/html-vite': '8.4.0-beta.3',
'@storybook/html-webpack5': '8.4.0-beta.3',
'@storybook/nextjs': '8.4.0-beta.3',
'@storybook/preact-vite': '8.4.0-beta.3',
'@storybook/preact-webpack5': '8.4.0-beta.3',
'@storybook/react-vite': '8.4.0-beta.3',
'@storybook/react-webpack5': '8.4.0-beta.3',
'@storybook/server-webpack5': '8.4.0-beta.3',
'@storybook/svelte-vite': '8.4.0-beta.3',
'@storybook/svelte-webpack5': '8.4.0-beta.3',
'@storybook/sveltekit': '8.4.0-beta.3',
'@storybook/vue3-vite': '8.4.0-beta.3',
'@storybook/vue3-webpack5': '8.4.0-beta.3',
'@storybook/web-components-vite': '8.4.0-beta.3',
'@storybook/web-components-webpack5': '8.4.0-beta.3',
'@storybook/blocks': '8.4.0-beta.3',
storybook: '8.4.0-beta.3',
sb: '8.4.0-beta.3',
'@storybook/cli': '8.4.0-beta.3',
'@storybook/codemod': '8.4.0-beta.3',
'@storybook/core-webpack': '8.4.0-beta.3',
'create-storybook': '8.4.0-beta.3',
'@storybook/csf-plugin': '8.4.0-beta.3',
'@storybook/instrumenter': '8.4.0-beta.3',
'@storybook/react-dom-shim': '8.4.0-beta.3',
'@storybook/source-loader': '8.4.0-beta.3',
'@storybook/test': '8.4.0-beta.3',
'@storybook/preset-create-react-app': '8.4.0-beta.3',
'@storybook/preset-html-webpack': '8.4.0-beta.3',
'@storybook/preset-preact-webpack': '8.4.0-beta.3',
'@storybook/preset-react-webpack': '8.4.0-beta.3',
'@storybook/preset-server-webpack': '8.4.0-beta.3',
'@storybook/preset-svelte-webpack': '8.4.0-beta.3',
'@storybook/preset-vue3-webpack': '8.4.0-beta.3',
'@storybook/html': '8.4.0-beta.3',
'@storybook/preact': '8.4.0-beta.3',
'@storybook/react': '8.4.0-beta.3',
'@storybook/server': '8.4.0-beta.3',
'@storybook/svelte': '8.4.0-beta.3',
'@storybook/vue3': '8.4.0-beta.3',
'@storybook/web-components': '8.4.0-beta.3',
'@storybook/addon-a11y': '8.5.0-alpha.2',
'@storybook/addon-actions': '8.5.0-alpha.2',
'@storybook/addon-backgrounds': '8.5.0-alpha.2',
'@storybook/addon-controls': '8.5.0-alpha.2',
'@storybook/addon-docs': '8.5.0-alpha.2',
'@storybook/addon-essentials': '8.5.0-alpha.2',
'@storybook/addon-mdx-gfm': '8.5.0-alpha.2',
'@storybook/addon-highlight': '8.5.0-alpha.2',
'@storybook/addon-interactions': '8.5.0-alpha.2',
'@storybook/addon-jest': '8.5.0-alpha.2',
'@storybook/addon-links': '8.5.0-alpha.2',
'@storybook/addon-measure': '8.5.0-alpha.2',
'@storybook/addon-onboarding': '8.5.0-alpha.2',
'@storybook/addon-outline': '8.5.0-alpha.2',
'@storybook/addon-storysource': '8.5.0-alpha.2',
'@storybook/experimental-addon-test': '8.5.0-alpha.2',
'@storybook/addon-themes': '8.5.0-alpha.2',
'@storybook/addon-toolbars': '8.5.0-alpha.2',
'@storybook/addon-viewport': '8.5.0-alpha.2',
'@storybook/builder-vite': '8.5.0-alpha.2',
'@storybook/builder-webpack5': '8.5.0-alpha.2',
'@storybook/core': '8.5.0-alpha.2',
'@storybook/builder-manager': '8.5.0-alpha.2',
'@storybook/channels': '8.5.0-alpha.2',
'@storybook/client-logger': '8.5.0-alpha.2',
'@storybook/components': '8.5.0-alpha.2',
'@storybook/core-common': '8.5.0-alpha.2',
'@storybook/core-events': '8.5.0-alpha.2',
'@storybook/core-server': '8.5.0-alpha.2',
'@storybook/csf-tools': '8.5.0-alpha.2',
'@storybook/docs-tools': '8.5.0-alpha.2',
'@storybook/manager': '8.5.0-alpha.2',
'@storybook/manager-api': '8.5.0-alpha.2',
'@storybook/node-logger': '8.5.0-alpha.2',
'@storybook/preview': '8.5.0-alpha.2',
'@storybook/preview-api': '8.5.0-alpha.2',
'@storybook/router': '8.5.0-alpha.2',
'@storybook/telemetry': '8.5.0-alpha.2',
'@storybook/theming': '8.5.0-alpha.2',
'@storybook/types': '8.5.0-alpha.2',
'@storybook/angular': '8.5.0-alpha.2',
'@storybook/ember': '8.5.0-alpha.2',
'@storybook/experimental-nextjs-vite': '8.5.0-alpha.2',
'@storybook/html-vite': '8.5.0-alpha.2',
'@storybook/html-webpack5': '8.5.0-alpha.2',
'@storybook/nextjs': '8.5.0-alpha.2',
'@storybook/preact-vite': '8.5.0-alpha.2',
'@storybook/preact-webpack5': '8.5.0-alpha.2',
'@storybook/react-vite': '8.5.0-alpha.2',
'@storybook/react-webpack5': '8.5.0-alpha.2',
'@storybook/server-webpack5': '8.5.0-alpha.2',
'@storybook/svelte-vite': '8.5.0-alpha.2',
'@storybook/svelte-webpack5': '8.5.0-alpha.2',
'@storybook/sveltekit': '8.5.0-alpha.2',
'@storybook/vue3-vite': '8.5.0-alpha.2',
'@storybook/vue3-webpack5': '8.5.0-alpha.2',
'@storybook/web-components-vite': '8.5.0-alpha.2',
'@storybook/web-components-webpack5': '8.5.0-alpha.2',
'@storybook/blocks': '8.5.0-alpha.2',
storybook: '8.5.0-alpha.2',
sb: '8.5.0-alpha.2',
'@storybook/cli': '8.5.0-alpha.2',
'@storybook/codemod': '8.5.0-alpha.2',
'@storybook/core-webpack': '8.5.0-alpha.2',
'create-storybook': '8.5.0-alpha.2',
'@storybook/csf-plugin': '8.5.0-alpha.2',
'@storybook/instrumenter': '8.5.0-alpha.2',
'@storybook/react-dom-shim': '8.5.0-alpha.2',
'@storybook/source-loader': '8.5.0-alpha.2',
'@storybook/test': '8.5.0-alpha.2',
'@storybook/preset-create-react-app': '8.5.0-alpha.2',
'@storybook/preset-html-webpack': '8.5.0-alpha.2',
'@storybook/preset-preact-webpack': '8.5.0-alpha.2',
'@storybook/preset-react-webpack': '8.5.0-alpha.2',
'@storybook/preset-server-webpack': '8.5.0-alpha.2',
'@storybook/preset-svelte-webpack': '8.5.0-alpha.2',
'@storybook/preset-vue3-webpack': '8.5.0-alpha.2',
'@storybook/html': '8.5.0-alpha.2',
'@storybook/preact': '8.5.0-alpha.2',
'@storybook/react': '8.5.0-alpha.2',
'@storybook/server': '8.5.0-alpha.2',
'@storybook/svelte': '8.5.0-alpha.2',
'@storybook/vue3': '8.5.0-alpha.2',
'@storybook/web-components': '8.5.0-alpha.2',
};

View File

@ -123,6 +123,7 @@ const Item = styled.div<ItemProps>(
({ theme }) => ({
width: '100%',
border: 'none',
borderRadius: theme.appBorderRadius,
background: 'none',
fontSize: theme.typography.size.s1,
transition: 'all 150ms ease-out',

View File

@ -109,7 +109,7 @@ const Wrapper = styled.div<WrapperProps>(
drop-shadow(0px 5px 5px rgba(0,0,0,0.05))
drop-shadow(0 1px 3px rgba(0,0,0,0.1))
`,
borderRadius: theme.appBorderRadius,
borderRadius: theme.appBorderRadius + 2,
fontSize: theme.typography.size.s1,
}
: {}

View File

@ -191,3 +191,45 @@ export const WithCustomIcon = {
],
},
} satisfies Story;
export const WithGroups = {
args: {
links: [
[
{
id: '1',
title: 'Link 1',
center: 'This is an addition description',
href: 'http://google.com',
onClick: onLinkClick,
},
],
[
{
id: '1',
title: 'Link 1',
center: 'This is an addition description',
icon: <LinkIcon />,
href: 'http://google.com',
onClick: onLinkClick,
},
{
id: '2',
title: 'Link 2',
center: 'This is an addition description',
href: 'http://google.com',
onClick: onLinkClick,
},
],
[
{
id: '2',
title: 'Link 2',
center: 'This is an addition description',
href: 'http://google.com',
onClick: onLinkClick,
},
],
],
},
} satisfies Story;

View File

@ -11,13 +11,20 @@ const List = styled.div(
minWidth: 180,
overflow: 'hidden',
overflowY: 'auto',
maxHeight: 15.5 * 32, // 11.5 items
maxHeight: 15.5 * 32 + 8, // 15.5 items at 32px each + 8px padding
},
({ theme }) => ({
borderRadius: theme.appBorderRadius,
borderRadius: theme.appBorderRadius + 2,
})
);
const Group = styled.div(({ theme }) => ({
padding: 4,
'& + &': {
borderTop: `1px solid ${theme.appBorderColor}`,
},
}));
export interface Link extends Omit<ListItemProps, 'onClick'> {
id: string;
onClick?: (
@ -42,17 +49,26 @@ const Item = ({ id, onClick, ...rest }: ItemProps) => {
};
export interface TooltipLinkListProps extends ComponentProps<typeof List> {
links: Link[];
links: Link[] | Link[][];
LinkWrapper?: LinkWrapperType;
}
export const TooltipLinkList = ({ links, LinkWrapper, ...props }: TooltipLinkListProps) => {
const isIndented = links.some((link) => link.icon);
const groups = Array.isArray(links[0]) ? (links as Link[][]) : [links as Link[]];
const isIndented = groups.some((group) => group.some((link) => link.icon));
return (
<List {...props}>
{links.map((link) => (
<Item key={link.id} isIndented={isIndented} LinkWrapper={LinkWrapper} {...link} />
))}
{groups
.filter((group) => group.length)
.map((group, index) => {
return (
<Group key={group.map((link) => link.id).join(`~${index}~`)}>
{group.map((link) => (
<Item key={link.id} isIndented={isIndented} LinkWrapper={LinkWrapper} {...link} />
))}
</Group>
);
})}
</List>
);
};

View File

@ -1 +1 @@
export const version = '8.4.0-beta.3';
export const version = '8.5.0-alpha.2';

View File

@ -8,9 +8,10 @@ import { CloseIcon, CogIcon } from '@storybook/icons';
import { transparentize } from 'polished';
import type { useMenu } from '../../container/Menu';
import { useLayout } from '../layout/LayoutProvider';
export type MenuList = ComponentProps<typeof TooltipLinkList>['links'];
export type MenuList = ReturnType<typeof useMenu>;
export const SidebarIconButton: FC<ComponentProps<typeof Button> & { highlighted: boolean }> =
styled(IconButton)<
@ -60,17 +61,21 @@ const SidebarMenuList: FC<{
menu: MenuList;
onHide: () => void;
}> = ({ menu, onHide }) => {
const links = useMemo(() => {
return menu.map(({ onClick, ...rest }) => ({
...rest,
onClick: ((event, item) => {
if (onClick) {
onClick(event, item);
}
onHide();
}) as ClickHandler,
}));
}, [menu, onHide]);
const links = useMemo(
() =>
menu.map((group) =>
group.map(({ onClick, ...rest }) => ({
...rest,
onClick: ((event, item) => {
if (onClick) {
onClick(event, item);
}
onHide();
}) as ClickHandler,
}))
),
[menu, onHide]
);
return <TooltipLinkList links={links} />;
};

View File

@ -85,6 +85,7 @@ const meta = {
refs: {},
status: {},
showCreateStoryButton: true,
isDevelopment: true,
},
decorators: [
(storyFn) => (

View File

@ -109,7 +109,6 @@ const useCombination = (
return useMemo(() => ({ hash, entries: Object.entries(hash) }), [hash]);
};
const isDevelopment = global.CONFIG_TYPE === 'DEVELOPMENT';
const isRendererReact = global.STORYBOOK_RENDERER === 'react';
export interface SidebarProps extends API_LoadedRefData {
@ -124,6 +123,7 @@ export interface SidebarProps extends API_LoadedRefData {
onMenuClick?: HeadingProps['onMenuClick'];
showCreateStoryButton?: boolean;
indexJson?: StoryIndex;
isDevelopment?: boolean;
}
export const Sidebar = React.memo(function Sidebar({
// @ts-expect-error (non strict)
@ -138,6 +138,7 @@ export const Sidebar = React.memo(function Sidebar({
extra,
menuHighlighted = false,
enableShortcuts = true,
isDevelopment = global.CONFIG_TYPE === 'DEVELOPMENT',
refs = {},
onMenuClick,
showCreateStoryButton = isDevelopment && isRendererReact,
@ -229,7 +230,7 @@ export const Sidebar = React.memo(function Sidebar({
)}
</Search>
</Top>
{isMobile || isLoading ? null : <SidebarBottom />}
{isMobile || isLoading ? null : <SidebarBottom isDevelopment={isDevelopment} />}
</ScrollArea>
</Container>
);

View File

@ -6,6 +6,7 @@ import { SidebarBottomBase } from './SidebarBottom';
export default {
component: SidebarBottomBase,
args: {
isDevelopment: true,
api: {
clearNotification: fn(),
emit: fn(),

View File

@ -92,9 +92,15 @@ interface SidebarBottomProps {
api: API;
notifications: State['notifications'];
status: State['status'];
isDevelopment?: boolean;
}
export const SidebarBottomBase = ({ api, notifications = [], status = {} }: SidebarBottomProps) => {
export const SidebarBottomBase = ({
api,
notifications = [],
status = {},
isDevelopment,
}: SidebarBottomProps) => {
const spacerRef = useRef<HTMLDivElement | null>(null);
const wrapperRef = useRef<HTMLDivElement | null>(null);
const [warningsActive, setWarningsActive] = useState(false);
@ -228,27 +234,36 @@ export const SidebarBottomBase = ({ api, notifications = [], status = {} }: Side
<div id={SIDEBAR_BOTTOM_SPACER_ID} ref={spacerRef}>
<Content id={SIDEBAR_BOTTOM_WRAPPER_ID} ref={wrapperRef}>
<NotificationList notifications={notifications} clearNotification={api.clearNotification} />
<TestingModule
{...{
testProviders: testProvidersArray,
errorCount: errors.length,
errorsActive,
setErrorsActive,
warningCount: warnings.length,
warningsActive,
setWarningsActive,
onRunTests,
onCancelTests,
onSetWatchMode,
}}
/>
{isDevelopment && (
<TestingModule
{...{
testProviders: testProvidersArray,
errorCount: errors.length,
errorsActive,
setErrorsActive,
warningCount: warnings.length,
warningsActive,
setWarningsActive,
onRunTests,
onCancelTests,
onSetWatchMode,
}}
/>
)}
</Content>
</div>
);
};
export const SidebarBottom = () => {
export const SidebarBottom = ({ isDevelopment }: { isDevelopment?: boolean }) => {
const api = useStorybookApi();
const { notifications, status } = useStorybookState();
return <SidebarBottomBase api={api} notifications={notifications} status={status} />;
return (
<SidebarBottomBase
api={api}
notifications={notifications}
status={status}
isDevelopment={isDevelopment}
/>
);
};

View File

@ -7,6 +7,8 @@ import type { Tag } from '@storybook/types';
import type { API } from '@storybook/core/manager-api';
import type { Link } from '../../../components/components/tooltip/TooltipLinkList';
const BUILT_IN_TAGS_SHOW = new Set(['play-fn']);
const Wrapper = styled.div({
@ -29,56 +31,60 @@ export const TagsFilterPanel = ({
toggleTag,
isDevelopment,
}: TagsFilterPanelProps) => {
const theme = useTheme();
const userTags = allTags.filter((tag) => !BUILT_IN_TAGS_SHOW.has(tag));
const docsUrl = api.getDocsUrl({ subpath: 'writing-stories/tags#filtering-by-custom-tags' });
const items = allTags.map((tag) => {
const checked = selectedTags.includes(tag);
const id = `tag-${tag}`;
return {
id,
title: tag,
right: (
<input
type="checkbox"
id={id}
name={id}
value={tag}
checked={checked}
onChange={() => {
// The onClick handler higher up the tree will handle the toggle
// For controlled inputs, a onClick handler is needed, though
// Accessibility-wise this isn't optimal, but I guess that's a limitation
// of the current design of TooltipLinkList
}}
/>
),
onClick: () => toggleTag(tag),
};
}) as any[];
const groups = [
allTags.map((tag) => {
const checked = selectedTags.includes(tag);
const id = `tag-${tag}`;
return {
id,
title: tag,
right: (
<input
type="checkbox"
id={id}
name={id}
value={tag}
checked={checked}
onChange={() => {
// The onClick handler higher up the tree will handle the toggle
// For controlled inputs, a onClick handler is needed, though
// Accessibility-wise this isn't optimal, but I guess that's a limitation
// of the current design of TooltipLinkList
}}
/>
),
onClick: () => toggleTag(tag),
};
}),
] as Link[][];
if (allTags.length === 0) {
items.push({
id: 'no-tags',
title: 'There are no tags. Use tags to organize and filter your Storybook.',
isIndented: false,
});
}
if (userTags.length === 0 && isDevelopment) {
items.push({
id: 'tags-docs',
title: 'Learn how to add tags',
icon: <ShareAltIcon />,
href: docsUrl,
style: {
borderTop: `4px solid ${theme.appBorderColor}`,
groups.push([
{
id: 'no-tags',
title: 'There are no tags. Use tags to organize and filter your Storybook.',
isIndented: false,
},
});
]);
}
if (userTags.length === 0 && isDevelopment) {
groups.push([
{
id: 'tags-docs',
title: 'Learn how to add tags',
icon: <ShareAltIcon />,
href: docsUrl,
},
]);
}
return (
<Wrapper>
<TooltipLinkList links={items} />
<TooltipLinkList links={groups} />
</Wrapper>
);
};

View File

@ -229,7 +229,12 @@ export const TestingModule = ({
const testing = testProviders.length > 0;
return (
<Outline running={running} crashed={crashed} failed={failed || errorCount > 0}>
<Outline
id="storybook-testing-module"
running={running}
crashed={crashed}
failed={failed || errorCount > 0}
>
<Card>
<Collapsible
style={{

View File

@ -9,6 +9,8 @@ import { STORIES_COLLAPSE_ALL } from '@storybook/core/core-events';
import type { API, State } from '@storybook/core/manager-api';
import { shortcutToHumanString } from '@storybook/core/manager-api';
import type { Link } from '../../components/components/tooltip/TooltipLinkList';
const focusableUIElements = {
storySearchField: 'storybook-explorer-searchfield',
storyListMenu: 'storybook-explorer-menu',
@ -58,8 +60,7 @@ export const useMenu = (
isPanelShown: boolean,
isNavShown: boolean,
enableShortcuts: boolean
) => {
const theme = useTheme();
): Link[][] => {
const shortcutKeys = api.getShortcutKeys();
const about = useMemo(
@ -105,11 +106,8 @@ export const useMenu = (
title: 'Keyboard shortcuts',
onClick: () => api.changeSettingsTab('shortcuts'),
right: enableShortcuts ? <Shortcut keys={shortcutKeys.shortcutsPage} /> : null,
style: {
borderBottom: `4px solid ${theme.appBorderColor}`,
},
}),
[api, enableShortcuts, shortcutKeys.shortcutsPage, theme.appBorderColor]
[api, enableShortcuts, shortcutKeys.shortcutsPage]
);
const sidebarToggle = useMemo(
@ -244,24 +242,29 @@ export const useMenu = (
}, [api, enableShortcuts, shortcutKeys]);
return useMemo(
() => [
about,
...(state.whatsNewData?.status === 'SUCCESS' ? [whatsNew] : []),
documentation,
shortcuts,
sidebarToggle,
toolbarToogle,
addonsToggle,
addonsOrientationToggle,
fullscreenToggle,
searchToggle,
up,
down,
prev,
next,
collapse,
...getAddonsShortcuts(),
],
() =>
[
[
about,
...(state.whatsNewData?.status === 'SUCCESS' ? [whatsNew] : []),
documentation,
shortcuts,
],
[
sidebarToggle,
toolbarToogle,
addonsToggle,
addonsOrientationToggle,
fullscreenToggle,
searchToggle,
up,
down,
prev,
next,
collapse,
],
getAddonsShortcuts(),
] satisfies Link[][],
[
about,
state,

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/builder-manager",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook manager builder",
"keywords": [
"storybook"
@ -39,7 +39,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/channels",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "",
"keywords": [
"storybook"
@ -39,7 +39,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/client-logger",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "",
"keywords": [
"storybook"
@ -39,7 +39,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/components",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Core Storybook Components",
"keywords": [
"storybook"
@ -39,7 +39,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/core-common",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"
@ -38,7 +38,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/core-events",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Event names used in storybook core",
"keywords": [
"storybook"
@ -70,7 +70,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/core-server",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"
@ -39,7 +39,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/csf-tools",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Parse and manipulate CSF and Storybook config files",
"keywords": [
"storybook"
@ -38,7 +38,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/docs-tools",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Shared utility functions for frameworks to implement docs",
"keywords": [
"storybook"
@ -39,7 +39,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/manager-api",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Core Storybook Manager API & Context",
"keywords": [
"storybook"
@ -38,7 +38,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/manager",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Core Storybook UI",
"keywords": [
"storybook"
@ -36,7 +36,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/node-logger",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "",
"keywords": [
"storybook"
@ -39,7 +39,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/preview-api",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "",
"keywords": [
"storybook"
@ -40,7 +40,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/preview",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "",
"keywords": [
"storybook"
@ -36,7 +36,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/router",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Core Storybook Router",
"keywords": [
"storybook"
@ -44,7 +44,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/telemetry",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Telemetry logging for crash reports and usage statistics",
"keywords": [
"storybook"
@ -39,7 +39,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/theming",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Core Storybook Components",
"keywords": [
"storybook"
@ -44,7 +44,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/types",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Core Storybook TS Types",
"keywords": [
"storybook"
@ -39,7 +39,7 @@
"*.d.ts"
],
"peerDependencies": {
"storybook": "workspace:^"
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
},
"publishConfig": {
"access": "public"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/angular",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.",
"keywords": [
"storybook",
@ -38,12 +38,12 @@
},
"dependencies": {
"@storybook/builder-webpack5": "workspace:*",
"@storybook/components": "workspace:^",
"@storybook/components": "workspace:*",
"@storybook/core-webpack": "workspace:*",
"@storybook/global": "^5.0.0",
"@storybook/manager-api": "workspace:^",
"@storybook/preview-api": "workspace:^",
"@storybook/theming": "workspace:^",
"@storybook/manager-api": "workspace:*",
"@storybook/preview-api": "workspace:*",
"@storybook/theming": "workspace:*",
"@types/node": "^22.0.0",
"@types/react": "^18.0.37",
"@types/react-dom": "^18.0.11",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/ember",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.",
"homepage": "https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember",
"bugs": {

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/experimental-nextjs-vite",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Next.js and Vite",
"keywords": [
"storybook",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/html-vite",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for HTML and Vite: Develop HTML in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/html-webpack5",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/nextjs",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Next.js",
"keywords": [
"storybook",
@ -156,7 +156,7 @@
"postcss-loader": "^8.1.1",
"react-refresh": "^0.14.0",
"resolve-url-loader": "^5.0.0",
"sass-loader": "^13.2.0",
"sass-loader": "^14.2.1",
"semver": "^7.3.5",
"style-loader": "^3.3.1",
"styled-jsx": "^5.1.6",

View File

@ -36,16 +36,16 @@ export const configureConfig = async ({
addScopedAlias(baseConfig, 'react', 'next/dist/compiled/react');
}
if (tryResolve('next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js')) {
setAlias(
addScopedAlias(
baseConfig,
'react-dom/test-utils',
'next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js'
);
}
if (tryResolve('next/dist/compiled/react-dom')) {
setAlias(baseConfig, 'react-dom$', 'next/dist/compiled/react-dom');
setAlias(baseConfig, 'react-dom/client', 'next/dist/compiled/react-dom/client');
setAlias(baseConfig, 'react-dom/server', 'next/dist/compiled/react-dom/server');
addScopedAlias(baseConfig, 'react-dom$', 'next/dist/compiled/react-dom');
addScopedAlias(baseConfig, 'react-dom/client', 'next/dist/compiled/react-dom/client');
addScopedAlias(baseConfig, 'react-dom/server', 'next/dist/compiled/react-dom/server');
}
setupRuntimeConfig(baseConfig, nextConfig);

View File

@ -51,18 +51,36 @@ export const addScopedAlias = (baseConfig: WebpackConfig, name: string, alias?:
};
/**
* @example // before main script path truncation require.resolve('styled-jsx') ===
* '/some/path/node_modules/styled-jsx/index.js // after main script path truncation
* scopedResolve('styled-jsx') === '/some/path/node_modules/styled-jsx'
* @example
*
* @param id The module id
* @returns A path to the module id scoped to the project folder without the main script path at the
* end
* ```
* // before main script path truncation
* require.resolve('styled-jsx') === '/some/path/node_modules/styled-jsx/index.js
* // after main script path truncation
* scopedResolve('styled-jsx') === '/some/path/node_modules/styled-jsx'
* ```
*
* @example
*
* ```
* // referencing a named export of a package
* scopedResolve('next/dist/compiled/react-dom/client') ===
* // returns the path to the package export without the script filename
* '/some/path/node_modules/next/dist/compiled/react-dom/client';
*
* // referencing a specific file within a CJS package
* scopedResolve('next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js') ===
* // returns the path to the physical file, including the script filename
* '/some/path/node_modules/next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js';
* ```
*
* @param id The module id or script file to resolve
* @returns An absolute path to the specified module id or script file scoped to the project folder
* @summary
* This is to help the addon in development.
* Without it, the addon resolves packages in its node_modules instead of the example's node_modules.
* Because require.resolve will also include the main script as part of the path, this function strips
* that to just include the path to the module folder
* that to just include the path to the module folder when the id provided is a package or named export.
*/
export const scopedResolve = (id: string): string => {
let scopedModulePath;
@ -74,9 +92,15 @@ export const scopedResolve = (id: string): string => {
scopedModulePath = require.resolve(id);
}
const moduleFolderStrPosition = scopedModulePath.lastIndexOf(
id.replace(/\//g /* all '/' occurances */, sep)
);
const idWithNativePathSep = id.replace(/\//g /* all '/' occurrences */, sep);
// If the id referenced the file specifically, return the full module path & filename
if (scopedModulePath.endsWith(idWithNativePathSep)) {
return scopedModulePath;
}
// Otherwise, return just the path to the module folder or named export
const moduleFolderStrPosition = scopedModulePath.lastIndexOf(idWithNativePathSep);
const beginningOfMainScriptPath = moduleFolderStrPosition + id.length;
return scopedModulePath.substring(0, beginningOfMainScriptPath);
};

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/preact-vite",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Preact and Vite: Develop Preact components in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/preact-webpack5",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Preact: Develop Preact Component in isolation.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/react-vite",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for React and Vite: Develop React components in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/react-webpack5",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for React: Develop React Component in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/server-webpack5",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/svelte-vite",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Svelte and Vite: Develop Svelte components in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/svelte-webpack5",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/sveltekit",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for SvelteKit",
"keywords": [
"storybook",

View File

@ -1,16 +1,21 @@
import { resolve } from 'node:path';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import type { Plugin } from 'vite';
// @ts-expect-error We are building for CJS and ESM, so we have to use import.meta.url for the ESM output
const filename = __filename ?? fileURLToPath(import.meta.url);
const dir = dirname(filename);
export async function mockSveltekitStores() {
return {
name: 'storybook:sveltekit-mock-stores',
config: () => ({
resolve: {
alias: {
'$app/forms': resolve(__dirname, '../src/mocks/app/forms.ts'),
'$app/navigation': resolve(__dirname, '../src/mocks/app/navigation.ts'),
'$app/stores': resolve(__dirname, '../src/mocks/app/stores.ts'),
'$app/forms': resolve(dir, '../src/mocks/app/forms.ts'),
'$app/navigation': resolve(dir, '../src/mocks/app/navigation.ts'),
'$app/stores': resolve(dir, '../src/mocks/app/stores.ts'),
},
},
}),

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/vue3-vite",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Vue3 and Vite: Develop Vue3 components in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/vue3-webpack5",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/web-components-vite",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for web-components and Vite: Develop Web Components in isolation with Hot Reloading.",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/web-components-webpack5",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook for web-components: View web components snippets in isolation with Hot Reloading.",
"keywords": [
"lit",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/blocks",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook Doc Blocks",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "sb",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook CLI",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/cli",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook CLI",
"keywords": [
"storybook"

View File

@ -43,7 +43,7 @@ const command = (name: string) =>
command('add <addon>')
.description('Add an addon to your Storybook')
.option(
'--package-manager <npm|pnpm|yarn1|yarn2>',
'--package-manager <npm|pnpm|yarn1|yarn2|bun>',
'Force package manager for installing dependencies'
)
.option('-c, --config-dir <dir-name>', 'Directory where to load Storybook configurations from')
@ -54,7 +54,7 @@ command('add <addon>')
command('remove <addon>')
.description('Remove an addon from your Storybook')
.option(
'--package-manager <npm|pnpm|yarn1|yarn2>',
'--package-manager <npm|pnpm|yarn1|yarn2|bun>',
'Force package manager for installing dependencies'
)
.option('-c, --config-dir <dir-name>', 'Directory where to load Storybook configurations from')
@ -70,7 +70,7 @@ command('remove <addon>')
command('upgrade')
.description(`Upgrade your Storybook packages to v${versions.storybook}`)
.option(
'--package-manager <npm|pnpm|yarn1|yarn2>',
'--package-manager <npm|pnpm|yarn1|yarn2|bun>',
'Force package manager for installing dependencies'
)
.option('-y --yes', 'Skip prompting the user')
@ -157,7 +157,7 @@ command('automigrate [fixId]')
.description('Check storybook for incompatibilities or migrations and apply fixes')
.option('-y --yes', 'Skip prompting the user')
.option('-n --dry-run', 'Only check for fixes, do not actually run them')
.option('--package-manager <npm|pnpm|yarn1|yarn2>', 'Force package manager')
.option('--package-manager <npm|pnpm|yarn1|yarn2|bun>', 'Force package manager')
.option('-l --list', 'List available migrations')
.option('-c, --config-dir <dir-name>', 'Directory of Storybook configurations to migrate')
.option('-s --skip-install', 'Skip installing deps')
@ -174,7 +174,7 @@ command('automigrate [fixId]')
command('doctor')
.description('Check Storybook for known problems and provide suggestions or fixes')
.option('--package-manager <npm|pnpm|yarn1|yarn2>', 'Force package manager')
.option('--package-manager <npm|pnpm|yarn1|yarn2|bun>', 'Force package manager')
.option('-c, --config-dir <dir-name>', 'Directory of Storybook configuration')
.action(async (options) => {
await doctor(options).catch((e) => {

View File

@ -1,6 +1,6 @@
{
"name": "storybook",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook's CLI - install, dev, build, upgrade, and more",
"keywords": [
"cli",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/codemod",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "A collection of codemod scripts written with JSCodeshift",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/core-webpack",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "create-storybook",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Initialize Storybook into your project",
"homepage": "https://github.com/storybookjs/storybook/tree/next/code/lib/create-storybook",
"bugs": {

View File

@ -25,7 +25,10 @@ program
.option('--enable-crash-reports', 'Enable sending crash reports to telemetry data')
.option('-f --force', 'Force add Storybook')
.option('-s --skip-install', 'Skip installing deps')
.option('--package-manager <npm|pnpm|yarn1|yarn2>', 'Force package manager for installing deps')
.option(
'--package-manager <npm|pnpm|yarn1|yarn2|bun>',
'Force package manager for installing deps'
)
.option('--use-pnp', 'Enable pnp mode for Yarn 2+')
.option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')
.option('-t --type <type>', 'Add Storybook for a specific project type')

View File

@ -245,7 +245,7 @@ export async function baseGenerator(
].filter(Boolean);
// TODO: migrate template stories in solid and qwik to use @storybook/test
if (['solid', 'qwik'].includes(rendererId)) {
if (['qwik'].includes(rendererId)) {
addonPackages.push('@storybook/testing-library');
} else {
addonPackages.push('@storybook/test');

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/csf-plugin",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Enrich CSF files via static analysis",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/instrumenter",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/react-dom-shim",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/source-loader",
"version": "8.4.0-beta.3",
"version": "8.5.0-alpha.2",
"description": "Source loader",
"keywords": [
"lib",

Some files were not shown because too many files have changed in this diff Show More