diff --git a/.github/workflows/danger-js.yml b/.github/workflows/danger-js.yml index 40b6466fd0c9..f83519953b4b 100644 --- a/.github/workflows/danger-js.yml +++ b/.github/workflows/danger-js.yml @@ -1,6 +1,19 @@ on: pull_request: - types: [opened, synchronize, reopened, labeled, unlabeled, edited] + types: + - opened + - synchronize + - reopened + - labeled + - unlabeled + - edited + branches: + - main + - next + +concurrency: + group: ${{ github.workflow }}-${{ github.event.number }} + cancel-in-progress: true name: Danger JS jobs: diff --git a/.github/workflows/prepare-patch-release.yml b/.github/workflows/prepare-patch-release.yml index c3f38d598364..20a4e24d023e 100644 --- a/.github/workflows/prepare-patch-release.yml +++ b/.github/workflows/prepare-patch-release.yml @@ -144,8 +144,8 @@ jobs: gh pr create \ --repo "${{github.repository }}" \ --title "Release: Patch ${{ steps.versions.outputs.next }}" \ + --label "release" \ --base latest-release \ - --label "maintenance" --head version-patch-from-${{ steps.versions.outputs.current }} \ --body "${{ steps.description.outputs.description }}" fi diff --git a/.github/workflows/prepare-prerelease.yml b/.github/workflows/prepare-prerelease.yml index e1d250575832..bf387d464ccf 100644 --- a/.github/workflows/prepare-prerelease.yml +++ b/.github/workflows/prepare-prerelease.yml @@ -138,15 +138,18 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | + RELEASE_TYPE=${{ inputs.release-type || 'prerelease' }} + CAPITALIZED_RELEASE_TYPE=${RELEASE_TYPE^} if PR_STATE=$(gh pr view --json state --jq .state 2>/dev/null) && [[ -n "$PR_STATE" && "$PR_STATE" == *"OPEN"* ]]; then gh pr edit \ --repo "${{github.repository }}" \ - --title "Bump version on \`next\`: ${{ inputs.release-type || 'prerelease' }} ${{ inputs.pre-id && format('({0})', inputs.pre-id) }} from ${{ steps.bump-version.outputs.current-version }} to ${{ steps.bump-version.outputs.next-version }}" \ + --title "Release: $CAPITALIZED_RELEASE_TYPE ${{ inputs.pre-id && format('{0} ', inputs.pre-id) }}${{ steps.bump-version.outputs.next-version }}" \ --body "${{ steps.description.outputs.description }}" else gh pr create \ --repo "${{github.repository }}"\ - --title "Bump version on \`next\`: ${{ inputs.release-type || 'prerelease' }} ${{ inputs.pre-id && format('({0})', inputs.pre-id) }} from ${{ steps.bump-version.outputs.current-version }} to ${{ steps.bump-version.outputs.next-version }}" \ + --title "Release: $CAPITALIZED_RELEASE_TYPE ${{ inputs.pre-id && format('{0} ', inputs.pre-id) }}${{ steps.bump-version.outputs.next-version }}" \ + --label "release" \ --base next-release \ --head version-prerelease-from-${{ steps.bump-version.outputs.current-version }} \ --body "${{ steps.description.outputs.description }}" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 329823876e9b..5dd070b1fe1b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -119,6 +119,30 @@ jobs: git merge ${{ github.ref_name }} git push origin ${{ steps.target.outputs.target }} + - name: Sync CHANGELOG.md from `main` to `next` + if: github.ref_name == 'latest-release' + working-directory: . + run: | + git fetch origin next + git checkout next + git pull + git checkout origin/main ./CHANGELOG.md + git add ./CHANGELOG.md + git commit -m "Update CHANGELOG.md for v${{ steps.version.outputs.current-version }}" + git push origin next + + - name: Sync versions/next.json from `next` to `main` + if: github.ref_name == 'next-release' + working-directory: . + run: | + git fetch origin main + git checkout main + git pull + git checkout origin/next ./docs/versions/next.json + git add ./docs/versions/next.json + git commit -m "Update versions/next.json for v${{ steps.version.outputs.current-version }}" + git push origin main + # Force push from next to main if it is not a prerelease, and this release is from next-release # This happens when eg. next has been tracking 7.1.0-alpha.X, and now we want to release 7.1.0 # This will keep release-next, next and main all tracking v7.1.0 diff --git a/.github/workflows/tests-unit.yml b/.github/workflows/tests-unit.yml index 038f0bc08730..6c355ec1714b 100644 --- a/.github/workflows/tests-unit.yml +++ b/.github/workflows/tests-unit.yml @@ -13,13 +13,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest] + os: [windows-latest] node_version: [16] - include: - - os: macos-latest - node_version: 16 - - os: windows-latest - node_version: 16 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cf3986f8fcb..ec7c86066743 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.0.26 + +- Next.js: Fix next/image usage in latest Next.js release - [#23296](https://github.com/storybookjs/storybook/pull/23296), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! +- NextJS: Fix `useParams` support - [#22946](https://github.com/storybookjs/storybook/pull/22946), thanks [@gitstart-storybook](https://github.com/gitstart-storybook)! +- NextJS: Allow disabling next/image lazy loading - [#21909](https://github.com/storybookjs/storybook/pull/21909), thanks [@martinnabhan](https://github.com/martinnabhan) + ## 7.0.25 - CLI: Fix pnp paths logic in storybook metadata - [#23259](https://github.com/storybookjs/storybook/pull/23259), thanks [@yannbf](https://github.com/yannbf)! diff --git a/code/addons/a11y/package.json b/code/addons/a11y/package.json index b0ca705152a9..e56114cfdba8 100644 --- a/code/addons/a11y/package.json +++ b/code/addons/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-a11y", - "version": "7.0.25", + "version": "7.0.26", "description": "Test component compliance with web accessibility standards", "keywords": [ "a11y", @@ -63,16 +63,16 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/addon-highlight": "7.0.25", - "@storybook/channels": "7.0.25", - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/core-events": "7.0.25", + "@storybook/addon-highlight": "7.0.26", + "@storybook/channels": "7.0.26", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/core-events": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/theming": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/theming": "7.0.26", + "@storybook/types": "7.0.26", "axe-core": "^4.2.0", "lodash": "^4.17.21", "react-resize-detector": "^7.1.2" diff --git a/code/addons/actions/package.json b/code/addons/actions/package.json index 0ff97288990e..10c04cfc109f 100644 --- a/code/addons/actions/package.json +++ b/code/addons/actions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-actions", - "version": "7.0.25", + "version": "7.0.26", "description": "Get UI feedback when an action is performed on an interactive element", "keywords": [ "storybook", @@ -80,14 +80,14 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/core-events": "7.0.25", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/core-events": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/theming": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/theming": "7.0.26", + "@storybook/types": "7.0.26", "dequal": "^2.0.2", "lodash": "^4.17.21", "polished": "^4.2.2", diff --git a/code/addons/backgrounds/package.json b/code/addons/backgrounds/package.json index 6a9554c9b601..f392e339cd81 100644 --- a/code/addons/backgrounds/package.json +++ b/code/addons/backgrounds/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-backgrounds", - "version": "7.0.25", + "version": "7.0.26", "description": "Switch backgrounds to view components in different settings", "keywords": [ "addon", @@ -76,14 +76,14 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/core-events": "7.0.25", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/core-events": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/theming": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/theming": "7.0.26", + "@storybook/types": "7.0.26", "memoizerific": "^1.11.3", "ts-dedent": "^2.0.0" }, diff --git a/code/addons/controls/package.json b/code/addons/controls/package.json index 8dfac3481861..9e33fbb4d7af 100644 --- a/code/addons/controls/package.json +++ b/code/addons/controls/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-controls", - "version": "7.0.25", + "version": "7.0.26", "description": "Interact with component inputs dynamically in the Storybook UI", "keywords": [ "addon", @@ -68,15 +68,15 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/blocks": "7.0.25", - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/core-common": "7.0.25", - "@storybook/manager-api": "7.0.25", - "@storybook/node-logger": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/theming": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/blocks": "7.0.26", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/core-common": "7.0.26", + "@storybook/manager-api": "7.0.26", + "@storybook/node-logger": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/theming": "7.0.26", + "@storybook/types": "7.0.26", "lodash": "^4.17.21", "ts-dedent": "^2.0.0" }, diff --git a/code/addons/docs/package.json b/code/addons/docs/package.json index d32063f22fca..c6175e4259df 100644 --- a/code/addons/docs/package.json +++ b/code/addons/docs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-docs", - "version": "7.0.25", + "version": "7.0.26", "description": "Document component usage and properties in Markdown", "keywords": [ "addon", @@ -101,19 +101,19 @@ "@babel/plugin-transform-react-jsx": "^7.19.0", "@jest/transform": "^29.3.1", "@mdx-js/react": "^2.1.5", - "@storybook/blocks": "7.0.25", - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/csf-plugin": "7.0.25", - "@storybook/csf-tools": "7.0.25", + "@storybook/blocks": "7.0.26", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/csf-plugin": "7.0.26", + "@storybook/csf-tools": "7.0.26", "@storybook/global": "^5.0.0", "@storybook/mdx2-csf": "^1.0.0", - "@storybook/node-logger": "7.0.25", - "@storybook/postinstall": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/react-dom-shim": "7.0.25", - "@storybook/theming": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/node-logger": "7.0.26", + "@storybook/postinstall": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/react-dom-shim": "7.0.26", + "@storybook/theming": "7.0.26", + "@storybook/types": "7.0.26", "fs-extra": "^11.1.0", "remark-external-links": "^8.0.0", "remark-slug": "^6.0.0", diff --git a/code/addons/essentials/package.json b/code/addons/essentials/package.json index 6de74611f93c..fb8d72a09c06 100644 --- a/code/addons/essentials/package.json +++ b/code/addons/essentials/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-essentials", - "version": "7.0.25", + "version": "7.0.26", "description": "Curated addons to bring out the best of Storybook", "keywords": [ "addon", @@ -119,23 +119,23 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/addon-actions": "7.0.25", - "@storybook/addon-backgrounds": "7.0.25", - "@storybook/addon-controls": "7.0.25", - "@storybook/addon-docs": "7.0.25", - "@storybook/addon-highlight": "7.0.25", - "@storybook/addon-measure": "7.0.25", - "@storybook/addon-outline": "7.0.25", - "@storybook/addon-toolbars": "7.0.25", - "@storybook/addon-viewport": "7.0.25", - "@storybook/core-common": "7.0.25", - "@storybook/manager-api": "7.0.25", - "@storybook/node-logger": "7.0.25", - "@storybook/preview-api": "7.0.25", + "@storybook/addon-actions": "7.0.26", + "@storybook/addon-backgrounds": "7.0.26", + "@storybook/addon-controls": "7.0.26", + "@storybook/addon-docs": "7.0.26", + "@storybook/addon-highlight": "7.0.26", + "@storybook/addon-measure": "7.0.26", + "@storybook/addon-outline": "7.0.26", + "@storybook/addon-toolbars": "7.0.26", + "@storybook/addon-viewport": "7.0.26", + "@storybook/core-common": "7.0.26", + "@storybook/manager-api": "7.0.26", + "@storybook/node-logger": "7.0.26", + "@storybook/preview-api": "7.0.26", "ts-dedent": "^2.0.0" }, "devDependencies": { - "@storybook/vue": "7.0.25", + "@storybook/vue": "7.0.26", "typescript": "^4.9.3" }, "peerDependencies": { diff --git a/code/addons/gfm/package.json b/code/addons/gfm/package.json index 4116c168eeaa..b8889d994602 100644 --- a/code/addons/gfm/package.json +++ b/code/addons/gfm/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-mdx-gfm", - "version": "7.0.25", + "version": "7.0.26", "description": "GitHub Flavored Markdown in Storybook", "keywords": [ "addon", @@ -51,7 +51,7 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/node-logger": "7.0.25", + "@storybook/node-logger": "7.0.26", "remark-gfm": "^3.0.1", "ts-dedent": "^2.0.0" }, diff --git a/code/addons/highlight/package.json b/code/addons/highlight/package.json index 94cb5aeb2d82..302fe9cc4da3 100644 --- a/code/addons/highlight/package.json +++ b/code/addons/highlight/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-highlight", - "version": "7.0.25", + "version": "7.0.26", "description": "Highlight DOM nodes within your stories", "keywords": [ "storybook-addons", @@ -61,9 +61,9 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/core-events": "7.0.25", + "@storybook/core-events": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/preview-api": "7.0.25" + "@storybook/preview-api": "7.0.26" }, "devDependencies": { "@types/webpack-env": "^1.16.0", diff --git a/code/addons/interactions/package.json b/code/addons/interactions/package.json index 7892a9e9c360..df001e4a9bb2 100644 --- a/code/addons/interactions/package.json +++ b/code/addons/interactions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-interactions", - "version": "7.0.25", + "version": "7.0.26", "description": "Automate, test and debug user interactions", "keywords": [ "storybook-addons", @@ -72,16 +72,16 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/core-common": "7.0.25", - "@storybook/core-events": "7.0.25", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/core-common": "7.0.26", + "@storybook/core-events": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/instrumenter": "7.0.25", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/theming": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/instrumenter": "7.0.26", + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/theming": "7.0.26", + "@storybook/types": "7.0.26", "jest-mock": "^27.0.6", "polished": "^4.2.2", "ts-dedent": "^2.2.0" diff --git a/code/addons/jest/package.json b/code/addons/jest/package.json index ca1b7550b5d5..07ef33231218 100644 --- a/code/addons/jest/package.json +++ b/code/addons/jest/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-jest", - "version": "7.0.25", + "version": "7.0.26", "description": "React storybook addon that show component jest report", "keywords": [ "addon", @@ -70,13 +70,13 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/core-events": "7.0.25", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/core-events": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/theming": "7.0.25", + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/theming": "7.0.26", "react-resize-detector": "^7.1.2", "upath": "^1.2.0" }, diff --git a/code/addons/links/package.json b/code/addons/links/package.json index 423e8741c2ef..c4be960b8a48 100644 --- a/code/addons/links/package.json +++ b/code/addons/links/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-links", - "version": "7.0.25", + "version": "7.0.26", "description": "Link stories together to build demos and prototypes with your UI components", "keywords": [ "addon", @@ -80,14 +80,14 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/client-logger": "7.0.25", - "@storybook/core-events": "7.0.25", + "@storybook/client-logger": "7.0.26", + "@storybook/core-events": "7.0.26", "@storybook/csf": "^0.1.0", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/router": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/router": "7.0.26", + "@storybook/types": "7.0.26", "prop-types": "^15.7.2", "ts-dedent": "^2.0.0" }, diff --git a/code/addons/measure/package.json b/code/addons/measure/package.json index e8f8fbdd33d8..d5e7a2c8c6c2 100644 --- a/code/addons/measure/package.json +++ b/code/addons/measure/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-measure", - "version": "7.0.25", + "version": "7.0.26", "description": "Inspect layouts by visualizing the box model", "keywords": [ "storybook-addons", @@ -75,13 +75,13 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/core-events": "7.0.25", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/core-events": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/types": "7.0.25" + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/types": "7.0.26" }, "devDependencies": { "typescript": "~4.9.3" diff --git a/code/addons/outline/package.json b/code/addons/outline/package.json index 31024e1b9520..5cf20eedf35d 100644 --- a/code/addons/outline/package.json +++ b/code/addons/outline/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-outline", - "version": "7.0.25", + "version": "7.0.26", "description": "Outline all elements with CSS to help with layout placement and alignment", "keywords": [ "storybook-addons", @@ -78,13 +78,13 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/core-events": "7.0.25", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/core-events": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/types": "7.0.26", "ts-dedent": "^2.0.0" }, "devDependencies": { diff --git a/code/addons/storyshots-core/package.json b/code/addons/storyshots-core/package.json index 3576ca8138b2..ae5352b5a884 100644 --- a/code/addons/storyshots-core/package.json +++ b/code/addons/storyshots-core/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storyshots", - "version": "7.0.25", + "version": "7.0.26", "description": "Take a code snapshot of every story automatically with Jest", "keywords": [ "addon", @@ -37,12 +37,12 @@ "dependencies": { "@jest/transform": "^29.3.1", "@storybook/babel-plugin-require-context-hook": "1.0.1", - "@storybook/client-api": "7.0.25", - "@storybook/core-common": "7.0.25", - "@storybook/core-webpack": "7.0.25", + "@storybook/client-api": "7.0.26", + "@storybook/core-common": "7.0.26", + "@storybook/core-webpack": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/preview-api": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/preview-api": "7.0.26", + "@storybook/types": "7.0.26", "@types/glob": "^7.1.3", "@types/jest-specific-snapshot": "^0.5.6", "glob": "^8.1.0", @@ -57,11 +57,11 @@ "@angular/core": "^13.3.6", "@angular/platform-browser-dynamic": "^13.3.6", "@emotion/jest": "^11.8.0", - "@storybook/addon-docs": "7.0.25", - "@storybook/angular": "7.0.25", - "@storybook/react": "7.0.25", - "@storybook/vue": "7.0.25", - "@storybook/vue3": "7.0.25", + "@storybook/addon-docs": "7.0.26", + "@storybook/angular": "7.0.26", + "@storybook/react": "7.0.26", + "@storybook/vue": "7.0.26", + "@storybook/vue3": "7.0.26", "babel-loader": "^9.1.2", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/code/addons/storyshots-puppeteer/package.json b/code/addons/storyshots-puppeteer/package.json index ebe8ffcc5117..4de1e18b9b7c 100644 --- a/code/addons/storyshots-puppeteer/package.json +++ b/code/addons/storyshots-puppeteer/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storyshots-puppeteer", - "version": "7.0.25", + "version": "7.0.26", "description": "Image snapshots addition to StoryShots based on puppeteer", "keywords": [ "addon", @@ -36,8 +36,8 @@ "dependencies": { "@axe-core/puppeteer": "^4.2.0", "@storybook/csf": "^0.1.0", - "@storybook/node-logger": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/node-logger": "7.0.26", + "@storybook/types": "7.0.26", "@types/jest-image-snapshot": "^5.1.0", "jest-image-snapshot": "^6.0.0" }, @@ -49,7 +49,7 @@ "rimraf": "^3.0.2" }, "peerDependencies": { - "@storybook/addon-storyshots": "7.0.25", + "@storybook/addon-storyshots": "7.0.26", "puppeteer": ">=2.0.0" }, "peerDependenciesMeta": { diff --git a/code/addons/storysource/package.json b/code/addons/storysource/package.json index 98e49006b44b..c03bc69e1dd8 100644 --- a/code/addons/storysource/package.json +++ b/code/addons/storysource/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storysource", - "version": "7.0.25", + "version": "7.0.26", "description": "View a story’s source code to see how it works and paste into your app", "keywords": [ "addon", @@ -53,13 +53,13 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/router": "7.0.25", - "@storybook/source-loader": "7.0.25", - "@storybook/theming": "7.0.25", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/router": "7.0.26", + "@storybook/source-loader": "7.0.26", + "@storybook/theming": "7.0.26", "estraverse": "^5.2.0", "prop-types": "^15.7.2", "react-syntax-highlighter": "^15.5.0" diff --git a/code/addons/toolbars/package.json b/code/addons/toolbars/package.json index ab90b87a1766..91c3bab79681 100644 --- a/code/addons/toolbars/package.json +++ b/code/addons/toolbars/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-toolbars", - "version": "7.0.25", + "version": "7.0.26", "description": "Create your own toolbar items that control story rendering", "keywords": [ "addon", @@ -68,11 +68,11 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/theming": "7.0.25" + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/theming": "7.0.26" }, "devDependencies": { "typescript": "~4.9.3" diff --git a/code/addons/viewport/package.json b/code/addons/viewport/package.json index d378c8da17d7..0bb9281be4e5 100644 --- a/code/addons/viewport/package.json +++ b/code/addons/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-viewport", - "version": "7.0.25", + "version": "7.0.26", "description": "Build responsive components by adjusting Storybook’s viewport size and orientation", "keywords": [ "addon", @@ -73,13 +73,13 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/client-logger": "7.0.25", - "@storybook/components": "7.0.25", - "@storybook/core-events": "7.0.25", + "@storybook/client-logger": "7.0.26", + "@storybook/components": "7.0.26", + "@storybook/core-events": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/theming": "7.0.25", + "@storybook/manager-api": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/theming": "7.0.26", "memoizerific": "^1.11.3", "prop-types": "^15.7.2" }, diff --git a/code/e2e-tests/framework-nextjs.spec.ts b/code/e2e-tests/framework-nextjs.spec.ts index c2c40733c454..d5519251da39 100644 --- a/code/e2e-tests/framework-nextjs.spec.ts +++ b/code/e2e-tests/framework-nextjs.spec.ts @@ -21,6 +21,32 @@ test.describe('Next.js', () => { await new SbPage(page).waitUntilLoaded(); }); + test.describe('next/image', () => { + let sbPage: SbPage; + + test.beforeEach(async ({ page }) => { + sbPage = new SbPage(page); + }); + + // TODO: Test is flaky, investigate why + test.skip('should lazy load images by default', async () => { + await sbPage.navigateToStory('frameworks/nextjs/Image', 'lazy'); + + const img = sbPage.previewRoot().locator('img'); + + expect(await img.evaluate((image) => image.complete)).toBeFalsy(); + }); + + // TODO: Test is flaky, investigate why + test.skip('should eager load images when loading parameter is set to eager', async () => { + await sbPage.navigateToStory('frameworks/nextjs/Image', 'eager'); + + const img = sbPage.previewRoot().locator('img'); + + expect(await img.evaluate((image) => image.complete)).toBeTruthy(); + }); + }); + test.describe('next/navigation', () => { let root: Locator; let sbPage: SbPage; diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json index eade72067f44..2b06c00e875e 100644 --- a/code/frameworks/angular/package.json +++ b/code/frameworks/angular/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/angular", - "version": "7.0.25", + "version": "7.0.26", "description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.", "keywords": [ "storybook", @@ -36,21 +36,21 @@ "prep": "../../../scripts/prepare/tsc.ts" }, "dependencies": { - "@storybook/builder-webpack5": "7.0.25", - "@storybook/cli": "7.0.25", - "@storybook/client-logger": "7.0.25", - "@storybook/core-client": "7.0.25", - "@storybook/core-common": "7.0.25", - "@storybook/core-events": "7.0.25", - "@storybook/core-server": "7.0.25", - "@storybook/core-webpack": "7.0.25", - "@storybook/docs-tools": "7.0.25", + "@storybook/builder-webpack5": "7.0.26", + "@storybook/cli": "7.0.26", + "@storybook/client-logger": "7.0.26", + "@storybook/core-client": "7.0.26", + "@storybook/core-common": "7.0.26", + "@storybook/core-events": "7.0.26", + "@storybook/core-server": "7.0.26", + "@storybook/core-webpack": "7.0.26", + "@storybook/docs-tools": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.0.25", - "@storybook/node-logger": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/telemetry": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/manager-api": "7.0.26", + "@storybook/node-logger": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/telemetry": "7.0.26", + "@storybook/types": "7.0.26", "@types/node": "^16.0.0", "@types/react": "^16.14.34", "@types/react-dom": "^16.9.14", diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json index 470ab1bd7fcb..4add1b85d005 100644 --- a/code/frameworks/ember/package.json +++ b/code/frameworks/ember/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/ember", - "version": "7.0.25", + "version": "7.0.26", "description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember", "bugs": { @@ -31,12 +31,12 @@ "prep": "../../../scripts/prepare/tsc.ts" }, "dependencies": { - "@storybook/builder-webpack5": "7.0.25", - "@storybook/core-common": "7.0.25", - "@storybook/docs-tools": "7.0.25", + "@storybook/builder-webpack5": "7.0.26", + "@storybook/core-common": "7.0.26", + "@storybook/docs-tools": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/preview-api": "7.0.25", - "@storybook/types": "7.0.25", + "@storybook/preview-api": "7.0.26", + "@storybook/types": "7.0.26", "ts-dedent": "^2.0.0" }, "devDependencies": { diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index e9f77587e13c..0667aa2db3c3 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-vite", - "version": "7.0.25", + "version": "7.0.26", "description": "Storybook for HTML and Vite: Develop HTML in isolation with Hot Reloading.", "keywords": [ "storybook" @@ -47,15 +47,15 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/addons": "7.0.25", - "@storybook/builder-vite": "7.0.25", - "@storybook/channel-postmessage": "7.0.25", - "@storybook/channel-websocket": "7.0.25", - "@storybook/client-api": "7.0.25", - "@storybook/core-server": "7.0.25", - "@storybook/html": "7.0.25", - "@storybook/node-logger": "7.0.25", - "@storybook/preview-web": "7.0.25", + "@storybook/addons": "7.0.26", + "@storybook/builder-vite": "7.0.26", + "@storybook/channel-postmessage": "7.0.26", + "@storybook/channel-websocket": "7.0.26", + "@storybook/client-api": "7.0.26", + "@storybook/core-server": "7.0.26", + "@storybook/html": "7.0.26", + "@storybook/node-logger": "7.0.26", + "@storybook/preview-web": "7.0.26", "magic-string": "^0.27.0" }, "devDependencies": { diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json index d7503b3522d4..dd700556b94b 100644 --- a/code/frameworks/html-webpack5/package.json +++ b/code/frameworks/html-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-webpack5", - "version": "7.0.25", + "version": "7.0.26", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" @@ -47,11 +47,11 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@storybook/builder-webpack5": "7.0.25", - "@storybook/core-common": "7.0.25", + "@storybook/builder-webpack5": "7.0.26", + "@storybook/core-common": "7.0.26", "@storybook/global": "^5.0.0", - "@storybook/html": "7.0.25", - "@storybook/preset-html-webpack": "7.0.25", + "@storybook/html": "7.0.26", + "@storybook/preset-html-webpack": "7.0.26", "@types/node": "^16.0.0" }, "devDependencies": { diff --git a/code/frameworks/nextjs/README.md b/code/frameworks/nextjs/README.md index b491cf2205f1..ae7534835dc9 100644 --- a/code/frameworks/nextjs/README.md +++ b/code/frameworks/nextjs/README.md @@ -28,7 +28,7 @@ - [Set `nextjs.appDirectory` to `true`](#set-nextjsappdirectory-to-true) - [Overriding defaults](#overriding-defaults-1) - [Global Defaults](#global-defaults-1) - - [`useSelectedLayoutSegment` and `useSelectedLayoutSegments` hook](#useselectedlayoutsegment-and-useselectedlayoutsegments-hook) + - [`useSelectedLayoutSegment` `useSelectedLayoutSegments` and `useParams` hook](#useselectedlayoutsegment-useselectedlayoutsegments-and-useparams-hook) - [Default Navigation Context](#default-navigation-context) - [Actions Integration Caveats](#actions-integration-caveats-1) - [Next.js Head](#nextjs-head) @@ -159,12 +159,16 @@ export default { framework: { name: '@storybook/nextjs', options: { + image: { + loading: 'eager', + }, nextConfigPath: path.resolve(__dirname, '../next.config.js'), }, }, }; ``` +- `image`: Props to pass to every instance of `next/image` - `nextConfigPath`: The absolute path to the `next.config.js` ### Next.js's Image Component @@ -499,9 +503,9 @@ export const parameters = { }; ``` -#### `useSelectedLayoutSegment` and `useSelectedLayoutSegments` hook +#### `useSelectedLayoutSegment` `useSelectedLayoutSegments` and `useParams` hook -The `useSelectedLayoutSegment` and `useSelectedLayoutSegments` hooks are supported in Storybook. You have to set the `nextjs.navigation.segments` parameter to return the segments you want to use. +The `useSelectedLayoutSegment` `useSelectedLayoutSegments` and `useParams` hooks are supported in Storybook. You have to set the `nextjs.navigation.segments` parameter to return the segments or the params you want to use. ```js // SomeComponentThatUsesTheNavigation.stories.js @@ -522,11 +526,46 @@ export default { export const Example = {}; // SomeComponentThatUsesTheNavigation.js -import { useSelectedLayoutSegment, useSelectedLayoutSegments } from 'next/navigation'; +import { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation'; export default function SomeComponentThatUsesTheNavigation() { const segment = useSelectedLayoutSegment(); // dashboard const segments = useSelectedLayoutSegments(); // ["dashboard", "analytics"] + const params = useParams(); // {} + ... +} +``` + +To use `useParams`, you have to use a two string elements array for a segment, the first array element is the param key and the second array element is the param value. + +```js +// SomeComponentThatUsesParams.stories.js +import SomeComponentThatUsesParams from './SomeComponentThatUsesParams'; + +export default { + component: SomeComponentThatUsesParams, + parameters: { + nextjs: { + appDirectory: true, + navigation: { + segments: [ + ['slug', 'hello'], + ['framework', 'nextjs'], + ] + }, + }, + }, +}; + +export const Example = {}; + +// SomeComponentThatUsesParams.js +import { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation'; + +export default function SomeComponentThatUsesParams() { + const segment = useSelectedLayoutSegment(); // hello + const segments = useSelectedLayoutSegments(); // ["hello", "nextjs"] + const params = useParams(); // { slug: "hello", framework: "nextjs" } ... } ``` diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index 54fad31ab7d7..8fcaadbffc7d 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/nextjs", - "version": "7.0.25", + "version": "7.0.26", "description": "Storybook for Next.js", "keywords": [ "storybook", @@ -70,13 +70,13 @@ "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.0", "@babel/runtime": "^7.21.0", - "@storybook/addon-actions": "7.0.25", - "@storybook/builder-webpack5": "7.0.25", - "@storybook/core-common": "7.0.25", - "@storybook/node-logger": "7.0.25", - "@storybook/preset-react-webpack": "7.0.25", - "@storybook/preview-api": "7.0.25", - "@storybook/react": "7.0.25", + "@storybook/addon-actions": "7.0.26", + "@storybook/builder-webpack5": "7.0.26", + "@storybook/core-common": "7.0.26", + "@storybook/node-logger": "7.0.26", + "@storybook/preset-react-webpack": "7.0.26", + "@storybook/preview-api": "7.0.26", + "@storybook/react": "7.0.26", "@types/node": "^16.0.0", "css-loader": "^6.7.3", "find-up": "^5.0.0", @@ -102,7 +102,7 @@ "@types/babel__core": "^7", "@types/babel__plugin-transform-runtime": "^7", "@types/babel__preset-env": "^7", - "next": "^13.2.4", + "next": "^13.4.8", "typescript": "^4.9.3", "webpack": "^5.65.0" }, @@ -143,8 +143,17 @@ "./src/preset.ts", "./src/preview.tsx", "./src/next-image-loader-stub.ts", + "./src/images/context.ts", + "./src/images/next-future-image.tsx", + "./src/images/next-legacy-image.tsx", + "./src/images/next-image.tsx", "./src/font/webpack/loader/storybook-nextjs-font-loader.ts" ], + "externals": [ + "sb-original/next/image", + "sb-original/next/future/image", + "sb-original/next/legacy/image" + ], "platform": "node" }, "gitHead": "9fb2573aa274f3f69d3358050e8df9c903e8245f" diff --git a/code/frameworks/nextjs/src/images/context.ts b/code/frameworks/nextjs/src/images/context.ts new file mode 100644 index 000000000000..81f8cf2d6c82 --- /dev/null +++ b/code/frameworks/nextjs/src/images/context.ts @@ -0,0 +1,16 @@ +import { createContext } from 'react'; +import type { ImageProps, StaticImageData } from 'next/image'; +import type { ImageProps as LegacyImageProps } from 'next/legacy/image'; + +// StaticRequire needs to be in scope for the TypeScript compiler to work. +// See: https://github.com/microsoft/TypeScript/issues/5711 +// Since next/image doesn't export StaticRequire we need to re-define it here and set src's type to it. +interface StaticRequire { + default: StaticImageData; +} + +declare type StaticImport = StaticRequire | StaticImageData; + +export const ImageContext = createContext< + Partial & { src: string | StaticImport }> & Omit +>({}); diff --git a/code/frameworks/nextjs/src/images/decorator.tsx b/code/frameworks/nextjs/src/images/decorator.tsx new file mode 100644 index 000000000000..f0917b3a3b50 --- /dev/null +++ b/code/frameworks/nextjs/src/images/decorator.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import type { Addon_StoryContext } from '@storybook/types'; +import { ImageContext } from './context'; + +export const ImageDecorator = ( + Story: React.FC, + { parameters }: Addon_StoryContext +): React.ReactNode => { + if (!parameters.nextjs?.image) { + return ; + } + + return ( + + + + ); +}; diff --git a/code/frameworks/nextjs/src/images/next-future-image.tsx b/code/frameworks/nextjs/src/images/next-future-image.tsx new file mode 100644 index 000000000000..559d2e857d39 --- /dev/null +++ b/code/frameworks/nextjs/src/images/next-future-image.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import type * as _NextImage from 'next/image'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore import is aliased in webpack config +import OriginalNextFutureImage from 'sb-original/next/future/image'; +import { ImageContext } from './context'; +import { defaultLoader } from './next-image-default-loader'; + +function NextFutureImage(props: _NextImage.ImageProps) { + const imageParameters = React.useContext(ImageContext); + + return ( + + ); +} + +export default NextFutureImage; diff --git a/code/frameworks/nextjs/src/images/next-image-default-loader.tsx b/code/frameworks/nextjs/src/images/next-image-default-loader.tsx new file mode 100644 index 000000000000..6029390979ac --- /dev/null +++ b/code/frameworks/nextjs/src/images/next-image-default-loader.tsx @@ -0,0 +1,28 @@ +import type * as _NextImage from 'next/image'; + +export const defaultLoader = ({ src, width, quality }: _NextImage.ImageLoaderProps) => { + const missingValues = []; + if (!src) { + missingValues.push('src'); + } + + if (!width) { + missingValues.push('width'); + } + + if (missingValues.length > 0) { + throw new Error( + `Next Image Optimization requires ${missingValues.join( + ', ' + )} to be provided. Make sure you pass them as props to the \`next/image\` component. Received: ${JSON.stringify( + { + src, + width, + quality, + } + )}` + ); + } + + return `${src}?w=${width}&q=${quality ?? 75}`; +}; diff --git a/code/frameworks/nextjs/src/images/next-image-stub.tsx b/code/frameworks/nextjs/src/images/next-image-stub.tsx deleted file mode 100644 index 7fc7268b5c7d..000000000000 --- a/code/frameworks/nextjs/src/images/next-image-stub.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* eslint-disable no-underscore-dangle, @typescript-eslint/no-non-null-assertion */ -import * as React from 'react'; -import type * as _NextImage from 'next/image'; -import type * as _NextLegacyImage from 'next/legacy/image'; -import semver from 'semver'; - -const defaultLoader = ({ src, width, quality }: _NextImage.ImageLoaderProps) => { - const missingValues = []; - if (!src) { - missingValues.push('src'); - } - - if (!width) { - missingValues.push('width'); - } - - if (missingValues.length > 0) { - throw new Error( - `Next Image Optimization requires ${missingValues.join( - ', ' - )} to be provided. Make sure you pass them as props to the \`next/image\` component. Received: ${JSON.stringify( - { - src, - width, - quality, - } - )}` - ); - } - - return `${src}?w=${width}&q=${quality ?? 75}`; -}; - -const NextImage = require('next/image') as typeof _NextImage; - -const OriginalNextImage = NextImage.default; - -Object.defineProperty(NextImage, 'default', { - configurable: true, - value: (props: _NextImage.ImageProps) => { - return ; - }, -}); - -if (semver.satisfies(process.env.__NEXT_VERSION!, '^13.0.0')) { - const LegacyNextImage = require('next/legacy/image') as typeof _NextLegacyImage; - const OriginalNextLegacyImage = LegacyNextImage.default; - - Object.defineProperty(OriginalNextLegacyImage, 'default', { - configurable: true, - value: (props: _NextLegacyImage.ImageProps) => ( - - ), - }); -} - -if (semver.satisfies(process.env.__NEXT_VERSION!, '^12.2.0')) { - const NextFutureImage = require('next/future/image') as typeof _NextImage; - const OriginalNextFutureImage = NextFutureImage.default; - - Object.defineProperty(OriginalNextFutureImage, 'default', { - configurable: true, - value: (props: _NextImage.ImageProps) => ( - - ), - }); -} diff --git a/code/frameworks/nextjs/src/images/next-image.tsx b/code/frameworks/nextjs/src/images/next-image.tsx new file mode 100644 index 000000000000..74e252d93a7d --- /dev/null +++ b/code/frameworks/nextjs/src/images/next-image.tsx @@ -0,0 +1,17 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore import is aliased in webpack config +import OriginalNextImage from 'sb-original/next/image'; +import type * as _NextImage from 'next/image'; +import React from 'react'; +import { ImageContext } from './context'; +import { defaultLoader } from './next-image-default-loader'; + +const MockedNextImage = (props: _NextImage.ImageProps) => { + const imageParameters = React.useContext(ImageContext); + + return ( + + ); +}; + +export default MockedNextImage; diff --git a/code/frameworks/nextjs/src/images/next-legacy-image.tsx b/code/frameworks/nextjs/src/images/next-legacy-image.tsx new file mode 100644 index 000000000000..8d899cc341a5 --- /dev/null +++ b/code/frameworks/nextjs/src/images/next-legacy-image.tsx @@ -0,0 +1,21 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore import is aliased in webpack config +import OriginalNextLegacyImage from 'sb-original/next/legacy/image'; +import type * as _NextLegacyImage from 'next/legacy/image'; +import React from 'react'; +import { ImageContext } from './context'; +import { defaultLoader } from './next-image-default-loader'; + +function NextLegacyImage(props: _NextLegacyImage.ImageProps) { + const imageParameters = React.useContext(ImageContext); + + return ( + + ); +} + +export default NextLegacyImage; diff --git a/code/frameworks/nextjs/src/images/webpack.ts b/code/frameworks/nextjs/src/images/webpack.ts index 967387f7b027..51064d40cc8a 100644 --- a/code/frameworks/nextjs/src/images/webpack.ts +++ b/code/frameworks/nextjs/src/images/webpack.ts @@ -1,11 +1,38 @@ import semver from 'semver'; import type { Configuration as WebpackConfig, RuleSetRule } from 'webpack'; import type { NextConfig } from 'next'; -import { addScopedAlias, getNextjsVersion } from '../utils'; +import path from 'path'; +import { getNextjsVersion } from '../utils'; export const configureImages = (baseConfig: WebpackConfig, nextConfig: NextConfig): void => { configureStaticImageImport(baseConfig, nextConfig); - addScopedAlias(baseConfig, 'next/image'); + configureImageDefaults(baseConfig); +}; + +const configureImageDefaults = (baseConfig: WebpackConfig): void => { + const version = getNextjsVersion(); + const resolve = baseConfig.resolve ?? {}; + resolve.alias = { + ...resolve.alias, + 'sb-original/next/image': require.resolve('next/image'), + 'next/image': path.resolve(__dirname, './images/next-image'), + }; + + if (semver.satisfies(version, '^13.0.0')) { + resolve.alias = { + ...resolve.alias, + 'sb-original/next/legacy/image': require.resolve('next/legacy/image'), + 'next/legacy/image': path.resolve(__dirname, './images/next-legacy-image'), + }; + } + + if (semver.satisfies(version, '^12.2.0')) { + resolve.alias = { + ...resolve.alias, + 'sb-original/next/future/image': require.resolve('next/future/image'), + 'next/future/image': path.resolve(__dirname, './images/next-future-image'), + }; + } }; const configureStaticImageImport = (baseConfig: WebpackConfig, nextConfig: NextConfig): void => { diff --git a/code/frameworks/nextjs/src/preview.tsx b/code/frameworks/nextjs/src/preview.tsx index 85a9f33770cb..9f30af9d787d 100644 --- a/code/frameworks/nextjs/src/preview.tsx +++ b/code/frameworks/nextjs/src/preview.tsx @@ -1,8 +1,8 @@ import type { Addon_DecoratorFunction } from '@storybook/types'; import './config/preview'; +import { ImageDecorator } from './images/decorator'; import { RouterDecorator } from './routing/decorator'; import { StyledJsxDecorator } from './styledJsx/decorator'; -import './images/next-image-stub'; import { HeadManagerDecorator } from './head-manager/decorator'; function addNextHeadCount() { @@ -16,6 +16,7 @@ addNextHeadCount(); export const decorators: Addon_DecoratorFunction[] = [ StyledJsxDecorator, + ImageDecorator, RouterDecorator, HeadManagerDecorator, ]; diff --git a/code/frameworks/nextjs/src/routing/app-router-provider.tsx b/code/frameworks/nextjs/src/routing/app-router-provider.tsx index cda802a41075..75c6c5629b87 100644 --- a/code/frameworks/nextjs/src/routing/app-router-provider.tsx +++ b/code/frameworks/nextjs/src/routing/app-router-provider.tsx @@ -2,12 +2,13 @@ import React from 'react'; import type { LayoutRouterContext as TLayoutRouterContext, AppRouterContext as TAppRouterContext, + GlobalLayoutRouterContext as TGlobalLayoutRouterContext, } from 'next/dist/shared/lib/app-router-context'; import type { PathnameContext as TPathnameContext, SearchParamsContext as TSearchParamsContext, } from 'next/dist/shared/lib/hooks-client-context'; -import type { FlightRouterState } from 'next/dist/server/app-render'; +import type { FlightRouterState } from 'next/dist/server/app-render/types'; import type { RouteParams } from './types'; /** @@ -21,17 +22,21 @@ let AppRouterContext: typeof TAppRouterContext; let LayoutRouterContext: typeof TLayoutRouterContext; let PathnameContext: typeof TPathnameContext; let SearchParamsContext: typeof TSearchParamsContext; +let GlobalLayoutRouterContext: typeof TGlobalLayoutRouterContext; try { AppRouterContext = require('next/dist/shared/lib/app-router-context').AppRouterContext; LayoutRouterContext = require('next/dist/shared/lib/app-router-context').LayoutRouterContext; PathnameContext = require('next/dist/shared/lib/hooks-client-context').PathnameContext; SearchParamsContext = require('next/dist/shared/lib/hooks-client-context').SearchParamsContext; + GlobalLayoutRouterContext = + require('next/dist/shared/lib/app-router-context').GlobalLayoutRouterContext; } catch { AppRouterContext = React.Fragment as any; LayoutRouterContext = React.Fragment as any; PathnameContext = React.Fragment as any; SearchParamsContext = React.Fragment as any; + GlobalLayoutRouterContext = React.Fragment as any; } type AppRouterProviderProps = { @@ -52,43 +57,63 @@ const getParallelRoutes = (segmentsList: Array): FlightRouterState => { const AppRouterProvider: React.FC = ({ children, action, routeParams }) => { const { pathname, query, segments = [], ...restRouteParams } = routeParams; + const tree: FlightRouterState = [pathname, { children: getParallelRoutes([...segments]) }]; + + // https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/app-router.tsx#L436 return ( - { - action('nextNavigation.refresh')(); - }, - ...restRouteParams, - }} - > + - - {children} - + { + action('nextNavigation.refresh')(); + }, + ...restRouteParams, + }} + > + + {children} + + + - + ); }; diff --git a/code/frameworks/nextjs/template/stories/Image.stories.jsx b/code/frameworks/nextjs/template/stories/Image.stories.jsx index c30778804dfe..bf3808282a6f 100644 --- a/code/frameworks/nextjs/template/stories/Image.stories.jsx +++ b/code/frameworks/nextjs/template/stories/Image.stories.jsx @@ -48,3 +48,30 @@ export const Sized = { ], }, }; + +export const Lazy = { + args: { + src: 'https://storybook.js.org/images/placeholders/50x50.png', + width: 50, + height: 50, + }, + decorators: [ + (Story) => ( + <> +
+ {Story()} + + ), + ], +}; + +export const Eager = { + ...Lazy, + parameters: { + nextjs: { + image: { + loading: 'eager', + }, + }, + }, +}; diff --git a/code/frameworks/nextjs/template/stories_nextjs-default-js/Navigation.stories.jsx b/code/frameworks/nextjs/template/stories_nextjs-default-js/Navigation.stories.jsx index 12b66e3205d2..166567aa456c 100644 --- a/code/frameworks/nextjs/template/stories_nextjs-default-js/Navigation.stories.jsx +++ b/code/frameworks/nextjs/template/stories_nextjs-default-js/Navigation.stories.jsx @@ -2,6 +2,7 @@ import { useRouter, usePathname, useSearchParams, + useParams, useSelectedLayoutSegment, useSelectedLayoutSegments, } from 'next/navigation'; @@ -11,6 +12,7 @@ function Component() { const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); + const params = useParams(); const segment = useSelectedLayoutSegment(); const segments = useSelectedLayoutSegments(); @@ -58,6 +60,16 @@ function Component() { ))}
+
+ params:{' '} +
    + {Object.entries(params).map(([key, value]) => ( +
  • + {key}: {value} +
  • + ))} +
+
{routerActions.map(({ cb, name }) => (