Skip to content

Core: Track vision simulator state through globals and apply styles in preview#33418

Merged
ghengeveld merged 8 commits into
nextfrom
vision-simulator-global
Jan 8, 2026
Merged

Core: Track vision simulator state through globals and apply styles in preview#33418
ghengeveld merged 8 commits into
nextfrom
vision-simulator-global

Conversation

@ghengeveld
Copy link
Copy Markdown
Member

@ghengeveld ghengeveld commented Dec 23, 2025

What I did

Synchronize vision simulator state with globals and apply vision filters in the preview rather than on the manager's preview iframe. This allows stories to specify a vision deficiency via globals and have Chromatic snapshot it as such.

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. Change the vision simulator's state
  2. Open the story in isolation mode
  3. Confirm the styles still apply

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

  • New Features

    • Added a global vision simulator decorator and initial global setting to apply vision filters across stories.
    • Added preset vision simulations (various color-vision types, grayscale, blur) and story examples demonstrating selections.
  • Refactor

    • Simulator state moved from local component state to global store for consistent behavior across the UI.
    • Centralized filter definitions into an embeddable resource and removed the standalone color-filter component.
  • Tests

    • Removed existing VisionSimulator tests.

✏️ Tip: You can customize this high-level summary in your review settings.

…ers in the preview rather than on the manager's preview iframe
@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Dec 23, 2025

View your CI Pipeline Execution ↗ for commit e3601ea

Command Status Duration Result
nx run-many -t compile,check,knip,test,pretty-d... ✅ Succeeded 9m 46s View ↗

☁️ Nx Cloud last updated this comment at 2026-01-08 09:44:53 UTC

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 23, 2025

📝 Walkthrough

Walkthrough

Removes the inline SVG filter component, centralizes vision filter metadata and SVG defs, migrates VisionSimulator state to Storybook globals, adds a decorator that injects/applies SVG/CSS filters to the DOM, and wires an initial global key and preview decorator.

Changes

