Merge branch 'next' into shilman/preact-framework-page

This commit is contained in:
Michael Shilman 2025-02-01 19:16:33 +08:00 committed by GitHub
commit 113128219b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
233 changed files with 7934 additions and 6120 deletions

View File

@ -25,7 +25,7 @@ executors:
default: "small"
working_directory: /tmp/storybook
docker:
- image: cimg/node:22.6.0
- image: cimg/node:22.13.1
environment:
NODE_OPTIONS: --max_old_space_size=6144
resource_class: <<parameters.class>>
@ -51,7 +51,7 @@ executors:
default: "small"
working_directory: /tmp/storybook
docker:
- image: cimg/node:22.6.0-browsers
- image: cimg/node:22.13.1-browsers
environment:
NODE_OPTIONS: --max_old_space_size=6144
resource_class: <<parameters.class>>
@ -133,7 +133,7 @@ jobs:
yarn docs:prettier:check
build:
executor:
class: xlarge
class: large
name: sb_node_22_classic
steps:
- git-shallow-clone/checkout_advanced:
@ -179,7 +179,7 @@ jobs:
- .verdaccio-cache
lint:
executor:
class: large
class: medium+
name: sb_node_22_classic
steps:
- git-shallow-clone/checkout_advanced:
@ -195,7 +195,7 @@ jobs:
- cancel-workflow-on-failure
knip:
executor:
class: large
class: medium
name: sb_node_22_classic
steps:
- git-shallow-clone/checkout_advanced:
@ -211,7 +211,7 @@ jobs:
- cancel-workflow-on-failure
bench-packages:
executor:
class: medium
class: small
name: sb_node_22_classic
steps:
- git-shallow-clone/checkout_advanced:
@ -260,7 +260,7 @@ jobs:
- cancel-workflow-on-failure
check:
executor:
class: xlarge
class: large
name: sb_node_22_classic
steps:
- git-shallow-clone/checkout_advanced:
@ -268,24 +268,18 @@ jobs:
- nx/set-shas:
main-branch-name: "next"
workflow-name: << pipeline.parameters.workflow >>
- run:
name: install in scripts
command: |
cd scripts
yarn install
- run:
name: install in code
command: |
cd code
yarn install
- restore_cache:
name: Restore Yarn cache
keys:
- build-yarn-2-cache-v4--{{ checksum "code/yarn.lock" }}--{{ checksum "scripts/yarn.lock" }}
- run:
name: Compile
command: |
yarn task --task compile --start-from=compile --no-link --debug
yarn task --task compile --start-from=auto --no-link --debug
- run:
name: Check
command: |
yarn task --task check --start-from=check --no-link --debug
yarn task --task check --start-from=auto --no-link --debug
- run:
name: Ensure no changes pending
command: |
@ -320,7 +314,7 @@ jobs:
- cancel-workflow-on-failure
unit-tests:
executor:
class: xlarge
class: large
name: sb_playwright
parallelism: 4
steps:
@ -332,7 +326,7 @@ jobs:
name: Test
command: |
cd code
SHARD="$((${CIRCLE_NODE_INDEX}+1))"; yarn test --reporter=blob --shard=${SHARD}/${CIRCLE_NODE_TOTAL}
SHARD="$((${CIRCLE_NODE_INDEX}+1))"; yarn test --reporter=blob --reporter=default --shard=${SHARD}/${CIRCLE_NODE_TOTAL}
# TODO: bring coverage back later. This has caused flakiness in the tests because
# Somehow Vitest reports coverage while some tests are still running,
# then it tries to report coverage again and as result it crashes like this:
@ -374,7 +368,7 @@ jobs:
- report-workflow-on-failure
chromatic-internal-storybook:
executor:
class: medium+
class: medium
name: sb_node_22_browsers
environment:
NODE_OPTIONS: --max_old_space_size=6144
@ -396,7 +390,7 @@ jobs:
parallelism:
type: integer
executor:
class: medium
class: large
name: sb_node_22_browsers
parallelism: << parameters.parallelism >>
steps:
@ -408,14 +402,27 @@ jobs:
name: Enable Corepack
command: sudo corepack enable yarn
- run:
name: Creating Sandboxes
command: yarn task --task sandbox --template $(yarn get-template --cadence << pipeline.parameters.workflow >> --task sandbox) --no-link --start-from=never --junit
name: Starting Event Collector
command: yarn jiti ./event-log-collector.ts
working_directory: scripts
background: true
- run:
name: Create Sandboxes
command: |
TEMPLATE=$(yarn get-template --cadence << pipeline.parameters.workflow >> --task sandbox)
yarn task --task build --template $TEMPLATE --no-link --start-from=sandbox --junit
if [[ $TEMPLATE != bench/* ]]; then
yarn --cwd scripts jiti ./event-log-checker.ts build $TEMPLATE
fi
cd sandbox/$(yarn get-sandbox-dir --template $TEMPLATE) && rm -rf node_modules
environment:
STORYBOOK_TELEMETRY_URL: "http://localhost:6007/event-log"
- report-workflow-on-failure:
template: $(yarn get-template --cadence << pipeline.parameters.workflow >> --task sandbox)
- persist_to_workspace:
root: .
paths:
- sandbox
- sandbox/**
- store_test_results:
path: test-results
smoke-test-sandboxes:
@ -438,53 +445,12 @@ jobs:
template: $(yarn get-template --cadence << pipeline.parameters.workflow >> --task smoke-test)
- store_test_results:
path: test-results
build-sandboxes:
parameters:
parallelism:
type: integer
executor:
class: large
name: sb_node_22_browsers
parallelism: << parameters.parallelism >>
steps:
- git-shallow-clone/checkout_advanced:
clone_options: "--depth 1 --verbose"
- attach_workspace:
at: .
- run:
name: Starting Event Collector
command: yarn jiti ./event-log-collector.ts
working_directory: scripts
background: true
- run:
name: Building Sandboxes
command: yarn task --task build --template $(yarn get-template --cadence << pipeline.parameters.workflow >> --task build) --no-link --start-from=never --junit
environment:
STORYBOOK_TELEMETRY_URL: "http://localhost:6007/event-log"
- run:
name: Verifying Telemetry
command: |
TEMPLATE=$(yarn get-template --cadence << pipeline.parameters.workflow >> --task build)
if [[ $TEMPLATE != bench/* ]]
then
yarn jiti ./event-log-checker.ts build $TEMPLATE
fi
working_directory: scripts
- report-workflow-on-failure:
template: $(yarn get-template --cadence << pipeline.parameters.workflow >> --task build)
- store_test_results:
path: test-results
- persist_to_workspace:
root: .
paths:
- sandbox/*/bench/*.json
- sandbox/*/storybook-static
test-runner-production:
parameters:
parallelism:
type: integer
executor:
class: large
class: medium+
name: sb_playwright
parallelism: << parameters.parallelism >>
steps:
@ -492,6 +458,11 @@ jobs:
clone_options: "--depth 1 --verbose"
- attach_workspace:
at: .
- run:
name: Install sandbox dependencies
command: |
TEMPLATE=$(yarn get-template --cadence << pipeline.parameters.workflow >> --task test-runner)
cd sandbox/$(yarn get-sandbox-dir --template $TEMPLATE) && yarn
- run:
name: Running Test Runner
command: yarn task --task test-runner --template $(yarn get-template --cadence << pipeline.parameters.workflow >> --task test-runner) --no-link --start-from=never --junit
@ -504,7 +475,7 @@ jobs:
parallelism:
type: integer
executor:
class: xlarge
class: large
name: sb_playwright
parallelism: << parameters.parallelism >>
steps:
@ -512,6 +483,11 @@ jobs:
clone_options: "--depth 1 --verbose"
- attach_workspace:
at: .
- run:
name: Install sandbox dependencies
command: |
TEMPLATE=$(yarn get-template --cadence << pipeline.parameters.workflow >> --task vitest-integration)
cd sandbox/$(yarn get-sandbox-dir --template $TEMPLATE) && yarn
- run:
name: Running story tests in Vitest
command: yarn task --task vitest-integration --template $(yarn get-template --cadence << pipeline.parameters.workflow >> --task vitest-integration) --no-link --start-from=never --junit
@ -551,6 +527,11 @@ jobs:
- checkout
- attach_workspace:
at: .
- run:
name: Install sandbox dependencies
command: |
TEMPLATE=$(yarn get-template --cadence << pipeline.parameters.workflow >> --task chromatic)
cd sandbox/$(yarn get-sandbox-dir --template $TEMPLATE) && yarn
- run:
name: Running Chromatic
command: yarn task --task chromatic --template $(yarn get-template --cadence << pipeline.parameters.workflow >> --task chromatic) --no-link --start-from=never --junit
@ -571,6 +552,11 @@ jobs:
clone_options: "--depth 1 --verbose"
- attach_workspace:
at: .
- run:
name: Install sandbox dependencies
command: |
TEMPLATE=$(yarn get-template --cadence << pipeline.parameters.workflow >> --task e2e-tests)
cd sandbox/$(yarn get-sandbox-dir --template $TEMPLATE) && yarn
- run:
name: Running E2E Tests
command: yarn task --task e2e-tests --template $(yarn get-template --cadence << pipeline.parameters.workflow >> --task e2e-tests) --no-link --start-from=never --junit
@ -586,7 +572,7 @@ jobs:
parallelism:
type: integer
executor:
class: medium
class: medium+
name: sb_playwright
parallelism: << parameters.parallelism >>
steps:
@ -594,6 +580,11 @@ jobs:
clone_options: "--depth 1 --verbose"
- attach_workspace:
at: .
- run:
name: Install sandbox dependencies
command: |
TEMPLATE=$(yarn get-template --cadence << pipeline.parameters.workflow >> --task e2e-tests-dev)
cd sandbox/$(yarn get-sandbox-dir --template $TEMPLATE) && yarn
- run:
name: Running E2E Tests
command: yarn task --task e2e-tests-dev --template $(yarn get-template --cadence << pipeline.parameters.workflow >> --task e2e-tests-dev) --no-link --start-from=never --junit
@ -609,7 +600,7 @@ jobs:
parallelism:
type: integer
executor:
class: medium
class: small
name: sb_playwright
parallelism: << parameters.parallelism >>
steps:
@ -617,6 +608,11 @@ jobs:
clone_options: "--depth 1 --verbose"
- attach_workspace:
at: .
- run:
name: Install sandbox dependencies
command: |
TEMPLATE=$(yarn get-template --cadence << pipeline.parameters.workflow >> --task bench)
cd sandbox/$(yarn get-sandbox-dir --template $TEMPLATE) && yarn
- run:
name: Running Bench
command: yarn task --task bench --template $(yarn get-template --cadence << pipeline.parameters.workflow >> --task bench) --no-link --start-from=never --junit
@ -627,7 +623,7 @@ jobs:
template: $(yarn get-template --cadence << pipeline.parameters.workflow >> --task bench)
test-empty-init:
executor:
class: medium
class: small
name: sb_node_22_browsers
parameters:
packageManager:
@ -837,18 +833,14 @@ workflows:
parallelism: 14
requires:
- build
- build-sandboxes:
parallelism: 14
requires:
- create-sandboxes
- chromatic-sandboxes:
parallelism: 11
requires:
- build-sandboxes
- create-sandboxes
- e2e-production:
parallelism: 9
requires:
- build-sandboxes
- create-sandboxes
- e2e-dev:
parallelism: 1
requires:
@ -856,7 +848,7 @@ workflows:
- test-runner-production:
parallelism: 9
requires:
- build-sandboxes
- create-sandboxes
- vitest-integration:
parallelism: 5
requires:
@ -864,7 +856,7 @@ workflows:
- bench-sandboxes:
parallelism: 5
requires:
- build-sandboxes
- create-sandboxes
- test-ui-testing-module:
requires:
- build
@ -913,18 +905,14 @@ workflows:
parallelism: 20
requires:
- build
- build-sandboxes:
parallelism: 20
requires:
- create-sandboxes
- chromatic-sandboxes:
parallelism: 17
requires:
- build-sandboxes
- create-sandboxes
- e2e-production:
parallelism: 15
requires:
- build-sandboxes
- create-sandboxes
- e2e-dev:
parallelism: 1
requires:
@ -932,7 +920,7 @@ workflows:
- test-runner-production:
parallelism: 15
requires:
- build-sandboxes
- create-sandboxes
- vitest-integration:
parallelism: 5
requires:
@ -949,7 +937,7 @@ workflows:
- bench-sandboxes:
parallelism: 5
requires:
- build-sandboxes
- create-sandboxes
# TODO: reenable once we find out the source of flakyness
# - test-runner-dev:
# parallelism: 4
@ -990,18 +978,14 @@ workflows:
# - smoke-test-sandboxes: # disabled for now
# requires:
# - create-sandboxes
- build-sandboxes:
parallelism: 37
requires:
- create-sandboxes
- chromatic-sandboxes:
parallelism: 34
requires:
- build-sandboxes
- create-sandboxes
- e2e-production:
parallelism: 32
requires:
- build-sandboxes
- create-sandboxes
- e2e-dev:
parallelism: 1
requires:
@ -1009,7 +993,7 @@ workflows:
- test-runner-production:
parallelism: 32
requires:
- build-sandboxes
- create-sandboxes
- vitest-integration:
parallelism: 11
requires:
@ -1044,7 +1028,7 @@ workflows:
- bench-sandboxes:
parallelism: 5
requires:
- build-sandboxes
- create-sandboxes
# TODO: reenable once we find out the source of flakyness
# - test-runner-dev:

View File

@ -174,12 +174,13 @@ jobs:
git commit -m "Update CHANGELOG.md for v${{ steps.version.outputs.current-version }} [skip ci]" || true
git push origin next
# TODO: remove this step - @JReinhold
# Sync the next.json version file to the main branch so it gets deployed to the docs site
# but only if this is a prerelease, because in minor/major releases we're already force pushing next-release onto main, so it's already there
- name: Sync version JSONs from `next-release` to `main`
if: github.ref_name == 'next-release'
if: github.ref_name == 'next-release' && steps.is-prerelease.outputs.prerelease == 'true'
working-directory: .
run: |
VERSION_FILE="./docs/versions/${{ steps.is-prerelease.outputs.prerelease == 'true' && 'next' || 'latest' }}.json"
VERSION_FILE="./docs/versions/next.json"
git fetch origin main
git checkout main
git pull

3
.nvmrc
View File

@ -1 +1,2 @@
22.6.0
22.13.1

894
.yarn/releases/yarn-4.3.0.cjs generated vendored

File diff suppressed because one or more lines are too long

934
.yarn/releases/yarn-4.6.0.cjs generated vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -8,4 +8,4 @@ nodeLinker: node-modules
npmPublishAccess: public
yarnPath: .yarn/releases/yarn-4.3.0.cjs
yarnPath: .yarn/releases/yarn-4.6.0.cjs

View File

@ -1,3 +1,15 @@
## 8.5.2
- Addon Test: Support Vitest 3 browser.test.instances field - [#30309](https://github.com/storybookjs/storybook/pull/30309), thanks @valentinpalkovic!
- CLI: Corrected Next.js createScript for pnpm. - [#30304](https://github.com/storybookjs/storybook/pull/30304), thanks @zhyd1997!
## 8.5.1
- Addon Test: Replace `interaction test` -> `component test` - [#30333](https://github.com/storybookjs/storybook/pull/30333), thanks @kylegach!
- Addon Test: Support Vitest 3 browser.test.instances field - [#30309](https://github.com/storybookjs/storybook/pull/30309), thanks @valentinpalkovic!
- Manager: Fix escaping of single quotes in dynamic import paths - [#30278](https://github.com/storybookjs/storybook/pull/30278), thanks @valentinpalkovic!
- RNW-Vite: Support requires for images/fonts - [#30305](https://github.com/storybookjs/storybook/pull/30305), thanks @dannyhw!
## 8.5.0
Storybook 8.5 is packed with powerful features to enhance your development workflow. This release makes it easier than ever to build accessible, well-tested UIs. Heres whats new:

View File

@ -1,3 +1,26 @@
## 8.6.0-alpha.3
- Core: Fix invalid Websocket termination - [#30408](https://github.com/storybookjs/storybook/pull/30408), thanks @valentinpalkovic!
- Core: Improve type compatibility with React 19 - [#30031](https://github.com/storybookjs/storybook/pull/30031), thanks @mrginglymus!
- Preview: Add `globals` to `extract()` - [#30415](https://github.com/storybookjs/storybook/pull/30415), thanks @ndelangen!
## 8.6.0-alpha.2
- Addon Test: Support Vitest 3 browser.test.instances field - [#30309](https://github.com/storybookjs/storybook/pull/30309), thanks @valentinpalkovic!
- Bun: Add support for text lock file - [#30160](https://github.com/storybookjs/storybook/pull/30160), thanks @Arctomachine!
- CLI: Corrected Next.js createScript for pnpm. - [#30304](https://github.com/storybookjs/storybook/pull/30304), thanks @zhyd1997!
## 8.6.0-alpha.1
- Addon Test: Replace `interaction test` -> `component test` - [#30333](https://github.com/storybookjs/storybook/pull/30333), thanks @kylegach!
- Angular: Fix accent character issue - [#30276](https://github.com/storybookjs/storybook/pull/30276), thanks @valentinpalkovic!
- Angular: Support experimental zoneless mode - [#28657](https://github.com/storybookjs/storybook/pull/28657), thanks @anedomansky!
- CLI: Use correct storybook internals import in automigration - [#30290](https://github.com/storybookjs/storybook/pull/30290), thanks @yannbf!
- Core: Add connection timeout notification - [#30288](https://github.com/storybookjs/storybook/pull/30288), thanks @valentinpalkovic!
- Csf Tools: Allow ConfigFile to create more import syntaxes - [#30204](https://github.com/storybookjs/storybook/pull/30204), thanks @yannbf!
- Manager: Escape single quotes in dynamic import paths in wrapManagerEntries function - [#30278](https://github.com/storybookjs/storybook/pull/30278), thanks @valentinpalkovic!
- RNW-Vite: Support requires for images/fonts - [#30305](https://github.com/storybookjs/storybook/pull/30305), thanks @dannyhw!
## 8.6.0-alpha.0

View File

@ -1,7 +1,7 @@
<h1>Migration</h1>
- [From version 8.4.x to 8.5.x](#from-version-84x-to-85x)
- [Introducing features.developmentModeForBuild](#introducing-featuresdevelopmentmodeforbuild)
- [From version 8.5.x to 8.6.x](#from-version-85x-to-86x)
- [Angular: Support experimental zoneless support](#angular-support-experimental-zoneless-support)
- [Added source code panel to docs](#added-source-code-panel-to-docs)
- [Addon-a11y: Component test integration](#addon-a11y-component-test-integration)
- [Addon-a11y: Changing the default element selector](#addon-a11y-changing-the-default-element-selector)
@ -427,6 +427,37 @@
- [Packages renaming](#packages-renaming)
- [Deprecated embedded addons](#deprecated-embedded-addons)
## From version 8.5.x to 8.6.x
### Angular: Support experimental zoneless support
Storybook now supports [Angular's experimental zoneless mode](https://angular.dev/guide/experimental/zoneless). This mode is intended to improve performance by removing Angular's zone.js dependency. To enable zoneless mode in your Angular Storybook, set the `experimentalZoneless` config in your `angular.json` file:
```diff
{
"projects": {
"your-project": {
"architect": {
"storybook": {
...
"options": {
...
+ "experimentalZoneless": true
}
}
"build-storybook": {
...
"options": {
...
+ "experimentalZoneless": true
}
}
}
}
}
}
```
## From version 8.4.x to 8.5.x
### Introducing features.developmentModeForBuild
@ -442,7 +473,7 @@ export default {
developmentModeForBuild: true,
},
};
```
````
### Added source code panel to docs

View File

@ -47,8 +47,12 @@ export default mergeConfig(
testNamePattern: /^(?!.*(UseState)).*$/,
browser: {
enabled: true,
name: 'chromium',
provider: 'playwright',
instances: [
{
browser: 'chromium',
},
],
headless: true,
screenshotFailures: false,
},

934
code/.yarn/releases/yarn-4.6.0.cjs generated vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -22,7 +22,6 @@ plugins:
- path: ../.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: '@yarnpkg/plugin-workspace-tools'
# See https://github.com/nrwl/nx/issues/22177
supportedArchitectures:
cpu:
- current
@ -36,6 +35,4 @@ supportedArchitectures:
unsafeHttpWhitelist:
- localhost
yarnPath: ../.yarn/releases/yarn-4.3.0.cjs
# Sometimes you get a "The remote archive doesn't match the expected checksum" error, uncommenting this line will fix it
# checksumBehavior: 'update'
yarnPath: .yarn/releases/yarn-4.6.0.cjs

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-a11y",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Test component compliance with web accessibility standards",
"keywords": [
"a11y",
@ -82,7 +82,7 @@
"react-dom": "^18.2.0",
"react-resize-detector": "^7.1.2",
"resize-observer-polyfill": "^1.5.1",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -42,13 +42,13 @@ const getFilter = (filterName: string) => {
return `url('#${filterName}')`;
};
const Hidden = styled.div(() => ({
const Hidden = styled.div({
'&, & svg': {
position: 'absolute',
width: 0,
height: 0,
},
}));
});
const ColorIcon = styled.span<{ filter: string }>(
{

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-actions",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Get UI feedback when an action is performed on an interactive element",
"keywords": [
"storybook",
@ -79,7 +79,7 @@
"react-dom": "^18.2.0",
"react-inspector": "^6.0.0",
"telejson": "^7.2.0",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-backgrounds",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Switch backgrounds to view components in different settings",
"keywords": [
"addon",
@ -63,7 +63,7 @@
"@storybook/icons": "^1.2.12",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

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

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-docs",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Document component usage and properties in Markdown",
"keywords": [
"addon",
@ -118,7 +118,7 @@
"react-dom": "^18.2.0",
"rehype-external-links": "^3.0.0",
"rehype-slug": "^6.0.0",
"typescript": "^5.3.2",
"typescript": "^5.7.3",
"vite": "^4.0.4"
},
"peerDependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-essentials",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Curated addons to bring out the best of Storybook",
"keywords": [
"addon",
@ -101,7 +101,7 @@
"ts-dedent": "^2.0.0"
},
"devDependencies": {
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-mdx-gfm",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "GitHub Flavored Markdown in Storybook",
"keywords": [
"addon",
@ -48,7 +48,7 @@
"ts-dedent": "^2.0.0"
},
"devDependencies": {
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-highlight",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Highlight DOM nodes within your stories",
"keywords": [
"storybook-addons",
@ -55,7 +55,7 @@
},
"devDependencies": {
"@types/webpack-env": "^1.16.0",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-interactions",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Automate, test and debug user interactions",
"keywords": [
"storybook-addons",
@ -66,7 +66,7 @@
"formik": "^2.2.9",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -14,12 +14,12 @@ import { MatcherResult } from './MatcherResult';
import { MethodCall } from './MethodCall';
import { StatusIcon } from './StatusIcon';
const MethodCallWrapper = styled.div(() => ({
const MethodCallWrapper = styled.div({
fontFamily: typography.fonts.mono,
fontSize: typography.size.s1,
overflowWrap: 'break-word',
inlineSize: 'calc( 100% - 40px )',
}));
});
const RowContainer = styled('div', {
shouldForwardProp: (prop) => !['call', 'pausedAt'].includes(prop.toString()),

View File

@ -141,7 +141,7 @@ export const getInteractions = (finalStatus: CallStates) =>
.filter((call) => call.interceptable)
.map((call) => ({
...call,
childCallIds: [],
childCallIds: [] as any[],
isCollapsed: false,
isHidden: false,
toggleCollapsed: () => {},

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-jest",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "React storybook addon that show component jest report",
"keywords": [
"addon",
@ -62,7 +62,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-resize-detector": "^7.1.2",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-links",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Link stories together to build demos and prototypes with your UI components",
"keywords": [
"storybook-addons",
@ -70,7 +70,7 @@
"ts-dedent": "^2.0.0"
},
"devDependencies": {
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-measure",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Inspect layouts by visualizing the box model",
"keywords": [
"storybook-addons",
@ -74,7 +74,7 @@
"@storybook/icons": "^1.2.12",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-onboarding",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Storybook Addon Onboarding - Introduces a new onboarding experience",
"keywords": [
"storybook-addons",
@ -54,7 +54,7 @@
"react-dom": "^18.2.0",
"react-joyride": "^2.8.2",
"react-use-measure": "^2.1.1",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,9 +1,9 @@
import { styled } from 'storybook/internal/theming';
export const ListWrapper = styled.ul(() => ({
export const ListWrapper = styled.ul({
display: 'flex',
flexDirection: 'column',
rowGap: 16,
padding: 0,
margin: 0,
}));
});

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-outline",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Outline all elements with CSS to help with layout placement and alignment",
"keywords": [
"storybook-addons",
@ -64,7 +64,7 @@
"@storybook/icons": "^1.2.12",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-storysource",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "View a storys source code to see how it works and paste into your app",
"keywords": [
"addon",
@ -56,7 +56,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-syntax-highlighter": "^15.5.0",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/experimental-addon-test",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Integrate Vitest with Storybook",
"keywords": [
"storybook-addons",
@ -95,8 +95,8 @@
"@types/istanbul-lib-report": "^3.0.3",
"@types/node": "^22.0.0",
"@types/semver": "^7",
"@vitest/browser": "3.0.0-beta.4",
"@vitest/runner": "3.0.0-beta.4",
"@vitest/browser": "^3.0.2",
"@vitest/runner": "^3.0.2",
"ansi-to-html": "^0.7.2",
"boxen": "^8.0.1",
"es-toolkit": "^1.22.0",
@ -115,8 +115,8 @@
"tinyglobby": "^0.2.10",
"tree-kill": "^1.2.2",
"ts-dedent": "^2.2.0",
"typescript": "^5.3.2",
"vitest": "3.0.0-beta.4"
"typescript": "^5.7.3",
"vitest": "^3.0.2"
},
"peerDependencies": {
"@vitest/browser": "^2.1.1 || ^3.0.0",

View File

@ -46,10 +46,10 @@ export const Empty = () => {
return (
<EmptyTabContent
title="Interaction testing"
title="Component testing"
description={
<>
Interaction tests allow you to verify the functional aspects of UIs. Write a play function
Component tests allow you to verify the functional aspects of UIs. Write a play function
for your story and you&apos;ll see it run here.
</>
}

View File

@ -14,12 +14,12 @@ import { MatcherResult } from './MatcherResult';
import { MethodCall } from './MethodCall';
import { StatusIcon } from './StatusIcon';
const MethodCallWrapper = styled.div(() => ({
const MethodCallWrapper = styled.div({
fontFamily: typography.fonts.mono,
fontSize: typography.size.s1,
overflowWrap: 'break-word',
inlineSize: 'calc( 100% - 40px )',
}));
});
const RowContainer = styled('div', {
shouldForwardProp: (prop) => !['call', 'pausedAt'].includes(prop.toString()),

View File

@ -379,7 +379,7 @@ export const TestProviderRender: FC<TestProviderRenderProps> = ({
icon={
state.crashed ? (
<TestStatusIcon status="critical" aria-label="status: crashed" />
) : // @ts-expect-error: TODO: Fix types
) : // @ts-expect-error @ghengeveld should check whether this is a bug or not
status === 'unknown' ? (
<TestStatusIcon status="unknown" aria-label="status: unknown" />
) : (

View File

@ -421,6 +421,24 @@ export default async function postInstall(options: PostinstallOptions) {
const isVitest3OrLater = !!(coercedVitestVersion && satisfies(coercedVitestVersion, '>=3.0.0'));
const browserConfig = isVitest3OrLater
? `{
enabled: true,
headless: true,
provider: 'playwright',
instances: [
{
browser: 'chromium',
}
]
}`
: `{
enabled: true,
headless: true,
name: 'chromium',
provider: 'playwright'
}`;
if (isVitest3OrLater && fileExtension === 'ts' && !vitestShimFile) {
await writeFile(
'vitest.shims.d.ts',
@ -465,12 +483,7 @@ export default async function postInstall(options: PostinstallOptions) {
],
test: {
name: 'storybook',
browser: {
enabled: true,
headless: true,
name: 'chromium',
provider: 'playwright',
},
browser: ${browserConfig},
setupFiles: ['${vitestSetupFilePath}'],
},
},
@ -509,12 +522,7 @@ export default async function postInstall(options: PostinstallOptions) {
],
test: {
name: 'storybook',
browser: {
enabled: true,
headless: true,
name: 'chromium',
provider: 'playwright',
},
browser: ${browserConfig},
setupFiles: ['${vitestSetupFilePath}'],
},
});

View File

@ -210,7 +210,6 @@ export const storybookTest = async (options?: UserOptions): Promise<Plugin[]> =>
: {}),
browser: {
...inputConfig_ONLY_MUTATE_WHEN_STRICTLY_NEEDED_OR_YOU_WILL_BE_FIRED.test?.browser,
commands: {
getInitialGlobals: () => {
const envConfig = JSON.parse(process.env.VITEST_STORYBOOK_CONFIG ?? '{}');

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-themes",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Switch between multiple themes for you components in Storybook",
"keywords": [
"css",
@ -60,7 +60,7 @@
},
"devDependencies": {
"@storybook/icons": "^1.2.12",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-toolbars",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Create your own toolbar items that control story rendering",
"keywords": [
"addon",
@ -52,7 +52,7 @@
"devDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-viewport",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Build responsive components by adjusting Storybooks viewport size and orientation",
"keywords": [
"addon",
@ -58,7 +58,7 @@
"@storybook/icons": "^1.2.12",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -74,10 +74,10 @@ const flip = ({ width, height, ...styles }: ViewportStyles) => ({
width: height,
});
const ActiveViewportSize = styled.div(() => ({
const ActiveViewportSize = styled.div({
display: 'inline-flex',
alignItems: 'center',
}));
});
const ActiveViewportLabel = styled.div(({ theme }) => ({
display: 'inline-block',

View File

@ -7,10 +7,10 @@ import { BrowserIcon, MobileIcon, TabletIcon } from '@storybook/icons';
import type { Viewport, ViewportMap } from './types';
export const ActiveViewportSize = styled.div(() => ({
export const ActiveViewportSize = styled.div({
display: 'inline-flex',
alignItems: 'center',
}));
});
export const ActiveViewportLabel = styled.div(({ theme }) => ({
display: 'inline-block',

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/builder-vite",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"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.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"
@ -96,7 +96,7 @@
"pretty-hrtime": "^1.0.3",
"sirv": "^2.0.4",
"slash": "^5.0.0",
"typescript": "^5.3.2"
"typescript": "^5.7.3"
},
"peerDependencies": {
"storybook": "workspace:^"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/core",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"
@ -275,6 +275,7 @@
},
"dependencies": {
"@storybook/csf": "0.1.12",
"@storybook/theming": "workspace:*",
"better-opn": "^3.0.2",
"browser-assert": "^1.2.1",
"esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0",
@ -295,16 +296,16 @@
"@babel/traverse": "^7.24.1",
"@babel/types": "^7.24.0",
"@discoveryjs/json-ext": "^0.5.3",
"@emotion/cache": "^11.11.0",
"@emotion/is-prop-valid": "^1.2.2",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@emotion/use-insertion-effect-with-fallbacks": "^1.0.1",
"@emotion/cache": "^11.14.0",
"@emotion/is-prop-valid": "^1.3.1",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
"@ndelangen/get-tarball": "^3.0.7",
"@polka/compression": "^1.0.0-next.28",
"@popperjs/core": "^2.6.0",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-scroll-area": "1.2.0-rc.7",
"@radix-ui/react-slot": "^1.0.2",
"@storybook/docs-mdx": "4.0.0-next.1",
@ -368,7 +369,7 @@
"js-yaml": "^4.1.0",
"lazy-universal-dotenv": "^4.0.0",
"leven": "^4.0.0",
"markdown-to-jsx": "^7.4.5",
"markdown-to-jsx": "^7.7.2",
"memfs": "^4.11.1",
"memoizerific": "^1.11.3",
"nanoid": "^4.0.2",
@ -405,7 +406,7 @@
"ts-dedent": "^2.0.0",
"tsconfig-paths": "^4.2.0",
"type-fest": "^4.18.1",
"typescript": "^5.3.2",
"typescript": "^5.7.3",
"unique-string": "^3.0.0",
"use-resize-observer": "^9.1.0",
"watchpack": "^2.2.0"

View File

@ -66,6 +66,6 @@ export const getFinals = (cwd: string) => {
return [
//
define('src/manager/runtime.ts', ['browser'], false),
define('src/manager/runtime.tsx', ['browser'], false),
];
};

View File

@ -1,6 +1,6 @@
import { existsSync } from 'node:fs';
import { mkdir, writeFile } from 'node:fs/promises';
import { dirname, join, relative } from 'node:path';
import { dirname, join, relative, sep } from 'node:path';
import { dedent } from '../../../../scripts/prepare/tools';
import type { getEntries } from '../entries';
@ -13,8 +13,8 @@ async function generateTypesMapperContent(filePath: string) {
return dedent`
// auto generated file from ${__filename}, do not edit
export * from '${join(upwards, downwards)}';
export type * from '${join(upwards, downwards)}';
export * from '${join(upwards, downwards).replaceAll(sep, '/')}';
export type * from '${join(upwards, downwards).replaceAll(sep, '/')}';
`;
}

View File

@ -60,7 +60,8 @@ export async function wrapManagerEntries(entrypoints: string[], uniqueId?: strin
const directory = dirname(location);
await mkdir(directory, { recursive: true });
}
await writeFile(location, `import '${slash(entry)}';`);
await writeFile(location, `import '${slash(entry).replaceAll(/'/g, "\\'")}';`);
return location;
})

View File

@ -12,7 +12,7 @@ const MockedWebsocket = vi.hoisted(() => {
onerror: (e: any) => void;
onclose: () => void;
onclose: (event: any) => void;
constructor(url: string) {
this.onopen = vi.fn();
@ -293,11 +293,16 @@ describe('WebsocketTransport', () => {
});
transport.setHandler(handler);
MockedWebsocket.ref.current.onclose();
MockedWebsocket.ref.current.onclose({ code: 1000, reason: 'test' });
expect(handler.mock.calls[0][0]).toMatchInlineSnapshot(`
{
"args": [],
"args": [
{
"code": 1000,
"reason": "test",
},
],
"from": "preview",
"type": "channelWSDisconnect",
}

View File

@ -13,7 +13,7 @@ export * from './main';
export default Channel;
export { PostMessageTransport } from './postmessage';
export { WebsocketTransport } from './websocket';
export { WebsocketTransport, HEARTBEAT_INTERVAL, HEARTBEAT_MAX_LATENCY } from './websocket';
type Options = Config & {
extraTransports?: ChannelTransport[];

View File

@ -17,6 +17,9 @@ interface WebsocketTransportArgs extends Partial<Config> {
onError: OnError;
}
export const HEARTBEAT_INTERVAL = 15000;
export const HEARTBEAT_MAX_LATENCY = 5000;
export class WebsocketTransport implements ChannelTransport {
private buffer: string[] = [];
@ -26,25 +29,48 @@ export class WebsocketTransport implements ChannelTransport {
private isReady = false;
private isClosed = false;
private pingTimeout: number | NodeJS.Timeout = 0;
private heartbeat() {
clearTimeout(this.pingTimeout);
this.pingTimeout = setTimeout(() => {
this.socket.close(3008, 'timeout');
}, HEARTBEAT_INTERVAL + HEARTBEAT_MAX_LATENCY);
}
constructor({ url, onError, page }: WebsocketTransportArgs) {
this.socket = new WebSocket(url);
this.socket.onopen = () => {
this.isReady = true;
this.heartbeat();
this.flush();
};
this.socket.onmessage = ({ data }) => {
const event = typeof data === 'string' && isJSON(data) ? parse(data) : data;
invariant(this.handler, 'WebsocketTransport handler should be set');
this.handler(event);
if (event.type === 'ping') {
this.heartbeat();
this.send({ type: 'pong' });
}
};
this.socket.onerror = (e) => {
if (onError) {
onError(e);
}
};
this.socket.onclose = () => {
this.socket.onclose = (ev) => {
invariant(this.handler, 'WebsocketTransport handler should be set');
this.handler({ type: EVENTS.CHANNEL_WS_DISCONNECT, args: [], from: page || 'preview' });
this.handler({
type: EVENTS.CHANNEL_WS_DISCONNECT,
args: [{ reason: ev.reason, code: ev.code }],
from: page || 'preview',
});
this.isClosed = true;
clearTimeout(this.pingTimeout);
};
}
@ -53,10 +79,12 @@ export class WebsocketTransport implements ChannelTransport {
}
send(event: any) {
if (!this.isReady) {
this.sendLater(event);
} else {
this.sendNow(event);
if (!this.isClosed) {
if (!this.isReady) {
this.sendLater(event);
} else {
this.sendNow(event);
}
}
}

View File

@ -13,7 +13,8 @@ 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';
const BUN_LOCKFILE = 'bun.lock';
const BUN_LOCKFILE_BINARY = 'bun.lockb';
type PackageManagerProxy =
| typeof NPMProxy
@ -37,6 +38,7 @@ export class JsPackageManagerFactory {
findUpSync(PNPM_LOCKFILE, { cwd }),
findUpSync(NPM_LOCKFILE, { cwd }),
findUpSync(BUN_LOCKFILE, { cwd }),
findUpSync(BUN_LOCKFILE_BINARY, { cwd }),
]
.filter(Boolean)
.sort((a, b) => {
@ -78,7 +80,10 @@ export class JsPackageManagerFactory {
return new NPMProxy({ cwd });
}
if (hasBunCommand && closestLockfile === BUN_LOCKFILE) {
if (
hasBunCommand &&
(closestLockfile === BUN_LOCKFILE || closestLockfile === BUN_LOCKFILE_BINARY)
) {
return new BUNProxy({ cwd });
}

View File

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

View File

@ -140,11 +140,11 @@ const IconPlaceholder = styled.div(({ theme }) => ({
animation: `${theme.animation.glow} 1.5s ease-in-out infinite`,
}));
const IconButtonSkeletonWrapper = styled.div(() => ({
const IconButtonSkeletonWrapper = styled.div({
marginTop: 6,
padding: 7,
height: 28,
}));
});
/** @deprecated This component will be removed in Storybook 9.0 */
export const IconButtonSkeleton = () => (

View File

@ -53,7 +53,7 @@ it('with no staticDirs favicon should return default', async () => {
it('with staticDirs containing a single favicon.ico should return the found favicon', async () => {
const location = 'static';
existsSyncMock.mockImplementation((p: string | Buffer | URL) => {
existsSyncMock.mockImplementation((p) => {
if (p === createPath(location)) {
return true;
}
@ -69,7 +69,7 @@ it('with staticDirs containing a single favicon.ico should return the found favi
it('with staticDirs containing a single favicon.svg should return the found favicon', async () => {
const location = 'static';
existsSyncMock.mockImplementation((p: string | Buffer | URL) => {
existsSyncMock.mockImplementation((p) => {
if (p === createPath(location)) {
return true;
}
@ -85,7 +85,7 @@ it('with staticDirs containing a single favicon.svg should return the found favi
it('with staticDirs containing a multiple favicons should return the first favicon and warn', async () => {
const location = 'static';
existsSyncMock.mockImplementation((p: string | Buffer | URL) => {
existsSyncMock.mockImplementation((p) => {
if (p === createPath(location)) {
return true;
}
@ -107,7 +107,7 @@ it('with staticDirs containing a multiple favicons should return the first favic
it('with multiple staticDirs containing a multiple favicons should return the first favicon and warn', async () => {
const locationA = 'static-a';
const locationB = 'static-b';
existsSyncMock.mockImplementation((p: string | Buffer | URL) => {
existsSyncMock.mockImplementation((p) => {
if (p === createPath(locationA)) {
return true;
}

View File

@ -1,5 +1,5 @@
import type { ChannelHandler } from '@storybook/core/channels';
import { Channel } from '@storybook/core/channels';
import { Channel, HEARTBEAT_INTERVAL } from '@storybook/core/channels';
import { isJSON, parse, stringify } from 'telejson';
import WebSocket, { WebSocketServer } from 'ws';
@ -37,6 +37,23 @@ export class ServerChannelTransport {
this.handler?.(event);
});
});
const interval = setInterval(() => {
this.send({ type: 'ping' });
}, HEARTBEAT_INTERVAL);
this.socket.on('close', function close() {
clearInterval(interval);
});
process.on('SIGTERM', () => {
this.socket.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.close(1001, 'Server is shutting down');
}
});
this.socket.close(() => process.exit(0));
});
}
setHandler(handler: ChannelHandler) {

View File

@ -1146,6 +1146,24 @@ describe('ConfigFile', () => {
export default config;
`);
});
it(`supports setting a namespaced import`, () => {
const config = loadConfig('').parse();
config.setImport({ namespace: 'path' }, 'path');
const parsed = babelPrint(config._ast);
expect(parsed).toMatchInlineSnapshot(`import * as path from 'path';`);
});
it(`supports setting import without specifier`, () => {
const config = loadConfig('').parse();
config.setImport(null, 'path');
const parsed = babelPrint(config._ast);
expect(parsed).toMatchInlineSnapshot(`import 'path';`);
});
});
describe('setRequireImport', () => {

View File

@ -801,16 +801,21 @@ export class ConfigFile {
*
* // import foo from 'bar';
* setImport('foo', 'bar');
*
* // import * as foo from 'bar';
* setImport({ namespace: 'foo' }, 'bar');
*
* // import 'bar';
* setImport(null, 'bar');
* ```
*
* @param importSpecifiers - The import specifiers to set. If a string is passed in, a default
* import will be set. Otherwise, an array of named imports will be set
* @param fromImport - The module to import from
*/
setImport(importSpecifier: string[] | string, fromImport: string) {
setImport(importSpecifier: string[] | string | { namespace: string } | null, fromImport: string) {
const getNewImportSpecifier = (specifier: string) =>
t.importSpecifier(t.identifier(specifier), t.identifier(specifier));
/**
* Returns true, when the given import declaration has the given import specifier
*
@ -839,26 +844,41 @@ export class ConfigFile {
* hasImportSpecifier(declaration, 'foo');
* ```
*/
const hasNamespaceImportSpecifier = (declaration: t.ImportDeclaration, name: string) =>
declaration.specifiers.find(
(specifier) =>
t.isImportNamespaceSpecifier(specifier) &&
t.isIdentifier(specifier.local) &&
specifier.local.name === name
);
/** Returns true when the given import declaration has a default import specifier */
const hasDefaultImportSpecifier = (declaration: t.ImportDeclaration, name: string) =>
declaration.specifiers.find((specifier) => t.isImportDefaultSpecifier(specifier));
declaration.specifiers.find(
(specifier) =>
t.isImportDefaultSpecifier(specifier) &&
t.isIdentifier(specifier.local) &&
specifier.local.name === name
);
const importDeclaration = this._ast.program.body.find(
(node) => t.isImportDeclaration(node) && node.source.value === fromImport
) as t.ImportDeclaration | undefined;
// if the import specifier is a string, we're dealing with default imports
if (typeof importSpecifier === 'string') {
// If the import declaration with the given source exists
// Handle side-effect imports (e.g., import 'foo')
if (importSpecifier === null) {
if (!importDeclaration) {
this._ast.program.body.unshift(t.importDeclaration([], t.stringLiteral(fromImport)));
}
// Handle default imports e.g. import foo from 'bar'
} else if (typeof importSpecifier === 'string') {
if (importDeclaration) {
if (!hasDefaultImportSpecifier(importDeclaration, importSpecifier)) {
// If the import declaration hasn'types a default specifier, we add it
importDeclaration.specifiers.push(
t.importDefaultSpecifier(t.identifier(importSpecifier))
);
}
// If the import declaration with the given source doesn'types exist
} else {
// Add the import declaration to the top of the file
this._ast.program.body.unshift(
t.importDeclaration(
[t.importDefaultSpecifier(t.identifier(importSpecifier))],
@ -866,22 +886,38 @@ export class ConfigFile {
)
);
}
// if the import specifier is an array, we're dealing with named imports
} else if (importDeclaration) {
importSpecifier.forEach((specifier) => {
if (!hasImportSpecifier(importDeclaration, specifier)) {
importDeclaration.specifiers.push(getNewImportSpecifier(specifier));
// Handle named imports e.g. import { foo } from 'bar'
} else if (Array.isArray(importSpecifier)) {
if (importDeclaration) {
importSpecifier.forEach((specifier) => {
if (!hasImportSpecifier(importDeclaration, specifier)) {
importDeclaration.specifiers.push(getNewImportSpecifier(specifier));
}
});
} else {
this._ast.program.body.unshift(
t.importDeclaration(
importSpecifier.map(getNewImportSpecifier),
t.stringLiteral(fromImport)
)
);
}
// Handle namespace imports e.g. import * as foo from 'bar'
} else if (importSpecifier.namespace) {
if (importDeclaration) {
if (!hasNamespaceImportSpecifier(importDeclaration, importSpecifier.namespace)) {
importDeclaration.specifiers.push(
t.importNamespaceSpecifier(t.identifier(importSpecifier.namespace))
);
}
});
} else {
this._ast.program.body.unshift(
t.importDeclaration(
importSpecifier.map((specifier) =>
t.importSpecifier(t.identifier(specifier), t.identifier(specifier))
),
t.stringLiteral(fromImport)
)
);
} else {
this._ast.program.body.unshift(
t.importDeclaration(
[t.importNamespaceSpecifier(t.identifier(importSpecifier.namespace))],
t.stringLiteral(fromImport)
)
);
}
}
}
}

View File

@ -345,7 +345,6 @@ export const init: ModuleFn<SubAPI, SubState> = ({
return undefined;
}
if (refId) {
// @ts-expect-error (possibly undefined)
return refs[refId].index ? refs[refId].index[storyId] : undefined;
}
return index ? index[storyId] : undefined;

View File

@ -1 +1 @@
export const version = '8.6.0-alpha.0';
export const version = '8.6.0-alpha.3';

View File

@ -93,7 +93,7 @@ const NotificationWithInteractiveStates = styled(Notification)({
const NotificationButton = NotificationWithInteractiveStates.withComponent('div');
const NotificationLink = NotificationWithInteractiveStates.withComponent(Link);
const NotificationIconWrapper = styled.div(() => ({
const NotificationIconWrapper = styled.div({
display: 'flex',
marginRight: 10,
alignItems: 'center',
@ -102,7 +102,7 @@ const NotificationIconWrapper = styled.div(() => ({
width: 16,
height: 16,
},
}));
});
const NotificationTextWrapper = styled.div(({ theme }) => ({
width: '100%',

View File

@ -743,18 +743,24 @@ export default {
'@storybook/core/theming/create': ['create', 'themes'],
'storybook/internal/channels': [
'Channel',
'HEARTBEAT_INTERVAL',
'HEARTBEAT_MAX_LATENCY',
'PostMessageTransport',
'WebsocketTransport',
'createBrowserChannel',
],
'@storybook/channels': [
'Channel',
'HEARTBEAT_INTERVAL',
'HEARTBEAT_MAX_LATENCY',
'PostMessageTransport',
'WebsocketTransport',
'createBrowserChannel',
],
'@storybook/core/channels': [
'Channel',
'HEARTBEAT_INTERVAL',
'HEARTBEAT_MAX_LATENCY',
'PostMessageTransport',
'WebsocketTransport',
'createBrowserChannel',

View File

@ -1,20 +1,28 @@
import React from 'react';
import type { Channel } from '@storybook/core/channels';
import { createBrowserChannel } from '@storybook/core/channels';
import type { Addon_Config, Addon_Types } from '@storybook/core/types';
import { global } from '@storybook/global';
import { FailedIcon } from '@storybook/icons';
import { color } from '@storybook/theming';
import { CHANNEL_CREATED } from '@storybook/core/core-events';
import type { AddonStore } from '@storybook/core/manager-api';
import { CHANNEL_CREATED, CHANNEL_WS_DISCONNECT } from '@storybook/core/core-events';
import type { API, AddonStore } from '@storybook/core/manager-api';
import { addons } from '@storybook/core/manager-api';
import { renderStorybookUI } from './index';
import Provider from './provider';
const WS_DISCONNECTED_NOTIFICATION_ID = 'CORE/WS_DISCONNECTED';
class ReactProvider extends Provider {
addons: AddonStore;
channel: Channel;
wsDisconnected = false;
constructor() {
super();
@ -37,8 +45,23 @@ class ReactProvider extends Provider {
return this.addons.getConfig();
}
handleAPI(api: unknown) {
handleAPI(api: API) {
this.addons.loadAddons(api);
this.channel.on(CHANNEL_WS_DISCONNECT, (ev) => {
const TIMEOUT_CODE = 3008;
this.wsDisconnected = true;
api.addNotification({
id: WS_DISCONNECTED_NOTIFICATION_ID,
content: {
headline: ev.code === TIMEOUT_CODE ? 'Server timed out' : 'Connection lost',
subHeadline: 'Please restart your Storybook server and reload the page',
},
icon: <FailedIcon color={color.negative} />,
link: undefined,
});
});
}
}

View File

@ -3793,6 +3793,9 @@ describe('PreviewWeb', () => {
},
"component": undefined,
"componentId": "component-one",
"globals": {
"a": "b",
},
"id": "component-one--a",
"initialArgs": {
"foo": "a",
@ -3844,6 +3847,9 @@ describe('PreviewWeb', () => {
},
"component": undefined,
"componentId": "component-one",
"globals": {
"a": "b",
},
"id": "component-one--b",
"initialArgs": {
"foo": "b",
@ -3876,6 +3882,9 @@ describe('PreviewWeb', () => {
"args": {},
"component": undefined,
"componentId": "component-one",
"globals": {
"a": "b",
},
"id": "component-one--e",
"initialArgs": {},
"kind": "Component One",
@ -3914,6 +3923,9 @@ describe('PreviewWeb', () => {
},
"component": undefined,
"componentId": "component-two",
"globals": {
"a": "b",
},
"id": "component-two--c",
"initialArgs": {
"foo": "c",

View File

@ -301,6 +301,9 @@ describe('StoryStore', () => {
},
"component": undefined,
"componentId": "component-one",
"globals": {
"a": "b",
},
"id": "component-one--a",
"initialArgs": {
"foo": "a",
@ -471,6 +474,9 @@ describe('StoryStore', () => {
},
"component": undefined,
"componentId": "component-one",
"globals": {
"a": "b",
},
"id": "component-one--a",
"initialArgs": {
"foo": "a",
@ -514,6 +520,9 @@ describe('StoryStore', () => {
},
"component": undefined,
"componentId": "component-one",
"globals": {
"a": "b",
},
"id": "component-one--b",
"initialArgs": {
"foo": "b",
@ -557,6 +566,9 @@ describe('StoryStore', () => {
},
"component": undefined,
"componentId": "component-two",
"globals": {
"a": "b",
},
"id": "component-two--c",
"initialArgs": {
"foo": "c",
@ -847,6 +859,9 @@ describe('StoryStore', () => {
},
"component": undefined,
"componentId": "component-one",
"globals": {
"a": "b",
},
"id": "component-one--a",
"initialArgs": {
"foo": "a",
@ -890,6 +905,9 @@ describe('StoryStore', () => {
},
"component": undefined,
"componentId": "component-one",
"globals": {
"a": "b",
},
"id": "component-one--b",
"initialArgs": {
"foo": "b",
@ -933,6 +951,9 @@ describe('StoryStore', () => {
},
"component": undefined,
"componentId": "component-two",
"globals": {
"a": "b",
},
"id": "component-two--c",
"initialArgs": {
"foo": "c",

View File

@ -323,7 +323,15 @@ export class StoryStore<TRenderer extends Renderer> {
}
return Object.assign(storyAcc, { [key]: value });
},
{ args: story.initialArgs }
{
//
args: story.initialArgs,
globals: {
...this.userGlobals.initialGlobals,
...this.userGlobals.globals,
...story.storyGlobals,
},
}
);
return acc;
},

View File

@ -92,5 +92,6 @@ export const Events = {
await new Promise((resolve) => channel.once(STORY_ARGS_UPDATED, resolve));
await within(canvasElement).findByText(/updated/);
},
tags: ['!vitest'],
// this story can't be reliably tested because the args changes results in renderPhases disrupting test runs
tags: ['!vitest', '!test'],
};

View File

@ -67,5 +67,6 @@ export const Hooks = {
});
await new Promise((resolve) => channel.once(STORY_ARGS_UPDATED, resolve));
},
tags: ['!vitest'],
// this story can't be reliably tested because the args changes results in renderPhases disrupting test runs
tags: ['!vitest', '!test'],
};

View File

@ -44,7 +44,8 @@ export const Events = {
await channel.emit('updateGlobals', { globals: { foo: 'fooValue' } });
await within(canvasElement).findByText('fooValue');
},
tags: ['!vitest'],
// this story can't be reliably tested because the globals changes results in renderPhases disrupting test runs
tags: ['!vitest', '!test'],
};
export const Overrides1 = {

View File

@ -105,4 +105,6 @@ export const ChangeArgs = {
await within(canvasElement).findByText(/New Text/);
await expect(button).toHaveFocus();
},
// this story can't be reliably tested because the args changes results in renderPhases disrupting test runs
tags: ['!vitest', '!test'],
};

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/builder-manager",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Storybook manager builder",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/channels",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/client-logger",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/components",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Core Storybook Components",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/core-common",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/core-events",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Event names used in storybook core",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/core-server",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/csf-tools",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Parse and manipulate CSF and Storybook config files",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/docs-tools",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Shared utility functions for frameworks to implement docs",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/manager-api",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Core Storybook Manager API & Context",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/manager",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Core Storybook UI",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/node-logger",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/preview-api",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/preview",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/router",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Core Storybook Router",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/telemetry",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Telemetry logging for crash reports and usage statistics",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/theming",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Core Storybook Components",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/types",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Core Storybook TS Types",
"keywords": [
"storybook"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/angular",
"version": "8.6.0-alpha.0",
"version": "8.6.0-alpha.3",
"description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.",
"keywords": [
"storybook",
@ -33,7 +33,7 @@
"!src/**/*"
],
"scripts": {
"check": "node ../../../scripts/node_modules/.bin/tsc",
"check": "yarn run -T tsc",
"prep": "rimraf dist && jiti ../../../scripts/prepare/tsc.ts"
},
"dependencies": {
@ -58,27 +58,28 @@
"webpack": "5"
},
"devDependencies": {
"@analogjs/vite-plugin-angular": "^0.2.24",
"@angular-devkit/architect": "^0.1703.0",
"@angular-devkit/build-angular": "^17.3.0",
"@angular-devkit/core": "^17.3.0",
"@angular/animations": "^17.3.0",
"@angular/cli": "^17.3.0",
"@angular/common": "^17.3.0",
"@angular/compiler": "^17.3.0",
"@angular/compiler-cli": "^17.3.0",
"@angular/core": "^17.3.0",
"@angular/forms": "^17.3.0",
"@angular/platform-browser": "^17.3.0",
"@angular/platform-browser-dynamic": "^17.3.0",
"@analogjs/vite-plugin-angular": "^1.12.1",
"@angular-devkit/architect": "^0.1901.1",
"@angular-devkit/build-angular": "^19.1.1",
"@angular-devkit/core": "^19.1.1",
"@angular/animations": "^19.1.1",
"@angular/cli": "^19.1.1",
"@angular/common": "^19.1.1",
"@angular/compiler": "^19.1.1",
"@angular/compiler-cli": "^19.1.1",
"@angular/core": "^19.1.1",
"@angular/forms": "^19.1.1",
"@angular/platform-browser": "^19.1.1",
"@angular/platform-browser-dynamic": "^19.1.1",
"@types/cross-spawn": "^6.0.2",
"@types/node": "^22.0.0",
"@types/tmp": "^0.2.3",
"cross-spawn": "^7.0.3",
"rimraf": "^6.0.1",
"tmp": "^0.2.1",
"typescript": "^5.3.2",
"typescript": "^5.7.3",
"webpack": "5",
"zone.js": "^0.14.2"
"zone.js": "^0.15.0"
},
"peerDependencies": {
"@angular-devkit/architect": ">=0.1500.0 < 0.2000.0",
@ -100,6 +101,9 @@
"peerDependenciesMeta": {
"@angular/cli": {
"optional": true
},
"zone.js": {
"optional": true
}
},
"engines": {

View File

@ -43,6 +43,7 @@ export type StorybookBuilderOptions = JsonObject & {
preserveSymlinks?: boolean;
assets?: AssetPattern[];
sourceMap?: SourceMapUnion;
experimentalZoneless?: boolean;
} & Pick<
// makes sure the option exists
CLIOptions,
@ -104,6 +105,7 @@ const commandBuilder: BuilderHandlerFn<StorybookBuilderOptions> = (
previewUrl,
sourceMap = false,
preserveSymlinks = false,
experimentalZoneless = false,
} = options;
const standaloneOptions: StandaloneBuildOptions = {
@ -124,6 +126,7 @@ const commandBuilder: BuilderHandlerFn<StorybookBuilderOptions> = (
...(assets ? { assets } : {}),
sourceMap,
preserveSymlinks,
experimentalZoneless,
},
tsConfig,
webpackStatsJson,

View File

@ -121,6 +121,11 @@
"type": ["boolean", "object"],
"description": "Configure sourcemaps. See: https://angular.io/guide/workspace-config#source-map-configuration",
"default": false
},
"experimentalZoneless": {
"type": "boolean",
"description": "Experimental: Use zoneless change detection.",
"default": false
}
},
"additionalProperties": false,

View File

@ -40,6 +40,7 @@ export type StorybookBuilderOptions = JsonObject & {
assets?: AssetPattern[];
preserveSymlinks?: boolean;
sourceMap?: SourceMapUnion;
experimentalZoneless?: boolean;
} & Pick<
// makes sure the option exists
CLIOptions,
@ -121,6 +122,7 @@ const commandBuilder: BuilderHandlerFn<StorybookBuilderOptions> = (options, cont
previewUrl,
sourceMap = false,
preserveSymlinks = false,
experimentalZoneless = false,
} = options;
const standaloneOptions: StandaloneOptions = {
@ -146,6 +148,7 @@ const commandBuilder: BuilderHandlerFn<StorybookBuilderOptions> = (options, cont
...(assets ? { assets } : {}),
preserveSymlinks,
sourceMap,
experimentalZoneless,
},
tsConfig,
initialPath,

View File

@ -157,6 +157,11 @@
"type": ["boolean", "object"],
"description": "Configure sourcemaps. See: https://angular.io/guide/workspace-config#source-map-configuration",
"default": false
},
"experimentalZoneless": {
"type": "boolean",
"description": "Experimental: Use zoneless change detection.",
"default": false
}
},
"additionalProperties": false,

View File

@ -20,6 +20,7 @@ export type StandaloneOptions = CLIOptions &
assets?: AssetPattern[];
sourceMap?: SourceMapUnion;
preserveSymlinks?: boolean;
experimentalZoneless?: boolean;
};
angularBuilderContext?: BuilderContext | null;
tsConfig?: string;

View File

@ -1,4 +1,4 @@
import { ApplicationRef, NgModule, enableProdMode } from '@angular/core';
import { ApplicationRef, NgModule } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { BehaviorSubject, Subject } from 'rxjs';
import { stringify } from 'telejson';
@ -14,6 +14,12 @@ type StoryRenderInfo = {
moduleMetadataSnapshot: string;
};
declare global {
const STORYBOOK_ANGULAR_OPTIONS: {
experimentalZoneless: boolean;
};
}
const applicationRefs = new Map<HTMLElement, ApplicationRef>();
/**
@ -96,7 +102,9 @@ export abstract class AbstractRenderer {
const analyzedMetadata = new PropertyExtractor(storyFnAngular.moduleMetadata, component);
const storyUid = targetDOMNode.getAttribute(STORY_UID_ATTRIBUTE);
const storyUid = this.generateStoryUIdFromRawStoryUid(
targetDOMNode.getAttribute(STORY_UID_ATTRIBUTE)
);
const componentSelector = storyUid !== null ? `${targetSelector}[${storyUid}]` : targetSelector;
if (storyUid !== null) {
const element = targetDOMNode.querySelector(targetSelector);
@ -110,14 +118,25 @@ export abstract class AbstractRenderer {
analyzedMetadata,
});
const providers = [
storyPropsProvider(newStoryProps$),
...analyzedMetadata.applicationProviders,
...(storyFnAngular.applicationConfig?.providers ?? []),
];
if (STORYBOOK_ANGULAR_OPTIONS?.experimentalZoneless) {
const { provideExperimentalZonelessChangeDetection } = await import('@angular/core');
if (!provideExperimentalZonelessChangeDetection) {
throw new Error('Experimental zoneless change detection requires Angular 18 or higher');
} else {
providers.unshift(provideExperimentalZonelessChangeDetection());
}
}
const applicationRef = await queueBootstrapping(() => {
return bootstrapApplication(application, {
...storyFnAngular.applicationConfig,
providers: [
storyPropsProvider(newStoryProps$),
...analyzedMetadata.applicationProviders,
...(storyFnAngular.applicationConfig?.providers ?? []),
],
providers,
});
});
@ -143,6 +162,27 @@ export abstract class AbstractRenderer {
return storyIdIsInvalidHtmlTagName ? `sb-${id.replace(invalidHtmlTag, '')}-component` : id;
}
/**
* Angular is unable to handle components that have selectors with accented attributes.
*
* Therefore, stories break when meta's title contains accents.
* https://github.com/storybookjs/storybook/issues/29132
*
* This method filters accents from a given raw id. For example, this method converts
* 'Example/Button with an "é" accent' into 'Example/Button with an "e" accent'.
*
* @memberof AbstractRenderer
* @protected
*/
protected generateStoryUIdFromRawStoryUid(rawStoryUid: string | null) {
if (rawStoryUid === null) {
return rawStoryUid;
}
const accentCharacters = /[\u0300-\u036f]/g;
return rawStoryUid.normalize('NFD').replace(accentCharacters, '');
}
/** Adds DOM element that angular will use as bootstrap component. */
protected initAngularRootElement(targetDOMNode: HTMLElement, targetSelector: string) {
targetDOMNode.innerHTML = '';

View File

@ -26,6 +26,8 @@ describe('RendererFactory', () => {
rootDocstargetDOMNode = global.document.getElementById('root-docs');
(platformBrowserDynamic as any).mockImplementation(platformBrowserDynamicTesting);
vi.spyOn(console, 'log').mockImplementation(() => {});
// @ts-expect-error Ignore
globalThis.STORYBOOK_ANGULAR_OPTIONS = { experimentalZoneless: false };
});
afterEach(() => {

View File

@ -11,6 +11,8 @@ import {
Input,
Output,
Pipe,
input,
output,
} from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
@ -26,7 +28,9 @@ import {
describe('getComponentInputsOutputs', () => {
it('should return empty if no I/O found', () => {
@Component({})
@Component({
standalone: false,
})
class FooComponent {}
expect(getComponentInputsOutputs(FooComponent)).toEqual({
@ -47,11 +51,18 @@ describe('getComponentInputsOutputs', () => {
template: '',
inputs: ['inputInComponentMetadata'],
outputs: ['outputInComponentMetadata'],
standalone: false,
})
class FooComponent {
@Input()
public input: string;
public signalInput = input<string>();
public signalInputAliased = input<string>('signalInputAliased', {
alias: 'signalInputAliasedAlias',
});
@Input('inputPropertyName')
public inputWithBindingPropertyName: string;
@ -60,6 +71,8 @@ describe('getComponentInputsOutputs', () => {
@Output('outputPropertyName')
public outputWithBindingPropertyName = new EventEmitter<Event>();
public signalOutput = output<string>();
}
const fooComponentFactory = resolveComponentFactory(FooComponent);
@ -79,7 +92,9 @@ describe('getComponentInputsOutputs', () => {
],
});
expect(sortByPropName(inputs)).toEqual(sortByPropName(fooComponentFactory.inputs));
expect(sortByPropName(inputs)).toEqual(
sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))
);
expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));
});
@ -88,6 +103,7 @@ describe('getComponentInputsOutputs', () => {
template: '',
inputs: ['input', 'inputWithBindingPropertyName'],
outputs: ['outputWithBindingPropertyName'],
standalone: false,
})
class FooComponent {
@Input()
@ -107,13 +123,16 @@ describe('getComponentInputsOutputs', () => {
const { inputs, outputs } = getComponentInputsOutputs(FooComponent);
expect(sortByPropName(inputs)).toEqual(sortByPropName(fooComponentFactory.inputs));
expect(sortByPropName(inputs)).toEqual(
sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))
);
expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));
});
it('should return I/O in the presence of multiple decorators', () => {
@Component({
template: '',
standalone: false,
})
class FooComponent {
@Input()
@ -137,13 +156,16 @@ describe('getComponentInputsOutputs', () => {
outputs: [],
});
expect(sortByPropName(inputs)).toEqual(sortByPropName(fooComponentFactory.inputs));
expect(sortByPropName(inputs)).toEqual(
sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))
);
expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));
});
it('should return I/O with extending classes', () => {
@Component({
template: '',
standalone: false,
})
class BarComponent {
@Input()
@ -155,6 +177,7 @@ describe('getComponentInputsOutputs', () => {
@Component({
template: '',
standalone: false,
})
class FooComponent extends BarComponent {
@Input()
@ -177,7 +200,9 @@ describe('getComponentInputsOutputs', () => {
outputs: [],
});
expect(sortByPropName(inputs)).toEqual(sortByPropName(fooComponentFactory.inputs));
expect(sortByPropName(inputs)).toEqual(
sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))
);
expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));
});
});

View File

@ -16,15 +16,13 @@ import { PropertyExtractor } from './PropertyExtractor';
const TEST_TOKEN = new InjectionToken('testToken');
const TestTokenProvider = { provide: TEST_TOKEN, useValue: 123 };
const TestService = Injectable()(class {});
const TestComponent1 = Component({})(class {});
const TestComponent2 = Component({})(class {});
const StandaloneTestComponent = Component({ standalone: true })(class {});
const StandaloneTestDirective = Directive({ standalone: true })(class {});
const MixedTestComponent1 = Component({ standalone: true })(
class extends StandaloneTestComponent {}
);
const MixedTestComponent2 = Component({})(class extends MixedTestComponent1 {});
const MixedTestComponent3 = Component({ standalone: true })(class extends MixedTestComponent2 {});
const TestComponent1 = Component({ standalone: false })(class {});
const TestComponent2 = Component({ standalone: false })(class {});
const StandaloneTestComponent = Component({})(class {});
const StandaloneTestDirective = Directive({})(class {});
const MixedTestComponent1 = Component({})(class extends StandaloneTestComponent {});
const MixedTestComponent2 = Component({ standalone: false })(class extends MixedTestComponent1 {});
const MixedTestComponent3 = Component({})(class extends MixedTestComponent2 {});
const TestModuleWithDeclarations = NgModule({ declarations: [TestComponent1] })(class {});
const TestModuleWithImportsAndProviders = NgModule({
imports: [TestModuleWithDeclarations],

View File

@ -22,9 +22,6 @@ import { global } from '@storybook/global';
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/** Zone JS is required by Angular itself. */
import 'zone.js';
// Included with Angular CLI.
/** APPLICATION IMPORTS */

View File

@ -3,7 +3,6 @@ import { PresetProperty } from 'storybook/internal/types';
import { dirname, join } from 'node:path';
import { StandaloneOptions } from './builders/utils/standalone-options';
import { StorybookConfig } from './types';
const getAbsolutePath = <I extends string>(input: I): I =>
dirname(require.resolve(join(input, 'package.json'))) as any;

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