Skip to content

.pr_agent_accepted_suggestions

qodo-merge-bot edited this page Aug 27, 2026 · 32 revisions
                     PR 3489 (2026-08-27)                    
[correctness] Docs import deleted list paths
Docs import deleted list paths The extraction relocates BaseList and BaseItem, but the canonical BaseList story still imports their now-deleted `core/src/components` paths, so Storybook cannot resolve either module. Rewire the story to the new package and declare that package as a direct docs dependency.

Issue description

The BaseList Storybook story imports BaseList and BaseItem from source directories removed by this extraction, causing unresolved-module failures.

Issue Context

Import both components from @vibe/base-list, and add @vibe/base-list as a direct dependency of @vibe/docs rather than relying on @vibe/core transitively.

Fix Focus Areas

  • packages/docs/src/pages/components/BaseList/BaseList.stories.tsx[3-4]
  • packages/docs/package.json[24-29]


                     PR 3486 (2026-08-26)                    
[maintainability] `StepsGalleryHeader` lacks component ID
`StepsGalleryHeader` lacks component ID The PR newly exposes `StepsGalleryHeader` from the standalone package without registering a corresponding `ComponentVibeId`. The new public component therefore does not participate in the repository's component identifier system.

Issue description

StepsGalleryHeader is newly exported as a public standalone-package component but has no ComponentVibeId registration.

Issue Context

Add a distinct shared component ID and apply it as data-vibe on the component root while preserving the intentional decision not to re-export this symbol from core.

Fix Focus Areas

  • packages/components/wizard/src/Steps/index.ts[3-3]
  • packages/components/wizard/src/Steps/StepsGalleryHeader.tsx[5-5]
  • packages/components/wizard/src/Steps/StepsGalleryHeader.tsx[66-69]
  • packages/shared/src/tests/constants.ts[181-188]


                     PR 3483 (2026-08-25)                    
[correctness] Core exposes internal `FieldLabel`
Core exposes internal `FieldLabel` The wildcard re-export exposes every `@vibe/text-inputs` root symbol through `@vibe/core`, including `FieldLabel` and `FieldLabelProps`, although core is intended to preserve only the existing `TextField`, `TextArea`, and `NumberField` API. This unintentionally expands core's supported public API and subjects future `FieldLabel` changes to compatibility constraints.

Issue description

@vibe/core uses a wildcard export from @vibe/text-inputs, unintentionally publishing the package-only FieldLabel and FieldLabelProps symbols through core.

Issue Context

Core should preserve its prior public surface by selectively re-exporting only TextField, TextArea, NumberField, and their intended public types from the standalone package. The text-inputs root barrel includes FieldLabel, so wildcard-exporting that barrel expands core's supported API and creates compatibility constraints for future FieldLabel changes.

Fix Focus Areas

  • packages/core/src/components/index.ts[55-55]
  • packages/components/text-inputs/src/index.ts[1-4]

[correctness] Slider TextField mock is stale
Slider TextField mock is stale `SelectionIndicator` now imports the named `TextField` export from `@vibe/text-inputs`, while all three Slider suites still mock the deleted `../../TextField/TextField` module. The mock therefore no longer intercepts the rendered component, so snapshots expecting `mock-text-field-comp` fail.

Issue description

The Slider tests mock the removed core-local TextField path, but SelectionIndicator now imports TextField from @vibe/text-inputs. Update the mocks to intercept the named package export so existing Slider behavior and snapshots remain isolated.

Issue Context

Preserve any other actual @vibe/text-inputs exports if needed, and provide TextField as a named mock export rather than a default export.

Fix Focus Areas

  • packages/core/src/components/Slider/tests/Slider-non-ranged.test.tsx[9-13]
  • packages/core/src/components/Slider/tests/Slider-ranged.test.tsx[9-13]
  • packages/core/src/components/Slider/tests/Slider.snapshot.test.tsx[12-16]


                     PR 3478 (2026-08-24)                    
[reliability] Outdated pinned dependencies
Outdated pinned dependencies `@vibe/attention-box` pins multiple `@vibe/*` dependencies to older patch versions than the versions currently used in this repo (and by `@vibe/core`), which can force consumers to install duplicate copies of these packages. This increases bundle size and can create subtle runtime/type skew when `@vibe/core` and `@vibe/attention-box` are used together.

Issue description