Cohort / File(s) Summary
Removed component
code/addons/a11y/src/components/ColorFilters.tsx
Deleted the React SVG component that exported inline SVG filter definitions.
Vision simulator UI
code/addons/a11y/src/components/VisionSimulator.tsx
Switched from local state to Storybook useGlobals (VISION_GLOBAL_KEY); options now derive from visionSimulatorFilters; selection/reset update globals; filter defs are injected via a hidden element (dangerouslySetInnerHTML); removed local filter imports/logic.
Filter definitions & metadata
code/addons/a11y/src/visionSimulatorFilters.ts
New exports: filters (map of key → {label, filter, percentage?}) and filterDefs (string of SVG filter markup with feColorMatrix entries).
Decorator implementation
code/addons/a11y/src/withVisionSimulator.ts
New withVisionSimulator decorator: injects filterDefs, observes globals.vision, computes/merges body CSS filter preserving non-vision filters, watches body class changes via MutationObserver, and restores state on cleanup.
Configuration & wiring
code/addons/a11y/src/constants.ts, code/addons/a11y/src/preview.tsx
Added VISION_GLOBAL_KEY; added withVisionSimulator to exported decorators; extended initialGlobals.a11y with vision: undefined.
Stories
code/addons/a11y/src/components/VisionSimulator.stories.tsx
Added stories with ManagerContext wrapper and play functions; includes default, preset-global (vision: 'achromatopsia'), and selection-interaction scenarios.
Tests
code/addons/a11y/src/components/VisionSimulator.test.tsx, code/addons/a11y/src/components/A11YPanel.test.tsx
Removed VisionSimulator.test.tsx (deleted); added a TypeScript jest-dom reference in A11YPanel.test.tsx.
Misc. test file formatting
code/*/*/__tests__/*, test-storybooks/*
Minor triple-slash reference formatting changes (removed trailing semicolons) across several test files.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as VisionSimulator UI
    participant Globals as Storybook Globals
    participant Decorator as withVisionSimulator
    participant DOM as Document/Body

    User->>UI: open selector / choose filter
    UI->>Globals: set global `vision` value
    Globals->>Decorator: globals change (vision)

    rect rgb(240,248,255)
    Note over Decorator,DOM: On mount
    Decorator->>DOM: inject hidden element with `filterDefs` (SVG filters)
    end

    rect rgb(240,255,240)
    Note over Decorator: On vision change
    Decorator->>Decorator: compute merged body filter string (preserve other filters)
    Decorator->>DOM: update `document.body.style.filter`
    end

    rect rgb(255,240,245)
    Note over Decorator,DOM: On unmount / cleanup
    Decorator->>DOM: remove injected filter element
    Decorator->>DOM: restore previous `body.style.filter`
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7a6c6a and e3601ea.

📒 Files selected for processing (6)
  • code/addons/a11y/src/components/A11YPanel.test.tsx
  • code/addons/links/src/react/components/link.test.tsx
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/renderers/svelte/src/__test__/composeStories/portable-stories.test.ts
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
✅ Files skipped from review due to trivial changes (1)
  • code/renderers/svelte/src/test/composeStories/portable-stories.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • code/addons/a11y/src/components/A11YPanel.test.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{test,spec}.{ts,tsx}: Test files should follow the naming pattern *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx
Follow the spy mocking rules defined in .cursor/rules/spy-mocking.mdc for consistent mocking patterns with Vitest

Files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access the mocked functions in Vitest tests
Implement mock behaviors in beforeEach blocks in Vitest tests
Mock all required dependencies that the test subject uses
Each mock implementation should return a Promise for async functions in Vitest
Mock implementations should match the expected return type of the original function
Mock all required properties and methods that the test subject uses in Vitest tests
Avoid direct function mocking without vi.mocked() in Vitest tests
Avoid mock implementations outside of beforeEach blocks in Vitest tests
Avoid mocking without the spy: true option in Vitest tests
Avoid inline mock implementations within test cases in Vitest tests
Avoid mocking only a subset of required dependencies in Vitest tests
Mock at the highest level of abstraction needed in Vitest tests
Keep mock implementations simple and focused in Vitest tests
Use type-safe mocking with vi.mocked() in Vitest tests
Document complex mock behaviors in Vitest tests
Group related mocks together in Vitest tests

Files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns
Achieve high test coverage of business logic, aiming for 75%+ coverage of statements/lines
Cover all branches, conditions, edge cases, error paths, and different input variations in unit tests
Use vi.mock() to mock file system, loggers, and other external dependencies in tests

Files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
🧠 Learnings (19)
📓 Common learnings
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.
📚 Learning: 2025-11-05T09:36:55.944Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Tabs/Tabs.stories.tsx:222-227
Timestamp: 2025-11-05T09:36:55.944Z
Learning: Repo: storybookjs/storybook PR: 32458 — In code/core/src/components/components/Button/Button.tsx (React/TypeScript), ButtonProps includes ariaLabel?: string | false and the component maps it to the DOM aria-label. Convention: ariaLabel is mandatory on all Button usages — provide a descriptive string for icon-only buttons; set ariaLabel=false when the button’s children already serve as the accessible name. Do not suggest using a raw aria-label prop on Button call sites.

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Keep mock implementations simple and focused in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-11-24T17:49:31.838Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T17:49:31.838Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Follow the spy mocking rules defined in `.cursor/rules/spy-mocking.mdc` for consistent mocking patterns with Vitest

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mock implementations outside of `beforeEach` blocks in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking without the `spy: true` option in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-11-24T17:49:31.838Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T17:49:31.838Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Test files should follow the naming pattern `*.test.ts`, `*.test.tsx`, `*.spec.ts`, or `*.spec.tsx`

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in `beforeEach` blocks in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Group related mocks together in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required properties and methods that the test subject uses in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock at the highest level of abstraction needed in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid direct function mocking without `vi.mocked()` in Vitest tests

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts
  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
  • code/addons/links/src/react/components/link.test.tsx
  • code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Use `vi.mock()` to mock file system, loggers, and other external dependencies in tests

Applied to files:

  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `vi.mock()` with the `spy: true` option for all package and file mocks in Vitest tests

Applied to files:

  • code/core/src/common/utils/__tests__/normalize-stories.test.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Export functions from modules if they need to be tested

Applied to files:

  • code/addons/links/src/react/components/link.test.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: nx
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (4)
code/addons/links/src/react/components/link.test.tsx (1)

2-2: LGTM: Correct TypeScript syntax.

The removal of the trailing semicolon aligns with proper TypeScript triple-slash directive syntax.

code/core/src/common/utils/__tests__/normalize-stories.test.ts (1)

1-1: LGTM: Correct TypeScript syntax.

The removal of the trailing semicolon aligns with proper TypeScript triple-slash directive syntax.

code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts (1)

2-2: LGTM: Correct TypeScript syntax.

The removal of the trailing semicolon aligns with proper TypeScript triple-slash directive syntax.

test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts (1)

1-1: LGTM: Correct TypeScript syntax.

The removal of the trailing semicolon aligns with proper TypeScript triple-slash directive syntax.


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

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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
code/addons/a11y/src/withVisionSimulator.ts (1)

20-33: Handle empty filter strings correctly.

When document.body.style.filter is an empty string, split(' ') returns [''], which passes through the filter check on line 22. While this won't break functionality (empty strings are filtered out by the truthiness check), it's worth being explicit.

🔎 Optional clarification
  useEffect(() => {
-    const existingFilters = document.body.style.filter.split(' ').filter((filter) => {
+    const existingFilters = (document.body.style.filter || '').split(' ').filter((filter) => {
      return filter && filter !== 'none' && !knownFilters.includes(filter);
    });

This makes the intent clearer and handles the empty string case explicitly.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 821b832 and fbb8802.

📒 Files selected for processing (6)
  • code/addons/a11y/src/components/ColorFilters.tsx
  • code/addons/a11y/src/components/VisionSimulator.tsx
  • code/addons/a11y/src/constants.ts
  • code/addons/a11y/src/preview.tsx
  • code/addons/a11y/src/visionSimulatorFilters.ts
  • code/addons/a11y/src/withVisionSimulator.ts
💤 Files with no reviewable changes (1)
  • code/addons/a11y/src/components/ColorFilters.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/addons/a11y/src/preview.tsx
  • code/addons/a11y/src/constants.ts
  • code/addons/a11y/src/withVisionSimulator.ts
  • code/addons/a11y/src/visionSimulatorFilters.ts
  • code/addons/a11y/src/components/VisionSimulator.tsx
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/addons/a11y/src/preview.tsx
  • code/addons/a11y/src/constants.ts
  • code/addons/a11y/src/withVisionSimulator.ts
  • code/addons/a11y/src/visionSimulatorFilters.ts
  • code/addons/a11y/src/components/VisionSimulator.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/addons/a11y/src/preview.tsx
  • code/addons/a11y/src/constants.ts
  • code/addons/a11y/src/withVisionSimulator.ts
  • code/addons/a11y/src/visionSimulatorFilters.ts
  • code/addons/a11y/src/components/VisionSimulator.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/a11y/src/preview.tsx
  • code/addons/a11y/src/constants.ts
  • code/addons/a11y/src/withVisionSimulator.ts
  • code/addons/a11y/src/visionSimulatorFilters.ts
  • code/addons/a11y/src/components/VisionSimulator.tsx
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/addons/a11y/src/preview.tsx
  • code/addons/a11y/src/constants.ts
  • code/addons/a11y/src/withVisionSimulator.ts
  • code/addons/a11y/src/visionSimulatorFilters.ts
  • code/addons/a11y/src/components/VisionSimulator.tsx
🧠 Learnings (13)
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/addons/a11y/src/preview.tsx
  • code/addons/a11y/src/withVisionSimulator.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in `beforeEach` blocks in Vitest tests

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mock implementations outside of `beforeEach` blocks in Vitest tests

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies in Vitest tests

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors in Vitest tests

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required properties and methods that the test subject uses in Vitest tests

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases in Vitest tests

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Group related mocks together in Vitest tests

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Keep mock implementations simple and focused in Vitest tests

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock at the highest level of abstraction needed in Vitest tests

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid direct function mocking without `vi.mocked()` in Vitest tests

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-05T09:37:25.920Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/tooltip/WithTooltip.tsx:54-96
Timestamp: 2025-11-05T09:37:25.920Z
Learning: Repo: storybookjs/storybook — In code/core/src/components/components/tooltip/WithTooltip.tsx, the legacy WithTooltip implementation is intentionally reintroduced for backward compatibility and is deprecated; maintainers (per Sidnioulz) do not want maintenance or improvements on it. Prefer WithTooltipNew/Popover; avoid suggesting changes to WithTooltip.* going forward.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
  • code/addons/a11y/src/components/VisionSimulator.tsx
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.tsx
🧬 Code graph analysis (3)
code/addons/a11y/src/preview.tsx (1)
code/addons/a11y/src/withVisionSimulator.ts (1)
  • withVisionSimulator (9-36)
code/addons/a11y/src/withVisionSimulator.ts (2)
code/addons/a11y/src/visionSimulatorFilters.ts (2)
  • filters (1-46)
  • filterDefs (48-100)
code/frameworks/angular/src/client/public-types.ts (1)
  • StoryFn (35-38)
code/addons/a11y/src/components/VisionSimulator.tsx (2)
code/addons/a11y/src/visionSimulatorFilters.ts (2)
  • filters (1-46)
  • filterDefs (48-100)
code/addons/a11y/src/constants.ts (1)
  • VISION_GLOBAL_KEY (4-4)
🪛 ast-grep (0.40.3)
code/addons/a11y/src/components/VisionSimulator.tsx

[warning] 63-63: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
code/addons/a11y/src/components/VisionSimulator.tsx

[error] 64-64: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: normal
  • GitHub Check: nx
  • GitHub Check: nx
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (9)
code/addons/a11y/src/components/VisionSimulator.tsx (3)

1-11: LGTM! Clean migration to global state.

The imports have been properly updated to support the global state architecture. The transition from local state management to useGlobals is a solid architectural improvement that enables cross-component state synchronization.


46-51: LGTM! Options generation is clean and type-safe.

The dynamic generation of options from the filters map is well-structured and leverages TypeScript's type inference effectively.


64-64: The use of dangerouslySetInnerHTML is safe here.

Static analysis tools flag this line, but the concern is a false positive. The filterDefs constant is a hardcoded SVG string from visionSimulatorFilters.ts, not user-supplied input, so there's no XSS risk. This is an appropriate use case for injecting static SVG filter definitions into the DOM.

code/addons/a11y/src/constants.ts (1)

4-4: LGTM! Clean constant addition.

The new VISION_GLOBAL_KEY constant properly centralizes the global state key for the vision simulator feature.

code/addons/a11y/src/preview.tsx (2)

8-12: LGTM! Decorator integration is clean.

The withVisionSimulator decorator is properly imported and exported in the decorators array, enabling vision simulation across all stories.


100-100: The vision global is correctly placed at the top level of initialGlobals and is consistently accessed throughout the codebase via destructuring (const { vision } = globals) and bracket notation (globals[VISION_GLOBAL_KEY] where the key resolves to "vision"). The structure is intentional: a11y-related settings like manual are nested, while vision is a separate top-level global.

code/addons/a11y/src/withVisionSimulator.ts (1)

7-7: LGTM! Clean computation of known filters.

The knownFilters array is correctly derived from the filters map, ensuring consistent filter detection throughout the decorator.

code/addons/a11y/src/visionSimulatorFilters.ts (2)

1-46: LGTM! Well-structured filter definitions.

The filters object provides a clean, centralized mapping of vision deficiencies with their labels, CSS filter values, and prevalence percentages. The use of as const ensures type safety for the filter keys.


48-100: LGTM! SVG filter definitions are properly structured.

The filterDefs constant contains well-formed SVG markup with color matrix filters for various vision deficiencies. The filter IDs correctly match the references in the filters object, and the display: none !important style ensures the SVG doesn't affect layout.

},
({ $filter }) => ({
filter: getFilter($filter),
filter: filters[$filter as keyof typeof filters].filter || 'none',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Verify the filter key exists before accessing.

The code assumes the filter key exists in the filters object, but if $filter is invalid, this could throw at runtime.

🔎 Proposed defensive fix
  ({ $filter }) => ({
-    filter: filters[$filter as keyof typeof filters].filter || 'none',
+    filter: filters[$filter as keyof typeof filters]?.filter || 'none',
  }),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
filter: filters[$filter as keyof typeof filters].filter || 'none',
({ $filter }) => ({
filter: filters[$filter as keyof typeof filters]?.filter || 'none',
}),
🤖 Prompt for AI Agents
In code/addons/a11y/src/components/VisionSimulator.tsx around line 35, the
lookup filters[$filter as keyof typeof filters].filter assumes $filter is a
valid key and may throw if it's invalid; first check that $filter exists in the
filters object (e.g. use "if ($filter in filters)" or
Object.prototype.hasOwnProperty.call(filters, $filter)) and only access .filter
when present, otherwise fall back to 'none' (or use optional chaining like
filters[$filter as keyof typeof filters]?.filter ?? 'none'); ensure the check is
typed so TypeScript accepts the access and keep the 'none' fallback.

Comment on lines +12 to +18
useEffect(() => {
document.body.insertAdjacentHTML('beforeend', filterDefs);

return () => {
document.body.removeChild(document.getElementById('storybook-a11y-vision-filters')!);
};
}, []);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add defensive checks for DOM manipulation.

The cleanup function uses a non-null assertion when removing the filter element. If the element was already removed (e.g., by another story or external code), this will throw a runtime error. Additionally, if multiple stories mount simultaneously, insertAdjacentHTML could insert duplicate elements with the same ID.

🔎 Proposed fix with existence checks
  useEffect(() => {
-    document.body.insertAdjacentHTML('beforeend', filterDefs);
+    const existingFilters = document.getElementById('storybook-a11y-vision-filters');
+    if (!existingFilters) {
+      document.body.insertAdjacentHTML('beforeend', filterDefs);
+    }

    return () => {
-      document.body.removeChild(document.getElementById('storybook-a11y-vision-filters')!);
+      const element = document.getElementById('storybook-a11y-vision-filters');
+      if (element && element.parentNode) {
+        element.parentNode.removeChild(element);
+      }
    };
  }, []);
🤖 Prompt for AI Agents
In code/addons/a11y/src/withVisionSimulator.ts around lines 12–18, the effect
unconditionally inserts filterDefs and uses a non-null assertion when removing
the element; change it to first check if an element with id
'storybook-a11y-vision-filters' already exists before inserting (skip insertion
if present) and in the cleanup use getElementById/querySelector to find the
element and only call removeChild if the element is found (no non-null
assertion). This prevents duplicate inserts when multiple stories mount and
avoids runtime errors if the element was removed elsewhere.

@storybook-app-bot
Copy link
Copy Markdown

storybook-app-bot Bot commented Dec 23, 2025

Package Benchmarks

Commit: e3601ea, ran on 8 January 2026 at 09:43:49 UTC

No significant changes detected, all good. 👏

@ghengeveld ghengeveld force-pushed the vision-simulator-global branch from 9af6551 to 8bf98c1 Compare December 23, 2025 15:47
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.

Actionable comments posted: 0

♻️ Duplicate comments (1)
code/addons/a11y/src/components/VisionSimulator.tsx (1)

29-31: Add optional chaining for defensive access.

This was flagged in a previous review but hasn't been addressed. If $filter is not a valid key in filters, this will throw at runtime.

🔎 Proposed fix
  ({ $filter }) => ({
-    filter: filters[$filter as keyof typeof filters].filter || 'none',
+    filter: filters[$filter as keyof typeof filters]?.filter || 'none',
  }),
🧹 Nitpick comments (2)
code/addons/a11y/src/components/VisionSimulator.stories.tsx (1)

9-17: Consider adding a proper type for the mock context.

Using any bypasses TypeScript strict mode. While acceptable for test files, a partial type would improve safety.

🔎 Proposed type-safe mock
-const managerContext: any = {
+const managerContext: Partial<{
+  state: Record<string, unknown>;
+  api: Record<string, ReturnType<typeof fn>>;
+}> = {
   state: {},
   api: {
     getGlobals: fn(() => ({ vision: undefined })),
     updateGlobals: fn(),
     getStoryGlobals: fn(() => ({ vision: undefined })),
     getUserGlobals: fn(() => ({ vision: undefined })),
   },
 };
code/addons/a11y/src/components/VisionSimulator.tsx (1)

59-59: Acknowledged: dangerouslySetInnerHTML for SVG filter definitions.

Static analysis flagged this for XSS risk. However, filterDefs is imported from a local module (../visionSimulatorFilters) containing hardcoded SVG filter definitions—not user input. The XSS risk is minimal since the content is developer-controlled source code.

Consider adding a brief comment explaining why this is safe to suppress future linter warnings:

🔎 Proposed clarifying comment
+      {/* filterDefs contains static SVG filter definitions from visionSimulatorFilters.ts */}
       <Hidden dangerouslySetInnerHTML={{ __html: filterDefs }} />
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fbb8802 and 8bf98c1.

