From 1ccf3513ecc01a2121ac24db92bca3da69e71893 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Wed, 15 Apr 2026 19:04:49 +0200 Subject: [PATCH 01/31] docs(plan): add Playwright + Chromatic page visual tests plan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integrated review findings: - Merged Unit 3 (scripts) into Unit 1 — not independently deliverable - Clarified two-job CI rationale: enables partial archive upload on failure - Resolved getGFIs() open question — fetch-gfis.json covers it via USE_MOCK_DATA - Documented reuseExistingServer caveat for local dev determinism - Clarified catch-all page coverage in Unit 2 --- ...wright-chromatic-page-visual-tests-plan.md | 288 ++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 docs/plans/2026-04-15-001-feat-playwright-chromatic-page-visual-tests-plan.md diff --git a/docs/plans/2026-04-15-001-feat-playwright-chromatic-page-visual-tests-plan.md b/docs/plans/2026-04-15-001-feat-playwright-chromatic-page-visual-tests-plan.md new file mode 100644 index 00000000000..d7c9ad3c1e2 --- /dev/null +++ b/docs/plans/2026-04-15-001-feat-playwright-chromatic-page-visual-tests-plan.md @@ -0,0 +1,288 @@ +--- +title: "feat: Full-page visual regression testing with Playwright + Chromatic" +type: feat +status: active +date: 2026-04-15 +--- + +# Full-Page Visual Regression Testing with Playwright + Chromatic + +## Overview + +Add full-page visual regression testing using Playwright to navigate real Next.js pages and Chromatic to capture, store, and diff DOM snapshots. Pages render against a production build with `USE_MOCK_DATA=true` for deterministic content. This replaces the Storybook-based approach (branch `feat/dual-storybook-page-visual-tests`) which required extensive mocking of server-only APIs. + +## Problem Frame + +During the Tailwind v4 migration, component-level Chromatic snapshots miss regressions that only surface in full-page context — layout spacing, responsive grids, section composition, cross-component interactions. The previous Storybook approach required mocking `next-intl/server`, `next/navigation`, `@/lib/data`, and `@/lib/utils/contributors` at the webpack level, and still fought `experimentalRSC` render pass issues. + +Playwright tests against a real Next.js build avoid all of this — pages render with real SSR, real component tree, real Tailwind output. The only controlled variable is the data layer, which already has a `USE_MOCK_DATA=true` toggle with 27 mock JSON files. + +## Requirements Trace + +- R1. Capture Chromatic visual snapshots of ~10 representative pages covering all layout patterns +- R2. Pages render deterministic content via `USE_MOCK_DATA=true` — no flaky API-dependent diffs +- R3. Test 3 viewport breakpoints per page: mobile (375px), tablet (768px), desktop (1280px) +- R4. Chromatic diffs show visual regressions on PRs via a separate Chromatic project +- R5. CI runs the Playwright visual tests and uploads to Chromatic in parallel with existing workflows +- R6. Existing e2e tests and Storybook Chromatic workflow are unaffected + +## Scope Boundaries + +- Not modifying existing e2e tests or Storybook setup +- Not testing every page — one representative per layout pattern +- Not testing multiple locales in this iteration (English only) +- Not adding interaction-based snapshots (hover states, modals) — just page-load snapshots + +### Deferred to Separate Tasks + +- Multi-locale visual testing (ar, zh): future iteration after English baseline is stable +- Interaction snapshots (modal open, tab switch): separate PR +- Integrating with the existing Storybook Chromatic project: these are intentionally separate projects + +## Context & Research + +### Relevant Code and Patterns + +| File/Pattern | Relevance | +|---|---| +| `playwright.config.ts` | Existing config with 4 e2e + 1 unit project. No `webServer` configured — tests assume external server. `outputDir: "./tests/__results__"` | +| `tests/e2e/` | Existing e2e tests using page object pattern (BasePage → HomePage etc.) | +| `tests/e2e/fixtures/testData.ts` | Centralized test URLs and data | +| `src/data-layer/storage.ts` | `USE_MOCK_DATA` toggle — reads from `src/data-layer/mocks/*.json` instead of Netlify Blobs | +| `src/data-layer/mocks/` | 27 JSON mock files (ETH price, apps, events, RSS, beaconchain, etc.) | +| `.github/workflows/chromatic.yml` | Existing Storybook Chromatic CI (keep separate) | +| `package.json` | `chromatic@16.0.0`, `@playwright/test@^1.52.0` installed. `@chromatic-com/playwright` NOT installed | + +### How Chromatic Playwright Works + +Chromatic Playwright captures **DOM archives** (not screenshots) during test execution via the `@chromatic-com/playwright` fixture. Archives are uploaded to Chromatic which re-renders them in its own browser fleet for pixel-diffing. The flow is: + +1. Build and start Next.js (`next build && next start` with `USE_MOCK_DATA=true`) +2. Run Playwright tests — Chromatic fixture captures DOM archives to `test-results/` +3. Upload archives to Chromatic (`npx chromatic --playwright`) + +### Key Constraints + +- **Chrome-only** for archive capture — Chromatic re-renders in its own multi-browser fleet +- **No TurboSnap** — unlike Storybook, every Playwright test runs on every build +- **`assetDomains`** required for `s3-dcl1.ethquokkaops.io` (app screenshots/media) +- **Separate Chromatic project** — can't mix Storybook and Playwright builds + +## Key Technical Decisions + +- **`USE_MOCK_DATA=true` at build time over runtime API mocking**: The data layer already switches between Netlify Blobs and local JSON files based on this env var. Building Next.js with it set bakes deterministic data into the SSG/ISR output. No need for MSW, `page.route()`, or webpack aliases. The 27 existing mock files are the fixtures. + +- **Production build (`next build && next start`) over dev server**: Production builds are deterministic (SSG/SSR at build time), faster to serve, and match what users actually see. Dev mode has HMR artifacts, slower rendering, and potential hydration differences. + +- **Separate Playwright project in existing config over new config file**: Add `chromatic-*` projects to `playwright.config.ts` alongside existing e2e projects. The `--project` flag isolates them. Avoids config duplication. + +- **3 viewport projects (mobile/tablet/desktop) over per-test viewport overrides**: Playwright projects with different viewport sizes run all tests at each size automatically. Cleaner than `test.use()` overrides in every file. 10 pages × 3 viewports = 30 snapshots per build. + +- **`disableAutoSnapshot: true` with explicit `takeSnapshot` calls**: Gives control over when exactly the snapshot is taken — after `networkidle`, after specific elements are visible. Prevents premature captures during hydration. + +- **Separate CI workflow file over extending existing chromatic.yml**: The Playwright visual test workflow has different steps (build Next.js, start server, run Playwright, upload archives). Keeping it in its own file avoids complicating the Storybook workflow. + +## Open Questions + +### Resolved During Planning + +- **Will `USE_MOCK_DATA=true` cover all data the pages need?** Yes — 27 mock files cover all data-layer getters. The mock layer operates at the storage level (Netlify Blobs → JSON files), so all `src/lib/data/` functions resolve to mock data transparently. No code changes needed. + +- **Does Chromatic Playwright conflict with the existing `@chromatic-com/storybook`?** No — `@chromatic-com/playwright` is a separate package. They coexist. Different Chromatic projects, different project tokens. + +- **Can we reuse the existing `outputDir: "./tests/__results__"`?** No — set the Chromatic projects to use the default `./test-results` so the Chromatic CLI finds them without extra config. Existing e2e tests keep their `./tests/__results__` path. + +- **Does `getGFIs()` (called by `[...slug]` page) need a separate mock?** No — `getGFIs()` is imported from `@/data-layer` which uses `get(KEYS.GFIS)` from the storage layer. `USE_MOCK_DATA=true` reads from `src/data-layer/mocks/fetch-gfis.json`, which exists. The `[...slug]` docs pages are covered by the same mock mechanism as all other data. + +### Deferred to Implementation + +- **Whether some pages need longer `delay` or `resourceArchiveTimeout`**: Pages with lazy-loaded images or client-side data may need tuning. Start with defaults and adjust if snapshots are flaky. + +## Output Structure + +``` +tests/ + visual/ # New directory for Chromatic visual tests + pages.spec.ts # All page-load visual tests in one file +.github/ + workflows/ + chromatic-pages.yml # New CI workflow for Playwright + Chromatic +``` + +## High-Level Technical Design + +> *This illustrates the intended approach and is directional guidance for review, not implementation specification.* + +```mermaid +sequenceDiagram + participant CI as GitHub Actions + participant Build as next build + participant Server as next start + participant PW as Playwright + participant Chromatic as Chromatic Cloud + + CI->>Build: USE_MOCK_DATA=true pnpm build + CI->>Server: pnpm start (port 3000) + CI->>PW: npx playwright test --project=chromatic-* + PW->>Server: Navigate to /en/, /en/wallets/, etc. + Server-->>PW: SSR HTML + hydration + PW->>PW: Wait for networkidle + stable DOM + PW->>PW: takeSnapshot() → DOM archive to test-results/ + PW-->>CI: Test results + archives + CI->>Chromatic: npx chromatic --playwright + Chromatic-->>CI: Visual diff results + build URL +``` + +## Implementation Units + +- [ ] **Unit 1: Install `@chromatic-com/playwright` and configure projects** + + **Goal:** Add the Chromatic Playwright package, create 3 viewport-specific projects in the Playwright config, and add convenience scripts. + + **Requirements:** R3, R5, R6 + + **Dependencies:** None + + **Files:** + - Modify: `package.json` (add `@chromatic-com/playwright` to devDependencies + add scripts) + - Modify: `playwright.config.ts` (add 3 chromatic projects + webServer) + + **Approach:** + - Install `@chromatic-com/playwright` as a dev dependency + - Add 3 new projects to `playwright.config.ts`: `chromatic-desktop` (1280×720), `chromatic-tablet` (768×1024), `chromatic-mobile` (375×812) + - All 3 use Chrome, share `testDir: "./tests/visual"`, and set `disableAutoSnapshot: true` + - Set `assetDomains: ["s3-dcl1.ethquokkaops.io"]` for external images + - Each project gets the default `test-results` outputDir (not `./tests/__results__`) + - Configure `webServer` to auto-start a production build on port 3000 with `USE_MOCK_DATA=true`. Use `reuseExistingServer: true` so it picks up an already-running server. **Caveat:** for deterministic local results, the running server must have been built with `USE_MOCK_DATA=true`. If a regular dev server is running on port 3000, the visual tests will silently use live data. In CI (Unit 3), the workflow builds with the flag explicitly. + - Existing e2e and unit projects are untouched + - Add package.json scripts: + - `test:visual` — runs all 3 chromatic projects + - `test:visual:desktop` — runs desktop only (fast iteration) + - `chromatic:pages` — uploads archives to Chromatic + + **Patterns to follow:** + - Existing project definitions in `playwright.config.ts` + - Existing `test:e2e`, `test:unit` script naming in `package.json` + + **Test scenarios:** + - Happy path: `npx playwright test --project=chromatic-desktop --list` shows the visual test files (once Unit 2 creates them) + - Edge case: existing `pnpm test:e2e` still runs only the 4 original e2e projects (no chromatic tests leak in) + + **Verification:** + - `pnpm test:e2e` passes unchanged + - `npx playwright test --project=chromatic-desktop --list` discovers tests from `tests/visual/` + +- [ ] **Unit 2: Create visual test file for ~10 pages** + + **Goal:** Write a single Playwright test file that navigates to each representative page and takes a Chromatic snapshot. + + **Requirements:** R1, R2 + + **Dependencies:** Unit 1 + + **Files:** + - Create: `tests/visual/pages.spec.ts` + + **Approach:** + - Import `test` and `takeSnapshot` from `@chromatic-com/playwright` + - One `test()` per page, each navigating to the English URL, waiting for `networkidle`, then calling `takeSnapshot()` + - Pages to cover (~10, one per layout pattern): + - `/en/` — homepage (hub/sections) + - `/en/wallets/` — hero + content + - `/en/staking/` — delegated interactive + - `/en/developers/` — hub variant with code examples + - `/en/apps/` — listing/grid + - `/en/community/events/` — events hub with tabs + - `/en/run-a-node/` — content page variant + - `/en/developers/docs/smart-contracts/` — docs layout (sidebar + TOC) + - `/en/history/` — static layout (breadcrumbs + TOC) + - `/en/wallets/find-wallet/` — product table + - The docs and history pages use the `[...slug]` catch-all route which imports `getGFIs()` directly from `@/data-layer`. This is covered by `USE_MOCK_DATA=true` (reads from `src/data-layer/mocks/fetch-gfis.json`), so no additional mocking is needed. + - Each test waits for a page-specific stable element (e.g., `h1`, main content area) before snapshotting to avoid hydration flicker + - Use `test.describe("Page Visual Tests", ...)` to group all tests + + **Patterns to follow:** + - `tests/e2e/home.spec.ts` for navigation and waiting patterns + - `tests/e2e/fixtures/testData.ts` for URL constants + + **Test scenarios:** + - Happy path: each test navigates to the page, waits for stable DOM, and `takeSnapshot()` produces an archive in `test-results/` + - Edge case: pages with lazy-loaded content (homepage swipers, staking comparisons) — wait for a visible stable element, not just `networkidle` + - Error path: if a page throws (e.g., missing mock data), the test fails with a clear error — not a blank snapshot + + **Verification:** + - `USE_MOCK_DATA=true pnpm build && pnpm start` then `npx playwright test --project=chromatic-desktop` runs all 10 tests and produces 10 archives in `test-results/` + +- [ ] **Unit 3: Create CI workflow** + + **Goal:** Add a GitHub Actions workflow that builds Next.js with mock data, runs Playwright visual tests, and uploads to Chromatic. + + **Requirements:** R4, R5, R6 + + **Dependencies:** Unit 2. Also requires the Chromatic project token (`CHROMATIC_PAGES_TOKEN`) to be created in the dashboard and stored as a GitHub Actions secret (see Manual Setup Required). + + **Files:** + - Create: `.github/workflows/chromatic-pages.yml` + + **Approach:** + - Two-job workflow to enable partial archive upload when some tests fail: + - **Job 1: `playwright-visual`** — checkout, install, `USE_MOCK_DATA=true pnpm build`, start server, run visual tests, upload `test-results/` as artifact (with `if: always()` so archives upload even on test failure) + - **Job 2: `chromatic-upload`** — download artifact, run `npx chromatic --playwright` with project token. Uses `if: always()` so Chromatic still receives partial results when some pages fail. + - Use `mcr.microsoft.com/playwright` container image for consistent browser versions + - Trigger on PRs to `dev`, `master`, `staging` + - Separate from existing `chromatic.yml` (Storybook) — both workflows trigger independently on the same events and run in parallel + - `exitZeroOnChanges: true` so visual changes don't block PRs + + **Patterns to follow:** + - Existing `.github/workflows/chromatic.yml` for trigger config and pnpm/node setup + + **Test scenarios:** + - Happy path: workflow runs both jobs, Chromatic build link appears in PR checks + - Edge case: `test-results/` artifact is correctly passed between jobs + - Error path: one page test fails → Job 1 uploads partial archives → Job 2 still runs Chromatic with available snapshots + + **Verification:** + - Workflow YAML is valid + - The two jobs are correctly sequenced (job 2 depends on job 1 via `needs:`) + - Both jobs use `if: always()` for partial-failure resilience + - Existing Storybook chromatic workflow is unchanged + +## System-Wide Impact + +- **Interaction graph:** Adds a new CI workflow and Playwright projects. Does not modify any application code, components, or the data layer. The `USE_MOCK_DATA` env var is already used by `test:unit`. +- **Error propagation:** Visual test failures don't block PRs (`exitZeroOnChanges: true`). Build failures in the Next.js step would fail the workflow — same as any CI build. +- **Unchanged invariants:** Existing e2e tests, Storybook, component Chromatic project, and the production build are completely unaffected. The mock data files in `src/data-layer/mocks/` are read-only in this context. + +## Alternative Approaches Considered + +**Storybook page stories with webpack mocking (implemented, then replaced):** Built on branch `feat/dual-storybook-page-visual-tests`. Required mocking `next-intl/server`, `next/navigation`, `@/lib/data`, and `@/lib/utils/contributors` at the webpack level. Worked but fought `experimentalRSC` render pass issues and required either composition components (divergence risk) or complex webpack aliases. Playwright against a real build avoids all of this. + +**Playwright `page.route()` for API mocking:** Mock individual fetch calls in each test. More flexible but requires maintaining route handlers per page. The `USE_MOCK_DATA` env var is simpler — one flag controls all data at the storage layer. + +**`toHaveScreenshot()` (Playwright's built-in visual comparison):** Standard Playwright visual regression with local baseline images. Works but requires committing baseline PNGs to the repo, manual updates on intentional changes, and doesn't provide the Chromatic review UI (side-by-side diff, accept/reject workflow, team collaboration). + +## Risks & Dependencies + +| Risk | Mitigation | +|------|------------| +| Mock data files become stale as APIs evolve | Mock files are already maintained for `test:unit`. If a new data field is added, unit tests catch it first. | +| DOM archive captures differ between local and CI | Use the official Playwright container image in CI. Run `next build && next start` (not dev mode) in both environments. | +| Some pages lazy-load content after `networkidle` | Use explicit `waitForSelector` on a stable element before `takeSnapshot()`. Tune `delay` and `resourceArchiveTimeout` per page if needed. | +| No TurboSnap — all 30 snapshots run on every PR | 30 snapshots is modest for Chromatic. If it becomes expensive, use `test.skip` to disable specific pages during non-visual PRs. | +| `@chromatic-com/playwright` bundles Storybook 8.x internally | This is used only for the archive packaging step and doesn't conflict with the project's Storybook 10.x. They operate in separate contexts. | +| Chromatic project requires manual dashboard setup | User is already creating the project. Store token as `CHROMATIC_PAGES_TOKEN` GitHub secret. | + +## Manual Setup Required + +1. Create a Playwright-type Chromatic project in the dashboard (named "ethereum-org-website-pages") +2. Store the project token as `CHROMATIC_PAGES_TOKEN` GitHub Actions secret +3. Run the first baseline build locally: `USE_MOCK_DATA=true pnpm build && pnpm start &` then `pnpm test:visual && pnpm chromatic:pages` + +## Sources & References + +- Chromatic Playwright docs: https://www.chromatic.com/docs/playwright/ +- Chromatic Playwright setup: https://www.chromatic.com/docs/playwright/setup/ +- Chromatic Playwright configuration: https://www.chromatic.com/docs/playwright/configure/ +- Chromatic Playwright targeted snapshots: https://www.chromatic.com/docs/playwright/targeted-snapshots/ +- Previous Storybook approach: branch `feat/dual-storybook-page-visual-tests` +- Existing mock data: `src/data-layer/mocks/` (27 JSON files) From cf718e84fa63c00f9ff443b4790cf98840cf89ea Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 15:10:20 +0200 Subject: [PATCH 02/31] feat(tests): add playwright + chromatic page visual regression tests --- .github/workflows/chromatic-pages.yml | 90 ++++ .gitignore | 2 + package.json | 5 + playwright.config.ts | 49 +- pnpm-lock.yaml | 642 +++----------------------- tests/visual/pages.spec.ts | 48 ++ 6 files changed, 249 insertions(+), 587 deletions(-) create mode 100644 .github/workflows/chromatic-pages.yml create mode 100644 tests/visual/pages.spec.ts diff --git a/.github/workflows/chromatic-pages.yml b/.github/workflows/chromatic-pages.yml new file mode 100644 index 00000000000..86a718e0af8 --- /dev/null +++ b/.github/workflows/chromatic-pages.yml @@ -0,0 +1,90 @@ +# Playwright + Chromatic full-page visual regression tests +# Separate from chromatic.yml (Storybook component snapshots) +name: "Chromatic: Page Visual Tests" + +on: + pull_request: + branches: [dev, master, staging] + types: [opened, synchronize, ready_for_review] + +jobs: + playwright-visual: + name: Build & Capture Snapshots + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/playwright:v1.53.0-noble + steps: + - name: Checkout repo + uses: actions/checkout@v6 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref }} + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 20 + cache: pnpm + + - name: Install dependencies + run: pnpm install + + - name: Build Next.js with mock data (English only) + run: pnpm build + env: + USE_MOCK_DATA: "true" + NEXT_PUBLIC_BUILD_LOCALES: "en" + + - name: Run visual tests + run: pnpm test:visual + env: + HOME: /root + USE_MOCK_DATA: "true" + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: chromatic-archives + path: test-results/ + retention-days: 1 + + chromatic-upload: + name: Upload to Chromatic + needs: playwright-visual + if: always() + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v6 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref }} + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 20 + cache: pnpm + + - name: Install dependencies + run: pnpm install + + - name: Download test results + uses: actions/download-artifact@v4 + with: + name: chromatic-archives + path: test-results/ + + - name: Publish to Chromatic + uses: chromaui/action@v1 + with: + projectToken: ${{ secrets.CHROMATIC_PAGES_TOKEN }} + playwright: true + exitZeroOnChanges: true diff --git a/.gitignore b/.gitignore index 93385efd35e..40a1c7f9ed1 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ /coverage tests/__results__/ tests/__report__/ +test-results/ # next.js /.next/ @@ -64,6 +65,7 @@ src/data/crowdin/bucketsAwaitingReviewReport.csv build-storybook.log build-archive.log storybook-static +storybook-static-pages # Trigger .trigger diff --git a/package.json b/package.json index d7d8377bd71..c04eb5ca4be 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,10 @@ "test:e2e:ui": "playwright test --project=e2e --ui", "test:e2e:debug": "playwright test --project=e2e --debug", "test:e2e:report": "playwright show-report tests/__report__", + "test:visual": "playwright test --project=chromatic-desktop --project=chromatic-tablet --project=chromatic-mobile", + "test:visual:desktop": "playwright test --project=chromatic-desktop", + "test:visual:build": "USE_MOCK_DATA=true NEXT_PUBLIC_BUILD_LOCALES=en next build", + "chromatic:pages": "chromatic --playwright", "trigger:dev": "trigger dev --env-file src/data-layer/.env.local", "trigger:deploy": "trigger deploy --env-file src/data-layer/.env.local" }, @@ -107,6 +111,7 @@ "yaml-loader": "^0.8.0" }, "devDependencies": { + "@chromatic-com/playwright": "^0.13.1", "@chromatic-com/storybook": "5.1.1", "@google/genai": "^1.46.0", "@netlify/plugin-nextjs": "^5.15.9", diff --git a/playwright.config.ts b/playwright.config.ts index 02aaa24c477..4aeb8e9ba84 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,11 +1,12 @@ import path from "path" import dotenv from "dotenv" +import type { ChromaticConfig } from "@chromatic-com/playwright" import { defineConfig, devices } from "@playwright/test" dotenv.config({ path: path.resolve(__dirname, ".env.local") }) -export default defineConfig({ +export default defineConfig({ testDir: "./tests", outputDir: "./tests/__results__", fullyParallel: true, @@ -68,5 +69,51 @@ export default defineConfig({ testDir: "./tests/unit", use: {}, }, + + // ───────────────────────────────────────────────────────────────────────── + // Chromatic visual tests - Full-page snapshots at 3 viewport sizes + // Uses @chromatic-com/playwright to capture DOM archives for Chromatic + // ───────────────────────────────────────────────────────────────────────── + { + name: "chromatic-desktop", + testDir: "./tests/visual", + outputDir: "./test-results", + use: { + ...devices["Desktop Chrome"], + // 1024 (Tailwind `lg`) keeps full-page snapshots under Chromatic's + // 25M pixel limit on our longest pages. + viewport: { width: 1024, height: 720 }, + disableAutoSnapshot: true, + assetDomains: ["s3-dcl1.ethquokkaops.io"], + }, + }, + { + name: "chromatic-tablet", + testDir: "./tests/visual", + outputDir: "./test-results", + use: { + ...devices["Desktop Chrome"], + viewport: { width: 768, height: 1024 }, + disableAutoSnapshot: true, + assetDomains: ["s3-dcl1.ethquokkaops.io"], + }, + }, + { + name: "chromatic-mobile", + testDir: "./tests/visual", + outputDir: "./test-results", + use: { + ...devices["Desktop Chrome"], + viewport: { width: 375, height: 812 }, + disableAutoSnapshot: true, + assetDomains: ["s3-dcl1.ethquokkaops.io"], + }, + }, ], + + webServer: { + command: "pnpm start", + port: 3000, + reuseExistingServer: true, + }, }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d09aee693d0..82e3c3fe94b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -235,9 +235,12 @@ importers: specifier: ^0.8.0 version: 0.8.1 devDependencies: + '@chromatic-com/playwright': + specifier: ^0.13.1 + version: 0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) '@chromatic-com/storybook': specifier: 5.1.1 - version: 5.1.1(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.21)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) + version: 5.1.1(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) '@google/genai': specifier: ^1.46.0 version: 1.46.0(@modelcontextprotocol/sdk@1.29.0(zod@3.25.76))(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -300,7 +303,7 @@ importers: version: 10.4.21(postcss@8.5.4) chromatic: specifier: 16.0.0 - version: 16.0.0(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.21)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)) + version: 16.0.0(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) decompress: specifier: ^4.2.1 version: 4.2.1 @@ -1646,8 +1649,8 @@ packages: '@bugsnag/cuid@3.2.1': resolution: {integrity: sha512-zpvN8xQ5rdRWakMd/BcVkdn2F8HKlDSbM3l7duueK590WmI1T0ObTLc1V/1e55r14WNjPd5AJTYX4yPEAFVi+Q==} - '@chromatic-com/playwright@0.12.5': - resolution: {integrity: sha512-KTPunElGUUEu1ks+G41pJB/WXf+1HeYBnvauvDpJfMlICKoZlL3in0gIUoER/La/zXC/YEKL4BeXvq/JnRQvUw==} + '@chromatic-com/playwright@0.13.1': + resolution: {integrity: sha512-IzR93Dd2Wv8EUI3LURai1IXa0TmWz76zecjgaf9UoSS+F9Mdz09x8PF1zoGm5Wt3D1uirV5eDzQjO6D8f2Ys4Q==} hasBin: true peerDependencies: '@playwright/test': ^1.0.0 @@ -4060,15 +4063,15 @@ packages: '@scure/bip39@1.6.0': resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} - '@segment/analytics-core@1.4.1': - resolution: {integrity: sha512-kV0Pf33HnthuBOVdYNani21kYyj118Fn+9757bxqoksiXoZlYvBsFq6giNdCsKcTIE1eAMqNDq3xE1VQ0cfsHA==} + '@segment/analytics-core@1.7.0': + resolution: {integrity: sha512-0DHSriS/oAB/2bIgOMv3fFV9/ivp39ibdOTTf+dDOhf+vlciBv0+MHw47k/6PRobbuls27cKkKZAKc4DDC2+gw==} - '@segment/analytics-generic-utils@1.1.1': - resolution: {integrity: sha512-THTIzBPHnvu1HYJU3fARdJ3qIkukO3zDXsmDm+kAeUks5R9CBXOQ6rPChiASVzSmwAIIo5uFIXXnCraojlq/Gw==} + '@segment/analytics-generic-utils@1.2.0': + resolution: {integrity: sha512-DfnW6mW3YQOLlDQQdR89k4EqfHb0g/3XvBXkovH1FstUN93eL1kfW9CsDcVQyH3bAC5ZsFyjA/o/1Q2j0QeoWw==} - '@segment/analytics-node@1.3.0': - resolution: {integrity: sha512-lRLz1WZaDokMoUe299yP5JkInc3OgJuqNNlxb6j0q22umCiq6b5iDo2gRmFn93reirIvJxWIicQsGrHd93q8GQ==} - engines: {node: '>=14'} + '@segment/analytics-node@2.1.3': + resolution: {integrity: sha512-xwMkyXgr7xgPsP0w79nzCwRHYi9jzj9ps4Im7xWGK8AKKE4eox39tMZOdRtpDbvXQlrs9fh64ZC0w/yZZDM/9g==} + engines: {node: '>=18'} '@sentry-internal/browser-utils@10.46.0': resolution: {integrity: sha512-WB1gBT9G13V02ekZ6NpUhoI1aGHV2eNfjEPthkU2bGBvFpQKnstwzjg7waIRGR7cu+YSW2Q6UI6aQLgBeOPD1g==} @@ -4611,41 +4614,11 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@storybook/addon-actions@8.5.8': - resolution: {integrity: sha512-7J0NAz+WDw1NmvmKIh0Qr5cxgVRDPFC5fmngbDNxedk147TkwrgmqOypgEi/SAksHbTWxJclbimoqdcsNtWffA==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-backgrounds@8.5.8': - resolution: {integrity: sha512-TsQFagQ95+d7H3/+qUZKI2B0SEK8iu6CV13cyry9Dm59nn2bBylFrwx4I3xDQUOWMiSF6QIRjCYzxKQ/jJ5OEg==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-controls@8.5.8': - resolution: {integrity: sha512-3iifI8mBGPsiPmV9eAYk+tK9i+xuWhVsa+sXz01xTZ/0yoOREpp972hka86mtCqdDTOJIpzh1LmxvB218OssvQ==} - peerDependencies: - storybook: ^8.5.8 - '@storybook/addon-docs@10.3.3': resolution: {integrity: sha512-trJQTpOtuOEuNv1Rn8X2Sopp5hSPpb0u0soEJ71BZAbxe4d2Y1d/1MYcxBdRKwncum6sCTsnxTpqQ/qvSJKlTQ==} peerDependencies: storybook: ^10.3.3 - '@storybook/addon-docs@8.5.8': - resolution: {integrity: sha512-zKVUqE0UGiq1gZtY2TX57SYB4RIsdlbTDxKW2JZ9HhZGLvZ5Qb7AvdiKTZxfOepGhuw3UcNXH/zCFkFCTJifMw==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-essentials@8.5.8': - resolution: {integrity: sha512-sCNvMZqL6dywnyHuZBrWl4f6QXsvpJHOioL3wJJKaaRMZmctbFmS0u6J8TQjmgZhQfyRzuJuhr1gJg9oeqp6AA==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-highlight@8.5.8': - resolution: {integrity: sha512-kkldtFrY0oQJY/vfNLkV66hVgtp66OO8T68KoZFsmUz4a3iYgzDS8WF+Av2/9jthktFvMchjFr8NKOno9YBGIg==} - peerDependencies: - storybook: ^8.5.8 - '@storybook/addon-links@10.3.3': resolution: {integrity: sha512-tazBHlB+YbU62bde5DWsq0lnxZjcAsPB3YRUpN2hSMfAySsudRingyWrgu5KeOxXhJvKJj0ohjQvGcMx/wgQUA==} peerDependencies: @@ -4655,43 +4628,11 @@ packages: react: optional: true - '@storybook/addon-measure@8.5.8': - resolution: {integrity: sha512-xf84ByTRkFPoNSck6Z5OJ0kXTYAYgmg/0Ke0eCY/CNgwh7lfjYQBrcjuKiYZ6jyRUMLdysXzIfF9/2MeFqLfIg==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-outline@8.5.8': - resolution: {integrity: sha512-NAC9VWZFg2gwvduzJRVAtxPeQfJjB8xfDDgcGjgLOCSQkZDDOmGVdLXf78pykMQKyuu/0YZ989KufAac6kRG5g==} - peerDependencies: - storybook: ^8.5.8 - '@storybook/addon-themes@10.3.3': resolution: {integrity: sha512-6PgH1o7yNnWRVj4lAT1DNcX/eZXKgzjhfmzgWh3oFpPfDDvUzpFxx+MClM5f/ZieIbyQscxEuq8li7+e/F5VEQ==} peerDependencies: storybook: ^10.3.3 - '@storybook/addon-toolbars@8.5.8': - resolution: {integrity: sha512-AfGdMNBp+vOjyiFKlOyUFLIU0kN1QF4PhVBqd0vYkWAk2w9n6a/ZlG0TcJGe7K5+bcvmZDAerYMKbDMSeg9bAw==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-viewport@8.5.8': - resolution: {integrity: sha512-SdoRb4bH99Knj2R+rTcMQQxHrtcIO1GLzTFitAefxBE1OUkq8FNLHMHd0Ip/sCQGLW/5F03U70R2uh7SkhBBYA==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/blocks@8.5.8': - resolution: {integrity: sha512-O6tJDJM83fDm3ZP1+lTf24l7HOTzSRXkkMDD7zB/JHixzlj9p6wI4UQc2lplLadDCa5ya1IwyE7zUDN/0UfC5Q==} - peerDependencies: - react: ^19.2.4 - react-dom: ^19.2.4 - storybook: ^8.5.8 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - '@storybook/builder-webpack5@10.3.3': resolution: {integrity: sha512-A7hop0VXG/06EZ7l2WIuhsrnpiV6NOOcOiVqjYDLplbVelkiiL98LTL+Om87u0n32sAfXWgFk2jIhSc3bbXlsQ==} peerDependencies: @@ -4701,38 +4642,11 @@ packages: typescript: optional: true - '@storybook/builder-webpack5@8.5.8': - resolution: {integrity: sha512-QaBIMyqWX/eQs4laQBXvAW9M/ylk73WljJySPlTl+8PNVuDtHli24oBJXwx5aV1NT53BLsaKAn/vb2QNL4+G1Q==} - peerDependencies: - storybook: ^8.5.8 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@storybook/components@8.5.8': - resolution: {integrity: sha512-PPEMqWPXn7rX+qISaOOv9CDSuuvG538f0+4M5Ppq2LwpjXecgOG5ktqJF0ZqxmTytT+RpEaJmgjGW0dMAKZswA==} - peerDependencies: - storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/core-webpack@10.3.3': resolution: {integrity: sha512-ESRM2k9m1V0qXaqEM+bvtCjv9+gYVE3PMuoNZMyIYNdGA4Pdc2PvQsUrKQNVByVbEGwjt+h0RE6b20bnBkdYsg==} peerDependencies: storybook: ^10.3.3 - '@storybook/core-webpack@8.5.8': - resolution: {integrity: sha512-M2LNQdYp0br8fgKMVtBh7YIo8mQsgALLc4i9PEXRS7wrp+bhvVnA9qhd5xDPzb0Rl4CHYbs4Yvkzo7ZQMibeIQ==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/core@8.5.8': - resolution: {integrity: sha512-OT02DQhkGpBgn5P+nZOZmbzxqubC4liVqbhpjp/HOGi5cOA3+fCJzDJeSDTu+pPh7dZnopC4XnR+5dWjtOJHdA==} - peerDependencies: - prettier: ^2 || ^3 - peerDependenciesMeta: - prettier: - optional: true - '@storybook/csf-plugin@10.3.3': resolution: {integrity: sha512-Utlh7zubm+4iOzBBfzLW4F4vD99UBtl2Do4edlzK2F7krQIcFvR2ontjAE8S1FQVLZAC3WHalCOS+Ch8zf3knA==} peerDependencies: @@ -4751,38 +4665,15 @@ packages: webpack: optional: true - '@storybook/csf-plugin@8.5.8': - resolution: {integrity: sha512-9p+TFutbvtPYEmg14UsvqBDWKP/p/+OkIdi+gkwCMw0yiJF/+7ErMHDB0vr5SpJpU7SFQmfpY2c/LaglEtaniw==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/csf@0.1.12': - resolution: {integrity: sha512-9/exVhabisyIVL0VxTCxo01Tdm8wefIXKXfltAPTSr8cbLn5JAxGQ6QV3mjdecLGEOucfoVhAKtJfVHxEK1iqw==} - - '@storybook/csf@0.1.13': - resolution: {integrity: sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q==} - '@storybook/global@5.0.0': resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} - '@storybook/icons@1.4.0': - resolution: {integrity: sha512-Td73IeJxOyalzvjQL+JXx72jlIYHgs+REaHiREOqfpo3A2AYYG71AUbcv+lg7mEDIweKVCxsMQ0UKo634c8XeA==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: ^19.2.4 - react-dom: ^19.2.4 - '@storybook/icons@2.0.1': resolution: {integrity: sha512-/smVjw88yK3CKsiuR71vNgWQ9+NuY2L+e8X7IMrFjexjm6ZR8ULrV2DRkTA61aV6ryefslzHEGDInGpnNeIocg==} peerDependencies: react: ^19.2.4 react-dom: ^19.2.4 - '@storybook/manager-api@8.5.8': - resolution: {integrity: sha512-ik3yikvYxAJMDFg0s3Pm7hZWucAlkFaaO7e2RlfOctaJFdaEi3evR4RS7GdmS38uKBEk31RC7x+nnIJkqEC59A==} - peerDependencies: - storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/nextjs@10.3.3': resolution: {integrity: sha512-/7iNyht4P0QDdSXDIHswgaNfWTGMI3OsQ+blLXlos4AvQMPWvGpDDtWg571+qD+6tKzdUwog+SYt7lvWT69SxA==} peerDependencies: @@ -4809,17 +4700,6 @@ packages: typescript: optional: true - '@storybook/preset-server-webpack@8.5.8': - resolution: {integrity: sha512-0QA23bmhchmec6zI0JzoXWIA723n8XhEtJndUQDS96cTyDGyb3AuedNgwu5xQw9Zv+EJZjO84uGcNYinPEnmKA==} - engines: {node: '>=18.0.0'} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/preview-api@8.5.8': - resolution: {integrity: sha512-HJoz2o28VVprnU5OG6JO6CHrD3ah6qVPWixbnmyUKd0hOYF5dayK5ptmeLyUpYX56Eb2KoYcuVaeQqAby4RkNw==} - peerDependencies: - storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0': resolution: {integrity: sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==} peerDependencies: @@ -4833,13 +4713,6 @@ packages: react-dom: ^19.2.4 storybook: ^10.3.3 - '@storybook/react-dom-shim@8.5.8': - resolution: {integrity: sha512-UT/kGJHPW+HLNCTmI1rV1to+dUZuXKUTaRv2wZ2BUq2/gjIuePyqQZYVQeb0LkZbuH2uviLrPfXpS5d3/RSUJw==} - peerDependencies: - react: ^19.2.4 - react-dom: ^19.2.4 - storybook: ^8.5.8 - '@storybook/react@10.3.3': resolution: {integrity: sha512-cGG5TbR8Tdx9zwlpsWyBEfWrejm5iWdYF26EwIhwuKq9GFUTAVrQzo0Rs7Tqc3ZyVhRS/YfsRiWSEH+zmq2JiQ==} peerDependencies: @@ -4851,23 +4724,6 @@ packages: typescript: optional: true - '@storybook/server-webpack5@8.5.8': - resolution: {integrity: sha512-bdRxp0kUGBstDdCEIfJEbsmM7vvyBES4Hjmj0jXcOefQYic5QTWTiDMrHgWPp8XWGjIoO+wOfWm2IXPP5Uceog==} - engines: {node: '>=18.0.0'} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/server@8.5.8': - resolution: {integrity: sha512-DB3IR7CCUklTXtytbOOX7Vig1h9ohQ3BPauvf7WlYXLv4JlkO54oTu37rL0wbqgmmh4FOF41ZSX8z4h4w41How==} - engines: {node: '>=18.0.0'} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/theming@8.5.8': - resolution: {integrity: sha512-/Rm6BV778sCT+3Ok861VYmw9BlEV5zcCq2zg5TOVuk8HqZw7H7VHtubVsjukEuhveYCs+oF+i2tv/II6jh6jdg==} - peerDependencies: - storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@svgr/babel-plugin-add-jsx-attribute@8.0.0': resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} engines: {node: '>=14'} @@ -5305,9 +5161,6 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@types/uuid@9.0.8': - resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} - '@types/xml2js@0.4.14': resolution: {integrity: sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==} @@ -6039,10 +5892,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - better-opn@3.0.2: - resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} - engines: {node: '>=12.0.0'} - big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -6095,9 +5944,6 @@ packages: brorand@1.1.0: resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - browser-assert@1.2.1: - resolution: {integrity: sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==} - browserify-aes@1.2.0: resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} @@ -6804,10 +6650,6 @@ packages: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} - define-lazy-prop@2.0.0: - resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} - engines: {node: '>=8'} - define-lazy-prop@3.0.0: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} @@ -7113,11 +6955,6 @@ packages: esast-util-from-js@2.0.1: resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} - esbuild-register@3.6.0: - resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} - peerDependencies: - esbuild: '>=0.12 <1' - esbuild@0.23.1: resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} engines: {node: '>=18'} @@ -7562,13 +7399,6 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - fork-ts-checker-webpack-plugin@8.0.0: - resolution: {integrity: sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==} - engines: {node: '>=12.13.0', yarn: '>=1.0.0'} - peerDependencies: - typescript: '>3.6.0' - webpack: ^5.11.0 - fork-ts-checker-webpack-plugin@9.1.0: resolution: {integrity: sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==} engines: {node: '>=14.21.3'} @@ -8101,11 +7931,6 @@ packages: is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -8252,10 +8077,6 @@ packages: resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} engines: {node: '>=18'} - is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - is-wsl@3.1.1: resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} @@ -8328,10 +8149,6 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsdoc-type-pratt-parser@4.1.0: - resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} - engines: {node: '>=12.0.0'} - jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} @@ -8564,9 +8381,6 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - map-or-similar@1.5.0: - resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} - markdown-extensions@2.0.0: resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} engines: {node: '>=16'} @@ -8677,9 +8491,6 @@ packages: memoize-one@6.0.0: resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} - memoizerific@1.11.3: - resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} - merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} @@ -9175,10 +8986,6 @@ packages: resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} engines: {node: '>=18'} - open@8.4.2: - resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} - engines: {node: '>=12'} - opener@1.5.2: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true @@ -10137,9 +9944,6 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-identifier@0.4.2: - resolution: {integrity: sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==} - safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -10416,8 +10220,8 @@ packages: next-intl: ^3 || ^4 storybook: ^9.0.0 || ^10.0.0 - storybook@10.3.3: - resolution: {integrity: sha512-tMoRAts9EVqf+mEMPLC6z1DPyHbcPe+CV1MhLN55IKsl0HxNjvVGK44rVPSePbltPE6vIsn4bdRj6CCUt8SJwQ==} + storybook@10.2.13: + resolution: {integrity: sha512-heMfJjOfbHvL+wlCAwFZlSxcakyJ5yQDam6e9k2RRArB1veJhRnsjO6lO1hOXjJYrqxfHA/ldIugbBVlCDqfvQ==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -10425,8 +10229,8 @@ packages: prettier: optional: true - storybook@8.5.8: - resolution: {integrity: sha512-k3QDa7z4a656oO3Mx929KNm+xIdEI2nIDCKatVl1mA6vt+ge+uwoiG+ro182J9LOEppR5XXD2mQQi4u1xNsy6A==} + storybook@10.3.3: + resolution: {integrity: sha512-tMoRAts9EVqf+mEMPLC6z1DPyHbcPe+CV1MhLN55IKsl0HxNjvVGK44rVPSePbltPE6vIsn4bdRj6CCUt8SJwQ==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -11014,10 +10818,6 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - unplugin@1.16.1: - resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} - engines: {node: '>=14.0.0'} - unplugin@2.3.11: resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} engines: {node: '>=18.12.0'} @@ -13993,36 +13793,26 @@ snapshots: '@bugsnag/cuid@3.2.1': {} - '@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.21)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)': + '@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)': dependencies: '@chromaui/rrweb-snapshot': 2.0.0-alpha.18-noAbsolute '@playwright/test': 1.53.1 - '@segment/analytics-node': 1.3.0 - '@storybook/addon-essentials': 8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/csf': 0.1.13 - '@storybook/manager-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/server-webpack5': 8.5.8(@swc/core@1.15.21)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) + '@segment/analytics-node': 2.1.3 + storybook: 10.2.13(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 transitivePeerDependencies: - - '@rspack/core' - - '@swc/core' - - '@types/react' + - '@testing-library/dom' - bufferutil - encoding - - esbuild - prettier - - supports-color - - typescript - - uglify-js + - react + - react-dom - utf-8-validate - - webpack-cli - optional: true - '@chromatic-com/storybook@5.1.1(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.21)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': + '@chromatic-com/storybook@5.1.1(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: '@neoconfetti/react': 1.0.0 - chromatic: 13.3.5(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.21)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)) + chromatic: 13.3.5(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) filesize: 10.1.6 jsonfile: 6.1.0 storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) @@ -14034,7 +13824,6 @@ snapshots: '@chromaui/rrweb-snapshot@2.0.0-alpha.18-noAbsolute': dependencies: postcss: 8.5.4 - optional: true '@clack/core@0.5.0': dependencies: @@ -14765,13 +14554,11 @@ snapshots: dependencies: '@lit-labs/ssr-dom-shim': 1.3.0 - '@lukeed/csprng@1.1.0': - optional: true + '@lukeed/csprng@1.1.0': {} '@lukeed/uuid@2.0.1': dependencies: '@lukeed/csprng': 1.1.0 - optional: true '@mdx-js/mdx@3.1.0(acorn@8.16.0)': dependencies: @@ -16618,30 +16405,28 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 - '@segment/analytics-core@1.4.1': + '@segment/analytics-core@1.7.0': dependencies: '@lukeed/uuid': 2.0.1 - '@segment/analytics-generic-utils': 1.1.1 + '@segment/analytics-generic-utils': 1.2.0 dset: 3.1.4 tslib: 2.8.1 - optional: true - '@segment/analytics-generic-utils@1.1.1': + '@segment/analytics-generic-utils@1.2.0': dependencies: tslib: 2.8.1 - optional: true - '@segment/analytics-node@1.3.0': + '@segment/analytics-node@2.1.3': dependencies: '@lukeed/uuid': 2.0.1 - '@segment/analytics-core': 1.4.1 - '@segment/analytics-generic-utils': 1.1.1 + '@segment/analytics-core': 1.7.0 + '@segment/analytics-generic-utils': 1.2.0 buffer: 6.0.3 + jose: 5.10.0 node-fetch: 2.7.0 tslib: 2.8.1 transitivePeerDependencies: - encoding - optional: true '@sentry-internal/browser-utils@10.46.0': dependencies: @@ -17450,32 +17235,6 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/addon-actions@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - '@types/uuid': 9.0.8 - dequal: 2.0.3 - polished: 4.3.1 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - uuid: 9.0.1 - optional: true - - '@storybook/addon-backgrounds@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - memoizerific: 1.11.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - - '@storybook/addon-controls@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - dequal: 2.0.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - '@storybook/addon-docs@10.3.3(@types/react@19.2.14)(esbuild@0.25.12)(rollup@4.46.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12))': dependencies: '@mdx-js/react': 3.1.0(@types/react@19.2.14)(react@19.2.4) @@ -17493,43 +17252,6 @@ snapshots: - vite - webpack - '@storybook/addon-docs@8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@mdx-js/react': 3.1.0(@types/react@19.2.14)(react@19.2.4) - '@storybook/blocks': 8.5.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/csf-plugin': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/react-dom-shim': 8.5.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - transitivePeerDependencies: - - '@types/react' - optional: true - - '@storybook/addon-essentials@8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/addon-actions': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-backgrounds': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-controls': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-docs': 8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-highlight': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-measure': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-outline': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-toolbars': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-viewport': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - transitivePeerDependencies: - - '@types/react' - optional: true - - '@storybook/addon-highlight@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/addon-links@10.3.3(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: '@storybook/global': 5.0.0 @@ -17537,47 +17259,11 @@ snapshots: optionalDependencies: react: 19.2.4 - '@storybook/addon-measure@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - tiny-invariant: 1.3.3 - optional: true - - '@storybook/addon-outline@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - '@storybook/addon-themes@10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 - '@storybook/addon-toolbars@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - - '@storybook/addon-viewport@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - memoizerific: 1.11.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - - '@storybook/blocks@8.5.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/csf': 0.1.12 - '@storybook/icons': 1.4.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optionalDependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optional: true - '@storybook/builder-webpack5@10.3.3(@swc/core@1.15.21)(esbuild@0.25.12)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(typescript@5.8.3)': dependencies: '@storybook/core-webpack': 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) @@ -17605,80 +17291,11 @@ snapshots: - uglify-js - webpack-cli - '@storybook/builder-webpack5@8.5.8(@swc/core@1.15.21)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': - dependencies: - '@storybook/core-webpack': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@types/semver': 7.7.1 - browser-assert: 1.2.1 - case-sensitive-paths-webpack-plugin: 2.4.0 - cjs-module-lexer: 1.4.3 - constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12)) - es-module-lexer: 1.7.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12)) - html-webpack-plugin: 5.6.3(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12)) - magic-string: 0.30.17 - path-browserify: 1.0.1 - process: 0.11.10 - semver: 7.7.4 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - style-loader: 3.3.4(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12)) - terser-webpack-plugin: 5.3.14(@swc/core@1.15.21)(esbuild@0.25.12)(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12)) - ts-dedent: 2.2.0 - url: 0.11.4 - util: 0.12.5 - util-deprecate: 1.0.2 - webpack: 5.99.9(@swc/core@1.15.21)(esbuild@0.25.12) - webpack-dev-middleware: 6.1.3(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12)) - webpack-hot-middleware: 2.26.1 - webpack-virtual-modules: 0.6.2 - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - '@rspack/core' - - '@swc/core' - - esbuild - - uglify-js - - webpack-cli - optional: true - - '@storybook/components@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/core-webpack@10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 - '@storybook/core-webpack@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - - '@storybook/core@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)': - dependencies: - '@storybook/csf': 0.1.12 - better-opn: 3.0.2 - browser-assert: 1.2.1 - esbuild: 0.25.12 - esbuild-register: 3.6.0(esbuild@0.25.12) - jsdoc-type-pratt-parser: 4.1.0 - process: 0.11.10 - recast: 0.23.11 - semver: 7.7.4 - util: 0.12.5 - ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - prettier: 3.5.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - optional: true - '@storybook/csf-plugin@10.3.3(esbuild@0.25.12)(rollup@4.46.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) @@ -17688,40 +17305,13 @@ snapshots: rollup: 4.46.2 webpack: 5.99.9(@swc/core@1.15.21)(esbuild@0.25.12) - '@storybook/csf-plugin@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - unplugin: 1.16.1 - optional: true - - '@storybook/csf@0.1.12': - dependencies: - type-fest: 2.19.0 - optional: true - - '@storybook/csf@0.1.13': - dependencies: - type-fest: 2.19.0 - optional: true - '@storybook/global@5.0.0': {} - '@storybook/icons@1.4.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optional: true - '@storybook/icons@2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/manager-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/nextjs@10.3.3(@swc/core@1.15.21)(babel-plugin-macros@3.1.0)(esbuild@0.25.12)(next@16.2.1(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12))': dependencies: '@babel/core': 7.29.0 @@ -17805,22 +17395,6 @@ snapshots: - uglify-js - webpack-cli - '@storybook/preset-server-webpack@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/core-webpack': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/global': 5.0.0 - '@storybook/server': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - safe-identifier: 0.4.2 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - yaml-loader: 0.8.1 - optional: true - - '@storybook/preview-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12))': dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -17841,13 +17415,6 @@ snapshots: react-dom: 19.2.4(react@19.2.4) storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) - '@storybook/react-dom-shim@8.5.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/react@10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(typescript@5.8.3)': dependencies: '@storybook/global': 5.0.0 @@ -17862,39 +17429,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/server-webpack5@8.5.8(@swc/core@1.15.21)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': - dependencies: - '@storybook/builder-webpack5': 8.5.8(@swc/core@1.15.21)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) - '@storybook/preset-server-webpack': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/server': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - '@rspack/core' - - '@swc/core' - - esbuild - - typescript - - uglify-js - - webpack-cli - optional: true - - '@storybook/server@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/components': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/csf': 0.1.12 - '@storybook/global': 5.0.0 - '@storybook/manager-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/preview-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/theming': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - yaml: 2.8.0 - optional: true - - '@storybook/theming@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 @@ -18377,9 +17911,6 @@ snapshots: '@types/unist@3.0.3': {} - '@types/uuid@9.0.8': - optional: true - '@types/xml2js@0.4.14': dependencies: '@types/node': 20.17.57 @@ -19678,11 +19209,6 @@ snapshots: baseline-browser-mapping@2.10.12: {} - better-opn@3.0.2: - dependencies: - open: 8.4.2 - optional: true - big.js@5.2.2: {} big.js@6.2.2: {} @@ -19739,9 +19265,6 @@ snapshots: brorand@1.1.0: {} - browser-assert@1.2.1: - optional: true - browserify-aes@1.2.0: dependencies: buffer-xor: 1.0.3 @@ -19974,13 +19497,13 @@ snapshots: chownr@3.0.0: {} - chromatic@13.3.5(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.21)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)): + chromatic@13.3.5(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)): optionalDependencies: - '@chromatic-com/playwright': 0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.21)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10) + '@chromatic-com/playwright': 0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) - chromatic@16.0.0(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.21)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)): + chromatic@16.0.0(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)): optionalDependencies: - '@chromatic-com/playwright': 0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.21)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10) + '@chromatic-com/playwright': 0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) chrome-trace-event@1.0.4: {} @@ -20461,9 +19984,6 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - define-lazy-prop@2.0.0: - optional: true - define-lazy-prop@3.0.0: {} define-properties@1.2.1: @@ -20591,8 +20111,7 @@ snapshots: dotenv@16.6.1: {} - dset@3.1.4: - optional: true + dset@3.1.4: {} dunder-proto@1.0.1: dependencies: @@ -20866,14 +20385,6 @@ snapshots: esast-util-from-estree: 2.0.0 vfile-message: 4.0.2 - esbuild-register@3.6.0(esbuild@0.25.12): - dependencies: - debug: 4.4.3(supports-color@10.2.2) - esbuild: 0.25.12 - transitivePeerDependencies: - - supports-color - optional: true - esbuild@0.23.1: optionalDependencies: '@esbuild/aix-ppc64': 0.23.1 @@ -21483,24 +20994,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12)): - dependencies: - '@babel/code-frame': 7.29.0 - chalk: 4.1.2 - chokidar: 3.6.0 - cosmiconfig: 7.1.0 - deepmerge: 4.3.1 - fs-extra: 10.1.0 - memfs: 3.5.3 - minimatch: 3.1.2 - node-abort-controller: 3.1.1 - schema-utils: 3.3.0 - semver: 7.7.4 - tapable: 2.2.2 - typescript: 5.8.3 - webpack: 5.99.9(@swc/core@1.15.21)(esbuild@0.25.12) - optional: true - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.15.21)(esbuild@0.25.12)): dependencies: '@babel/code-frame': 7.27.1 @@ -22135,9 +21628,6 @@ snapshots: is-decimal@2.0.1: {} - is-docker@2.2.1: - optional: true - is-docker@3.0.0: {} is-extendable@0.1.1: {} @@ -22255,11 +21745,6 @@ snapshots: is-what@5.5.0: {} - is-wsl@2.2.0: - dependencies: - is-docker: 2.2.1 - optional: true - is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 @@ -22330,9 +21815,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsdoc-type-pratt-parser@4.1.0: - optional: true - jsesc@3.0.2: {} jsesc@3.1.0: {} @@ -22573,9 +22055,6 @@ snapshots: make-error@1.3.6: {} - map-or-similar@1.5.0: - optional: true - markdown-extensions@2.0.0: {} markdown-it@14.1.1: @@ -22824,11 +22303,6 @@ snapshots: memoize-one@6.0.0: {} - memoizerific@1.11.3: - dependencies: - map-or-similar: 1.5.0 - optional: true - merge-descriptors@2.0.0: {} merge-stream@2.0.0: {} @@ -23492,13 +22966,6 @@ snapshots: is-inside-container: 1.0.0 wsl-utils: 0.1.0 - open@8.4.2: - dependencies: - define-lazy-prop: 2.0.0 - is-docker: 2.2.1 - is-wsl: 2.2.0 - optional: true - opener@1.5.2: {} optionator@0.9.4: @@ -24582,9 +24049,6 @@ snapshots: safe-buffer@5.2.1: {} - safe-identifier@0.4.2: - optional: true - safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -24948,7 +24412,7 @@ snapshots: - react - react-dom - storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10): + storybook@10.2.13(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -24971,16 +24435,28 @@ snapshots: - react-dom - utf-8-validate - storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10): + storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10): dependencies: - '@storybook/core': 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) + '@storybook/global': 5.0.0 + '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@testing-library/jest-dom': 6.9.1 + '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) + '@vitest/expect': 3.2.4 + '@vitest/spy': 3.2.4 + esbuild: 0.25.12 + open: 10.2.0 + recast: 0.23.11 + semver: 7.7.4 + use-sync-external-store: 1.5.0(react@19.2.4) + ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: prettier: 3.5.3 transitivePeerDependencies: + - '@testing-library/dom' - bufferutil - - supports-color + - react + - react-dom - utf-8-validate - optional: true stream-browserify@3.0.0: dependencies: @@ -25700,12 +25176,6 @@ snapshots: unpipe@1.0.0: {} - unplugin@1.16.1: - dependencies: - acorn: 8.16.0 - webpack-virtual-modules: 0.6.2 - optional: true - unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 diff --git a/tests/visual/pages.spec.ts b/tests/visual/pages.spec.ts new file mode 100644 index 00000000000..536c03bd57d --- /dev/null +++ b/tests/visual/pages.spec.ts @@ -0,0 +1,48 @@ +import { takeSnapshot, test } from "@chromatic-com/playwright" + +/** + * Full-page visual regression tests for Chromatic. + * + * Each test navigates to a representative page, waits for the content + * to stabilize, then captures a DOM archive via takeSnapshot(). + * Archives are uploaded to Chromatic for pixel-diffing. + * + * Run against a production build with USE_MOCK_DATA=true for deterministic content: + * USE_MOCK_DATA=true pnpm build && pnpm start + * pnpm test:visual + */ + +const pages = [ + { name: "Homepage", path: "/en/", stableSelector: "h1" }, + { name: "Wallets", path: "/en/wallets/", stableSelector: "h1" }, + { name: "Staking", path: "/en/staking/", stableSelector: "h1" }, + { name: "Developers", path: "/en/developers/", stableSelector: "h1" }, + { name: "Apps", path: "/en/apps/", stableSelector: "h1" }, + { + name: "Community Events", + path: "/en/community/events/", + stableSelector: "h1", + }, + { name: "Run a Node", path: "/en/run-a-node/", stableSelector: "h1" }, + { + name: "Docs - Smart Contracts", + path: "/en/developers/docs/smart-contracts/", + stableSelector: "article#main-content", + }, + { name: "History", path: "/en/history/", stableSelector: "h1" }, + { + name: "Find Wallet", + path: "/en/wallets/find-wallet/", + stableSelector: "h1", + }, +] + +test.describe("Page Visual Tests", () => { + for (const { name, path, stableSelector } of pages) { + test(name, async ({ page }, testInfo) => { + await page.goto(path, { waitUntil: "networkidle" }) + await page.locator(stableSelector).first().waitFor({ state: "visible" }) + await takeSnapshot(page, testInfo) + }) + } +}) From 2942aebd68485021e23d78719ad0bafd8508ab7b Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 15:55:40 +0200 Subject: [PATCH 03/31] test(visual): wait for nav hydration and cover each src/layouts layout --- tests/visual/pages.spec.ts | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/tests/visual/pages.spec.ts b/tests/visual/pages.spec.ts index 536c03bd57d..09b617eb5eb 100644 --- a/tests/visual/pages.spec.ts +++ b/tests/visual/pages.spec.ts @@ -12,7 +12,11 @@ import { takeSnapshot, test } from "@chromatic-com/playwright" * pnpm test:visual */ +// Each entry covers either a distinct app route or one layout from src/layouts/. +// App-route pages all share BaseLayout; md-slug pages additionally exercise +// their template's layout component. const pages = [ + // App routes { name: "Homepage", path: "/en/", stableSelector: "h1" }, { name: "Wallets", path: "/en/wallets/", stableSelector: "h1" }, { name: "Staking", path: "/en/staking/", stableSelector: "h1" }, @@ -24,17 +28,41 @@ const pages = [ stableSelector: "h1", }, { name: "Run a Node", path: "/en/run-a-node/", stableSelector: "h1" }, + { name: "History", path: "/en/history/", stableSelector: "h1" }, + { name: "Get ETH", path: "/en/get-eth/", stableSelector: "h1" }, + { + name: "Find Wallet", + path: "/en/wallets/find-wallet/", + stableSelector: "h1", + }, + + // src/layouts/ coverage (one representative per layout) + // StaticLayout + { name: "Bridges", path: "/en/bridges/", stableSelector: "h1" }, + // DocsLayout { name: "Docs - Smart Contracts", path: "/en/developers/docs/smart-contracts/", stableSelector: "article#main-content", }, - { name: "History", path: "/en/history/", stableSelector: "h1" }, + // TutorialLayout { - name: "Find Wallet", - path: "/en/wallets/find-wallet/", + name: "Tutorial - Hello World", + path: "/en/developers/tutorials/hello-world-smart-contract/", + stableSelector: "h1", + }, + // md/StakingLayout + { name: "Staking - Solo", path: "/en/staking/solo/", stableSelector: "h1" }, + // md/RoadmapLayout + { + name: "Roadmap - Security", + path: "/en/roadmap/security/", stableSelector: "h1", }, + // md/UpgradeLayout + { name: "Roadmap - Merge", path: "/en/roadmap/merge/", stableSelector: "h1" }, + // md/UseCasesLayout (ContentLayout is covered transitively by any md layout) + { name: "DeFi", path: "/en/defi/", stableSelector: "h1" }, ] test.describe("Page Visual Tests", () => { @@ -42,6 +70,10 @@ test.describe("Page Visual Tests", () => { test(name, async ({ page }, testInfo) => { await page.goto(path, { waitUntil: "networkidle" }) await page.locator(stableSelector).first().waitFor({ state: "visible" }) + await page + .locator('nav[aria-label="Primary"] .animate-pulse-light') + .first() + .waitFor({ state: "detached" }) await takeSnapshot(page, testInfo) }) } From f7fbbe22b18e222a2dc924fb3d1a4f8a7cf4fce1 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 16:11:30 +0200 Subject: [PATCH 04/31] chore(chromatic): zip archive uploads in chromatic:pages --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c04eb5ca4be..0cea4c7c816 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "test:visual": "playwright test --project=chromatic-desktop --project=chromatic-tablet --project=chromatic-mobile", "test:visual:desktop": "playwright test --project=chromatic-desktop", "test:visual:build": "USE_MOCK_DATA=true NEXT_PUBLIC_BUILD_LOCALES=en next build", - "chromatic:pages": "chromatic --playwright", + "chromatic:pages": "chromatic --playwright --zip", "trigger:dev": "trigger dev --env-file src/data-layer/.env.local", "trigger:deploy": "trigger deploy --env-file src/data-layer/.env.local" }, From d04c41dc7db22708d43c08c906babeebcb475c34 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 16:28:39 +0200 Subject: [PATCH 05/31] chore(chromatic): align visual test ci with official playwright pattern --- .github/workflows/chromatic-pages.yml | 4 +--- package.json | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/chromatic-pages.yml b/.github/workflows/chromatic-pages.yml index 86a718e0af8..6e7ef5e0fb7 100644 --- a/.github/workflows/chromatic-pages.yml +++ b/.github/workflows/chromatic-pages.yml @@ -12,13 +12,12 @@ jobs: name: Build & Capture Snapshots runs-on: ubuntu-latest container: - image: mcr.microsoft.com/playwright:v1.53.0-noble + image: mcr.microsoft.com/playwright:v1.53.1-noble steps: - name: Checkout repo uses: actions/checkout@v6 with: fetch-depth: 0 - ref: ${{ github.event.pull_request.head.ref }} - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -62,7 +61,6 @@ jobs: uses: actions/checkout@v6 with: fetch-depth: 0 - ref: ${{ github.event.pull_request.head.ref }} - name: Setup pnpm uses: pnpm/action-setup@v4 diff --git a/package.json b/package.json index 0cea4c7c816..0bb48d5ba1f 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "test:visual": "playwright test --project=chromatic-desktop --project=chromatic-tablet --project=chromatic-mobile", "test:visual:desktop": "playwright test --project=chromatic-desktop", "test:visual:build": "USE_MOCK_DATA=true NEXT_PUBLIC_BUILD_LOCALES=en next build", - "chromatic:pages": "chromatic --playwright --zip", + "chromatic:pages": "chromatic --playwright --zip --exit-zero-on-changes", "trigger:dev": "trigger dev --env-file src/data-layer/.env.local", "trigger:deploy": "trigger deploy --env-file src/data-layer/.env.local" }, From 9751ae7072e9161e2cd9eb2a1f25c40333fe0e7c Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 16:42:19 +0200 Subject: [PATCH 06/31] chore(chromatic): group chromatic:pages with chromatic script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0bb48d5ba1f..a02aecbcf0a 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "build-storybook": "storybook build", "build-storybook:chromatic": "storybook build --test", "chromatic": "chromatic --project-token fee8e66c9916", + "chromatic:pages": "chromatic --playwright --zip --exit-zero-on-changes", "lint:md": "markdownlint-cli2 \"public/content/**/*.md\" \"!public/content/translations/**\"", "lint:md:fix": "markdownlint-cli2 --fix \"public/content/**/*.md\" \"!public/content/translations/**\"", "markdown-checker": "ts-node -O '{ \"module\": \"commonjs\" }' src/scripts/markdownChecker.ts", @@ -31,7 +32,6 @@ "test:visual": "playwright test --project=chromatic-desktop --project=chromatic-tablet --project=chromatic-mobile", "test:visual:desktop": "playwright test --project=chromatic-desktop", "test:visual:build": "USE_MOCK_DATA=true NEXT_PUBLIC_BUILD_LOCALES=en next build", - "chromatic:pages": "chromatic --playwright --zip --exit-zero-on-changes", "trigger:dev": "trigger dev --env-file src/data-layer/.env.local", "trigger:deploy": "trigger deploy --env-file src/data-layer/.env.local" }, From 21e65285289000737911eadeeb163aaf9ae76c9c Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 16:51:05 +0200 Subject: [PATCH 07/31] chore(chromatic): harden visual test workflow installs Use --frozen-lockfile on both pnpm installs so CI cannot silently drift from the committed lockfile. Also drop the unneeded `if: always()` on chromatic-upload; it was only ever reachable via `needs`, so the default already gates it on the build job producing artifacts to upload. --- .github/workflows/chromatic-pages.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/chromatic-pages.yml b/.github/workflows/chromatic-pages.yml index 6e7ef5e0fb7..42b958cf1f3 100644 --- a/.github/workflows/chromatic-pages.yml +++ b/.github/workflows/chromatic-pages.yml @@ -29,7 +29,7 @@ jobs: cache: pnpm - name: Install dependencies - run: pnpm install + run: pnpm install --frozen-lockfile - name: Build Next.js with mock data (English only) run: pnpm build @@ -54,7 +54,6 @@ jobs: chromatic-upload: name: Upload to Chromatic needs: playwright-visual - if: always() runs-on: ubuntu-latest steps: - name: Checkout repo @@ -72,7 +71,7 @@ jobs: cache: pnpm - name: Install dependencies - run: pnpm install + run: pnpm install --frozen-lockfile - name: Download test results uses: actions/download-artifact@v4 From 4af8be7a01e92f4bbf9e4cc692aea7fcf439c111 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 16:51:13 +0200 Subject: [PATCH 08/31] test(visual): wait on domcontentloaded and default stable selector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit networkidle is flaky on Next.js pages due to analytics beacons and prefetch — the explicit stable-selector + nav-skeleton-detach waits already gate readiness, so domcontentloaded is enough. Also default stableSelector to "h1" in the loop destructure and drop the 15 redundant literals from the page table. --- tests/visual/pages.spec.ts | 51 ++++++++++++++------------------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/tests/visual/pages.spec.ts b/tests/visual/pages.spec.ts index 09b617eb5eb..a5f88402cc9 100644 --- a/tests/visual/pages.spec.ts +++ b/tests/visual/pages.spec.ts @@ -14,31 +14,23 @@ import { takeSnapshot, test } from "@chromatic-com/playwright" // Each entry covers either a distinct app route or one layout from src/layouts/. // App-route pages all share BaseLayout; md-slug pages additionally exercise -// their template's layout component. -const pages = [ +// their template's layout component. stableSelector defaults to "h1". +const pages: Array<{ name: string; path: string; stableSelector?: string }> = [ // App routes - { name: "Homepage", path: "/en/", stableSelector: "h1" }, - { name: "Wallets", path: "/en/wallets/", stableSelector: "h1" }, - { name: "Staking", path: "/en/staking/", stableSelector: "h1" }, - { name: "Developers", path: "/en/developers/", stableSelector: "h1" }, - { name: "Apps", path: "/en/apps/", stableSelector: "h1" }, - { - name: "Community Events", - path: "/en/community/events/", - stableSelector: "h1", - }, - { name: "Run a Node", path: "/en/run-a-node/", stableSelector: "h1" }, - { name: "History", path: "/en/history/", stableSelector: "h1" }, - { name: "Get ETH", path: "/en/get-eth/", stableSelector: "h1" }, - { - name: "Find Wallet", - path: "/en/wallets/find-wallet/", - stableSelector: "h1", - }, + { name: "Homepage", path: "/en/" }, + { name: "Wallets", path: "/en/wallets/" }, + { name: "Staking", path: "/en/staking/" }, + { name: "Developers", path: "/en/developers/" }, + { name: "Apps", path: "/en/apps/" }, + { name: "Community Events", path: "/en/community/events/" }, + { name: "Run a Node", path: "/en/run-a-node/" }, + { name: "History", path: "/en/history/" }, + { name: "Get ETH", path: "/en/get-eth/" }, + { name: "Find Wallet", path: "/en/wallets/find-wallet/" }, // src/layouts/ coverage (one representative per layout) // StaticLayout - { name: "Bridges", path: "/en/bridges/", stableSelector: "h1" }, + { name: "Bridges", path: "/en/bridges/" }, // DocsLayout { name: "Docs - Smart Contracts", @@ -49,26 +41,21 @@ const pages = [ { name: "Tutorial - Hello World", path: "/en/developers/tutorials/hello-world-smart-contract/", - stableSelector: "h1", }, // md/StakingLayout - { name: "Staking - Solo", path: "/en/staking/solo/", stableSelector: "h1" }, + { name: "Staking - Solo", path: "/en/staking/solo/" }, // md/RoadmapLayout - { - name: "Roadmap - Security", - path: "/en/roadmap/security/", - stableSelector: "h1", - }, + { name: "Roadmap - Security", path: "/en/roadmap/security/" }, // md/UpgradeLayout - { name: "Roadmap - Merge", path: "/en/roadmap/merge/", stableSelector: "h1" }, + { name: "Roadmap - Merge", path: "/en/roadmap/merge/" }, // md/UseCasesLayout (ContentLayout is covered transitively by any md layout) - { name: "DeFi", path: "/en/defi/", stableSelector: "h1" }, + { name: "DeFi", path: "/en/defi/" }, ] test.describe("Page Visual Tests", () => { - for (const { name, path, stableSelector } of pages) { + for (const { name, path, stableSelector = "h1" } of pages) { test(name, async ({ page }, testInfo) => { - await page.goto(path, { waitUntil: "networkidle" }) + await page.goto(path, { waitUntil: "domcontentloaded" }) await page.locator(stableSelector).first().waitFor({ state: "visible" }) await page .locator('nav[aria-label="Primary"] .animate-pulse-light') From 3b81d9de17226a2360c354b5ef6aaacc52dc0a0f Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 16:52:07 +0200 Subject: [PATCH 09/31] ci(chromatic): align page visual test pr triggers with chromatic.yml --- .github/workflows/chromatic-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/chromatic-pages.yml b/.github/workflows/chromatic-pages.yml index 42b958cf1f3..d1486237c3b 100644 --- a/.github/workflows/chromatic-pages.yml +++ b/.github/workflows/chromatic-pages.yml @@ -4,7 +4,7 @@ name: "Chromatic: Page Visual Tests" on: pull_request: - branches: [dev, master, staging] + branches: [master, staging, "test/**"] types: [opened, synchronize, ready_for_review] jobs: From c58190f80bd1aa9ebd456915671841ad3c7f0eac Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 16:54:58 +0200 Subject: [PATCH 10/31] chore(visual): trim noisy comments in visual test config and spec --- playwright.config.ts | 1 - tests/visual/pages.spec.ts | 39 +++++++++----------------------------- 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 4aeb8e9ba84..0cdb9c904de 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -72,7 +72,6 @@ export default defineConfig({ // ───────────────────────────────────────────────────────────────────────── // Chromatic visual tests - Full-page snapshots at 3 viewport sizes - // Uses @chromatic-com/playwright to capture DOM archives for Chromatic // ───────────────────────────────────────────────────────────────────────── { name: "chromatic-desktop", diff --git a/tests/visual/pages.spec.ts b/tests/visual/pages.spec.ts index a5f88402cc9..fd13c5ceb42 100644 --- a/tests/visual/pages.spec.ts +++ b/tests/visual/pages.spec.ts @@ -1,22 +1,8 @@ import { takeSnapshot, test } from "@chromatic-com/playwright" -/** - * Full-page visual regression tests for Chromatic. - * - * Each test navigates to a representative page, waits for the content - * to stabilize, then captures a DOM archive via takeSnapshot(). - * Archives are uploaded to Chromatic for pixel-diffing. - * - * Run against a production build with USE_MOCK_DATA=true for deterministic content: - * USE_MOCK_DATA=true pnpm build && pnpm start - * pnpm test:visual - */ +// Requires a USE_MOCK_DATA=true build for deterministic snapshots (see test:visual:build). -// Each entry covers either a distinct app route or one layout from src/layouts/. -// App-route pages all share BaseLayout; md-slug pages additionally exercise -// their template's layout component. stableSelector defaults to "h1". const pages: Array<{ name: string; path: string; stableSelector?: string }> = [ - // App routes { name: "Homepage", path: "/en/" }, { name: "Wallets", path: "/en/wallets/" }, { name: "Staking", path: "/en/staking/" }, @@ -28,28 +14,21 @@ const pages: Array<{ name: string; path: string; stableSelector?: string }> = [ { name: "Get ETH", path: "/en/get-eth/" }, { name: "Find Wallet", path: "/en/wallets/find-wallet/" }, - // src/layouts/ coverage (one representative per layout) - // StaticLayout - { name: "Bridges", path: "/en/bridges/" }, - // DocsLayout + // One representative per src/layouts/ layout — keeps coverage without per-page duplication. + { name: "Bridges", path: "/en/bridges/" }, // StaticLayout { name: "Docs - Smart Contracts", path: "/en/developers/docs/smart-contracts/", stableSelector: "article#main-content", - }, - // TutorialLayout + }, // DocsLayout { name: "Tutorial - Hello World", path: "/en/developers/tutorials/hello-world-smart-contract/", - }, - // md/StakingLayout - { name: "Staking - Solo", path: "/en/staking/solo/" }, - // md/RoadmapLayout - { name: "Roadmap - Security", path: "/en/roadmap/security/" }, - // md/UpgradeLayout - { name: "Roadmap - Merge", path: "/en/roadmap/merge/" }, - // md/UseCasesLayout (ContentLayout is covered transitively by any md layout) - { name: "DeFi", path: "/en/defi/" }, + }, // TutorialLayout + { name: "Staking - Solo", path: "/en/staking/solo/" }, // md/StakingLayout + { name: "Roadmap - Security", path: "/en/roadmap/security/" }, // md/RoadmapLayout + { name: "Roadmap - Merge", path: "/en/roadmap/merge/" }, // md/UpgradeLayout + { name: "DeFi", path: "/en/defi/" }, // md/UseCasesLayout ] test.describe("Page Visual Tests", () => { From 1b7db865ee3ee09f14ab2a7cce41b83c7039c264 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 17:02:18 +0200 Subject: [PATCH 11/31] fix(chromatic): delegate test:visual:build to pnpm build for webpack parity --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a02aecbcf0a..1a912743de2 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "test:e2e:report": "playwright show-report tests/__report__", "test:visual": "playwright test --project=chromatic-desktop --project=chromatic-tablet --project=chromatic-mobile", "test:visual:desktop": "playwright test --project=chromatic-desktop", - "test:visual:build": "USE_MOCK_DATA=true NEXT_PUBLIC_BUILD_LOCALES=en next build", + "test:visual:build": "USE_MOCK_DATA=true NEXT_PUBLIC_BUILD_LOCALES=en pnpm build", "trigger:dev": "trigger dev --env-file src/data-layer/.env.local", "trigger:deploy": "trigger deploy --env-file src/data-layer/.env.local" }, From f03561b0f3e1ae667e64c86cd3fc6fdc5011a8bd Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 17:22:52 +0200 Subject: [PATCH 12/31] chore(deps): regenerate pnpm-lock.yaml after dev merge The previous merge of origin/dev preferred dev's lockfile, which dropped @chromatic-com/playwright added by this branch. Regenerated to restore the missing entry and unblock unit-tests CI. --- pnpm-lock.yaml | 572 ++----------------------------------------------- 1 file changed, 12 insertions(+), 560 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d05e86a9718..4330760fc47 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -246,7 +246,7 @@ importers: version: 0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) '@chromatic-com/storybook': specifier: 5.1.1 - version: 5.1.1(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) + version: 5.1.1(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) '@google/genai': specifier: ^1.46.0 version: 1.46.0(@modelcontextprotocol/sdk@1.29.0(zod@3.25.76))(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -306,7 +306,7 @@ importers: version: 7.18.0(eslint@8.57.1)(typescript@5.8.3) chromatic: specifier: 16.0.0 - version: 16.0.0(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)) + version: 16.0.0(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) decompress: specifier: ^4.2.1 version: 4.2.1 @@ -2538,9 +2538,6 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.11': - resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} @@ -2588,12 +2585,6 @@ packages: '@types/react': '>=16' react: ^19.2.4 - '@mdx-js/react@3.1.1': - resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==} - peerDependencies: - '@types/react': '>=16' - react: ^19.2.4 - '@metamask/eth-json-rpc-provider@1.0.1': resolution: {integrity: sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==} engines: {node: '>=14.0.0'} @@ -4678,13 +4669,6 @@ packages: '@storybook/global@5.0.0': resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} - '@storybook/icons@1.6.0': - resolution: {integrity: sha512-hcFZIjW8yQz8O8//2WTIXylm5Xsgc+lW9ISLgUk1xGmptIJQRdlhVIXCpSyLrQaaRiyhQRaVg7l3BD9S216BHw==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: ^19.2.4 - react-dom: ^19.2.4 - '@storybook/icons@2.0.1': resolution: {integrity: sha512-/smVjw88yK3CKsiuR71vNgWQ9+NuY2L+e8X7IMrFjexjm6ZR8ULrV2DRkTA61aV6ryefslzHEGDInGpnNeIocg==} peerDependencies: @@ -5704,12 +5688,6 @@ packages: peerDependencies: acorn: ^8 - acorn-import-phases@1.0.4: - resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} - engines: {node: '>=10.13.0'} - peerDependencies: - acorn: ^8.14.0 - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -5773,9 +5751,6 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - algoliasearch@5.25.0: resolution: {integrity: sha512-n73BVorL4HIwKlfJKb4SEzAYkR3Buwfwbh+MYxg2mloFph2fFGV58E90QTzdbfzWrLn4HE5Czx/WTjI8fcHaMg==} engines: {node: '>= 14.0.0'} @@ -6031,9 +6006,6 @@ packages: brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - brace-expansion@1.1.14: - resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} @@ -7021,9 +6993,6 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - es-module-lexer@2.0.0: - resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} - es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -7384,9 +7353,6 @@ packages: fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-parser@5.2.5: resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} hasBin: true @@ -7492,13 +7458,6 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} - fork-ts-checker-webpack-plugin@8.0.0: - resolution: {integrity: sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==} - engines: {node: '>=12.13.0', yarn: '>=1.0.0'} - peerDependencies: - typescript: '>3.6.0' - webpack: ^5.11.0 - fork-ts-checker-webpack-plugin@9.1.0: resolution: {integrity: sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==} engines: {node: '>=14.21.3'} @@ -7821,18 +7780,6 @@ packages: webpack: optional: true - html-webpack-plugin@5.6.6: - resolution: {integrity: sha512-bLjW01UTrvoWTJQL5LsMRo1SypHW80FTm12OJRSnr3v6YHNhfe+1r0MYUZJMACxnCHURVnBWRwAsWs2yPU9Ezw==} - engines: {node: '>=10.13.0'} - peerDependencies: - '@rspack/core': 0.x || 1.x - webpack: ^5.20.0 - peerDependenciesMeta: - '@rspack/core': - optional: true - webpack: - optional: true - htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} @@ -8257,10 +8204,6 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsdoc-type-pratt-parser@4.8.0: - resolution: {integrity: sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==} - engines: {node: '>=12.0.0'} - jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} @@ -8469,10 +8412,6 @@ packages: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} - loader-runner@4.3.1: - resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} - engines: {node: '>=6.11.5'} - loader-utils@2.0.4: resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} engines: {node: '>=8.9.0'} @@ -8857,9 +8796,6 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -9763,11 +9699,6 @@ packages: peerDependencies: react: ^19.2.4 - react-dom@19.2.5: - resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} - peerDependencies: - react: ^19.2.4 - react-emoji-render@2.0.1: resolution: {integrity: sha512-SKtsdwgEf2BFNiE9y4UBFZBWjkRcyWmhMprVly52+J77/zxThcfaQ3sCA0+2LtGJIRMpm4DGWSvyLg72fd1rXQ==} peerDependencies: @@ -9864,10 +9795,6 @@ packages: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} - react@19.2.5: - resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} - engines: {node: '>=0.10.0'} - readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -10144,10 +10071,6 @@ packages: resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} engines: {node: '>= 10.13.0'} - schema-utils@4.3.3: - resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} - engines: {node: '>= 10.13.0'} - search-insights@2.17.3: resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==} @@ -10639,32 +10562,11 @@ packages: uglify-js: optional: true - terser-webpack-plugin@5.4.0: - resolution: {integrity: sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@swc/core': '*' - esbuild: '*' - uglify-js: '*' - webpack: ^5.1.0 - peerDependenciesMeta: - '@swc/core': - optional: true - esbuild: - optional: true - uglify-js: - optional: true - terser@5.40.0: resolution: {integrity: sha512-cfeKl/jjwSR5ar7d0FGmave9hFGJT8obyo0z+CrQOylLDbk7X81nPU6vq9VORa5jU30SkDnT2FXjLbR8HLP+xA==} engines: {node: '>=10'} hasBin: true - terser@5.46.1: - resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} - engines: {node: '>=10'} - hasBin: true - text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -11223,10 +11125,6 @@ packages: resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} engines: {node: '>=10.13.0'} - watchpack@2.5.1: - resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} - engines: {node: '>=10.13.0'} - web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} @@ -11258,23 +11156,9 @@ packages: resolution: {integrity: sha512-ykKKus8lqlgXX/1WjudpIEjqsafjOTcOJqxnAbMLAu/KCsDCJ6GBtvscewvTkrn24HsnvFwrSCbenFrhtcCsAA==} engines: {node: '>=10.13.0'} - webpack-sources@3.3.4: - resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} - engines: {node: '>=10.13.0'} - webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack@5.106.2: - resolution: {integrity: sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - webpack@5.99.9: resolution: {integrity: sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==} engines: {node: '>=10.13.0'} @@ -11473,11 +11357,6 @@ packages: engines: {node: '>= 14.6'} hasBin: true - yaml@2.8.3: - resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} - engines: {node: '>= 14.6'} - hasBin: true - yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -13980,16 +13859,12 @@ snapshots: '@bugsnag/cuid@3.2.1': {} - '@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)': + '@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)': dependencies: '@chromaui/rrweb-snapshot': 2.0.0-alpha.18-noAbsolute '@playwright/test': 1.53.1 - '@segment/analytics-node': 1.3.0 - '@storybook/addon-essentials': 8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/csf': 0.1.13 - '@storybook/manager-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/server-webpack5': 8.5.8(@swc/core@1.15.24)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) + '@segment/analytics-node': 2.1.3 + storybook: 10.2.13(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 transitivePeerDependencies: - '@testing-library/dom' @@ -14000,10 +13875,10 @@ snapshots: - react-dom - utf-8-validate - '@chromatic-com/storybook@5.1.1(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': + '@chromatic-com/storybook@5.1.1(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: '@neoconfetti/react': 1.0.0 - chromatic: 13.3.5(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)) + chromatic: 13.3.5(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) filesize: 10.1.6 jsonfile: 6.1.0 storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) @@ -14015,7 +13890,6 @@ snapshots: '@chromaui/rrweb-snapshot@2.0.0-alpha.18-noAbsolute': dependencies: postcss: 8.5.10 - optional: true '@clack/core@0.5.0': dependencies: @@ -14705,12 +14579,6 @@ snapshots: '@jridgewell/set-array@1.2.1': {} - '@jridgewell/source-map@0.3.11': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - optional: true - '@jridgewell/source-map@0.3.6': dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -14787,13 +14655,6 @@ snapshots: '@types/react': 19.2.14 react: 19.2.4 - '@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@types/mdx': 2.0.13 - '@types/react': 19.2.14 - react: 19.2.5 - optional: true - '@metamask/eth-json-rpc-provider@1.0.1': dependencies: '@metamask/json-rpc-engine': 7.3.3 @@ -17430,32 +17291,6 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/addon-actions@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - '@types/uuid': 9.0.8 - dequal: 2.0.3 - polished: 4.3.1 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - uuid: 9.0.1 - optional: true - - '@storybook/addon-backgrounds@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - memoizerific: 1.11.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - - '@storybook/addon-controls@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - dequal: 2.0.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - '@storybook/addon-docs@10.3.3(@types/react@19.2.14)(esbuild@0.25.12)(rollup@4.46.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12))': dependencies: '@mdx-js/react': 3.1.0(@types/react@19.2.14)(react@19.2.4) @@ -17473,43 +17308,6 @@ snapshots: - vite - webpack - '@storybook/addon-docs@8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.5) - '@storybook/blocks': 8.5.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/csf-plugin': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/react-dom-shim': 8.5.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - transitivePeerDependencies: - - '@types/react' - optional: true - - '@storybook/addon-essentials@8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/addon-actions': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-backgrounds': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-controls': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-docs': 8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-highlight': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-measure': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-outline': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-toolbars': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-viewport': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - transitivePeerDependencies: - - '@types/react' - optional: true - - '@storybook/addon-highlight@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/addon-links@10.3.3(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: '@storybook/global': 5.0.0 @@ -17522,28 +17320,6 @@ snapshots: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 - '@storybook/addon-toolbars@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - - '@storybook/addon-viewport@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - memoizerific: 1.11.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - - '@storybook/blocks@8.5.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/csf': 0.1.12 - '@storybook/icons': 1.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optionalDependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - optional: true - '@storybook/builder-webpack5@10.3.3(@swc/core@1.15.24)(esbuild@0.25.12)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(typescript@5.8.3)': dependencies: '@storybook/core-webpack': 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) @@ -17571,80 +17347,11 @@ snapshots: - uglify-js - webpack-cli - '@storybook/builder-webpack5@8.5.8(@swc/core@1.15.24)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': - dependencies: - '@storybook/core-webpack': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@types/semver': 7.7.1 - browser-assert: 1.2.1 - case-sensitive-paths-webpack-plugin: 2.4.0 - cjs-module-lexer: 1.4.3 - constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - es-module-lexer: 1.7.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - html-webpack-plugin: 5.6.6(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - magic-string: 0.30.21 - path-browserify: 1.0.1 - process: 0.11.10 - semver: 7.7.4 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - style-loader: 3.3.4(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - terser-webpack-plugin: 5.4.0(@swc/core@1.15.24)(esbuild@0.25.12)(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - ts-dedent: 2.2.0 - url: 0.11.4 - util: 0.12.5 - util-deprecate: 1.0.2 - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - webpack-dev-middleware: 6.1.3(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - webpack-hot-middleware: 2.26.1 - webpack-virtual-modules: 0.6.2 - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - '@rspack/core' - - '@swc/core' - - esbuild - - uglify-js - - webpack-cli - optional: true - - '@storybook/components@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/core-webpack@10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 - '@storybook/core-webpack@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - - '@storybook/core@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)': - dependencies: - '@storybook/csf': 0.1.12 - better-opn: 3.0.2 - browser-assert: 1.2.1 - esbuild: 0.25.12 - esbuild-register: 3.6.0(esbuild@0.25.12) - jsdoc-type-pratt-parser: 4.8.0 - process: 0.11.10 - recast: 0.23.11 - semver: 7.7.4 - util: 0.12.5 - ws: 8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - prettier: 3.5.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - optional: true - '@storybook/csf-plugin@10.3.3(esbuild@0.25.12)(rollup@4.46.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) @@ -17656,22 +17363,11 @@ snapshots: '@storybook/global@5.0.0': {} - '@storybook/icons@1.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - optional: true - '@storybook/icons@2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/manager-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/nextjs@10.3.3(@swc/core@1.15.24)(babel-plugin-macros@3.1.0)(esbuild@0.25.12)(next@16.2.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12))': dependencies: '@babel/core': 7.29.0 @@ -17755,22 +17451,6 @@ snapshots: - uglify-js - webpack-cli - '@storybook/preset-server-webpack@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/core-webpack': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/global': 5.0.0 - '@storybook/server': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - safe-identifier: 0.4.2 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - yaml-loader: 0.8.1 - optional: true - - '@storybook/preview-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12))': dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -17791,13 +17471,6 @@ snapshots: react-dom: 19.2.4(react@19.2.4) storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) - '@storybook/react-dom-shim@8.5.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/react@10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(typescript@5.8.3)': dependencies: '@storybook/global': 5.0.0 @@ -17812,39 +17485,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/server-webpack5@8.5.8(@swc/core@1.15.24)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': - dependencies: - '@storybook/builder-webpack5': 8.5.8(@swc/core@1.15.24)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) - '@storybook/preset-server-webpack': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/server': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - '@rspack/core' - - '@swc/core' - - esbuild - - typescript - - uglify-js - - webpack-cli - optional: true - - '@storybook/server@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/components': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/csf': 0.1.12 - '@storybook/global': 5.0.0 - '@storybook/manager-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/preview-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/theming': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - yaml: 2.8.3 - optional: true - - '@storybook/theming@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 @@ -19367,11 +19007,6 @@ snapshots: dependencies: acorn: 8.16.0 - acorn-import-phases@1.0.4(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - optional: true - acorn-jsx@5.3.2(acorn@8.14.1): dependencies: acorn: 8.14.1 @@ -19405,11 +19040,6 @@ snapshots: optionalDependencies: ajv: 8.17.1 - ajv-formats@2.1.1(ajv@8.18.0): - optionalDependencies: - ajv: 8.18.0 - optional: true - ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -19423,12 +19053,6 @@ snapshots: ajv: 8.17.1 fast-deep-equal: 3.1.3 - ajv-keywords@5.1.0(ajv@8.18.0): - dependencies: - ajv: 8.18.0 - fast-deep-equal: 3.1.3 - optional: true - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -19443,14 +19067,6 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ajv@8.18.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - optional: true - algoliasearch@5.25.0: dependencies: '@algolia/client-abtesting': 5.25.0 @@ -19746,12 +19362,6 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@1.1.14: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - optional: true - brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 @@ -19994,13 +19604,13 @@ snapshots: chownr@3.0.0: {} - chromatic@13.3.5(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)): + chromatic@13.3.5(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)): optionalDependencies: - '@chromatic-com/playwright': 0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10) + '@chromatic-com/playwright': 0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) - chromatic@16.0.0(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)): + chromatic@16.0.0(@chromatic-com/playwright@0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)): optionalDependencies: - '@chromatic-com/playwright': 0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10) + '@chromatic-com/playwright': 0.13.1(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) chrome-trace-event@1.0.4: {} @@ -20244,20 +19854,6 @@ snapshots: randombytes: 2.1.0 randomfill: 1.0.4 - css-loader@6.11.0(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - icss-utils: 5.1.0(postcss@8.5.4) - postcss: 8.5.4 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.4) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.4) - postcss-modules-scope: 3.2.1(postcss@8.5.4) - postcss-modules-values: 4.0.0(postcss@8.5.4) - postcss-value-parser: 4.2.0 - semver: 7.7.4 - optionalDependencies: - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optional: true - css-loader@6.11.0(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12)): dependencies: icss-utils: 5.1.0(postcss@8.5.4) @@ -20858,9 +20454,6 @@ snapshots: es-module-lexer@1.7.0: {} - es-module-lexer@2.0.0: - optional: true - es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -21402,9 +20995,6 @@ snapshots: fast-uri@3.0.6: {} - fast-uri@3.1.0: - optional: true - fast-xml-parser@5.2.5: dependencies: strnum: 2.1.1 @@ -21509,24 +21099,6 @@ snapshots: dependencies: is-callable: 1.2.7 - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - '@babel/code-frame': 7.29.0 - chalk: 4.1.2 - chokidar: 3.6.0 - cosmiconfig: 7.1.0 - deepmerge: 4.3.1 - fs-extra: 10.1.0 - memfs: 3.5.3 - minimatch: 3.1.5 - node-abort-controller: 3.1.1 - schema-utils: 3.3.0 - semver: 7.7.4 - tapable: 2.3.2 - typescript: 5.8.3 - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optional: true - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12)): dependencies: '@babel/code-frame': 7.27.1 @@ -21936,17 +21508,6 @@ snapshots: optionalDependencies: webpack: 5.99.9(@swc/core@1.15.24)(esbuild@0.25.12) - html-webpack-plugin@5.6.6(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.18.1 - pretty-error: 4.0.0 - tapable: 2.3.2 - optionalDependencies: - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optional: true - htmlparser2@10.1.0: dependencies: domelementtype: 2.3.0 @@ -22352,9 +21913,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsdoc-type-pratt-parser@4.8.0: - optional: true - jsesc@3.0.2: {} jsesc@3.1.0: {} @@ -22556,9 +22114,6 @@ snapshots: loader-runner@4.3.0: {} - loader-runner@4.3.1: - optional: true - loader-utils@2.0.4: dependencies: big.js: 5.2.2 @@ -23233,11 +22788,6 @@ snapshots: dependencies: brace-expansion: 1.1.11 - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.14 - optional: true - minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -24168,12 +23718,6 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 - react-dom@19.2.5(react@19.2.5): - dependencies: - react: 19.2.5 - scheduler: 0.27.0 - optional: true - react-emoji-render@2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: classnames: 2.5.1 @@ -24277,9 +23821,6 @@ snapshots: react@19.2.4: {} - react@19.2.5: - optional: true - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -24673,14 +24214,6 @@ snapshots: ajv-formats: 2.1.1(ajv@8.17.1) ajv-keywords: 5.1.0(ajv@8.17.1) - schema-utils@4.3.3: - dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.18.0 - ajv-formats: 2.1.1(ajv@8.18.0) - ajv-keywords: 5.1.0(ajv@8.18.0) - optional: true - search-insights@2.17.3: {} section-matter@1.0.0: @@ -25019,7 +24552,7 @@ snapshots: recast: 0.23.11 semver: 7.7.4 use-sync-external-store: 1.5.0(react@19.2.4) - ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: prettier: 3.5.3 transitivePeerDependencies: @@ -25186,11 +24719,6 @@ snapshots: strnum@2.1.1: {} - style-loader@3.3.4(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optional: true - style-loader@3.3.4(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12)): dependencies: webpack: 5.99.9(@swc/core@1.15.24)(esbuild@0.25.12) @@ -25322,18 +24850,6 @@ snapshots: '@swc/core': 1.15.24 esbuild: 0.25.12 - terser-webpack-plugin@5.4.0(@swc/core@1.15.24)(esbuild@0.25.12)(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - terser: 5.46.1 - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optionalDependencies: - '@swc/core': 1.15.24 - esbuild: 0.25.12 - optional: true - terser@5.40.0: dependencies: '@jridgewell/source-map': 0.3.6 @@ -25341,14 +24857,6 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - terser@5.46.1: - dependencies: - '@jridgewell/source-map': 0.3.11 - acorn: 8.16.0 - commander: 2.20.3 - source-map-support: 0.5.21 - optional: true - text-table@0.2.0: {} thread-stream@0.15.2: @@ -26041,12 +25549,6 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - watchpack@2.5.1: - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - optional: true - web-streams-polyfill@3.3.3: {} webextension-polyfill@0.10.0: {} @@ -26072,17 +25574,6 @@ snapshots: - bufferutil - utf-8-validate - webpack-dev-middleware@6.1.3(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - colorette: 2.0.20 - memfs: 3.5.3 - mime-types: 2.1.35 - range-parser: 1.2.1 - schema-utils: 4.3.2 - optionalDependencies: - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optional: true - webpack-dev-middleware@6.1.3(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12)): dependencies: colorette: 2.0.20 @@ -26101,43 +25592,8 @@ snapshots: webpack-sources@3.3.2: {} - webpack-sources@3.3.4: - optional: true - webpack-virtual-modules@0.6.2: {} - webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.16.0 - acorn-import-phases: 1.0.4(acorn@8.16.0) - browserslist: 4.28.2 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.20.1 - es-module-lexer: 2.0.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - loader-runner: 4.3.1 - mime-db: 1.54.0 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.2 - terser-webpack-plugin: 5.4.0(@swc/core@1.15.24)(esbuild@0.25.12)(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - watchpack: 2.5.1 - webpack-sources: 3.3.4 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - optional: true - webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12): dependencies: '@types/eslint-scope': 3.7.7 @@ -26276,7 +25732,6 @@ snapshots: optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 - optional: true wsl-utils@0.1.0: dependencies: @@ -26325,9 +25780,6 @@ snapshots: yaml@2.8.0: {} - yaml@2.8.3: - optional: true - yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 From 4cfc51ba16d5a73deca4d4a06cf67b26de9c0931 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 17:26:20 +0200 Subject: [PATCH 13/31] fix(playwright): only start webServer for chromatic visual tests The webServer block ran pnpm start for every project, breaking unit tests in CI which don't need (or have) a production build. Gate it on chromatic project args so unit and e2e runs skip it. --- playwright.config.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 0cdb9c904de..78fc0cee322 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -6,6 +6,8 @@ import { defineConfig, devices } from "@playwright/test" dotenv.config({ path: path.resolve(__dirname, ".env.local") }) +const needsWebServer = process.argv.some((arg) => arg.includes("chromatic")) + export default defineConfig({ testDir: "./tests", outputDir: "./tests/__results__", @@ -110,9 +112,11 @@ export default defineConfig({ }, ], - webServer: { - command: "pnpm start", - port: 3000, - reuseExistingServer: true, - }, + webServer: needsWebServer + ? { + command: "pnpm start", + port: 3000, + reuseExistingServer: true, + } + : undefined, }) From da217ee1e9f8fe4ce76f94da0b3d13074210a8ba Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 17:38:02 +0200 Subject: [PATCH 14/31] chore(playwright): extract visual tests into dedicated config --- package.json | 4 +-- playwright.config.ts | 52 +------------------------------------ playwright.visual.config.ts | 51 ++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 53 deletions(-) create mode 100644 playwright.visual.config.ts diff --git a/package.json b/package.json index df1424d47d2..fad2991f482 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,8 @@ "test:e2e:ui": "playwright test --project=e2e --ui", "test:e2e:debug": "playwright test --project=e2e --debug", "test:e2e:report": "playwright show-report tests/__report__", - "test:visual": "playwright test --project=chromatic-desktop --project=chromatic-tablet --project=chromatic-mobile", - "test:visual:desktop": "playwright test --project=chromatic-desktop", + "test:visual": "playwright test --config playwright.visual.config.ts", + "test:visual:desktop": "playwright test --config playwright.visual.config.ts --project=chromatic-desktop", "test:visual:build": "USE_MOCK_DATA=true NEXT_PUBLIC_BUILD_LOCALES=en pnpm build", "trigger:dev": "trigger dev --env-file src/data-layer/.env.local", "trigger:deploy": "trigger deploy --env-file src/data-layer/.env.local" diff --git a/playwright.config.ts b/playwright.config.ts index 78fc0cee322..02aaa24c477 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,14 +1,11 @@ import path from "path" import dotenv from "dotenv" -import type { ChromaticConfig } from "@chromatic-com/playwright" import { defineConfig, devices } from "@playwright/test" dotenv.config({ path: path.resolve(__dirname, ".env.local") }) -const needsWebServer = process.argv.some((arg) => arg.includes("chromatic")) - -export default defineConfig({ +export default defineConfig({ testDir: "./tests", outputDir: "./tests/__results__", fullyParallel: true, @@ -71,52 +68,5 @@ export default defineConfig({ testDir: "./tests/unit", use: {}, }, - - // ───────────────────────────────────────────────────────────────────────── - // Chromatic visual tests - Full-page snapshots at 3 viewport sizes - // ───────────────────────────────────────────────────────────────────────── - { - name: "chromatic-desktop", - testDir: "./tests/visual", - outputDir: "./test-results", - use: { - ...devices["Desktop Chrome"], - // 1024 (Tailwind `lg`) keeps full-page snapshots under Chromatic's - // 25M pixel limit on our longest pages. - viewport: { width: 1024, height: 720 }, - disableAutoSnapshot: true, - assetDomains: ["s3-dcl1.ethquokkaops.io"], - }, - }, - { - name: "chromatic-tablet", - testDir: "./tests/visual", - outputDir: "./test-results", - use: { - ...devices["Desktop Chrome"], - viewport: { width: 768, height: 1024 }, - disableAutoSnapshot: true, - assetDomains: ["s3-dcl1.ethquokkaops.io"], - }, - }, - { - name: "chromatic-mobile", - testDir: "./tests/visual", - outputDir: "./test-results", - use: { - ...devices["Desktop Chrome"], - viewport: { width: 375, height: 812 }, - disableAutoSnapshot: true, - assetDomains: ["s3-dcl1.ethquokkaops.io"], - }, - }, ], - - webServer: needsWebServer - ? { - command: "pnpm start", - port: 3000, - reuseExistingServer: true, - } - : undefined, }) diff --git a/playwright.visual.config.ts b/playwright.visual.config.ts new file mode 100644 index 00000000000..ad8195b18bc --- /dev/null +++ b/playwright.visual.config.ts @@ -0,0 +1,51 @@ +import type { ChromaticConfig } from "@chromatic-com/playwright" +import { defineConfig, devices } from "@playwright/test" + +import baseConfig from "./playwright.config" + +export default defineConfig({ + ...baseConfig, + + projects: [ + { + name: "chromatic-desktop", + testDir: "./tests/visual", + outputDir: "./test-results", + use: { + ...devices["Desktop Chrome"], + // 1024 (Tailwind `lg`) keeps full-page snapshots under Chromatic's 25M pixel limit on our longest pages. + viewport: { width: 1024, height: 720 }, + disableAutoSnapshot: true, + assetDomains: ["s3-dcl1.ethquokkaops.io"], + }, + }, + { + name: "chromatic-tablet", + testDir: "./tests/visual", + outputDir: "./test-results", + use: { + ...devices["Desktop Chrome"], + viewport: { width: 768, height: 1024 }, + disableAutoSnapshot: true, + assetDomains: ["s3-dcl1.ethquokkaops.io"], + }, + }, + { + name: "chromatic-mobile", + testDir: "./tests/visual", + outputDir: "./test-results", + use: { + ...devices["Desktop Chrome"], + viewport: { width: 375, height: 812 }, + disableAutoSnapshot: true, + assetDomains: ["s3-dcl1.ethquokkaops.io"], + }, + }, + ], + + webServer: { + command: "pnpm start", + port: 3000, + reuseExistingServer: true, + }, +}) From 7ce97f473b1fd9c80101010bd749ad2c45342f36 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 19:36:06 +0200 Subject: [PATCH 15/31] ci(chromatic): allow manual dispatch for page visual workflow --- .github/workflows/chromatic-pages.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/chromatic-pages.yml b/.github/workflows/chromatic-pages.yml index d1486237c3b..11ee508162f 100644 --- a/.github/workflows/chromatic-pages.yml +++ b/.github/workflows/chromatic-pages.yml @@ -6,6 +6,7 @@ on: pull_request: branches: [master, staging, "test/**"] types: [opened, synchronize, ready_for_review] + workflow_dispatch: jobs: playwright-visual: From e3a610599b53b890ef6665b1a5f4d8bc4548d887 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 19:42:21 +0200 Subject: [PATCH 16/31] ci(chromatic): temporarily include dev branch for test run --- .github/workflows/chromatic-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/chromatic-pages.yml b/.github/workflows/chromatic-pages.yml index 11ee508162f..287f8af09cf 100644 --- a/.github/workflows/chromatic-pages.yml +++ b/.github/workflows/chromatic-pages.yml @@ -4,7 +4,7 @@ name: "Chromatic: Page Visual Tests" on: pull_request: - branches: [master, staging, "test/**"] + branches: [master, staging, dev, "test/**"] types: [opened, synchronize, ready_for_review] workflow_dispatch: From b02ec67ffae49d1bfa4014324948e2b473a5606a Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Wed, 22 Apr 2026 13:33:59 +0200 Subject: [PATCH 17/31] chore(docs): untrack local planning doc Plans under docs/plans/ are local working artifacts and should not be committed alongside feature work. --- ...wright-chromatic-page-visual-tests-plan.md | 288 ------------------ 1 file changed, 288 deletions(-) delete mode 100644 docs/plans/2026-04-15-001-feat-playwright-chromatic-page-visual-tests-plan.md diff --git a/docs/plans/2026-04-15-001-feat-playwright-chromatic-page-visual-tests-plan.md b/docs/plans/2026-04-15-001-feat-playwright-chromatic-page-visual-tests-plan.md deleted file mode 100644 index d7c9ad3c1e2..00000000000 --- a/docs/plans/2026-04-15-001-feat-playwright-chromatic-page-visual-tests-plan.md +++ /dev/null @@ -1,288 +0,0 @@ ---- -title: "feat: Full-page visual regression testing with Playwright + Chromatic" -type: feat -status: active -date: 2026-04-15 ---- - -# Full-Page Visual Regression Testing with Playwright + Chromatic - -## Overview - -Add full-page visual regression testing using Playwright to navigate real Next.js pages and Chromatic to capture, store, and diff DOM snapshots. Pages render against a production build with `USE_MOCK_DATA=true` for deterministic content. This replaces the Storybook-based approach (branch `feat/dual-storybook-page-visual-tests`) which required extensive mocking of server-only APIs. - -## Problem Frame - -During the Tailwind v4 migration, component-level Chromatic snapshots miss regressions that only surface in full-page context — layout spacing, responsive grids, section composition, cross-component interactions. The previous Storybook approach required mocking `next-intl/server`, `next/navigation`, `@/lib/data`, and `@/lib/utils/contributors` at the webpack level, and still fought `experimentalRSC` render pass issues. - -Playwright tests against a real Next.js build avoid all of this — pages render with real SSR, real component tree, real Tailwind output. The only controlled variable is the data layer, which already has a `USE_MOCK_DATA=true` toggle with 27 mock JSON files. - -## Requirements Trace - -- R1. Capture Chromatic visual snapshots of ~10 representative pages covering all layout patterns -- R2. Pages render deterministic content via `USE_MOCK_DATA=true` — no flaky API-dependent diffs -- R3. Test 3 viewport breakpoints per page: mobile (375px), tablet (768px), desktop (1280px) -- R4. Chromatic diffs show visual regressions on PRs via a separate Chromatic project -- R5. CI runs the Playwright visual tests and uploads to Chromatic in parallel with existing workflows -- R6. Existing e2e tests and Storybook Chromatic workflow are unaffected - -## Scope Boundaries - -- Not modifying existing e2e tests or Storybook setup -- Not testing every page — one representative per layout pattern -- Not testing multiple locales in this iteration (English only) -- Not adding interaction-based snapshots (hover states, modals) — just page-load snapshots - -### Deferred to Separate Tasks - -- Multi-locale visual testing (ar, zh): future iteration after English baseline is stable -- Interaction snapshots (modal open, tab switch): separate PR -- Integrating with the existing Storybook Chromatic project: these are intentionally separate projects - -## Context & Research - -### Relevant Code and Patterns - -| File/Pattern | Relevance | -|---|---| -| `playwright.config.ts` | Existing config with 4 e2e + 1 unit project. No `webServer` configured — tests assume external server. `outputDir: "./tests/__results__"` | -| `tests/e2e/` | Existing e2e tests using page object pattern (BasePage → HomePage etc.) | -| `tests/e2e/fixtures/testData.ts` | Centralized test URLs and data | -| `src/data-layer/storage.ts` | `USE_MOCK_DATA` toggle — reads from `src/data-layer/mocks/*.json` instead of Netlify Blobs | -| `src/data-layer/mocks/` | 27 JSON mock files (ETH price, apps, events, RSS, beaconchain, etc.) | -| `.github/workflows/chromatic.yml` | Existing Storybook Chromatic CI (keep separate) | -| `package.json` | `chromatic@16.0.0`, `@playwright/test@^1.52.0` installed. `@chromatic-com/playwright` NOT installed | - -### How Chromatic Playwright Works - -Chromatic Playwright captures **DOM archives** (not screenshots) during test execution via the `@chromatic-com/playwright` fixture. Archives are uploaded to Chromatic which re-renders them in its own browser fleet for pixel-diffing. The flow is: - -1. Build and start Next.js (`next build && next start` with `USE_MOCK_DATA=true`) -2. Run Playwright tests — Chromatic fixture captures DOM archives to `test-results/` -3. Upload archives to Chromatic (`npx chromatic --playwright`) - -### Key Constraints - -- **Chrome-only** for archive capture — Chromatic re-renders in its own multi-browser fleet -- **No TurboSnap** — unlike Storybook, every Playwright test runs on every build -- **`assetDomains`** required for `s3-dcl1.ethquokkaops.io` (app screenshots/media) -- **Separate Chromatic project** — can't mix Storybook and Playwright builds - -## Key Technical Decisions - -- **`USE_MOCK_DATA=true` at build time over runtime API mocking**: The data layer already switches between Netlify Blobs and local JSON files based on this env var. Building Next.js with it set bakes deterministic data into the SSG/ISR output. No need for MSW, `page.route()`, or webpack aliases. The 27 existing mock files are the fixtures. - -- **Production build (`next build && next start`) over dev server**: Production builds are deterministic (SSG/SSR at build time), faster to serve, and match what users actually see. Dev mode has HMR artifacts, slower rendering, and potential hydration differences. - -- **Separate Playwright project in existing config over new config file**: Add `chromatic-*` projects to `playwright.config.ts` alongside existing e2e projects. The `--project` flag isolates them. Avoids config duplication. - -- **3 viewport projects (mobile/tablet/desktop) over per-test viewport overrides**: Playwright projects with different viewport sizes run all tests at each size automatically. Cleaner than `test.use()` overrides in every file. 10 pages × 3 viewports = 30 snapshots per build. - -- **`disableAutoSnapshot: true` with explicit `takeSnapshot` calls**: Gives control over when exactly the snapshot is taken — after `networkidle`, after specific elements are visible. Prevents premature captures during hydration. - -- **Separate CI workflow file over extending existing chromatic.yml**: The Playwright visual test workflow has different steps (build Next.js, start server, run Playwright, upload archives). Keeping it in its own file avoids complicating the Storybook workflow. - -## Open Questions - -### Resolved During Planning - -- **Will `USE_MOCK_DATA=true` cover all data the pages need?** Yes — 27 mock files cover all data-layer getters. The mock layer operates at the storage level (Netlify Blobs → JSON files), so all `src/lib/data/` functions resolve to mock data transparently. No code changes needed. - -- **Does Chromatic Playwright conflict with the existing `@chromatic-com/storybook`?** No — `@chromatic-com/playwright` is a separate package. They coexist. Different Chromatic projects, different project tokens. - -- **Can we reuse the existing `outputDir: "./tests/__results__"`?** No — set the Chromatic projects to use the default `./test-results` so the Chromatic CLI finds them without extra config. Existing e2e tests keep their `./tests/__results__` path. - -- **Does `getGFIs()` (called by `[...slug]` page) need a separate mock?** No — `getGFIs()` is imported from `@/data-layer` which uses `get(KEYS.GFIS)` from the storage layer. `USE_MOCK_DATA=true` reads from `src/data-layer/mocks/fetch-gfis.json`, which exists. The `[...slug]` docs pages are covered by the same mock mechanism as all other data. - -### Deferred to Implementation - -- **Whether some pages need longer `delay` or `resourceArchiveTimeout`**: Pages with lazy-loaded images or client-side data may need tuning. Start with defaults and adjust if snapshots are flaky. - -## Output Structure - -``` -tests/ - visual/ # New directory for Chromatic visual tests - pages.spec.ts # All page-load visual tests in one file -.github/ - workflows/ - chromatic-pages.yml # New CI workflow for Playwright + Chromatic -``` - -## High-Level Technical Design - -> *This illustrates the intended approach and is directional guidance for review, not implementation specification.* - -```mermaid -sequenceDiagram - participant CI as GitHub Actions - participant Build as next build - participant Server as next start - participant PW as Playwright - participant Chromatic as Chromatic Cloud - - CI->>Build: USE_MOCK_DATA=true pnpm build - CI->>Server: pnpm start (port 3000) - CI->>PW: npx playwright test --project=chromatic-* - PW->>Server: Navigate to /en/, /en/wallets/, etc. - Server-->>PW: SSR HTML + hydration - PW->>PW: Wait for networkidle + stable DOM - PW->>PW: takeSnapshot() → DOM archive to test-results/ - PW-->>CI: Test results + archives - CI->>Chromatic: npx chromatic --playwright - Chromatic-->>CI: Visual diff results + build URL -``` - -## Implementation Units - -- [ ] **Unit 1: Install `@chromatic-com/playwright` and configure projects** - - **Goal:** Add the Chromatic Playwright package, create 3 viewport-specific projects in the Playwright config, and add convenience scripts. - - **Requirements:** R3, R5, R6 - - **Dependencies:** None - - **Files:** - - Modify: `package.json` (add `@chromatic-com/playwright` to devDependencies + add scripts) - - Modify: `playwright.config.ts` (add 3 chromatic projects + webServer) - - **Approach:** - - Install `@chromatic-com/playwright` as a dev dependency - - Add 3 new projects to `playwright.config.ts`: `chromatic-desktop` (1280×720), `chromatic-tablet` (768×1024), `chromatic-mobile` (375×812) - - All 3 use Chrome, share `testDir: "./tests/visual"`, and set `disableAutoSnapshot: true` - - Set `assetDomains: ["s3-dcl1.ethquokkaops.io"]` for external images - - Each project gets the default `test-results` outputDir (not `./tests/__results__`) - - Configure `webServer` to auto-start a production build on port 3000 with `USE_MOCK_DATA=true`. Use `reuseExistingServer: true` so it picks up an already-running server. **Caveat:** for deterministic local results, the running server must have been built with `USE_MOCK_DATA=true`. If a regular dev server is running on port 3000, the visual tests will silently use live data. In CI (Unit 3), the workflow builds with the flag explicitly. - - Existing e2e and unit projects are untouched - - Add package.json scripts: - - `test:visual` — runs all 3 chromatic projects - - `test:visual:desktop` — runs desktop only (fast iteration) - - `chromatic:pages` — uploads archives to Chromatic - - **Patterns to follow:** - - Existing project definitions in `playwright.config.ts` - - Existing `test:e2e`, `test:unit` script naming in `package.json` - - **Test scenarios:** - - Happy path: `npx playwright test --project=chromatic-desktop --list` shows the visual test files (once Unit 2 creates them) - - Edge case: existing `pnpm test:e2e` still runs only the 4 original e2e projects (no chromatic tests leak in) - - **Verification:** - - `pnpm test:e2e` passes unchanged - - `npx playwright test --project=chromatic-desktop --list` discovers tests from `tests/visual/` - -- [ ] **Unit 2: Create visual test file for ~10 pages** - - **Goal:** Write a single Playwright test file that navigates to each representative page and takes a Chromatic snapshot. - - **Requirements:** R1, R2 - - **Dependencies:** Unit 1 - - **Files:** - - Create: `tests/visual/pages.spec.ts` - - **Approach:** - - Import `test` and `takeSnapshot` from `@chromatic-com/playwright` - - One `test()` per page, each navigating to the English URL, waiting for `networkidle`, then calling `takeSnapshot()` - - Pages to cover (~10, one per layout pattern): - - `/en/` — homepage (hub/sections) - - `/en/wallets/` — hero + content - - `/en/staking/` — delegated interactive - - `/en/developers/` — hub variant with code examples - - `/en/apps/` — listing/grid - - `/en/community/events/` — events hub with tabs - - `/en/run-a-node/` — content page variant - - `/en/developers/docs/smart-contracts/` — docs layout (sidebar + TOC) - - `/en/history/` — static layout (breadcrumbs + TOC) - - `/en/wallets/find-wallet/` — product table - - The docs and history pages use the `[...slug]` catch-all route which imports `getGFIs()` directly from `@/data-layer`. This is covered by `USE_MOCK_DATA=true` (reads from `src/data-layer/mocks/fetch-gfis.json`), so no additional mocking is needed. - - Each test waits for a page-specific stable element (e.g., `h1`, main content area) before snapshotting to avoid hydration flicker - - Use `test.describe("Page Visual Tests", ...)` to group all tests - - **Patterns to follow:** - - `tests/e2e/home.spec.ts` for navigation and waiting patterns - - `tests/e2e/fixtures/testData.ts` for URL constants - - **Test scenarios:** - - Happy path: each test navigates to the page, waits for stable DOM, and `takeSnapshot()` produces an archive in `test-results/` - - Edge case: pages with lazy-loaded content (homepage swipers, staking comparisons) — wait for a visible stable element, not just `networkidle` - - Error path: if a page throws (e.g., missing mock data), the test fails with a clear error — not a blank snapshot - - **Verification:** - - `USE_MOCK_DATA=true pnpm build && pnpm start` then `npx playwright test --project=chromatic-desktop` runs all 10 tests and produces 10 archives in `test-results/` - -- [ ] **Unit 3: Create CI workflow** - - **Goal:** Add a GitHub Actions workflow that builds Next.js with mock data, runs Playwright visual tests, and uploads to Chromatic. - - **Requirements:** R4, R5, R6 - - **Dependencies:** Unit 2. Also requires the Chromatic project token (`CHROMATIC_PAGES_TOKEN`) to be created in the dashboard and stored as a GitHub Actions secret (see Manual Setup Required). - - **Files:** - - Create: `.github/workflows/chromatic-pages.yml` - - **Approach:** - - Two-job workflow to enable partial archive upload when some tests fail: - - **Job 1: `playwright-visual`** — checkout, install, `USE_MOCK_DATA=true pnpm build`, start server, run visual tests, upload `test-results/` as artifact (with `if: always()` so archives upload even on test failure) - - **Job 2: `chromatic-upload`** — download artifact, run `npx chromatic --playwright` with project token. Uses `if: always()` so Chromatic still receives partial results when some pages fail. - - Use `mcr.microsoft.com/playwright` container image for consistent browser versions - - Trigger on PRs to `dev`, `master`, `staging` - - Separate from existing `chromatic.yml` (Storybook) — both workflows trigger independently on the same events and run in parallel - - `exitZeroOnChanges: true` so visual changes don't block PRs - - **Patterns to follow:** - - Existing `.github/workflows/chromatic.yml` for trigger config and pnpm/node setup - - **Test scenarios:** - - Happy path: workflow runs both jobs, Chromatic build link appears in PR checks - - Edge case: `test-results/` artifact is correctly passed between jobs - - Error path: one page test fails → Job 1 uploads partial archives → Job 2 still runs Chromatic with available snapshots - - **Verification:** - - Workflow YAML is valid - - The two jobs are correctly sequenced (job 2 depends on job 1 via `needs:`) - - Both jobs use `if: always()` for partial-failure resilience - - Existing Storybook chromatic workflow is unchanged - -## System-Wide Impact - -- **Interaction graph:** Adds a new CI workflow and Playwright projects. Does not modify any application code, components, or the data layer. The `USE_MOCK_DATA` env var is already used by `test:unit`. -- **Error propagation:** Visual test failures don't block PRs (`exitZeroOnChanges: true`). Build failures in the Next.js step would fail the workflow — same as any CI build. -- **Unchanged invariants:** Existing e2e tests, Storybook, component Chromatic project, and the production build are completely unaffected. The mock data files in `src/data-layer/mocks/` are read-only in this context. - -## Alternative Approaches Considered - -**Storybook page stories with webpack mocking (implemented, then replaced):** Built on branch `feat/dual-storybook-page-visual-tests`. Required mocking `next-intl/server`, `next/navigation`, `@/lib/data`, and `@/lib/utils/contributors` at the webpack level. Worked but fought `experimentalRSC` render pass issues and required either composition components (divergence risk) or complex webpack aliases. Playwright against a real build avoids all of this. - -**Playwright `page.route()` for API mocking:** Mock individual fetch calls in each test. More flexible but requires maintaining route handlers per page. The `USE_MOCK_DATA` env var is simpler — one flag controls all data at the storage layer. - -**`toHaveScreenshot()` (Playwright's built-in visual comparison):** Standard Playwright visual regression with local baseline images. Works but requires committing baseline PNGs to the repo, manual updates on intentional changes, and doesn't provide the Chromatic review UI (side-by-side diff, accept/reject workflow, team collaboration). - -## Risks & Dependencies - -| Risk | Mitigation | -|------|------------| -| Mock data files become stale as APIs evolve | Mock files are already maintained for `test:unit`. If a new data field is added, unit tests catch it first. | -| DOM archive captures differ between local and CI | Use the official Playwright container image in CI. Run `next build && next start` (not dev mode) in both environments. | -| Some pages lazy-load content after `networkidle` | Use explicit `waitForSelector` on a stable element before `takeSnapshot()`. Tune `delay` and `resourceArchiveTimeout` per page if needed. | -| No TurboSnap — all 30 snapshots run on every PR | 30 snapshots is modest for Chromatic. If it becomes expensive, use `test.skip` to disable specific pages during non-visual PRs. | -| `@chromatic-com/playwright` bundles Storybook 8.x internally | This is used only for the archive packaging step and doesn't conflict with the project's Storybook 10.x. They operate in separate contexts. | -| Chromatic project requires manual dashboard setup | User is already creating the project. Store token as `CHROMATIC_PAGES_TOKEN` GitHub secret. | - -## Manual Setup Required - -1. Create a Playwright-type Chromatic project in the dashboard (named "ethereum-org-website-pages") -2. Store the project token as `CHROMATIC_PAGES_TOKEN` GitHub Actions secret -3. Run the first baseline build locally: `USE_MOCK_DATA=true pnpm build && pnpm start &` then `pnpm test:visual && pnpm chromatic:pages` - -## Sources & References - -- Chromatic Playwright docs: https://www.chromatic.com/docs/playwright/ -- Chromatic Playwright setup: https://www.chromatic.com/docs/playwright/setup/ -- Chromatic Playwright configuration: https://www.chromatic.com/docs/playwright/configure/ -- Chromatic Playwright targeted snapshots: https://www.chromatic.com/docs/playwright/targeted-snapshots/ -- Previous Storybook approach: branch `feat/dual-storybook-page-visual-tests` -- Existing mock data: `src/data-layer/mocks/` (27 JSON files) From 2fe4d2b4c9556a7c997f6dea51601acadd3edea2 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Wed, 22 Apr 2026 14:07:59 +0200 Subject: [PATCH 18/31] test(visual): wait for all data-slot=loading indicators before snapshot --- src/components/ui/skeleton.tsx | 1 + src/components/ui/spinner.tsx | 2 +- tests/visual/pages.spec.ts | 7 +++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx index aa5081dfa27..ee730091884 100644 --- a/src/components/ui/skeleton.tsx +++ b/src/components/ui/skeleton.tsx @@ -27,6 +27,7 @@ type SkeletonProps = React.HTMLAttributes const Skeleton = ({ className, ...props }: SkeletonProps) => { return (
>(({ className, ...props }, ref) => ( -
+
)) diff --git a/tests/visual/pages.spec.ts b/tests/visual/pages.spec.ts index fd13c5ceb42..4b7f4352f92 100644 --- a/tests/visual/pages.spec.ts +++ b/tests/visual/pages.spec.ts @@ -36,10 +36,9 @@ test.describe("Page Visual Tests", () => { test(name, async ({ page }, testInfo) => { await page.goto(path, { waitUntil: "domcontentloaded" }) await page.locator(stableSelector).first().waitFor({ state: "visible" }) - await page - .locator('nav[aria-label="Primary"] .animate-pulse-light') - .first() - .waitFor({ state: "detached" }) + await page.waitForFunction( + () => document.querySelectorAll('[data-slot="loading"]').length === 0 + ) await takeSnapshot(page, testInfo) }) } From 590b7e83514405c9c9ec5b72ec136e7c0bfc7f12 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Wed, 22 Apr 2026 14:41:05 +0200 Subject: [PATCH 19/31] chore(skills): add page-visual-tests skill --- .claude/skills/page-visual-tests/SKILL.md | 76 +++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 .claude/skills/page-visual-tests/SKILL.md diff --git a/.claude/skills/page-visual-tests/SKILL.md b/.claude/skills/page-visual-tests/SKILL.md new file mode 100644 index 00000000000..b7e4668ef70 --- /dev/null +++ b/.claude/skills/page-visual-tests/SKILL.md @@ -0,0 +1,76 @@ +--- +name: page-visual-tests +description: Playwright + Chromatic full-page visual tests for ethereum.org. Trigger on "add a page to the visual suite", "the snapshot keeps changing", "chromatic pages", "chromatic playwright", or edits to `tests/visual/`, `playwright.visual.config.ts`, or `.github/workflows/chromatic-pages.yml`. Skip for Storybook Chromatic (`chromatic.yml`), e2e (`tests/e2e/`), unit (`tests/unit/`). +--- + +# Page Visual Tests (Playwright + Chromatic) + +This repo has two Chromatic projects: Storybook (`chromatic.yml` + `pnpm chromatic`) and **page visual tests** (`chromatic-pages.yml` + `pnpm chromatic:pages`). This skill is the second one only. + +The Playwright suite captures DOM archives (not PNGs) per page × viewport; Chromatic re-renders them in the cloud to diff. A green local `pnpm test:visual` just means archives were produced — the diff happens after upload. + +## Files that matter + +- `playwright.visual.config.ts` — visual-only config (3 viewports + `webServer`) +- `playwright.config.ts` — base (e2e + unit; **no `webServer`**) +- `tests/visual/pages.spec.ts` — page list + readiness pattern +- `.github/workflows/chromatic-pages.yml` — CI +- `src/components/ui/skeleton.tsx`, `src/components/ui/spinner.tsx` — loading primitives +- `package.json` scripts: `test:visual*`, `chromatic:pages` + +## Non-obvious constraints + +**Dual Playwright config.** `webServer` lives only in `playwright.visual.config.ts`. Moving it into the base config breaks `pnpm test:unit` and `pnpm test:e2e` in CI — they try to start Next against a missing `.next` build. + +**Desktop viewport is 1024, not 1280.** Chromatic caps snapshots at `width × height ≤ 25M` px. The tallest tested pages reach ~22.5k px; 1280 overflows, 1024 fits. Measure `document.documentElement.scrollHeight` before raising the viewport or adding a long page. + +**Loading contract: `data-slot="loading"`.** The shared `Skeleton` and `Spinner` primitives carry this attribute. Each test waits until `document.querySelectorAll('[data-slot="loading"]').length === 0` before snapshotting. Any bespoke loader — raw `animate-pulse-light`, a local Skeleton copy, a custom spinner — is invisible to the wait and will silently flake. Fix by routing through the shared primitive or adding `data-slot="loading"` to the bespoke loader's root. + +**Imports come from `@chromatic-com/playwright`, not `@playwright/test`.** The two packages re-export `expect` with skewed types, so `expect(...).toHaveCount(0)` misbehaves — prefer `page.waitForFunction` for the loading wait. + +**Environment.** `USE_MOCK_DATA=true` and `NEXT_PUBLIC_BUILD_LOCALES=en` are required at build and test time. All paths are `/en/...`. + +**Use `domcontentloaded`, not `networkidle`.** Analytics and background fetches keep the network perpetually busy. + +## Canonical test + +```ts +import { takeSnapshot, test } from "@chromatic-com/playwright" + +const pages: Array<{ name: string; path: string; stableSelector?: string }> = [ + { name: "Homepage", path: "/en/" }, + { + name: "Docs - Smart Contracts", + path: "/en/developers/docs/smart-contracts/", + stableSelector: "article#main-content", // DocsLayout renders no
wrapper + }, + // ... +] + +test.describe("Page Visual Tests", () => { + for (const { name, path, stableSelector = "h1" } of pages) { + test(name, async ({ page }, testInfo) => { + await page.goto(path, { waitUntil: "domcontentloaded" }) + await page.locator(stableSelector).first().waitFor({ state: "visible" }) + await page.waitForFunction( + () => document.querySelectorAll('[data-slot="loading"]').length === 0 + ) + await takeSnapshot(page, testInfo) + }) + } +}) +``` + +Override `stableSelector` when there's no visible `h1` above the fold or the layout wraps content unusually. + +## Common situations + +**Adding a page.** Each entry costs three snapshots (one per viewport) against Chromatic's budget, so check whether the page's layout (under `src/layouts/`) is already covered before adding. Scan the page subtree for bespoke loaders — they're the single biggest flake cause — and confirm full-page height stays under the 25M-pixel budget. Local loop: `pnpm test:visual:build` once, then `pnpm test:visual:desktop` for iteration, `pnpm test:visual` for the full sweep. + +**Flaky snapshot.** The culprit is almost always a loader without `data-slot="loading"`. Run with `--trace=on` and inspect the `waitForFunction` step in the trace — if its duration is ~0 ms, the loader isn't being waited on. If dynamic content is drifting, double-check `USE_MOCK_DATA=true` is set in both build and test steps. + +**Pixel-limit error.** Measure the page's full-page height at 1024 px; if it exceeds ~24,400 px, the page needs shortening or removal from the suite. Cropping to viewport was considered and rejected — it defeats the below-the-fold regression coverage that justifies using Playwright over Storybook here. + +**Works locally, fails in CI.** Usually `HOME: /root` missing from the test step — GitHub Actions overrides `HOME` inside containers, and Playwright can no longer find the browsers baked into the `mcr.microsoft.com/playwright` image. Also check that the image tag matches `@playwright/test` in `package.json`. + +Branch: `feat/playwright-chromatic-page-visual-tests` · PR: From 3d2fb3bb1001c3bb493a024f6f26b190e2cfccb3 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Wed, 22 Apr 2026 14:48:31 +0200 Subject: [PATCH 20/31] refactor(visual): drop /en prefix, stableselector, and devices spread --- .claude/skills/page-visual-tests/SKILL.md | 17 +++------ playwright.visual.config.ts | 30 ++++++---------- tests/visual/pages.spec.ts | 43 ++++++++++------------- 3 files changed, 34 insertions(+), 56 deletions(-) diff --git a/.claude/skills/page-visual-tests/SKILL.md b/.claude/skills/page-visual-tests/SKILL.md index b7e4668ef70..a65fba9a0a8 100644 --- a/.claude/skills/page-visual-tests/SKILL.md +++ b/.claude/skills/page-visual-tests/SKILL.md @@ -28,7 +28,7 @@ The Playwright suite captures DOM archives (not PNGs) per page × viewport; Chro **Imports come from `@chromatic-com/playwright`, not `@playwright/test`.** The two packages re-export `expect` with skewed types, so `expect(...).toHaveCount(0)` misbehaves — prefer `page.waitForFunction` for the loading wait. -**Environment.** `USE_MOCK_DATA=true` and `NEXT_PUBLIC_BUILD_LOCALES=en` are required at build and test time. All paths are `/en/...`. +**Environment.** `USE_MOCK_DATA=true` and `NEXT_PUBLIC_BUILD_LOCALES=en` are required at build and test time. Paths in the spec are unprefixed (`/wallets/`, not `/en/wallets/`) because `localePrefix: "as-needed"` serves English at the root — adding `/en` would just trigger a redirect. **Use `domcontentloaded`, not `networkidle`.** Analytics and background fetches keep the network perpetually busy. @@ -37,21 +37,16 @@ The Playwright suite captures DOM archives (not PNGs) per page × viewport; Chro ```ts import { takeSnapshot, test } from "@chromatic-com/playwright" -const pages: Array<{ name: string; path: string; stableSelector?: string }> = [ - { name: "Homepage", path: "/en/" }, - { - name: "Docs - Smart Contracts", - path: "/en/developers/docs/smart-contracts/", - stableSelector: "article#main-content", // DocsLayout renders no
wrapper - }, +const pages: Array<{ name: string; path: string }> = [ + { name: "Homepage", path: "/" }, + { name: "Docs - Smart Contracts", path: "/developers/docs/smart-contracts/" }, // ... ] test.describe("Page Visual Tests", () => { - for (const { name, path, stableSelector = "h1" } of pages) { + for (const { name, path } of pages) { test(name, async ({ page }, testInfo) => { await page.goto(path, { waitUntil: "domcontentloaded" }) - await page.locator(stableSelector).first().waitFor({ state: "visible" }) await page.waitForFunction( () => document.querySelectorAll('[data-slot="loading"]').length === 0 ) @@ -61,8 +56,6 @@ test.describe("Page Visual Tests", () => { }) ``` -Override `stableSelector` when there's no visible `h1` above the fold or the layout wraps content unusually. - ## Common situations **Adding a page.** Each entry costs three snapshots (one per viewport) against Chromatic's budget, so check whether the page's layout (under `src/layouts/`) is already covered before adding. Scan the page subtree for bespoke loaders — they're the single biggest flake cause — and confirm full-page height stays under the 25M-pixel budget. Local loop: `pnpm test:visual:build` once, then `pnpm test:visual:desktop` for iteration, `pnpm test:visual` for the full sweep. diff --git a/playwright.visual.config.ts b/playwright.visual.config.ts index ad8195b18bc..70443e79d62 100644 --- a/playwright.visual.config.ts +++ b/playwright.visual.config.ts @@ -1,8 +1,13 @@ import type { ChromaticConfig } from "@chromatic-com/playwright" -import { defineConfig, devices } from "@playwright/test" +import { defineConfig } from "@playwright/test" import baseConfig from "./playwright.config" +const visualUse: ChromaticConfig = { + disableAutoSnapshot: true, + assetDomains: ["s3-dcl1.ethquokkaops.io"], +} + export default defineConfig({ ...baseConfig, @@ -11,35 +16,20 @@ export default defineConfig({ name: "chromatic-desktop", testDir: "./tests/visual", outputDir: "./test-results", - use: { - ...devices["Desktop Chrome"], - // 1024 (Tailwind `lg`) keeps full-page snapshots under Chromatic's 25M pixel limit on our longest pages. - viewport: { width: 1024, height: 720 }, - disableAutoSnapshot: true, - assetDomains: ["s3-dcl1.ethquokkaops.io"], - }, + // 1024 (Tailwind `lg`) keeps full-page snapshots under Chromatic's 25M pixel limit on our longest pages. + use: { ...visualUse, viewport: { width: 1024, height: 720 } }, }, { name: "chromatic-tablet", testDir: "./tests/visual", outputDir: "./test-results", - use: { - ...devices["Desktop Chrome"], - viewport: { width: 768, height: 1024 }, - disableAutoSnapshot: true, - assetDomains: ["s3-dcl1.ethquokkaops.io"], - }, + use: { ...visualUse, viewport: { width: 768, height: 1024 } }, }, { name: "chromatic-mobile", testDir: "./tests/visual", outputDir: "./test-results", - use: { - ...devices["Desktop Chrome"], - viewport: { width: 375, height: 812 }, - disableAutoSnapshot: true, - assetDomains: ["s3-dcl1.ethquokkaops.io"], - }, + use: { ...visualUse, viewport: { width: 375, height: 812 } }, }, ], diff --git a/tests/visual/pages.spec.ts b/tests/visual/pages.spec.ts index 4b7f4352f92..78b883676ad 100644 --- a/tests/visual/pages.spec.ts +++ b/tests/visual/pages.spec.ts @@ -2,40 +2,35 @@ import { takeSnapshot, test } from "@chromatic-com/playwright" // Requires a USE_MOCK_DATA=true build for deterministic snapshots (see test:visual:build). -const pages: Array<{ name: string; path: string; stableSelector?: string }> = [ - { name: "Homepage", path: "/en/" }, - { name: "Wallets", path: "/en/wallets/" }, - { name: "Staking", path: "/en/staking/" }, - { name: "Developers", path: "/en/developers/" }, - { name: "Apps", path: "/en/apps/" }, - { name: "Community Events", path: "/en/community/events/" }, - { name: "Run a Node", path: "/en/run-a-node/" }, - { name: "History", path: "/en/history/" }, - { name: "Get ETH", path: "/en/get-eth/" }, - { name: "Find Wallet", path: "/en/wallets/find-wallet/" }, +const pages: Array<{ name: string; path: string }> = [ + { name: "Homepage", path: "/" }, + { name: "Wallets", path: "/wallets/" }, + { name: "Staking", path: "/staking/" }, + { name: "Developers", path: "/developers/" }, + { name: "Apps", path: "/apps/" }, + { name: "Community Events", path: "/community/events/" }, + { name: "Run a Node", path: "/run-a-node/" }, + { name: "History", path: "/history/" }, + { name: "Get ETH", path: "/get-eth/" }, + { name: "Find Wallet", path: "/wallets/find-wallet/" }, // One representative per src/layouts/ layout — keeps coverage without per-page duplication. - { name: "Bridges", path: "/en/bridges/" }, // StaticLayout - { - name: "Docs - Smart Contracts", - path: "/en/developers/docs/smart-contracts/", - stableSelector: "article#main-content", - }, // DocsLayout + { name: "Bridges", path: "/bridges/" }, // StaticLayout + { name: "Docs - Smart Contracts", path: "/developers/docs/smart-contracts/" }, // DocsLayout { name: "Tutorial - Hello World", - path: "/en/developers/tutorials/hello-world-smart-contract/", + path: "/developers/tutorials/hello-world-smart-contract/", }, // TutorialLayout - { name: "Staking - Solo", path: "/en/staking/solo/" }, // md/StakingLayout - { name: "Roadmap - Security", path: "/en/roadmap/security/" }, // md/RoadmapLayout - { name: "Roadmap - Merge", path: "/en/roadmap/merge/" }, // md/UpgradeLayout - { name: "DeFi", path: "/en/defi/" }, // md/UseCasesLayout + { name: "Staking - Solo", path: "/staking/solo/" }, // md/StakingLayout + { name: "Roadmap - Security", path: "/roadmap/security/" }, // md/RoadmapLayout + { name: "Roadmap - Merge", path: "/roadmap/merge/" }, // md/UpgradeLayout + { name: "DeFi", path: "/defi/" }, // md/UseCasesLayout ] test.describe("Page Visual Tests", () => { - for (const { name, path, stableSelector = "h1" } of pages) { + for (const { name, path } of pages) { test(name, async ({ page }, testInfo) => { await page.goto(path, { waitUntil: "domcontentloaded" }) - await page.locator(stableSelector).first().waitFor({ state: "visible" }) await page.waitForFunction( () => document.querySelectorAll('[data-slot="loading"]').length === 0 ) From d4eab3e4e6caea12eec4a0384c30255f394db9c5 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Wed, 22 Apr 2026 20:02:25 +0200 Subject: [PATCH 21/31] fix(visual): stabilize dynamic content across snapshots --- .github/workflows/chromatic-pages.yml | 2 + app/[locale]/_components/HomepageLazy.tsx | 3 +- package.json | 2 +- playwright.visual.config.ts | 11 ++- src/components/EthPriceCard.tsx | 114 +++------------------- src/lib/utils/wallets.ts | 10 +- 6 files changed, 34 insertions(+), 108 deletions(-) diff --git a/.github/workflows/chromatic-pages.yml b/.github/workflows/chromatic-pages.yml index 287f8af09cf..1881acb5803 100644 --- a/.github/workflows/chromatic-pages.yml +++ b/.github/workflows/chromatic-pages.yml @@ -36,6 +36,7 @@ jobs: run: pnpm build env: USE_MOCK_DATA: "true" + IS_VISUAL_TEST: "true" NEXT_PUBLIC_BUILD_LOCALES: "en" - name: Run visual tests @@ -43,6 +44,7 @@ jobs: env: HOME: /root USE_MOCK_DATA: "true" + IS_VISUAL_TEST: "true" - name: Upload test results if: always() diff --git a/app/[locale]/_components/HomepageLazy.tsx b/app/[locale]/_components/HomepageLazy.tsx index feba8b27deb..0470011ea78 100644 --- a/app/[locale]/_components/HomepageLazy.tsx +++ b/app/[locale]/_components/HomepageLazy.tsx @@ -13,7 +13,8 @@ const Skeleton = ({ }) => (
) diff --git a/package.json b/package.json index fad2991f482..0b589bd4cb3 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "test:e2e:report": "playwright show-report tests/__report__", "test:visual": "playwright test --config playwright.visual.config.ts", "test:visual:desktop": "playwright test --config playwright.visual.config.ts --project=chromatic-desktop", - "test:visual:build": "USE_MOCK_DATA=true NEXT_PUBLIC_BUILD_LOCALES=en pnpm build", + "test:visual:build": "USE_MOCK_DATA=true IS_VISUAL_TEST=true NEXT_PUBLIC_BUILD_LOCALES=en pnpm build", "trigger:dev": "trigger dev --env-file src/data-layer/.env.local", "trigger:deploy": "trigger deploy --env-file src/data-layer/.env.local" }, diff --git a/playwright.visual.config.ts b/playwright.visual.config.ts index 70443e79d62..88ec54f88f3 100644 --- a/playwright.visual.config.ts +++ b/playwright.visual.config.ts @@ -8,6 +8,11 @@ const visualUse: ChromaticConfig = { assetDomains: ["s3-dcl1.ethquokkaops.io"], } +// Append "Chromatic" to the default UA so `isChromatic()` returns true client-side. +// Several components (QuizWidget, Simulator) use this signal to skip randomization. +const userAgent = + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Chromatic" + export default defineConfig({ ...baseConfig, @@ -17,19 +22,19 @@ export default defineConfig({ testDir: "./tests/visual", outputDir: "./test-results", // 1024 (Tailwind `lg`) keeps full-page snapshots under Chromatic's 25M pixel limit on our longest pages. - use: { ...visualUse, viewport: { width: 1024, height: 720 } }, + use: { ...visualUse, userAgent, viewport: { width: 1024, height: 720 } }, }, { name: "chromatic-tablet", testDir: "./tests/visual", outputDir: "./test-results", - use: { ...visualUse, viewport: { width: 768, height: 1024 } }, + use: { ...visualUse, userAgent, viewport: { width: 768, height: 1024 } }, }, { name: "chromatic-mobile", testDir: "./tests/visual", outputDir: "./test-results", - use: { ...visualUse, viewport: { width: 375, height: 812 } }, + use: { ...visualUse, userAgent, viewport: { width: 375, height: 812 } }, }, ], diff --git a/src/components/EthPriceCard.tsx b/src/components/EthPriceCard.tsx index 0013a162071..5d16bd11f27 100644 --- a/src/components/EthPriceCard.tsx +++ b/src/components/EthPriceCard.tsx @@ -1,101 +1,37 @@ "use client" -import { useEffect, useState } from "react" -import { ArrowDownRight, ArrowUpRight, Info } from "lucide-react" +import { Info } from "lucide-react" import { useLocale } from "next-intl" -import type { LoadingState } from "@/lib/types" - import Tooltip from "@/components/Tooltip" import InlineLink from "@/components/ui/Link" +import { Skeleton } from "@/components/ui/skeleton" import { cn } from "@/lib/utils/cn" import { numberFormat } from "@/lib/utils/numbers" import { Flex } from "./ui/flex" -import { useRtlFlip } from "@/hooks/useRtlFlip" +import { useGasEthPrice } from "@/hooks/useGasEthPrice" import { useTranslation } from "@/hooks/useTranslation" -type EthPriceResponse = { - ethereum: { - usd: string - usd_24h_change: number - } -} - -type EthPriceState = { - currentPriceUSD: string - percentChangeUSD: number -} - const EthPriceCard = ({ className, ...props }: React.HTMLAttributes) => { const locale = useLocale() const { t } = useTranslation() - const [state, setState] = useState>({ - loading: true, - }) - const { twFlipForRtl } = useRtlFlip() - - useEffect(() => { - const fetchData = async () => { - try { - const response = await fetch( - "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd&include_24hr_change=true" - ) - if (!response.ok) throw new Error(response.statusText) - const data: EthPriceResponse = await response.json() - if (data && data.ethereum) { - const currentPriceUSD = data.ethereum.usd - const percentChangeUSD = +data.ethereum.usd_24h_change / 100 - setState({ - loading: false, - data: { currentPriceUSD, percentChangeUSD }, - }) - } - } catch (error: unknown) { - error instanceof Error && console.error(error.message) - setState({ - loading: false, - error, - }) - } - } - fetchData() - }, []) + const { ethPrice } = useGasEthPrice() - const hasError = "error" in state - const hasData = "data" in state + const isLoading = ethPrice === 0 - const formatPrice = (price: string) => + const formatPrice = (price: number) => numberFormat(locale, { style: "currency", currency: "USD", minimumFractionDigits: 2, maximumFractionDigits: 2, - }).format(+price) - - const formatPercentage = (amount: number): string => - numberFormat(locale, { - style: "percent", - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }).format(amount) - - const getPriceString = (): string => { - if (state.loading) return t("loading") - if (hasError) return t("loading-error-refresh") - return formatPrice(state.data.currentPriceUSD) - } - - const price = getPriceString() - - const isNegativeChange = hasData && state.data.percentChangeUSD < 0 - - const change = hasData ? formatPercentage(state.data.percentChangeUSD) : "" + }).format(price) const tooltipContent = (
@@ -109,10 +45,7 @@ const EthPriceCard = ({ return ( -
+ {isLoading ? ( + + ) : ( + formatPrice(ethPrice) )} - > - {price}
- - {/* min-h-[33px] prevents jump when price loads */} - -
- {change} - {isNegativeChange ? ( - - ) : ( - - )} -
-
- ({t("last-24-hrs")}) -
-
) } diff --git a/src/lib/utils/wallets.ts b/src/lib/utils/wallets.ts index 8c8607ab7ca..05f70c70562 100644 --- a/src/lib/utils/wallets.ts +++ b/src/lib/utils/wallets.ts @@ -21,15 +21,21 @@ import type { WalletRow, } from "../types" +// Visual test builds set IS_VISUAL_TEST=true to keep wallet order deterministic +// across runs. Not tied to USE_MOCK_DATA, which is also used by unit tests and +// local dev with mocked storage. +const maybeShuffle = (list: T[]): T[] => + process.env.IS_VISUAL_TEST === "true" ? list : shuffle(list) + export const getSupportedLocaleWallets = (locale: string) => - shuffle( + maybeShuffle( walletsData.filter((wallet) => wallet.languages_supported.includes(locale as WalletLanguage) ) ) export const getNonSupportedLocaleWallets = (locale: string) => - shuffle( + maybeShuffle( walletsData.filter( (wallet) => !wallet.languages_supported.includes(locale as WalletLanguage) ) From 1382533f6e13cb4d6efd79324131ba1b3f67d9fa Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Mon, 27 Apr 2026 13:26:48 +0200 Subject: [PATCH 22/31] fix(visual): wait for ssr:false hydration and image load before snapshot --- tests/visual/pages.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/visual/pages.spec.ts b/tests/visual/pages.spec.ts index 78b883676ad..82025adf908 100644 --- a/tests/visual/pages.spec.ts +++ b/tests/visual/pages.spec.ts @@ -34,6 +34,24 @@ test.describe("Page Visual Tests", () => { await page.waitForFunction( () => document.querySelectorAll('[data-slot="loading"]').length === 0 ) + // FeedbackWidget is dynamic({ ssr: false }); waiting for its button proves + // hydration finished and dynamic chunks landed — same pattern other + // ssr:false components (Emoji/Twemoji) rely on to render. + await page.waitForSelector('[data-testid="feedback-widget-button"]') + // Force every to load now so below-the-fold images + // are present in the full-page snapshot (Chromatic captures the entire + // scroll height, not just the viewport). + await page.evaluate(() => { + for (const img of Array.from(document.images)) { + if (img.loading === "lazy") img.loading = "eager" + } + }) + // Next.js Image's blur placeholder is removed only after the underlying + // finishes loading. Snapshotting earlier captures the inline + // background-image and shows pixelated blur in the diff. + await page.waitForFunction(() => + Array.from(document.images).every((img) => img.complete) + ) await takeSnapshot(page, testInfo) }) } From 1f2458f71d2b7ab6d4976b682d2de09633279f2a Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Mon, 27 Apr 2026 14:31:05 +0200 Subject: [PATCH 23/31] chore(deps): regenerate pnpm-lock.yaml after dev merge --- pnpm-lock.yaml | 936 +++---------------------------------------------- 1 file changed, 58 insertions(+), 878 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99d7893445b..eece8887ddb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -241,9 +241,12 @@ importers: specifier: ^0.8.0 version: 0.8.1 devDependencies: + '@chromatic-com/playwright': + specifier: ^0.13.1 + version: 0.13.2(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) '@chromatic-com/storybook': specifier: 5.1.1 - version: 5.1.1(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) + version: 5.1.1(@chromatic-com/playwright@0.13.2(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) '@google/genai': specifier: ^1.46.0 version: 1.46.0(@modelcontextprotocol/sdk@1.29.0(zod@3.25.76))(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -303,7 +306,7 @@ importers: version: 7.18.0(eslint@8.57.1)(typescript@5.8.3) chromatic: specifier: 16.0.0 - version: 16.0.0(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)) + version: 16.0.0(@chromatic-com/playwright@0.13.2(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) decompress: specifier: ^4.2.1 version: 4.2.1 @@ -1648,8 +1651,8 @@ packages: '@bugsnag/cuid@3.2.1': resolution: {integrity: sha512-zpvN8xQ5rdRWakMd/BcVkdn2F8HKlDSbM3l7duueK590WmI1T0ObTLc1V/1e55r14WNjPd5AJTYX4yPEAFVi+Q==} - '@chromatic-com/playwright@0.12.5': - resolution: {integrity: sha512-KTPunElGUUEu1ks+G41pJB/WXf+1HeYBnvauvDpJfMlICKoZlL3in0gIUoER/La/zXC/YEKL4BeXvq/JnRQvUw==} + '@chromatic-com/playwright@0.13.2': + resolution: {integrity: sha512-QJN8x/w05+gfOYjiy0lBUsYUellkXxZ3l0H2b1iJy/9sMsfs+ZyRSG2u0WUnKk8xQScurOfx/kNA2BFCSbWKyw==} hasBin: true peerDependencies: '@playwright/test': ^1.0.0 @@ -2531,9 +2534,6 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.11': - resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} @@ -2581,12 +2581,6 @@ packages: '@types/react': '>=16' react: ^19.2.4 - '@mdx-js/react@3.1.1': - resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==} - peerDependencies: - '@types/react': '>=16' - react: ^19.2.4 - '@metamask/eth-json-rpc-provider@1.0.1': resolution: {integrity: sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==} engines: {node: '>=14.0.0'} @@ -4066,15 +4060,15 @@ packages: '@scure/bip39@1.6.0': resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} - '@segment/analytics-core@1.4.1': - resolution: {integrity: sha512-kV0Pf33HnthuBOVdYNani21kYyj118Fn+9757bxqoksiXoZlYvBsFq6giNdCsKcTIE1eAMqNDq3xE1VQ0cfsHA==} + '@segment/analytics-core@1.7.0': + resolution: {integrity: sha512-0DHSriS/oAB/2bIgOMv3fFV9/ivp39ibdOTTf+dDOhf+vlciBv0+MHw47k/6PRobbuls27cKkKZAKc4DDC2+gw==} - '@segment/analytics-generic-utils@1.1.1': - resolution: {integrity: sha512-THTIzBPHnvu1HYJU3fARdJ3qIkukO3zDXsmDm+kAeUks5R9CBXOQ6rPChiASVzSmwAIIo5uFIXXnCraojlq/Gw==} + '@segment/analytics-generic-utils@1.2.0': + resolution: {integrity: sha512-DfnW6mW3YQOLlDQQdR89k4EqfHb0g/3XvBXkovH1FstUN93eL1kfW9CsDcVQyH3bAC5ZsFyjA/o/1Q2j0QeoWw==} - '@segment/analytics-node@1.3.0': - resolution: {integrity: sha512-lRLz1WZaDokMoUe299yP5JkInc3OgJuqNNlxb6j0q22umCiq6b5iDo2gRmFn93reirIvJxWIicQsGrHd93q8GQ==} - engines: {node: '>=14'} + '@segment/analytics-node@2.1.3': + resolution: {integrity: sha512-xwMkyXgr7xgPsP0w79nzCwRHYi9jzj9ps4Im7xWGK8AKKE4eox39tMZOdRtpDbvXQlrs9fh64ZC0w/yZZDM/9g==} + engines: {node: '>=18'} '@sentry-internal/browser-utils@10.46.0': resolution: {integrity: sha512-WB1gBT9G13V02ekZ6NpUhoI1aGHV2eNfjEPthkU2bGBvFpQKnstwzjg7waIRGR7cu+YSW2Q6UI6aQLgBeOPD1g==} @@ -4613,41 +4607,11 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@storybook/addon-actions@8.5.8': - resolution: {integrity: sha512-7J0NAz+WDw1NmvmKIh0Qr5cxgVRDPFC5fmngbDNxedk147TkwrgmqOypgEi/SAksHbTWxJclbimoqdcsNtWffA==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-backgrounds@8.5.8': - resolution: {integrity: sha512-TsQFagQ95+d7H3/+qUZKI2B0SEK8iu6CV13cyry9Dm59nn2bBylFrwx4I3xDQUOWMiSF6QIRjCYzxKQ/jJ5OEg==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-controls@8.5.8': - resolution: {integrity: sha512-3iifI8mBGPsiPmV9eAYk+tK9i+xuWhVsa+sXz01xTZ/0yoOREpp972hka86mtCqdDTOJIpzh1LmxvB218OssvQ==} - peerDependencies: - storybook: ^8.5.8 - '@storybook/addon-docs@10.3.3': resolution: {integrity: sha512-trJQTpOtuOEuNv1Rn8X2Sopp5hSPpb0u0soEJ71BZAbxe4d2Y1d/1MYcxBdRKwncum6sCTsnxTpqQ/qvSJKlTQ==} peerDependencies: storybook: ^10.3.3 - '@storybook/addon-docs@8.5.8': - resolution: {integrity: sha512-zKVUqE0UGiq1gZtY2TX57SYB4RIsdlbTDxKW2JZ9HhZGLvZ5Qb7AvdiKTZxfOepGhuw3UcNXH/zCFkFCTJifMw==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-essentials@8.5.8': - resolution: {integrity: sha512-sCNvMZqL6dywnyHuZBrWl4f6QXsvpJHOioL3wJJKaaRMZmctbFmS0u6J8TQjmgZhQfyRzuJuhr1gJg9oeqp6AA==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-highlight@8.5.8': - resolution: {integrity: sha512-kkldtFrY0oQJY/vfNLkV66hVgtp66OO8T68KoZFsmUz4a3iYgzDS8WF+Av2/9jthktFvMchjFr8NKOno9YBGIg==} - peerDependencies: - storybook: ^8.5.8 - '@storybook/addon-links@10.3.3': resolution: {integrity: sha512-tazBHlB+YbU62bde5DWsq0lnxZjcAsPB3YRUpN2hSMfAySsudRingyWrgu5KeOxXhJvKJj0ohjQvGcMx/wgQUA==} peerDependencies: @@ -4657,43 +4621,11 @@ packages: react: optional: true - '@storybook/addon-measure@8.5.8': - resolution: {integrity: sha512-xf84ByTRkFPoNSck6Z5OJ0kXTYAYgmg/0Ke0eCY/CNgwh7lfjYQBrcjuKiYZ6jyRUMLdysXzIfF9/2MeFqLfIg==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-outline@8.5.8': - resolution: {integrity: sha512-NAC9VWZFg2gwvduzJRVAtxPeQfJjB8xfDDgcGjgLOCSQkZDDOmGVdLXf78pykMQKyuu/0YZ989KufAac6kRG5g==} - peerDependencies: - storybook: ^8.5.8 - '@storybook/addon-themes@10.3.3': resolution: {integrity: sha512-6PgH1o7yNnWRVj4lAT1DNcX/eZXKgzjhfmzgWh3oFpPfDDvUzpFxx+MClM5f/ZieIbyQscxEuq8li7+e/F5VEQ==} peerDependencies: storybook: ^10.3.3 - '@storybook/addon-toolbars@8.5.8': - resolution: {integrity: sha512-AfGdMNBp+vOjyiFKlOyUFLIU0kN1QF4PhVBqd0vYkWAk2w9n6a/ZlG0TcJGe7K5+bcvmZDAerYMKbDMSeg9bAw==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/addon-viewport@8.5.8': - resolution: {integrity: sha512-SdoRb4bH99Knj2R+rTcMQQxHrtcIO1GLzTFitAefxBE1OUkq8FNLHMHd0Ip/sCQGLW/5F03U70R2uh7SkhBBYA==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/blocks@8.5.8': - resolution: {integrity: sha512-O6tJDJM83fDm3ZP1+lTf24l7HOTzSRXkkMDD7zB/JHixzlj9p6wI4UQc2lplLadDCa5ya1IwyE7zUDN/0UfC5Q==} - peerDependencies: - react: ^19.2.4 - react-dom: ^19.2.4 - storybook: ^8.5.8 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - '@storybook/builder-webpack5@10.3.3': resolution: {integrity: sha512-A7hop0VXG/06EZ7l2WIuhsrnpiV6NOOcOiVqjYDLplbVelkiiL98LTL+Om87u0n32sAfXWgFk2jIhSc3bbXlsQ==} peerDependencies: @@ -4703,38 +4635,11 @@ packages: typescript: optional: true - '@storybook/builder-webpack5@8.5.8': - resolution: {integrity: sha512-QaBIMyqWX/eQs4laQBXvAW9M/ylk73WljJySPlTl+8PNVuDtHli24oBJXwx5aV1NT53BLsaKAn/vb2QNL4+G1Q==} - peerDependencies: - storybook: ^8.5.8 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@storybook/components@8.5.8': - resolution: {integrity: sha512-PPEMqWPXn7rX+qISaOOv9CDSuuvG538f0+4M5Ppq2LwpjXecgOG5ktqJF0ZqxmTytT+RpEaJmgjGW0dMAKZswA==} - peerDependencies: - storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/core-webpack@10.3.3': resolution: {integrity: sha512-ESRM2k9m1V0qXaqEM+bvtCjv9+gYVE3PMuoNZMyIYNdGA4Pdc2PvQsUrKQNVByVbEGwjt+h0RE6b20bnBkdYsg==} peerDependencies: storybook: ^10.3.3 - '@storybook/core-webpack@8.5.8': - resolution: {integrity: sha512-M2LNQdYp0br8fgKMVtBh7YIo8mQsgALLc4i9PEXRS7wrp+bhvVnA9qhd5xDPzb0Rl4CHYbs4Yvkzo7ZQMibeIQ==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/core@8.5.8': - resolution: {integrity: sha512-OT02DQhkGpBgn5P+nZOZmbzxqubC4liVqbhpjp/HOGi5cOA3+fCJzDJeSDTu+pPh7dZnopC4XnR+5dWjtOJHdA==} - peerDependencies: - prettier: ^2 || ^3 - peerDependenciesMeta: - prettier: - optional: true - '@storybook/csf-plugin@10.3.3': resolution: {integrity: sha512-Utlh7zubm+4iOzBBfzLW4F4vD99UBtl2Do4edlzK2F7krQIcFvR2ontjAE8S1FQVLZAC3WHalCOS+Ch8zf3knA==} peerDependencies: @@ -4753,38 +4658,15 @@ packages: webpack: optional: true - '@storybook/csf-plugin@8.5.8': - resolution: {integrity: sha512-9p+TFutbvtPYEmg14UsvqBDWKP/p/+OkIdi+gkwCMw0yiJF/+7ErMHDB0vr5SpJpU7SFQmfpY2c/LaglEtaniw==} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/csf@0.1.12': - resolution: {integrity: sha512-9/exVhabisyIVL0VxTCxo01Tdm8wefIXKXfltAPTSr8cbLn5JAxGQ6QV3mjdecLGEOucfoVhAKtJfVHxEK1iqw==} - - '@storybook/csf@0.1.13': - resolution: {integrity: sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q==} - '@storybook/global@5.0.0': resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} - '@storybook/icons@1.6.0': - resolution: {integrity: sha512-hcFZIjW8yQz8O8//2WTIXylm5Xsgc+lW9ISLgUk1xGmptIJQRdlhVIXCpSyLrQaaRiyhQRaVg7l3BD9S216BHw==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: ^19.2.4 - react-dom: ^19.2.4 - '@storybook/icons@2.0.1': resolution: {integrity: sha512-/smVjw88yK3CKsiuR71vNgWQ9+NuY2L+e8X7IMrFjexjm6ZR8ULrV2DRkTA61aV6ryefslzHEGDInGpnNeIocg==} peerDependencies: react: ^19.2.4 react-dom: ^19.2.4 - '@storybook/manager-api@8.5.8': - resolution: {integrity: sha512-ik3yikvYxAJMDFg0s3Pm7hZWucAlkFaaO7e2RlfOctaJFdaEi3evR4RS7GdmS38uKBEk31RC7x+nnIJkqEC59A==} - peerDependencies: - storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/nextjs@10.3.3': resolution: {integrity: sha512-/7iNyht4P0QDdSXDIHswgaNfWTGMI3OsQ+blLXlos4AvQMPWvGpDDtWg571+qD+6tKzdUwog+SYt7lvWT69SxA==} peerDependencies: @@ -4811,17 +4693,6 @@ packages: typescript: optional: true - '@storybook/preset-server-webpack@8.5.8': - resolution: {integrity: sha512-0QA23bmhchmec6zI0JzoXWIA723n8XhEtJndUQDS96cTyDGyb3AuedNgwu5xQw9Zv+EJZjO84uGcNYinPEnmKA==} - engines: {node: '>=18.0.0'} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/preview-api@8.5.8': - resolution: {integrity: sha512-HJoz2o28VVprnU5OG6JO6CHrD3ah6qVPWixbnmyUKd0hOYF5dayK5ptmeLyUpYX56Eb2KoYcuVaeQqAby4RkNw==} - peerDependencies: - storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0': resolution: {integrity: sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==} peerDependencies: @@ -4835,13 +4706,6 @@ packages: react-dom: ^19.2.4 storybook: ^10.3.3 - '@storybook/react-dom-shim@8.5.8': - resolution: {integrity: sha512-UT/kGJHPW+HLNCTmI1rV1to+dUZuXKUTaRv2wZ2BUq2/gjIuePyqQZYVQeb0LkZbuH2uviLrPfXpS5d3/RSUJw==} - peerDependencies: - react: ^19.2.4 - react-dom: ^19.2.4 - storybook: ^8.5.8 - '@storybook/react@10.3.3': resolution: {integrity: sha512-cGG5TbR8Tdx9zwlpsWyBEfWrejm5iWdYF26EwIhwuKq9GFUTAVrQzo0Rs7Tqc3ZyVhRS/YfsRiWSEH+zmq2JiQ==} peerDependencies: @@ -4853,23 +4717,6 @@ packages: typescript: optional: true - '@storybook/server-webpack5@8.5.8': - resolution: {integrity: sha512-bdRxp0kUGBstDdCEIfJEbsmM7vvyBES4Hjmj0jXcOefQYic5QTWTiDMrHgWPp8XWGjIoO+wOfWm2IXPP5Uceog==} - engines: {node: '>=18.0.0'} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/server@8.5.8': - resolution: {integrity: sha512-DB3IR7CCUklTXtytbOOX7Vig1h9ohQ3BPauvf7WlYXLv4JlkO54oTu37rL0wbqgmmh4FOF41ZSX8z4h4w41How==} - engines: {node: '>=18.0.0'} - peerDependencies: - storybook: ^8.5.8 - - '@storybook/theming@8.5.8': - resolution: {integrity: sha512-/Rm6BV778sCT+3Ok861VYmw9BlEV5zcCq2zg5TOVuk8HqZw7H7VHtubVsjukEuhveYCs+oF+i2tv/II6jh6jdg==} - peerDependencies: - storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@svgr/babel-plugin-add-jsx-attribute@8.0.0': resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} engines: {node: '>=14'} @@ -5395,9 +5242,6 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@types/uuid@9.0.8': - resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} - '@types/xml2js@0.4.14': resolution: {integrity: sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==} @@ -5836,12 +5680,6 @@ packages: peerDependencies: acorn: ^8 - acorn-import-phases@1.0.4: - resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} - engines: {node: '>=10.13.0'} - peerDependencies: - acorn: ^8.14.0 - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -5905,9 +5743,6 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - algoliasearch@5.25.0: resolution: {integrity: sha512-n73BVorL4HIwKlfJKb4SEzAYkR3Buwfwbh+MYxg2mloFph2fFGV58E90QTzdbfzWrLn4HE5Czx/WTjI8fcHaMg==} engines: {node: '>= 14.0.0'} @@ -6125,10 +5960,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - better-opn@3.0.2: - resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} - engines: {node: '>=12.0.0'} - big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -6170,9 +6001,6 @@ packages: brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - brace-expansion@1.1.14: - resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} @@ -6187,9 +6015,6 @@ packages: brorand@1.1.0: resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - browser-assert@1.2.1: - resolution: {integrity: sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==} - browserify-aes@1.2.0: resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} @@ -6885,10 +6710,6 @@ packages: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} - define-lazy-prop@2.0.0: - resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} - engines: {node: '>=8'} - define-lazy-prop@3.0.0: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} @@ -7167,9 +6988,6 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - es-module-lexer@2.0.0: - resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} - es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -7195,11 +7013,6 @@ packages: esast-util-from-js@2.0.1: resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} - esbuild-register@3.6.0: - resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} - peerDependencies: - esbuild: '>=0.12 <1' - esbuild@0.23.1: resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} engines: {node: '>=18'} @@ -7535,9 +7348,6 @@ packages: fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-builder@1.1.5: resolution: {integrity: sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==} @@ -7646,13 +7456,6 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} - fork-ts-checker-webpack-plugin@8.0.0: - resolution: {integrity: sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==} - engines: {node: '>=12.13.0', yarn: '>=1.0.0'} - peerDependencies: - typescript: '>3.6.0' - webpack: ^5.11.0 - fork-ts-checker-webpack-plugin@9.1.0: resolution: {integrity: sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==} engines: {node: '>=14.21.3'} @@ -7975,18 +7778,6 @@ packages: webpack: optional: true - html-webpack-plugin@5.6.7: - resolution: {integrity: sha512-md+vXtdCAe60s1k6AU3dUyMJnDxUyQAwfwPKoLisvgUF1IXjtlLsk2se54+qfL9Mdm26bbwvjJybpNx48NKRLw==} - engines: {node: '>=10.13.0'} - peerDependencies: - '@rspack/core': 0.x || 1.x - webpack: ^5.20.0 - peerDependenciesMeta: - '@rspack/core': - optional: true - webpack: - optional: true - htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} @@ -8196,11 +7987,6 @@ packages: is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -8347,10 +8133,6 @@ packages: resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} engines: {node: '>=18'} - is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - is-wsl@3.1.1: resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} @@ -8420,10 +8202,6 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsdoc-type-pratt-parser@4.8.0: - resolution: {integrity: sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==} - engines: {node: '>=12.0.0'} - jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} @@ -8632,10 +8410,6 @@ packages: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} - loader-runner@4.3.1: - resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} - engines: {node: '>=6.11.5'} - loader-utils@2.0.4: resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} engines: {node: '>=8.9.0'} @@ -8733,9 +8507,6 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - map-or-similar@1.5.0: - resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} - markdown-extensions@2.0.0: resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} engines: {node: '>=16'} @@ -8846,9 +8617,6 @@ packages: memoize-one@6.0.0: resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} - memoizerific@1.11.3: - resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} - merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} @@ -9026,9 +8794,6 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -9336,10 +9101,6 @@ packages: resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} engines: {node: '>=18'} - open@8.4.2: - resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} - engines: {node: '>=12'} - opener@1.5.2: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true @@ -9940,11 +9701,6 @@ packages: peerDependencies: react: ^19.2.4 - react-dom@19.2.5: - resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} - peerDependencies: - react: ^19.2.4 - react-emoji-render@2.0.1: resolution: {integrity: sha512-SKtsdwgEf2BFNiE9y4UBFZBWjkRcyWmhMprVly52+J77/zxThcfaQ3sCA0+2LtGJIRMpm4DGWSvyLg72fd1rXQ==} peerDependencies: @@ -10041,10 +9797,6 @@ packages: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} - react@19.2.5: - resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} - engines: {node: '>=0.10.0'} - readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -10271,9 +10023,6 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-identifier@0.4.2: - resolution: {integrity: sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==} - safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -10324,10 +10073,6 @@ packages: resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} engines: {node: '>= 10.13.0'} - schema-utils@4.3.3: - resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} - engines: {node: '>= 10.13.0'} - search-insights@2.17.3: resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==} @@ -10554,8 +10299,8 @@ packages: next-intl: ^3 || ^4 storybook: ^9.0.0 || ^10.0.0 - storybook@10.3.3: - resolution: {integrity: sha512-tMoRAts9EVqf+mEMPLC6z1DPyHbcPe+CV1MhLN55IKsl0HxNjvVGK44rVPSePbltPE6vIsn4bdRj6CCUt8SJwQ==} + storybook@10.2.13: + resolution: {integrity: sha512-heMfJjOfbHvL+wlCAwFZlSxcakyJ5yQDam6e9k2RRArB1veJhRnsjO6lO1hOXjJYrqxfHA/ldIugbBVlCDqfvQ==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -10563,8 +10308,8 @@ packages: prettier: optional: true - storybook@8.5.8: - resolution: {integrity: sha512-k3QDa7z4a656oO3Mx929KNm+xIdEI2nIDCKatVl1mA6vt+ge+uwoiG+ro182J9LOEppR5XXD2mQQi4u1xNsy6A==} + storybook@10.3.3: + resolution: {integrity: sha512-tMoRAts9EVqf+mEMPLC6z1DPyHbcPe+CV1MhLN55IKsl0HxNjvVGK44rVPSePbltPE6vIsn4bdRj6CCUt8SJwQ==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -10790,10 +10535,6 @@ packages: resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} - tapable@2.3.3: - resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} - engines: {node: '>=6'} - tar-stream@1.6.2: resolution: {integrity: sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==} engines: {node: '>= 0.8.0'} @@ -10826,32 +10567,11 @@ packages: uglify-js: optional: true - terser-webpack-plugin@5.4.0: - resolution: {integrity: sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@swc/core': '*' - esbuild: '*' - uglify-js: '*' - webpack: ^5.1.0 - peerDependenciesMeta: - '@swc/core': - optional: true - esbuild: - optional: true - uglify-js: - optional: true - terser@5.40.0: resolution: {integrity: sha512-cfeKl/jjwSR5ar7d0FGmave9hFGJT8obyo0z+CrQOylLDbk7X81nPU6vq9VORa5jU30SkDnT2FXjLbR8HLP+xA==} engines: {node: '>=10'} hasBin: true - terser@5.46.1: - resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} - engines: {node: '>=10'} - hasBin: true - text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -11165,10 +10885,6 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - unplugin@1.16.1: - resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} - engines: {node: '>=14.0.0'} - unplugin@2.3.11: resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} engines: {node: '>=18.12.0'} @@ -11414,10 +11130,6 @@ packages: resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} engines: {node: '>=10.13.0'} - watchpack@2.5.1: - resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} - engines: {node: '>=10.13.0'} - web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} @@ -11449,23 +11161,9 @@ packages: resolution: {integrity: sha512-ykKKus8lqlgXX/1WjudpIEjqsafjOTcOJqxnAbMLAu/KCsDCJ6GBtvscewvTkrn24HsnvFwrSCbenFrhtcCsAA==} engines: {node: '>=10.13.0'} - webpack-sources@3.3.4: - resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} - engines: {node: '>=10.13.0'} - webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack@5.106.2: - resolution: {integrity: sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - webpack@5.99.9: resolution: {integrity: sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==} engines: {node: '>=10.13.0'} @@ -11664,11 +11362,6 @@ packages: engines: {node: '>= 14.6'} hasBin: true - yaml@2.8.3: - resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} - engines: {node: '>= 14.6'} - hasBin: true - yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -14132,36 +13825,26 @@ snapshots: '@bugsnag/cuid@3.2.1': {} - '@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)': + '@chromatic-com/playwright@0.13.2(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)': dependencies: '@chromaui/rrweb-snapshot': 2.0.0-alpha.18-noAbsolute '@playwright/test': 1.53.1 - '@segment/analytics-node': 1.3.0 - '@storybook/addon-essentials': 8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/csf': 0.1.13 - '@storybook/manager-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/server-webpack5': 8.5.8(@swc/core@1.15.24)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) + '@segment/analytics-node': 2.1.3 + storybook: 10.2.13(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 transitivePeerDependencies: - - '@rspack/core' - - '@swc/core' - - '@types/react' + - '@testing-library/dom' - bufferutil - encoding - - esbuild - prettier - - supports-color - - typescript - - uglify-js + - react + - react-dom - utf-8-validate - - webpack-cli - optional: true - '@chromatic-com/storybook@5.1.1(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': + '@chromatic-com/storybook@5.1.1(@chromatic-com/playwright@0.13.2(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: '@neoconfetti/react': 1.0.0 - chromatic: 13.3.5(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)) + chromatic: 13.3.5(@chromatic-com/playwright@0.13.2(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) filesize: 10.1.6 jsonfile: 6.1.0 storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) @@ -14173,7 +13856,6 @@ snapshots: '@chromaui/rrweb-snapshot@2.0.0-alpha.18-noAbsolute': dependencies: postcss: 8.5.10 - optional: true '@clack/core@0.5.0': dependencies: @@ -14863,12 +14545,6 @@ snapshots: '@jridgewell/set-array@1.2.1': {} - '@jridgewell/source-map@0.3.11': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - optional: true - '@jridgewell/source-map@0.3.6': dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -14903,13 +14579,11 @@ snapshots: dependencies: '@lit-labs/ssr-dom-shim': 1.3.0 - '@lukeed/csprng@1.1.0': - optional: true + '@lukeed/csprng@1.1.0': {} '@lukeed/uuid@2.0.1': dependencies: '@lukeed/csprng': 1.1.0 - optional: true '@mdx-js/mdx@3.1.0(acorn@8.16.0)': dependencies: @@ -14947,13 +14621,6 @@ snapshots: '@types/react': 19.2.14 react: 19.2.4 - '@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@types/mdx': 2.0.13 - '@types/react': 19.2.14 - react: 19.2.5 - optional: true - '@metamask/eth-json-rpc-provider@1.0.1': dependencies: '@metamask/json-rpc-engine': 7.3.3 @@ -16760,30 +16427,28 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 - '@segment/analytics-core@1.4.1': + '@segment/analytics-core@1.7.0': dependencies: '@lukeed/uuid': 2.0.1 - '@segment/analytics-generic-utils': 1.1.1 + '@segment/analytics-generic-utils': 1.2.0 dset: 3.1.4 tslib: 2.8.1 - optional: true - '@segment/analytics-generic-utils@1.1.1': + '@segment/analytics-generic-utils@1.2.0': dependencies: tslib: 2.8.1 - optional: true - '@segment/analytics-node@1.3.0': + '@segment/analytics-node@2.1.3': dependencies: '@lukeed/uuid': 2.0.1 - '@segment/analytics-core': 1.4.1 - '@segment/analytics-generic-utils': 1.1.1 + '@segment/analytics-core': 1.7.0 + '@segment/analytics-generic-utils': 1.2.0 buffer: 6.0.3 + jose: 5.10.0 node-fetch: 2.7.0 tslib: 2.8.1 transitivePeerDependencies: - encoding - optional: true '@sentry-internal/browser-utils@10.46.0': dependencies: @@ -17587,32 +17252,6 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/addon-actions@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - '@types/uuid': 9.0.8 - dequal: 2.0.3 - polished: 4.3.1 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - uuid: 9.0.1 - optional: true - - '@storybook/addon-backgrounds@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - memoizerific: 1.11.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - - '@storybook/addon-controls@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - dequal: 2.0.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - '@storybook/addon-docs@10.3.3(@types/react@19.2.14)(esbuild@0.25.12)(rollup@4.46.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12))': dependencies: '@mdx-js/react': 3.1.0(@types/react@19.2.14)(react@19.2.4) @@ -17630,43 +17269,6 @@ snapshots: - vite - webpack - '@storybook/addon-docs@8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.5) - '@storybook/blocks': 8.5.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/csf-plugin': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/react-dom-shim': 8.5.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - transitivePeerDependencies: - - '@types/react' - optional: true - - '@storybook/addon-essentials@8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/addon-actions': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-backgrounds': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-controls': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-docs': 8.5.8(@types/react@19.2.14)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-highlight': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-measure': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-outline': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-toolbars': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/addon-viewport': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - transitivePeerDependencies: - - '@types/react' - optional: true - - '@storybook/addon-highlight@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/addon-links@10.3.3(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: '@storybook/global': 5.0.0 @@ -17674,47 +17276,11 @@ snapshots: optionalDependencies: react: 19.2.4 - '@storybook/addon-measure@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - tiny-invariant: 1.3.3 - optional: true - - '@storybook/addon-outline@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - '@storybook/addon-themes@10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 - '@storybook/addon-toolbars@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - - '@storybook/addon-viewport@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - memoizerific: 1.11.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - - '@storybook/blocks@8.5.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/csf': 0.1.12 - '@storybook/icons': 1.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optionalDependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - optional: true - '@storybook/builder-webpack5@10.3.3(@swc/core@1.15.24)(esbuild@0.25.12)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(typescript@5.8.3)': dependencies: '@storybook/core-webpack': 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)) @@ -17742,80 +17308,11 @@ snapshots: - uglify-js - webpack-cli - '@storybook/builder-webpack5@8.5.8(@swc/core@1.15.24)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': - dependencies: - '@storybook/core-webpack': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@types/semver': 7.7.1 - browser-assert: 1.2.1 - case-sensitive-paths-webpack-plugin: 2.4.0 - cjs-module-lexer: 1.4.3 - constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - es-module-lexer: 1.7.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - html-webpack-plugin: 5.6.7(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - magic-string: 0.30.21 - path-browserify: 1.0.1 - process: 0.11.10 - semver: 7.7.4 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - style-loader: 3.3.4(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - terser-webpack-plugin: 5.4.0(@swc/core@1.15.24)(esbuild@0.25.12)(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - ts-dedent: 2.2.0 - url: 0.11.4 - util: 0.12.5 - util-deprecate: 1.0.2 - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - webpack-dev-middleware: 6.1.3(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - webpack-hot-middleware: 2.26.1 - webpack-virtual-modules: 0.6.2 - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - '@rspack/core' - - '@swc/core' - - esbuild - - uglify-js - - webpack-cli - optional: true - - '@storybook/components@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - - '@storybook/core-webpack@10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': + '@storybook/core-webpack@10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 - '@storybook/core-webpack@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - optional: true - - '@storybook/core@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)': - dependencies: - '@storybook/csf': 0.1.12 - better-opn: 3.0.2 - browser-assert: 1.2.1 - esbuild: 0.25.12 - esbuild-register: 3.6.0(esbuild@0.25.12) - jsdoc-type-pratt-parser: 4.8.0 - process: 0.11.10 - recast: 0.23.11 - semver: 7.7.4 - util: 0.12.5 - ws: 8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - prettier: 3.5.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - optional: true - '@storybook/csf-plugin@10.3.3(esbuild@0.25.12)(rollup@4.46.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) @@ -17825,40 +17322,13 @@ snapshots: rollup: 4.46.2 webpack: 5.99.9(@swc/core@1.15.24)(esbuild@0.25.12) - '@storybook/csf-plugin@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - unplugin: 1.16.1 - optional: true - - '@storybook/csf@0.1.12': - dependencies: - type-fest: 2.19.0 - optional: true - - '@storybook/csf@0.1.13': - dependencies: - type-fest: 2.19.0 - optional: true - '@storybook/global@5.0.0': {} - '@storybook/icons@1.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - optional: true - '@storybook/icons@2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/manager-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/nextjs@10.3.3(@swc/core@1.15.24)(babel-plugin-macros@3.1.0)(esbuild@0.25.12)(next@16.2.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12))': dependencies: '@babel/core': 7.29.0 @@ -17942,22 +17412,6 @@ snapshots: - uglify-js - webpack-cli - '@storybook/preset-server-webpack@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/core-webpack': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/global': 5.0.0 - '@storybook/server': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - safe-identifier: 0.4.2 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - yaml-loader: 0.8.1 - optional: true - - '@storybook/preview-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12))': dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -17978,13 +17432,6 @@ snapshots: react-dom: 19.2.4(react@19.2.4) storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) - '@storybook/react-dom-shim@8.5.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@storybook/react@10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10))(typescript@5.8.3)': dependencies: '@storybook/global': 5.0.0 @@ -17999,39 +17446,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/server-webpack5@8.5.8(@swc/core@1.15.24)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': - dependencies: - '@storybook/builder-webpack5': 8.5.8(@swc/core@1.15.24)(esbuild@0.25.12)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) - '@storybook/preset-server-webpack': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/server': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - '@rspack/core' - - '@swc/core' - - esbuild - - typescript - - uglify-js - - webpack-cli - optional: true - - '@storybook/server@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - '@storybook/components': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/csf': 0.1.12 - '@storybook/global': 5.0.0 - '@storybook/manager-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/preview-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/theming': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - ts-dedent: 2.2.0 - yaml: 2.8.3 - optional: true - - '@storybook/theming@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))': - dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - optional: true - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 @@ -18583,9 +17997,6 @@ snapshots: '@types/unist@3.0.3': {} - '@types/uuid@9.0.8': - optional: true - '@types/xml2js@0.4.14': dependencies: '@types/node': 20.17.57 @@ -19557,11 +18968,6 @@ snapshots: dependencies: acorn: 8.16.0 - acorn-import-phases@1.0.4(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - optional: true - acorn-jsx@5.3.2(acorn@8.14.1): dependencies: acorn: 8.14.1 @@ -19595,11 +19001,6 @@ snapshots: optionalDependencies: ajv: 8.17.1 - ajv-formats@2.1.1(ajv@8.18.0): - optionalDependencies: - ajv: 8.18.0 - optional: true - ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -19613,12 +19014,6 @@ snapshots: ajv: 8.17.1 fast-deep-equal: 3.1.3 - ajv-keywords@5.1.0(ajv@8.18.0): - dependencies: - ajv: 8.18.0 - fast-deep-equal: 3.1.3 - optional: true - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -19633,14 +19028,6 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ajv@8.18.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - optional: true - algoliasearch@5.25.0: dependencies: '@algolia/client-abtesting': 5.25.0 @@ -19894,11 +19281,6 @@ snapshots: baseline-browser-mapping@2.10.19: {} - better-opn@3.0.2: - dependencies: - open: 8.4.2 - optional: true - big.js@5.2.2: {} big.js@6.2.2: {} @@ -19943,12 +19325,6 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@1.1.14: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - optional: true - brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 @@ -19963,9 +19339,6 @@ snapshots: brorand@1.1.0: {} - browser-assert@1.2.1: - optional: true - browserify-aes@1.2.0: dependencies: buffer-xor: 1.0.3 @@ -20194,13 +19567,13 @@ snapshots: chownr@3.0.0: {} - chromatic@13.3.5(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)): + chromatic@13.3.5(@chromatic-com/playwright@0.13.2(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)): optionalDependencies: - '@chromatic-com/playwright': 0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10) + '@chromatic-com/playwright': 0.13.2(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) - chromatic@16.0.0(@chromatic-com/playwright@0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10)): + chromatic@16.0.0(@chromatic-com/playwright@0.13.2(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10)): optionalDependencies: - '@chromatic-com/playwright': 0.12.5(@playwright/test@1.53.1)(@swc/core@1.15.24)(@types/react@19.2.14)(bufferutil@4.0.9)(esbuild@0.25.12)(prettier@3.5.3)(typescript@5.8.3)(utf-8-validate@5.0.10) + '@chromatic-com/playwright': 0.13.2(@playwright/test@1.53.1)(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10) chrome-trace-event@1.0.4: {} @@ -20444,20 +19817,6 @@ snapshots: randombytes: 2.1.0 randomfill: 1.0.4 - css-loader@6.11.0(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - icss-utils: 5.1.0(postcss@8.5.4) - postcss: 8.5.4 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.4) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.4) - postcss-modules-scope: 3.2.1(postcss@8.5.4) - postcss-modules-values: 4.0.0(postcss@8.5.4) - postcss-value-parser: 4.2.0 - semver: 7.7.4 - optionalDependencies: - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optional: true - css-loader@6.11.0(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12)): dependencies: icss-utils: 5.1.0(postcss@8.5.4) @@ -20693,9 +20052,6 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - define-lazy-prop@2.0.0: - optional: true - define-lazy-prop@3.0.0: {} define-properties@1.2.1: @@ -20821,8 +20177,7 @@ snapshots: dotenv@16.6.1: {} - dset@3.1.4: - optional: true + dset@3.1.4: {} dunder-proto@1.0.1: dependencies: @@ -21062,9 +20417,6 @@ snapshots: es-module-lexer@1.7.0: {} - es-module-lexer@2.0.0: - optional: true - es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -21102,14 +20454,6 @@ snapshots: esast-util-from-estree: 2.0.0 vfile-message: 4.0.2 - esbuild-register@3.6.0(esbuild@0.25.12): - dependencies: - debug: 4.4.3(supports-color@10.2.2) - esbuild: 0.25.12 - transitivePeerDependencies: - - supports-color - optional: true - esbuild@0.23.1: optionalDependencies: '@esbuild/aix-ppc64': 0.23.1 @@ -21614,9 +20958,6 @@ snapshots: fast-uri@3.0.6: {} - fast-uri@3.1.0: - optional: true - fast-xml-builder@1.1.5: dependencies: path-expression-matcher: 1.5.0 @@ -21727,24 +21068,6 @@ snapshots: dependencies: is-callable: 1.2.7 - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - '@babel/code-frame': 7.29.0 - chalk: 4.1.2 - chokidar: 3.6.0 - cosmiconfig: 7.1.0 - deepmerge: 4.3.1 - fs-extra: 10.1.0 - memfs: 3.5.3 - minimatch: 3.1.5 - node-abort-controller: 3.1.1 - schema-utils: 3.3.0 - semver: 7.7.4 - tapable: 2.3.3 - typescript: 5.8.3 - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optional: true - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12)): dependencies: '@babel/code-frame': 7.27.1 @@ -22154,17 +21477,6 @@ snapshots: optionalDependencies: webpack: 5.99.9(@swc/core@1.15.24)(esbuild@0.25.12) - html-webpack-plugin@5.6.7(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.18.1 - pretty-error: 4.0.0 - tapable: 2.3.3 - optionalDependencies: - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optional: true - htmlparser2@10.1.0: dependencies: domelementtype: 2.3.0 @@ -22389,9 +21701,6 @@ snapshots: is-decimal@2.0.1: {} - is-docker@2.2.1: - optional: true - is-docker@3.0.0: {} is-extendable@0.1.1: {} @@ -22509,11 +21818,6 @@ snapshots: is-what@5.5.0: {} - is-wsl@2.2.0: - dependencies: - is-docker: 2.2.1 - optional: true - is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 @@ -22578,9 +21882,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsdoc-type-pratt-parser@4.8.0: - optional: true - jsesc@3.0.2: {} jsesc@3.1.0: {} @@ -22782,9 +22083,6 @@ snapshots: loader-runner@4.3.0: {} - loader-runner@4.3.1: - optional: true - loader-utils@2.0.4: dependencies: big.js: 5.2.2 @@ -22877,9 +22175,6 @@ snapshots: make-error@1.3.6: {} - map-or-similar@1.5.0: - optional: true - markdown-extensions@2.0.0: {} markdown-it@14.1.1: @@ -23128,11 +22423,6 @@ snapshots: memoize-one@6.0.0: {} - memoizerific@1.11.3: - dependencies: - map-or-similar: 1.5.0 - optional: true - merge-descriptors@2.0.0: {} merge-stream@2.0.0: {} @@ -23467,11 +22757,6 @@ snapshots: dependencies: brace-expansion: 1.1.11 - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.14 - optional: true - minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -23791,13 +23076,6 @@ snapshots: is-inside-container: 1.0.0 wsl-utils: 0.1.0 - open@8.4.2: - dependencies: - define-lazy-prop: 2.0.0 - is-docker: 2.2.1 - is-wsl: 2.2.0 - optional: true - opener@1.5.2: {} optionator@0.9.4: @@ -24411,12 +23689,6 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 - react-dom@19.2.5(react@19.2.5): - dependencies: - react: 19.2.5 - scheduler: 0.27.0 - optional: true - react-emoji-render@2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: classnames: 2.5.1 @@ -24520,9 +23792,6 @@ snapshots: react@19.2.4: {} - react@19.2.5: - optional: true - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -24878,9 +24147,6 @@ snapshots: safe-buffer@5.2.1: {} - safe-identifier@0.4.2: - optional: true - safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -24919,14 +24185,6 @@ snapshots: ajv-formats: 2.1.1(ajv@8.17.1) ajv-keywords: 5.1.0(ajv@8.17.1) - schema-utils@4.3.3: - dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.18.0 - ajv-formats: 2.1.1(ajv@8.18.0) - ajv-keywords: 5.1.0(ajv@8.18.0) - optional: true - search-insights@2.17.3: {} section-matter@1.0.0: @@ -25252,7 +24510,7 @@ snapshots: - react - react-dom - storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10): + storybook@10.2.13(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -25265,7 +24523,7 @@ snapshots: recast: 0.23.11 semver: 7.7.4 use-sync-external-store: 1.5.0(react@19.2.4) - ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: prettier: 3.5.3 transitivePeerDependencies: @@ -25275,16 +24533,28 @@ snapshots: - react-dom - utf-8-validate - storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10): + storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@5.0.10): dependencies: - '@storybook/core': 8.5.8(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) + '@storybook/global': 5.0.0 + '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@testing-library/jest-dom': 6.9.1 + '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) + '@vitest/expect': 3.2.4 + '@vitest/spy': 3.2.4 + esbuild: 0.25.12 + open: 10.2.0 + recast: 0.23.11 + semver: 7.7.4 + use-sync-external-store: 1.5.0(react@19.2.4) + ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: prettier: 3.5.3 transitivePeerDependencies: + - '@testing-library/dom' - bufferutil - - supports-color + - react + - react-dom - utf-8-validate - optional: true stream-browserify@3.0.0: dependencies: @@ -25422,11 +24692,6 @@ snapshots: strnum@2.2.3: {} - style-loader@3.3.4(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optional: true - style-loader@3.3.4(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12)): dependencies: webpack: 5.99.9(@swc/core@1.15.24)(esbuild@0.25.12) @@ -25515,9 +24780,6 @@ snapshots: tapable@2.3.2: {} - tapable@2.3.3: - optional: true - tar-stream@1.6.2: dependencies: bl: 1.2.3 @@ -25561,18 +24823,6 @@ snapshots: '@swc/core': 1.15.24 esbuild: 0.25.12 - terser-webpack-plugin@5.4.0(@swc/core@1.15.24)(esbuild@0.25.12)(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - terser: 5.46.1 - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optionalDependencies: - '@swc/core': 1.15.24 - esbuild: 0.25.12 - optional: true - terser@5.40.0: dependencies: '@jridgewell/source-map': 0.3.6 @@ -25580,14 +24830,6 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - terser@5.46.1: - dependencies: - '@jridgewell/source-map': 0.3.11 - acorn: 8.16.0 - commander: 2.20.3 - source-map-support: 0.5.21 - optional: true - text-table@0.2.0: {} thread-stream@0.15.2: @@ -25984,12 +25226,6 @@ snapshots: unpipe@1.0.0: {} - unplugin@1.16.1: - dependencies: - acorn: 8.16.0 - webpack-virtual-modules: 0.6.2 - optional: true - unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 @@ -26286,12 +25522,6 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - watchpack@2.5.1: - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - optional: true - web-streams-polyfill@3.3.3: {} webextension-polyfill@0.10.0: {} @@ -26317,17 +25547,6 @@ snapshots: - bufferutil - utf-8-validate - webpack-dev-middleware@6.1.3(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)): - dependencies: - colorette: 2.0.20 - memfs: 3.5.3 - mime-types: 2.1.35 - range-parser: 1.2.1 - schema-utils: 4.3.2 - optionalDependencies: - webpack: 5.106.2(@swc/core@1.15.24)(esbuild@0.25.12) - optional: true - webpack-dev-middleware@6.1.3(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12)): dependencies: colorette: 2.0.20 @@ -26346,43 +25565,8 @@ snapshots: webpack-sources@3.3.2: {} - webpack-sources@3.3.4: - optional: true - webpack-virtual-modules@0.6.2: {} - webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.16.0 - acorn-import-phases: 1.0.4(acorn@8.16.0) - browserslist: 4.28.2 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.20.1 - es-module-lexer: 2.0.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - loader-runner: 4.3.1 - mime-db: 1.54.0 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.3 - terser-webpack-plugin: 5.4.0(@swc/core@1.15.24)(esbuild@0.25.12)(webpack@5.106.2(@swc/core@1.15.24)(esbuild@0.25.12)) - watchpack: 2.5.1 - webpack-sources: 3.3.4 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - optional: true - webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12): dependencies: '@types/eslint-scope': 3.7.7 @@ -26521,7 +25705,6 @@ snapshots: optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 - optional: true wsl-utils@0.1.0: dependencies: @@ -26570,9 +25753,6 @@ snapshots: yaml@2.8.0: {} - yaml@2.8.3: - optional: true - yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 From 306594fa5b4cd98142a30aeeea6602e97a2efc39 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Mon, 27 Apr 2026 15:33:17 +0200 Subject: [PATCH 24/31] fix(visual): share maybeShuffle across apps and staking grids --- .claude/skills/page-visual-tests/SKILL.md | 4 +- next.config.js | 4 ++ .../useStakingProductsCardGrid.ts | 5 ++- src/lib/utils/apps.ts | 45 ++++++++++--------- src/lib/utils/random.ts | 8 ++++ src/lib/utils/wallets.ts | 9 +--- 6 files changed, 44 insertions(+), 31 deletions(-) diff --git a/.claude/skills/page-visual-tests/SKILL.md b/.claude/skills/page-visual-tests/SKILL.md index a65fba9a0a8..331a72027d2 100644 --- a/.claude/skills/page-visual-tests/SKILL.md +++ b/.claude/skills/page-visual-tests/SKILL.md @@ -30,6 +30,8 @@ The Playwright suite captures DOM archives (not PNGs) per page × viewport; Chro **Environment.** `USE_MOCK_DATA=true` and `NEXT_PUBLIC_BUILD_LOCALES=en` are required at build and test time. Paths in the spec are unprefixed (`/wallets/`, not `/en/wallets/`) because `localePrefix: "as-needed"` serves English at the root — adding `/en` would just trigger a redirect. +**Random ordering: `maybeShuffle`.** Lodash `shuffle` and `.sort(() => Math.random() - 0.5)` flake snapshots independently of loaders. Wrap them with `maybeShuffle` from `src/lib/utils/random.ts` — it returns the list unchanged when `IS_VISUAL_TEST=true`. Current call sites: `wallets.ts`, `apps.ts` (Highlights/Discover/AppOfTheWeek), `useStakingProductsCardGrid.ts`. The env var is exposed to the client bundle via `next.config.js`'s `env` block; without that, `process.env.IS_VISUAL_TEST` evaluates to `undefined` in client components and the shuffle still runs. + **Use `domcontentloaded`, not `networkidle`.** Analytics and background fetches keep the network perpetually busy. ## Canonical test @@ -60,7 +62,7 @@ test.describe("Page Visual Tests", () => { **Adding a page.** Each entry costs three snapshots (one per viewport) against Chromatic's budget, so check whether the page's layout (under `src/layouts/`) is already covered before adding. Scan the page subtree for bespoke loaders — they're the single biggest flake cause — and confirm full-page height stays under the 25M-pixel budget. Local loop: `pnpm test:visual:build` once, then `pnpm test:visual:desktop` for iteration, `pnpm test:visual` for the full sweep. -**Flaky snapshot.** The culprit is almost always a loader without `data-slot="loading"`. Run with `--trace=on` and inspect the `waitForFunction` step in the trace — if its duration is ~0 ms, the loader isn't being waited on. If dynamic content is drifting, double-check `USE_MOCK_DATA=true` is set in both build and test steps. +**Flaky snapshot.** Two main causes. (1) A loader without `data-slot="loading"` — run with `--trace=on` and inspect the `waitForFunction` step; ~0 ms duration means it isn't being waited on. (2) Random ordering — grep the page subtree for `shuffle(`, `Math.random()`, or `.sort(() =>` and route through `maybeShuffle`. If dynamic content is drifting, double-check `USE_MOCK_DATA=true` is set in both build and test steps. **Pixel-limit error.** Measure the page's full-page height at 1024 px; if it exceeds ~24,400 px, the page needs shortening or removal from the suite. Cropping to viewport was considered and rejected — it defeats the below-the-fold regression coverage that justifies using Playwright over Storybook here. diff --git a/next.config.js b/next.config.js index 52da595ff32..5455b9939ce 100644 --- a/next.config.js +++ b/next.config.js @@ -46,6 +46,10 @@ module.exports = (phase) => { process.env.DEPLOY_URL || process.env.URL || "https://ethereum.org", + // Inline IS_VISUAL_TEST into the client bundle so client-side shuffles + // (e.g. useStakingProductsCardGrid) can opt out of randomization during + // visual test builds. Server code reads it from process.env directly. + IS_VISUAL_TEST: process.env.IS_VISUAL_TEST, }, webpack: (config) => { // Parse .all-contributorsrc as JSON (no .json extension) diff --git a/src/components/Staking/StakingProductsCardGrid/useStakingProductsCardGrid.ts b/src/components/Staking/StakingProductsCardGrid/useStakingProductsCardGrid.ts index 06d3815741c..86c5f1509a8 100644 --- a/src/components/Staking/StakingProductsCardGrid/useStakingProductsCardGrid.ts +++ b/src/components/Staking/StakingProductsCardGrid/useStakingProductsCardGrid.ts @@ -1,5 +1,6 @@ import { useEffect, useState } from "react" -import { shuffle } from "lodash" + +import { maybeShuffle } from "@/lib/utils/random" import stakingProducts from "@/data/staking-products.json" @@ -110,7 +111,7 @@ export const useStakingProductsCardGrid = ({ } updateRankedProducts( - shuffle(products) + maybeShuffle(products) .map((product) => ({ ...product, rankingScore: getRankingScore(product), diff --git a/src/lib/utils/apps.ts b/src/lib/utils/apps.ts index 22c48d2a144..22056d76695 100644 --- a/src/lib/utils/apps.ts +++ b/src/lib/utils/apps.ts @@ -3,6 +3,7 @@ import { AppCategory, AppCategoryEnum, AppData } from "@/lib/types" import { TagProps } from "@/components/ui/tag" import { getValidDate } from "@/lib/utils/date" +import { maybeShuffle } from "@/lib/utils/random" // Get highlighted apps (apps with highlight=true) export const getHighlightedApps = ( @@ -14,9 +15,9 @@ export const getHighlightedApps = ( ? appsData[category] : Object.values(appsData).flatMap((categoryApps) => categoryApps) - const highlightedApps = appsToFilter - .filter((app) => app.highlight) - .sort(() => Math.random() - 0.5) + const highlightedApps = maybeShuffle( + appsToFilter.filter((app) => app.highlight) + ) return count ? highlightedApps.slice(0, count) : highlightedApps } @@ -26,10 +27,11 @@ export const getDiscoverApps = ( appsData: Record, count?: number ) => { - const discoverApps = Object.values(appsData) - .flatMap((categoryDapps) => categoryDapps) - .filter((app) => app.discover) - .sort(() => Math.random() - 0.5) + const discoverApps = maybeShuffle( + Object.values(appsData) + .flatMap((categoryDapps) => categoryDapps) + .filter((app) => app.discover) + ) return count ? discoverApps.slice(0, count) : discoverApps } @@ -50,20 +52,21 @@ export const parseAppsOfTheWeek = ( ) => { const currentDate = new Date() - const appsOfTheWeek = Object.values(appsData) - .flatMap((categoryApps) => categoryApps) - .filter((app) => { - // Handle both Date objects and date strings (for mock data) - const startDate = getValidDate(app.appOfTheWeekStartDate) - const endDate = getValidDate(app.appOfTheWeekEndDate) + const appsOfTheWeek = maybeShuffle( + Object.values(appsData) + .flatMap((categoryApps) => categoryApps) + .filter((app) => { + // Handle both Date objects and date strings (for mock data) + const startDate = getValidDate(app.appOfTheWeekStartDate) + const endDate = getValidDate(app.appOfTheWeekEndDate) - return ( - startDate && - endDate && - currentDate >= startDate && - currentDate <= endDate - ) - }) - .sort(() => Math.random() - 0.5) + return ( + startDate && + endDate && + currentDate >= startDate && + currentDate <= endDate + ) + }) + ) return appsOfTheWeek } diff --git a/src/lib/utils/random.ts b/src/lib/utils/random.ts index 8ea1e9fd813..021d69ba73b 100644 --- a/src/lib/utils/random.ts +++ b/src/lib/utils/random.ts @@ -1,3 +1,11 @@ +import { shuffle } from "lodash" + +// Visual test builds set IS_VISUAL_TEST=true to keep list order deterministic +// across runs. Not tied to USE_MOCK_DATA, which is also used by unit tests and +// local dev with mocked storage. +export const maybeShuffle = (list: T[]): T[] => + process.env.IS_VISUAL_TEST === "true" ? list : shuffle(list) + /** * Seeded LCG (Linear Congruential Generator) random number generator. * Same seed always produces the same sequence — deterministic across all users. diff --git a/src/lib/utils/wallets.ts b/src/lib/utils/wallets.ts index 05f70c70562..ebbaa6c5d90 100644 --- a/src/lib/utils/wallets.ts +++ b/src/lib/utils/wallets.ts @@ -1,6 +1,7 @@ -import { shuffle, union } from "lodash" +import { union } from "lodash" import { getLanguageCodeName } from "@/lib/utils/intl" +import { maybeShuffle } from "@/lib/utils/random" import { capitalize } from "@/lib/utils/string" import { newToCrypto } from "@/data/wallets/new-to-crypto" @@ -21,12 +22,6 @@ import type { WalletRow, } from "../types" -// Visual test builds set IS_VISUAL_TEST=true to keep wallet order deterministic -// across runs. Not tied to USE_MOCK_DATA, which is also used by unit tests and -// local dev with mocked storage. -const maybeShuffle = (list: T[]): T[] => - process.env.IS_VISUAL_TEST === "true" ? list : shuffle(list) - export const getSupportedLocaleWallets = (locale: string) => maybeShuffle( walletsData.filter((wallet) => From 4e88a09ce80c9d1d66f34e78205a6bae8fa103ee Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Mon, 27 Apr 2026 16:29:06 +0200 Subject: [PATCH 25/31] fix(visual): also wait for next/image blur placeholder removal --- tests/visual/pages.spec.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/visual/pages.spec.ts b/tests/visual/pages.spec.ts index 82025adf908..975e65a7de9 100644 --- a/tests/visual/pages.spec.ts +++ b/tests/visual/pages.spec.ts @@ -46,11 +46,15 @@ test.describe("Page Visual Tests", () => { if (img.loading === "lazy") img.loading = "eager" } }) - // Next.js Image's blur placeholder is removed only after the underlying - // finishes loading. Snapshotting earlier captures the inline - // background-image and shows pixelated blur in the diff. + // Next.js Image's blur placeholder is rendered as an inline + // background-image style and removed only after React's onLoad handler + // re-renders post-load. img.complete flips a tick earlier, so checking + // it alone races the unmount and snapshots the green pixelated blur. await page.waitForFunction(() => - Array.from(document.images).every((img) => img.complete) + Array.from(document.images).every( + (img) => + img.complete && img.naturalWidth > 0 && !img.style.backgroundImage + ) ) await takeSnapshot(page, testInfo) }) From 2259ea91061f58fd90e5595ea0911d0b1182aa90 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Mon, 27 Apr 2026 16:31:26 +0200 Subject: [PATCH 26/31] ci(visual): bump chromaui/action to v16 to match chromatic 16.x --- .github/workflows/chromatic-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/chromatic-pages.yml b/.github/workflows/chromatic-pages.yml index 1881acb5803..e25f8ad3129 100644 --- a/.github/workflows/chromatic-pages.yml +++ b/.github/workflows/chromatic-pages.yml @@ -83,7 +83,7 @@ jobs: path: test-results/ - name: Publish to Chromatic - uses: chromaui/action@v1 + uses: chromaui/action@v16 with: projectToken: ${{ secrets.CHROMATIC_PAGES_TOKEN }} playwright: true From 5a42aa40bbb722bf50369db4b7029df39b05f742 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Mon, 27 Apr 2026 17:20:57 +0200 Subject: [PATCH 27/31] Revert "ci(chromatic): temporarily include dev branch for test run" This reverts commit e3a610599b53b890ef6665b1a5f4d8bc4548d887. --- .github/workflows/chromatic-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/chromatic-pages.yml b/.github/workflows/chromatic-pages.yml index e25f8ad3129..5a9bedf6b91 100644 --- a/.github/workflows/chromatic-pages.yml +++ b/.github/workflows/chromatic-pages.yml @@ -4,7 +4,7 @@ name: "Chromatic: Page Visual Tests" on: pull_request: - branches: [master, staging, dev, "test/**"] + branches: [master, staging, "test/**"] types: [opened, synchronize, ready_for_review] workflow_dispatch: From 070e5bff56de29c9948f7297aaef2feb9a37ce04 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Sat, 2 May 2026 13:48:00 +0200 Subject: [PATCH 28/31] feat(data-layer): expose eth 24hr percent change extends fetchEthPrice to request usd_24h_change from coingecko, adds ethpricedata type with optional percentchange24h, surfaces it through the gas-eth-price api route and usegasethprice hook so consumers can render the indicator. --- app/api/gas-eth-price/route.ts | 1 + src/data-layer/fetchers/fetchEthPrice.ts | 18 +++++++++++------- src/data-layer/index.ts | 3 ++- src/data-layer/mocks/fetch-eth-price.json | 5 +++-- src/hooks/useGasEthPrice.tsx | 13 +++++++++++-- src/lib/types.ts | 4 ++++ 6 files changed, 32 insertions(+), 12 deletions(-) diff --git a/app/api/gas-eth-price/route.ts b/app/api/gas-eth-price/route.ts index b4005206ce5..a71dbd122af 100644 --- a/app/api/gas-eth-price/route.ts +++ b/app/api/gas-eth-price/route.ts @@ -20,5 +20,6 @@ export async function GET() { return NextResponse.json({ gasPrice: gasPriceData.gasPrice, ethPriceUSD: ethPriceData.value, + ethPercentChange24h: ethPriceData.percentChange24h, }) } diff --git a/src/data-layer/fetchers/fetchEthPrice.ts b/src/data-layer/fetchers/fetchEthPrice.ts index 6ee2b72a268..624a7c22002 100644 --- a/src/data-layer/fetchers/fetchEthPrice.ts +++ b/src/data-layer/fetchers/fetchEthPrice.ts @@ -1,4 +1,4 @@ -import type { MetricReturnData } from "@/lib/types" +import type { EthPriceData } from "@/lib/types" import { fetchRetry } from "./fetchRetry" @@ -6,11 +6,11 @@ export const FETCH_ETH_PRICE_TASK_ID = "fetch-eth-price" /** * Fetch Ethereum price data from CoinGecko API. - * Returns the latest USD price data. + * Returns the latest USD price and 24hr percent change. */ -export async function fetchEthPrice(): Promise { +export async function fetchEthPrice(): Promise { const apiKey = process.env.COINGECKO_API_KEY - const url = `https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd&x_cg_demo_api_key=${apiKey}` + const url = `https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd&include_24hr_change=true&x_cg_demo_api_key=${apiKey}` console.log("Starting Ethereum price data fetch") @@ -23,9 +23,10 @@ export async function fetchEthPrice(): Promise { throw new Error(error) } - const data: { ethereum: { usd: number } } = await response.json() + const data: { ethereum: { usd: number; usd_24h_change?: number } } = + await response.json() const { - ethereum: { usd }, + ethereum: { usd, usd_24h_change }, } = data if (!usd) { @@ -33,11 +34,14 @@ export async function fetchEthPrice(): Promise { } const timestamp = Date.now() + const percentChange24h = + typeof usd_24h_change === "number" ? usd_24h_change / 100 : undefined console.log("Successfully fetched Ethereum price data", { price: usd, + percentChange24h, timestamp, }) - return { value: usd, timestamp } + return { value: usd, timestamp, percentChange24h } } diff --git a/src/data-layer/index.ts b/src/data-layer/index.ts index b7f77f02f18..6421e656918 100644 --- a/src/data-layer/index.ts +++ b/src/data-layer/index.ts @@ -3,6 +3,7 @@ import type { BlockspaceData, Commit, CommunityPick, + EthPriceData, EventItem, GHIssue, GitHubContributorsData, @@ -26,7 +27,7 @@ import { KEYS } from "./tasks" export { KEYS } -export const getEthPrice = () => get(KEYS.ETH_PRICE) +export const getEthPrice = () => get(KEYS.ETH_PRICE) export const getL2beatData = () => get(KEYS.L2BEAT) export const getAppsData = () => get>(KEYS.APPS) export const getGrowThePieData = () => get(KEYS.GROW_THE_PIE) diff --git a/src/data-layer/mocks/fetch-eth-price.json b/src/data-layer/mocks/fetch-eth-price.json index bcbe08ae6b5..f409c513010 100644 --- a/src/data-layer/mocks/fetch-eth-price.json +++ b/src/data-layer/mocks/fetch-eth-price.json @@ -1,4 +1,5 @@ { "value": 2941.42, - "timestamp": 1765912003677 -} \ No newline at end of file + "timestamp": 1765912003677, + "percentChange24h": 0.0234 +} diff --git a/src/hooks/useGasEthPrice.tsx b/src/hooks/useGasEthPrice.tsx index 4b4108abf12..36cdeeb63f4 100644 --- a/src/hooks/useGasEthPrice.tsx +++ b/src/hooks/useGasEthPrice.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from "react" type GasEthPriceData = { ethPrice: number gasPrice: number + ethPercentChange24h?: number } export const useGasEthPrice = (): GasEthPriceData => { @@ -15,9 +16,17 @@ export const useGasEthPrice = (): GasEthPriceData => { try { const res = await fetch("/api/gas-eth-price") if (!res.ok) throw new Error("Failed to fetch gas/ETH price") - const json: { ethPriceUSD: number; gasPrice: number } = await res.json() + const json: { + ethPriceUSD: number + gasPrice: number + ethPercentChange24h?: number + } = await res.json() if (!json.ethPriceUSD) throw new Error("Unable to fetch ETH price") - setData({ ethPrice: json.ethPriceUSD, gasPrice: json.gasPrice }) + setData({ + ethPrice: json.ethPriceUSD, + gasPrice: json.gasPrice, + ethPercentChange24h: json.ethPercentChange24h, + }) } catch (error) { console.error(error) } diff --git a/src/lib/types.ts b/src/lib/types.ts index 57625789077..f74bbc4b4cb 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -577,6 +577,10 @@ export type DefiLlamaTVLResponse = { export type MetricReturnData = ValueOrError +export type EthPriceData = + | { value: number; timestamp?: number; percentChange24h?: number } + | { error: string } + export type StatsBoxState = ValueOrError export type GrowThePieMetricKey = "txCount" | "txCostsMedianUsd" From b4a1f65a8c42de763cc77526b7b0da7372864a6a Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Sat, 2 May 2026 13:48:17 +0200 Subject: [PATCH 29/31] fix(eth-price-card): restore 24hr change indicator with stable layout re-renders the percent change row dropped during the data-layer migration. uses fixed-size skeletons (h-[1lh] for the price line, h-7 w-28 for the percent) so the card no longer shifts when data loads. extends numbertopercent to accept intl options for the two-decimal percentage formatting. --- src/components/EthPriceCard.tsx | 62 +++++++++++++++++++++++++-------- src/lib/utils/numbers.ts | 7 +++- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/components/EthPriceCard.tsx b/src/components/EthPriceCard.tsx index da22071cdf3..fb4528ae886 100644 --- a/src/components/EthPriceCard.tsx +++ b/src/components/EthPriceCard.tsx @@ -1,6 +1,6 @@ "use client" -import { Info } from "lucide-react" +import { ArrowDownRight, ArrowUpRight, Info } from "lucide-react" import { useLocale } from "next-intl" import Tooltip from "@/components/Tooltip" @@ -8,11 +8,12 @@ import InlineLink from "@/components/ui/Link" import { Skeleton } from "@/components/ui/skeleton" import { cn } from "@/lib/utils/cn" -import { numberFormat } from "@/lib/utils/numbers" +import { formatPriceUSD, numberToPercent } from "@/lib/utils/numbers" import { Flex } from "./ui/flex" import { useGasEthPrice } from "@/hooks/useGasEthPrice" +import { useRtlFlip } from "@/hooks/useRtlFlip" import { useTranslation } from "@/hooks/useTranslation" const EthPriceCard = ({ @@ -21,17 +22,12 @@ const EthPriceCard = ({ }: React.HTMLAttributes) => { const locale = useLocale() const { t } = useTranslation() - const { ethPrice } = useGasEthPrice() + const { ethPrice, ethPercentChange24h } = useGasEthPrice() + const { twFlipForRtl } = useRtlFlip() const isLoading = ethPrice === 0 - - const formatPrice = (price: number) => - numberFormat(locale, { - style: "currency", - currency: "USD", - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }).format(price) + const hasChange = typeof ethPercentChange24h === "number" + const isNegativeChange = hasChange && ethPercentChange24h < 0 const tooltipContent = (
@@ -45,7 +41,10 @@ const EthPriceCard = ({ return ( -
+
{isLoading ? ( - + ) : ( - formatPrice(ethPrice) + formatPriceUSD(ethPrice, locale) )}
+ + {/* min-h-[33px] prevents jump when price loads */} + +
+ {isLoading ? ( + + ) : ( + hasChange && ( + + {numberToPercent(ethPercentChange24h, locale, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} + {isNegativeChange ? ( + + ) : ( + + )} + + ) + )} +
+
+ ({t("last-24-hrs")}) +
+
) } diff --git a/src/lib/utils/numbers.ts b/src/lib/utils/numbers.ts index dd79876310b..40a76cd1a20 100644 --- a/src/lib/utils/numbers.ts +++ b/src/lib/utils/numbers.ts @@ -80,8 +80,13 @@ export const formatPriceUSD = (value: number, locale: string): string => { }).format(value) } -export const numberToPercent = (num: number, locale: string): string => +export const numberToPercent = ( + num: number, + locale: string, + options?: Intl.NumberFormatOptions +): string => numberFormat(locale, { style: "percent", maximumFractionDigits: 0, + ...options, }).format(num) From 41cbb9b63d5fa46479d58e6a579501c22ecc01c9 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Sat, 2 May 2026 13:54:11 +0200 Subject: [PATCH 30/31] review feedback --- .claude/skills/page-visual-tests/SKILL.md | 4 +++- .../StakingProductsCardGrid/useStakingProductsCardGrid.ts | 4 ++-- src/lib/utils/apps.ts | 8 ++++---- src/lib/utils/random.ts | 2 +- src/lib/utils/wallets.ts | 6 +++--- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.claude/skills/page-visual-tests/SKILL.md b/.claude/skills/page-visual-tests/SKILL.md index 331a72027d2..b296cfda48a 100644 --- a/.claude/skills/page-visual-tests/SKILL.md +++ b/.claude/skills/page-visual-tests/SKILL.md @@ -62,7 +62,9 @@ test.describe("Page Visual Tests", () => { **Adding a page.** Each entry costs three snapshots (one per viewport) against Chromatic's budget, so check whether the page's layout (under `src/layouts/`) is already covered before adding. Scan the page subtree for bespoke loaders — they're the single biggest flake cause — and confirm full-page height stays under the 25M-pixel budget. Local loop: `pnpm test:visual:build` once, then `pnpm test:visual:desktop` for iteration, `pnpm test:visual` for the full sweep. -**Flaky snapshot.** Two main causes. (1) A loader without `data-slot="loading"` — run with `--trace=on` and inspect the `waitForFunction` step; ~0 ms duration means it isn't being waited on. (2) Random ordering — grep the page subtree for `shuffle(`, `Math.random()`, or `.sort(() =>` and route through `maybeShuffle`. If dynamic content is drifting, double-check `USE_MOCK_DATA=true` is set in both build and test steps. +**Flaky snapshot.** Two main causes. (1) A loader without `data-slot="loading"` — run with `--trace=on` and inspect the `waitForFunction` step; ~0 ms duration means it isn't being waited on. (2) Random ordering — grep the page subtree for `shuffle(`, `Math.random()`, or `.sort(() =>` and route through `safeShuffle`. If dynamic content is drifting, double-check `USE_MOCK_DATA=true` is set in both build and test steps. + +**Local `pnpm dev` masks a regression.** `playwright.visual.config.ts` sets `reuseExistingServer: true`, which is correct for CI but means a `pnpm dev` already running on :3000 will be used silently in place of the production build the suite assumes. If a snapshot diff doesn't reproduce in CI, kill the dev server and run `pnpm test:visual:build` to rebuild against the production output before retrying. **Pixel-limit error.** Measure the page's full-page height at 1024 px; if it exceeds ~24,400 px, the page needs shortening or removal from the suite. Cropping to viewport was considered and rejected — it defeats the below-the-fold regression coverage that justifies using Playwright over Storybook here. diff --git a/src/components/Staking/StakingProductsCardGrid/useStakingProductsCardGrid.ts b/src/components/Staking/StakingProductsCardGrid/useStakingProductsCardGrid.ts index 86c5f1509a8..23bce439b16 100644 --- a/src/components/Staking/StakingProductsCardGrid/useStakingProductsCardGrid.ts +++ b/src/components/Staking/StakingProductsCardGrid/useStakingProductsCardGrid.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from "react" -import { maybeShuffle } from "@/lib/utils/random" +import { safeShuffle } from "@/lib/utils/random" import stakingProducts from "@/data/staking-products.json" @@ -111,7 +111,7 @@ export const useStakingProductsCardGrid = ({ } updateRankedProducts( - maybeShuffle(products) + safeShuffle(products) .map((product) => ({ ...product, rankingScore: getRankingScore(product), diff --git a/src/lib/utils/apps.ts b/src/lib/utils/apps.ts index 22056d76695..f2ba0d9a927 100644 --- a/src/lib/utils/apps.ts +++ b/src/lib/utils/apps.ts @@ -3,7 +3,7 @@ import { AppCategory, AppCategoryEnum, AppData } from "@/lib/types" import { TagProps } from "@/components/ui/tag" import { getValidDate } from "@/lib/utils/date" -import { maybeShuffle } from "@/lib/utils/random" +import { safeShuffle } from "@/lib/utils/random" // Get highlighted apps (apps with highlight=true) export const getHighlightedApps = ( @@ -15,7 +15,7 @@ export const getHighlightedApps = ( ? appsData[category] : Object.values(appsData).flatMap((categoryApps) => categoryApps) - const highlightedApps = maybeShuffle( + const highlightedApps = safeShuffle( appsToFilter.filter((app) => app.highlight) ) @@ -27,7 +27,7 @@ export const getDiscoverApps = ( appsData: Record, count?: number ) => { - const discoverApps = maybeShuffle( + const discoverApps = safeShuffle( Object.values(appsData) .flatMap((categoryDapps) => categoryDapps) .filter((app) => app.discover) @@ -52,7 +52,7 @@ export const parseAppsOfTheWeek = ( ) => { const currentDate = new Date() - const appsOfTheWeek = maybeShuffle( + const appsOfTheWeek = safeShuffle( Object.values(appsData) .flatMap((categoryApps) => categoryApps) .filter((app) => { diff --git a/src/lib/utils/random.ts b/src/lib/utils/random.ts index 021d69ba73b..ede24aa29ca 100644 --- a/src/lib/utils/random.ts +++ b/src/lib/utils/random.ts @@ -3,7 +3,7 @@ import { shuffle } from "lodash" // Visual test builds set IS_VISUAL_TEST=true to keep list order deterministic // across runs. Not tied to USE_MOCK_DATA, which is also used by unit tests and // local dev with mocked storage. -export const maybeShuffle = (list: T[]): T[] => +export const safeShuffle = (list: T[]): T[] => process.env.IS_VISUAL_TEST === "true" ? list : shuffle(list) /** diff --git a/src/lib/utils/wallets.ts b/src/lib/utils/wallets.ts index ebbaa6c5d90..b7570babc33 100644 --- a/src/lib/utils/wallets.ts +++ b/src/lib/utils/wallets.ts @@ -1,7 +1,7 @@ import { union } from "lodash" import { getLanguageCodeName } from "@/lib/utils/intl" -import { maybeShuffle } from "@/lib/utils/random" +import { safeShuffle } from "@/lib/utils/random" import { capitalize } from "@/lib/utils/string" import { newToCrypto } from "@/data/wallets/new-to-crypto" @@ -23,14 +23,14 @@ import type { } from "../types" export const getSupportedLocaleWallets = (locale: string) => - maybeShuffle( + safeShuffle( walletsData.filter((wallet) => wallet.languages_supported.includes(locale as WalletLanguage) ) ) export const getNonSupportedLocaleWallets = (locale: string) => - maybeShuffle( + safeShuffle( walletsData.filter( (wallet) => !wallet.languages_supported.includes(locale as WalletLanguage) ) From d64d2f3cbc0ab0d1fab356d41a250ca294242bd2 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Sat, 2 May 2026 14:01:40 +0200 Subject: [PATCH 31/31] regenerate lock file --- pnpm-lock.yaml | 57 ++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 46 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db25b0f040c..7d536e5531e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -158,7 +158,7 @@ importers: version: 4.18.1 lucide-react: specifier: ^1.12.0 - version: 1.12.0(react@19.2.4) + version: 1.14.0(react@19.2.4) motion: specifier: ^12.36.0 version: 12.36.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -8448,8 +8448,8 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@1.12.0: - resolution: {integrity: sha512-rTKR3RN6HIAxdNZALoPvqxd64vjL9nTThU0JF9q1Qg8yUnmo1r+d8baN72YNVK3RGxUmzBzbd77IWJq/fkm+Xw==} + lucide-react@1.14.0: + resolution: {integrity: sha512-+1mdWcfSJVUsaTIjN9zoezmUhfXo5l0vP7ekBMPo3jcS/aIkxHnXqAPsByszMZx/Y8oQBRJxJx5xg+RH3urzxA==} peerDependencies: react: ^19.2.4 @@ -9414,10 +9414,6 @@ packages: resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.12: - resolution: {integrity: sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==} - engines: {node: ^10 || ^12 || >=14} - postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} @@ -13804,7 +13800,7 @@ snapshots: '@chromaui/rrweb-snapshot@2.0.0-alpha.18-noAbsolute': dependencies: - postcss: 8.5.12 + postcss: 8.5.10 '@clack/core@0.5.0': dependencies: @@ -19770,12 +19766,12 @@ snapshots: css-loader@7.1.4(webpack@5.99.9(@swc/core@1.15.24)(esbuild@0.25.12)): dependencies: - icss-utils: 5.1.0(postcss@8.5.12) - postcss: 8.5.12 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.12) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.12) - postcss-modules-scope: 3.2.1(postcss@8.5.12) - postcss-modules-values: 4.0.0(postcss@8.5.12) + icss-utils: 5.1.0(postcss@8.5.10) + postcss: 8.5.10 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.10) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.10) + postcss-modules-scope: 3.2.1(postcss@8.5.10) + postcss-modules-values: 4.0.0(postcss@8.5.10) postcss-value-parser: 4.2.0 semver: 7.7.4 optionalDependencies: @@ -21461,10 +21457,6 @@ snapshots: dependencies: postcss: 8.5.10 - icss-utils@5.1.0(postcss@8.5.12): - dependencies: - postcss: 8.5.12 - icu-minify@4.9.1: dependencies: '@formatjs/icu-messageformat-parser': 3.5.3 @@ -22071,7 +22063,7 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@1.12.0(react@19.2.4): + lucide-react@1.14.0(react@19.2.4): dependencies: react: 19.2.4 @@ -23327,10 +23319,6 @@ snapshots: dependencies: postcss: 8.5.10 - postcss-modules-extract-imports@3.1.0(postcss@8.5.12): - dependencies: - postcss: 8.5.12 - postcss-modules-local-by-default@4.2.0(postcss@8.5.10): dependencies: icss-utils: 5.1.0(postcss@8.5.10) @@ -23338,33 +23326,16 @@ snapshots: postcss-selector-parser: 7.1.0 postcss-value-parser: 4.2.0 - postcss-modules-local-by-default@4.2.0(postcss@8.5.12): - dependencies: - icss-utils: 5.1.0(postcss@8.5.12) - postcss: 8.5.12 - postcss-selector-parser: 7.1.0 - postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.1(postcss@8.5.10): dependencies: postcss: 8.5.10 postcss-selector-parser: 7.1.0 - postcss-modules-scope@3.2.1(postcss@8.5.12): - dependencies: - postcss: 8.5.12 - postcss-selector-parser: 7.1.0 - postcss-modules-values@4.0.0(postcss@8.5.10): dependencies: icss-utils: 5.1.0(postcss@8.5.10) postcss: 8.5.10 - postcss-modules-values@4.0.0(postcss@8.5.12): - dependencies: - icss-utils: 5.1.0(postcss@8.5.12) - postcss: 8.5.12 - postcss-selector-parser@7.1.0: dependencies: cssesc: 3.0.0 @@ -23384,12 +23355,6 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.12: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postgres-array@2.0.0: {} postgres-bytea@1.0.0: {}