Skip to content

Viewport: Prioritize story viewport globals and avoid user-global pollution#33849

Merged
valentinpalkovic merged 3 commits into
storybookjs:nextfrom
ia319:bug/33831-viewport-story-global-precedence
Feb 24, 2026
Merged

Viewport: Prioritize story viewport globals and avoid user-global pollution#33849
valentinpalkovic merged 3 commits into
storybookjs:nextfrom
ia319:bug/33831-viewport-story-global-precedence

Conversation

@ia319
Copy link
Copy Markdown
Member

@ia319 ia319 commented Feb 15, 2026

Closes #33831

What I did

  • prioritize story viewport globals when story viewport globals exist
  • remove story-to-user viewport global synchronization
  • reset invalid viewport options only when no story viewport global exists

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

  1. Copy the preview and stories code from the issue reproduction link into the sandbox.

  • After running, switch between stories and observe the viewport.
  • Use the button to reset the viewport or select another device, then switch between stories and observe.
  • Pass viewport-related query parameters, then switch between stories and observe.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=<PR_NUMBER>

Summary by CodeRabbit

  • Bug Fixes
    • Improved viewport value resolution to prioritize story-level settings when present, producing more consistent viewport and rotation behavior.
    • Stopped unconditional resets on updates; viewport now only resets conditionally, avoiding unexpected overrides.
    • Invalid option handling now falls back to sensible defaults only when no story-level setting exists, preserving user choices otherwise.
    • Keyboard shortcuts and overall lifecycle behavior remain unchanged.

…ort pollution

- prioritize story viewport globals when story viewport globals exist
- remove story-to-user viewport global synchronization
- reset invalid viewport options only when no story viewport global exists
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 15, 2026

📝 Walkthrough

Walkthrough

Reworks viewport value resolution in the useViewport hook: introduces storyHasViewport plus primary/secondary global precedence, removes the unconditional reset on storyGlobals updates, and changes invalid-option handling to reset to defaults only when no story-level viewport exists.

Changes

Cohort / File(s) Summary
Viewport global resolution logic
code/core/src/viewport/useViewport.ts
Reworked global value resolution to introduce storyHasViewport, primaryGlobal, and secondaryGlobal with two-tier precedence. Removed the unconditional effect that reset the viewport on every storyGlobals update; now resets are conditional. Invalid-option handling no longer forces a story-global reset when a story-level viewport exists; defaults are applied only when no story-level viewport is present. Minor normalization adjustments align default handling across sources.

Sequence Diagram(s)

(omitted — changes are localized and do not introduce a new multi-component sequential flow)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)

Comment @coderabbitai help to get the list of available commands and usage tips.

@valentinpalkovic valentinpalkovic moved this to Empathy Queue (prioritized) in Core Team Projects Feb 16, 2026
@valentinpalkovic valentinpalkovic moved this from Empathy Queue (prioritized) to In Progress in Core Team Projects Feb 24, 2026
@valentinpalkovic
Copy link
Copy Markdown
Contributor

Hi @ia319,

Thank you for your contribution!

The story path=/story/manager-components-preview-viewport--rotated in Storybook's own Storybook seems to be off. See https://www.chromatic.com/test?appId=635781f3500dd2c49e189caf&id=69915c954d42ecdd8c0e716a. the rotated global doesn't seem to be taken into consideration anymore. Could you please take a look?

@valentinpalkovic valentinpalkovic moved this from In Progress to On Hold in Core Team Projects Feb 24, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
code/core/src/viewport/useViewport.ts (1)

84-95: ⚠️ Potential issue | 🟡 Minor

Use defined-value check to distinguish between unset and explicitly undefined viewports.

The in operator returns true even when a property is explicitly set to undefined. If a story sets globals: { viewport: undefined } to clear a viewport override, PARAM_KEY in storyGlobals will still evaluate true, treating it as if a viewport is set. This causes inconsistent behavior: the viewport locks even though the story hasn't meaningfully configured one.

Check for defined values instead: storyGlobals[PARAM_KEY] !== undefined. This aligns with the pattern already used in the codebase (e.g., VisionSimulator addon) and ensures undefined properties are treated as absent.