📒 Files selected for processing (3)
  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
  • code/addons/a11y/src/components/VisionSimulator.tsx
  • code/addons/a11y/src/withVisionSimulator.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • code/addons/a11y/src/withVisionSimulator.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
  • code/addons/a11y/src/components/VisionSimulator.tsx
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
  • code/addons/a11y/src/components/VisionSimulator.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
  • code/addons/a11y/src/components/VisionSimulator.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
  • code/addons/a11y/src/components/VisionSimulator.tsx
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
  • code/addons/a11y/src/components/VisionSimulator.tsx
🧠 Learnings (6)
📓 Common learnings
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
📚 Learning: 2025-11-05T09:37:25.920Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/tooltip/WithTooltip.tsx:54-96
Timestamp: 2025-11-05T09:37:25.920Z
Learning: Repo: storybookjs/storybook — In code/core/src/components/components/tooltip/WithTooltip.tsx, the legacy WithTooltip implementation is intentionally reintroduced for backward compatibility and is deprecated; maintainers (per Sidnioulz) do not want maintenance or improvements on it. Prefer WithTooltipNew/Popover; avoid suggesting changes to WithTooltip.* going forward.

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
  • code/addons/a11y/src/components/VisionSimulator.tsx
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
  • code/addons/a11y/src/components/VisionSimulator.tsx
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: In viewport tool code, when using the `useGlobals` hook from storybook/manager-api, the third returned value `storyGlobals` is guaranteed by TypeScript to be defined (not undefined/null), making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: The useGlobals hook from storybook/manager-api returns a tuple where the third element (storyGlobals) is typed as Globals, not Globals | undefined. This means TypeScript guarantees it's always defined, making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
🪛 ast-grep (0.40.3)
code/addons/a11y/src/components/VisionSimulator.tsx

