diff --git a/.claude/skills/page-visual-tests/SKILL.md b/.claude/skills/page-visual-tests/SKILL.md new file mode 100644 index 00000000000..b296cfda48a --- /dev/null +++ b/.claude/skills/page-visual-tests/SKILL.md @@ -0,0 +1,73 @@ +--- +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. 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 + +```ts +import { takeSnapshot, test } from "@chromatic-com/playwright" + +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 } of pages) { + test(name, async ({ page }, testInfo) => { + await page.goto(path, { waitUntil: "domcontentloaded" }) + await page.waitForFunction( + () => document.querySelectorAll('[data-slot="loading"]').length === 0 + ) + await takeSnapshot(page, testInfo) + }) + } +}) +``` + +## 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.** 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. + +**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: diff --git a/.github/workflows/chromatic-pages.yml b/.github/workflows/chromatic-pages.yml new file mode 100644 index 00000000000..5a9bedf6b91 --- /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: [master, staging, "test/**"] + types: [opened, synchronize, ready_for_review] + workflow_dispatch: + +jobs: + playwright-visual: + name: Build & Capture Snapshots + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/playwright:v1.53.1-noble + steps: + - name: Checkout repo + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - 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 --frozen-lockfile + + - name: Build Next.js with mock data (English only) + run: pnpm build + env: + USE_MOCK_DATA: "true" + IS_VISUAL_TEST: "true" + NEXT_PUBLIC_BUILD_LOCALES: "en" + + - name: Run visual tests + run: pnpm test:visual + env: + HOME: /root + USE_MOCK_DATA: "true" + IS_VISUAL_TEST: "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 + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - 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 --frozen-lockfile + + - name: Download test results + uses: actions/download-artifact@v4 + with: + name: chromatic-archives + path: test-results/ + + - name: Publish to Chromatic + uses: chromaui/action@v16 + 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/app/[locale]/_components/HomepageLazy.tsx b/app/[locale]/_components/HomepageLazy.tsx index feba8b27deb..b1f5fd9dcd0 100644 --- a/app/[locale]/_components/HomepageLazy.tsx +++ b/app/[locale]/_components/HomepageLazy.tsx @@ -13,6 +13,7 @@ const Skeleton = ({ }) => (
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/next.config.js b/next.config.js index a3dbda3f666..5ab40c4448c 100644 --- a/next.config.js +++ b/next.config.js @@ -42,6 +42,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) => { config.module.rules.push({ diff --git a/package.json b/package.json index a21422b1120..3e458e2e5eb 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/**\"", "update-tutorials": "ts-node -O '{ \"module\": \"commonjs\" }' src/scripts/update-tutorials-list.ts", @@ -27,6 +28,9 @@ "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 --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 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" }, @@ -108,6 +112,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.visual.config.ts b/playwright.visual.config.ts new file mode 100644 index 00000000000..88ec54f88f3 --- /dev/null +++ b/playwright.visual.config.ts @@ -0,0 +1,46 @@ +import type { ChromaticConfig } from "@chromatic-com/playwright" +import { defineConfig } from "@playwright/test" + +import baseConfig from "./playwright.config" + +const visualUse: ChromaticConfig = { + disableAutoSnapshot: true, + 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, + + projects: [ + { + name: "chromatic-desktop", + 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, userAgent, viewport: { width: 1024, height: 720 } }, + }, + { + name: "chromatic-tablet", + testDir: "./tests/visual", + outputDir: "./test-results", + use: { ...visualUse, userAgent, viewport: { width: 768, height: 1024 } }, + }, + { + name: "chromatic-mobile", + testDir: "./tests/visual", + outputDir: "./test-results", + use: { ...visualUse, userAgent, viewport: { width: 375, height: 812 } }, + }, + ], + + webServer: { + command: "pnpm start", + port: 3000, + reuseExistingServer: true, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 584390c610d..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) @@ -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) @@ -300,7 +303,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 @@ -1645,8 +1648,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 @@ -2524,9 +2527,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==} @@ -2574,12 +2574,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'} @@ -4053,15 +4047,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==} @@ -4600,41 +4594,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: @@ -4644,43 +4608,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: @@ -4690,38 +4622,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: @@ -4740,38 +4645,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: @@ -4798,17 +4680,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: @@ -4822,13 +4693,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: @@ -4840,23 +4704,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'} @@ -5382,9 +5229,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==} @@ -5823,12 +5667,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: @@ -5892,9 +5730,6 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - algoliasearch@5.25.0: resolution: {integrity: sha512-n73BVorL4HIwKlfJKb4SEzAYkR3Buwfwbh+MYxg2mloFph2fFGV58E90QTzdbfzWrLn4HE5Czx/WTjI8fcHaMg==} engines: {node: '>= 14.0.0'} @@ -6112,10 +5947,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==} @@ -6157,9 +5988,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==} @@ -6174,9 +6002,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==} @@ -6869,10 +6694,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'} @@ -7100,10 +6921,6 @@ packages: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} - enhanced-resolve@5.21.0: - resolution: {integrity: sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==} - engines: {node: '>=10.13.0'} - entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} @@ -7152,9 +6969,6 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - es-module-lexer@2.1.0: - resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} - es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -7180,11 +6994,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'} @@ -7520,9 +7329,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==} @@ -7631,13 +7437,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'} @@ -7953,18 +7752,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==} @@ -8174,11 +7961,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} @@ -8321,10 +8103,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'} @@ -8394,10 +8172,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'} @@ -8606,10 +8380,6 @@ packages: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} - loader-runner@4.3.2: - resolution: {integrity: sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==} - engines: {node: '>=6.11.5'} - loader-utils@2.0.4: resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} engines: {node: '>=8.9.0'} @@ -8678,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 @@ -8707,9 +8477,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'} @@ -8820,9 +8587,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'} @@ -9000,9 +8764,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'} @@ -9306,10 +9067,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'} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -9657,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'} @@ -9906,11 +9659,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: @@ -10007,10 +9755,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==} @@ -10237,9 +9981,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'} @@ -10290,10 +10031,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==} @@ -10516,8 +10253,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 @@ -10525,8 +10262,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 @@ -10752,10 +10489,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'} @@ -10788,32 +10521,11 @@ packages: uglify-js: optional: true - terser-webpack-plugin@5.5.0: - resolution: {integrity: sha512-UYhptBwhWvfIjKd/UuFo6D8uq9xpGLDK+z8EDsj/zWhrTaH34cKEbrkMKfV5YWqGBvAYA3tlzZbs2R+qYrbQJA==} - 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.2: - resolution: {integrity: sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==} - engines: {node: '>=10'} - hasBin: true - text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -11123,10 +10835,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'} @@ -11372,10 +11080,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'} @@ -11402,23 +11106,9 @@ packages: resolution: {integrity: sha512-ykKKus8lqlgXX/1WjudpIEjqsafjOTcOJqxnAbMLAu/KCsDCJ6GBtvscewvTkrn24HsnvFwrSCbenFrhtcCsAA==} engines: {node: '>=10.13.0'} - webpack-sources@3.4.0: - resolution: {integrity: sha512-gHwIe1cgBvvfLeu1Yz/dcFpmHfKDVxxyqI+kzqmuxZED81z2ChxpyqPaWcNqigPywhaEke7AjSGga+kxY55gjQ==} - 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'} @@ -11617,11 +11307,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'} @@ -14085,36 +13770,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) @@ -14125,8 +13800,7 @@ snapshots: '@chromaui/rrweb-snapshot@2.0.0-alpha.18-noAbsolute': dependencies: - postcss: 8.5.12 - optional: true + postcss: 8.5.10 '@clack/core@0.5.0': dependencies: @@ -14814,12 +14488,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 @@ -14854,13 +14522,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: @@ -14898,13 +14564,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 @@ -16702,30 +16361,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: @@ -17529,32 +17186,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) @@ -17572,43 +17203,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 @@ -17616,48 +17210,12 @@ 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)': + '@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)) case-sensitive-paths-webpack-plugin: 2.4.0 @@ -17684,80 +17242,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.5.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) @@ -17767,40 +17256,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 @@ -17884,22 +17346,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) @@ -17920,13 +17366,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 @@ -17941,39 +17380,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 @@ -18525,9 +17931,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 @@ -19499,11 +18902,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 @@ -19537,11 +18935,6 @@ snapshots: optionalDependencies: ajv: 8.17.1 - ajv-formats@2.1.1(ajv@8.20.0): - optionalDependencies: - ajv: 8.20.0 - optional: true - ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -19555,12 +18948,6 @@ snapshots: ajv: 8.17.1 fast-deep-equal: 3.1.3 - ajv-keywords@5.1.0(ajv@8.20.0): - dependencies: - ajv: 8.20.0 - fast-deep-equal: 3.1.3 - optional: true - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -19575,14 +18962,6 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ajv@8.20.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 @@ -19836,11 +19215,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: {} @@ -19885,12 +19259,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 @@ -19905,9 +19273,6 @@ snapshots: brorand@1.1.0: {} - browser-assert@1.2.1: - optional: true - browserify-aes@1.2.0: dependencies: buffer-xor: 1.0.3 @@ -20136,13 +19501,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: {} @@ -20386,20 +19751,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.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: - 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.10) @@ -20633,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: @@ -20761,8 +20109,7 @@ snapshots: dotenv@16.6.1: {} - dset@3.1.4: - optional: true + dset@3.1.4: {} dunder-proto@1.0.1: dependencies: @@ -20898,12 +20245,6 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.2 - enhanced-resolve@5.21.0: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.3 - optional: true - entities@2.2.0: {} entities@4.5.0: {} @@ -21006,9 +20347,6 @@ snapshots: es-module-lexer@1.7.0: {} - es-module-lexer@2.1.0: - optional: true - es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -21046,14 +20384,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 @@ -21558,9 +20888,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 @@ -21671,24 +20998,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 @@ -22092,17 +21401,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 @@ -22323,9 +21621,6 @@ snapshots: is-decimal@2.0.1: {} - is-docker@2.2.1: - optional: true - is-docker@3.0.0: {} is-extendable@0.1.1: {} @@ -22441,11 +21736,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 @@ -22510,9 +21800,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsdoc-type-pratt-parser@4.8.0: - optional: true - jsesc@3.0.2: {} jsesc@3.1.0: {} @@ -22714,9 +22001,6 @@ snapshots: loader-runner@4.3.0: {} - loader-runner@4.3.2: - optional: true - loader-utils@2.0.4: dependencies: big.js: 5.2.2 @@ -22779,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 @@ -22809,9 +22093,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: @@ -23060,11 +22341,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: {} @@ -23399,11 +22675,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 @@ -23721,13 +22992,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 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -24091,13 +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 - optional: true - postgres-array@2.0.0: {} postgres-bytea@1.0.0: {} @@ -24319,12 +23576,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 @@ -24428,9 +23679,6 @@ snapshots: react@19.2.4: {} - react@19.2.5: - optional: true - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -24786,9 +24034,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 @@ -24827,14 +24072,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.20.0 - ajv-formats: 2.1.1(ajv@8.20.0) - ajv-keywords: 5.1.0(ajv@8.20.0) - optional: true - search-insights@2.17.3: {} section-matter@1.0.0: @@ -25154,7 +24391,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) @@ -25167,7 +24404,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: @@ -25177,16 +24414,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: @@ -25324,11 +24573,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) @@ -25417,9 +24661,6 @@ snapshots: tapable@2.3.2: {} - tapable@2.3.3: - optional: true - tar-stream@1.6.2: dependencies: bl: 1.2.3 @@ -25463,18 +24704,6 @@ snapshots: '@swc/core': 1.15.24 esbuild: 0.25.12 - terser-webpack-plugin@5.5.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.2 - 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 @@ -25482,14 +24711,6 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - terser@5.46.2: - 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: @@ -25884,12 +25105,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 @@ -26186,29 +25401,12 @@ 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: {} webidl-conversions@3.0.1: {} - 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 @@ -26227,43 +25425,8 @@ snapshots: webpack-sources@3.3.2: {} - webpack-sources@3.4.0: - 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.21.0 - es-module-lexer: 2.1.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.2 - mime-db: 1.54.0 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.3 - terser-webpack-plugin: 5.5.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.4.0 - 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 @@ -26402,7 +25565,6 @@ snapshots: optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 - optional: true wsl-utils@0.1.0: dependencies: @@ -26451,9 +25613,6 @@ snapshots: yaml@2.8.0: {} - yaml@2.8.3: - optional: true - yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 diff --git a/src/components/EthPriceCard.tsx b/src/components/EthPriceCard.tsx index 05c2a45eaf7..fb4528ae886 100644 --- a/src/components/EthPriceCard.tsx +++ b/src/components/EthPriceCard.tsx @@ -1,101 +1,33 @@ "use client" -import { useEffect, useState } from "react" import { ArrowDownRight, ArrowUpRight, 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 { 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" -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 { ethPrice, ethPercentChange24h } = useGasEthPrice() 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 hasError = "error" in state - const hasData = "data" in state - - const formatPrice = (price: string) => - 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) : "" + const isLoading = ethPrice === 0 + const hasChange = typeof ethPercentChange24h === "number" + const isNegativeChange = hasChange && ethPercentChange24h < 0 const tooltipContent = (
@@ -124,28 +56,40 @@ const EthPriceCard = ({ -
+ {isLoading ? ( + + ) : ( + formatPriceUSD(ethPrice, locale) )} - > - {price}
{/* min-h-[33px] prevents jump when price loads */} -
- {change} - {isNegativeChange ? ( - +
+ {isLoading ? ( + ) : ( - + hasChange && ( + + {numberToPercent(ethPercentChange24h, locale, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} + {isNegativeChange ? ( + + ) : ( + + )} + + ) )}
diff --git a/src/components/Staking/StakingProductsCardGrid/useStakingProductsCardGrid.ts b/src/components/Staking/StakingProductsCardGrid/useStakingProductsCardGrid.ts index 06d3815741c..23bce439b16 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 { safeShuffle } from "@/lib/utils/random" import stakingProducts from "@/data/staking-products.json" @@ -110,7 +111,7 @@ export const useStakingProductsCardGrid = ({ } updateRankedProducts( - shuffle(products) + safeShuffle(products) .map((product) => ({ ...product, rankingScore: getRankingScore(product), diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx index ea2eec850a6..5f4911bbe19 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/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" diff --git a/src/lib/utils/apps.ts b/src/lib/utils/apps.ts index 22c48d2a144..f2ba0d9a927 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 { safeShuffle } 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 = safeShuffle( + 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 = safeShuffle( + 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 = safeShuffle( + 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/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) diff --git a/src/lib/utils/random.ts b/src/lib/utils/random.ts index 8ea1e9fd813..ede24aa29ca 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 safeShuffle = (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 8c8607ab7ca..b7570babc33 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 { safeShuffle } from "@/lib/utils/random" import { capitalize } from "@/lib/utils/string" import { newToCrypto } from "@/data/wallets/new-to-crypto" @@ -22,14 +23,14 @@ import type { } from "../types" export const getSupportedLocaleWallets = (locale: string) => - shuffle( + safeShuffle( walletsData.filter((wallet) => wallet.languages_supported.includes(locale as WalletLanguage) ) ) export const getNonSupportedLocaleWallets = (locale: string) => - shuffle( + safeShuffle( walletsData.filter( (wallet) => !wallet.languages_supported.includes(locale as WalletLanguage) ) diff --git a/tests/visual/pages.spec.ts b/tests/visual/pages.spec.ts new file mode 100644 index 00000000000..975e65a7de9 --- /dev/null +++ b/tests/visual/pages.spec.ts @@ -0,0 +1,62 @@ +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 }> = [ + { 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: "/bridges/" }, // StaticLayout + { name: "Docs - Smart Contracts", path: "/developers/docs/smart-contracts/" }, // DocsLayout + { + name: "Tutorial - Hello World", + path: "/developers/tutorials/hello-world-smart-contract/", + }, // TutorialLayout + { 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 } of pages) { + test(name, async ({ page }, testInfo) => { + await page.goto(path, { waitUntil: "domcontentloaded" }) + 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 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 && img.naturalWidth > 0 && !img.style.backgroundImage + ) + ) + await takeSnapshot(page, testInfo) + }) + } +})