🛠️ Suggested changes
-  const storyHasViewport = PARAM_KEY in storyGlobals;
+  const storyHasViewport = storyGlobals[PARAM_KEY] !== undefined;
-  const isLocked = disable || PARAM_KEY in storyGlobals || !keys.length;
+  const isLocked = disable || storyHasViewport || !keys.length;
-        if (!(PARAM_KEY in storyGlobals)) {
+        if (storyGlobals[PARAM_KEY] === undefined) {

Also applies to: 198-206

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/viewport/useViewport.ts` around lines 84 - 95, The code uses
the in operator to detect a story-level viewport via "PARAM_KEY in
storyGlobals", which treats explicit undefined as present; change these checks
to explicit defined-value checks (e.g., storyGlobals[PARAM_KEY] !== undefined)
wherever you currently use "in" for viewport detection (notably around the
computation of storyHasViewport/primaryGlobal/secondaryGlobal/isLocked and the
similar block at the later 198-206 region) so that explicitly undefined globals
are treated as absent and the viewport lock logic (isLocked and
primary/secondary selection) behaves correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@code/core/src/viewport/useViewport.ts`:
- Around line 84-95: The code uses the in operator to detect a story-level
viewport via "PARAM_KEY in storyGlobals", which treats explicit undefined as
present; change these checks to explicit defined-value checks (e.g.,
storyGlobals[PARAM_KEY] !== undefined) wherever you currently use "in" for
viewport detection (notably around the computation of
storyHasViewport/primaryGlobal/secondaryGlobal/isLocked and the similar block at
the later 198-206 region) so that explicitly undefined globals are treated as
absent and the viewport lock logic (isLocked and primary/secondary selection)
behaves correctly.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2118601 and 6d1e517.

📒 Files selected for processing (1)
  • code/core/src/viewport/useViewport.ts

@ia319
Copy link
Copy Markdown
Member Author

ia319 commented Feb 24, 2026

@valentinpalkovic Now it should be fine.

I removed the incorrect default false in parseGlobals—it was wrongly overriding the real isRotated.
It was originally added to prevent isRotated from becoming undefined when only value is passed in, updateGlobals already handles that.

Copy link
Copy Markdown
Contributor

@valentinpalkovic valentinpalkovic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@valentinpalkovic valentinpalkovic added the patch:yes Bugfix & documentation PR that need to be picked to main branch label Feb 24, 2026
@valentinpalkovic valentinpalkovic moved this from On Hold to In Progress in Core Team Projects Feb 24, 2026
@valentinpalkovic valentinpalkovic merged commit ca086e8 into storybookjs:next Feb 24, 2026
120 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Core Team Projects Feb 24, 2026
@yannbf yannbf removed the patch:yes Bugfix & documentation PR that need to be picked to main branch label Feb 26, 2026
@valentinpalkovic valentinpalkovic added the needs qa Indicates that this needs manual QA during the upcoming minor/major release label Mar 10, 2026
@storybook-app-bot
Copy link
Copy Markdown

Package Benchmarks

Commit: 6d1e517, ran on 10 March 2026 at 11:30:59 UTC

The following packages have significant changes to their size or dependencies:

@storybook/addon-docs

Before After Difference
Dependency count 18 18 0
Self size 1.66 MB 1.64 MB 🎉 -17 KB 🎉
Dependency size 9.25 MB 9.25 MB 🎉 -219 B 🎉
Bundle Size Analyzer Link Link

storybook

Before After Difference
Dependency count 49 49 0
Self size 20.21 MB 20.42 MB 🚨 +207 KB 🚨
Dependency size 16.52 MB 16.52 MB 0 B
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 183 183 0
Self size 779 KB 779 KB 🎉 -13 B 🎉
Dependency size 67.35 MB 67.56 MB 🚨 +208 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 176 176 0
Self size 32 KB 32 KB 🚨 +36 B 🚨
Dependency size 65.88 MB 66.08 MB 🚨 +207 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 50 50 0
Self size 1.04 MB 1.04 MB 🚨 +905 B 🚨
Dependency size 36.73 MB 36.94 MB 🚨 +207 KB 🚨
Bundle Size Analyzer node node

@Sidnioulz Sidnioulz removed the needs qa Indicates that this needs manual QA during the upcoming minor/major release label Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Bug]: Reset viewport global after changing story

5 participants