[warning] 58-58: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
code/addons/a11y/src/components/VisionSimulator.tsx

[error] 59-59: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: nx
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (6)
code/addons/a11y/src/components/VisionSimulator.stories.tsx (3)

19-29: LGTM!

The decorator pattern correctly provides the ManagerContext needed for the VisionSimulator component to function in isolation.


33-35: LGTM!

Good use of role-based querying with getByRole for accessible and resilient interaction testing.


37-46: LGTM!

The WithFilter story effectively tests the new globals-based vision filter state, which aligns with the PR objective of synchronizing vision simulator state with Storybook globals for Chromatic snapshot testing.

code/addons/a11y/src/components/VisionSimulator.tsx (3)

1-11: LGTM!

Imports are well-organized. Using useGlobals from storybook/manager-api correctly implements the global state migration.


37-46: LGTM!

The refactor from local state to global state via useGlobals is clean. Deriving options from the centralized filters map improves maintainability.


55-55: The defaultOptions prop usage is correct. The Select component's API explicitly supports passing either a single value or an array (defaultOptions?: Value | Value[]), so receiving a string key is valid and no change is needed.

Likely an incorrect or invalid review comment.

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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
code/addons/a11y/src/withVisionSimulator.ts (1)

40-47: Prevent duplicate filter definition insertions.