The new @vibe/attention-box package.json pins several @vibe/* dependencies to older patch versions than the versions currently present in the monorepo and used by @vibe/core. When published, installing @vibe/core will bring in @vibe/attention-box, which will then pull older versions of @vibe/button, @vibe/shared, etc., leading to duplicate installs and potential runtime/version skew.

Issue Context

  • @vibe/attention-box currently depends on older patch versions (e.g. @vibe/button 4.0.7, @vibe/shared 4.0.5).
  • In this same PR branch, the repo’s current versions are newer (e.g. @vibe/button 4.0.8, @vibe/shared 4.0.6) and @vibe/core depends on those newer versions.

Fix Focus Areas

Update packages/components/attention-box/package.json dependency versions to match the current workspace package versions (or use your repo’s standard policy such as workspace:* / ^ ranges).

  • packages/components/attention-box/package.json[40-49]


                     PR 3477 (2026-08-24)                    
[reliability] Shared version mismatch
Shared version mismatch @vibe/accordion pins @vibe/shared to 4.0.3 while the workspace version is 4.0.5 (and other packages depend on 4.0.5), which can prevent workspace linking and cause a different published @vibe/shared to be installed. That can break the build (missing exports like ComponentVibeId/useMergeRef) or produce multiple installed @vibe/shared copies in consumers.

Issue description

@vibe/accordion depends on @vibe/shared version 4.0.3, but this monorepo’s workspace @vibe/shared is 4.0.5 and other packages already pin to 4.0.5. With exact versions, this can prevent workspace resolution and pull an older published @vibe/shared, causing missing exports and/or duplicated installs.

Issue Context

  • @vibe/accordion imports ComponentVibeId, VibeComponentProps, and useMergeRef from @vibe/shared, so resolving to an older shared version is high risk.

Fix Focus Areas

  • packages/components/accordion/package.json[39-44]

Proposed fix

  • Change @vibe/shared dependency in packages/components/accordion/package.json from 4.0.3 to 4.0.5 (matching the workspace and other packages).


                     PR 3474 (2026-08-23)                    
[reliability] Workspace version mismatches
Workspace version mismatches @vibe/alert-banner pins @vibe/* dependencies to versions that do not match the workspace package versions in this repo, so Yarn/Lerna may treat them as external (registry) dependencies rather than local workspace links. This can break monorepo builds/tests (wrong dependency graph / missing local changes) or make the package compile against different APIs than the repo actually contains.

Issue description

packages/components/alert-banner/package.json pins several @vibe/* dependencies to versions older than the versions of those packages present in this monorepo. In Yarn workspaces/Lerna, a dependency is only treated as a workspace/local package when its version range satisfies the workspace package version; otherwise it can be installed from the registry and excluded from the local package graph.

Issue Context

This repo uses Yarn workspaces and Lerna for build/test orchestration. Version mismatches can cause:

  • Building/testing against published packages instead of the local workspace packages.
  • Incorrect lerna --include-dependencies build ordering (dependency edges not recognized).

Fix Focus Areas

  • packages/components/alert-banner/package.json[40-50]
  • package.json[5-23]
  • scripts/build-dependencies.sh[1-1]

Proposed fix

Update @vibe/alert-banner dependency versions to match the workspace package versions in this repo (or use a workspace protocol/range that satisfies them). Concretely, align at least:

  • @vibe/button to 4.0.7
  • @vibe/hooks to 4.0.7
  • @vibe/icon-button to 4.0.12
  • @vibe/shared to 4.0.5
  • @vibe/tooltip to 4.0.12
  • @vibe/typography to 4.0.12 (Keep @vibe/link at 4.0.3 and @vibe/icons at 4.1.0 if those already match.)

[maintainability] Duplicate icons dependency
Duplicate icons dependency @vibe/icons is listed in both dependencies and devDependencies in @vibe/alert-banner, which increases the chance of duplicate installs/version skew and is inconsistent with other packages’ patterns. It should be listed only where needed (typically dependencies only if used at runtime).

Issue description

@vibe/icons is declared in both dependencies and devDependencies for @vibe/alert-banner.

Issue Context

Other component packages typically keep @vibe/icons in devDependencies when only used for tests/examples, or in dependencies when used at runtime. Duplicating it in both sections is unnecessary and can lead to drift.

Fix Focus Areas

  • packages/components/alert-banner/package.json[40-61]

Proposed fix

Keep @vibe/icons only in dependencies (since AlertBanner.tsx imports CloseSmall at runtime) and remove it from devDependencies.



                     PR 3473 (2026-08-23)                    
[reliability] Shared version mismatch
Shared version mismatch `@vibe/transitions` depends on `@vibe/shared` v4.0.3 while the workspace `@vibe/shared` package is v4.0.5, which can prevent workspace linking and/or pull a different published version with potentially different exports. This can break builds/tests or cause runtime/type inconsistencies depending on which `@vibe/shared` gets resolved.

Issue description

@vibe/transitions pins @vibe/shared to 4.0.3, but the repo’s @vibe/shared workspace package is 4.0.5. With exact version pinning, this can prevent Yarn/Lerna from linking the workspace package and instead resolve a different registry version (or fail if unavailable), causing build/test failures or missing exports.

Issue Context

Most packages in this monorepo pin internal dependencies to the exact workspace version (e.g. @vibe/shared: 4.0.5). The new package should follow the same pattern.

Fix Focus Areas

  • packages/components/transitions/package.json[39-43]

Suggested fix

Update @vibe/shared dependency version in @vibe/transitions to match the workspace version (currently 4.0.5), consistent with other packages.


[correctness] Exports snapshot will fail
Exports snapshot will fail `@vibe/core` now re-exports `SlideTransition` from `@vibe/transitions`, which changes `Object.keys(components)` in `packages/core/src/__tests__/exports.test.ts`. The snapshot currently contains `TransitionView` but not `SlideTransition`, so this PR likely breaks the exports snapshot test.

Issue description

The @vibe/core components barrel now exports SlideTransition, which changes the set of exported keys used by the exports snapshot test. The snapshot currently expects TransitionView but does not include SlideTransition, so tests will fail.

Issue Context

packages/core/src/__tests__/exports.test.ts snapshots Object.keys(components).sort(). Any new named export from packages/core/src/components/index.ts must be reflected in exports.test.ts.snap, or the export must be removed if it’s unintended.

Fix Focus Areas

  • packages/core/src/components/index.ts[77-84]
  • packages/core/src/tests/exports.test.ts[6-9]
  • packages/core/src/tests/snapshots/exports.test.ts.snap[101-117]

Suggested fix

Either:

  1. If SlideTransition is intended to be part of @vibe/core public exports, update the snapshot to include SlideTransition (run the test suite with snapshot update).
  2. If it’s not intended to be exported from core, remove SlideTransition from the re-export list in packages/core/src/components/index.ts.

[performance] Build ignores skip flag
Build ignores skip flag `@vibe/transitions` always builds mocked classnames (`mock_classnames=on rollup -c`) and does not respect `SKIP_RELEASE_ARTIFACTS`, unlike other packages. This undermines the CI workflow’s `SKIP_RELEASE_ARTIFACTS` optimization and can increase build time/artifact generation unexpectedly.

Issue description

@vibe/transitions build script always runs the mocked-classnames rollup build, ignoring the repo-wide SKIP_RELEASE_ARTIFACTS flag used in CI.

Issue Context

The GitHub workflow sets SKIP_RELEASE_ARTIFACTS when running lerna run build. Other packages implement a build:mocked-classnames script that conditionally skips the second build when SKIP_RELEASE_ARTIFACTS=true.

Fix Focus Areas

  • packages/components/transitions/package.json[34-37]
  • .github/workflows/build-and-upload.yml[38-45]

Suggested fix

Match the standard pattern used by other component packages:

  • Set build to rollup -c && yarn build:mocked-classnames
  • Add build:mocked-classnames: [ "$SKIP_RELEASE_ARTIFACTS" = "true" ] || mock_classnames=on rollup -c


                     PR 3472 (2026-08-23)                    
[performance] Pinned deps cause duplication
Pinned deps cause duplication @vibe/toggle pins older exact versions of @vibe/shared/@vibe/style/@vibe/typography than @vibe/core, so installing @vibe/core can pull multiple versions of these libraries and inflate bundle size (and potentially duplicate styles/runtime utilities). This is introduced by the new package.json and is amplified because @vibe/core now depends on @vibe/toggle.

Issue description

@vibe/toggle pins exact dependency versions that are older than the ones @vibe/core uses. Because @vibe/core now depends on @vibe/toggle, consumers of @vibe/core may end up with multiple installed copies of @vibe/shared, @vibe/style, and @vibe/typography, increasing bundle size and risking subtle inconsistencies.

Issue Context

  • @vibe/toggle dependencies: @vibe/shared@4.0.3, @vibe/style@4.0.0, @vibe/typography@4.0.6.
  • @vibe/core dependencies: @vibe/shared@4.0.5, @vibe/style@4.1.0, @vibe/typography@4.0.12.

Fix Focus Areas

  • packages/components/toggle/package.json[39-45]
  • packages/core/package.json[118-126]

Suggested fix

Update @vibe/toggle to use the same versions as @vibe/core (or adopt an internal policy such as keeping all @vibe/* deps aligned to the repo’s current patch), so package managers can dedupe cleanly.


[reliability] Hardcoded node_modules paths
Hardcoded node_modules paths @vibe/toggle’s tsconfig hardcodes `typeRoots` and `paths` to `../../../node_modules`, unlike the other component packages, making builds fragile under non-hoisted installs (and incompatible with environments without node_modules such as Yarn PnP). This configuration increases maintenance risk and can cause module/type resolution to behave differently from the rest of the monorepo.

Issue description

packages/components/toggle/tsconfig.json hardcodes typeRoots and a paths mapping pointing to ../../../node_modules. This is inconsistent with other component packages and can break type/module resolution in setups that don’t have a physical node_modules tree at that location.

Issue Context

Other component packages (e.g. @vibe/checkbox) rely on the shared @vibe/config/tsconfig without overriding typeRoots/paths, keeping resolution consistent across the monorepo.

Fix Focus Areas

  • packages/components/toggle/tsconfig.json[1-10]
  • packages/components/checkbox/tsconfig.json[1-8]

Suggested fix

Remove the typeRoots and paths overrides unless there is a proven, documented need. If path mapping is required, prefer a workspace-consistent approach (e.g. using standard Node resolution, or a repo-wide TS path config) rather than hardcoding to ../../../node_modules.



                     PR 3471 (2026-08-23)                    
[performance] Build script skips convention
Build script skips convention `@vibe/theme-provider`’s `build` script always runs the mocked_classnames rollup build and does not honor the repo’s common `SKIP_RELEASE_ARTIFACTS` guard used by other component packages. This increases build time and deviates from established release-artifact behavior.

Issue description

The new package uses "build": "rollup -c && mock_classnames=on rollup -c" with no SKIP_RELEASE_ARTIFACTS check and no separate build:mocked-classnames script. Other component packages standardize on build:mocked-classnames with a guard to skip these artifacts.

Issue Context

Keeping consistent build scripts across component packages helps CI performance and predictable release behavior.

Fix Focus Areas

  • packages/components/theme-provider/package.json[34-37]

Suggested fix

  • Update scripts to match the established pattern:
  • "build": "rollup -c && yarn build:mocked-classnames"
  • "build:mocked-classnames": "[ \"$SKIP_RELEASE_ARTIFACTS\" = \"true\" ] || mock_classnames=on rollup -c"
  • Ensure lerna/yarn workflows that rely on SKIP_RELEASE_ARTIFACTS behave the same for this new package.


                     PR 3469 (2026-08-20)                    
[correctness] Missing style dependency
Missing style dependency `@vibe/tabs` SCSS imports `@vibe/style`, but `packages/components/tabs/package.json` does not declare `@vibe/style` in `dependencies`, so consumers may fail to resolve Sass imports when using `@vibe/tabs` outside the monorepo. This is a publish-time/runtime build break for the new package.

Issue description

@vibe/tabs imports @vibe/style from SCSS (~@vibe/style/dist/mixins), but the package does not list @vibe/style in dependencies. When published/consumed independently, Sass compilation (or any build step resolving these imports) can fail with a module-not-found error.

Issue Context

Other component packages that import @vibe/style in their SCSS declare it as a direct dependency.

Fix Focus Areas

  • packages/components/tabs/package.json[40-48]
  • packages/components/tabs/src/Tab/Tab.module.scss[1-3]

What to change

Add "@vibe/style": "4.1.0" (or the repo-standard current @vibe/style version) to dependencies in packages/components/tabs/package.json.



                     PR 3468 (2026-08-20)                    
[performance] Artifact skip flag ignored
Artifact skip flag ignored The Skeleton build always runs the mocked-classnames Rollup pass, so builds using `SKIP_RELEASE_ARTIFACTS=true` still generate and upload `dist/mocked_classnames`. This adds an unnecessary second compilation and defeats the workflow's artifact-skip control for this package.

Issue description

The Skeleton package always builds mocked-classname release artifacts, even when SKIP_RELEASE_ARTIFACTS=true requests that these artifacts be skipped.

Issue Context

Other extracted component packages expose a separate guarded build:mocked-classnames script. The shared Rollup configuration writes mocked builds to dist/mocked_classnames, and CI passes SKIP_RELEASE_ARTIFACTS into package builds.

Fix Focus Areas

  • packages/components/skeleton/package.json[34-37]

[maintainability] Shared dependency version mismatch
Shared dependency version mismatch `@vibe/skeleton` pins `@vibe/shared` 4.0.3 while its direct consumer `@vibe/core` and every sibling component package use 4.0.4. Installing core therefore requires incompatible exact shared versions, duplicating the package and leaving Skeleton on the older implementation.

Issue description

The new Skeleton package pins @vibe/shared 4.0.3, whereas the current workspace package and consuming core package are version 4.0.4.

Issue Context

Skeleton uses runtime utilities from @vibe/shared, not only types. Exact mismatched versions prevent the dependency graph from using one consistent shared release.

Fix Focus Areas

  • packages/components/skeleton/package.json[39-43]


                     PR 3446 (2026-07-27)                    
[correctness] Missing core export
Missing core export `@vibe/core` no longer exports `EditableTypography`, so `import { EditableTypography } from "@vibe/core"` will fail for existing consumers. Core already depends on `@vibe/editable` and re-exports `EditableHeading`/`EditableText`, but does not re-export `EditableTypography`.

Issue description

@vibe/core’s components barrel re-exports EditableHeading and EditableText from @vibe/editable, but it no longer re-exports EditableTypography. This is a breaking change for consumers importing EditableTypography from @vibe/core.

Issue Context

  • @vibe/core’s public entrypoint re-exports everything from ./components.
  • @vibe/editable exports EditableTypography from its own index.

Fix Focus Areas

  • packages/core/src/components/index.ts[31-35]

Suggested fix

Update the @vibe/editable re-export line to include EditableTypography (and EditableTypographyProps at minimum), e.g.:


[reliability] Undeclared style dependency
Undeclared style dependency `@vibe/editable` imports Sass mixins/functions from `@vibe/style/dist/*` but `packages/components/editable/package.json` does not declare `@vibe/style` as a dependency, which can cause the package build to fail (unresolved Sass imports) when `@vibe/style` isn’t hoisted/available or isn’t built first in topological builds.

Issue description

@vibe/editable uses Sass imports from @vibe/style/dist/... but does not list @vibe/style in its dependencies. This creates a non-deterministic build that can fail when dependencies aren’t hoisted or when build order doesn’t build @vibe/style first.

Issue Context

Multiple SCSS files in the new package import @vibe/style/dist/mixins and @vibe/style/dist/functions. Other component packages that import these Sass assets (e.g. @vibe/typography) declare @vibe/style directly, and @vibe/style’s build script is responsible for producing the dist/mixins and dist/functions folders.

Fix

Add "@vibe/style": "4.0.0" (or the repo-standard compatible version) to packages/components/editable/package.json under dependencies.

Fix Focus Areas

  • packages/components/editable/package.json[39-45]


                     PR 3445 (2026-07-27)                    
[correctness] Missing style dependency
Missing style dependency @vibe/counter imports Sass mixins from @vibe/style but does not declare @vibe/style in its dependencies, which can break building/consuming the package when @vibe/style isn’t otherwise installed/hoisted.

Issue description

packages/components/counter/src/Counter/Counter.module.scss imports ~@vibe/style/dist/mixins, but packages/components/counter/package.json does not list @vibe/style in dependencies. This makes the package’s build and/or isolated consumption rely on incidental workspace hoisting.

Issue Context

Other component packages that import the same @vibe/style mixins declare @vibe/style as a direct dependency.

Fix Focus Areas

  • packages/components/counter/package.json[39-44]

[maintainability] Unconditional mocked-classnames build
Unconditional mocked-classnames build @vibe/counter’s build script always runs the mocked-classnames Rollup build and does not follow the repo’s common `build:mocked-classnames` + `SKIP_RELEASE_ARTIFACTS` guard pattern, which can cause inconsistent CI behavior and unnecessary extra build work.

Issue description

Most packages use build:mocked-classnames with a SKIP_RELEASE_ARTIFACTS guard and have build call it. @vibe/counter currently runs mock_classnames=on rollup -c unconditionally, which deviates from the established convention.

Issue Context

This pattern exists in multiple packages (including @vibe/core) and is likely used to skip expensive artifact generation in some CI/release flows.

Fix Focus Areas

  • packages/components/counter/package.json[34-38]


                     PR 3441 (2026-07-20)                    
[reliability] Core-package dependency cycle
Core-package dependency cycle @vibe/core now depends on @vibe/color-picker, while @vibe/color-picker imports runtime symbols from @vibe/core, creating a circular module/package dependency that can yield partially-initialized/undefined exports at runtime and unstable bundling behavior.

Issue description

@vibe/core re-exports from @vibe/color-picker, but the new @vibe/color-picker package imports useGridKeyboardNavigation / GridKeyboardNavigationContext from @vibe/core, forming a circular dependency. This risks circular ESM evaluation (undefined exports / initialization order bugs) and complicates builds.

Issue Context

  • @vibe/core depends on @vibe/color-picker.
  • @vibe/color-picker currently depends on and imports from @vibe/core.
  • The @vibe/core root entry also has side-effect imports (see separate finding).

Fix Focus Areas

  • packages/components/color-picker/package.json[40-51]
  • packages/core/package.json[91-107]
  • packages/components/color-picker/src/ColorPicker/components/ColorPickerContent/ColorPickerContent.tsx[19-23]
  • packages/components/color-picker/src/ColorPicker/components/ColorPickerContent/ColorPickerColorsGrid.tsx[1-12]
  • packages/components/color-picker/src/ColorPicker/components/ColorPickerContent/ColorPickerClearButton.tsx[1-7]

Suggested approach

  1. Remove @vibe/core as a dependency of @vibe/color-picker.
  2. Move the needed keyboard-navigation hook/context to a lower-level package that both can depend on (e.g. @vibe/shared or @vibe/hooks), or copy the minimal implementation into @vibe/color-picker.
  3. Update @vibe/core to re-export those APIs from the new location (preserving public API), and update @vibe/color-picker imports to use the new location (not @vibe/core).

[reliability] Pinned core version mismatch
Pinned core version mismatch @vibe/color-picker pins @vibe/core to 4.0.0, but the workspace @vibe/core package is 4.5.3; depending on package-manager workspace rules this can resolve a different core version than the local source, producing inconsistent builds/tests.

Issue description

The new package declares an exact dependency on @vibe/core version 4.0.0, but the repo’s @vibe/core workspace version is 4.5.3. With exact pins, workspace linking can be skipped and a registry version may be used instead of local sources.

Issue Context

This also exacerbates the circular dependency risk by potentially introducing multiple instances/versions of @vibe/core.

Fix Focus Areas

  • packages/components/color-picker/package.json[40-50]
  • packages/core/package.json[1-5]

Suggested approach

  • If @vibe/color-picker must depend on @vibe/core, change the version to match the workspace (4.5.3) or use the repo’s standard workspace dependency strategy.
  • Preferably (and consistent with other separated component packages), remove the dependency on @vibe/core entirely and depend on lower-level packages instead.

[maintainability] Duplicate SVG mock
Duplicate SVG mock packages/components/color-picker/src/ColorPicker/__tests__/ColorPicker.test.tsx adds a local react-inlinesvg mock even though Vitest already loads vitest.setup.mjs (which defines the same mock) for the package test run. Keeping both mocks is redundant and can lead to confusion or inconsistent behavior if one mock implementation changes and the other doesn’t.

Issue description

ColorPicker.test.tsx defines a vi.mock("react-inlinesvg"), but this mock is already provided globally by vitest.setup.mjs (loaded via @vibe/config's setupFiles). This duplication increases maintenance overhead and can cause confusion if the mocks diverge.

Issue Context

The base Vitest config loads ./vitest.setup.mjs automatically, and the color-picker package has its own vitest.setup.mjs with the same mock.

Fix Focus Areas

  • Remove the redundant vi.mock("react-inlinesvg", ...) block from the test file and rely on vitest.setup.mjs.
  • packages/components/color-picker/src/ColorPicker/tests/ColorPicker.test.tsx[1-9]


                     PR 3440 (2026-07-20)                    
[maintainability] Misleading Checkbox export TODO
Misleading Checkbox export TODO The TODO comment in @vibe/core says the wildcard re-export is blocked by “enums”, but @vibe/checkbox currently exports only Checkbox and CheckboxProps; this mismatch can confuse future maintainers about why the export is not `export *`.

Issue description

@vibe/core has a TODO comment implying it can't export * from "@vibe/checkbox" due to enums, but @vibe/checkbox currently exports only Checkbox and CheckboxProps. This comment is misleading and may cause incorrect assumptions during future refactors.

Issue Context

  • @vibe/core currently does a named re-export for Checkbox.
  • @vibe/checkbox entrypoints only expose Checkbox + CheckboxProps.

Fix Focus Areas

  • packages/core/src/components/index.ts[10-11]


                     PR 3435 (2026-07-14)                    
[correctness] Missing radius recommendation
Missing radius recommendation Adding numeric border-radius vars makes 4px/8px/16px map to multiple allowed CSS vars, but no recommended var is configured for border-radius values. This can cause the stylelint rule’s autofix path (when useRecommendedFixes is enabled) to emit invalid CSS (var(undefined)) and can also break the props-to-allowed-vars unit test logic that assumes recommendations exist for multi-option values.

Issue description

New numeric border-radius tokens create duplicate replacements for the same canonical values (e.g., 16px now matches both --border-radius-big and --border-radius-16). The stylelint rule’s autofix logic uses recommended when multiple replacements exist; for border-radius props recommended is currently undefined, leading to var(undefined) when useRecommendedFixes: true. The unit tests also assume recommended is iterable for multi-option values and will fail/throw once duplicates exist.

Issue Context

  • BORDER_RADIUSES now includes both semantic and numeric vars.
  • getPropsToAllowedCssVars() groups vars by canonical value; duplicates are expected after this PR.
  • Fix-mode behavior must remain deterministic and produce valid CSS.

Fix Focus Areas

  • packages/style/stylelint-config/rules/use-defined-css-var-when-available/props-to-allowed-vars.js[16-24]
  • packages/style/stylelint-config/rules/use-defined-css-var-when-available/props-to-allowed-vars.js[140-168]
  • packages/style/stylelint-config/rules/use-defined-css-var-when-available/index.js[68-88]
  • packages/style/stylelint-config/rules/use-defined-css-var-when-available/tests/props-to-allowed-vars.test.js[54-87]
  • packages/style/stylelint-config/rules/use-defined-css-var-when-available/tests/index.test.js[52-96]

What to change

  1. Choose a single recommended token per duplicated canonical border-radius value (e.g., prefer semantic tokens --border-radius-small/medium/big to preserve existing behavior, or prefer numeric tokens to promote primitives) and pass them via mapPropsToAllowedVars(..., ..., recommendedList) for BORDER_RADIUSES_PROPS.
  2. Harden autofix: if useRecommendedFixes is enabled but recommended is missing/undefined for a value, do not apply a fix (avoid emitting var(undefined)), and keep reporting the warning.
  3. Update/adjust tests to reflect the new multi-option reality:
  • Ensure the recommendation tests don’t crash when recommended is absent.
  • Update expected warning text / expected fixed output depending on your chosen recommended token.

[maintainability] Border-radius autofix stops
Border-radius autofix stops Adding numeric border-radius vars makes 4px/8px/16px resolve to multiple allowed variables, and the stylelint plugin skips fixes for multi-option values unless `useRecommendedFixes` is enabled. `@vibe/core` runs `stylelint:fix` without that option, so raw border-radius literals may remain unfixed even when using `--fix`.

Issue description

After adding --border-radius-4/8/16 alongside --border-radius-small/medium/big, the same canonical values now have multiple valid token replacements. The stylelint rule only autofixes multi-option values when useRecommendedFixes is enabled, so existing stylelint --fix workflows will stop converting border-radius: 4px/8px/16px into token usage.

Issue Context

  • The plugin fix logic returns early for multi-option values unless secondaryOptionObject.useRecommendedFixes is true.
  • packages/core config does not set useRecommendedFixes, but does provide a stylelint:fix script.

Fix Focus Areas

  • packages/core/.stylelintrc.json[1-12]
  • packages/style/stylelint-config/index.js[1-7]
  • packages/style/stylelint-config/rules/use-defined-css-var-when-available/index.js[56-88]
  • packages/style/stylelint-config/rules/use-defined-css-var-when-available/props-to-allowed-vars.js[157-166]

Suggested change

Update the stylelint rule configuration to include useRecommendedFixes: true (while preserving existing severity overrides), e.g.:



                     PR 3408 (2026-06-15)                    
[correctness] Fixed class not applied
Fixed class not applied `useFixedPosition` does not actually switch the modal to `position: fixed` because `.modal { position: relative; }` is declared later with the same specificity, overriding `.fixedPosition`. Consumers enabling `useFixedPosition` will still see the RTL centering issue because the modal remains relatively positioned.

Issue description

The new .fixedPosition { position: fixed; } class is overridden by the later .modal { position: relative; } rule (same specificity; later wins), so useFixedPosition is ineffective.

Issue Context

Modal.tsx applies both styles.modal and styles.fixedPosition to the same element. With current SCSS ordering, the browser keeps position: relative.

Fix Focus Areas

  • packages/core/src/components/Modal/Modal/Modal.module.scss[26-83]

Suggested changes

  • Increase specificity by scoping the override under .modal, e.g. inside .modal { &.fixedPosition { position: fixed; } }, or define .modal.fixedPosition { position: fixed; } after the base .modal position declaration.
  • Avoid !important unless there’s no cleaner cascade solution.


                     PR 3362 (2026-05-21)                    
[correctness] Flex wrapper blocks fullWidth
Flex wrapper blocks fullWidth The Overview story wraps `ButtonGroup` in a `display: flex` container without making the `ButtonGroup` flex item stretch, so the component can remain shrink-to-content and toggling `fullWidth` may still show no visible width change. This happens because `fullWidth` styles apply to an inner container, not the root element, so the root must be allowed to expand to reflect the change.

Issue description

Overview wraps ButtonGroup with a flex container (display: "flex"). Since the ButtonGroup root isn’t given width: 100% or flex: 1, it can shrink to its contents as a flex item, meaning fullWidth toggling may still not produce any visible change.

Issue Context

ButtonGroup's fullWidth mainly affects the inner .buttonsContainer and button wrappers, not the root wrapper element. The root needs to be allowed to expand for width: 100% on inner elements to matter.

Fix Focus Areas

  • packages/docs/src/pages/components/ButtonGroup/ButtonGroup.stories.tsx[20-25]

Suggested fix

Change the wrapper to a non-flex full-width block wrapper:



                     PR 3361 (2026-05-21)                    
[maintainability] Duplicate day-picker versions
Duplicate day-picker versions After bumping @vibe/core to react-day-picker@^8.10.2, yarn.lock still pins react-day-picker@^8.8.0 to 8.10.1, so the workspace resolves two different react-day-picker versions (8.10.2 and 8.10.1). This increases install/bundle surface area and makes dependency behavior harder to reason about across packages that pull different trees.

Issue description

The PR bumps @vibe/core to react-day-picker@^8.10.2, but the repo’s yarn.lock still resolves react-day-picker@^8.8.0 to 8.10.1 while react-day-picker@^8.10.2 resolves to 8.10.2. This results in two different installed react-day-picker versions.

Issue Context

storybook-addon-playground depends on @vibe/core@^3.59.0, which in turn depends on react-day-picker@^8.8.0, keeping the older lock entry alive.

Fix Focus Areas

  • /yarn.lock[18034-18042]
  • /yarn.lock[6702-6734]
  • /yarn.lock[19835-19846]

Suggested fix

  • Update the lockfile so all react-day-picker ranges resolve to the same version (preferably 8.10.2), e.g. by running a targeted upgrade/dedupe (yarn upgrade react-day-picker@8.10.2 and/or a dedupe flow) and committing the updated yarn.lock.
  • If needed for consistency, add a workspace-level override (e.g., Yarn resolutions) to force a single react-day-picker version.


                     PR 3346 (2026-04-09)                    
[correctness] Unlabeled active option
Unlabeled active option ColorPickerColorsGrid sets aria-activedescendant to an element id on the
  • , but the human-readable aria-label is applied to a nested instead. As a result, the active descendant option itself has no accessible name, so screen readers may not announce the active color during keyboard navigation.

    Issue description

    aria-activedescendant points to the <li role="option">, but the option has no accessible name because aria-label is currently on a nested <Clickable role="presentation">. This prevents reliable screen reader announcement of the active color.

    Issue Context

    For the active-descendant listbox pattern, the element referenced by aria-activedescendant should be the one that exposes the accessible name.

    Fix Focus Areas

    • packages/core/src/components/ColorPicker/components/ColorPickerItemComponent/ColorPickerItemComponent.tsx[120-157]
    • packages/core/src/components/ColorPicker/components/ColorPickerContent/ColorPickerColorsGrid.tsx[133-160]

    Suggested fix

    • Add aria-label={colorAriaLabel} to the <li role="option">.
    • Remove aria-label from the nested Clickable (and keep it presentational/hidden, e.g. aria-hidden, if you still need to avoid double announcements).
    • Consider moving the click handler to the <li> (or otherwise ensure activating the role="option" element triggers selection) to align behavior with the option semantics and avoid relying on a presentational child for interaction.

  • [reliability] New ARIA states untested
    New ARIA states untested The PR adds key accessibility attributes (`aria-activedescendant` on the listbox and `aria-selected` on options) but the updated tests do not assert these behaviors/attributes. This weakens confidence that screen reader announcements and selection-state semantics work as intended.

    Issue description

    New accessibility behavior was added (role=listbox/option, aria-activedescendant, aria-selected), but tests do not assert these attributes/behaviors.

    Issue Context

    The PR’s goal is screen reader support during keyboard navigation and selection-state announcements; without assertions, regressions are likely.

    Fix Focus Areas

    • packages/core/src/components/ColorPicker/tests/ColorPicker.test.tsx[20-42]
    • packages/core/src/components/ColorPicker/components/ColorPickerContent/ColorPickerColorsGrid.tsx[129-142]
    • packages/core/src/components/ColorPicker/components/ColorPickerItemComponent/ColorPickerItemComponent.tsx[121-135]

    [correctness] Invalid option IDs
    Invalid option IDs ColorPickerColorsGrid builds option `id` values by concatenating the raw `color` string, which can include spaces/characters (e.g. CSS `rgb(0, 0, 0)`) and produce invalid HTML IDs. This can break `aria-activedescendant` targeting and prevent VoiceOver from announcing the active option during keyboard navigation.

    Issue description

    getColorItemId() builds DOM IDs from the raw color string (e.g. ...-item-rgb(0, 0, 0)), which can contain spaces/special chars and become invalid, breaking aria-activedescendant.

    Issue Context

    ColorPicker supports arbitrary CSS color strings (not only monday tokens), so this can occur in real usage when forceUseRawColorList is used with values like rgb(...).

    Fix Focus Areas

    • packages/core/src/components/ColorPicker/components/ColorPickerContent/ColorPickerColorsGrid.tsx[129-160]

    Suggested approach

    • Generate option IDs using a stable, safe suffix (preferably the index):
    • const getColorItemId = (index: number) => gridId ? ${gridId}-item-${index} : undefined;
    • Pass id={getColorItemId(index)} into ColorPickerItemComponent
    • Compute activeDescendantId using activeIndex directly: activeIndex >= 0 ? getColorItemId(activeIndex) : undefined
    • Keep key={color} as-is to avoid React key churn.


                         PR 3343 (2026-03-30)                    
    [correctness] Dry-run blocks publishing
    Dry-run blocks publishing The v3 release workflow runs `yarn lerna publish` with `--dry-run`, so it can succeed without actually publishing any packages to npm. This makes the workflow non-functional as a release pipeline.

    Issue description

    The v3 release workflow uses lerna publish ... --dry-run, which prevents publishing packages to npm.

    Issue Context

    This workflow is named and structured as a release workflow, and the existing release.yml performs a real publish.

    Fix Focus Areas

    • .github/workflows/release-v3.yml[81-82]

    Proposed change

    Update the publish step to remove --dry-run (keep --dist-tag v3 if that’s intended), e.g.:

    • yarn lerna publish from-package --dist-tag v3 -y

    [correctness] Versioning flag inconsistency
    Versioning flag inconsistency The v3 workflow’s `lerna version` command omits `--conventional-graduate`, unlike the main `release.yml` workflow. This can change which packages get promoted to stable during versioning and lead to unexpected version outputs vs the established release process.

    Issue description

    release-v3.yml runs yarn lerna version without the --conventional-graduate flag, diverging from the repo’s existing release workflow.

    Issue Context

    release.yml includes --conventional-graduate in the analogous step. If v3 should follow the same promotion/versioning rules, this omission can change which packages are graduated/promoted during a release.

    Fix Focus Areas

    • .github/workflows/release-v3.yml[73-76]

    Proposed change

    Either:

    1. Add --conventional-graduate to match release.yml, or
    2. Add an explicit comment in the workflow explaining why v3 intentionally diverges (to avoid future confusion/mis-releases).


                         PR 3333 (2026-03-15)                    
    [correctness] Checkbox toggles hidden input
    Checkbox toggles hidden input `Checkbox.setChecked()`/`setUnchecked()` now call Playwright `check()`/`uncheck()` on the Checkbox ``, but the core component intentionally styles that input as a hidden 0×0 element, so the element is not interactable and toggle operations can fail/time out.

    Issue description

    Checkbox.setChecked()/setUnchecked() uses Playwright check()/uncheck() on the underlying &amp;amp;amp;lt;input&amp;amp;amp;gt;, but the core Checkbox intentionally styles that input with hidden-element() (opacity 0, width/height 0). This makes the input non-interactable and can cause toggle operations to fail.

    Issue Context

    The visual/clickable target in the core component is the rendered checkbox control (the element with data-testid derived from ComponentDefaultTestId.CHECKBOX_CHECKBOX), not the hidden input.

    Fix Focus Areas

    • packages/testkit/components/Checkbox.ts[20-58]
    • packages/core/src/components/Checkbox/Checkbox.module.scss[69-75]
    • packages/style/src/mixins/_common.scss[9-14]

    [reliability] Toast locator non-unique
    Toast locator non-unique The new selector `div[data-testid^="toast"]` matches both the toast root (`toast_`) and the internal toast content container (`toast-content`), so the testkit `Toast` locator can resolve to multiple elements and break strict Playwright waits/assertions/actions.

    Issue description

    div[data-testid^=&amp;amp;amp;quot;toast&amp;amp;amp;quot;] matches both the toast root and the internal toast-content div, making the locator non-unique and breaking strict Playwright operations (waits/assertions/actions).

    Issue Context

    The Toast root has role=&amp;amp;amp;quot;alert&amp;amp;amp;quot;, while the toast-content container does not; this is a stable discriminator.

    Fix Focus Areas

    • packages/testkit/tests/Toast.test.ts[1-6]
    • packages/core/src/components/Toast/Toast.tsx[187-205]
    • packages/core/src/tests/constants.ts[89-93]
    • packages/components/layout/src/Flex/Flex.tsx[68-75]


                         PR 3328 (2026-03-11)                    
    [correctness] Input focus not cleared
    Input focus not cleared Checkbox.onMouseUpCallback blurs only the wrapper/label, but the component’s visual focus/hover styling is still driven by the hidden input’s focus selectors, so the checkbox can remain in a focused/hovered visual state after pointer interaction. This can leave a persistent focus ring/background until focus moves elsewhere, contradicting the intent of the new blur logic.

    Issue description

    onMouseUpCallback blurs only the wrapper/label, but focus-driven visuals are still controlled by the hidden &amp;amp;lt;input&amp;amp;gt; (.input:focus...). If the input ends up focused after pointer activation, its focus styles can persist.

    Issue Context

    The PR’s intent (per comment) is to remove persistent focus ring after pointer interaction and keep keyboard-only focus indication via :focus-visible.

    Fix Focus Areas

    • packages/core/src/components/Checkbox/Checkbox.tsx[105-114]
    • packages/core/src/components/Checkbox/Checkbox.module.scss[80-96] (verify focus styles align with the updated blur behavior)

    Suggested approach

    In onMouseUpCallback, after the double requestAnimationFrame, check document.activeElement and blur inputRef.current if it’s focused (and/or blur both wrapper and input safely). Ensure the callback still works for both separateLabel and non-separate modes.



                         PR 3326 (2026-03-10)                    
    [correctness] Misses multiline imports
    Misses multiline imports detectPromotedComponentImports applies a single-line regex to each line of the file, so multi-line imports (a common formatting style) will not be detected and promotedComponentAnalysis will miss real old/new API usage.

    Issue description

    detectPromotedComponentImports() currently regex-matches imports per line, which fails to detect multi-line import blocks (common in TS/JS). This under-reports old/new API usage for promoted components and can hide required manual migrations.

    Issue Context

    The code splits file content by \n and runs /import\s+\{([^}]+)\}\s+from.../g on each single line.

    Fix Focus Areas

    • packages/mcp/src/server/tools/v4-migration.ts[743-803]


                         PR 3323 (2026-03-07)                    
    [correctness] V4 version check weak
    V4 version check weak The v4 MCP analyzer determines v4 by `vibeCoreVersion.startsWith("4")`, which misclassifies versions expressed as ranges/prefixed formats (e.g. `^4.0.0`).

    Issue description

    analyzePackageJson uses startsWith(&amp;amp;amp;amp;quot;4&amp;amp;amp;amp;quot;) for major-version detection, which fails for prefixed semver ranges (e.g., ^4.0.0).

    Issue Context

    This impacts the tool’s migrationStatus and therefore the guidance/recommendations it emits.

    Fix Focus Areas

    • packages/mcp/src/server/tools/v4-migration.ts[341-365]


                         PR 3322 (2026-03-07)                    
    [correctness] Overbroad next import rewrite
    Overbroad next import rewrite `next-imports-migration` rewrites every `@vibe/core/next` import declaration to `@vibe/core`, but the file comment states only a subset of components were promoted; if other exports remain under `/next` in v4 this will break those imports.

    Issue description

    The migration currently rewrites the entire import source for any @vibe/core/next import, even though the comment lists only a subset of components that were promoted.

    Issue Context

    A safer approach is to move only specific specifiers and split imports when necessary.

    Fix Focus Areas

    • packages/codemod/transformations/core/v3-to-v4/next-imports-migration.ts[5-15]

    [reliability] Type import removal incomplete
    Type import removal incomplete `type-imports-migration` removes `VibeComponent`/`withStaticProps*` import specifiers but does not attempt to update usages, so migrated code may be left with unresolved identifiers requiring manual follow-up.

    Issue description

    The codemod removes imports for deprecated type utilities but doesn&amp;amp;amp;amp;#x27;t update usage sites, so output may not compile.

    Issue Context

    A safer migration either updates the AST where these identifiers are used, or emits warnings when it detects remaining references.

    Fix Focus Areas

    • packages/codemod/transformations/core/v3-to-v4/type-imports-migration.ts[13-56]


                         PR 3321 (2026-03-05)                    
    [correctness] Unsupported codemod commands
    Unsupported codemod commands The guide documents running @vibe/codemod with positional “migration names” (e.g. `aria-props-migration`, `icon-props-rename`), but the CLI only supports `--migration/-m` with a small set of choices. Users following the guide will not run the intended transformation and will likely get the interactive wizard or the wrong migration.

    Issue description

    The Vibe 4 migration guide documents several @vibe/codemod commands using positional arguments (e.g. npx @vibe/codemod aria-props-migration). The actual CLI only supports selecting a migration via --migration/-m (choices: v3/v4/enums), so these commands won’t run as documented.

    Issue Context

    The codemod CLI is implemented in packages/codemod/bin/vibe-codemod.ts and only defines option-based selection via yargs. The docs should reflect the real CLI interface.

    Fix Focus Areas

    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[174-175]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[371-372]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[476-492]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[508-509]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[683-684]

    [correctness] Wrong enums codemod cmd
    Wrong enums codemod cmd The FAQ tells users to run `npx @vibe/codemod -m enums` for Vibe 4 enum migration, but the CLI’s `enums` migration actually maps to the v2→v3 enums transformation directory. Users will run the wrong codemod and not get the v4 enum-to-literal changes.

    Issue description

    The Vibe 4 migration FAQ recommends running npx @vibe/codemod -m enums, but enums is not the v3→v4 migration. The CLI maps it to v2-to-v3/enums, so users will run the wrong codemod.

    Issue Context

    The v4 migration (v3→v4 transformations) is executed via --migration v4.

    Fix Focus Areas

    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[557-560]

    [correctness] Unsupported codemod commands
    Unsupported codemod commands The guide documents running @vibe/codemod with positional “migration names” (e.g. `aria-props-migration`, `icon-props-rename`), but the CLI only supports `--migration/-m` with a small set of choices. Users following the guide will not run the intended transformation and will likely get the interactive wizard or the wrong migration.

    Issue description

    The Vibe 4 migration guide documents several @vibe/codemod commands using positional arguments (e.g. npx @vibe/codemod aria-props-migration). The actual CLI only supports selecting a migration via --migration/-m (choices: v3/v4/enums), so these commands won’t run as documented.

    Issue Context

    The codemod CLI is implemented in packages/codemod/bin/vibe-codemod.ts and only defines option-based selection via yargs. The docs should reflect the real CLI interface.

    Fix Focus Areas

    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[174-175]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[371-372]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[476-492]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[508-509]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[683-684]

    [correctness] Unsupported codemod commands
    Unsupported codemod commands The guide documents running @vibe/codemod with positional “migration names” (e.g. `aria-props-migration`, `icon-props-rename`), but the CLI only supports `--migration/-m` with a small set of choices. Users following the guide will not run the intended transformation and will likely get the interactive wizard or the wrong migration.

    Issue description

    The Vibe 4 migration guide documents several @vibe/codemod commands using positional arguments (e.g. npx @vibe/codemod aria-props-migration). The actual CLI only supports selecting a migration via --migration/-m (choices: v3/v4/enums), so these commands won’t run as documented.

    Issue Context

    The codemod CLI is implemented in packages/codemod/bin/vibe-codemod.ts and only defines option-based selection via yargs. The docs should reflect the real CLI interface.

    Fix Focus Areas

    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[174-175]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[371-372]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[476-492]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[508-509]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[683-684]

    [correctness] Unsupported codemod commands
    Unsupported codemod commands The guide documents running @vibe/codemod with positional “migration names” (e.g. `aria-props-migration`, `icon-props-rename`), but the CLI only supports `--migration/-m` with a small set of choices. Users following the guide will not run the intended transformation and will likely get the interactive wizard or the wrong migration.

    Issue description

    The Vibe 4 migration guide documents several @vibe/codemod commands using positional arguments (e.g. npx @vibe/codemod aria-props-migration). The actual CLI only supports selecting a migration via --migration/-m (choices: v3/v4/enums), so these commands won’t run as documented.

    Issue Context

    The codemod CLI is implemented in packages/codemod/bin/vibe-codemod.ts and only defines option-based selection via yargs. The docs should reflect the real CLI interface.

    Fix Focus Areas

    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[174-175]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[371-372]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[476-492]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[508-509]
    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[683-684]

    [correctness] Changelog link missing --docs
    Changelog link missing --docs The new Vibe 4 changelog links to `?path=/docs/vibe-4-migration-guide` (no `--docs`), while other docs links in this repo use `...--docs`. This is likely to 404 in Storybook and breaks navigation from the changelog to the guide.

    Issue description

    The Vibe 4 changelog links to a Storybook docs path without the --docs suffix, which is inconsistent with other internal doc links and likely breaks.

    Issue Context

    This repo commonly links to docs pages using ?path=/docs/&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;slug&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;--docs.

    Fix Focus Areas

    • packages/docs/src/pages/migration-guide/vibe-4-changelog.md[1-6]

    [correctness] Bad VIBE4 changelog ref
    Bad VIBE4 changelog ref The migration guide references `VIBE4_CHANGELOG.md` for an example, but the added changelog file is `vibe-4-changelog.md`. This creates a dead/incorrect reference for readers looking for the mentioned example.

    Issue description

    The Vibe 4 migration guide references VIBE4_CHANGELOG.md, but the actual changelog file in this docs area is vibe-4-changelog.md. Readers will not be able to find the referenced example.

    Issue Context

    There is already a vibe-4-changelog.md file under the migration guide docs folder.

    Fix Focus Areas

    • packages/docs/src/pages/migration-guide/vibe-4-migration-guide.mdx[470-480]

    [correctness] Changelog link missing --docs
    Changelog link missing --docs The new Vibe 4 changelog links to `?path=/docs/vibe-4-migration-guide` (no `--docs`), while other docs links in this repo use `...--docs`. This is likely to 404 in Storybook and breaks navigation from the changelog to the guide.

    Issue description

    The Vibe 4 changelog links to a Storybook docs path without the --docs suffix, which is inconsistent with other internal doc links and likely breaks.

    Issue Context

    This repo commonly links to docs pages using ?path=/docs/&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;slug&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;--docs.

    Fix Focus Areas

    • packages/docs/src/pages/migration-guide/vibe-4-changelog.md[1-6]


                         PR 3316 (2026-03-03)                    
    [correctness] BaseInput right padding mismatch
    BaseInput right padding mismatch After reducing BaseInput `padding-inline-start` to 8px, the default `rightThinnerPadding` modifier still sets `padding-inline-end` to 16px when `renderRight` is absent. This creates an unintended 8px/16px asymmetry for the common “no right element” case and contradicts the migration guide’s stated BaseInput padding (8px start, 4px end).

    Issue description

    BaseInput reduced base padding-inline-start to 8px, but the default modifier applied when renderRight is missing (rightThinnerPadding) still sets padding-inline-end to 16px. This yields unintended asymmetric padding (8px/16px) in common cases.

    Issue Context

    rightThinnerPadding is currently applied when !renderRight, i.e., the absence of right content. Previously this likely produced symmetric 16px/16px padding; after the change it produces 8px/16px.

    Fix Focus Areas

    • packages/base/src/BaseInput/BaseInput.module.scss[3-41]
    • packages/base/src/BaseInput/BaseInput.tsx[23-33]
    • VIBE4_MIGRATION_GUIDE.md[411-446]

    [correctness] BaseInput right padding mismatch
    BaseInput right padding mismatch After reducing BaseInput `padding-inline-start` to 8px, the default `rightThinnerPadding` modifier still sets `padding-inline-end` to 16px when `renderRight` is absent. This creates an unintended 8px/16px asymmetry for the common “no right element” case and contradicts the migration guide’s stated BaseInput padding (8px start, 4px end).

    Issue description

    BaseInput reduced base padding-inline-start to 8px, but the default modifier applied when renderRight is missing (rightThinnerPadding) still sets padding-inline-end to 16px. This yields unintended asymmetric padding (8px/16px) in common cases.

    Issue Context

    rightThinnerPadding is currently applied when !renderRight, i.e., the absence of right content. Previously this likely produced symmetric 16px/16px padding; after the change it produces 8px/16px.

    Fix Focus Areas

    • packages/base/src/BaseInput/BaseInput.module.scss[3-41]
    • packages/base/src/BaseInput/BaseInput.tsx[23-33]
    • VIBE4_MIGRATION_GUIDE.md[411-446]

    [correctness] BaseInput right padding mismatch
    BaseInput right padding mismatch After reducing BaseInput `padding-inline-start` to 8px, the default `rightThinnerPadding` modifier still sets `padding-inline-end` to 16px when `renderRight` is absent. This creates an unintended 8px/16px asymmetry for the common “no right element” case and contradicts the migration guide’s stated BaseInput padding (8px start, 4px end).

    Issue description

    BaseInput reduced base padding-inline-start to 8px, but the default modifier applied when renderRight is missing (rightThinnerPadding) still sets padding-inline-end to 16px. This yields unintended asymmetric padding (8px/16px) in common cases.

    Issue Context

    rightThinnerPadding is currently applied when !renderRight, i.e., the absence of right content. Previously this likely produced symmetric 16px/16px padding; after the change it produces 8px/16px.

    Fix Focus Areas

    • packages/base/src/BaseInput/BaseInput.module.scss[3-41]
    • packages/base/src/BaseInput/BaseInput.tsx[23-33]
    • VIBE4_MIGRATION_GUIDE.md[411-446]

    [correctness] BaseInput right padding mismatch
    BaseInput right padding mismatch After reducing BaseInput `padding-inline-start` to 8px, the default `rightThinnerPadding` modifier still sets `padding-inline-end` to 16px when `renderRight` is absent. This creates an unintended 8px/16px asymmetry for the common “no right element” case and contradicts the migration guide’s stated BaseInput padding (8px start, 4px end).

    Issue description

    BaseInput reduced base padding-inline-start to 8px, but the default modifier applied when renderRight is missing (rightThinnerPadding) still sets padding-inline-end to 16px. This yields unintended asymmetric padding (8px/16px) in common cases.

    Issue Context

    rightThinnerPadding is currently applied when !renderRight, i.e., the absence of right content. Previously this likely produced symmetric 16px/16px padding; after the change it produces 8px/16px.

    Fix Focus Areas

    • packages/base/src/BaseInput/BaseInput.module.scss[3-41]
    • packages/base/src/BaseInput/BaseInput.tsx[23-33]
    • VIBE4_MIGRATION_GUIDE.md[411-446]

    [correctness] Dropdown placeholder shifts indent
    Dropdown placeholder shifts indent After reducing `.placeholderText` left padding to `--spacing-small` (8px), the selected value in medium/large still starts further right because it’s rendered via `BaseItem` (12px horizontal padding) inside `.selectedItem` (4px left padding). Users will see the text jump horizontally when transitioning from placeholder → selected value in medium/large.

    Issue description

    In non-searchable single-select Dropdown, placeholder and selected value have different left indents for medium/large sizes after reducing .placeholderText padding. This causes a visible horizontal jump when an option is selected.

    Issue Context

    • Placeholder is rendered as &amp;amp;amp;lt;Text&amp;amp;amp;gt; with .placeholderText { padding-inline-start: var(--spacing-small) }.
    • Selected value is rendered as &amp;amp;amp;lt;BaseItem size={size}&amp;amp;amp;gt; inside .selectedItem { padding-inline-start: var(--spacing-xs) }.
    • BaseItem applies its own horizontal padding (12px for medium/large).

    Fix Focus Areas

    • packages/core/src/components/Dropdown/components/Trigger/Trigger.module.scss[52-94]
    • packages/core/src/components/Dropdown/components/Trigger/SingleSelectTrigger.tsx[45-66]
    • packages/core/src/components/BaseItem/BaseItem.module.scss[35-45]


                         PR 3285 (2026-02-26)                    
    [correctness] String children not rendered
    String children not rendered `DialogProps.children` is typed to allow `string`, but non-element children are treated as invalid and the reference/trigger rendering falls back to an empty ``, effectively dropping string children at runtime. This is a type/runtime contract mismatch that can make a Dialog trigger disappear if a consumer passes a text child.

    Issue description

    DialogProps.children (and RefableProps.children) allow string, but string children are not rendered. This is a type/runtime contract mismatch and can lead to a missing trigger in the UI.

    Issue Context

    Dialog decides whether to render Refable based on React.isValidElement, and falls back to an empty &amp;lt;span&amp;gt; if no valid elements exist. Refable also returns null for non-elements.

    Fix Focus Areas

    • packages/components/dialog/src/Dialog/Dialog.types.ts[226-231]
    • packages/components/dialog/src/Dialog/Dialog.tsx[93-95]
    • packages/components/dialog/src/Dialog/Dialog.tsx[519-537]
    • packages/components/dialog/src/Dialog/components/Refable/Refable.tsx[20-24]

    Suggested change

    Choose one:

    1. Support string children: treat string/number children as renderable by wrapping them in a &amp;lt;span&amp;gt;/&amp;lt;div&amp;gt; reference wrapper and rendering the text inside (so the trigger is visible and ref-able).
    2. Disallow string children: remove string from DialogProps[&amp;#x27;children&amp;#x27;] and RefableProps[&amp;#x27;children&amp;#x27;] and update any docs accordingly. Add a unit test for &amp;lt;Dialog content=...&amp;gt;Plain text&amp;lt;/Dialog&amp;gt; behavior consistent with the chosen approach.


                         PR 3274 (2026-02-26)                    
    [correctness] Codemod overwrites spread props
    Codemod overwrites spread props The v3→v4 codemod may add a new `tooltipProps={{ position: ... }}` even when `tooltipProps` is already provided via a JSX spread, overwriting and dropping the spread-provided `tooltipProps`. This can silently change tooltip behavior after codemod runs.

    Issue description

    The TextWithHighlight v3→v4 codemod can incorrectly overwrite tooltipProps when tooltipProps is supplied via JSX spread props (&amp;amp;lt;TextWithHighlight {...props} ... /&amp;amp;gt;). Because the codemod only checks for an explicit tooltipProps JSXAttribute, it may append a new explicit tooltipProps={{ position: ... }}, which can drop existing tooltip configuration.

    Issue Context

    • isPropExists only checks JSXAttribute nodes and ignores JSXSpreadAttribute.
    • The transformation appends a new tooltipProps attribute when isPropExists(..., &amp;amp;quot;tooltipProps&amp;amp;quot;) is false.
    • In React/JSX, an explicitly provided prop can override values coming from earlier spreads.

    Fix Focus Areas

    • packages/codemod/transformations/core/v3-to-v4/TextWithHighlight-component-migration.ts[26-65]
    • packages/codemod/src/utils/prop-utils.ts[33-37]
    • packages/codemod/transformations/core/v3-to-v4/tests/TextWithHighlight-component-migration.test.ts[1-112]

    Acceptance criteria

    • If the JSX element contains any JSXSpreadAttribute, the codemod must not silently overwrite potential spread-provided tooltipProps.
    • Add/adjust tests to cover at least one spread-props scenario and assert the codemod behavior (either safe merge or explicit manual warning + no unsafe overwrite).


                         PR 3271 (2026-02-26)                    
    [correctness] AvatarBadge tabIndex mismatch
    AvatarBadge tabIndex mismatch `ClickableProps.tabIndex` is now `number`-only, but `AvatarBadgeProps.tabIndex` remains `string | number` and is forwarded into `ClickableWrapper` as `clickableProps`, which is typed as `ClickableProps`. This creates a type incompatibility and undermines the intended breaking-change cleanup (forces casts or breaks TS builds).

    Issue description

    ClickableProps.tabIndex is now number-only, but AvatarBadgeProps.tabIndex still allows string | number and forwards tabIndex into ClickableWrapper via clickableProps, which is typed as ClickableProps. This creates a TS type incompatibility and defeats the goal of removing string tabIndex usage.

    Issue Context

    This PR introduces a breaking change: Clickable.tabIndex: string | number -&amp;amp;gt; number. Internal components that forward tabIndex into Clickable/ClickableWrapper must be updated accordingly.

    Fix Focus Areas

    • packages/core/src/components/Avatar/AvatarBadge.tsx[13-70]
    • packages/components/clickable/src/Clickable/Clickable.tsx[49-60]
    • packages/components/clickable/src/Clickable/ClickableWrapper.tsx[6-34]
    • packages/docs/src/pages/components/Avatar/Avatar.stories.tsx[23-32]

    [correctness] AvatarBadge tabIndex mismatch
    AvatarBadge tabIndex mismatch `ClickableProps.tabIndex` is now `number`-only, but `AvatarBadgeProps.tabIndex` remains `string | number` and is forwarded into `ClickableWrapper` as `clickableProps`, which is typed as `ClickableProps`. This creates a type incompatibility and undermines the intended breaking-change cleanup (forces casts or breaks TS builds).

    Issue description

    ClickableProps.tabIndex is now number-only, but AvatarBadgeProps.tabIndex still allows string | number and forwards tabIndex into ClickableWrapper via clickableProps, which is typed as ClickableProps. This creates a TS type incompatibility and defeats the goal of removing string tabIndex usage.

    Issue Context

    This PR introduces a breaking change: Clickable.tabIndex: string | number -&amp;gt; number. Internal components that forward tabIndex into Clickable/ClickableWrapper must be updated accordingly.

    Fix Focus Areas

    • packages/core/src/components/Avatar/AvatarBadge.tsx[13-70]
    • packages/components/clickable/src/Clickable/Clickable.tsx[49-60]
    • packages/components/clickable/src/Clickable/ClickableWrapper.tsx[6-34]
    • packages/docs/src/pages/components/Avatar/Avatar.stories.tsx[23-32]

    [correctness] RadioButton uses string tabIndex
    RadioButton uses string tabIndex RadioButton still models/passes its children tab index as a string (default "0") into ``. Since this PR removed `Number(tabIndex)` coercion and narrowed `Clickable.tabIndex` to `number`, RadioButton becomes an internal missed migration and can cause type-check failures or inconsistent focus behavior at runtime.

    Issue description

    Clickable.tabIndex is now number-only and useClickableProps no longer coerces strings via Number(tabIndex). RadioButton still defines childrenTabIndex as a string (defaulting to &amp;amp;quot;0&amp;amp;quot;) and passes it directly into &amp;amp;lt;Clickable tabIndex={childrenTabIndex}&amp;amp;gt;, which is now incompatible.

    Issue Context

    This PR intentionally removed string coercion and narrowed types for Clickable. Any remaining internal callers passing string tabIndex values must be migrated.

    Fix Focus Areas

    • packages/core/src/components/RadioButton/RadioButton.tsx[12-106]
    • packages/core/src/components/RadioButton/RadioButton.tsx[160-176]

    [correctness] RadioButton uses string tabIndex
    RadioButton uses string tabIndex RadioButton still models/passes its children tab index as a string (default "0") into ``. Since this PR removed `Number(tabIndex)` coercion and narrowed `Clickable.tabIndex` to `number`, RadioButton becomes an internal missed migration and can cause type-check failures or inconsistent focus behavior at runtime.

    Issue description

    Clickable.tabIndex is now number-only and useClickableProps no longer coerces strings via Number(tabIndex). RadioButton still defines childrenTabIndex as a string (defaulting to &amp;quot;0&amp;quot;) and passes it directly into &amp;lt;Clickable tabIndex={childrenTabIndex}&amp;gt;, which is now incompatible.

    Issue Context

    This PR intentionally removed string coercion and narrowed types for Clickable. Any remaining internal callers passing string tabIndex values must be migrated.

    Fix Focus Areas

    • packages/core/src/components/RadioButton/RadioButton.tsx[12-106]
    • packages/core/src/components/RadioButton/RadioButton.tsx[160-176]

    [correctness] Docgen output stale
    Docgen output stale The committed `react-docgen-output.json` still documents Clickable `ariaHasPopup` as `boolean | string` and `tabIndex` as `string | number` with default `"0"`, which no longer matches the source after this PR. This will mislead consumers using the docs/playground and contradict the migration guide.

    Issue description

    The committed docgen artifact used by the docs/playground still reflects the old Clickable prop types (ariaHasPopup: boolean | string, tabIndex: string | number, default tabIndex: &amp;quot;0&amp;quot;). After this breaking change, the documentation is now incorrect.

    Issue Context

    The source of truth (packages/components/clickable/src/Clickable/Clickable.tsx) now defines ariaHasPopup?: boolean, tabIndex?: number, and tabIndex = 0. The docs/playground artifact should be regenerated to avoid confusing consumers.

    Fix Focus Areas

    • packages/docs/src/pages/playground/react-docgen-output.json[6852-7106]
    • packages/components/clickable/src/Clickable/Clickable.tsx[49-92]
    • packages/docs/src/pages/components/Avatar/Avatar.stories.tsx[23-32]

    [correctness] Docgen output stale
    Docgen output stale The committed `react-docgen-output.json` still documents Clickable `ariaHasPopup` as `boolean | string` and `tabIndex` as `string | number` with default `"0"`, which no longer matches the source after this PR. This will mislead consumers using the docs/playground and contradict the migration guide.

    Issue description

    The committed docgen artifact used by the docs/playground still reflects the old Clickable prop types (ariaHasPopup: boolean | string, tabIndex: string | number, default tabIndex: &quot;0&quot;). After this breaking change, the documentation is now incorrect.

    Issue Context

    The source of truth (packages/components/clickable/src/Clickable/Clickable.tsx) now defines ariaHasPopup?: boolean, tabIndex?: number, and tabIndex = 0. The docs/playground artifact should be regenerated to avoid confusing consumers.

    Fix Focus Areas

    • packages/docs/src/pages/playground/react-docgen-output.json[6852-7106]
    • packages/components/clickable/src/Clickable/Clickable.tsx[49-92]
    • packages/docs/src/pages/components/Avatar/Avatar.stories.tsx[23-32]

    [correctness] RadioButton uses string tabIndex
    RadioButton uses string tabIndex RadioButton still models/passes its children tab index as a string (default "0") into ``. Since this PR removed `Number(tabIndex)` coercion and narrowed `Clickable.tabIndex` to `number`, RadioButton becomes an internal missed migration and can cause type-check failures or inconsistent focus behavior at runtime.

    Issue description

    Clickable.tabIndex is now number-only and useClickableProps no longer coerces strings via Number(tabIndex). RadioButton still defines childrenTabIndex as a string (defaulting to &amp;amp;amp;quot;0&amp;amp;amp;quot;) and passes it directly into &amp;amp;amp;lt;Clickable tabIndex={childrenTabIndex}&amp;amp;amp;gt;, which is now incompatible.

    Issue Context

    This PR intentionally removed string coercion and narrowed types for Clickable. Any remaining internal callers passing string tabIndex values must be migrated.

    Fix Focus Areas

    • packages/core/src/components/RadioButton/RadioButton.tsx[12-106]
    • packages/core/src/components/RadioButton/RadioButton.tsx[160-176]

    [correctness] RadioButton uses string tabIndex
    RadioButton uses string tabIndex RadioButton still models/passes its children tab index as a string (default "0") into ``. Since this PR removed `Number(tabIndex)` coercion and narrowed `Clickable.tabIndex` to `number`, RadioButton becomes an internal missed migration and can cause type-check failures or inconsistent focus behavior at runtime.

    Issue description

    Clickable.tabIndex is now number-only and useClickableProps no longer coerces strings via Number(tabIndex). RadioButton still defines childrenTabIndex as a string (defaulting to &amp;amp;quot;0&amp;amp;quot;) and passes it directly into &amp;amp;lt;Clickable tabIndex={childrenTabIndex}&amp;amp;gt;, which is now incompatible.

    Issue Context

    This PR intentionally removed string coercion and narrowed types for Clickable. Any remaining internal callers passing string tabIndex values must be migrated.

    Fix Focus Areas

    • packages/core/src/components/RadioButton/RadioButton.tsx[12-106]
    • packages/core/src/components/RadioButton/RadioButton.tsx[160-176]


                         PR 2950 (2025-06-25)                    
    [general] Remove conflicting accessibility attributes

    ✅ Remove conflicting accessibility attributes

    Setting aria-hidden to true while also providing ariaLabel creates conflicting accessibility signals. Remove aria-hidden since these buttons need to be accessible to screen readers for proper spinbutton functionality.

    packages/core/src/components/NumberField/components/NumberFieldSpinButton/NumberFieldSpinButton.tsx [25-46]

     <IconButton
    -  aria-hidden
       ariaLabel="Increase"
       hideTooltip
       ariaControls={inputId}
       tabIndex={-1}
       onClick={onIncrement}
       disabled={disabled || isAtMax}
       size={iconButtonSize}
       icon={DropdownChevronUp}
     />
     <IconButton
    -  aria-hidden
       ariaLabel="Decrease"
       hideTooltip
       ariaControls={inputId}
       tabIndex={-1}
       onClick={onDecrement}
       disabled={disabled || isAtMin}
       size={iconButtonSize}
       icon={DropdownChevronDown}
     />

    Suggestion importance[1-10]: 9

    __

    Why: This suggestion correctly identifies a critical accessibility issue. Using aria-hidden on the increment and decrement buttons makes them completely inaccessible to screen readers, which contradicts the presence of ariaLabel. Removing aria-hidden is essential for the component to be usable by people relying on assistive technologies.



    Clone this wiki locally