Line 41 unconditionally inserts filterDefs into the DOM, which can create duplicate elements with the same ID (storybook-a11y-vision-filters) if multiple stories mount simultaneously or if the decorator is applied multiple times.

🔎 Proposed fix
   useEffect(() => {
-    document.body.insertAdjacentHTML('beforeend', filterDefs);
+    const existingFilters = document.getElementById('storybook-a11y-vision-filters');
+    if (!existingFilters) {
+      document.body.insertAdjacentHTML('beforeend', filterDefs);
+    }
 
     return () => {
       const filterDefsElement = document.getElementById('storybook-a11y-vision-filters');
       filterDefsElement?.parentElement?.removeChild(filterDefsElement);
     };
   }, []);
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8bf98c1 and 74f7123.

📒 Files selected for processing (1)
  • code/addons/a11y/src/withVisionSimulator.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/addons/a11y/src/withVisionSimulator.ts
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/addons/a11y/src/withVisionSimulator.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/addons/a11y/src/withVisionSimulator.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/a11y/src/withVisionSimulator.ts
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/addons/a11y/src/withVisionSimulator.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.
📚 Learning: 2025-11-05T09:37:25.920Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/tooltip/WithTooltip.tsx:54-96
Timestamp: 2025-11-05T09:37:25.920Z
Learning: Repo: storybookjs/storybook — In code/core/src/components/components/tooltip/WithTooltip.tsx, the legacy WithTooltip implementation is intentionally reintroduced for backward compatibility and is deprecated; maintainers (per Sidnioulz) do not want maintenance or improvements on it. Prefer WithTooltipNew/Popover; avoid suggesting changes to WithTooltip.* going forward.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
📚 Learning: 2025-11-05T09:36:55.944Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Tabs/Tabs.stories.tsx:222-227
Timestamp: 2025-11-05T09:36:55.944Z
Learning: Repo: storybookjs/storybook PR: 32458 — In code/core/src/components/components/Button/Button.tsx (React/TypeScript), ButtonProps includes ariaLabel?: string | false and the component maps it to the DOM aria-label. Convention: ariaLabel is mandatory on all Button usages — provide a descriptive string for icon-only buttons; set ariaLabel=false when the button’s children already serve as the accessible name. Do not suggest using a raw aria-label prop on Button call sites.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: In viewport tool code, when using the `useGlobals` hook from storybook/manager-api, the third returned value `storyGlobals` is guaranteed by TypeScript to be defined (not undefined/null), making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
🧬 Code graph analysis (1)
code/addons/a11y/src/withVisionSimulator.ts (1)
code/addons/a11y/src/visionSimulatorFilters.ts (2)
  • filters (1-46)
  • filterDefs (48-100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
  • GitHub Check: nx

Comment thread code/addons/a11y/src/withVisionSimulator.ts Outdated
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.

Actionable comments posted: 0

🧹 Nitpick comments (4)
code/addons/a11y/src/components/VisionSimulator.stories.tsx (4)

1-1: Remove unused import.

PlayFunctionContext is imported but never used in this file.

🔎 Proposed fix
-import type { PlayFunction, PlayFunctionContext } from 'storybook/internal/types';
+import type { PlayFunction } from 'storybook/internal/types';

9-17: Improve type safety and consider test isolation concerns.

The managerContext is typed as any and defined at module scope, which could lead to:

  1. Reduced type safety.
  2. Test interference — the mock functions (fn()) accumulate call history across all stories. If stories run sequentially or in parallel, assertions like line 52 (expect(managerContext.api.updateGlobals).toHaveBeenCalledWith(...)) could produce false positives or negatives.

Consider typing the mock more strictly (e.g., Partial<ManagerContextProps>) and resetting or isolating mocks per story if call-count assertions are critical.

🔎 Proposed improvements

Option 1: Add explicit type annotation

import type { ManagerContextProps } from 'storybook/manager-api';

const managerContext: Partial<ManagerContextProps> = {
  state: {},
  api: {
    getGlobals: fn(() => ({ vision: undefined })),
    updateGlobals: fn(),
    getStoryGlobals: fn(() => ({ vision: undefined })),
    getUserGlobals: fn(() => ({ vision: undefined })),
  } as any, // api type is complex, cast if needed
};

Option 2: Reset mocks in each story's play function (if test isolation is needed)

export const Selection = meta.story({
  play: async (context) => {
    // Reset mocks to prevent interference from other stories
    managerContext.api.updateGlobals.mockClear();
    
    await openMenu(context);
    await context.userEvent.click(await screen.findByText('Blurred vision'));
    await expect(managerContext.api.updateGlobals).toHaveBeenCalledWith({ vision: 'blurred' });
    // ...
  },
});

23-23: Improve type safety for Story parameter.

The Story parameter is typed as any. Consider using a more specific type, such as React.ComponentType or the appropriate Storybook decorator type.

🔎 Proposed fix
  decorators: [
-    (Story: any) => (
+    (Story: React.ComponentType) => (
      <ManagerContext.Provider value={managerContext}>
        <Story />
      </ManagerContext.Provider>
    ),
  ],

48-57: Use context.canvas instead of screen for consistency.

Line 51 uses screen.findByText, while the openMenu function (line 34) and the final assertion (lines 54-55) use context.canvas. Using screen can query elements outside the component's render scope, leading to false positives or interference from other DOM elements.

For consistency and proper test scoping, use context.canvas.findByText.

🔎 Proposed fix
  play: async (context) => {
    await openMenu(context);
-    await context.userEvent.click(await screen.findByText('Blurred vision'));
+    await context.userEvent.click(await context.canvas.findByText('Blurred vision'));
    await expect(managerContext.api.updateGlobals).toHaveBeenCalledWith({ vision: 'blurred' });
    await expect(
      context.canvas.getByRole('button', { name: 'Vision simulator Blurred vision' })
    ).toBeVisible();
  },
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74f7123 and db0548d.

📒 Files selected for processing (2)
  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
  • code/addons/a11y/src/components/VisionSimulator.test.tsx
💤 Files with no reviewable changes (1)
  • code/addons/a11y/src/components/VisionSimulator.test.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
🧠 Learnings (6)
📓 Common learnings
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
📚 Learning: 2025-11-05T09:37:25.920Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/tooltip/WithTooltip.tsx:54-96
Timestamp: 2025-11-05T09:37:25.920Z
Learning: Repo: storybookjs/storybook — In code/core/src/components/components/tooltip/WithTooltip.tsx, the legacy WithTooltip implementation is intentionally reintroduced for backward compatibility and is deprecated; maintainers (per Sidnioulz) do not want maintenance or improvements on it. Prefer WithTooltipNew/Popover; avoid suggesting changes to WithTooltip.* going forward.

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: In viewport tool code, when using the `useGlobals` hook from storybook/manager-api, the third returned value `storyGlobals` is guaranteed by TypeScript to be defined (not undefined/null), making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/addons/a11y/src/components/VisionSimulator.stories.tsx
🧬 Code graph analysis (1)
code/addons/a11y/src/components/VisionSimulator.stories.tsx (3)
code/addons/a11y/src/components/VisionSimulator.tsx (1)
  • VisionSimulator (37-62)
code/core/src/csf/csf-factories.ts (1)
  • Story (122-154)
code/core/src/test/testing-library.ts (1)
  • userEvent (123-126)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: nx
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (1)
code/addons/a11y/src/components/VisionSimulator.stories.tsx (1)

6-6: The relative import path works for the a11y addon, as evidenced by consistent usage in multiple story files (VisionSimulator, TestDiscrepancyMessage, A11YPanel, Report). However, consider using subpath imports (e.g., import preview from '#.storybook/preview') instead, which aligns with modern Storybook patterns and eliminates dependency on the relative path depth.

⛔ Skipped due to learnings
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32594
File: code/core/src/components/components/Popover/WithPopover.tsx:7-9
Timestamp: 2025-10-01T15:24:01.060Z
Learning: In the Storybook repository, "react-aria-components/patched-dist/*" (e.g., "react-aria-components/patched-dist/Dialog", "react-aria-components/patched-dist/Popover", "react-aria-components/patched-dist/Tooltip") are valid import paths created by a patch applied to the react-aria-components package. These imports should not be flagged as broken or invalid until a maintainer explicitly states they are no longer acceptable.
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/tooltip/WithTooltip.tsx:54-96
Timestamp: 2025-11-05T09:37:25.920Z
Learning: Repo: storybookjs/storybook — In code/core/src/components/components/tooltip/WithTooltip.tsx, the legacy WithTooltip implementation is intentionally reintroduced for backward compatibility and is deprecated; maintainers (per Sidnioulz) do not want maintenance or improvements on it. Prefer WithTooltipNew/Popover; avoid suggesting changes to WithTooltip.* going forward.

@ghengeveld ghengeveld force-pushed the vision-simulator-global branch from b17cdb0 to 3830aed Compare December 23, 2025 19:41
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.

Actionable comments posted: 0

♻️ Duplicate comments (1)
code/addons/a11y/src/withVisionSimulator.ts (1)

42-49: Past review issue partially addressed: duplicate insertion still possible.

The cleanup now safely uses optional chaining (good!), but the insertion on line 43 still doesn't check for an existing element. If multiple stories mount simultaneously (e.g., in docs mode), duplicate <svg> elements with the same ID could be inserted.

🔎 Add existence check before insertion
  useEffect(() => {
-    document.body.insertAdjacentHTML('beforeend', filterDefs);
+    const existingFilters = document.getElementById('storybook-a11y-vision-filters');
+    if (!existingFilters) {
+      document.body.insertAdjacentHTML('beforeend', filterDefs);
+    }

    return () => {
      const filterDefsElement = document.getElementById('storybook-a11y-vision-filters');
      filterDefsElement?.parentElement?.removeChild(filterDefsElement);
    };
  }, []);
🧹 Nitpick comments (1)
code/addons/a11y/src/withVisionSimulator.ts (1)

7-8: Consider the regex construction approach.

The regex is built from filter strings that contain special characters like parentheses, quotes, and hashes. Word boundaries (\b) may not behave as expected with these characters in all contexts (e.g., \b after ) might not match correctly).

Since the filters come from a trusted local module, the static analysis ReDoS warning is likely a false positive. However, if you encounter issues with filter removal, consider escaping special regex characters or using a simpler string-based approach.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b17cdb0 and 3830aed.

📒 Files selected for processing (1)
  • code/addons/a11y/src/withVisionSimulator.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/addons/a11y/src/withVisionSimulator.ts
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/addons/a11y/src/withVisionSimulator.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/addons/a11y/src/withVisionSimulator.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/a11y/src/withVisionSimulator.ts
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/addons/a11y/src/withVisionSimulator.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.
📚 Learning: 2025-11-05T09:37:25.920Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/tooltip/WithTooltip.tsx:54-96
Timestamp: 2025-11-05T09:37:25.920Z
Learning: Repo: storybookjs/storybook — In code/core/src/components/components/tooltip/WithTooltip.tsx, the legacy WithTooltip implementation is intentionally reintroduced for backward compatibility and is deprecated; maintainers (per Sidnioulz) do not want maintenance or improvements on it. Prefer WithTooltipNew/Popover; avoid suggesting changes to WithTooltip.* going forward.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
📚 Learning: 2025-11-05T09:36:55.944Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Tabs/Tabs.stories.tsx:222-227
Timestamp: 2025-11-05T09:36:55.944Z
Learning: Repo: storybookjs/storybook PR: 32458 — In code/core/src/components/components/Button/Button.tsx (React/TypeScript), ButtonProps includes ariaLabel?: string | false and the component maps it to the DOM aria-label. Convention: ariaLabel is mandatory on all Button usages — provide a descriptive string for icon-only buttons; set ariaLabel=false when the button’s children already serve as the accessible name. Do not suggest using a raw aria-label prop on Button call sites.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: In viewport tool code, when using the `useGlobals` hook from storybook/manager-api, the third returned value `storyGlobals` is guaranteed by TypeScript to be defined (not undefined/null), making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/addons/a11y/src/withVisionSimulator.ts
🧬 Code graph analysis (1)
code/addons/a11y/src/withVisionSimulator.ts (2)
code/addons/a11y/src/visionSimulatorFilters.ts (2)
  • filters (1-46)
  • filterDefs (48-100)
code/frameworks/angular/src/client/public-types.ts (1)
  • StoryFn (35-38)
🪛 ast-grep (0.40.3)
code/addons/a11y/src/withVisionSimulator.ts

[warning] 7-7: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(\\b(${knownFilters.join('|')})\\b, 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: nx
  • GitHub Check: Core Unit Tests, windows-latest

@github-actions github-actions Bot added the Stale label Jan 7, 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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @code/addons/a11y/src/components/A11YPanel.test.tsx:
- Line 2: The triple-slash TypeScript directive at the top of the test file is
terminated with an extra semicolon which makes the directive invalid; remove the
trailing semicolon from the triple-slash reference directive (the line starting
with /// <reference types="@testing-library/jest-dom">) so it becomes a proper
TS triple-slash directive without a semicolon.
🧹 Nitpick comments (1)
code/addons/a11y/src/components/A11YPanel.test.tsx (1)

15-23: Align mocking patterns with coding guidelines.

The current mocking setup has two deviations from the project's testing guidelines:

  1. Lines 15 and 18: vi.mock() calls are missing the spy: true option
  2. Lines 21-23: Mock implementation is outside a beforeEach block

As per coding guidelines, all mocks should use spy: true and mock behaviors should be implemented in beforeEach blocks for consistency and proper cleanup between tests.

♻️ Proposed refactor
-vi.mock('storybook/manager-api');
+vi.mock('storybook/manager-api', { spy: true });
 const mockedManagerApi = vi.mocked(managerApi);
 
-vi.mock('./A11yContext');
+vi.mock('./A11yContext', { spy: true });
 const mockedUseA11yContext = vi.mocked(useA11yContext);
 
-mockedManagerApi.useParameter.mockReturnValue({
-  manual: false,
-} as any);

Then add a beforeEach block before the test suite:

describe('A11YPanel', () => {
  beforeEach(() => {
    mockedManagerApi.useParameter.mockReturnValue({
      manual: false,
    } as any);
  });

  // ... rest of tests
});
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3830aed and b7a6c6a.

📒 Files selected for processing (1)
  • code/addons/a11y/src/components/A11YPanel.test.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{test,spec}.{ts,tsx}: Test files should follow the naming pattern *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx
Follow the spy mocking rules defined in .cursor/rules/spy-mocking.mdc for consistent mocking patterns with Vitest

Files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access the mocked functions in Vitest tests
Implement mock behaviors in beforeEach blocks in Vitest tests
Mock all required dependencies that the test subject uses
Each mock implementation should return a Promise for async functions in Vitest
Mock implementations should match the expected return type of the original function
Mock all required properties and methods that the test subject uses in Vitest tests
Avoid direct function mocking without vi.mocked() in Vitest tests
Avoid mock implementations outside of beforeEach blocks in Vitest tests
Avoid mocking without the spy: true option in Vitest tests
Avoid inline mock implementations within test cases in Vitest tests
Avoid mocking only a subset of required dependencies in Vitest tests
Mock at the highest level of abstraction needed in Vitest tests
Keep mock implementations simple and focused in Vitest tests
Use type-safe mocking with vi.mocked() in Vitest tests
Document complex mock behaviors in Vitest tests
Group related mocks together in Vitest tests

Files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns
Achieve high test coverage of business logic, aiming for 75%+ coverage of statements/lines
Cover all branches, conditions, edge cases, error paths, and different input variations in unit tests
Use vi.mock() to mock file system, loggers, and other external dependencies in tests

Files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
🧠 Learnings (17)
📓 Common learnings
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.
📚 Learning: 2025-11-05T09:36:55.944Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Tabs/Tabs.stories.tsx:222-227
Timestamp: 2025-11-05T09:36:55.944Z
Learning: Repo: storybookjs/storybook PR: 32458 — In code/core/src/components/components/Button/Button.tsx (React/TypeScript), ButtonProps includes ariaLabel?: string | false and the component maps it to the DOM aria-label. Convention: ariaLabel is mandatory on all Button usages — provide a descriptive string for icon-only buttons; set ariaLabel=false when the button’s children already serve as the accessible name. Do not suggest using a raw aria-label prop on Button call sites.

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required properties and methods that the test subject uses in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Keep mock implementations simple and focused in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Group related mocks together in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-10-03T07:55:42.639Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/manager/components/preview/Toolbar.tsx:102-105
Timestamp: 2025-10-03T07:55:42.639Z
Learning: In code/core/src/manager/components/preview/Toolbar.tsx, we intentionally do not add aria-label/aria-labelledby to StyledToolbar (AbstractToolbar) because the enclosing section is already labeled via an sr-only heading and the toolbar is the only content. Revisit only if real user testing indicates a need.

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in `beforeEach` blocks in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `vi.mocked()` to type and access the mocked functions in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mock implementations outside of `beforeEach` blocks in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid direct function mocking without `vi.mocked()` in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use type-safe mocking with `vi.mocked()` in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock at the highest level of abstraction needed in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `vi.mock()` with the `spy: true` option for all package and file mocks in Vitest tests

Applied to files:

  • code/addons/a11y/src/components/A11YPanel.test.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
  • GitHub Check: nx

Comment thread code/addons/a11y/src/components/A11YPanel.test.tsx Outdated
Copy link
Copy Markdown
Member

@ndelangen ndelangen left a comment

Choose a reason for hiding this comment

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

Amazing work @ghengeveld this is an fantastic improvement!

I was going to suggest we add stories for this new behavior, but then I noticed that you did 👏

Merge it!

@ghengeveld ghengeveld merged commit d03a3ee into next Jan 8, 2026
69 checks passed
@ghengeveld ghengeveld deleted the vision-simulator-global branch January 8, 2026 09:53
@ghengeveld ghengeveld removed the Stale label Jan 14, 2026
@ghengeveld ghengeveld added the needs qa Indicates that this needs manual QA during the upcoming minor/major release label Jan 14, 2026
@ndelangen ndelangen removed the needs qa Indicates that this needs manual QA during the upcoming minor/major release label Jan 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants