From f82709b2607f2df28ffb3de9b998d63b898abcc6 Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 11 Mar 2026 00:08:37 +0100 Subject: [PATCH 01/26] feat(storybook): add Phase 1 spec for Storybook 10 setup + story scaffolding Spec for issue #83 Phase 1: Storybook 10 initialization, configuration, and story scaffolding for all 100 components. Includes spike gate for SB10+React 19 compatibility, tiered next/* functional mocks, shared Vite config extraction, and compound component story refinement. --- specs/active/2026-03-10-storybook-setup.md | 356 +++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 specs/active/2026-03-10-storybook-setup.md diff --git a/specs/active/2026-03-10-storybook-setup.md b/specs/active/2026-03-10-storybook-setup.md new file mode 100644 index 0000000..6608c7d --- /dev/null +++ b/specs/active/2026-03-10-storybook-setup.md @@ -0,0 +1,356 @@ +--- +title: "Storybook 10 Setup + Story Scaffolding" +status: active +created: 2026-03-10 +estimate: 8-10h +tier: standard +issue: "#83 (Phase 1)" +--- + +# Storybook 10 Setup + Story Scaffolding + +## Context + +The @vllnt/ui component library (100 components) has no interactive documentation or playground. Developers rely on a 1700-line `component-preview.tsx` switch statement in the registry app and static Playwright CT snapshots. Storybook 10 provides interactive controls, auto-docs from TypeScript props, and a foundation for Chromatic visual testing and registry iframe embedding (future phases). + +This spec covers **Phase 1 only** of issue #83: Storybook 10 initialization, configuration, and story scaffolding for all 100 components. Phases 2-6 (deployment, Chromatic, registry embed, composition) are separate specs. + +## Codebase Impact (MANDATORY) + +| Area | Impact | Detail | +|------|--------|--------| +| `packages/ui/.storybook/main.ts` | CREATE | Storybook config: framework, addons, stories glob, Vite builder with PostCSS + path aliases + next/* stubs | +| `packages/ui/.storybook/preview.tsx` | CREATE | Global decorators: import styles.css + themes/default.css, ThemeProvider decorator (mounts next-themes + toggles .dark class) | +| `packages/ui/.storybook/next-stubs.ts` | CREATE | Functional mocks for next/* modules: Link→``, Image→``, useRouter→`{push,replace,back,...}`, usePathname→`/`, useSearchParams→empty | +| `packages/ui/.storybook/tsconfig.json` | CREATE | TypeScript config for Storybook builder (extends base) | +| `packages/ui/.storybook/vite-shared.ts` | CREATE | Shared Vite config (PostCSS + path aliases) reused by both Storybook and Playwright CT | +| `packages/ui/src/components/**/*.stories.tsx` | CREATE | Story files for 100 components — auto-generated from CVA variants | +| `scripts/generate-stories.ts` | CREATE | Story generator script (parallel to existing generate-tests.ts), `--force` flag skips files with `// manual` header | +| `packages/ui/package.json` | MODIFY | Add `storybook`, `build-storybook` scripts + storybook devDeps; add `storybook-static/` to clean script | +| `turbo.json` | MODIFY | Add `storybook` (persistent, filter: `@vllnt/ui`) and `build-storybook` (filter: `@vllnt/ui`) tasks | +| `packages/ui/tsup.config.ts` | MODIFY | Exclude `*.stories.tsx` from dist build | +| `packages/ui/eslint.config.js` | AFFECTED | May need storybook ESLint plugin or story file overrides | +| `packages/ui/src/components/**/*.visual.tsx` | AFFECTED | Coexist with stories — no changes, kept for Playwright CT | +| `packages/ui/playwright-ct.config.ts` | AFFECTED | Vite alias + PostCSS config extracted to shared vite-shared.ts | +| `styles.css` + `themes/default.css` | AFFECTED | Imported by Storybook preview — no changes needed | + +**Files:** 7 create | 3 modify | 4 affected +**Reuse:** Playwright CT Vite config extracted to shared module, existing `generate-tests.ts` pattern for story generator, CVA variant definitions for auto-Controls +**Breaking changes:** None — additive only +**New dependencies:** `storybook@10`, `@storybook/react-vite@10`, `@storybook/addon-essentials@10`, `@storybook/addon-a11y`, `@storybook/addon-themes` (all devDeps, standard Storybook stack) + +## User Journey (MANDATORY) + +### Primary Journey + +ACTOR: Component library developer +GOAL: Browse and interact with all @vllnt/ui components in Storybook +PRECONDITION: Repository cloned, dependencies installed + +1. Developer runs `pnpm storybook` from packages/ui + -> System starts Storybook dev server on localhost:6006 + -> Developer sees Storybook UI with sidebar listing all 100 components + +2. Developer clicks a component in sidebar (e.g., Button) + -> System renders Button story with default args + -> Developer sees live Button component with Controls panel showing CVA variants (size, variant) + +3. Developer changes variant in Controls panel (e.g., variant: "destructive", size: "lg") + -> System re-renders Button with new props in real-time + -> Developer sees updated component with correct Tailwind styles + +4. Developer toggles dark mode via toolbar + -> System applies `.dark` class and CSS variable overrides + -> Developer sees component in dark theme + +5. Developer clicks "Docs" tab + -> System shows auto-generated documentation from TypeScript props + -> Developer sees prop table, description, and all stories inline + +POSTCONDITION: All 100 components browsable with interactive controls, dark/light theme, and auto-docs + +### Error Journeys + +E1. Storybook fails to start (missing CSS/PostCSS) + Trigger: styles.css not imported or PostCSS not configured in Storybook Vite config + 1. Developer runs `pnpm storybook` + -> System shows build error: "Cannot resolve styles.css" or unstyled components + -> Developer sees error in terminal + 2. Developer checks `.storybook/preview.tsx` imports + -> System guides to CSS import fix + Recovery: Storybook restarts with correct CSS + +E2. Story file import error (component not found) + Trigger: Story imports from wrong path or component renamed + 1. Developer opens Storybook + -> System shows "Failed to fetch" or blank story + -> Developer sees red error overlay with stack trace + 2. Developer fixes import path in .stories.tsx + -> System hot-reloads story + Recovery: Story renders correctly + +E3. Build-storybook fails (TypeScript errors in stories) + Trigger: Story file has type errors that dev server ignores but build catches + 1. Developer runs `pnpm build-storybook` + -> System shows TypeScript error with file path and line number + -> Developer sees actionable error message + 2. Developer fixes type error in story file + -> System builds successfully + Recovery: Static Storybook build completes + +### Edge Cases + +EC1. Component with no CVA variants (e.g., Separator): Story renders default with no Controls +EC2. Compound components (Dialog, DropdownMenu): Story shows full composition with sub-components +EC3. Components requiring providers (ThemeProvider, next-themes): Decorator mounts next-themes ThemeProvider AND toggles `.dark` class on `document.documentElement` +EC4. Provider-dependent compounds (Sidebar→SidebarProvider, Toast→Toaster): Stories must wrap in required provider +EC5. Components with complex props (ReactNode children, render props): Args use template pattern +EC6. "use client" components: Storybook runs client-side, no SSR issues + +## Acceptance Criteria (MANDATORY) + +### Must Have (BLOCKING — all must pass to ship) + +- [ ] AC-1: GIVEN packages/ui with Storybook configured WHEN developer runs `pnpm storybook` THEN Storybook dev server starts on localhost:6006 without errors +- [ ] AC-2: GIVEN Storybook running WHEN developer opens sidebar THEN all 100 components are listed and navigable +- [ ] AC-3: GIVEN a component story (e.g., Button) WHEN developer views it THEN component renders with correct Tailwind styles and CSS variables +- [ ] AC-4: GIVEN a component with CVA variants WHEN developer opens Controls panel THEN all variants are interactive (dropdown/radio for each variant prop) +- [ ] AC-5: GIVEN Storybook toolbar WHEN developer toggles dark mode THEN component re-renders with dark theme CSS variables +- [ ] AC-6: GIVEN any component story WHEN developer clicks Docs tab THEN auto-generated prop table is shown with types from TypeScript +- [ ] AC-7: GIVEN the project WHEN developer runs `pnpm build-storybook` THEN static Storybook builds to `storybook-static/` without errors + +### Error Criteria (BLOCKING — all must pass) + +- [ ] AC-E1: GIVEN Storybook config WHEN styles.css or theme CSS is missing THEN build fails with clear error message pointing to the missing import +- [ ] AC-E2: GIVEN a story with wrong import path WHEN Storybook loads THEN error overlay shows file path and specific import that failed +- [ ] AC-E3: GIVEN story files with TypeScript errors WHEN `build-storybook` runs THEN errors are reported with file:line and actionable message + +- [ ] AC-8: GIVEN compound components (Dialog, Sheet, DropdownMenu, Sidebar, Toast — top 5) WHEN stories render THEN full composition with sub-components + required providers is shown +- [ ] AC-9: GIVEN components importing next/* (breadcrumb, blog-card, navbar-saas, pagination, sidebar, etc.) WHEN Storybook renders THEN next-stubs provide functional mocks (Link navigates, Image renders, useRouter returns mock router) + +### Should Have (ship without, fix soon) + +- [ ] AC-10: GIVEN the `generate-stories.ts` script WHEN developer runs `pnpm storybook:generate` THEN story stubs are created for components missing stories (skips files with `// manual` header) +- [ ] AC-11: GIVEN compound components beyond top 5 WHEN stories render THEN full composition with sub-components is shown + +## Scope + +- [ ] 0. **GATE**: 1h spike — verify SB10 + React 19 + all addons install cleanly in packages/ui, resolve any peer dep conflicts -> Kill criteria gate +- [ ] 1. Initialize Storybook 10 with React-Vite framework -> AC-1, AC-E1 +- [ ] 2. Create next-stubs.ts with functional mocks (Link→``, Image→``, useRouter→mock router, usePathname→`/`, useSearchParams→empty URLSearchParams) -> AC-9 +- [ ] 3. Extract shared Vite config (PostCSS + aliases) from playwright-ct.config.ts to .storybook/vite-shared.ts, update both configs -> DRY +- [ ] 4. Configure .storybook/preview.tsx with CSS imports + ThemeProvider decorator (mount next-themes + toggle .dark class) -> AC-3, AC-5 +- [ ] 5. Configure .storybook/main.ts with stories glob + addons + next/* Vite aliases -> AC-2, AC-6, AC-9 +- [ ] 6. Exclude *.stories.tsx from tsup build -> AC-7 +- [ ] 7. Add storybook scripts to package.json (incl. storybook-static/ in clean) + turbo.json (filter: @vllnt/ui) -> AC-1, AC-7 +- [ ] 8. Create story generator script (generate-stories.ts) with --force overwrite protection -> AC-10 +- [ ] 9. Generate stories for all 100 components with CVA variant args -> AC-2, AC-4 +- [ ] 10. Manually refine top 5 compound stories (Dialog, Sheet, DropdownMenu, Sidebar, Toast) with providers -> AC-8 +- [ ] 11. Verify build-storybook produces static output -> AC-7, AC-E3 + +### Out of Scope + +- Storybook deployment (storybook.vllnt.com) — Phase 3 +- Chromatic visual testing — Phase 4 +- Registry iframe embedding — Phase 5 +- Storybook composition for consumers — Phase 6 +- Converting .visual.tsx to stories — coexist, don't migrate +- Custom Storybook theme/branding — nice-to-have, not Phase 1 + +## Quality Checklist + +### Blocking (must pass to ship) + +- [ ] All Must Have ACs passing +- [ ] All Error Criteria ACs passing +- [ ] All scope items implemented +- [ ] No regressions in existing tests (vitest + playwright CT) +- [ ] Error states handled (not just happy path) +- [ ] No hardcoded secrets or credentials +- [ ] `pnpm storybook` starts without errors +- [ ] `pnpm build-storybook` completes without errors +- [ ] All 100 components appear in Storybook sidebar +- [ ] Dark/light theme toggle works for all stories +- [ ] tsup build still excludes stories from dist/ +- [ ] next/* stub components render without errors for all 9 affected components +- [ ] Existing Playwright CT tests still pass (shared Vite config refactor) + +### Advisory (should pass, not blocking) + +- [ ] All Should Have ACs passing +- [ ] Story files follow component directory convention ({name}.stories.tsx) +- [ ] Controls panel shows meaningful labels (not raw prop names) +- [ ] Auto-docs prop table renders complete TypeScript types +- [ ] generate-stories.ts --force respects `// manual` header (no overwrite) + +## Test Strategy (MANDATORY) + +### Test Environment + +| Component | Status | Detail | +|-----------|--------|--------| +| Test runner | Detected | Vitest 4.0.16 (jsdom, globals) | +| E2E framework | Detected | Playwright CT 1.57.0 (chromium snapshots) | +| Test DB | N/A | No database | +| Mock inventory | Minimal | vi.useFakeTimers() only, no API mocks | + +### AC -> Test Mapping + +| AC | Test Type | Test Intention | +|----|-----------|----------------| +| AC-1 | E2E (process) | `pnpm storybook` starts, HTTP 200 on localhost:6006 | +| AC-2 | E2E (browser) | Storybook sidebar lists all 100 component names | +| AC-3 | E2E (browser) | Button story renders with Tailwind classes applied | +| AC-4 | E2E (browser) | Changing variant Control updates rendered component | +| AC-5 | E2E (browser) | Toggling dark mode applies .dark class and CSS vars | +| AC-6 | E2E (browser) | Docs tab shows prop table with TypeScript types | +| AC-7 | Unit (process) | `pnpm build-storybook` exits 0, storybook-static/ exists | +| AC-E1 | Unit (build) | Missing CSS import causes build failure with clear message | +| AC-E2 | E2E (browser) | Wrong import shows error overlay with file path | +| AC-E3 | Unit (build) | TS error in story causes build failure with file:line | + +### Failure Mode Tests (MANDATORY) + +| Source | ID | Test Intention | Priority | +|--------|----|----------------|----------| +| Error Journey | E1 | Build: verify CSS import is present and Tailwind processes correctly | BLOCKING | +| Error Journey | E2 | E2E: story with bad import shows error overlay (not blank page) | BLOCKING | +| Error Journey | E3 | Build: TS error in story produces actionable build error | BLOCKING | +| Edge Case | EC1 | E2E: Separator story (no CVA) renders without Controls crash | Advisory | +| Edge Case | EC2 | E2E: Dialog compound story shows all sub-components | Advisory | +| Failure Hypothesis | FH-1 (HIGH) | Build: verify tsup excludes *.stories.tsx from dist | BLOCKING | +| Failure Hypothesis | FH-2 (MED) | E2E: next-themes ThemeProvider works in Storybook (no Next.js context) | BLOCKING | +| Failure Hypothesis | FH-3 (MED) | Build: storybook addons resolve without version conflicts (validated by spike gate) | BLOCKING | +| Failure Hypothesis | FH-4 (HIGH) | E2E: next/* stubs (useRouter, useSearchParams) provide functional returns, not just empty aliases | BLOCKING | +| Failure Hypothesis | FH-5 (MED) | E2E: provider-dependent components (Sidebar, Toast) render when wrapped in required provider decorator | BLOCKING | +| Failure Hypothesis | FH-6 (MED) | Build: shared Vite config refactor doesn't break existing Playwright CT tests | BLOCKING | + +### Mock Boundary + +| Dependency | Strategy | Justification | +|------------|----------|---------------| +| next-themes | Mount in decorator | ThemeProvider mounted in preview decorator + manual `.dark` class toggle on `document.documentElement` | +| next/link | Functional stub → `` | Passive consumer — renders as anchor tag with href passthrough | +| next/image | Functional stub → `` | Passive consumer — renders as img with src/alt/width/height passthrough | +| next/navigation (useRouter) | Functional mock | Active consumer — returns `{push: console.log, replace: console.log, back: console.log, forward: console.log, refresh: noop, prefetch: noop}` | +| next/navigation (usePathname) | Functional mock | Returns `"/"` — static default sufficient for story rendering | +| next/navigation (useSearchParams) | Functional mock | Returns `new URLSearchParams()` — empty params for story context | +| @xyflow/react | Real | Works standalone, no server dependency | +| embla-carousel | Real | Client-only, works in Storybook | + +### TDD Commitment + +All tests written BEFORE implementation (RED -> GREEN -> REFACTOR). +Every Must Have + Error AC tracked in e2e-scenarios registry. + +## Risks + +| Risk | Impact | Likelihood | Mitigation | +|------|--------|------------|------------| +| Storybook 10 + React 19 + addon compatibility | HIGH | MED | **Scope item 0 (spike gate)**: 1h install + verify before any config work. Kill criteria if unresolvable in <2h. | +| next-themes ThemeProvider fails outside Next.js | MED | MED | Decorator mounts ThemeProvider AND manually toggles `.dark` class — dual strategy covers both CSS var and class-based theming | +| next/* stubs return wrong shape, components crash | HIGH | MED | Functional mocks with correct return types. Tiered: passive (Link→``, Image→``) vs active (useRouter→mock object). Test each of 9 affected components. | +| Provider-dependent components render blank | MED | HIGH | Identify all provider deps (Sidebar→SidebarProvider, Toast→Toaster, etc.) during story generation. Wrap in provider decorator per component. | +| Story generator misses component variants | MED | LOW | Cross-check against component-preview.tsx switch cases. Manual refinement pass. | +| Story generator --force overwrites manual refinements | MED | MED | `--force` skips files with `// manual` header comment. Default mode skips existing files entirely. | +| Storybook devDeps bloat (SB is large) | LOW | HIGH | devDeps only, not in published package. Monitor install size. | +| PostCSS/Tailwind config mismatch between Playwright CT and Storybook | MED | LOW | Extract shared Vite config to `vite-shared.ts`, both configs import from single source | +| Shared Vite config refactor breaks Playwright CT | MED | LOW | Run existing Playwright CT suite after refactor as regression check | +| pnpm-lock.yaml change triggers unwanted canary publish | MED | HIGH | turbo `build-storybook` task scoped to `@vllnt/ui` only; storybook-static/ excluded from dist; no publish path changes | + +**Kill criteria:** If Storybook 10 has blocking incompatibility with React 19 or Tailwind 3 that can't be resolved in <2h (scope item 0 spike), fall back to Storybook 9. + +## State Machine + +**Status**: N/A — Stateless feature + +**Rationale**: Storybook setup is a static configuration + code generation task. No persistent state transitions, no user state management. Build -> output. + +## Analysis + +### Assumptions Challenged + +| Assumption | Evidence For | Evidence Against | Verdict | +|------------|-------------|-----------------|---------| +| Storybook 10 supports React 19 | SB10 release notes list React 19 support, ESM-only aligns with React 19 | React 19 is bleeding edge, some SB addons may lag | RISKY — spike gate (scope 0) validates before committing | +| CVA variants can auto-generate Storybook Controls | CVA exports variant types, SB `argTypes` can map to enum Controls | CVA uses complex TypeScript types that SB may not auto-detect | RISKY — may need explicit argTypes mapping | +| next-themes ThemeProvider works in Storybook | It's a React context, should work anywhere | It expects Next.js `` attribute management, may fail headless | MITIGATED — dual strategy: mount ThemeProvider + manual .dark toggle | +| next/* stubs are sufficient as empty aliases | Simple aliasing pattern, works for passive consumers | Active consumers (useRouter, useSearchParams) need functional return values, not empty modules | INVALID — need tiered functional mocks | +| 100 stories can be auto-generated | generate-tests.ts already does variant extraction + template generation | Stories need more nuance (composition, children, interactions, provider wrapping) | VALID for scaffolding, manual refinement needed for compounds + provider-deps | +| Existing PostCSS/Tailwind config works in Storybook | Playwright CT uses identical Vite + PostCSS setup successfully | Storybook Vite builder may handle PostCSS differently | VALID — both use Vite, extracted to shared config | +| All components render standalone | Most are pure UI | Sidebar needs SidebarProvider, Toast needs Toaster wrapper | PARTIALLY VALID — must enumerate provider-dependent components | + +### Blind Spots + +1. **[Integration]** Components importing from `next/image`, `next/link`, or other Next.js modules will fail in Storybook without aliases or mocks. + Why it matters: 9 components use next/* — need tiered functional stubs, not empty aliases. Active consumers (useRouter, useSearchParams) must return correct shapes. + +2. **[Integration]** Provider-dependent components (Sidebar→SidebarProvider, Toast→Toaster) render blank without their context provider. + Why it matters: Stories silently render nothing — no error, just empty canvas. Must enumerate and wrap all provider-dependent components. + +3. **[Performance]** Loading 100 component stories in dev mode may be slow on initial load. Storybook lazy-loads, but the story index build could be heavy. + Why it matters: Slow dev startup kills DX — the whole point of Storybook. + +4. **[Maintenance]** No automated check that new components get stories. Easy to add a component and forget the story. + Why it matters: Story coverage will degrade over time without enforcement (Phase 2+ concern). + +5. **[CI]** pnpm-lock.yaml changes from storybook devDeps may trigger canary publish workflow. `build-storybook` output must not leak into publish paths. + Why it matters: False canary publishes waste CI time and confuse consumers. + +### Failure Hypotheses + +| IF | THEN | BECAUSE | Severity | Mitigation | +|----|------|---------|----------|------------| +| Components import `next/image` or `next/link` | Storybook build fails with module not found | Next.js modules unavailable outside Next.js runtime | HIGH | Tiered Vite aliases in main.ts: passive (Link→``, Image→``), active (useRouter→mock router object with push/replace/back) | +| useRouter/useSearchParams stubs return wrong shape | Component crashes at runtime (not build) | Active consumers call `.push()`, `.get()` etc. on returned objects | HIGH | Functional mocks return correct TypeScript-compliant shapes. Test all 9 affected components individually. | +| next-themes ThemeProvider is used as decorator | Theme toggle doesn't work or SSR error | next-themes expects Next.js Script/html attribute injection | MED | Dual strategy: mount ThemeProvider in decorator AND manually toggle `.dark` class on `document.documentElement` | +| Provider-dependent components (Sidebar, Toast) render blank | Story shows empty canvas, no error | Component reads from React context that doesn't exist | MED | Enumerate provider-deps during story gen. Wrap in provider decorator. Add FH-5 test. | +| Storybook devDeps conflict with existing deps | pnpm install fails or version resolution error | SB10 may pin specific React/React-DOM versions conflicting with workspace | MED | Spike gate (scope 0) catches this before any config work. Use `pnpm.overrides` if needed. | +| Shared Vite config refactor breaks Playwright CT | Existing visual snapshot tests fail | Config extraction changes import paths or build behavior | MED | Run full Playwright CT suite after refactor. Rollback if regressions. | +| generate-stories --force overwrites manually refined stories | Manual work lost | No protection for hand-edited story files | MED | `--force` skips files with `// manual` header. Default mode never overwrites existing files. | + +### The Real Question + +Confirmed — spec solves the right problem. The library needs interactive documentation. Storybook is the industry standard. The existing generate-tests.ts pattern proves the team already automates per-component scaffolding, making story generation a natural extension. Phase 1 (setup + scaffold) is the correct first step before deployment or visual testing phases. + +### Component Classification + +**Tier 1 — Pure UI** (no external deps): Button, Badge, Card, Input, Separator, etc. (~85 components) +**Tier 2 — Passive next/* consumers** (Link, Image only): breadcrumb, blog-card, navbar-saas, pagination, profile-section (~5 components) +**Tier 3 — Active next/* consumers** (useRouter, usePathname, useSearchParams): category-filter, lang-provider, search-bar, sidebar, view-switcher (~4-5 components) +**Tier 4 — Provider-dependent**: Sidebar→SidebarProvider, Toast→Toaster (enumerate during scope 9) + +### Open Items + +- [resolved] 9 components import from `next/` → addressed: tiered functional mocks in next-stubs.ts (scope 2) +- [resolved] Addon compatibility risk → addressed: spike gate (scope 0) +- [resolved] Story overwrite risk → addressed: `// manual` header protection (scope 8) +- [improvement] CI check that every component has a .stories.tsx -> no action (Phase 2+ concern) +- [question] Should story generator reuse component-preview.tsx demo logic or start fresh? -> explore at implementation +- [question] Full list of provider-dependent components → enumerate during scope 9 story generation + +## Notes + +## Progress + +| # | Scope Item | Status | Iteration | +|---|-----------|--------|-----------| +| 0 | Spike: SB10 + React 19 + addons | pending | - | +| 1 | Initialize Storybook 10 | pending | - | +| 2 | Create next-stubs.ts | pending | - | +| 3 | Extract shared Vite config | pending | - | +| 4 | Configure preview.tsx | pending | - | +| 5 | Configure main.ts + next/* aliases | pending | - | +| 6 | Exclude stories from tsup | pending | - | +| 7 | Add scripts + turbo.json (scoped) | pending | - | +| 8 | Create story generator (--force protection) | pending | - | +| 9 | Generate all 100 stories | pending | - | +| 10 | Refine top 5 compound stories | pending | - | +| 11 | Verify build-storybook | pending | - | + +## Timeline + +| Action | Timestamp | Duration | Notes | +|--------|-----------|----------|-------| +| plan | 2026-03-10T16:50:00Z | - | Created from issue #83 Phase 1 | +| spec-review | 2026-03-10T17:30:00Z | - | 4-perspective adversarial review, 10 findings applied | From ec9f14bec6969154aed816776c839281a501ec61 Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:06:57 +0100 Subject: [PATCH 02/26] feat(storybook): add test-runner, designs, MCP addons + story coverage check - Add @storybook/test-runner, @storybook/addon-designs, @storybook/addon-mcp - Add check-story-coverage.ts CI script ensuring 100% story coverage - Promote story coverage enforcement to Must Have (AC-10) - Expand scope to 14 items (0-12 + 8b) --- specs/active/2026-03-10-storybook-setup.md | 36 ++++++++++++++-------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/specs/active/2026-03-10-storybook-setup.md b/specs/active/2026-03-10-storybook-setup.md index 6608c7d..1c0d715 100644 --- a/specs/active/2026-03-10-storybook-setup.md +++ b/specs/active/2026-03-10-storybook-setup.md @@ -26,18 +26,19 @@ This spec covers **Phase 1 only** of issue #83: Storybook 10 initialization, con | `packages/ui/.storybook/vite-shared.ts` | CREATE | Shared Vite config (PostCSS + path aliases) reused by both Storybook and Playwright CT | | `packages/ui/src/components/**/*.stories.tsx` | CREATE | Story files for 100 components — auto-generated from CVA variants | | `scripts/generate-stories.ts` | CREATE | Story generator script (parallel to existing generate-tests.ts), `--force` flag skips files with `// manual` header | -| `packages/ui/package.json` | MODIFY | Add `storybook`, `build-storybook` scripts + storybook devDeps; add `storybook-static/` to clean script | -| `turbo.json` | MODIFY | Add `storybook` (persistent, filter: `@vllnt/ui`) and `build-storybook` (filter: `@vllnt/ui`) tasks | +| `scripts/check-story-coverage.ts` | CREATE | CI script: scans src/components/*/index.ts, fails if any component dir lacks a .stories.tsx file | +| `packages/ui/package.json` | MODIFY | Add `storybook`, `build-storybook`, `test-storybook` scripts + storybook devDeps; add `storybook-static/` to clean script | +| `turbo.json` | MODIFY | Add `storybook` (persistent, filter: `@vllnt/ui`), `build-storybook`, and `test-storybook` (filter: `@vllnt/ui`) tasks | | `packages/ui/tsup.config.ts` | MODIFY | Exclude `*.stories.tsx` from dist build | | `packages/ui/eslint.config.js` | AFFECTED | May need storybook ESLint plugin or story file overrides | | `packages/ui/src/components/**/*.visual.tsx` | AFFECTED | Coexist with stories — no changes, kept for Playwright CT | | `packages/ui/playwright-ct.config.ts` | AFFECTED | Vite alias + PostCSS config extracted to shared vite-shared.ts | | `styles.css` + `themes/default.css` | AFFECTED | Imported by Storybook preview — no changes needed | -**Files:** 7 create | 3 modify | 4 affected +**Files:** 8 create | 3 modify | 4 affected **Reuse:** Playwright CT Vite config extracted to shared module, existing `generate-tests.ts` pattern for story generator, CVA variant definitions for auto-Controls **Breaking changes:** None — additive only -**New dependencies:** `storybook@10`, `@storybook/react-vite@10`, `@storybook/addon-essentials@10`, `@storybook/addon-a11y`, `@storybook/addon-themes` (all devDeps, standard Storybook stack) +**New dependencies:** `storybook@10`, `@storybook/react-vite@10`, `@storybook/addon-essentials@10`, `@storybook/addon-a11y`, `@storybook/addon-themes`, `@storybook/addon-mcp`, `@storybook/test-runner`, `@storybook/addon-designs` (all devDeps) ## User Journey (MANDATORY) @@ -130,23 +131,26 @@ EC6. "use client" components: Storybook runs client-side, no SSR issues ### Should Have (ship without, fix soon) -- [ ] AC-10: GIVEN the `generate-stories.ts` script WHEN developer runs `pnpm storybook:generate` THEN story stubs are created for components missing stories (skips files with `// manual` header) -- [ ] AC-11: GIVEN compound components beyond top 5 WHEN stories render THEN full composition with sub-components is shown +- [ ] AC-10: GIVEN a component directory under src/components/ WHEN it exports a component THEN a corresponding .stories.tsx file exists (enforced by CI check) +- [ ] AC-11: GIVEN the `generate-stories.ts` script WHEN developer runs `pnpm storybook:generate` THEN story stubs are created for components missing stories (skips files with `// manual` header) +- [ ] AC-12: GIVEN compound components beyond top 5 WHEN stories render THEN full composition with sub-components is shown ## Scope -- [ ] 0. **GATE**: 1h spike — verify SB10 + React 19 + all addons install cleanly in packages/ui, resolve any peer dep conflicts -> Kill criteria gate +- [ ] 0. **GATE**: 1h spike — verify SB10 + React 19 + all addons (essentials, a11y, themes, MCP, test-runner, designs) install cleanly in packages/ui, resolve any peer dep conflicts -> Kill criteria gate - [ ] 1. Initialize Storybook 10 with React-Vite framework -> AC-1, AC-E1 - [ ] 2. Create next-stubs.ts with functional mocks (Link→``, Image→``, useRouter→mock router, usePathname→`/`, useSearchParams→empty URLSearchParams) -> AC-9 - [ ] 3. Extract shared Vite config (PostCSS + aliases) from playwright-ct.config.ts to .storybook/vite-shared.ts, update both configs -> DRY - [ ] 4. Configure .storybook/preview.tsx with CSS imports + ThemeProvider decorator (mount next-themes + toggle .dark class) -> AC-3, AC-5 -- [ ] 5. Configure .storybook/main.ts with stories glob + addons + next/* Vite aliases -> AC-2, AC-6, AC-9 +- [ ] 5. Configure .storybook/main.ts with stories glob + addons (essentials, a11y, themes, MCP, designs) + next/* Vite aliases -> AC-2, AC-6, AC-9 - [ ] 6. Exclude *.stories.tsx from tsup build -> AC-7 - [ ] 7. Add storybook scripts to package.json (incl. storybook-static/ in clean) + turbo.json (filter: @vllnt/ui) -> AC-1, AC-7 -- [ ] 8. Create story generator script (generate-stories.ts) with --force overwrite protection -> AC-10 +- [ ] 8. Create story generator script (generate-stories.ts) with --force overwrite protection -> AC-11 +- [ ] 8b. Create story coverage check script (check-story-coverage.ts) + add `check:stories` to package.json + turbo lint pipeline -> AC-10 - [ ] 9. Generate stories for all 100 components with CVA variant args -> AC-2, AC-4 - [ ] 10. Manually refine top 5 compound stories (Dialog, Sheet, DropdownMenu, Sidebar, Toast) with providers -> AC-8 -- [ ] 11. Verify build-storybook produces static output -> AC-7, AC-E3 +- [ ] 11. Add `test-storybook` script + configure @storybook/test-runner -> smoke test all stories +- [ ] 12. Verify build-storybook produces static output -> AC-7, AC-E3 ### Out of Scope @@ -156,6 +160,9 @@ EC6. "use client" components: Storybook runs client-side, no SSR issues - Storybook composition for consumers — Phase 6 - Converting .visual.tsx to stories — coexist, don't migrate - Custom Storybook theme/branding — nice-to-have, not Phase 1 +- @storybook/addon-mcp advanced configuration (custom toolsets, CI integration) — installed + default config only in Phase 1 +- @storybook/addon-designs Figma file linking per story — installed, configure per-component in Phase 2+ +- @storybook/test-runner CI integration (run in GitHub Actions) — installed + local smoke test only in Phase 1 ## Quality Checklist @@ -170,6 +177,7 @@ EC6. "use client" components: Storybook runs client-side, no SSR issues - [ ] `pnpm storybook` starts without errors - [ ] `pnpm build-storybook` completes without errors - [ ] All 100 components appear in Storybook sidebar +- [ ] `pnpm check:stories` passes (100% story coverage) - [ ] Dark/light theme toggle works for all stories - [ ] tsup build still excludes stories from dist/ - [ ] next/* stub components render without errors for all 9 affected components @@ -323,9 +331,9 @@ Confirmed — spec solves the right problem. The library needs interactive docum ### Open Items - [resolved] 9 components import from `next/` → addressed: tiered functional mocks in next-stubs.ts (scope 2) -- [resolved] Addon compatibility risk → addressed: spike gate (scope 0) +- [resolved] Addon compatibility risk → addressed: spike gate (scope 0), includes @storybook/addon-mcp (requires SB >=9.1.16, verify SB10 compat) - [resolved] Story overwrite risk → addressed: `// manual` header protection (scope 8) -- [improvement] CI check that every component has a .stories.tsx -> no action (Phase 2+ concern) +- [resolved] CI check that every component has a .stories.tsx -> addressed: check-story-coverage.ts (scope 8b) - [question] Should story generator reuse component-preview.tsx demo logic or start fresh? -> explore at implementation - [question] Full list of provider-dependent components → enumerate during scope 9 story generation @@ -344,9 +352,11 @@ Confirmed — spec solves the right problem. The library needs interactive docum | 6 | Exclude stories from tsup | pending | - | | 7 | Add scripts + turbo.json (scoped) | pending | - | | 8 | Create story generator (--force protection) | pending | - | +| 8b | Create story coverage check script | pending | - | | 9 | Generate all 100 stories | pending | - | | 10 | Refine top 5 compound stories | pending | - | -| 11 | Verify build-storybook | pending | - | +| 11 | Configure test-runner + smoke tests | pending | - | +| 12 | Verify build-storybook | pending | - | ## Timeline From ffb4bc2faa444b7adb4c8f08ae6c18feb2ab6559 Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:51:09 +0100 Subject: [PATCH 03/26] feat(storybook): implement Storybook 10 with full component coverage - Configure .storybook/main.ts with React-Vite, a11y, themes, designs, MCP addons - Configure .storybook/preview.ts with dark mode toggle via withThemeByClassName - Create next-stubs.ts for Next.js component mocking (Link, Image, navigation) - Create story generator script with CVA variant extraction for Controls - Create story coverage check script (check:stories) - Generate stories for all 99 components with automatic argTypes - Manually refine 6 compound stories (dialog, sheet, dropdown, sidebar, toast, mdx-content) - Add Storybook scripts to package.json + turbo.json pipeline - Exclude stories from tsup build and tsc typecheck - Add storybook-static/ to .gitignore - Update ESLint config to ignore storybook build output --- .gitignore | 3 + packages/ui/.storybook/main.ts | 39 + packages/ui/.storybook/next-stubs.ts | 77 + packages/ui/.storybook/preview.ts | 29 + packages/ui/eslint.config.js | 8 +- packages/ui/package.json | 20 +- packages/ui/scripts/check-story-coverage.ts | 47 + packages/ui/scripts/generate-stories.ts | 304 ++ .../accordion/accordion.stories.tsx | 16 + .../alert-dialog/alert-dialog.stories.tsx | 16 + .../ui/src/components/alert/alert.stories.tsx | 29 + .../aspect-ratio/aspect-ratio.stories.tsx | 13 + .../src/components/avatar/avatar.stories.tsx | 13 + .../ui/src/components/badge/badge.stories.tsx | 41 + .../blog-card/blog-card.stories.tsx | 13 + .../breadcrumb/breadcrumb.stories.tsx | 13 + .../src/components/button/button.stories.tsx | 83 + .../components/calendar/calendar.stories.tsx | 13 + .../components/callout/callout.stories.tsx | 16 + .../ui/src/components/card/card.stories.tsx | 16 + .../components/carousel/carousel.stories.tsx | 13 + .../category-filter.stories.tsx | 13 + .../components/chart/area-chart.stories.tsx | 13 + .../components/checkbox/checkbox.stories.tsx | 13 + .../checklist/checklist.stories.tsx | 16 + .../code-block/code-block.stories.tsx | 13 + .../code-playground.stories.tsx | 13 + .../collapsible/collapsible.stories.tsx | 13 + .../components/command/command.stories.tsx | 16 + .../comparison/comparison.stories.tsx | 16 + .../completion-dialog.stories.tsx | 13 + .../content-intro/content-intro.stories.tsx | 13 + .../context-menu/context-menu.stories.tsx | 16 + .../cookie-consent/cookie-consent.stories.tsx | 13 + .../src/components/dialog/dialog.stories.tsx | 64 + .../src/components/drawer/drawer.stories.tsx | 13 + .../dropdown-menu/dropdown-menu.stories.tsx | 45 + .../components/exercise/exercise.stories.tsx | 16 + .../ui/src/components/faq/faq.stories.tsx | 16 + .../filter-bar/filter-bar.stories.tsx | 13 + .../floating-action-button.stories.tsx | 13 + .../flow-diagram/flow-diagram.stories.tsx | 13 + .../horizontal-scroll-row.stories.tsx | 13 + .../hover-card/hover-card.stories.tsx | 16 + .../inline-input/inline-input.stories.tsx | 13 + .../input-otp/input-otp.stories.tsx | 13 + .../ui/src/components/input/input.stories.tsx | 13 + .../key-concept/key-concept.stories.tsx | 16 + .../keyboard-shortcuts-help.stories.tsx | 13 + .../ui/src/components/label/label.stories.tsx | 16 + .../lang-provider/lang-provider.stories.tsx | 13 + .../learning-objectives.stories.tsx | 16 + .../mdx-content/mdx-content.stories.tsx | 29 + .../components/menubar/menubar.stories.tsx | 16 + .../model-selector/model-selector.stories.tsx | 13 + .../navbar-saas/navbar-saas.stories.tsx | 13 + .../navigation-menu.stories.tsx | 16 + .../pagination/pagination.stories.tsx | 13 + .../components/popover/popover.stories.tsx | 16 + .../components/pro-tip/pro-tip.stories.tsx | 16 + .../profile-section.stories.tsx | 13 + .../progress-bar/progress-bar.stories.tsx | 13 + .../progress-card/progress-card.stories.tsx | 13 + .../ui/src/components/quiz/quiz.stories.tsx | 16 + .../radio-group/radio-group.stories.tsx | 13 + .../resizable/resizable.stories.tsx | 13 + .../scroll-area/scroll-area.stories.tsx | 16 + .../search-bar/search-bar.stories.tsx | 13 + .../search-dialog/search-dialog.stories.tsx | 13 + .../src/components/select/select.stories.tsx | 13 + .../separator/separator.stories.tsx | 13 + .../share-dialog/share-dialog.stories.tsx | 13 + .../share-section/share-section.stories.tsx | 13 + .../ui/src/components/sheet/sheet.stories.tsx | 88 + .../sidebar-provider.stories.tsx | 13 + .../sidebar-toggle/sidebar-toggle.stories.tsx | 13 + .../components/sidebar/sidebar.stories.tsx | 63 + .../components/skeleton/skeleton.stories.tsx | 13 + .../src/components/slider/slider.stories.tsx | 13 + .../slideshow/slideshow.stories.tsx | 13 + .../social-fab/social-fab.stories.tsx | 13 + .../components/spinner/spinner.stories.tsx | 13 + .../step-by-step/step-by-step.stories.tsx | 16 + .../step-navigation.stories.tsx | 13 + .../src/components/switch/switch.stories.tsx | 13 + .../table-of-contents-panel.stories.tsx | 13 + .../table-of-contents.stories.tsx | 13 + .../ui/src/components/table/table.stories.tsx | 16 + .../ui/src/components/tabs/tabs.stories.tsx | 16 + .../components/terminal/terminal.stories.tsx | 13 + .../components/textarea/textarea.stories.tsx | 13 + .../theme-provider/theme-provider.stories.tsx | 13 + .../theme-toggle/theme-toggle.stories.tsx | 13 + .../thinking-block/thinking-block.stories.tsx | 13 + .../tldr-section/tldr-section.stories.tsx | 16 + .../ui/src/components/toast/toast.stories.tsx | 71 + .../toggle-group/toggle-group.stories.tsx | 13 + .../src/components/toggle/toggle.stories.tsx | 45 + .../components/tooltip/tooltip.stories.tsx | 16 + .../truncated-text/truncated-text.stories.tsx | 13 + .../tutorial-card/tutorial-card.stories.tsx | 13 + .../tutorial-complete.stories.tsx | 46 + .../tutorial-filters.stories.tsx | 38 + .../tutorial-intro-content.stories.tsx | 18 + .../tutorial-mdx/tutorial-mdx.stories.tsx | 17 + .../video-embed/video-embed.stories.tsx | 27 + .../view-switcher/view-switcher.stories.tsx | 21 + packages/ui/tsconfig.json | 2 +- packages/ui/tsup.config.ts | 1 + pnpm-lock.yaml | 3718 ++++++++++++++++- turbo.json | 14 + 111 files changed, 6032 insertions(+), 109 deletions(-) create mode 100644 packages/ui/.storybook/main.ts create mode 100644 packages/ui/.storybook/next-stubs.ts create mode 100644 packages/ui/.storybook/preview.ts create mode 100644 packages/ui/scripts/check-story-coverage.ts create mode 100644 packages/ui/scripts/generate-stories.ts create mode 100644 packages/ui/src/components/accordion/accordion.stories.tsx create mode 100644 packages/ui/src/components/alert-dialog/alert-dialog.stories.tsx create mode 100644 packages/ui/src/components/alert/alert.stories.tsx create mode 100644 packages/ui/src/components/aspect-ratio/aspect-ratio.stories.tsx create mode 100644 packages/ui/src/components/avatar/avatar.stories.tsx create mode 100644 packages/ui/src/components/badge/badge.stories.tsx create mode 100644 packages/ui/src/components/blog-card/blog-card.stories.tsx create mode 100644 packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx create mode 100644 packages/ui/src/components/button/button.stories.tsx create mode 100644 packages/ui/src/components/calendar/calendar.stories.tsx create mode 100644 packages/ui/src/components/callout/callout.stories.tsx create mode 100644 packages/ui/src/components/card/card.stories.tsx create mode 100644 packages/ui/src/components/carousel/carousel.stories.tsx create mode 100644 packages/ui/src/components/category-filter/category-filter.stories.tsx create mode 100644 packages/ui/src/components/chart/area-chart.stories.tsx create mode 100644 packages/ui/src/components/checkbox/checkbox.stories.tsx create mode 100644 packages/ui/src/components/checklist/checklist.stories.tsx create mode 100644 packages/ui/src/components/code-block/code-block.stories.tsx create mode 100644 packages/ui/src/components/code-playground/code-playground.stories.tsx create mode 100644 packages/ui/src/components/collapsible/collapsible.stories.tsx create mode 100644 packages/ui/src/components/command/command.stories.tsx create mode 100644 packages/ui/src/components/comparison/comparison.stories.tsx create mode 100644 packages/ui/src/components/completion-dialog/completion-dialog.stories.tsx create mode 100644 packages/ui/src/components/content-intro/content-intro.stories.tsx create mode 100644 packages/ui/src/components/context-menu/context-menu.stories.tsx create mode 100644 packages/ui/src/components/cookie-consent/cookie-consent.stories.tsx create mode 100644 packages/ui/src/components/dialog/dialog.stories.tsx create mode 100644 packages/ui/src/components/drawer/drawer.stories.tsx create mode 100644 packages/ui/src/components/dropdown-menu/dropdown-menu.stories.tsx create mode 100644 packages/ui/src/components/exercise/exercise.stories.tsx create mode 100644 packages/ui/src/components/faq/faq.stories.tsx create mode 100644 packages/ui/src/components/filter-bar/filter-bar.stories.tsx create mode 100644 packages/ui/src/components/floating-action-button/floating-action-button.stories.tsx create mode 100644 packages/ui/src/components/flow-diagram/flow-diagram.stories.tsx create mode 100644 packages/ui/src/components/horizontal-scroll-row/horizontal-scroll-row.stories.tsx create mode 100644 packages/ui/src/components/hover-card/hover-card.stories.tsx create mode 100644 packages/ui/src/components/inline-input/inline-input.stories.tsx create mode 100644 packages/ui/src/components/input-otp/input-otp.stories.tsx create mode 100644 packages/ui/src/components/input/input.stories.tsx create mode 100644 packages/ui/src/components/key-concept/key-concept.stories.tsx create mode 100644 packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.stories.tsx create mode 100644 packages/ui/src/components/label/label.stories.tsx create mode 100644 packages/ui/src/components/lang-provider/lang-provider.stories.tsx create mode 100644 packages/ui/src/components/learning-objectives/learning-objectives.stories.tsx create mode 100644 packages/ui/src/components/mdx-content/mdx-content.stories.tsx create mode 100644 packages/ui/src/components/menubar/menubar.stories.tsx create mode 100644 packages/ui/src/components/model-selector/model-selector.stories.tsx create mode 100644 packages/ui/src/components/navbar-saas/navbar-saas.stories.tsx create mode 100644 packages/ui/src/components/navigation-menu/navigation-menu.stories.tsx create mode 100644 packages/ui/src/components/pagination/pagination.stories.tsx create mode 100644 packages/ui/src/components/popover/popover.stories.tsx create mode 100644 packages/ui/src/components/pro-tip/pro-tip.stories.tsx create mode 100644 packages/ui/src/components/profile-section/profile-section.stories.tsx create mode 100644 packages/ui/src/components/progress-bar/progress-bar.stories.tsx create mode 100644 packages/ui/src/components/progress-card/progress-card.stories.tsx create mode 100644 packages/ui/src/components/quiz/quiz.stories.tsx create mode 100644 packages/ui/src/components/radio-group/radio-group.stories.tsx create mode 100644 packages/ui/src/components/resizable/resizable.stories.tsx create mode 100644 packages/ui/src/components/scroll-area/scroll-area.stories.tsx create mode 100644 packages/ui/src/components/search-bar/search-bar.stories.tsx create mode 100644 packages/ui/src/components/search-dialog/search-dialog.stories.tsx create mode 100644 packages/ui/src/components/select/select.stories.tsx create mode 100644 packages/ui/src/components/separator/separator.stories.tsx create mode 100644 packages/ui/src/components/share-dialog/share-dialog.stories.tsx create mode 100644 packages/ui/src/components/share-section/share-section.stories.tsx create mode 100644 packages/ui/src/components/sheet/sheet.stories.tsx create mode 100644 packages/ui/src/components/sidebar-provider/sidebar-provider.stories.tsx create mode 100644 packages/ui/src/components/sidebar-toggle/sidebar-toggle.stories.tsx create mode 100644 packages/ui/src/components/sidebar/sidebar.stories.tsx create mode 100644 packages/ui/src/components/skeleton/skeleton.stories.tsx create mode 100644 packages/ui/src/components/slider/slider.stories.tsx create mode 100644 packages/ui/src/components/slideshow/slideshow.stories.tsx create mode 100644 packages/ui/src/components/social-fab/social-fab.stories.tsx create mode 100644 packages/ui/src/components/spinner/spinner.stories.tsx create mode 100644 packages/ui/src/components/step-by-step/step-by-step.stories.tsx create mode 100644 packages/ui/src/components/step-navigation/step-navigation.stories.tsx create mode 100644 packages/ui/src/components/switch/switch.stories.tsx create mode 100644 packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.stories.tsx create mode 100644 packages/ui/src/components/table-of-contents/table-of-contents.stories.tsx create mode 100644 packages/ui/src/components/table/table.stories.tsx create mode 100644 packages/ui/src/components/tabs/tabs.stories.tsx create mode 100644 packages/ui/src/components/terminal/terminal.stories.tsx create mode 100644 packages/ui/src/components/textarea/textarea.stories.tsx create mode 100644 packages/ui/src/components/theme-provider/theme-provider.stories.tsx create mode 100644 packages/ui/src/components/theme-toggle/theme-toggle.stories.tsx create mode 100644 packages/ui/src/components/thinking-block/thinking-block.stories.tsx create mode 100644 packages/ui/src/components/tldr-section/tldr-section.stories.tsx create mode 100644 packages/ui/src/components/toast/toast.stories.tsx create mode 100644 packages/ui/src/components/toggle-group/toggle-group.stories.tsx create mode 100644 packages/ui/src/components/toggle/toggle.stories.tsx create mode 100644 packages/ui/src/components/tooltip/tooltip.stories.tsx create mode 100644 packages/ui/src/components/truncated-text/truncated-text.stories.tsx create mode 100644 packages/ui/src/components/tutorial-card/tutorial-card.stories.tsx create mode 100644 packages/ui/src/components/tutorial-complete/tutorial-complete.stories.tsx create mode 100644 packages/ui/src/components/tutorial-filters/tutorial-filters.stories.tsx create mode 100644 packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.stories.tsx create mode 100644 packages/ui/src/components/tutorial-mdx/tutorial-mdx.stories.tsx create mode 100644 packages/ui/src/components/video-embed/video-embed.stories.tsx create mode 100644 packages/ui/src/components/view-switcher/view-switcher.stories.tsx diff --git a/.gitignore b/.gitignore index a88ea45..7da2b8c 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,9 @@ playwright-results/ playwright-report/ .snapshots/ +# Storybook +storybook-static/ + # Generated public/r/ next-env.d.ts diff --git a/packages/ui/.storybook/main.ts b/packages/ui/.storybook/main.ts new file mode 100644 index 0000000..5d8c98a --- /dev/null +++ b/packages/ui/.storybook/main.ts @@ -0,0 +1,39 @@ +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' + +import { defineMain } from '@storybook/react-vite/node' + +const __dirname = dirname(fileURLToPath(import.meta.url)) + +export default defineMain({ + stories: ['../src/**/*.stories.@(ts|tsx)'], + + framework: '@storybook/react-vite', + + addons: [ + '@storybook/addon-a11y', + '@storybook/addon-themes', + '@storybook/addon-designs', + '@storybook/addon-mcp', + ], + + viteFinal(config) { + return { + ...config, + resolve: { + ...config.resolve, + alias: { + ...(config.resolve?.alias ?? {}), + '@': resolve(__dirname, '../src'), + 'next/link': resolve(__dirname, './next-stubs.ts'), + 'next/image': resolve(__dirname, './next-stubs.ts'), + 'next/navigation': resolve(__dirname, './next-stubs.ts'), + }, + }, + css: { + ...config.css, + postcss: resolve(__dirname, '../postcss.config.mjs'), + }, + } + }, +}) diff --git a/packages/ui/.storybook/next-stubs.ts b/packages/ui/.storybook/next-stubs.ts new file mode 100644 index 0000000..09abacc --- /dev/null +++ b/packages/ui/.storybook/next-stubs.ts @@ -0,0 +1,77 @@ +/** + * Functional stubs for next/* modules used in Storybook. + * + * Tiered approach: + * - Passive (Link, Image): render native HTML equivalents + * - Active (useRouter, usePathname, useSearchParams): return functional mock objects + * + * This file is aliased via Vite resolve in main.ts: + * next/link -> ./next-stubs.ts + * next/image -> ./next-stubs.ts + * next/navigation -> ./next-stubs.ts + */ +import * as React from 'react' + +/* ---------- next/link ---------- */ +function Link({ + href, + children, + ...props +}: { + href: string + children?: React.ReactNode + [key: string]: unknown +}) { + return React.createElement('a', { href: String(href), ...props }, children) +} + +/* ---------- next/image ---------- */ +function Image({ + src, + alt, + width, + height, + fill, + ...props +}: { + src: string + alt: string + width?: number + height?: number + fill?: boolean + [key: string]: unknown +}) { + const style = fill ? { objectFit: 'cover' as const, width: '100%', height: '100%' } : {} + return React.createElement('img', { + src: String(src), + alt, + width, + height, + style, + ...props, + }) +} + +/* ---------- next/navigation ---------- */ +function useRouter() { + return { + push: (url: string) => console.log('[storybook] router.push:', url), + replace: (url: string) => console.log('[storybook] router.replace:', url), + back: () => console.log('[storybook] router.back'), + forward: () => console.log('[storybook] router.forward'), + refresh: () => {}, + prefetch: () => {}, + } +} + +function usePathname(): string { + return '/' +} + +function useSearchParams(): URLSearchParams { + return new URLSearchParams() +} + +/* ---------- exports ---------- */ +export default Link +export { Link, Image, useRouter, usePathname, useSearchParams } diff --git a/packages/ui/.storybook/preview.ts b/packages/ui/.storybook/preview.ts new file mode 100644 index 0000000..d163822 --- /dev/null +++ b/packages/ui/.storybook/preview.ts @@ -0,0 +1,29 @@ +import { Renderer, definePreview } from '@storybook/react-vite' + +import addonThemes from '@storybook/addon-themes' + +import '../styles.css' +import '../themes/default.css' + +export default definePreview({ + addons: [addonThemes()], + + decorators: [ + addonThemes.withThemeByClassName({ + themes: { + light: '', + dark: 'dark', + }, + defaultTheme: 'light', + }), + ], + + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + }, +}) diff --git a/packages/ui/eslint.config.js b/packages/ui/eslint.config.js index 14884a6..7500d0f 100644 --- a/packages/ui/eslint.config.js +++ b/packages/ui/eslint.config.js @@ -2,7 +2,7 @@ import { react } from '@vllnt/eslint-config' export default [ { - ignores: ['node_modules/**', 'dist/**', 'eslint.config.js', 'scripts/**', 'playwright-ct.config.ts', 'playwright/**', 'postcss.config.mjs', 'tailwind.config.ts', 'tsup.config.ts'], + ignores: ['node_modules/**', 'dist/**', 'storybook-static/**', '.storybook/**', 'eslint.config.js', 'scripts/**', 'playwright-ct.config.ts', 'playwright/**', 'postcss.config.mjs', 'tailwind.config.ts', 'tsup.config.ts'], }, ...react, { @@ -24,6 +24,12 @@ export default [ 'max-lines-per-function': 'off', }, }, + { + files: ['**/*.stories.{ts,tsx}'], + rules: { + 'max-lines-per-function': 'off', + }, + }, { files: ['**/components/slideshow/slideshow.tsx'], rules: { diff --git a/packages/ui/package.json b/packages/ui/package.json index 778dac4..49c124e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -67,7 +67,7 @@ ], "scripts": { "build": "tsup", - "clean": "rm -rf dist node_modules coverage .snapshots playwright-report test-results", + "clean": "rm -rf dist node_modules coverage .snapshots playwright-report test-results storybook-static", "lint": "eslint .", "lint:fix": "eslint . --fix", "check:circular": "madge --circular --extensions ts,tsx src", @@ -77,13 +77,18 @@ "test:visual": "playwright test -c playwright-ct.config.ts", "test:visual:update": "playwright test -c playwright-ct.config.ts --update-snapshots", "test:all": "pnpm test:coverage && pnpm test:visual", - "test:generate": "tsx scripts/generate-tests.ts" + "test:generate": "tsx scripts/generate-tests.ts", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build", + "test-storybook": "test-storybook", + "storybook:generate": "tsx scripts/generate-stories.ts", + "check:stories": "tsx scripts/check-story-coverage.ts" }, "peerDependencies": { - "react": ">=18.0.0", - "react-dom": ">=18.0.0", "next": ">=14.0.0", "next-themes": ">=0.4.0", + "react": ">=18.0.0", + "react-dom": ">=18.0.0", "tailwindcss": ">=3.0.0" }, "peerDependenciesMeta": { @@ -138,6 +143,12 @@ }, "devDependencies": { "@playwright/experimental-ct-react": "^1.57.0", + "@storybook/addon-a11y": "^10.2.17", + "@storybook/addon-designs": "^11.1.2", + "@storybook/addon-mcp": "^0.3.4", + "@storybook/addon-themes": "^10.2.17", + "@storybook/react-vite": "^10.2.17", + "@storybook/test-runner": "^0.24.2", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", "@types/node": "^22", @@ -152,6 +163,7 @@ "jsdom": "^26.1.0", "playwright": "^1.57.0", "postcss": "^8.5.6", + "storybook": "^10.2.17", "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", "tsup": "^8.5.0", diff --git a/packages/ui/scripts/check-story-coverage.ts b/packages/ui/scripts/check-story-coverage.ts new file mode 100644 index 0000000..f41ff1c --- /dev/null +++ b/packages/ui/scripts/check-story-coverage.ts @@ -0,0 +1,47 @@ +/** + * Story Coverage Check + * + * Verifies every component directory has a corresponding .stories.tsx file. + * Exits with code 1 if any component is missing a story. + * + * Usage: pnpm -F @vllnt/ui check:stories + */ + +import { existsSync, readdirSync, statSync } from 'fs' +import { dirname, join } from 'path' +import { fileURLToPath } from 'url' + +const __dirname = dirname(fileURLToPath(import.meta.url)) +const COMPONENTS_DIR = join(__dirname, '../src/components') + +function main(): void { + const componentDirs = readdirSync(COMPONENTS_DIR).filter((dir) => { + const fullPath = join(COMPONENTS_DIR, dir) + return statSync(fullPath).isDirectory() + }) + + const missing: string[] = [] + + for (const dir of componentDirs) { + const dirPath = join(COMPONENTS_DIR, dir) + const files = readdirSync(dirPath) + const hasStory = files.some((f) => f.endsWith('.stories.tsx')) + + if (!hasStory) { + missing.push(dir) + } + } + + if (missing.length > 0) { + console.error(`Missing stories for ${missing.length} component(s):\n`) + for (const name of missing) { + console.error(` - ${name}`) + } + console.error(`\nRun: pnpm -F @vllnt/ui storybook:generate`) + process.exit(1) + } + + console.log(`All ${componentDirs.length} components have stories.`) +} + +main() diff --git a/packages/ui/scripts/generate-stories.ts b/packages/ui/scripts/generate-stories.ts new file mode 100644 index 0000000..12d321d --- /dev/null +++ b/packages/ui/scripts/generate-stories.ts @@ -0,0 +1,304 @@ +/** + * Story Generator Script + * + * Generates Storybook story files (.stories.tsx) for all components. + * Extracts CVA variants automatically to create Controls. + * + * Usage: pnpm -F @vllnt/ui storybook:generate + * + * Options: + * --force Overwrite existing stories (skips files with "// manual" header) + */ + +import { existsSync, readdirSync, readFileSync, statSync, writeFileSync } from 'fs' +import { basename, dirname, join } from 'path' +import { fileURLToPath } from 'url' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +const COMPONENTS_DIR = join(__dirname, '../src/components') + +interface VariantInfo { + name: string + values: string[] + defaultValue?: string +} + +interface ComponentInfo { + name: string + fileName: string + dirName: string + filePath: string + hasVariants: boolean + variants: VariantInfo[] + exports: string[] + needsChildren: boolean +} + +function toPascalCase(str: string): string { + return str + .split('-') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join('') +} + +function extractVariants(source: string): VariantInfo[] { + const variants: VariantInfo[] = [] + if (!source.includes('cva(')) return variants + + const defaultsMatch = source.match(/defaultVariants\s*:\s*\{([^}]+)\}/s) + const defaults: Record = {} + if (defaultsMatch?.[1]) { + const defaultsStr = defaultsMatch[1] + const defaultPairs = defaultsStr.matchAll(/(\w+)\s*:\s*['"](\w+)['"]/g) + for (const match of defaultPairs) { + if (match[1] && match[2]) { + defaults[match[1]] = match[2] + } + } + } + + const variantsStartMatch = source.match(/variants\s*:\s*\{/) + if (!variantsStartMatch || variantsStartMatch.index === undefined) return variants + + const variantsStartPos = variantsStartMatch.index + variantsStartMatch[0].length + let depth = 1 + let variantsEndPos = variantsStartPos + + for (let i = variantsStartPos; i < source.length; i++) { + if (source[i] === '{') depth++ + if (source[i] === '}') { + depth-- + if (depth === 0) { + variantsEndPos = i + break + } + } + } + + const variantsBlock = source.slice(variantsStartPos, variantsEndPos) + const variantTypeRegex = /(\w+)\s*:\s*\{/g + let typeMatch + + while ((typeMatch = variantTypeRegex.exec(variantsBlock)) !== null) { + const variantName = typeMatch[1] + const typeStartPos = typeMatch.index + typeMatch[0].length + let typeDepth = 1 + let typeEndPos = typeStartPos + + for (let i = typeStartPos; i < variantsBlock.length; i++) { + if (variantsBlock[i] === '{') typeDepth++ + if (variantsBlock[i] === '}') { + typeDepth-- + if (typeDepth === 0) { + typeEndPos = i + break + } + } + } + + const typeContent = variantsBlock.slice(typeStartPos, typeEndPos) + const values: string[] = [] + const keyRegex = /(\w+)\s*:\s*['"`,]/g + let keyMatch + + while ((keyMatch = keyRegex.exec(typeContent)) !== null) { + if (keyMatch[1]) values.push(keyMatch[1]) + } + + if (values.length > 0 && variantName) { + variants.push({ + name: variantName, + values, + defaultValue: defaults[variantName], + }) + } + } + + return variants +} + +function extractExports(source: string): string[] { + const exports: string[] = [] + + const namedExports = source.matchAll(/export\s*\{\s*([^}]+)\s*\}/g) + for (const match of namedExports) { + if (!match[1]) continue + const names = match[1].split(',').map((n) => n.trim().split(' ')[0]) + exports.push(...names.filter((n): n is string => Boolean(n) && /^[A-Z]/.test(n))) + } + + const constExports = source.matchAll(/export\s+(?:const|function)\s+([A-Z]\w+)/g) + for (const match of constExports) { + if (match[1]) exports.push(match[1]) + } + + const defaultExport = source.match(/export\s+default\s+([A-Z]\w+)/) + if (defaultExport?.[1]) { + exports.push(defaultExport[1]) + } + + return [...new Set(exports)] +} + +const CHILDREN_COMPONENTS = new Set([ + 'Button', 'Badge', 'Label', 'Card', 'Accordion', 'Tabs', 'Dialog', + 'DropdownMenu', 'Command', 'Callout', 'ProTip', 'KeyConcept', + 'TldrSection', 'LearningObjectives', 'Checklist', 'StepByStep', + 'Comparison', 'Faq', 'Exercise', 'Quiz', 'Alert', 'AlertDialog', + 'Sheet', 'Popover', 'HoverCard', 'Tooltip', 'ContextMenu', + 'NavigationMenu', 'Menubar', 'ScrollArea', 'Table', +]) + +function analyzeComponent(dirPath: string): ComponentInfo | null { + const dirName = basename(dirPath) + const files = readdirSync(dirPath).filter( + (f) => f.endsWith('.tsx') && !f.includes('.test.') && !f.includes('.visual.') && !f.includes('.stories.') + ) + + let mainFile = files.find((f) => f === `${dirName}.tsx`) + if (!mainFile) mainFile = files.find((f) => f.endsWith('.tsx')) + if (!mainFile) return null + + const filePath = join(dirPath, mainFile) + if (!existsSync(filePath)) return null + + const source = readFileSync(filePath, 'utf-8') + const fileName = mainFile.replace('.tsx', '') + const name = toPascalCase(fileName) + + return { + name, + fileName, + dirName, + filePath, + hasVariants: source.includes('cva('), + variants: extractVariants(source), + exports: extractExports(source), + needsChildren: CHILDREN_COMPONENTS.has(name), + } +} + +function isManualStory(filePath: string): boolean { + if (!existsSync(filePath)) return false + const firstLine = readFileSync(filePath, 'utf-8').split('\n')[0] ?? '' + return firstLine.includes('// manual') +} + +function generateStory(component: ComponentInfo): string { + const { name, fileName, variants, exports, needsChildren } = component + const primaryExport = exports.find((e) => e === name) || exports[0] || name + const childContent = needsChildren ? `children: '${name}',` : '' + + const argTypes: string[] = [] + const defaultArgs: string[] = [] + + for (const variant of variants) { + argTypes.push( + ` ${variant.name}: {\n control: 'select',\n options: [${variant.values.map((v) => `'${v}'`).join(', ')}],\n },` + ) + if (variant.defaultValue) { + defaultArgs.push(` ${variant.name}: '${variant.defaultValue}',`) + } + } + + const argTypesBlock = argTypes.length > 0 + ? `\n argTypes: {\n${argTypes.join('\n')}\n },` + : '' + + const argsBlock = (defaultArgs.length > 0 || childContent) + ? `\n args: {\n${[...defaultArgs, childContent ? ` ${childContent}` : ''].filter(Boolean).join('\n')}\n },` + : '' + + return `import type { Meta, StoryObj } from '@storybook/react-vite' + +import { ${primaryExport} } from './${fileName}' + +const meta = { + title: 'Components/${name}', + component: ${primaryExport},${argTypesBlock}${argsBlock} +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = {} +${variants.length > 0 ? generateVariantStories(variants, name) : ''} +` +} + +function generateVariantStories(variants: VariantInfo[], _componentName: string): string { + const stories: string[] = [] + + for (const variant of variants) { + for (const value of variant.values) { + if (value === variant.defaultValue) continue + const storyName = toPascalCase(`${variant.name}-${value}`) + stories.push(`export const ${storyName}: Story = { + args: { + ${variant.name}: '${value}', + }, +}`) + } + } + + return stories.length > 0 ? '\n' + stories.join('\n\n') + '\n' : '' +} + +async function main(): Promise { + const forceRegenerate = process.argv.includes('--force') + + console.log('Scanning components...\n') + if (forceRegenerate) { + console.log('Force mode: overwriting stories (except // manual files)\n') + } + + const componentDirs = readdirSync(COMPONENTS_DIR).filter((dir) => { + const fullPath = join(COMPONENTS_DIR, dir) + return statSync(fullPath).isDirectory() + }) + + let generated = 0 + let skipped = 0 + + for (const dir of componentDirs) { + const dirPath = join(COMPONENTS_DIR, dir) + const component = analyzeComponent(dirPath) + + if (!component) { + console.log(` SKIP ${dir}: no component file found`) + skipped++ + continue + } + + const storyPath = join(dirPath, `${component.fileName}.stories.tsx`) + + if (existsSync(storyPath)) { + if (isManualStory(storyPath)) { + console.log(` SKIP ${component.name}: manual story (preserved)`) + skipped++ + continue + } + if (!forceRegenerate) { + console.log(` SKIP ${component.name}: story exists`) + skipped++ + continue + } + } + + const story = generateStory(component) + writeFileSync(storyPath, story) + + const variantCount = component.variants.reduce((sum, v) => sum + v.values.length, 0) + console.log(` GENERATED ${component.name}: ${variantCount} variants`) + generated++ + } + + console.log(`\nSummary:`) + console.log(` Generated: ${generated}`) + console.log(` Skipped: ${skipped}`) + console.log(` Total: ${componentDirs.length}`) +} + +main().catch(console.error) diff --git a/packages/ui/src/components/accordion/accordion.stories.tsx b/packages/ui/src/components/accordion/accordion.stories.tsx new file mode 100644 index 0000000..31d40e6 --- /dev/null +++ b/packages/ui/src/components/accordion/accordion.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Accordion } from "./accordion"; + +const meta = { + args: { + children: "Accordion", + }, + component: Accordion, + title: "Components/Accordion", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/alert-dialog/alert-dialog.stories.tsx b/packages/ui/src/components/alert-dialog/alert-dialog.stories.tsx new file mode 100644 index 0000000..35ffe14 --- /dev/null +++ b/packages/ui/src/components/alert-dialog/alert-dialog.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { AlertDialog } from "./alert-dialog"; + +const meta = { + args: { + children: "AlertDialog", + }, + component: AlertDialog, + title: "Components/AlertDialog", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/alert/alert.stories.tsx b/packages/ui/src/components/alert/alert.stories.tsx new file mode 100644 index 0000000..c0ba7b9 --- /dev/null +++ b/packages/ui/src/components/alert/alert.stories.tsx @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Alert } from "./alert"; + +const meta = { + args: { + children: "Alert", + variant: "default", + }, + argTypes: { + variant: { + control: "select", + options: ["default", "destructive"], + }, + }, + component: Alert, + title: "Components/Alert", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const VariantDestructive: Story = { + args: { + variant: "destructive", + }, +}; diff --git a/packages/ui/src/components/aspect-ratio/aspect-ratio.stories.tsx b/packages/ui/src/components/aspect-ratio/aspect-ratio.stories.tsx new file mode 100644 index 0000000..ee4eaf8 --- /dev/null +++ b/packages/ui/src/components/aspect-ratio/aspect-ratio.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { AspectRatio } from "./aspect-ratio"; + +const meta = { + component: AspectRatio, + title: "Components/AspectRatio", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/avatar/avatar.stories.tsx b/packages/ui/src/components/avatar/avatar.stories.tsx new file mode 100644 index 0000000..6fb97b7 --- /dev/null +++ b/packages/ui/src/components/avatar/avatar.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Avatar } from "./avatar"; + +const meta = { + component: Avatar, + title: "Components/Avatar", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/badge/badge.stories.tsx b/packages/ui/src/components/badge/badge.stories.tsx new file mode 100644 index 0000000..5dfc615 --- /dev/null +++ b/packages/ui/src/components/badge/badge.stories.tsx @@ -0,0 +1,41 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Badge } from "./badge"; + +const meta = { + args: { + children: "Badge", + variant: "default", + }, + argTypes: { + variant: { + control: "select", + options: ["default", "destructive", "outline", "secondary"], + }, + }, + component: Badge, + title: "Components/Badge", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const VariantDestructive: Story = { + args: { + variant: "destructive", + }, +}; + +export const VariantOutline: Story = { + args: { + variant: "outline", + }, +}; + +export const VariantSecondary: Story = { + args: { + variant: "secondary", + }, +}; diff --git a/packages/ui/src/components/blog-card/blog-card.stories.tsx b/packages/ui/src/components/blog-card/blog-card.stories.tsx new file mode 100644 index 0000000..4baffde --- /dev/null +++ b/packages/ui/src/components/blog-card/blog-card.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { BlogCard } from "./blog-card"; + +const meta = { + component: BlogCard, + title: "Components/BlogCard", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx b/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx new file mode 100644 index 0000000..324b672 --- /dev/null +++ b/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Breadcrumb } from "./breadcrumb"; + +const meta = { + component: Breadcrumb, + title: "Components/Breadcrumb", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/button/button.stories.tsx b/packages/ui/src/components/button/button.stories.tsx new file mode 100644 index 0000000..a0e5f47 --- /dev/null +++ b/packages/ui/src/components/button/button.stories.tsx @@ -0,0 +1,83 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Button } from "./button"; + +const meta = { + args: { + children: "Button", + size: "default", + variant: "default", + }, + argTypes: { + size: { + control: "select", + options: ["default", "icon", "lg", "sm"], + }, + variant: { + control: "select", + options: [ + "default", + "destructive", + "ghost", + "link", + "outline", + "secondary", + ], + }, + }, + component: Button, + title: "Components/Button", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const SizeIcon: Story = { + args: { + size: "icon", + }, +}; + +export const SizeLg: Story = { + args: { + size: "lg", + }, +}; + +export const SizeSm: Story = { + args: { + size: "sm", + }, +}; + +export const VariantDestructive: Story = { + args: { + variant: "destructive", + }, +}; + +export const VariantGhost: Story = { + args: { + variant: "ghost", + }, +}; + +export const VariantLink: Story = { + args: { + variant: "link", + }, +}; + +export const VariantOutline: Story = { + args: { + variant: "outline", + }, +}; + +export const VariantSecondary: Story = { + args: { + variant: "secondary", + }, +}; diff --git a/packages/ui/src/components/calendar/calendar.stories.tsx b/packages/ui/src/components/calendar/calendar.stories.tsx new file mode 100644 index 0000000..dd007f1 --- /dev/null +++ b/packages/ui/src/components/calendar/calendar.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Calendar } from "./calendar"; + +const meta = { + component: Calendar, + title: "Components/Calendar", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/callout/callout.stories.tsx b/packages/ui/src/components/callout/callout.stories.tsx new file mode 100644 index 0000000..e00d477 --- /dev/null +++ b/packages/ui/src/components/callout/callout.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Callout } from "./callout"; + +const meta = { + args: { + children: "Callout", + }, + component: Callout, + title: "Components/Callout", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/card/card.stories.tsx b/packages/ui/src/components/card/card.stories.tsx new file mode 100644 index 0000000..c32142b --- /dev/null +++ b/packages/ui/src/components/card/card.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Card } from "./card"; + +const meta = { + args: { + children: "Card", + }, + component: Card, + title: "Components/Card", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/carousel/carousel.stories.tsx b/packages/ui/src/components/carousel/carousel.stories.tsx new file mode 100644 index 0000000..e5c2615 --- /dev/null +++ b/packages/ui/src/components/carousel/carousel.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Carousel } from "./carousel"; + +const meta = { + component: Carousel, + title: "Components/Carousel", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/category-filter/category-filter.stories.tsx b/packages/ui/src/components/category-filter/category-filter.stories.tsx new file mode 100644 index 0000000..44a74c3 --- /dev/null +++ b/packages/ui/src/components/category-filter/category-filter.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { CategoryFilter } from "./category-filter"; + +const meta = { + component: CategoryFilter, + title: "Components/CategoryFilter", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/chart/area-chart.stories.tsx b/packages/ui/src/components/chart/area-chart.stories.tsx new file mode 100644 index 0000000..6cbb0db --- /dev/null +++ b/packages/ui/src/components/chart/area-chart.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { AreaChart } from "./area-chart"; + +const meta = { + component: AreaChart, + title: "Components/AreaChart", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/checkbox/checkbox.stories.tsx b/packages/ui/src/components/checkbox/checkbox.stories.tsx new file mode 100644 index 0000000..cd717ca --- /dev/null +++ b/packages/ui/src/components/checkbox/checkbox.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Checkbox } from "./checkbox"; + +const meta = { + component: Checkbox, + title: "Components/Checkbox", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/checklist/checklist.stories.tsx b/packages/ui/src/components/checklist/checklist.stories.tsx new file mode 100644 index 0000000..dd1b4c2 --- /dev/null +++ b/packages/ui/src/components/checklist/checklist.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Checklist } from "./checklist"; + +const meta = { + args: { + children: "Checklist", + }, + component: Checklist, + title: "Components/Checklist", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/code-block/code-block.stories.tsx b/packages/ui/src/components/code-block/code-block.stories.tsx new file mode 100644 index 0000000..691ff81 --- /dev/null +++ b/packages/ui/src/components/code-block/code-block.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { CodeBlock } from "./code-block"; + +const meta = { + component: CodeBlock, + title: "Components/CodeBlock", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/code-playground/code-playground.stories.tsx b/packages/ui/src/components/code-playground/code-playground.stories.tsx new file mode 100644 index 0000000..24ac372 --- /dev/null +++ b/packages/ui/src/components/code-playground/code-playground.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { CodePlayground } from "./code-playground"; + +const meta = { + component: CodePlayground, + title: "Components/CodePlayground", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/collapsible/collapsible.stories.tsx b/packages/ui/src/components/collapsible/collapsible.stories.tsx new file mode 100644 index 0000000..031cd3a --- /dev/null +++ b/packages/ui/src/components/collapsible/collapsible.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Collapsible } from "./collapsible"; + +const meta = { + component: Collapsible, + title: "Components/Collapsible", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/command/command.stories.tsx b/packages/ui/src/components/command/command.stories.tsx new file mode 100644 index 0000000..080f543 --- /dev/null +++ b/packages/ui/src/components/command/command.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Command } from "./command"; + +const meta = { + args: { + children: "Command", + }, + component: Command, + title: "Components/Command", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/comparison/comparison.stories.tsx b/packages/ui/src/components/comparison/comparison.stories.tsx new file mode 100644 index 0000000..c7dd754 --- /dev/null +++ b/packages/ui/src/components/comparison/comparison.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Comparison } from "./comparison"; + +const meta = { + args: { + children: "Comparison", + }, + component: Comparison, + title: "Components/Comparison", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/completion-dialog/completion-dialog.stories.tsx b/packages/ui/src/components/completion-dialog/completion-dialog.stories.tsx new file mode 100644 index 0000000..fc1e430 --- /dev/null +++ b/packages/ui/src/components/completion-dialog/completion-dialog.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { CompletionDialog } from "./completion-dialog"; + +const meta = { + component: CompletionDialog, + title: "Components/CompletionDialog", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/content-intro/content-intro.stories.tsx b/packages/ui/src/components/content-intro/content-intro.stories.tsx new file mode 100644 index 0000000..b7d3f31 --- /dev/null +++ b/packages/ui/src/components/content-intro/content-intro.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ContentIntro } from "./content-intro"; + +const meta = { + component: ContentIntro, + title: "Components/ContentIntro", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/context-menu/context-menu.stories.tsx b/packages/ui/src/components/context-menu/context-menu.stories.tsx new file mode 100644 index 0000000..db7f506 --- /dev/null +++ b/packages/ui/src/components/context-menu/context-menu.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ContextMenu } from "./context-menu"; + +const meta = { + args: { + children: "ContextMenu", + }, + component: ContextMenu, + title: "Components/ContextMenu", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/cookie-consent/cookie-consent.stories.tsx b/packages/ui/src/components/cookie-consent/cookie-consent.stories.tsx new file mode 100644 index 0000000..a5d43fd --- /dev/null +++ b/packages/ui/src/components/cookie-consent/cookie-consent.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { CookieConsent } from "./cookie-consent"; + +const meta = { + component: CookieConsent, + title: "Components/CookieConsent", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/dialog/dialog.stories.tsx b/packages/ui/src/components/dialog/dialog.stories.tsx new file mode 100644 index 0000000..6a5438b --- /dev/null +++ b/packages/ui/src/components/dialog/dialog.stories.tsx @@ -0,0 +1,64 @@ +// manual +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "./dialog"; + +const meta = { + component: Dialog, + parameters: { + layout: "centered", + }, + title: "Components/Dialog", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + Dialog Title + + This is a description of the dialog content. It provides context for + the action. + + + + + + + + + + + ), +}; diff --git a/packages/ui/src/components/drawer/drawer.stories.tsx b/packages/ui/src/components/drawer/drawer.stories.tsx new file mode 100644 index 0000000..bb68592 --- /dev/null +++ b/packages/ui/src/components/drawer/drawer.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Drawer } from "./drawer"; + +const meta = { + component: Drawer, + title: "Components/Drawer", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/dropdown-menu/dropdown-menu.stories.tsx b/packages/ui/src/components/dropdown-menu/dropdown-menu.stories.tsx new file mode 100644 index 0000000..7546770 --- /dev/null +++ b/packages/ui/src/components/dropdown-menu/dropdown-menu.stories.tsx @@ -0,0 +1,45 @@ +// manual +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "./dropdown-menu"; + +const meta = { + component: DropdownMenu, + parameters: { + layout: "centered", + }, + title: "Components/DropdownMenu", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + Actions + + Edit + Duplicate + + Delete + + + ), +}; diff --git a/packages/ui/src/components/exercise/exercise.stories.tsx b/packages/ui/src/components/exercise/exercise.stories.tsx new file mode 100644 index 0000000..9a75634 --- /dev/null +++ b/packages/ui/src/components/exercise/exercise.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Exercise } from "./exercise"; + +const meta = { + args: { + children: "Exercise", + }, + component: Exercise, + title: "Components/Exercise", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/faq/faq.stories.tsx b/packages/ui/src/components/faq/faq.stories.tsx new file mode 100644 index 0000000..8a8ada1 --- /dev/null +++ b/packages/ui/src/components/faq/faq.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { FAQ } from "./faq"; + +const meta = { + args: { + children: "Faq", + }, + component: FAQ, + title: "Components/Faq", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/filter-bar/filter-bar.stories.tsx b/packages/ui/src/components/filter-bar/filter-bar.stories.tsx new file mode 100644 index 0000000..028efe3 --- /dev/null +++ b/packages/ui/src/components/filter-bar/filter-bar.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { FilterBar } from "./filter-bar"; + +const meta = { + component: FilterBar, + title: "Components/FilterBar", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/floating-action-button/floating-action-button.stories.tsx b/packages/ui/src/components/floating-action-button/floating-action-button.stories.tsx new file mode 100644 index 0000000..e5457d9 --- /dev/null +++ b/packages/ui/src/components/floating-action-button/floating-action-button.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { FloatingActionButton } from "./floating-action-button"; + +const meta = { + component: FloatingActionButton, + title: "Components/FloatingActionButton", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/flow-diagram/flow-diagram.stories.tsx b/packages/ui/src/components/flow-diagram/flow-diagram.stories.tsx new file mode 100644 index 0000000..fdf39ca --- /dev/null +++ b/packages/ui/src/components/flow-diagram/flow-diagram.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { FlowDiagram } from "./flow-diagram"; + +const meta = { + component: FlowDiagram, + title: "Components/FlowDiagram", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/horizontal-scroll-row/horizontal-scroll-row.stories.tsx b/packages/ui/src/components/horizontal-scroll-row/horizontal-scroll-row.stories.tsx new file mode 100644 index 0000000..236eccf --- /dev/null +++ b/packages/ui/src/components/horizontal-scroll-row/horizontal-scroll-row.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { HorizontalScrollRow } from "./horizontal-scroll-row"; + +const meta = { + component: HorizontalScrollRow, + title: "Components/HorizontalScrollRow", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/hover-card/hover-card.stories.tsx b/packages/ui/src/components/hover-card/hover-card.stories.tsx new file mode 100644 index 0000000..7df58ba --- /dev/null +++ b/packages/ui/src/components/hover-card/hover-card.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { HoverCard } from "./hover-card"; + +const meta = { + args: { + children: "HoverCard", + }, + component: HoverCard, + title: "Components/HoverCard", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/inline-input/inline-input.stories.tsx b/packages/ui/src/components/inline-input/inline-input.stories.tsx new file mode 100644 index 0000000..e850b02 --- /dev/null +++ b/packages/ui/src/components/inline-input/inline-input.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { InlineInput } from "./inline-input"; + +const meta = { + component: InlineInput, + title: "Components/InlineInput", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/input-otp/input-otp.stories.tsx b/packages/ui/src/components/input-otp/input-otp.stories.tsx new file mode 100644 index 0000000..5ad8c5e --- /dev/null +++ b/packages/ui/src/components/input-otp/input-otp.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { InputOTP } from "./input-otp"; + +const meta = { + component: InputOTP, + title: "Components/InputOtp", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/input/input.stories.tsx b/packages/ui/src/components/input/input.stories.tsx new file mode 100644 index 0000000..b8e447e --- /dev/null +++ b/packages/ui/src/components/input/input.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Input } from "./input"; + +const meta = { + component: Input, + title: "Components/Input", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/key-concept/key-concept.stories.tsx b/packages/ui/src/components/key-concept/key-concept.stories.tsx new file mode 100644 index 0000000..f6e9979 --- /dev/null +++ b/packages/ui/src/components/key-concept/key-concept.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { KeyConcept } from "./key-concept"; + +const meta = { + args: { + children: "KeyConcept", + }, + component: KeyConcept, + title: "Components/KeyConcept", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.stories.tsx b/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.stories.tsx new file mode 100644 index 0000000..8324c43 --- /dev/null +++ b/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { KeyboardShortcutsHelp } from "./keyboard-shortcuts-help"; + +const meta = { + component: KeyboardShortcutsHelp, + title: "Components/KeyboardShortcutsHelp", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/label/label.stories.tsx b/packages/ui/src/components/label/label.stories.tsx new file mode 100644 index 0000000..871ace8 --- /dev/null +++ b/packages/ui/src/components/label/label.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Label } from "./label"; + +const meta = { + args: { + children: "Label", + }, + component: Label, + title: "Components/Label", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/lang-provider/lang-provider.stories.tsx b/packages/ui/src/components/lang-provider/lang-provider.stories.tsx new file mode 100644 index 0000000..64833ef --- /dev/null +++ b/packages/ui/src/components/lang-provider/lang-provider.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { LangProvider } from "./lang-provider"; + +const meta = { + component: LangProvider, + title: "Components/LangProvider", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/learning-objectives/learning-objectives.stories.tsx b/packages/ui/src/components/learning-objectives/learning-objectives.stories.tsx new file mode 100644 index 0000000..d113d0c --- /dev/null +++ b/packages/ui/src/components/learning-objectives/learning-objectives.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { LearningObjectives } from "./learning-objectives"; + +const meta = { + args: { + children: "LearningObjectives", + }, + component: LearningObjectives, + title: "Components/LearningObjectives", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/mdx-content/mdx-content.stories.tsx b/packages/ui/src/components/mdx-content/mdx-content.stories.tsx new file mode 100644 index 0000000..8154e05 --- /dev/null +++ b/packages/ui/src/components/mdx-content/mdx-content.stories.tsx @@ -0,0 +1,29 @@ +// manual +/** + * MDXContent is an async RSC — cannot render directly in Storybook. + * This story renders a placeholder explaining the limitation. + */ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +function MDXContentPlaceholder() { + return ( +
+

MDXContent

+

+ This is an async React Server Component. It processes MDX content + server-side and cannot render in Storybook. +

+

See the registry app for a live preview.

+
+ ); +} + +const meta = { + component: MDXContentPlaceholder, + title: "Components/MDXContent", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/menubar/menubar.stories.tsx b/packages/ui/src/components/menubar/menubar.stories.tsx new file mode 100644 index 0000000..049f731 --- /dev/null +++ b/packages/ui/src/components/menubar/menubar.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Menubar } from "./menubar"; + +const meta = { + args: { + children: "Menubar", + }, + component: Menubar, + title: "Components/Menubar", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/model-selector/model-selector.stories.tsx b/packages/ui/src/components/model-selector/model-selector.stories.tsx new file mode 100644 index 0000000..e3b0fd5 --- /dev/null +++ b/packages/ui/src/components/model-selector/model-selector.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ModelSelector } from "./model-selector"; + +const meta = { + component: ModelSelector, + title: "Components/ModelSelector", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/navbar-saas/navbar-saas.stories.tsx b/packages/ui/src/components/navbar-saas/navbar-saas.stories.tsx new file mode 100644 index 0000000..d6c84fa --- /dev/null +++ b/packages/ui/src/components/navbar-saas/navbar-saas.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { NavbarSaas } from "./navbar-saas"; + +const meta = { + component: NavbarSaas, + title: "Components/NavbarSaas", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/navigation-menu/navigation-menu.stories.tsx b/packages/ui/src/components/navigation-menu/navigation-menu.stories.tsx new file mode 100644 index 0000000..e0356de --- /dev/null +++ b/packages/ui/src/components/navigation-menu/navigation-menu.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { NavigationMenu } from "./navigation-menu"; + +const meta = { + args: { + children: "NavigationMenu", + }, + component: NavigationMenu, + title: "Components/NavigationMenu", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/pagination/pagination.stories.tsx b/packages/ui/src/components/pagination/pagination.stories.tsx new file mode 100644 index 0000000..5e49b9d --- /dev/null +++ b/packages/ui/src/components/pagination/pagination.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Pagination } from "./pagination"; + +const meta = { + component: Pagination, + title: "Components/Pagination", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/popover/popover.stories.tsx b/packages/ui/src/components/popover/popover.stories.tsx new file mode 100644 index 0000000..33acb8a --- /dev/null +++ b/packages/ui/src/components/popover/popover.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Popover } from "./popover"; + +const meta = { + args: { + children: "Popover", + }, + component: Popover, + title: "Components/Popover", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/pro-tip/pro-tip.stories.tsx b/packages/ui/src/components/pro-tip/pro-tip.stories.tsx new file mode 100644 index 0000000..8217e97 --- /dev/null +++ b/packages/ui/src/components/pro-tip/pro-tip.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ProTip } from "./pro-tip"; + +const meta = { + args: { + children: "ProTip", + }, + component: ProTip, + title: "Components/ProTip", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/profile-section/profile-section.stories.tsx b/packages/ui/src/components/profile-section/profile-section.stories.tsx new file mode 100644 index 0000000..a041c9f --- /dev/null +++ b/packages/ui/src/components/profile-section/profile-section.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ProfileSection } from "./profile-section"; + +const meta = { + component: ProfileSection, + title: "Components/ProfileSection", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/progress-bar/progress-bar.stories.tsx b/packages/ui/src/components/progress-bar/progress-bar.stories.tsx new file mode 100644 index 0000000..81bda47 --- /dev/null +++ b/packages/ui/src/components/progress-bar/progress-bar.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ProgressBar } from "./progress-bar"; + +const meta = { + component: ProgressBar, + title: "Components/ProgressBar", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/progress-card/progress-card.stories.tsx b/packages/ui/src/components/progress-card/progress-card.stories.tsx new file mode 100644 index 0000000..1f3392c --- /dev/null +++ b/packages/ui/src/components/progress-card/progress-card.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ContentCard } from "./progress-card"; + +const meta = { + component: ContentCard, + title: "Components/ProgressCard", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/quiz/quiz.stories.tsx b/packages/ui/src/components/quiz/quiz.stories.tsx new file mode 100644 index 0000000..44d8d68 --- /dev/null +++ b/packages/ui/src/components/quiz/quiz.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Quiz } from "./quiz"; + +const meta = { + args: { + children: "Quiz", + }, + component: Quiz, + title: "Components/Quiz", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/radio-group/radio-group.stories.tsx b/packages/ui/src/components/radio-group/radio-group.stories.tsx new file mode 100644 index 0000000..0beed16 --- /dev/null +++ b/packages/ui/src/components/radio-group/radio-group.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { RadioGroup } from "./radio-group"; + +const meta = { + component: RadioGroup, + title: "Components/RadioGroup", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/resizable/resizable.stories.tsx b/packages/ui/src/components/resizable/resizable.stories.tsx new file mode 100644 index 0000000..c5ac4dc --- /dev/null +++ b/packages/ui/src/components/resizable/resizable.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ResizableHandle } from "./resizable"; + +const meta = { + component: ResizableHandle, + title: "Components/Resizable", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/scroll-area/scroll-area.stories.tsx b/packages/ui/src/components/scroll-area/scroll-area.stories.tsx new file mode 100644 index 0000000..18b9213 --- /dev/null +++ b/packages/ui/src/components/scroll-area/scroll-area.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ScrollArea } from "./scroll-area"; + +const meta = { + args: { + children: "ScrollArea", + }, + component: ScrollArea, + title: "Components/ScrollArea", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/search-bar/search-bar.stories.tsx b/packages/ui/src/components/search-bar/search-bar.stories.tsx new file mode 100644 index 0000000..2bcdd23 --- /dev/null +++ b/packages/ui/src/components/search-bar/search-bar.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { SearchBar } from "./search-bar"; + +const meta = { + component: SearchBar, + title: "Components/SearchBar", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/search-dialog/search-dialog.stories.tsx b/packages/ui/src/components/search-dialog/search-dialog.stories.tsx new file mode 100644 index 0000000..2d5130f --- /dev/null +++ b/packages/ui/src/components/search-dialog/search-dialog.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { SearchDialog } from "./search-dialog"; + +const meta = { + component: SearchDialog, + title: "Components/SearchDialog", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/select/select.stories.tsx b/packages/ui/src/components/select/select.stories.tsx new file mode 100644 index 0000000..03956c7 --- /dev/null +++ b/packages/ui/src/components/select/select.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Select } from "./select"; + +const meta = { + component: Select, + title: "Components/Select", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/separator/separator.stories.tsx b/packages/ui/src/components/separator/separator.stories.tsx new file mode 100644 index 0000000..0340407 --- /dev/null +++ b/packages/ui/src/components/separator/separator.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Separator } from "./separator"; + +const meta = { + component: Separator, + title: "Components/Separator", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/share-dialog/share-dialog.stories.tsx b/packages/ui/src/components/share-dialog/share-dialog.stories.tsx new file mode 100644 index 0000000..3e14289 --- /dev/null +++ b/packages/ui/src/components/share-dialog/share-dialog.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ShareDialog } from "./share-dialog"; + +const meta = { + component: ShareDialog, + title: "Components/ShareDialog", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/share-section/share-section.stories.tsx b/packages/ui/src/components/share-section/share-section.stories.tsx new file mode 100644 index 0000000..66255a3 --- /dev/null +++ b/packages/ui/src/components/share-section/share-section.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ShareSection } from "./share-section"; + +const meta = { + component: ShareSection, + title: "Components/ShareSection", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/sheet/sheet.stories.tsx b/packages/ui/src/components/sheet/sheet.stories.tsx new file mode 100644 index 0000000..e867b6c --- /dev/null +++ b/packages/ui/src/components/sheet/sheet.stories.tsx @@ -0,0 +1,88 @@ +// manual +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "./sheet"; + +const meta = { + component: Sheet, + parameters: { + layout: "centered", + }, + title: "Components/Sheet", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + Sheet Title + + Sheet description with contextual information. + + +
Sheet body content goes here.
+
+
+ ), +}; + +export const Left: Story = { + render: () => ( + + + + + + + Navigation + Left-side navigation panel. + + + + ), +}; + +export const Bottom: Story = { + render: () => ( + + + + + + + Details + Bottom-side panel. + + + + ), +}; diff --git a/packages/ui/src/components/sidebar-provider/sidebar-provider.stories.tsx b/packages/ui/src/components/sidebar-provider/sidebar-provider.stories.tsx new file mode 100644 index 0000000..edb9c65 --- /dev/null +++ b/packages/ui/src/components/sidebar-provider/sidebar-provider.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { SidebarProvider } from "./sidebar-provider"; + +const meta = { + component: SidebarProvider, + title: "Components/SidebarProvider", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/sidebar-toggle/sidebar-toggle.stories.tsx b/packages/ui/src/components/sidebar-toggle/sidebar-toggle.stories.tsx new file mode 100644 index 0000000..4f8efa0 --- /dev/null +++ b/packages/ui/src/components/sidebar-toggle/sidebar-toggle.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { SidebarToggle } from "./sidebar-toggle"; + +const meta = { + component: SidebarToggle, + title: "Components/SidebarToggle", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/sidebar/sidebar.stories.tsx b/packages/ui/src/components/sidebar/sidebar.stories.tsx new file mode 100644 index 0000000..d163673 --- /dev/null +++ b/packages/ui/src/components/sidebar/sidebar.stories.tsx @@ -0,0 +1,63 @@ +// manual +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { SidebarProvider } from "../sidebar-provider"; + +import { Sidebar } from "./sidebar"; + +const sampleSections = [ + { + items: [ + { href: "/introduction", title: "Introduction" }, + { href: "/installation", title: "Installation" }, + { href: "/quickstart", title: "Quick Start" }, + ], + title: "Getting Started", + }, + { + collapsible: true, + defaultOpen: true, + items: [ + { href: "/button", title: "Button" }, + { href: "/input", title: "Input" }, + { href: "/dialog", title: "Dialog" }, + { href: "/dropdown", title: "Dropdown Menu" }, + ], + title: "Components", + }, + { + collapsible: true, + defaultOpen: false, + items: [ + { href: "/theming", title: "Theming" }, + { href: "/customization", title: "Customization" }, + ], + title: "Advanced", + }, +]; + +const meta = { + component: Sidebar, + decorators: [ + (Story) => ( + +
+ +
+
+ ), + ], + parameters: { + layout: "fullscreen", + }, + title: "Components/Sidebar", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + sections: sampleSections, + }, +}; diff --git a/packages/ui/src/components/skeleton/skeleton.stories.tsx b/packages/ui/src/components/skeleton/skeleton.stories.tsx new file mode 100644 index 0000000..51a500a --- /dev/null +++ b/packages/ui/src/components/skeleton/skeleton.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Skeleton } from "./skeleton"; + +const meta = { + component: Skeleton, + title: "Components/Skeleton", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/slider/slider.stories.tsx b/packages/ui/src/components/slider/slider.stories.tsx new file mode 100644 index 0000000..c8bb989 --- /dev/null +++ b/packages/ui/src/components/slider/slider.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Slider } from "./slider"; + +const meta = { + component: Slider, + title: "Components/Slider", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/slideshow/slideshow.stories.tsx b/packages/ui/src/components/slideshow/slideshow.stories.tsx new file mode 100644 index 0000000..d89a96e --- /dev/null +++ b/packages/ui/src/components/slideshow/slideshow.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Slideshow } from "./slideshow"; + +const meta = { + component: Slideshow, + title: "Components/Slideshow", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/social-fab/social-fab.stories.tsx b/packages/ui/src/components/social-fab/social-fab.stories.tsx new file mode 100644 index 0000000..c3a1c55 --- /dev/null +++ b/packages/ui/src/components/social-fab/social-fab.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { SocialFAB } from "./social-fab"; + +const meta = { + component: SocialFAB, + title: "Components/SocialFab", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/spinner/spinner.stories.tsx b/packages/ui/src/components/spinner/spinner.stories.tsx new file mode 100644 index 0000000..eb69015 --- /dev/null +++ b/packages/ui/src/components/spinner/spinner.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Spinner } from "./spinner"; + +const meta = { + component: Spinner, + title: "Components/Spinner", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/step-by-step/step-by-step.stories.tsx b/packages/ui/src/components/step-by-step/step-by-step.stories.tsx new file mode 100644 index 0000000..f3d518f --- /dev/null +++ b/packages/ui/src/components/step-by-step/step-by-step.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { StepByStep } from "./step-by-step"; + +const meta = { + args: { + children: "StepByStep", + }, + component: StepByStep, + title: "Components/StepByStep", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/step-navigation/step-navigation.stories.tsx b/packages/ui/src/components/step-navigation/step-navigation.stories.tsx new file mode 100644 index 0000000..a507914 --- /dev/null +++ b/packages/ui/src/components/step-navigation/step-navigation.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { StepNavigation } from "./step-navigation"; + +const meta = { + component: StepNavigation, + title: "Components/StepNavigation", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/switch/switch.stories.tsx b/packages/ui/src/components/switch/switch.stories.tsx new file mode 100644 index 0000000..707ff54 --- /dev/null +++ b/packages/ui/src/components/switch/switch.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Switch } from "./switch"; + +const meta = { + component: Switch, + title: "Components/Switch", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.stories.tsx b/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.stories.tsx new file mode 100644 index 0000000..6d8208a --- /dev/null +++ b/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { TableOfContentsPanel } from "./table-of-contents-panel"; + +const meta = { + component: TableOfContentsPanel, + title: "Components/TableOfContentsPanel", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/table-of-contents/table-of-contents.stories.tsx b/packages/ui/src/components/table-of-contents/table-of-contents.stories.tsx new file mode 100644 index 0000000..17cf9d3 --- /dev/null +++ b/packages/ui/src/components/table-of-contents/table-of-contents.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { TableOfContents } from "./table-of-contents"; + +const meta = { + component: TableOfContents, + title: "Components/TableOfContents", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/table/table.stories.tsx b/packages/ui/src/components/table/table.stories.tsx new file mode 100644 index 0000000..25fa8cf --- /dev/null +++ b/packages/ui/src/components/table/table.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Table } from "./table"; + +const meta = { + args: { + children: "Table", + }, + component: Table, + title: "Components/Table", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/tabs/tabs.stories.tsx b/packages/ui/src/components/tabs/tabs.stories.tsx new file mode 100644 index 0000000..7b706e6 --- /dev/null +++ b/packages/ui/src/components/tabs/tabs.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Tabs } from "./tabs"; + +const meta = { + args: { + children: "Tabs", + }, + component: Tabs, + title: "Components/Tabs", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/terminal/terminal.stories.tsx b/packages/ui/src/components/terminal/terminal.stories.tsx new file mode 100644 index 0000000..04c5c9d --- /dev/null +++ b/packages/ui/src/components/terminal/terminal.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Terminal } from "./terminal"; + +const meta = { + component: Terminal, + title: "Components/Terminal", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/textarea/textarea.stories.tsx b/packages/ui/src/components/textarea/textarea.stories.tsx new file mode 100644 index 0000000..d18221d --- /dev/null +++ b/packages/ui/src/components/textarea/textarea.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Textarea } from "./textarea"; + +const meta = { + component: Textarea, + title: "Components/Textarea", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/theme-provider/theme-provider.stories.tsx b/packages/ui/src/components/theme-provider/theme-provider.stories.tsx new file mode 100644 index 0000000..77d79fd --- /dev/null +++ b/packages/ui/src/components/theme-provider/theme-provider.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ThemeProvider } from "./theme-provider"; + +const meta = { + component: ThemeProvider, + title: "Components/ThemeProvider", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/theme-toggle/theme-toggle.stories.tsx b/packages/ui/src/components/theme-toggle/theme-toggle.stories.tsx new file mode 100644 index 0000000..a14de1e --- /dev/null +++ b/packages/ui/src/components/theme-toggle/theme-toggle.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ThemeToggle } from "./theme-toggle"; + +const meta = { + component: ThemeToggle, + title: "Components/ThemeToggle", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/thinking-block/thinking-block.stories.tsx b/packages/ui/src/components/thinking-block/thinking-block.stories.tsx new file mode 100644 index 0000000..ee80995 --- /dev/null +++ b/packages/ui/src/components/thinking-block/thinking-block.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ThinkingBlock } from "./thinking-block"; + +const meta = { + component: ThinkingBlock, + title: "Components/ThinkingBlock", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/tldr-section/tldr-section.stories.tsx b/packages/ui/src/components/tldr-section/tldr-section.stories.tsx new file mode 100644 index 0000000..92f483f --- /dev/null +++ b/packages/ui/src/components/tldr-section/tldr-section.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { TLDRSection } from "./tldr-section"; + +const meta = { + args: { + children: "TldrSection", + }, + component: TLDRSection, + title: "Components/TldrSection", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/toast/toast.stories.tsx b/packages/ui/src/components/toast/toast.stories.tsx new file mode 100644 index 0000000..e04aa87 --- /dev/null +++ b/packages/ui/src/components/toast/toast.stories.tsx @@ -0,0 +1,71 @@ +// manual +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { + Toast, + ToastAction, + ToastClose, + ToastDescription, + ToastTitle, +} from "./toast"; + +const meta = { + args: { + variant: "default", + }, + argTypes: { + variant: { + control: "select", + options: ["default", "destructive"], + }, + }, + component: Toast, + parameters: { + layout: "centered", + }, + title: "Components/Toast", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (arguments_) => ( + +
+ Notification + Your changes have been saved. +
+ +
+ ), +}; + +export const Destructive: Story = { + args: { + variant: "destructive", + }, + render: (arguments_) => ( + +
+ Error + + Something went wrong. Please try again. + +
+ +
+ ), +}; + +export const WithAction: Story = { + render: (arguments_) => ( + +
+ Update available + A new version is ready to install. +
+ Update +
+ ), +}; diff --git a/packages/ui/src/components/toggle-group/toggle-group.stories.tsx b/packages/ui/src/components/toggle-group/toggle-group.stories.tsx new file mode 100644 index 0000000..fcbccef --- /dev/null +++ b/packages/ui/src/components/toggle-group/toggle-group.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ToggleGroup } from "./toggle-group"; + +const meta = { + component: ToggleGroup, + title: "Components/ToggleGroup", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/toggle/toggle.stories.tsx b/packages/ui/src/components/toggle/toggle.stories.tsx new file mode 100644 index 0000000..d1b9ebc --- /dev/null +++ b/packages/ui/src/components/toggle/toggle.stories.tsx @@ -0,0 +1,45 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Toggle } from "./toggle"; + +const meta = { + args: { + size: "default", + variant: "default", + }, + argTypes: { + size: { + control: "select", + options: ["default", "lg", "sm"], + }, + variant: { + control: "select", + options: ["default", "outline"], + }, + }, + component: Toggle, + title: "Components/Toggle", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const SizeLg: Story = { + args: { + size: "lg", + }, +}; + +export const SizeSm: Story = { + args: { + size: "sm", + }, +}; + +export const VariantOutline: Story = { + args: { + variant: "outline", + }, +}; diff --git a/packages/ui/src/components/tooltip/tooltip.stories.tsx b/packages/ui/src/components/tooltip/tooltip.stories.tsx new file mode 100644 index 0000000..fb1ff55 --- /dev/null +++ b/packages/ui/src/components/tooltip/tooltip.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { Tooltip } from "./tooltip"; + +const meta = { + args: { + children: "Tooltip", + }, + component: Tooltip, + title: "Components/Tooltip", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/truncated-text/truncated-text.stories.tsx b/packages/ui/src/components/truncated-text/truncated-text.stories.tsx new file mode 100644 index 0000000..df70562 --- /dev/null +++ b/packages/ui/src/components/truncated-text/truncated-text.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { TruncatedText } from "./truncated-text"; + +const meta = { + component: TruncatedText, + title: "Components/TruncatedText", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/tutorial-card/tutorial-card.stories.tsx b/packages/ui/src/components/tutorial-card/tutorial-card.stories.tsx new file mode 100644 index 0000000..b4b48b9 --- /dev/null +++ b/packages/ui/src/components/tutorial-card/tutorial-card.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { TutorialCard } from "./tutorial-card"; + +const meta = { + component: TutorialCard, + title: "Components/TutorialCard", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/tutorial-complete/tutorial-complete.stories.tsx b/packages/ui/src/components/tutorial-complete/tutorial-complete.stories.tsx new file mode 100644 index 0000000..24c68c0 --- /dev/null +++ b/packages/ui/src/components/tutorial-complete/tutorial-complete.stories.tsx @@ -0,0 +1,46 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { TutorialComplete } from "./tutorial-complete"; + +const noop = (): void => undefined; + +const meta = { + args: { + backHref: "/tutorials", + completedSections: new Set(["intro", "getting-started", "advanced"]), + completionPercent: 100, + labels: { + backToTutorials: "Back to Tutorials", + profileName: "Jane Doe", + profileTagline: "React Developer", + relatedContent: "Continue Learning", + reviewSections: "Review Sections", + shareOn: "Share on", + shareTitle: "I just completed this tutorial!", + startOver: "Start Over", + tutorialComplete: "Tutorial Complete!", + tutorialFinished: "Tutorial Finished", + youveCompletedAll: "You've completed all sections of", + youveFinishedWith: "You've finished with", + }, + onGoToSection: noop, + onRestart: noop, + relatedContent: [ + { href: "/next-tutorial", title: "Next Steps", type: "Tutorial" }, + ], + sections: [ + { id: "intro", title: "Introduction" }, + { id: "getting-started", title: "Getting Started" }, + { id: "advanced", title: "Advanced Concepts" }, + ], + shareUrl: "https://example.com/tutorial", + title: "React Fundamentals", + }, + component: TutorialComplete, + title: "Components/TutorialComplete", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/tutorial-filters/tutorial-filters.stories.tsx b/packages/ui/src/components/tutorial-filters/tutorial-filters.stories.tsx new file mode 100644 index 0000000..5151464 --- /dev/null +++ b/packages/ui/src/components/tutorial-filters/tutorial-filters.stories.tsx @@ -0,0 +1,38 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { TutorialFilters } from "./tutorial-filters"; + +const noop = (): void => undefined; + +const meta = { + args: { + currentDifficulty: "all", + currentTags: [], + labels: { + activeFilters: "Active filters:", + clear: "Clear", + clearAll: "Clear all", + difficulty: { + advanced: "Advanced", + all: "All Levels", + beginner: "Beginner", + intermediate: "Intermediate", + }, + difficultyLabel: "Difficulty", + searchFilter: "Search", + searchLabel: "Search tutorials", + searchPlaceholder: "Search by title or keyword...", + tagsLabel: "Topics", + }, + onFilterChange: noop, + searchQuery: "", + tags: ["React", "TypeScript", "Tailwind", "Components"], + }, + component: TutorialFilters, + title: "Components/TutorialFilters", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.stories.tsx b/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.stories.tsx new file mode 100644 index 0000000..0381c40 --- /dev/null +++ b/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { TutorialIntroContent } from "./tutorial-intro-content"; + +const meta = { + args: { + content: + "This tutorial covers the fundamentals of building modern React applications with TypeScript and Tailwind CSS.", + title: "React Fundamentals", + }, + component: TutorialIntroContent, + title: "Components/TutorialIntroContent", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/tutorial-mdx/tutorial-mdx.stories.tsx b/packages/ui/src/components/tutorial-mdx/tutorial-mdx.stories.tsx new file mode 100644 index 0000000..693c4ab --- /dev/null +++ b/packages/ui/src/components/tutorial-mdx/tutorial-mdx.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { TutorialMDX } from "./tutorial-mdx"; + +const meta = { + args: { + content: + "# Advanced React Patterns\n\nLearn about compound components, render props, and custom hooks.", + }, + component: TutorialMDX, + title: "Components/TutorialMdx", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/video-embed/video-embed.stories.tsx b/packages/ui/src/components/video-embed/video-embed.stories.tsx new file mode 100644 index 0000000..e276a63 --- /dev/null +++ b/packages/ui/src/components/video-embed/video-embed.stories.tsx @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { VideoEmbed } from "./video-embed"; + +const meta = { + args: { + src: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + title: "Tutorial Video", + }, + argTypes: { + aspectRatio: { + control: "select", + options: ["1/1", "4/3", "16/9"], + }, + type: { + control: "select", + options: ["custom", "vimeo", "youtube"], + }, + }, + component: VideoEmbed, + title: "Components/VideoEmbed", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/src/components/view-switcher/view-switcher.stories.tsx b/packages/ui/src/components/view-switcher/view-switcher.stories.tsx new file mode 100644 index 0000000..9d24d5b --- /dev/null +++ b/packages/ui/src/components/view-switcher/view-switcher.stories.tsx @@ -0,0 +1,21 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; + +import { ViewSwitcher } from "./view-switcher"; + +const meta = { + args: { + defaultKey: "list", + options: [ + { key: "list", label: "List View" }, + { key: "grid", label: "Grid View" }, + { key: "table", label: "Table View" }, + ], + }, + component: ViewSwitcher, + title: "Components/ViewSwitcher", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index d192a4b..0900042 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -8,5 +8,5 @@ "types": ["vitest/globals", "@testing-library/jest-dom"] }, "include": ["src", "vitest.config.ts", "playwright-ct.config.ts", "playwright", "scripts", "tailwind.config.ts", "postcss.config.mjs"], - "exclude": ["node_modules"] + "exclude": ["node_modules", "src/**/*.stories.ts", "src/**/*.stories.tsx"] } diff --git a/packages/ui/tsup.config.ts b/packages/ui/tsup.config.ts index 7d924bf..341e3f5 100644 --- a/packages/ui/tsup.config.ts +++ b/packages/ui/tsup.config.ts @@ -8,6 +8,7 @@ export default defineConfig([ 'src/**/*.{ts,tsx}', '!src/**/*.test.*', '!src/**/*.visual.*', + '!src/**/*.stories.*', '!src/**/__tests__/**', ], format: ['esm'], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8c6e6d7..3dcff6e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -244,6 +244,24 @@ importers: '@playwright/experimental-ct-react': specifier: ^1.57.0 version: 1.58.2(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0)(vite@7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0)) + '@storybook/addon-a11y': + specifier: ^10.2.17 + version: 10.2.17(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + '@storybook/addon-designs': + specifier: ^11.1.2 + version: 11.1.2(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + '@storybook/addon-mcp': + specifier: ^0.3.4 + version: 0.3.4(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + '@storybook/addon-themes': + specifier: ^10.2.17 + version: 10.2.17(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + '@storybook/react-vite': + specifier: ^10.2.17 + version: 10.2.17(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0)) + '@storybook/test-runner': + specifier: ^0.24.2 + version: 0.24.2(@types/node@22.19.10)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -286,6 +304,9 @@ importers: postcss: specifier: ^8.5.6 version: 8.5.6 + storybook: + specifier: ^10.2.17 + version: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tailwindcss: specifier: ^3.4.17 version: 3.4.19(tsx@4.21.0) @@ -294,7 +315,7 @@ importers: version: 1.0.7(tailwindcss@3.4.19(tsx@4.21.0)) tsup: specifier: ^8.5.0 - version: 8.5.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3) + version: 8.5.1(@swc/core@1.15.18)(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3) tsx: specifier: ^4.21.0 version: 4.21.0 @@ -408,12 +429,91 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-jsx@7.28.6': resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-typescript@7.28.6': resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} @@ -466,6 +566,9 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} @@ -520,9 +623,15 @@ packages: peerDependencies: '@noble/ciphers': ^1.0.0 + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + '@emnapi/runtime@1.8.1': resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} @@ -1029,6 +1138,14 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@figspec/components@2.1.0': + resolution: {integrity: sha512-PFKBX2oFz+vhThKTNsu7Mh4ZT3X7YCiM694UkAMT36j/p0tdmXs9Je0Sf88stTEcMgwYvNv9TZtvniYmgaE+bw==} + + '@figspec/react@2.0.1': + resolution: {integrity: sha512-xflqJ3XQZVzm8+7dsm8OFxVAmBNNA3Mg65sqwNHiq7VRSMSD7qwH4BPsBy07ZaX+9nHeaacBpFZd3Q0aIsISqw==} + peerDependencies: + react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@floating-ui/core@1.7.4': resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} @@ -1044,6 +1161,12 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + '@hono/node-server@1.19.11': resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} engines: {node: '>=18.14.1'} @@ -1238,6 +1361,113 @@ packages: '@types/node': optional: true + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@30.3.0': + resolution: {integrity: sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/core@30.3.0': + resolution: {integrity: sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/create-cache-key-function@30.3.0': + resolution: {integrity: sha512-hTupmOWylzeyqbMNeSNi7ZDprpjrcroAOOG+qCEW66st3+Z5RnYHVYkUt+zjIcLmrTUi2lPY79hJz8mB3L2oXQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/diff-sequences@30.3.0': + resolution: {integrity: sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/environment@30.3.0': + resolution: {integrity: sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect-utils@30.3.0': + resolution: {integrity: sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect@30.3.0': + resolution: {integrity: sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/fake-timers@30.3.0': + resolution: {integrity: sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/get-type@30.1.0': + resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/globals@30.3.0': + resolution: {integrity: sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/pattern@30.0.1': + resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/reporters@30.3.0': + resolution: {integrity: sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@30.0.5': + resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/snapshot-utils@30.3.0': + resolution: {integrity: sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/source-map@30.0.1': + resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-result@30.3.0': + resolution: {integrity: sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-sequencer@30.3.0': + resolution: {integrity: sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/transform@30.3.0': + resolution: {integrity: sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/types@30.3.0': + resolution: {integrity: sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4': + resolution: {integrity: sha512-6PyZBYKnnVNqOSB0YFly+62R7dmov8segT27A+RVTBVd4iAE6kbW9QBJGlyR2yG4D4ohzhZSTIu7BK1UTtmFFA==} + peerDependencies: + typescript: '>= 4.3.x' + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + typescript: + optional: true + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1254,6 +1484,14 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@lit-labs/react@2.1.3': + resolution: {integrity: sha512-OD9h2JynerBQUMNzb563jiVpxfvPF0HjQkKY2mx0lpVYvD7F+rtJpOGz6ek+6ufMidV3i+MPT9SX62OKWHFrQg==} + + '@lit/react@1.0.8': + resolution: {integrity: sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==} + peerDependencies: + '@types/react': 17 || 18 || 19 + '@mdx-js/mdx@3.1.1': resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} @@ -1271,6 +1509,9 @@ packages: resolution: {integrity: sha512-7G0Uf0yK3f2bjElBLGHIQzgRgMESczOMyYVasq1XK8P5HaXtlW4eQhz9MBL+TQILZLaruq+ClGId+hH0w4jvWw==} engines: {node: '>=18'} + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + '@next/env@16.1.6': resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} @@ -1369,6 +1610,10 @@ packages: '@open-draft/until@2.1.0': resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@pkgr/core@0.2.9': resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -1989,6 +2234,15 @@ packages: '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: '>=4.59.0' + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.59.0': resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} cpu: [arm] @@ -2117,16 +2371,218 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + + '@sinclair/typebox@0.34.48': + resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} + '@sindresorhus/merge-streams@4.0.0': resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@15.1.1': + resolution: {integrity: sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==} + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@storybook/addon-a11y@10.2.17': + resolution: {integrity: sha512-J0ogEc4/XFC+Ytz+X1we6TOKreEk/shgUs/mtxdsLa0xJ6bp2n2OQPSjNtQHH/nK4SRBSfHWPm8ztfcXTzeG9w==} + peerDependencies: + storybook: ^10.2.17 + + '@storybook/addon-designs@11.1.2': + resolution: {integrity: sha512-d9tOOJSNrUOshK0hvnDtR17uk/gfDAbs0DKGRaKe0VacUVLJkJEPor4OpxKKFG59qtSi4iU1FYyb668hfMdCdw==} + peerDependencies: + '@storybook/addon-docs': ^10.0.0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + storybook: ^10.0.0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 + peerDependenciesMeta: + '@storybook/addon-docs': + optional: true + react: + optional: true + react-dom: + optional: true + + '@storybook/addon-mcp@0.3.4': + resolution: {integrity: sha512-d01mKM4Fc/wNcxWOdwc1kTIZNRGvZso2MiwVpmQS83myuFDMFkSQZq/QpkPOcQx2XqQqawuY/k/yxe5e+WD0DQ==} + peerDependencies: + '@storybook/addon-vitest': ^9.1.16 || ^10.0.0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 + storybook: ^9.1.16 || ^10.0.0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 + peerDependenciesMeta: + '@storybook/addon-vitest': + optional: true + + '@storybook/addon-themes@10.2.17': + resolution: {integrity: sha512-5AJ6h/i967CEDG3DNstfgKo9ysDNIOb1pnbn8VbcD/Fw8D2dZm7pLkTAQOnxu6lFQaIU10DIiVp7cviBMasDUg==} + peerDependencies: + storybook: ^10.2.17 + + '@storybook/builder-vite@10.2.17': + resolution: {integrity: sha512-m/OBveTLm5ds/tUgHmmbKzgSi/oeCpQwm5rZa49vP2BpAd41Q7ER6TzkOoISzPoNNMAcbVmVc5vn7k6hdbPSHw==} + peerDependencies: + storybook: ^10.2.17 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@storybook/csf-plugin@10.2.17': + resolution: {integrity: sha512-crHH8i/4mwzeXpWRPgwvwX2vjytW42zyzTRySUax5dTU8o9sjk4y+Z9hkGx3Nmu1TvqseS8v1Z20saZr/tQcWw==} + peerDependencies: + esbuild: '*' + rollup: '>=4.59.0' + storybook: ^10.2.17 + vite: '*' + webpack: '*' + peerDependenciesMeta: + esbuild: + optional: true + rollup: + optional: true + vite: + optional: true + webpack: + optional: true + + '@storybook/global@5.0.0': + resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} + + '@storybook/icons@2.0.1': + resolution: {integrity: sha512-/smVjw88yK3CKsiuR71vNgWQ9+NuY2L+e8X7IMrFjexjm6ZR8ULrV2DRkTA61aV6ryefslzHEGDInGpnNeIocg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@storybook/mcp@0.5.1': + resolution: {integrity: sha512-Sa9nrvnzI6y+dJ63cc1krZmeLjUGqvgGRaBsccBUja4cm5/jxIau20CM61MCX1jg9I7FzrwnnXSmifw2LtT+Cg==} + + '@storybook/react-dom-shim@10.2.17': + resolution: {integrity: sha512-x9Kb7eUSZ1zGsEw/TtWrvs1LwWIdNp8qoOQCgPEjdB07reSJcE8R3+ASWHJThmd4eZf66ZALPJyerejake4Osw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + storybook: ^10.2.17 + + '@storybook/react-vite@10.2.17': + resolution: {integrity: sha512-E/1hNmxVsjy9l3TuaNufSqkdz8saTJUGEs8GRCjKlF7be2wljIwewUxjAT3efk+bxOCw76ZmqGHk6MnRa3y7Gw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + storybook: ^10.2.17 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@storybook/react@10.2.17': + resolution: {integrity: sha512-875AVMYil2X9Civil6GFZ8koIzlKxcXbl2eJ7+/GPbhIonTNmwx0qbWPHttjZXUvFuQ4RRtb9KkBwy4TCb/LeA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + storybook: ^10.2.17 + typescript: '>= 4.9.x' + peerDependenciesMeta: + typescript: + optional: true + + '@storybook/test-runner@0.24.2': + resolution: {integrity: sha512-76DbflDTGAKq8Af6uHbWTGnKzKHhjLbJaZXRFhVnKqFocoXcej58C9DpM0BJ3addu7fSDJmPwfR97OINg16XFQ==} + engines: {node: '>=20.0.0'} + hasBin: true + peerDependencies: + storybook: ^0.0.0-0 || ^10.0.0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 + + '@swc/core-darwin-arm64@1.15.18': + resolution: {integrity: sha512-+mIv7uBuSaywN3C9LNuWaX1jJJ3SKfiJuE6Lr3bd+/1Iv8oMU7oLBjYMluX1UrEPzwN2qCdY6Io0yVicABoCwQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.15.18': + resolution: {integrity: sha512-wZle0eaQhnzxWX5V/2kEOI6Z9vl/lTFEC6V4EWcn+5pDjhemCpQv9e/TDJ0GIoiClX8EDWRvuZwh+Z3dhL1NAg==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.15.18': + resolution: {integrity: sha512-ao61HGXVqrJFHAcPtF4/DegmwEkVCo4HApnotLU8ognfmU8x589z7+tcf3hU+qBiU1WOXV5fQX6W9Nzs6hjxDw==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.15.18': + resolution: {integrity: sha512-3xnctOBLIq3kj8PxOCgPrGjBLP/kNOddr6f5gukYt/1IZxsITQaU9TDyjeX6jG+FiCIHjCuWuffsyQDL5Ew1bg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-arm64-musl@1.15.18': + resolution: {integrity: sha512-0a+Lix+FSSHBSBOA0XznCcHo5/1nA6oLLjcnocvzXeqtdjnPb+SvchItHI+lfeiuj1sClYPDvPMLSLyXFaiIKw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-x64-gnu@1.15.18': + resolution: {integrity: sha512-wG9J8vReUlpaHz4KOD/5UE1AUgirimU4UFT9oZmupUDEofxJKYb1mTA/DrMj0s78bkBiNI+7Fo2EgPuvOJfuAA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-linux-x64-musl@1.15.18': + resolution: {integrity: sha512-4nwbVvCphKzicwNWRmvD5iBaZj8JYsRGa4xOxJmOyHlMDpsvvJ2OR2cODlvWyGFH6BYL1MfIAK3qph3hp0Az6g==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-win32-arm64-msvc@1.15.18': + resolution: {integrity: sha512-zk0RYO+LjiBCat2RTMHzAWaMky0cra9loH4oRrLKLLNuL+jarxKLFDA8xTZWEkCPLjUTwlRN7d28eDLLMgtUcQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.15.18': + resolution: {integrity: sha512-yVuTrZ0RccD5+PEkpcLOBAuPbYBXS6rslENvIXfvJGXSdX5QGi1ehC4BjAMl5FkKLiam4kJECUI0l7Hq7T1vwg==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.15.18': + resolution: {integrity: sha512-7NRmE4hmUQNCbYU3Hn9Tz57mK9Qq4c97ZS+YlamlK6qG9Fb5g/BB3gPDe0iLlJkns/sYv2VWSkm8c3NmbEGjbg==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.15.18': + resolution: {integrity: sha512-z87aF9GphWp//fnkRsqvtY+inMVPgYW3zSlXH1kJFvRT5H/wiAn+G32qW5l3oEk63KSF1x3Ov0BfHCObAmT8RA==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@swc/jest@0.2.39': + resolution: {integrity: sha512-eyokjOwYd0Q8RnMHri+8/FS1HIrIUKK/sRrFp8c1dThUOfNeCWbLmBP1P5VsKdvmkd25JaH+OKYwEYiAYg9YAA==} + engines: {npm: '>= 7.0.0'} + peerDependencies: + '@swc/core': '*' + + '@swc/types@0.1.25': + resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==} + '@tailwindcss/typography@0.5.19': resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} peerDependencies: @@ -2166,9 +2622,38 @@ packages: '@types/react-dom': optional: true + '@testing-library/user-event@14.6.1': + resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + + '@tmcp/adapter-valibot@0.1.5': + resolution: {integrity: sha512-9P2wrVYPngemNK0UvPb/opC722/jfd09QxXmme1TRp/wPsl98vpSk/MXt24BCMqBRv4Dvs0xxJH4KHDcjXW52Q==} + peerDependencies: + tmcp: ^1.17.0 + valibot: ^1.1.0 + + '@tmcp/session-manager@0.2.1': + resolution: {integrity: sha512-DOGy9LfufXCy1wfpGHZ6qPSDQtRnTVwOb71+41ffovTqzLMZlK3iLK/LIsekHxIiku+iIAUiqEKN+DHbqEm8IA==} + peerDependencies: + tmcp: ^1.16.3 + + '@tmcp/transport-http@0.8.5': + resolution: {integrity: sha512-qQLqiCTtbxtTSswqOn/782df7O57RxI/yLUtCDQ++kHEhbmDUc8glmmtGJ3mrb7yPSPoM5VF2Pc2Q5cA6quzLA==} + peerDependencies: + '@tmcp/auth': ^0.3.3 || ^0.4.0 + tmcp: ^1.18.0 + peerDependenciesMeta: + '@tmcp/auth': + optional: true + '@ts-morph/common@0.27.0': resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -2211,6 +2696,9 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/doctrine@0.0.9': + resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} + '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} @@ -2220,6 +2708,15 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -2249,6 +2746,12 @@ packages: '@types/react@19.2.13': resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} + '@types/resolve@1.20.6': + resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} @@ -2258,6 +2761,15 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/wait-on@5.3.4': + resolution: {integrity: sha512-EBsPjFMrFlMbbUFf9D1Fp+PAB2TwmUn7a3YtHyD9RLuTIk1jDd8SxXVAoez2Ciy+8Jsceo2MYEYZzJ/DvorOKw==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + '@typescript-eslint/eslint-plugin@8.56.1': resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2401,35 +2913,135 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - '@vercel/analytics@1.6.1': - resolution: {integrity: sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==} - peerDependencies: - '@remix-run/react': ^2 - '@sveltejs/kit': ^1 || ^2 - next: '>=16.1.6' - react: ^18 || ^19 || ^19.0.0-rc - svelte: '>= 4' - vue: ^3 - vue-router: ^4 - peerDependenciesMeta: - '@remix-run/react': - optional: true - '@sveltejs/kit': - optional: true - next: - optional: true - react: - optional: true - svelte: - optional: true - vue: - optional: true - vue-router: - optional: true + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] - '@vercel/speed-insights@1.3.1': - resolution: {integrity: sha512-PbEr7FrMkUrGYvlcLHGkXdCkxnylCWePx7lPxxq36DNdfo9mcUjLOmqOyPDHAOgnfqgGGdmE3XI9L/4+5fr+vQ==} - peerDependencies: + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + '@valibot/to-json-schema@1.5.0': + resolution: {integrity: sha512-GE7DmSr1C2UCWPiV0upRH6mv0cCPsqYGs819fb6srCS1tWhyXrkGGe+zxUiwzn/L1BOfADH4sNjY/YHCuP8phQ==} + peerDependencies: + valibot: ^1.2.0 + + '@vercel/analytics@1.6.1': + resolution: {integrity: sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==} + peerDependencies: + '@remix-run/react': ^2 + '@sveltejs/kit': ^1 || ^2 + next: '>=16.1.6' + react: ^18 || ^19 || ^19.0.0-rc + svelte: '>= 4' + vue: ^3 + vue-router: ^4 + peerDependenciesMeta: + '@remix-run/react': + optional: true + '@sveltejs/kit': + optional: true + next: + optional: true + react: + optional: true + svelte: + optional: true + vue: + optional: true + vue-router: + optional: true + + '@vercel/speed-insights@1.3.1': + resolution: {integrity: sha512-PbEr7FrMkUrGYvlcLHGkXdCkxnylCWePx7lPxxq36DNdfo9mcUjLOmqOyPDHAOgnfqgGGdmE3XI9L/4+5fr+vQ==} + peerDependencies: '@sveltejs/kit': ^1 || ^2 next: '>=16.1.6' react: ^18 || ^19 || ^19.0.0-rc @@ -2465,6 +3077,9 @@ packages: '@vitest/browser': optional: true + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@vitest/expect@4.0.18': resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} @@ -2479,6 +3094,9 @@ packages: vite: optional: true + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@vitest/pretty-format@4.0.18': resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} @@ -2488,9 +3106,15 @@ packages: '@vitest/snapshot@4.0.18': resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + '@vitest/spy@4.0.18': resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vitest/utils@4.0.18': resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} @@ -2545,6 +3169,10 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -2559,6 +3187,14 @@ packages: ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2567,6 +3203,10 @@ packages: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -2575,6 +3215,10 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + ansis@4.2.0: resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} engines: {node: '>=14'} @@ -2586,9 +3230,19 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + append-transform@2.0.0: + resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==} + engines: {node: '>=8'} + + archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -2653,6 +3307,9 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.4.24: resolution: {integrity: sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==} engines: {node: ^10 || ^12 || >=14} @@ -2668,10 +3325,38 @@ packages: resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==} engines: {node: '>=4'} + axios@1.13.6: + resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + babel-jest@30.3.0: + resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 || ^8.0.0-0 + + babel-plugin-istanbul@7.0.1: + resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} + engines: {node: '>=12'} + + babel-plugin-jest-hoist@30.3.0: + resolution: {integrity: sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + babel-preset-current-node-syntax@1.2.0: + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} + peerDependencies: + '@babel/core': ^7.0.0 || ^8.0.0-0 + + babel-preset-jest@30.3.0: + resolution: {integrity: sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 || ^8.0.0-beta.1 + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -2710,10 +3395,20 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + builtin-modules@5.0.0: resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} engines: {node: '>=18.20'} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + bundle-require@5.1.0: resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2728,6 +3423,10 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + caching-transform@4.0.0: + resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -2748,16 +3447,32 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + caniuse-lite@1.0.30001769: resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -2769,6 +3484,10 @@ packages: change-case@5.4.4: resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} @@ -2781,6 +3500,10 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -2793,6 +3516,9 @@ packages: resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -2803,6 +3529,10 @@ packages: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -2818,6 +3548,9 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -2832,19 +3565,36 @@ packages: react: ^18 || ^19 || ^19.0.0-rc react-dom: ^18 || ^19 || ^19.0.0-rc + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + code-block-writer@13.0.3: resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + collect-v8-coverage@1.0.3: + resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -2852,6 +3602,10 @@ packages: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + commander@14.0.3: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} @@ -2859,10 +3613,16 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@3.0.2: + resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -2881,6 +3641,9 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -2947,6 +3710,10 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + cwd@0.10.0: + resolution: {integrity: sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==} + engines: {node: '>=0.8'} + d3-color@3.1.0: resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} engines: {node: '>=12'} @@ -3031,6 +3798,10 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} @@ -3045,6 +3816,10 @@ packages: babel-plugin-macros: optional: true + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -3056,14 +3831,34 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + + default-require-extensions@3.0.1: + resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==} + engines: {node: '>=8'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -3076,6 +3871,10 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} @@ -3089,6 +3888,9 @@ packages: resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} engines: {node: '>=0.3.1'} + diffable-html@4.1.0: + resolution: {integrity: sha512-++kyNek+YBLH8cLXS+iTj/Hiy2s5qkRJEJ8kgu/WHbFrVY2vz9xPFUT+fii2zGF0m1CaojDlQJjkfrCt7YWM1g==} + dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -3096,12 +3898,31 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + dom-serializer@0.2.2: + resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==} + + domelementtype@1.3.1: + resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@2.4.2: + resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==} + + domutils@1.7.0: + resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} + dotenv@16.0.3: resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} engines: {node: '>=12'} @@ -3117,6 +3938,9 @@ packages: e-prime@0.10.4: resolution: {integrity: sha512-tzBmM2mFSnAq5BuxPSyin6qXb3yMe1wufJN7L7ZPcEWS5S+jI2dhKQEoqHVEcSMMXo/j5lcWpX5jzA6wLSmX6w==} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + eciesjs@0.4.17: resolution: {integrity: sha512-TOOURki4G7sD1wDCjj7NfLaXZZ49dFOeEb5y39IXpb8p0hRzVvfvzZHOi5JcT+PpyAbi/Y+lxPb8eTag2WYH8w==} engines: {bun: '>=1', deno: '>=2', node: '>=16'} @@ -3140,6 +3964,10 @@ packages: embla-carousel@8.6.0: resolution: {integrity: sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==} + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -3149,10 +3977,20 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} + encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + entities@1.1.2: + resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==} + + entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} @@ -3161,6 +3999,10 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} @@ -3199,6 +4041,9 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + es6-error@4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} @@ -3231,6 +4076,10 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -3376,6 +4225,9 @@ packages: jiti: optional: true + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3415,6 +4267,9 @@ packages: estree-util-visit@2.0.0: resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -3442,10 +4297,30 @@ packages: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} + engines: {node: '>= 0.8.0'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expand-tilde@1.2.2: + resolution: {integrity: sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==} + engines: {node: '>=0.10.0'} + + expect-playwright@0.8.0: + resolution: {integrity: sha512-+kn8561vHAY+dt+0gMqqj1oY+g5xWrsuGMk4QGxotT2WS545nVqqjs37z6hrYfIuucwqthzwJfCJUEYqixyljg==} + deprecated: ⚠️ The 'expect-playwright' package is deprecated. The Playwright core assertions (via @playwright/test) now cover the same functionality. Please migrate to built-in expect. See https://playwright.dev/docs/test-assertions for migration. + expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + expect@30.3.0: + resolution: {integrity: sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + express-rate-limit@8.2.1: resolution: {integrity: sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==} engines: {node: '>= 16'} @@ -3488,6 +4363,9 @@ packages: fault@1.0.4: resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -3517,10 +4395,30 @@ packages: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} + find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + + find-file-up@0.1.3: + resolution: {integrity: sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==} + engines: {node: '>=0.10.0'} + + find-pkg@0.1.2: + resolution: {integrity: sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==} + engines: {node: '>=0.10.0'} + + find-process@1.4.11: + resolution: {integrity: sha512-mAOh9gGk9WZ4ip5UjV0o6Vb4SrfnAmtsFNzkMRH9HQiFXVQnDyQFrSHTK5UoG6E+KV+s+cIznbtwpfN41l2nFA==} + hasBin: true + find-up-simple@1.0.1: resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -3535,10 +4433,31 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} + foreground-child@2.0.0: + resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} + engines: {node: '>=8.0.0'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} @@ -3558,10 +4477,20 @@ packages: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} + fromentries@1.3.2: + resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} + + fs-exists-sync@0.1.0: + resolution: {integrity: sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==} + engines: {node: '>=0.10.0'} + fs-extra@11.3.3: resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} engines: {node: '>=14.14'} + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3616,6 +4545,10 @@ packages: resolution: {integrity: sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==} engines: {node: '>=14.16'} + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -3643,6 +4576,27 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + global-modules@0.2.3: + resolution: {integrity: sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==} + engines: {node: '>=0.10.0'} + + global-prefix@0.1.5: + resolution: {integrity: sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==} + engines: {node: '>=0.10.0'} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -3680,6 +4634,10 @@ packages: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -3699,6 +4657,10 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + hasha@5.2.2: + resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} + engines: {node: '>=8'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -3733,6 +4695,10 @@ packages: highlightjs-vue@1.0.0: resolution: {integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==} + homedir-polyfill@1.0.3: + resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} + engines: {node: '>=0.10.0'} + hono@4.12.5: resolution: {integrity: sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==} engines: {node: '>=16.9.0'} @@ -3750,6 +4716,9 @@ packages: html-url-attributes@3.0.1: resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + htmlparser2@3.10.1: + resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} + http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -3790,6 +4759,11 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -3802,9 +4776,16 @@ packages: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} @@ -3878,6 +4859,11 @@ packages: is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -3890,6 +4876,10 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + is-generator-function@1.1.2: resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} @@ -3907,6 +4897,11 @@ packages: eslint: '*' typescript: '>=4.7.4' + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-interactive@2.0.0: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} @@ -3980,6 +4975,9 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} @@ -4000,11 +4998,23 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + is-windows@0.2.0: + resolution: {integrity: sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==} + engines: {node: '>=0.10.0'} - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} isexe@3.1.5: resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} @@ -4014,10 +5024,34 @@ packages: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} + istanbul-lib-hook@3.0.0: + resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} + engines: {node: '>=8'} + + istanbul-lib-instrument@4.0.3: + resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-processinfo@2.0.3: + resolution: {integrity: sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==} + engines: {node: '>=8'} + istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + istanbul-reports@3.2.0: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} @@ -4026,10 +5060,161 @@ packages: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jest-changed-files@30.3.0: + resolution: {integrity: sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-circus@30.3.0: + resolution: {integrity: sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-cli@30.3.0: + resolution: {integrity: sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@30.3.0: + resolution: {integrity: sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@types/node': '*' + esbuild-register: '>=3.4.0' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + esbuild-register: + optional: true + ts-node: + optional: true + + jest-diff@30.3.0: + resolution: {integrity: sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-docblock@30.2.0: + resolution: {integrity: sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-each@30.3.0: + resolution: {integrity: sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-environment-node@30.3.0: + resolution: {integrity: sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-haste-map@30.3.0: + resolution: {integrity: sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-junit@16.0.0: + resolution: {integrity: sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==} + engines: {node: '>=10.12.0'} + + jest-leak-detector@30.3.0: + resolution: {integrity: sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-matcher-utils@30.3.0: + resolution: {integrity: sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-message-util@30.3.0: + resolution: {integrity: sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-mock@30.3.0: + resolution: {integrity: sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-process-manager@0.4.0: + resolution: {integrity: sha512-80Y6snDyb0p8GG83pDxGI/kQzwVTkCxc7ep5FPe/F6JYdvRDhwr6RzRmPSP7SEwuLhxo80lBS/NqOdUIbHIfhw==} + deprecated: ⚠️ The 'jest-process-manager' package is deprecated. Please migrate to Playwright's built-in test runner (@playwright/test) which now includes full Jest-style features and parallel testing. See https://playwright.dev/docs/intro for details. + + jest-regex-util@30.0.1: + resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve-dependencies@30.3.0: + resolution: {integrity: sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve@30.3.0: + resolution: {integrity: sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runner@30.3.0: + resolution: {integrity: sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runtime@30.3.0: + resolution: {integrity: sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-serializer-html@7.1.0: + resolution: {integrity: sha512-xYL2qC7kmoYHJo8MYqJkzrl/Fdlx+fat4U1AqYg+kafqwcKPiMkOcjWHPKhueuNEgr+uemhGc+jqXYiwCyRyLA==} + + jest-snapshot@30.3.0: + resolution: {integrity: sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-util@30.3.0: + resolution: {integrity: sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-validate@30.3.0: + resolution: {integrity: sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-watch-typeahead@3.0.1: + resolution: {integrity: sha512-SFmHcvdueTswZlVhPCWfLXMazvwZlA2UZTrcE7MC3NwEVeWvEcOx6HUe+igMbnmA6qowuBSW4in8iC6J2EYsgQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + jest: ^30.0.0 + + jest-watcher@30.3.0: + resolution: {integrity: sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-worker@30.3.0: + resolution: {integrity: sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest@30.3.0: + resolution: {integrity: sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + jiti@1.21.7: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + joi@17.13.3: + resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + jose@6.1.3: resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} @@ -4043,6 +5228,10 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true @@ -4067,6 +5256,9 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-rpc-2.0@1.7.1: + resolution: {integrity: sha512-JqZjhjAanbpkXIzFE7u8mE/iFblawwlXtONaCvRqI+pyABVz7B4M1EUNpyVW+dZjqgQ2L5HFmZCmOCgUKm00hg==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -4084,6 +5276,9 @@ packages: engines: {node: '>=6'} hasBin: true + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} @@ -4109,6 +5304,10 @@ packages: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -4124,10 +5323,17 @@ packages: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.flattendeep@4.4.0: + resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -4138,6 +5344,10 @@ packages: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -4145,12 +5355,19 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lowlight@1.20.0: resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.2.6: + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -4169,10 +5386,17 @@ packages: magicast@0.5.2: resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} + make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + markdown-extensions@2.0.0: resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} engines: {node: '>=16'} @@ -4311,10 +5535,18 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + mime-db@1.54.0: resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} engines: {node: '>= 0.6'} + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mime-types@3.0.2: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} @@ -4341,6 +5573,15 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + mlly@1.8.1: resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} @@ -4369,6 +5610,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -4423,6 +5669,13 @@ packages: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-preload@0.2.1: + resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} + engines: {node: '>=8'} + node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} @@ -4441,6 +5694,11 @@ packages: nwsapi@2.2.23: resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} + nyc@15.1.0: + resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==} + engines: {node: '>=8.9'} + hasBin: true + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -4495,6 +5753,10 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -4503,6 +5765,10 @@ packages: resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} engines: {node: '>=18'} + os-homedir@1.0.2: + resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} + engines: {node: '>=0.10.0'} + outvariant@1.4.3: resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} @@ -4510,14 +5776,37 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-map@3.0.0: + resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-hash@4.0.0: + resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} + engines: {node: '>=8'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} @@ -4536,6 +5825,10 @@ packages: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} + parse-passwd@1.0.0: + resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} + engines: {node: '>=0.10.0'} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -4553,6 +5846,10 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -4564,6 +5861,14 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} @@ -4573,6 +5878,10 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4584,6 +5893,9 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + picoquery@2.5.0: + resolution: {integrity: sha512-j1kgOFxtaCyoFCkpoYG2Oj3OdGakadO7HZ7o5CqyRazlmBekKhbDoUnNnXASE07xSY4nDImWZkrZv7toSxMi/g==} + pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -4596,6 +5908,10 @@ packages: resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -4689,6 +6005,10 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + pretty-format@30.3.0: + resolution: {integrity: sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + pretty-ms@9.3.0: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} @@ -4697,6 +6017,10 @@ packages: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} + process-on-spawn@1.1.0: + resolution: {integrity: sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==} + engines: {node: '>=8'} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -4711,10 +6035,16 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@7.0.1: + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} + qs@6.15.0: resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} engines: {node: '>=0.6'} @@ -4736,6 +6066,15 @@ packages: peerDependencies: react: '>=16.8.0' + react-docgen-typescript@2.4.0: + resolution: {integrity: sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==} + peerDependencies: + typescript: '>= 4.3.x' + + react-docgen@8.0.2: + resolution: {integrity: sha512-+NRMYs2DyTP4/tqWz371Oo50JqmWltR1h2gcdgUMAWZJIAvrd0/SqlCfx7tpzpl/s36rzw6qH2MjoNrxtRNYhA==} + engines: {node: ^20.9.0 || >=22} + react-dom@19.2.4: resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: @@ -4747,6 +6086,9 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-markdown@10.1.0: resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} peerDependencies: @@ -4806,6 +6148,10 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -4858,6 +6204,10 @@ packages: rehype-recma@1.0.0: resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} + release-zalgo@1.0.0: + resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==} + engines: {node: '>=4'} + remark-mdx@3.1.1: resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} @@ -4875,10 +6225,21 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + requireindex@1.1.0: resolution: {integrity: sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==} engines: {node: '>=0.10.5'} + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-dir@0.1.1: + resolution: {integrity: sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -4910,6 +6271,11 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + rollup@4.59.0: resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -4922,13 +6288,23 @@ packages: rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -4964,6 +6340,9 @@ packages: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -5024,6 +6403,14 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + sonner@1.7.4: resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} peerDependencies: @@ -5034,6 +6421,9 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -5045,6 +6435,23 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + spawn-wrap@2.0.0: + resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==} + engines: {node: '>=8'} + + spawnd@5.0.0: + resolution: {integrity: sha512-28+AJr82moMVWolQvlAIv3JcYDkjkFTEmfDc503wxrF5l2rQ3dFz6DpbXp3kD4zmgGGldfM4xM4v1sFj/ZaIOA==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + sqids@0.3.0: + resolution: {integrity: sha512-lOQK1ucVg+W6n3FhRwwSeUijxe93b51Bfz5PMRMihVf1iVkl82ePQG7V5vwrhzB11v0NtsR25PSZRGiSomJaJw==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -5063,13 +6470,34 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} + storybook@10.2.17: + resolution: {integrity: sha512-yueTpl5YJqLzQqs3CanxNdAAfFU23iP0j+JVJURE4ghfEtRmWfWoZWLGkVcyjmgum7UmjwAlqRuOjQDNvH89kw==} + hasBin: true + peerDependencies: + prettier: ^2 || ^3 + peerDependenciesMeta: + prettier: + optional: true + strict-event-emitter@0.5.1: resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-length@6.0.0: + resolution: {integrity: sha512-1U361pxZHEQ+FeSjzqRpV+cu2vTzYeWeafXFLykiFlv4Vc0n3njgU8HrMbyik5uwm77naWMuVG8fhEF+Ovb1Kg==} + engines: {node: '>=16'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} @@ -5097,6 +6525,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-entities@4.0.4: resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} @@ -5116,6 +6547,10 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} @@ -5160,10 +6595,18 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -5195,6 +6638,10 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -5219,10 +6666,18 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + tinyrainbow@3.0.3: resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + tldts-core@6.1.86: resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} @@ -5237,6 +6692,12 @@ packages: resolution: {integrity: sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==} hasBin: true + tmcp@1.19.3: + resolution: {integrity: sha512-plz/TLKNFrdfQN32LjCTN6ULy6pynfGPgHcU7KGCI5dBrxQ9Mub99SmcYuzxEkLjJooQuOD3gosSwZEl1htOtw==} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -5282,6 +6743,10 @@ packages: peerDependencies: typescript: '>=4.0.0' + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -5357,6 +6822,18 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + type-fest@5.4.4: resolution: {integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==} engines: {node: '>=20'} @@ -5381,6 +6858,9 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + typescript-eslint@8.56.1: resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5441,6 +6921,13 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + until-async@3.0.2: resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} @@ -5453,6 +6940,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uri-template-matcher@1.1.2: + resolution: {integrity: sha512-uZc1h12jdO3m/R77SfTEOuo6VbMhgWznaawKpBjRGSJb7i91x5PgI37NQJtG+Cerxkk0yr1pylBY2qG1kQ+aEQ==} + use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} @@ -5481,6 +6971,22 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + valibot@1.2.0: + resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -5615,6 +7121,19 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + wait-on@7.2.0: + resolution: {integrity: sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==} + engines: {node: '>=12.0.0'} + hasBin: true + + wait-port@0.2.14: + resolution: {integrity: sha512-kIzjWcr6ykl7WFbZd0TMae8xovwqcqbx6FM9l+7agOgUByhzdjfzZBPK2CPufldTOMxbUivss//Sh9MFawmPRQ==} + engines: {node: '>=8'} + hasBin: true + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + weasel-words@0.1.1: resolution: {integrity: sha512-rWkTAGqs4TN6qreS06+irmFUMrQVx5KoFjD8CxMHUsAwmxw/upDcfleaEYOLsonUbornahg+VJ9xrWxp4udyJA==} @@ -5626,6 +7145,9 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} @@ -5651,10 +7173,17 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + which-typed-array@1.1.20: resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} engines: {node: '>= 0.4'} + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -5685,9 +7214,20 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + write-file-atomic@3.0.3: + resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + write-good@1.0.8: resolution: {integrity: sha512-P1Ct7+DNrOcr2JAxDZ3Q5i5sx2LSveu7iLaoUL0A+YiG0GKf0l5+9j3rwMeyh6JeTL1+HfQV1rnwEvzhNIvpFw==} engines: {node: '>=6', npm: '>=5'} @@ -5705,13 +7245,23 @@ packages: utf-8-validate: optional: true + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} + xml@1.0.1: + resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} + xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5719,10 +7269,18 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -5915,53 +7473,128 @@ snapshots: dependencies: '@babel/types': 7.29.0 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) '@babel/helper-plugin-utils': 7.28.6 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color @@ -5990,6 +7623,8 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@bcoe/v8-coverage@0.2.3': {} + '@bcoe/v8-coverage@1.0.2': {} '@boundaries/elements@1.2.0(@typescript-eslint/parser@8.56.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))': @@ -6053,11 +7688,22 @@ snapshots: dependencies: '@noble/ciphers': 1.3.0 + '@emnapi/core@1.8.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.25.12': optional: true @@ -6338,6 +7984,16 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@figspec/components@2.1.0': {} + + '@figspec/react@2.0.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@figspec/components': 2.1.0 + '@lit-labs/react': 2.1.3(@types/react@19.2.13) + react: 19.2.4 + transitivePeerDependencies: + - '@types/react' + '@floating-ui/core@1.7.4': dependencies: '@floating-ui/utils': 0.2.10 @@ -6355,6 +8011,12 @@ snapshots: '@floating-ui/utils@0.2.10': {} + '@hapi/hoek@9.3.0': {} + + '@hapi/topo@5.1.0': + dependencies: + '@hapi/hoek': 9.3.0 + '@hono/node-server@1.19.11(hono@4.12.5)': dependencies: hono: 4.12.5 @@ -6495,6 +8157,214 @@ snapshots: optionalDependencies: '@types/node': 22.19.10 + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.2 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@30.3.0': + dependencies: + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + chalk: 4.1.2 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + slash: 3.0.0 + + '@jest/core@30.3.0': + dependencies: + '@jest/console': 30.3.0 + '@jest/pattern': 30.0.1 + '@jest/reporters': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 4.4.0 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-changed-files: 30.3.0 + jest-config: 30.3.0(@types/node@22.19.10) + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-resolve-dependencies: 30.3.0 + jest-runner: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + jest-watcher: 30.3.0 + pretty-format: 30.3.0 + slash: 3.0.0 + transitivePeerDependencies: + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + '@jest/create-cache-key-function@30.3.0': + dependencies: + '@jest/types': 30.3.0 + + '@jest/diff-sequences@30.3.0': {} + + '@jest/environment@30.3.0': + dependencies: + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + jest-mock: 30.3.0 + + '@jest/expect-utils@30.3.0': + dependencies: + '@jest/get-type': 30.1.0 + + '@jest/expect@30.3.0': + dependencies: + expect: 30.3.0 + jest-snapshot: 30.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@30.3.0': + dependencies: + '@jest/types': 30.3.0 + '@sinonjs/fake-timers': 15.1.1 + '@types/node': 22.19.10 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + + '@jest/get-type@30.1.0': {} + + '@jest/globals@30.3.0': + dependencies: + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/types': 30.3.0 + jest-mock: 30.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/pattern@30.0.1': + dependencies: + '@types/node': 22.19.10 + jest-regex-util: 30.0.1 + + '@jest/reporters@30.3.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@jridgewell/trace-mapping': 0.3.31 + '@types/node': 22.19.10 + chalk: 4.1.2 + collect-v8-coverage: 1.0.3 + exit-x: 0.2.2 + glob: 10.5.0 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + jest-worker: 30.3.0 + slash: 3.0.0 + string-length: 4.0.2 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@30.0.5': + dependencies: + '@sinclair/typebox': 0.34.48 + + '@jest/snapshot-utils@30.3.0': + dependencies: + '@jest/types': 30.3.0 + chalk: 4.1.2 + graceful-fs: 4.2.11 + natural-compare: 1.4.0 + + '@jest/source-map@30.0.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@30.3.0': + dependencies: + '@jest/console': 30.3.0 + '@jest/types': 30.3.0 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.3 + + '@jest/test-sequencer@30.3.0': + dependencies: + '@jest/test-result': 30.3.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + slash: 3.0.0 + + '@jest/transform@30.3.0': + dependencies: + '@babel/core': 7.29.0 + '@jest/types': 30.3.0 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 7.0.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + jest-regex-util: 30.0.1 + jest-util: 30.3.0 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + + '@jest/types@30.3.0': + dependencies: + '@jest/pattern': 30.0.1 + '@jest/schemas': 30.0.5 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.19.10 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0))': + dependencies: + glob: 13.0.6 + react-docgen-typescript: 2.4.0(typescript@5.9.3) + vite: 7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0) + optionalDependencies: + typescript: 5.9.3 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -6514,6 +8384,16 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@lit-labs/react@2.1.3(@types/react@19.2.13)': + dependencies: + '@lit/react': 1.0.8(@types/react@19.2.13) + transitivePeerDependencies: + - '@types/react' + + '@lit/react@1.0.8(@types/react@19.2.13)': + dependencies: + '@types/react': 19.2.13 + '@mdx-js/mdx@3.1.1': dependencies: '@types/estree': 1.0.8 @@ -6575,6 +8455,13 @@ snapshots: outvariant: 1.4.3 strict-event-emitter: 0.5.1 + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 + '@tybys/wasm-util': 0.10.1 + optional: true + '@next/env@16.1.6': {} '@next/eslint-plugin-next@16.1.6': @@ -6638,6 +8525,9 @@ snapshots: '@open-draft/until@2.1.0': {} + '@pkgjs/parseargs@0.11.0': + optional: true + '@pkgr/core@0.2.9': {} '@playwright/experimental-ct-core@1.58.2(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0)': @@ -7311,6 +9201,14 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.27': {} + '@rollup/pluginutils@5.3.0(rollup@4.59.0)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.59.0 + '@rollup/rollup-android-arm-eabi@4.59.0': optional: true @@ -7388,63 +9286,312 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + + '@sideway/formula@3.0.1': {} + + '@sideway/pinpoint@2.0.0': {} + + '@sinclair/typebox@0.34.48': {} + '@sindresorhus/merge-streams@4.0.0': {} - '@standard-schema/spec@1.1.0': {} + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 - '@swc/helpers@0.5.15': + '@sinonjs/fake-timers@15.1.1': dependencies: - tslib: 2.8.1 + '@sinonjs/commons': 3.0.1 - '@tailwindcss/typography@0.5.19(tailwindcss@3.4.19(tsx@4.21.0))': + '@standard-schema/spec@1.1.0': {} + + '@storybook/addon-a11y@10.2.17(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: - postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.19(tsx@4.21.0) + '@storybook/global': 5.0.0 + axe-core: 4.11.1 + storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-table@8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@storybook/addon-designs@11.1.2(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: - '@tanstack/table-core': 8.21.3 + '@figspec/react': 2.0.1(@types/react@19.2.13)(react@19.2.4) + storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + optionalDependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - '@types/react' - '@tanstack/table-core@8.21.3': {} + '@storybook/addon-mcp@0.3.4(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': + dependencies: + '@storybook/mcp': 0.5.1(typescript@5.9.3) + '@tmcp/adapter-valibot': 0.1.5(tmcp@1.19.3(typescript@5.9.3))(valibot@1.2.0(typescript@5.9.3)) + '@tmcp/transport-http': 0.8.5(tmcp@1.19.3(typescript@5.9.3)) + picoquery: 2.5.0 + storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + tmcp: 1.19.3(typescript@5.9.3) + valibot: 1.2.0(typescript@5.9.3) + transitivePeerDependencies: + - '@tmcp/auth' + - typescript - '@testing-library/dom@10.4.1': + '@storybook/addon-themes@10.2.17(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.28.6 - '@types/aria-query': 5.0.4 - aria-query: 5.3.0 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - picocolors: 1.1.1 - pretty-format: 27.5.1 + storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + ts-dedent: 2.2.0 - '@testing-library/jest-dom@6.9.1': + '@storybook/builder-vite@10.2.17(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0))': dependencies: - '@adobe/css-tools': 4.4.4 - aria-query: 5.3.2 - css.escape: 1.5.1 - dom-accessibility-api: 0.6.3 - picocolors: 1.1.1 - redent: 3.0.0 + '@storybook/csf-plugin': 10.2.17(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0)) + storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + ts-dedent: 2.2.0 + vite: 7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0) + transitivePeerDependencies: + - esbuild + - rollup + - webpack - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@storybook/csf-plugin@10.2.17(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0))': dependencies: - '@babel/runtime': 7.28.6 - '@testing-library/dom': 10.4.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + unplugin: 2.3.11 optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) - + esbuild: 0.27.3 + rollup: 4.59.0 + vite: 7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0) + + '@storybook/global@5.0.0': {} + + '@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/mcp@0.5.1(typescript@5.9.3)': + dependencies: + '@tmcp/adapter-valibot': 0.1.5(tmcp@1.19.3(typescript@5.9.3))(valibot@1.2.0(typescript@5.9.3)) + '@tmcp/transport-http': 0.8.5(tmcp@1.19.3(typescript@5.9.3)) + tmcp: 1.19.3(typescript@5.9.3) + valibot: 1.2.0(typescript@5.9.3) + transitivePeerDependencies: + - '@tmcp/auth' + - typescript + + '@storybook/react-dom-shim@10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.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: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + '@storybook/react-vite@10.2.17(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0))': + dependencies: + '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0)) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@storybook/builder-vite': 10.2.17(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0)) + '@storybook/react': 10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + empathic: 2.0.0 + magic-string: 0.30.21 + react: 19.2.4 + react-docgen: 8.0.2 + react-dom: 19.2.4(react@19.2.4) + resolve: 1.22.11 + storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + tsconfig-paths: 4.2.0 + vite: 7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0) + transitivePeerDependencies: + - esbuild + - rollup + - supports-color + - typescript + - webpack + + '@storybook/react@10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': + dependencies: + '@storybook/global': 5.0.0 + '@storybook/react-dom-shim': 10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + react: 19.2.4 + react-docgen: 8.0.2 + react-dom: 19.2.4(react@19.2.4) + storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@storybook/test-runner@0.24.2(@types/node@22.19.10)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + '@jest/types': 30.3.0 + '@swc/core': 1.15.18 + '@swc/jest': 0.2.39(@swc/core@1.15.18) + expect-playwright: 0.8.0 + jest: 30.3.0(@types/node@22.19.10) + jest-circus: 30.3.0 + jest-environment-node: 30.3.0 + jest-junit: 16.0.0 + jest-process-manager: 0.4.0 + jest-runner: 30.3.0 + jest-serializer-html: 7.1.0 + jest-watch-typeahead: 3.0.1(jest@30.3.0(@types/node@22.19.10)) + nyc: 15.1.0 + playwright: 1.58.2 + playwright-core: 1.58.2 + rimraf: 3.0.2 + storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + uuid: 8.3.2 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/node' + - babel-plugin-macros + - debug + - esbuild-register + - node-notifier + - supports-color + - ts-node + + '@swc/core-darwin-arm64@1.15.18': + optional: true + + '@swc/core-darwin-x64@1.15.18': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.15.18': + optional: true + + '@swc/core-linux-arm64-gnu@1.15.18': + optional: true + + '@swc/core-linux-arm64-musl@1.15.18': + optional: true + + '@swc/core-linux-x64-gnu@1.15.18': + optional: true + + '@swc/core-linux-x64-musl@1.15.18': + optional: true + + '@swc/core-win32-arm64-msvc@1.15.18': + optional: true + + '@swc/core-win32-ia32-msvc@1.15.18': + optional: true + + '@swc/core-win32-x64-msvc@1.15.18': + optional: true + + '@swc/core@1.15.18': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.25 + optionalDependencies: + '@swc/core-darwin-arm64': 1.15.18 + '@swc/core-darwin-x64': 1.15.18 + '@swc/core-linux-arm-gnueabihf': 1.15.18 + '@swc/core-linux-arm64-gnu': 1.15.18 + '@swc/core-linux-arm64-musl': 1.15.18 + '@swc/core-linux-x64-gnu': 1.15.18 + '@swc/core-linux-x64-musl': 1.15.18 + '@swc/core-win32-arm64-msvc': 1.15.18 + '@swc/core-win32-ia32-msvc': 1.15.18 + '@swc/core-win32-x64-msvc': 1.15.18 + + '@swc/counter@0.1.3': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@swc/jest@0.2.39(@swc/core@1.15.18)': + dependencies: + '@jest/create-cache-key-function': 30.3.0 + '@swc/core': 1.15.18 + '@swc/counter': 0.1.3 + jsonc-parser: 3.3.1 + + '@swc/types@0.1.25': + dependencies: + '@swc/counter': 0.1.3 + + '@tailwindcss/typography@0.5.19(tailwindcss@3.4.19(tsx@4.21.0))': + dependencies: + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.19(tsx@4.21.0) + + '@tanstack/react-table@8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/table-core': 8.21.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@tanstack/table-core@8.21.3': {} + + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.28.6 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.9.1': + dependencies: + '@adobe/css-tools': 4.4.4 + aria-query: 5.3.2 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + picocolors: 1.1.1 + redent: 3.0.0 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@testing-library/dom': 10.4.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': + dependencies: + '@testing-library/dom': 10.4.1 + + '@tmcp/adapter-valibot@0.1.5(tmcp@1.19.3(typescript@5.9.3))(valibot@1.2.0(typescript@5.9.3))': + dependencies: + '@standard-schema/spec': 1.1.0 + '@valibot/to-json-schema': 1.5.0(valibot@1.2.0(typescript@5.9.3)) + tmcp: 1.19.3(typescript@5.9.3) + valibot: 1.2.0(typescript@5.9.3) + + '@tmcp/session-manager@0.2.1(tmcp@1.19.3(typescript@5.9.3))': + dependencies: + tmcp: 1.19.3(typescript@5.9.3) + + '@tmcp/transport-http@0.8.5(tmcp@1.19.3(typescript@5.9.3))': + dependencies: + '@tmcp/session-manager': 0.2.1(tmcp@1.19.3(typescript@5.9.3)) + esm-env: 1.2.2 + tmcp: 1.19.3(typescript@5.9.3) + '@ts-morph/common@0.27.0': dependencies: fast-glob: 3.3.3 minimatch: 10.2.4 path-browserify: 1.0.1 + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@types/aria-query@5.0.4': {} '@types/babel__core@7.20.5': @@ -7500,6 +9647,8 @@ snapshots: '@types/deep-eql@4.0.2': {} + '@types/doctrine@0.0.9': {} + '@types/estree-jsx@1.0.5': dependencies: '@types/estree': 1.0.8 @@ -7510,6 +9659,16 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + '@types/json-schema@7.0.15': {} '@types/mdast@4.0.4': @@ -7538,12 +9697,26 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/resolve@1.20.6': {} + + '@types/stack-utils@2.0.3': {} + '@types/statuses@2.0.6': {} '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} + '@types/wait-on@5.3.4': + dependencies: + '@types/node': 22.19.10 + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -7751,6 +9924,69 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + '@valibot/to-json-schema@1.5.0(valibot@1.2.0(typescript@5.9.3))': + dependencies: + valibot: 1.2.0(typescript@5.9.3) + '@vercel/analytics@1.6.1(next@16.1.6(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': optionalDependencies: next: 16.1.6(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -7787,6 +10023,14 @@ snapshots: tinyrainbow: 3.0.3 vitest: 4.0.18(@types/node@22.19.10)(jiti@1.21.7)(jsdom@26.1.0)(msw@2.12.9(@types/node@22.19.10)(typescript@5.9.3))(tsx@4.21.0) + '@vitest/expect@3.2.4': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + tinyrainbow: 2.0.0 + '@vitest/expect@4.0.18': dependencies: '@standard-schema/spec': 1.1.0 @@ -7805,6 +10049,10 @@ snapshots: msw: 2.12.9(@types/node@22.19.10)(typescript@5.9.3) vite: 7.3.1(@types/node@22.19.10)(jiti@1.21.7)(tsx@4.21.0) + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + '@vitest/pretty-format@4.0.18': dependencies: tinyrainbow: 3.0.3 @@ -7820,8 +10068,18 @@ snapshots: magic-string: 0.30.21 pathe: 2.0.3 + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.4 + '@vitest/spy@4.0.18': {} + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + '@vitest/utils@4.0.18': dependencies: '@vitest/pretty-format': 4.0.18 @@ -7901,6 +10159,11 @@ snapshots: agent-base@7.1.4: {} + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + ajv-formats@3.0.1(ajv@8.18.0): optionalDependencies: ajv: 8.18.0 @@ -7919,16 +10182,30 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} + ansis@4.2.0: {} any-promise@1.3.0: {} @@ -7938,8 +10215,18 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + append-transform@2.0.0: + dependencies: + default-require-extensions: 3.0.1 + + archy@1.0.0: {} + arg@5.0.2: {} + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + argparse@2.0.1: {} aria-hidden@1.2.6: @@ -8027,6 +10314,8 @@ snapshots: async-function@1.0.0: {} + asynckit@0.4.0: {} + autoprefixer@10.4.24(postcss@8.5.6): dependencies: browserslist: 4.28.1 @@ -8042,8 +10331,68 @@ snapshots: axe-core@4.11.1: {} + axios@1.13.6: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axobject-query@4.1.0: {} + babel-jest@30.3.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@jest/transform': 30.3.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 7.0.1 + babel-preset-jest: 30.3.0(@babel/core@7.29.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@7.0.1: + dependencies: + '@babel/helper-plugin-utils': 7.28.6 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 6.0.3 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@30.3.0: + dependencies: + '@types/babel__core': 7.20.5 + + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) + + babel-preset-jest@30.3.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + babel-plugin-jest-hoist: 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -8089,8 +10438,18 @@ snapshots: node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + builtin-modules@5.0.0: {} + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + bundle-require@5.1.0(esbuild@0.27.3): dependencies: esbuild: 0.27.3 @@ -8100,6 +10459,13 @@ snapshots: cac@6.7.14: {} + caching-transform@4.0.0: + dependencies: + hasha: 5.2.2 + make-dir: 3.1.0 + package-hash: 4.0.0 + write-file-atomic: 3.0.3 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -8121,12 +10487,30 @@ snapshots: camelcase-css@2.0.1: {} + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + caniuse-lite@1.0.30001769: {} ccount@2.0.1: {} + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + chai@6.2.2: {} + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -8136,6 +10520,8 @@ snapshots: change-case@5.4.4: {} + char-regex@1.0.2: {} + character-entities-html4@2.1.0: {} character-entities-legacy@3.0.0: {} @@ -8144,6 +10530,8 @@ snapshots: character-reference-invalid@2.0.1: {} + check-error@2.1.3: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -8162,6 +10550,8 @@ snapshots: ci-info@4.4.0: {} + cjs-module-lexer@2.2.0: {} + class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 @@ -8172,6 +10562,8 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 + clean-stack@2.2.0: {} + cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -8182,6 +10574,12 @@ snapshots: client-only@0.0.1: {} + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -8202,26 +10600,46 @@ snapshots: - '@types/react' - '@types/react-dom' + co@4.6.0: {} + code-block-writer@13.0.3: {} collapse-white-space@2.1.0: {} + collect-v8-coverage@1.0.3: {} + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} commander@11.1.0: {} + commander@12.1.0: {} + commander@14.0.3: {} commander@2.20.3: {} + commander@3.0.2: {} + commander@4.1.1: {} + commondir@1.0.1: {} + concat-map@0.0.1: {} confbox@0.1.8: {} @@ -8232,6 +10650,8 @@ snapshots: content-type@1.0.5: {} + convert-source-map@1.9.0: {} + convert-source-map@2.0.0: {} convex@1.31.7(react@19.2.4): @@ -8282,6 +10702,11 @@ snapshots: csstype@3.2.3: {} + cwd@0.10.0: + dependencies: + find-pkg: 0.1.2 + fs-exists-sync: 0.1.0 + d3-color@3.1.0: {} d3-dispatch@3.0.1: {} @@ -8357,6 +10782,8 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decimal.js@10.6.0: {} decode-named-character-reference@1.3.0: @@ -8365,24 +10792,41 @@ snapshots: dedent@1.7.1: {} + deep-eql@5.0.2: {} + deep-is@0.1.4: {} deepmerge-ts@7.1.5: {} deepmerge@4.3.1: {} + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + + default-require-extensions@3.0.1: + dependencies: + strip-bom: 4.0.0 + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 + delayed-stream@1.0.0: {} + depd@2.0.0: {} dequal@2.0.3: {} @@ -8390,6 +10834,8 @@ snapshots: detect-libc@2.1.2: optional: true + detect-newline@3.1.0: {} + detect-node-es@1.1.0: {} devlop@1.1.0: @@ -8400,16 +10846,42 @@ snapshots: diff@8.0.3: {} + diffable-html@4.1.0: + dependencies: + htmlparser2: 3.10.1 + dlv@1.1.3: {} doctrine@2.1.0: dependencies: esutils: 2.0.3 + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + dom-accessibility-api@0.5.16: {} dom-accessibility-api@0.6.3: {} + dom-serializer@0.2.2: + dependencies: + domelementtype: 2.3.0 + entities: 2.2.0 + + domelementtype@1.3.1: {} + + domelementtype@2.3.0: {} + + domhandler@2.4.2: + dependencies: + domelementtype: 1.3.1 + + domutils@1.7.0: + dependencies: + dom-serializer: 0.2.2 + domelementtype: 1.3.1 + dotenv@16.0.3: {} dotenv@17.2.4: {} @@ -8422,6 +10894,8 @@ snapshots: e-prime@0.10.4: {} + eastasianwidth@0.2.0: {} + eciesjs@0.4.17: dependencies: '@ecies/ciphers': 0.2.5(@noble/ciphers@1.3.0) @@ -8445,18 +10919,28 @@ snapshots: embla-carousel@8.6.0: {} + emittery@0.13.1: {} + emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} + empathic@2.0.0: {} + encodeurl@2.0.0: {} + entities@1.1.2: {} + + entities@2.2.0: {} + entities@6.0.1: {} env-paths@2.2.1: {} + environment@1.1.0: {} + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 @@ -8564,6 +11048,8 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + es6-error@4.1.1: {} + esast-util-from-estree@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 @@ -8671,6 +11157,8 @@ snapshots: escape-string-regexp@1.0.5: {} + escape-string-regexp@2.0.0: {} + escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} @@ -8890,6 +11378,8 @@ snapshots: transitivePeerDependencies: - supports-color + esm-env@1.2.2: {} + espree@10.4.0: dependencies: acorn: 8.15.0 @@ -8937,6 +11427,8 @@ snapshots: '@types/estree-jsx': 1.0.5 '@types/unist': 3.0.3 + estree-walker@2.0.2: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.8 @@ -8978,8 +11470,27 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 + exit-x@0.2.2: {} + + exit@0.1.2: {} + + expand-tilde@1.2.2: + dependencies: + os-homedir: 1.0.2 + + expect-playwright@0.8.0: {} + expect-type@1.3.0: {} + expect@30.3.0: + dependencies: + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + express-rate-limit@8.2.1(express@5.2.1): dependencies: express: 5.2.1 @@ -9054,6 +11565,10 @@ snapshots: dependencies: format: 0.2.2 + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -9086,8 +11601,34 @@ snapshots: transitivePeerDependencies: - supports-color + find-cache-dir@3.3.2: + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + + find-file-up@0.1.3: + dependencies: + fs-exists-sync: 0.1.0 + resolve-dir: 0.1.1 + + find-pkg@0.1.2: + dependencies: + find-file-up: 0.1.3 + + find-process@1.4.11: + dependencies: + chalk: 4.1.2 + commander: 12.1.0 + loglevel: 1.9.2 + find-up-simple@1.0.1: {} + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -9106,10 +11647,30 @@ snapshots: flatted@3.3.3: {} + follow-redirects@1.15.11: {} + for-each@0.3.5: dependencies: is-callable: 1.2.7 + foreground-child@2.0.0: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 3.0.7 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + format@0.2.2: {} formdata-polyfill@4.0.10: @@ -9122,12 +11683,18 @@ snapshots: fresh@2.0.0: {} + fromentries@1.3.2: {} + + fs-exists-sync@0.1.0: {} + fs-extra@11.3.3: dependencies: graceful-fs: 4.2.11 jsonfile: 6.2.0 universalify: 2.0.1 + fs.realpath@1.0.0: {} + fsevents@2.3.2: optional: true @@ -9176,6 +11743,8 @@ snapshots: get-own-enumerable-keys@1.0.0: {} + get-package-type@0.1.0: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -9206,6 +11775,42 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 10.2.4 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@13.0.6: + dependencies: + minimatch: 10.2.4 + minipass: 7.1.3 + path-scurry: 2.0.2 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 10.2.4 + once: 1.4.0 + path-is-absolute: 1.0.1 + + global-modules@0.2.3: + dependencies: + global-prefix: 0.1.5 + is-windows: 0.2.0 + + global-prefix@0.1.5: + dependencies: + homedir-polyfill: 1.0.3 + ini: 1.3.8 + is-windows: 0.2.0 + which: 1.3.1 + globals@14.0.0: {} globals@16.5.0: {} @@ -9236,6 +11841,8 @@ snapshots: has-bigints@1.1.0: {} + has-flag@3.0.0: {} + has-flag@4.0.0: {} has-property-descriptors@1.0.2: @@ -9252,6 +11859,11 @@ snapshots: dependencies: has-symbols: 1.1.0 + hasha@5.2.2: + dependencies: + is-stream: 2.0.1 + type-fest: 0.8.1 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -9325,6 +11937,10 @@ snapshots: highlightjs-vue@1.0.0: {} + homedir-polyfill@1.0.3: + dependencies: + parse-passwd: 1.0.0 + hono@4.12.5: {} html-encoding-sniffer@4.0.0: @@ -9337,6 +11953,15 @@ snapshots: html-url-attributes@3.0.1: {} + htmlparser2@3.10.1: + dependencies: + domelementtype: 1.3.1 + domhandler: 2.4.2 + domutils: 1.7.0 + entities: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -9380,14 +12005,26 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + imurmurhash@0.1.4: {} indent-string@4.0.0: {} indent-string@5.0.0: {} + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + inherits@2.0.4: {} + ini@1.3.8: {} + inline-style-parser@0.2.7: {} input-otp@1.4.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4): @@ -9464,6 +12101,8 @@ snapshots: is-decimal@2.0.1: {} + is-docker@3.0.0: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -9472,6 +12111,8 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-generator-fn@2.1.0: {} + is-generator-function@1.1.2: dependencies: call-bound: 1.0.4 @@ -9496,6 +12137,10 @@ snapshots: transitivePeerDependencies: - supports-color + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-interactive@2.0.0: {} is-map@2.0.3: {} @@ -9553,6 +12198,8 @@ snapshots: dependencies: which-typed-array: 1.1.20 + is-typedarray@1.0.0: {} + is-unicode-supported@1.3.0: {} is-unicode-supported@2.1.0: {} @@ -9568,36 +12215,454 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-windows@0.2.0: {} + + is-windows@1.0.2: {} + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + isarray@2.0.5: {} isexe@2.0.0: {} - isexe@3.1.5: {} + isexe@3.1.5: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-hook@3.0.0: + dependencies: + append-transform: 2.0.0 + + istanbul-lib-instrument@4.0.3: + dependencies: + '@babel/core': 7.29.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.7.4 + transitivePeerDependencies: + - supports-color + + istanbul-lib-processinfo@2.0.3: + dependencies: + archy: 1.0.0 + cross-spawn: 7.0.6 + istanbul-lib-coverage: 3.2.2 + p-map: 3.0.0 + rimraf: 3.0.2 + uuid: 8.3.2 + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jest-changed-files@30.3.0: + dependencies: + execa: 5.1.1 + jest-util: 30.3.0 + p-limit: 3.1.0 + + jest-circus@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.7.1 + is-generator-fn: 2.1.0 + jest-each: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + p-limit: 3.1.0 + pretty-format: 30.3.0 + pure-rand: 7.0.1 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@30.3.0(@types/node@22.19.10): + dependencies: + '@jest/core': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 + chalk: 4.1.2 + exit-x: 0.2.2 + import-local: 3.2.0 + jest-config: 30.3.0(@types/node@22.19.10) + jest-util: 30.3.0 + jest-validate: 30.3.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + jest-config@30.3.0(@types/node@22.19.10): + dependencies: + '@babel/core': 7.29.0 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.3.0 + '@jest/types': 30.3.0 + babel-jest: 30.3.0(@babel/core@7.29.0) + chalk: 4.1.2 + ci-info: 4.4.0 + deepmerge: 4.3.1 + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-circus: 30.3.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-runner: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + parse-json: 5.2.0 + pretty-format: 30.3.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.19.10 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@30.3.0: + dependencies: + '@jest/diff-sequences': 30.3.0 + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + pretty-format: 30.3.0 + + jest-docblock@30.2.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 + chalk: 4.1.2 + jest-util: 30.3.0 + pretty-format: 30.3.0 + + jest-environment-node@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + jest-mock: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + + jest-haste-map@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 30.0.1 + jest-util: 30.3.0 + jest-worker: 30.3.0 + picomatch: 4.0.3 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-junit@16.0.0: + dependencies: + mkdirp: 1.0.4 + strip-ansi: 6.0.1 + uuid: 8.3.2 + xml: 1.0.1 + + jest-leak-detector@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + pretty-format: 30.3.0 + + jest-matcher-utils@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + jest-diff: 30.3.0 + pretty-format: 30.3.0 + + jest-message-util@30.3.0: + dependencies: + '@babel/code-frame': 7.29.0 + '@jest/types': 30.3.0 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + picomatch: 4.0.3 + pretty-format: 30.3.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + jest-util: 30.3.0 + + jest-pnp-resolver@1.2.3(jest-resolve@30.3.0): + optionalDependencies: + jest-resolve: 30.3.0 + + jest-process-manager@0.4.0: + dependencies: + '@types/wait-on': 5.3.4 + chalk: 4.1.2 + cwd: 0.10.0 + exit: 0.1.2 + find-process: 1.4.11 + prompts: 2.4.2 + signal-exit: 3.0.7 + spawnd: 5.0.0 + tree-kill: 1.2.2 + wait-on: 7.2.0 + transitivePeerDependencies: + - debug + - supports-color + + jest-regex-util@30.0.1: {} + + jest-resolve-dependencies@30.3.0: + dependencies: + jest-regex-util: 30.0.1 + jest-snapshot: 30.3.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@30.3.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + jest-pnp-resolver: 1.2.3(jest-resolve@30.3.0) + jest-util: 30.3.0 + jest-validate: 30.3.0 + slash: 3.0.0 + unrs-resolver: 1.11.1 + + jest-runner@30.3.0: + dependencies: + '@jest/console': 30.3.0 + '@jest/environment': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + chalk: 4.1.2 + emittery: 0.13.1 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-haste-map: 30.3.0 + jest-leak-detector: 30.3.0 + jest-message-util: 30.3.0 + jest-resolve: 30.3.0 + jest-runtime: 30.3.0 + jest-util: 30.3.0 + jest-watcher: 30.3.0 + jest-worker: 30.3.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/globals': 30.3.0 + '@jest/source-map': 30.0.1 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + chalk: 4.1.2 + cjs-module-lexer: 2.2.0 + collect-v8-coverage: 1.0.3 + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-serializer-html@7.1.0: + dependencies: + diffable-html: 4.1.0 + + jest-snapshot@30.3.0: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + '@jest/snapshot-utils': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) + chalk: 4.1.2 + expect: 30.3.0 + graceful-fs: 4.2.11 + jest-diff: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + pretty-format: 30.3.0 + semver: 7.7.4 + synckit: 0.11.12 + transitivePeerDependencies: + - supports-color + + jest-util@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + chalk: 4.1.2 + ci-info: 4.4.0 + graceful-fs: 4.2.11 + picomatch: 4.0.3 + + jest-validate@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 + camelcase: 6.3.0 + chalk: 4.1.2 + leven: 3.1.0 + pretty-format: 30.3.0 - istanbul-lib-coverage@3.2.2: {} + jest-watch-typeahead@3.0.1(jest@30.3.0(@types/node@22.19.10)): + dependencies: + ansi-escapes: 7.3.0 + chalk: 5.6.2 + jest: 30.3.0(@types/node@22.19.10) + jest-regex-util: 30.0.1 + jest-watcher: 30.3.0 + slash: 5.1.0 + string-length: 6.0.0 + strip-ansi: 7.1.2 - istanbul-lib-report@3.0.1: + jest-watcher@30.3.0: dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.19.10 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 30.3.0 + string-length: 4.0.2 - istanbul-reports@3.2.0: + jest-worker@30.3.0: dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 + '@types/node': 22.19.10 + '@ungap/structured-clone': 1.3.0 + jest-util: 30.3.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 - iterator.prototype@1.1.5: + jest@30.3.0(@types/node@22.19.10): dependencies: - define-data-property: 1.1.4 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - has-symbols: 1.1.0 - set-function-name: 2.0.2 + '@jest/core': 30.3.0 + '@jest/types': 30.3.0 + import-local: 3.2.0 + jest-cli: 30.3.0(@types/node@22.19.10) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node jiti@1.21.7: {} + joi@17.13.3: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + jose@6.1.3: {} joycon@3.1.1: {} @@ -9606,6 +12671,11 @@ snapshots: js-tokens@4.0.0: {} + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -9643,6 +12713,8 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-rpc-2.0@1.7.1: {} + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -9653,6 +12725,8 @@ snapshots: json5@2.2.3: {} + jsonc-parser@3.3.1: {} + jsonfile@6.2.0: dependencies: universalify: 2.0.1 @@ -9680,6 +12754,8 @@ snapshots: dependencies: language-subtag-registry: 0.3.23 + leven@3.1.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -9691,10 +12767,16 @@ snapshots: load-tsconfig@0.2.5: {} + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 + lodash.flattendeep@4.4.0: {} + lodash.merge@4.6.2: {} lodash@4.17.23: {} @@ -9704,12 +12786,16 @@ snapshots: chalk: 5.6.2 is-unicode-supported: 1.3.0 + loglevel@1.9.2: {} + longest-streak@3.1.0: {} loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 + loupe@3.2.1: {} + lowlight@1.20.0: dependencies: fault: 1.0.4 @@ -9717,6 +12803,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.2.6: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -9737,10 +12825,18 @@ snapshots: '@babel/types': 7.29.0 source-map-js: 1.2.1 + make-dir@3.1.0: + dependencies: + semver: 6.3.1 + make-dir@4.0.0: dependencies: semver: 7.7.4 + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + markdown-extensions@2.0.0: {} math-intrinsics@1.1.0: {} @@ -10063,8 +13159,14 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mime-types@3.0.2: dependencies: mime-db: 1.54.0 @@ -10085,6 +13187,10 @@ snapshots: minimist@1.2.8: {} + minipass@7.1.3: {} + + mkdirp@1.0.4: {} + mlly@1.8.1: dependencies: acorn: 8.16.0 @@ -10129,6 +13235,8 @@ snapshots: nanoid@3.3.11: {} + napi-postinstall@0.3.4: {} + natural-compare@1.4.0: {} natural-orderby@5.0.0: {} @@ -10176,6 +13284,12 @@ snapshots: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 + node-int64@0.4.0: {} + + node-preload@0.2.1: + dependencies: + process-on-spawn: 1.1.0 + node-releases@2.0.27: {} normalize-path@3.0.0: {} @@ -10191,6 +13305,38 @@ snapshots: nwsapi@2.2.23: {} + nyc@15.1.0: + dependencies: + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + caching-transform: 4.0.0 + convert-source-map: 1.9.0 + decamelize: 1.2.0 + find-cache-dir: 3.3.2 + find-up: 4.1.0 + foreground-child: 2.0.0 + get-package-type: 0.1.0 + glob: 7.2.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-hook: 3.0.0 + istanbul-lib-instrument: 4.0.3 + istanbul-lib-processinfo: 2.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.2.0 + make-dir: 3.1.0 + node-preload: 0.2.1 + p-map: 3.0.0 + process-on-spawn: 1.1.0 + resolve-from: 5.0.0 + rimraf: 3.0.2 + signal-exit: 3.0.7 + spawn-wrap: 2.0.0 + test-exclude: 6.0.0 + yargs: 15.4.1 + transitivePeerDependencies: + - supports-color + object-assign@4.1.1: {} object-hash@3.0.0: {} @@ -10249,6 +13395,13 @@ snapshots: dependencies: mimic-function: 5.0.1 + open@10.2.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + wsl-utils: 0.1.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -10270,6 +13423,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.2 + os-homedir@1.0.2: {} + outvariant@1.4.3: {} own-keys@1.0.1: @@ -10278,14 +13433,37 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 + p-map@3.0.0: + dependencies: + aggregate-error: 3.1.0 + + p-try@2.2.0: {} + + package-hash@4.0.0: + dependencies: + graceful-fs: 4.2.11 + hasha: 5.2.2 + lodash.flattendeep: 4.4.0 + release-zalgo: 1.0.0 + + package-json-from-dist@1.0.1: {} + package-manager-detector@1.6.0: {} parent-module@1.0.1: @@ -10311,6 +13489,8 @@ snapshots: parse-ms@4.0.0: {} + parse-passwd@1.0.0: {} + parse5@7.3.0: dependencies: entities: 6.0.1 @@ -10323,30 +13503,50 @@ snapshots: path-exists@4.0.0: {} + path-is-absolute@1.0.1: {} + path-key@3.1.1: {} path-key@4.0.0: {} path-parse@1.0.7: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.2.6 + minipass: 7.1.3 + path-to-regexp@6.3.0: {} path-to-regexp@8.3.0: {} pathe@2.0.3: {} + pathval@2.0.1: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} picomatch@4.0.3: {} + picoquery@2.5.0: {} + pify@2.3.0: {} pirates@4.0.7: {} pkce-challenge@5.0.1: {} + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -10428,12 +13628,22 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 + pretty-format@30.3.0: + dependencies: + '@jest/schemas': 30.0.5 + ansi-styles: 5.2.0 + react-is: 18.3.1 + pretty-ms@9.3.0: dependencies: parse-ms: 4.0.0 prismjs@1.30.0: {} + process-on-spawn@1.1.0: + dependencies: + fromentries: 1.3.2 + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -10452,8 +13662,12 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-from-env@1.1.0: {} + punycode@2.3.1: {} + pure-rand@7.0.1: {} + qs@6.15.0: dependencies: side-channel: 1.1.0 @@ -10476,6 +13690,25 @@ snapshots: date-fns-jalali: 4.1.0-0 react: 19.2.4 + react-docgen-typescript@2.4.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + react-docgen@8.0.2: + dependencies: + '@babel/core': 7.29.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.28.0 + '@types/doctrine': 0.0.9 + '@types/resolve': 1.20.6 + doctrine: 3.0.0 + resolve: 1.22.11 + strip-indent: 4.1.1 + transitivePeerDependencies: + - supports-color + react-dom@19.2.4(react@19.2.4): dependencies: react: 19.2.4 @@ -10485,6 +13718,8 @@ snapshots: react-is@17.0.2: {} + react-is@18.3.1: {} + react-markdown@10.1.0(@types/react@19.2.13)(react@19.2.4): dependencies: '@types/hast': 3.0.4 @@ -10553,6 +13788,12 @@ snapshots: dependencies: pify: 2.3.0 + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -10642,6 +13883,10 @@ snapshots: transitivePeerDependencies: - supports-color + release-zalgo@1.0.0: + dependencies: + es6-error: 4.1.1 + remark-mdx@3.1.1: dependencies: mdast-util-mdx: 3.0.0 @@ -10670,8 +13915,19 @@ snapshots: require-from-string@2.0.2: {} + require-main-filename@2.0.0: {} + requireindex@1.1.0: {} + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-dir@0.1.1: + dependencies: + expand-tilde: 1.2.2 + global-modules: 0.2.3 + resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -10699,6 +13955,10 @@ snapshots: reusify@1.1.0: {} + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + rollup@4.59.0: dependencies: '@types/estree': 1.0.8 @@ -10742,10 +14002,16 @@ snapshots: rrweb-cssom@0.8.0: {} + run-applescript@7.1.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -10754,6 +14020,8 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 + safe-buffer@5.2.1: {} + safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -10802,6 +14070,8 @@ snapshots: transitivePeerDependencies: - supports-color + set-blocking@2.0.0: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -10939,6 +14209,10 @@ snapshots: sisteransi@1.0.5: {} + slash@3.0.0: {} + + slash@5.1.0: {} + sonner@1.7.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 @@ -10946,12 +14220,43 @@ snapshots: source-map-js@1.2.1: {} + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + source-map@0.6.1: {} source-map@0.7.6: {} space-separated-tokens@2.0.2: {} + spawn-wrap@2.0.0: + dependencies: + foreground-child: 2.0.0 + is-windows: 1.0.2 + make-dir: 3.1.0 + rimraf: 3.0.2 + signal-exit: 3.0.7 + which: 2.0.2 + + spawnd@5.0.0: + dependencies: + exit: 0.1.2 + signal-exit: 3.0.7 + tree-kill: 1.2.2 + wait-port: 0.2.14 + transitivePeerDependencies: + - supports-color + + sprintf-js@1.0.3: {} + + sqids@0.3.0: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + stackback@0.0.2: {} statuses@2.0.2: {} @@ -10965,14 +14270,52 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 + storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@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.1) + '@vitest/expect': 3.2.4 + '@vitest/spy': 3.2.4 + esbuild: 0.27.3 + open: 10.2.0 + recast: 0.23.11 + semver: 7.7.4 + use-sync-external-store: 1.6.0(react@19.2.4) + ws: 8.19.0 + optionalDependencies: + prettier: 3.8.1 + transitivePeerDependencies: + - '@testing-library/dom' + - bufferutil + - react + - react-dom + - utf-8-validate + strict-event-emitter@0.5.1: {} + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-length@6.0.0: + dependencies: + strip-ansi: 7.1.2 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.2 + string-width@7.2.0: dependencies: emoji-regex: 10.6.0 @@ -11029,6 +14372,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + stringify-entities@4.0.4: dependencies: character-entities-html4: 2.1.0 @@ -11050,6 +14397,8 @@ snapshots: strip-bom@3.0.0: {} + strip-bom@4.0.0: {} + strip-final-newline@2.0.0: {} strip-final-newline@4.0.0: {} @@ -11087,10 +14436,18 @@ snapshots: tinyglobby: 0.2.15 ts-interface-checker: 0.1.13 + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} symbol-tree@3.2.4: {} @@ -11137,6 +14494,12 @@ snapshots: - tsx - yaml + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 10.2.4 + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -11158,8 +14521,12 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinyrainbow@2.0.0: {} + tinyrainbow@3.0.3: {} + tinyspy@4.0.4: {} + tldts-core@6.1.86: {} tldts-core@7.0.23: {} @@ -11172,6 +14539,18 @@ snapshots: dependencies: tldts-core: 7.0.23 + tmcp@1.19.3(typescript@5.9.3): + dependencies: + '@standard-schema/spec': 1.1.0 + json-rpc-2.0: 1.7.1 + sqids: 0.3.0 + uri-template-matcher: 1.1.2 + valibot: 1.2.0(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + tmpl@1.0.5: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -11207,6 +14586,8 @@ snapshots: picomatch: 4.0.3 typescript: 5.9.3 + ts-dedent@2.2.0: {} + ts-interface-checker@0.1.13: {} ts-morph@26.0.0: @@ -11222,7 +14603,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3): + tsup@8.5.1(@swc/core@1.15.18)(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3): dependencies: bundle-require: 5.1.0(esbuild@0.27.3) cac: 6.7.14 @@ -11242,6 +14623,7 @@ snapshots: tinyglobby: 0.2.15 tree-kill: 1.2.2 optionalDependencies: + '@swc/core': 1.15.18 postcss: 8.5.6 typescript: 5.9.3 transitivePeerDependencies: @@ -11288,6 +14670,12 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-detect@4.0.8: {} + + type-fest@0.21.3: {} + + type-fest@0.8.1: {} + type-fest@5.4.4: dependencies: tagged-tag: 1.0.0 @@ -11331,6 +14719,10 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typedarray-to-buffer@3.1.5: + dependencies: + is-typedarray: 1.0.0 + typescript-eslint@8.56.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3): dependencies: '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) @@ -11401,6 +14793,37 @@ snapshots: unpipe@1.0.0: {} + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.16.0 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + until-async@3.0.2: {} update-browserslist-db@1.2.3(browserslist@4.28.1): @@ -11413,6 +14836,8 @@ snapshots: dependencies: punycode: 2.3.1 + uri-template-matcher@1.1.2: {} + use-callback-ref@1.3.3(@types/react@19.2.13)(react@19.2.4): dependencies: react: 19.2.4 @@ -11434,6 +14859,18 @@ snapshots: util-deprecate@1.0.2: {} + uuid@8.3.2: {} + + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + valibot@1.2.0(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + vary@1.1.2: {} vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): @@ -11525,12 +14962,36 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + wait-on@7.2.0: + dependencies: + axios: 1.13.6 + joi: 17.13.3 + lodash: 4.17.23 + minimist: 1.2.8 + rxjs: 7.8.2 + transitivePeerDependencies: + - debug + + wait-port@0.2.14: + dependencies: + chalk: 2.4.2 + commander: 3.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + weasel-words@0.1.1: {} web-streams-polyfill@3.3.3: {} webidl-conversions@7.0.0: {} + webpack-virtual-modules@0.6.2: {} + whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 @@ -11573,6 +15034,8 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 + which-module@2.0.1: {} + which-typed-array@1.1.20: dependencies: available-typed-arrays: 1.0.7 @@ -11583,6 +15046,10 @@ snapshots: gopd: 1.2.0 has-tostringtag: 1.0.2 + which@1.3.1: + dependencies: + isexe: 2.0.0 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -11612,8 +15079,26 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.1.2 + wrappy@1.0.2: {} + write-file-atomic@3.0.3: + dependencies: + imurmurhash: 0.1.4 + is-typedarray: 1.0.0 + signal-exit: 3.0.7 + typedarray-to-buffer: 3.1.5 + + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + write-good@1.0.8: dependencies: adverb-where: 0.2.6 @@ -11626,16 +15111,43 @@ snapshots: ws@8.19.0: {} + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 + xml-name-validator@5.0.0: {} + xml@1.0.1: {} + xmlchars@2.2.0: {} + y18n@4.0.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + yargs-parser@21.1.1: {} + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yargs@17.7.2: dependencies: cliui: 8.0.1 diff --git a/turbo.json b/turbo.json index 9eb98a5..58d43e6 100644 --- a/turbo.json +++ b/turbo.json @@ -36,6 +36,20 @@ "registry:build": { "dependsOn": ["^build"], "outputs": ["public/r/**"] + }, + "storybook": { + "persistent": true, + "cache": false + }, + "build-storybook": { + "dependsOn": ["^build"], + "outputs": ["storybook-static/**"] + }, + "test-storybook": { + "cache": false + }, + "check:stories": { + "cache": false } } } From de382cebea43cee83449c2dc2ecf01c6490b2c2e Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:54:20 +0100 Subject: [PATCH 04/26] refactor(registry): replace ComponentPreview with Storybook embeds - Create StorybookEmbed client component (iframe wrapper with loading state) - Create sync-from-storybook.ts script (maps story IDs to registry components) - Generate component-metadata.json from Storybook index.json + registry.json - Refactor [slug]/page.tsx to use StorybookEmbed + synced metadata - Refactor components/page.tsx to use metadata cards instead of previews - Delete ComponentPreview switch statement (1,714 LOC) - Delete 34 MDX files (header.mdx + example.mdx) - Add "View in Storybook" links with story variant badges - shadcn /r/*.json API unchanged Stories are now the single source of truth for component visualization. --- apps/registry/app/components/[slug]/page.tsx | 276 ++- apps/registry/app/components/page.tsx | 56 +- .../component-preview/component-preview.tsx | 1714 ----------------- .../components/component-preview/index.ts | 1 - .../components/storybook-embed/index.ts | 1 + .../storybook-embed/storybook-embed.tsx | 50 + apps/registry/lib/component-metadata.json | 1298 +++++++++++++ apps/registry/package.json | 4 +- .../registry/default/badge/example.mdx | 8 - .../registry/default/badge/header.mdx | 7 - .../registry/default/breadcrumb/example.mdx | 8 - .../registry/default/breadcrumb/header.mdx | 7 - .../registry/default/button/example.mdx | 26 - .../registry/default/button/header.mdx | 7 - .../registry/default/card/example.mdx | 28 - .../registry/registry/default/card/header.mdx | 7 - .../registry/default/code-block/example.mdx | 11 - .../registry/default/code-block/header.mdx | 7 - .../registry/default/command/example.mdx | 26 - .../registry/default/command/header.mdx | 7 - .../registry/default/dialog/example.mdx | 30 - .../registry/default/dialog/header.mdx | 7 - .../default/dropdown-menu/example.mdx | 27 - .../registry/default/dropdown-menu/header.mdx | 7 - .../default/horizontal-scroll-row/example.mdx | 14 - .../default/horizontal-scroll-row/header.mdx | 7 - .../registry/default/input/example.mdx | 8 - .../registry/default/input/header.mdx | 7 - .../default/lang-provider/example.mdx | 8 - .../registry/default/lang-provider/header.mdx | 7 - .../default/profile-section/example.mdx | 22 - .../default/profile-section/header.mdx | 7 - .../default/theme-provider/example.mdx | 12 - .../default/theme-provider/header.mdx | 7 - .../registry/default/theme-toggle/example.mdx | 8 - .../registry/default/theme-toggle/header.mdx | 7 - .../registry/default/tldr-section/example.mdx | 12 - .../registry/default/tldr-section/header.mdx | 7 - .../registry/default/toast/example.mdx | 30 - .../registry/default/toast/header.mdx | 7 - .../default/view-switcher/example.mdx | 17 - .../registry/default/view-switcher/header.mdx | 7 - apps/registry/scripts/sync-from-storybook.ts | 164 ++ pnpm-lock.yaml | 3 + .../2026-03-11-registry-storybook-embed.md | 78 + turbo.json | 3 + 46 files changed, 1754 insertions(+), 2308 deletions(-) delete mode 100644 apps/registry/components/component-preview/component-preview.tsx delete mode 100644 apps/registry/components/component-preview/index.ts create mode 100644 apps/registry/components/storybook-embed/index.ts create mode 100644 apps/registry/components/storybook-embed/storybook-embed.tsx create mode 100644 apps/registry/lib/component-metadata.json delete mode 100644 apps/registry/registry/default/badge/example.mdx delete mode 100644 apps/registry/registry/default/badge/header.mdx delete mode 100644 apps/registry/registry/default/breadcrumb/example.mdx delete mode 100644 apps/registry/registry/default/breadcrumb/header.mdx delete mode 100644 apps/registry/registry/default/button/example.mdx delete mode 100644 apps/registry/registry/default/button/header.mdx delete mode 100644 apps/registry/registry/default/card/example.mdx delete mode 100644 apps/registry/registry/default/card/header.mdx delete mode 100644 apps/registry/registry/default/code-block/example.mdx delete mode 100644 apps/registry/registry/default/code-block/header.mdx delete mode 100644 apps/registry/registry/default/command/example.mdx delete mode 100644 apps/registry/registry/default/command/header.mdx delete mode 100644 apps/registry/registry/default/dialog/example.mdx delete mode 100644 apps/registry/registry/default/dialog/header.mdx delete mode 100644 apps/registry/registry/default/dropdown-menu/example.mdx delete mode 100644 apps/registry/registry/default/dropdown-menu/header.mdx delete mode 100644 apps/registry/registry/default/horizontal-scroll-row/example.mdx delete mode 100644 apps/registry/registry/default/horizontal-scroll-row/header.mdx delete mode 100644 apps/registry/registry/default/input/example.mdx delete mode 100644 apps/registry/registry/default/input/header.mdx delete mode 100644 apps/registry/registry/default/lang-provider/example.mdx delete mode 100644 apps/registry/registry/default/lang-provider/header.mdx delete mode 100644 apps/registry/registry/default/profile-section/example.mdx delete mode 100644 apps/registry/registry/default/profile-section/header.mdx delete mode 100644 apps/registry/registry/default/theme-provider/example.mdx delete mode 100644 apps/registry/registry/default/theme-provider/header.mdx delete mode 100644 apps/registry/registry/default/theme-toggle/example.mdx delete mode 100644 apps/registry/registry/default/theme-toggle/header.mdx delete mode 100644 apps/registry/registry/default/tldr-section/example.mdx delete mode 100644 apps/registry/registry/default/tldr-section/header.mdx delete mode 100644 apps/registry/registry/default/toast/example.mdx delete mode 100644 apps/registry/registry/default/toast/header.mdx delete mode 100644 apps/registry/registry/default/view-switcher/example.mdx delete mode 100644 apps/registry/registry/default/view-switcher/header.mdx create mode 100644 apps/registry/scripts/sync-from-storybook.ts create mode 100644 specs/active/2026-03-11-registry-storybook-embed.md diff --git a/apps/registry/app/components/[slug]/page.tsx b/apps/registry/app/components/[slug]/page.tsx index 6365917..e940bfa 100644 --- a/apps/registry/app/components/[slug]/page.tsx +++ b/apps/registry/app/components/[slug]/page.tsx @@ -1,14 +1,15 @@ import { readFile } from "node:fs/promises"; import path from "node:path"; -import { CodeBlock, MDXContent, Sidebar, TableOfContents } from "@vllnt/ui"; +import { CodeBlock, Sidebar, TableOfContents } from "@vllnt/ui"; import { ExternalLink } from "lucide-react"; import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; -import { ComponentPreview } from "@/components/component-preview"; import { QuickAdd } from "@/components/quick-add"; +import { StorybookEmbed } from "@/components/storybook-embed"; +import componentMetadata from "@/lib/component-metadata.json"; import { getCategoryForComponent, getSidebarSections, @@ -21,6 +22,20 @@ type Props = { }; const registry = registryData as Registry; +const metadata_map = componentMetadata as Record< + string, + { + category: string; + defaultStoryId: string; + description: string; + name: string; + stories: { id: string; name: string }[]; + title: string; + } +>; + +const STORYBOOK_URL = + process.env.NEXT_PUBLIC_STORYBOOK_URL ?? "http://localhost:6006"; export async function generateStaticParams() { return registry.items @@ -36,44 +51,6 @@ function getNpmUrl(packageName: string): string { return `https://www.npmjs.com/package/${packageName}`; } -function parseFrontmatter(content: string): { - content: string; - metadata: Record; -} { - const frontmatterRegex = /^---\s*\n([\S\s]*?)\n---\s*\n([\S\s]*)$/; - const match = frontmatterRegex.exec(content); - - if (!match?.[1] || !match[2]) { - return { content, metadata: {} }; - } - - const yamlContent = match[1]; - const bodyContent = match[2]; - - const metadata: Record = {}; - yamlContent.split("\n").forEach((line) => { - const colonIndex = line.indexOf(":"); - if (colonIndex > 0) { - const key = line.slice(0, colonIndex).trim(); - const value = line - .slice(colonIndex + 1) - .trim() - .replaceAll(/^["']|["']$/g, ""); - metadata[key] = value; - } - }); - - return { content: bodyContent, metadata }; -} - -function getComponentDirectory(component: RegistryComponent): string { - if (component.files[0]?.path) { - const componentFilePath = path.join(process.cwd(), component.files[0].path); - return path.dirname(componentFilePath); - } - return path.join(process.cwd(), "registry", "default", component.name); -} - export async function generateMetadata(props: Props): Promise { const { slug } = await props.params; const component = registry.items.find( @@ -85,33 +62,24 @@ export async function generateMetadata(props: Props): Promise { return {}; } - const componentDirectory = getComponentDirectory(component); - const headerPath = path.join(componentDirectory, "header.mdx"); - - try { - const headerContent = await readFile(headerPath, "utf8"); - const { metadata } = parseFrontmatter(headerContent); - - return { - description: metadata.description || component.description, - openGraph: { - description: metadata.description || component.description, - title: metadata.title || component.title, - type: "website", - }, - title: metadata.title || `${component.title} - VLLNT UI`, - twitter: { - card: "summary_large_image", - description: metadata.description || component.description, - title: metadata.title || component.title, - }, - }; - } catch { - return { - description: component.description, - title: `${component.title} - VLLNT UI`, - }; - } + const meta = metadata_map[slug]; + const title = meta?.title ?? component.title; + const description = meta?.description ?? component.description; + + return { + description, + openGraph: { + description, + title, + type: "website", + }, + title: `${title} - VLLNT UI`, + twitter: { + card: "summary_large_image", + description, + title, + }, + }; } export default async function ComponentPage(props: Props) { @@ -125,48 +93,30 @@ export default async function ComponentPage(props: Props) { notFound(); } - // Read component file for code display - use actual source from @vllnt/ui + const meta = metadata_map[slug]; + const displayTitle = meta?.title ?? component.title ?? component.name; + const displayDescription = meta?.description ?? component.description ?? ""; + + // Read component source for code display let componentCode = ""; try { - // Map component name to actual source file path in packages/ui/src/components - // Chart components are in chart/ subdirectory: packages/ui/src/components/chart/{name}.tsx const isChartComponent = ["area-chart", "bar-chart", "line-chart"].includes( component.name, ); - if (isChartComponent) { - const chartPath = path.join( - process.cwd(), - "..", - "..", - "packages", - "ui", - "src", - "components", - "chart", - `${component.name}.tsx`, - ); - componentCode = await readFile(chartPath, "utf8"); - } else { - // Most components are in subdirectories: packages/ui/src/components/{name}/{name}.tsx - const subdirectoryPath = path.join( - process.cwd(), - "..", - "..", - "packages", - "ui", - "src", - "components", - component.name, - `${component.name}.tsx`, - ); - - // Try reading from subdirectory first (most components) - try { - componentCode = await readFile(subdirectoryPath, "utf8"); - } catch { - // Fallback to direct file (e.g., theme-provider.tsx) - const directPath = path.join( + const sourcePath = isChartComponent + ? path.join( + process.cwd(), + "..", + "..", + "packages", + "ui", + "src", + "components", + "chart", + `${component.name}.tsx`, + ) + : path.join( process.cwd(), "..", "..", @@ -174,54 +124,40 @@ export default async function ComponentPage(props: Props) { "ui", "src", "components", + component.name, `${component.name}.tsx`, ); - componentCode = await readFile(directPath, "utf8"); - } - } - } catch (error) { - console.error("Error reading component source file:", error); - } - - const componentDirectory = getComponentDirectory(component); - // Read header.mdx for title, description, and SEO metadata - let headerContent = ""; - let headerMetadata: Record = {}; - try { - const headerPath = path.join(componentDirectory, "header.mdx"); - const headerRaw = await readFile(headerPath, "utf8"); - const parsed = parseFrontmatter(headerRaw); - headerContent = parsed.content; - headerMetadata = parsed.metadata; - } catch { - // Header file is optional, fallback to registry defaults - } - - // Read example.mdx for usage examples - let exampleContent = ""; - try { - const examplePath = path.join(componentDirectory, "example.mdx"); - exampleContent = await readFile(examplePath, "utf8"); + try { + componentCode = await readFile(sourcePath, "utf8"); + } catch { + const directPath = path.join( + process.cwd(), + "..", + "..", + "packages", + "ui", + "src", + "components", + `${component.name}.tsx`, + ); + componentCode = await readFile(directPath, "utf8"); + } } catch { - // Example file is optional, ignore if it doesn't exist + // Source file not found — skip code section } const installCommand = `pnpm dlx shadcn@latest add https://ui.vllnt.com/r/${component.name}.json`; const sections = [ { id: "installation", title: "Installation" }, - ...(exampleContent ? [{ id: "usage", title: "Usage" }] : []), + ...(meta?.defaultStoryId ? [{ id: "storybook", title: "Storybook" }] : []), ...(componentCode ? [{ id: "code", title: "Code" }] : []), ...(component.dependencies && component.dependencies.length > 0 ? [{ id: "dependencies", title: "Dependencies" }] : []), ] as { id: string; title: string }[]; - const displayTitle = headerMetadata.title || component.title; - const displayDescription = - headerContent || headerMetadata.description || component.description; - return ( <> @@ -232,26 +168,20 @@ export default async function ComponentPage(props: Props) { {/* Header */}

{displayTitle}

- {headerContent ? ( -
-
- -
-
- ) : ( -

- {displayDescription} -

- )} +

+ {displayDescription} +

- {/* Preview Section */} -
-
- + {/* Preview — Storybook Embed */} + {meta?.defaultStoryId ? ( +
+
+ +
-
+ ) : null} {/* Installation */}
@@ -261,13 +191,43 @@ export default async function ComponentPage(props: Props) {
- {/* Examples */} - {exampleContent ? ( -
-

Usage

-
- -
+ {/* Storybook link */} + {meta?.defaultStoryId ? ( +
+

Storybook

+

+ Explore all variants, controls, and accessibility checks in + the interactive Storybook playground. +

+ + View in Storybook + + + {meta.stories.length > 1 ? ( +
+

+ {meta.stories.length} stories available: +

+
+ {meta.stories.map((story) => ( + + {story.name} + + ))} +
+
+ ) : null}
) : null} diff --git a/apps/registry/app/components/page.tsx b/apps/registry/app/components/page.tsx index d3cd5e7..15b724e 100644 --- a/apps/registry/app/components/page.tsx +++ b/apps/registry/app/components/page.tsx @@ -1,13 +1,22 @@ import { Sidebar } from "@vllnt/ui"; import Link from "next/link"; -import { ComponentPreview } from "@/components/component-preview/component-preview"; +import componentMetadata from "@/lib/component-metadata.json"; import { components, getSidebarSections, groupedComponents, } from "@/lib/sidebar-sections"; +const metadata_map = componentMetadata as Record< + string, + { + description: string; + stories: { id: string; name: string }[]; + title: string; + } +>; + export default function ComponentsPage() { return ( <> @@ -26,29 +35,36 @@ export default function ComponentsPage() {

{group.label}

- {group.items.map((component) => ( -
+ {group.items.map((component) => { + const meta = metadata_map[component.name]; + const storyCount = meta?.stories?.length ?? 0; + + return ( - {component.title} - -
-
- +
+

+ {component.title} +

+ {meta?.description ? ( +

+ {meta.description} +

+ ) : null}
-
-
-

- {component.title} -

-
-
- ))} +
+ + {storyCount > 0 + ? `${storyCount} ${storyCount === 1 ? "story" : "stories"}` + : "No preview"} + +
+ + ); + })}
))} diff --git a/apps/registry/components/component-preview/component-preview.tsx b/apps/registry/components/component-preview/component-preview.tsx deleted file mode 100644 index df7c939..0000000 --- a/apps/registry/components/component-preview/component-preview.tsx +++ /dev/null @@ -1,1714 +0,0 @@ -"use client"; - -import * as React from "react"; - -import { - Accordion, - AccordionContent, - AccordionItem, - AccordionTrigger, - Alert, - AlertDescription, - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger, - AlertTitle, - AspectRatio, - Avatar, - AvatarFallback, - AvatarImage, - Badge, - Breadcrumb, - Button, - Calendar, - Callout, - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, - Carousel, - CarouselContent, - CarouselItem, - CarouselNext, - CarouselPrevious, - CategoryFilter, - Checkbox, - Checklist, - CodeBlock, - CodePlayground, - Collapsible, - CollapsibleContent, - CollapsibleTrigger, - CommandDialog, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - CommonMistake, - Comparison, - ContentCard, - ContextMenu, - ContextMenuContent, - ContextMenuItem, - ContextMenuTrigger, - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, - Drawer, - DrawerClose, - DrawerContent, - DrawerDescription, - DrawerFooter, - DrawerHeader, - DrawerTitle, - DrawerTrigger, - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, - Exercise, - FAQ, - FAQItem, - FloatingActionButton, - Glossary, - HorizontalScrollRow, - HoverCard, - HoverCardContent, - HoverCardTrigger, - InlineInput, - Input, - InputOTP, - InputOTPGroup, - InputOTPSlot, - KeyboardShortcutsHelp, - KeyConcept, - LangProvider, - LearningObjectives, - Menubar, - MenubarContent, - MenubarItem, - MenubarMenu, - MenubarSeparator, - MenubarTrigger, - NavigationMenu, - NavigationMenuContent, - NavigationMenuItem, - NavigationMenuLink, - NavigationMenuList, - NavigationMenuTrigger, - Pagination, - Popover, - PopoverContent, - PopoverTrigger, - Prerequisites, - ProfileSection, - ProgressBar, - ProTip, - Quiz, - RadioGroup, - RadioGroupItem, - ResizableHandle, - ResizablePanel, - ResizablePanelGroup, - ScrollArea, - SearchBar, - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, - Separator, - ShareSection, - Sheet, - SheetClose, - SheetContent, - SheetDescription, - SheetFooter, - SheetHeader, - SheetTitle, - SheetTrigger, - Sidebar, - SidebarProvider, - SidebarToggle, - Skeleton, - Slider, - Spinner, - Step, - StepByStep, - StepNavigation, - Summary, - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableOfContents, - TableRow, - Tabs, - TabsContent, - TabsList, - TabsTrigger, - Terminal, - Textarea, - ThemeProvider, - ThemeToggle, - ThinkingBlock, - TLDRSection, - Toast, - ToastDescription, - ToastTitle, - Toggle, - ToggleGroup, - ToggleGroupItem, - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, - TutorialCard, - VideoEmbed, - ViewSwitcher, -} from "@vllnt/ui"; -import { - Bold, - ChevronsUpDown, - Italic, - Plus, - Terminal as TerminalIcon, - Underline, -} from "lucide-react"; - -type ComponentPreviewProps = { - componentName: string; -}; - -// Simple text-based preview for components that need complex context -function SimplePreview({ description }: { description: string }) { - return ( -
-

{description}

-
- ); -} - -function ButtonPreview() { - return ( -
- - - - - - -
- ); -} - -function BadgePreview() { - return ( -
- Default - Secondary - Destructive - Outline -
- ); -} - -function CardPreview() { - return ( - - - Card Title - Card description goes here. - - -

Card content

-
- - - -
- ); -} - -function InputPreview() { - return ( -
- - -
- ); -} - -function BreadcrumbPreview() { - return ( - - ); -} - -function DropdownMenuPreview() { - return ( - - - - - - Profile - Settings - Logout - - - ); -} - -function ToastPreview() { - return ( -
- - Toast Title - Toast description goes here. - -
- ); -} - -function TLDRSectionPreview() { - return ( - - This is a collapsible section with a loading animation. When you first - expand it, you'll see a shimmer effect before the content appears. - - ); -} - -function DialogPreview() { - return ( - - - - - - - Dialog Example - - This is an example dialog component. - - - - - - - - - ); -} - -function CodeBlockPreview() { - return ( - - {`function greet(name: string) { - return \`Hello, \${name}!\` -}`} - - ); -} - -function ProfileSectionPreview() { - return ( - - ); -} - -function ThemeTogglePreview() { - return ( - - ); -} - -function LangProviderPreview() { - return ( -
- -

- Sets the HTML lang attribute. -

-
- ); -} - -function ThemeProviderPreview() { - return ( - -
-

- Theme Provider wraps your app for theme support. -

-
-
- ); -} - -function CommandPreview() { - const [open, setOpen] = React.useState(false); - return ( -
- - - - - No results found. - - Calendar - Settings - - - -
- ); -} - -function TabsPreview() { - return ( - - - Account - Password - - -

- Manage your account here. -

-
- -

- Change your password here. -

-
-
- ); -} - -function CalloutPreview() { - return ( -
- This is an informational callout. - This is a warning callout. - This is a helpful tip. - This is a danger callout. -
- ); -} - -function CheckboxPreview() { - return ( -
-
- - -
-
- - -
-
- ); -} - -function TerminalPreview() { - return ( - - ); -} - -// New real previews - -function FAQPreview() { - return ( - // eslint-disable-next-line react/jsx-pascal-case -- FAQ is an acronym - - -

A collapsible FAQ component for displaying questions and answers.

-
- -

Wrap FAQItem components inside the FAQ component.

-
-
- ); -} - -function QuizPreview() { - return ( - Paris has been France's capital since the 12th century.

- } - hint="It's known as the City of Light" - options={[ - { label: "London" }, - { correct: true, label: "Paris" }, - { label: "Berlin" }, - ]} - question="What is the capital of France?" - /> - ); -} - -function ChecklistPreview() { - return ( - - ); -} - -function StepByStepPreview() { - return ( - - Run npm install to install dependencies. - Set up your configuration files. - Build your application for production. - - ); -} - -function ProTipPreview() { - return ( -
- -

Use TypeScript for better developer experience.

-
- Always add unique keys to list items.

} - title="Forgetting keys" - > -

Rendering lists without keys causes issues.

-
-
- ); -} - -function ProgressBarPreview() { - return ( -
- - -
- ); -} - -function KeyConceptPreview() { - return ( -
- -

A reusable piece of UI that encapsulates structure and behavior.

-
- - -

Data passed from parent to child components.

-
- -

Data that changes over time within a component.

-
-
-
- ); -} - -function LearningObjectivesPreview() { - return ( -
- - - -

We covered the basics of React components.

-
-
- ); -} - -function ComparisonPreview() { - return ( - - ); -} - -function ExercisePreview() { - return ( - const [count, setCount] = useState(0) - } - title="Create a Counter" - > -

Create a component that displays and increments a number.

-
- ); -} - -function SidebarTogglePreview() { - const [open, setOpen] = React.useState(false); - return ( -
- { - setOpen(!open); - }} - open={open} - /> - - Sidebar is {open ? "open" : "closed"} - -
- ); -} - -function ThinkingBlockPreview() { - return ( - - ); -} - -function InlineInputPreview() { - const [value, setValue] = React.useState("Click to edit"); - return ( -
-

Click the input to edit:

- { - setValue(v); - }} - value={value} - /> -
- ); -} - -function VideoEmbedPreview() { - return ( -
- -
- ); -} - -function BlogCardPreview() { - return ( - - ); -} - -function CategoryFilterPreview() { - return ( - - ); -} - -function PaginationPreview() { - return ; -} - -function SearchBarPreview() { - return ( - -
-
-
- } - > - { - console.info("Search:", q); - }} - placeholder="Search articles..." - /> - - ); -} - -function ShareSectionPreview() { - return ( - - ); -} - -function CodePlaygroundPreview() { - return ( - - {`function Button({ children }) { - return -}`} - - ); -} - -function FloatingActionButtonPreview() { - return ( -
- { - alert("Clicked!"); - }} - position="bottom-right" - > - - -
- ); -} - -function KeyboardShortcutsHelpPreview() { - const [isOpen, setIsOpen] = React.useState(false); - return ( -
- - { - setIsOpen(false); - }} - shortcuts={[ - { description: "Open command palette", keys: ["⌘", "K"] }, - { description: "Close dialog", keys: ["Esc"] }, - ]} - /> -
- ); -} - -function StepNavigationPreview() { - const [step, setStep] = React.useState(2); - return ( - 1} - currentStep={step} - onNext={() => { - setStep(step + 1); - }} - onPrev={() => { - setStep(step - 1); - }} - stepLabel="Step" - totalSteps={5} - /> - ); -} - -function TableOfContentsPreview() { - return ( - - ); -} - -function TutorialCardPreview() { - return ( - - ); -} - -function AreaChartPreview() { - return ( -
- - - - - - - - - - -
- ); -} - -function BarChartPreview() { - return ( -
-
-
-
-
-
- ); -} - -function LineChartPreview() { - return ( -
- - - - - - - - -
- ); -} - -function SidebarPreview() { - return ( -
- -
- ); -} - -function SidebarProviderPreview() { - return ( - -
-

- Manages sidebar state with useSidebar() hook. -

-
-
- ); -} - -function MDXContentPreview() { - return ( - - ); -} - -function AccordionPreview() { - return ( - - - What is this? - - A collapsible section. - - - - ); -} - -// New shadcn primitive previews - -function TextareaPreview() { - return ( -
- +``` + + + +## API Reference diff --git a/packages/ui/src/components/theme-provider/theme-provider.mdx b/packages/ui/src/components/theme-provider/theme-provider.mdx index 833ed52..d0e39a2 100644 --- a/packages/ui/src/components/theme-provider/theme-provider.mdx +++ b/packages/ui/src/components/theme-provider/theme-provider.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './theme-provider.stories' @@ -21,7 +21,15 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/theme-provider.json import { ThemeProvider } from '@vllnt/ui' ``` -## Controls +## Usage + +```tsx +ThemeProvider content +``` + + + +## API Reference diff --git a/packages/ui/src/components/theme-toggle/theme-toggle.mdx b/packages/ui/src/components/theme-toggle/theme-toggle.mdx index 854cde4..7459997 100644 --- a/packages/ui/src/components/theme-toggle/theme-toggle.mdx +++ b/packages/ui/src/components/theme-toggle/theme-toggle.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './theme-toggle.stories' @@ -21,7 +21,22 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/theme-toggle.json import { ThemeToggle } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx + + ThemeToggle content + +``` + + + +## API Reference @@ -34,3 +49,21 @@ import { ThemeToggle } from '@vllnt/ui' | `system` | `string` | Yes | - | | `toggle_theme` | `string` | Yes | - | +## Type Definitions + +### ThemeButtonProps + +```tsx +type ThemeButtonProps = { + ariaLabel: string + children?: React.ReactNode + icon: string +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `ariaLabel` | `string` | Yes | - | +| `children` | `React.ReactNode` | No | React content (JSX, string, number, etc.) | +| `icon` | `string` | Yes | - | + diff --git a/packages/ui/src/components/thinking-block/thinking-block.mdx b/packages/ui/src/components/thinking-block/thinking-block.mdx index df398a5..e0fc6b6 100644 --- a/packages/ui/src/components/thinking-block/thinking-block.mdx +++ b/packages/ui/src/components/thinking-block/thinking-block.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './thinking-block.stories' @@ -21,14 +21,23 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/thinking-block.json import { ThinkingBlock } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx + +``` + + + +## API Reference | Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | -| `className` | `string` | No | - | -| `isStreaming` | `boolean` | No | - | +| `isStreaming` | `boolean` | No | `true` or `false` | | `thinking` | `string` | Yes | - | ## Dependencies diff --git a/packages/ui/src/components/tldr-section/tldr-section.mdx b/packages/ui/src/components/tldr-section/tldr-section.mdx index 2bab0bc..793b7e6 100644 --- a/packages/ui/src/components/tldr-section/tldr-section.mdx +++ b/packages/ui/src/components/tldr-section/tldr-section.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './tldr-section.stories' @@ -21,12 +21,40 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/tldr-section.json import { TLDRSection } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx + + TldrSection content + +``` + + + +## API Reference | Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | -| `children` | `React.ReactNode` | Yes | - | +| `children` | `React.ReactNode` | Yes | React content (JSX, string, number, etc.) | +| `label` | `string` | Yes | - | + +## Type Definitions + +### TLDRSectionProps + +```tsx +type TLDRSectionProps = { + children: React.ReactNode + label: string +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `children` | `React.ReactNode` | Yes | React content (JSX, string, number, etc.) | | `label` | `string` | Yes | - | diff --git a/packages/ui/src/components/toast/toast.mdx b/packages/ui/src/components/toast/toast.mdx index defdbb4..f4a6c6f 100644 --- a/packages/ui/src/components/toast/toast.mdx +++ b/packages/ui/src/components/toast/toast.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './toast.stories' @@ -18,16 +18,30 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/toast.json ## Import ```tsx -import { Toast, ToastAction, ToastClose, ToastDescription, ToastTitle } from '@vllnt/ui' +import { + Toast, + ToastAction, + ToastClose, + ToastDescription, + ToastTitle, +} from '@vllnt/ui' ``` -## Props +## Usage + +```tsx +Toast content +``` + + + +## API Reference | Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | -| `variant` | `"default" \| "destructive"` | No | - | +| `variant` | `"default" \| "destructive"` | No | `default`, `destructive` | ## Variants @@ -38,13 +52,13 @@ import { Toast, ToastAction, ToastClose, ToastDescription, ToastTitle } from '@v | `default` | Yes | | `destructive` | - | -## Stories +## Examples ### Destructive - + ### With Action - + diff --git a/packages/ui/src/components/toggle-group/toggle-group.mdx b/packages/ui/src/components/toggle-group/toggle-group.mdx index faaa30a..153497b 100644 --- a/packages/ui/src/components/toggle-group/toggle-group.mdx +++ b/packages/ui/src/components/toggle-group/toggle-group.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './toggle-group.stories' @@ -21,7 +21,19 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/toggle-group.json import { ToggleGroup, ToggleGroupItem } from '@vllnt/ui' ``` -## Controls +## Usage + +```tsx + + + +``` + + + +## API Reference +### ToggleGroup.displayName + diff --git a/packages/ui/src/components/toggle/toggle.mdx b/packages/ui/src/components/toggle/toggle.mdx index 091c4ca..1ca29db 100644 --- a/packages/ui/src/components/toggle/toggle.mdx +++ b/packages/ui/src/components/toggle/toggle.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './toggle.stories' @@ -21,10 +21,22 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/toggle.json import { Toggle } from '@vllnt/ui' ``` -## Controls +## Usage + +```tsx + + + +``` + + + +## API Reference +### Toggle.displayName + ## Variants ### size @@ -35,9 +47,9 @@ import { Toggle } from '@vllnt/ui' | `lg` | - | | `sm` | - | - + - + ### variant @@ -46,5 +58,5 @@ import { Toggle } from '@vllnt/ui' | `default` | Yes | | `outline` | - | - + diff --git a/packages/ui/src/components/tooltip/tooltip.mdx b/packages/ui/src/components/tooltip/tooltip.mdx index a9a919c..da76c25 100644 --- a/packages/ui/src/components/tooltip/tooltip.mdx +++ b/packages/ui/src/components/tooltip/tooltip.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './tooltip.stories' @@ -18,10 +18,23 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/tooltip.json ## Import ```tsx -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@vllnt/ui' +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '@vllnt/ui' ``` -## Controls +## Usage + +```tsx +Hover me +``` + + + +## API Reference diff --git a/packages/ui/src/components/truncated-text/truncated-text.mdx b/packages/ui/src/components/truncated-text/truncated-text.mdx index ada58cb..ce39dec 100644 --- a/packages/ui/src/components/truncated-text/truncated-text.mdx +++ b/packages/ui/src/components/truncated-text/truncated-text.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './truncated-text.stories' @@ -19,14 +19,20 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/truncated-text.json import { TruncatedText } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx +TruncatedText content +``` + + + +## API Reference | Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | | `children` | `string` | Yes | - | -| `className` | `string` | No | - | -| `default` | `'calc(100vw - 220px)')` | Yes | - | | `maxWidth` | `string` | No | - | diff --git a/packages/ui/src/components/tutorial-card/tutorial-card.mdx b/packages/ui/src/components/tutorial-card/tutorial-card.mdx index 2b30309..f79d3ee 100644 --- a/packages/ui/src/components/tutorial-card/tutorial-card.mdx +++ b/packages/ui/src/components/tutorial-card/tutorial-card.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './tutorial-card.stories' @@ -21,17 +21,85 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/tutorial-card.json import { TutorialCard } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx + + ... + +``` + + + +## API Reference | Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | -| `getProgress` | `(id: string) => null \| TutorialCardProgress` | No | - | +| `getProgress` | `(id: string) => null \| TutorialCardProgress` | No | Callback: `(id: string) => null | TutorialCardProgress` | | `href` | `string` | Yes | - | -| `labels` | `TutorialCardLabels` | Yes | - | +| `labels` | `TutorialCardLabels` | Yes | `TutorialCardLabels` object | | `linkComponent` | `React.ComponentType<{` | No | - | -| `children` | `ReactNode` | Yes | - | -| `className` | `string` | No | - | | `href` | `string` | Yes | - | +| `tutorial` | `TutorialCardMeta` | Yes | `TutorialCardMeta` object | + +## Type Definitions + +### TutorialCardProgress + +```tsx +type TutorialCardProgress = { + completedCount: number + totalSections: number +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `completedCount` | `number` | Yes | - | +| `totalSections` | `number` | Yes | - | + +### TutorialCardMeta + +```tsx +type TutorialCardMeta = { + description: string + difficulty: "advanced" | "beginner" | "intermediate" + estimatedTime: string + id: string + sectionCount: number + tags: string[] + title: string +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `description` | `string` | Yes | - | +| `difficulty` | `"advanced" \| "beginner" \| "intermediate"` | Yes | `advanced`, `beginner`, `intermediate` | +| `estimatedTime` | `string` | Yes | - | +| `id` | `string` | Yes | - | +| `sectionCount` | `number` | Yes | - | +| `tags` | `string[]` | Yes | Array of `string` | +| `title` | `string` | Yes | - | + +### TutorialCardLabels + +```tsx +type TutorialCardLabels = { + completed: string + difficulty: Record + sectionsCount: string +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `completed` | `string` | Yes | - | +| `difficulty` | `Record<string, string>` | Yes | - | +| `sectionsCount` | `string` | Yes | - | diff --git a/packages/ui/src/components/tutorial-complete/tutorial-complete.mdx b/packages/ui/src/components/tutorial-complete/tutorial-complete.mdx index c91481b..b3cfb20 100644 --- a/packages/ui/src/components/tutorial-complete/tutorial-complete.mdx +++ b/packages/ui/src/components/tutorial-complete/tutorial-complete.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './tutorial-complete.stories' @@ -21,7 +21,25 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/tutorial-complete.json import { TutorialComplete } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx + console.log(index)} + onRestart={() => {}} + imageSource="value" + socialLinks={socialLinks} + shareUrl="/example" + title="My Title" +/> +``` + + + +## API Reference @@ -30,9 +48,82 @@ import { TutorialComplete } from '@vllnt/ui' | `backHref` | `string` | Yes | - | | `completedSections` | `Set<string>` | Yes | - | | `completionPercent` | `number` | Yes | - | -| `labels` | `TutorialCompleteLabels` | Yes | - | +| `labels` | `TutorialCompleteLabels` | Yes | `TutorialCompleteLabels` object | | `linkComponent` | `React.ComponentType<{` | No | - | -| `children` | `ReactNode` | Yes | - | -| `className` | `string` | No | - | | `href` | `string` | Yes | - | +| `onGoToSection` | `(index: number) => void` | Yes | Callback: `(index: number) => void` | +| `onRestart` | `() => void` | Yes | Callback function | +| `profile` | `{` | No | - | +| `imageSource` | `string` | Yes | - | +| `socialLinks` | `{ href: string; label: string }[]` | Yes | Array of `{ href: string; label: string }` | +| `relatedContent` | `TutorialCompleteRelatedContent[]` | Yes | Array of `TutorialCompleteRelatedContent` objects | +| `sections` | `TutorialCompleteSection[]` | Yes | Array of `TutorialCompleteSection` objects | +| `shareUrl` | `string` | Yes | - | +| `title` | `string` | Yes | - | + +## Type Definitions + +### TutorialCompleteSection + +```tsx +type TutorialCompleteSection = { + id: string + title: string +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `id` | `string` | Yes | - | +| `title` | `string` | Yes | - | + +### TutorialCompleteRelatedContent + +```tsx +type TutorialCompleteRelatedContent = { + href: string + title: string + type: string +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `href` | `string` | Yes | - | +| `title` | `string` | Yes | - | +| `type` | `string` | Yes | - | + +### TutorialCompleteLabels + +```tsx +type TutorialCompleteLabels = { + backToTutorials: string + profileName: string + profileTagline: string + relatedContent: string + reviewSections: string + shareOn: string + shareTitle: string + startOver: string + tutorialComplete: string + tutorialFinished: string + youveCompletedAll: string + youveFinishedWith: string +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `backToTutorials` | `string` | Yes | - | +| `profileName` | `string` | Yes | - | +| `profileTagline` | `string` | Yes | - | +| `relatedContent` | `string` | Yes | - | +| `reviewSections` | `string` | Yes | - | +| `shareOn` | `string` | Yes | - | +| `shareTitle` | `string` | Yes | - | +| `startOver` | `string` | Yes | - | +| `tutorialComplete` | `string` | Yes | - | +| `tutorialFinished` | `string` | Yes | - | +| `youveCompletedAll` | `string` | Yes | - | +| `youveFinishedWith` | `string` | Yes | - | diff --git a/packages/ui/src/components/tutorial-filters/tutorial-filters.mdx b/packages/ui/src/components/tutorial-filters/tutorial-filters.mdx index b9a4274..7bedd87 100644 --- a/packages/ui/src/components/tutorial-filters/tutorial-filters.mdx +++ b/packages/ui/src/components/tutorial-filters/tutorial-filters.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './tutorial-filters.stories' @@ -21,18 +21,77 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/tutorial-filters.json import { TutorialFilters } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx + console.log(updates)} + searchQuery="value" +/> +``` + + + +## API Reference | Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | | `currentDifficulty` | `string` | Yes | - | -| `currentTags` | `string[]` | Yes | - | -| `difficultyOptions` | `string[]` | No | - | -| `isPending` | `boolean` | No | - | -| `labels` | `TutorialFiltersLabels` | Yes | - | -| `onFilterChange` | `(updates: FilterUpdates) => void` | Yes | - | +| `currentTags` | `string[]` | Yes | Array of `string` | +| `difficultyOptions` | `string[]` | No | Array of `string` | +| `isPending` | `boolean` | No | `true` or `false` | +| `labels` | `TutorialFiltersLabels` | Yes | `TutorialFiltersLabels` object | +| `onFilterChange` | `(updates: FilterUpdates) => void` | Yes | Callback: `(updates: FilterUpdates) => void` | | `searchQuery` | `string` | Yes | - | -| `tags` | `string[]` | Yes | - | +| `tags` | `string[]` | Yes | Array of `string` | + +## Type Definitions + +### TutorialFiltersLabels + +```tsx +type TutorialFiltersLabels = { + activeFilters: string + clear: string + clearAll: string + difficulty: Record + difficultyLabel: string + searchFilter: string + searchLabel: string + searchPlaceholder: string + tagsLabel: string +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `activeFilters` | `string` | Yes | - | +| `clear` | `string` | Yes | - | +| `clearAll` | `string` | Yes | - | +| `difficulty` | `Record<string, string>` | Yes | - | +| `difficultyLabel` | `string` | Yes | - | +| `searchFilter` | `string` | Yes | - | +| `searchLabel` | `string` | Yes | - | +| `searchPlaceholder` | `string` | Yes | - | +| `tagsLabel` | `string` | Yes | - | + +### FilterUpdates + +```tsx +type FilterUpdates = { + difficulty?: string + search?: string + tags?: string[] +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `difficulty` | `string` | No | - | +| `search` | `string` | No | - | +| `tags` | `string[]` | No | Array of `string` | diff --git a/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.mdx b/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.mdx index f7b8292..00cbe70 100644 --- a/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.mdx +++ b/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './tutorial-intro-content.stories' @@ -21,13 +21,25 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/tutorial-intro-content.json import { TutorialIntroContent } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx + + TutorialIntroContent content + +``` + + + +## API Reference | Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | -| `className` | `string` | No | - | | `content` | `string` | Yes | - | | `title` | `string` | Yes | - | diff --git a/packages/ui/src/components/tutorial-mdx/tutorial-mdx.mdx b/packages/ui/src/components/tutorial-mdx/tutorial-mdx.mdx index d5446c5..adde829 100644 --- a/packages/ui/src/components/tutorial-mdx/tutorial-mdx.mdx +++ b/packages/ui/src/components/tutorial-mdx/tutorial-mdx.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './tutorial-mdx.stories' @@ -21,12 +21,39 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/tutorial-mdx.json import { TutorialMDX } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx + + TutorialMdx content + +``` + + + +## API Reference | Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | +| `content` | `string` | Yes | - | + +## Type Definitions + +### TutorialMDXProps + +```tsx +type TutorialMDXProps = { + className?: string + content: string +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | | `className` | `string` | No | - | | `content` | `string` | Yes | - | diff --git a/packages/ui/src/components/video-embed/video-embed.mdx b/packages/ui/src/components/video-embed/video-embed.mdx index 03263d8..fba3a7d 100644 --- a/packages/ui/src/components/video-embed/video-embed.mdx +++ b/packages/ui/src/components/video-embed/video-embed.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './video-embed.stories' @@ -21,15 +21,26 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/video-embed.json import { VideoEmbed } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx + +``` + + + +## API Reference | Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | -| `aspectRatio` | `"1/1" \| "4/3" \| "16/9"` | No | - | +| `aspectRatio` | `"1/1" \| "4/3" \| "16/9"` | No | `1/1`, `4/3`, `16/9` | | `src` | `string` | Yes | - | | `thumbnail` | `string` | No | - | | `title` | `string` | Yes | - | -| `type` | `"custom" \| "vimeo" \| "youtube"` | No | - | +| `type` | `"custom" \| "vimeo" \| "youtube"` | No | `custom`, `vimeo`, `youtube` | diff --git a/packages/ui/src/components/view-switcher/view-switcher.mdx b/packages/ui/src/components/view-switcher/view-switcher.mdx index 24fe63e..4bd52d1 100644 --- a/packages/ui/src/components/view-switcher/view-switcher.mdx +++ b/packages/ui/src/components/view-switcher/view-switcher.mdx @@ -1,4 +1,4 @@ -import { Meta, Primary, Controls, Story, Canvas } from '@storybook/addon-docs/blocks' +import { Meta, Primary, Controls, Story, Canvas, Source } from '@storybook/addon-docs/blocks' import * as Stories from './view-switcher.stories' @@ -21,14 +21,46 @@ pnpm dlx shadcn@latest add https://ui.vllnt.com/r/view-switcher.json import { ViewSwitcher } from '@vllnt/ui' ``` -## Props +## Usage + +```tsx +const options = [ + { + key: "value", + label: "Example item", + }, +] + + +``` + + + +## API Reference | Prop | Type | Required | Description | | ---- | ---- | -------- | ----------- | -| `className` | `string` | No | - | | `defaultKey` | `string` | No | - | -| `options` | `ViewOption[]` | Yes | - | +| `options` | `ViewOption[]` | Yes | Array of `ViewOption` objects | | `paramName` | `string` | No | - | +## Type Definitions + +### ViewOption + +```tsx +type ViewOption = { + key: string + label: string +} +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `key` | `string` | Yes | - | +| `label` | `string` | Yes | - | + From bc7872c5cde627bb4fe9353df37b2879095034e7 Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 11 Mar 2026 21:13:55 +0100 Subject: [PATCH 11/26] fix(storybook): add remark-gfm for markdown table support in MDX docs MDX uses @mdx-js/mdx which doesn't support GFM pipe tables by default. Add remark-gfm plugin to addon-docs mdxCompileOptions so all markdown tables in .mdx files render as proper HTML tables. --- packages/ui/.storybook/main.ts | 12 +- packages/ui/package.json | 1 + pnpm-lock.yaml | 195 +++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+), 1 deletion(-) diff --git a/packages/ui/.storybook/main.ts b/packages/ui/.storybook/main.ts index fb3dc38..aca850e 100644 --- a/packages/ui/.storybook/main.ts +++ b/packages/ui/.storybook/main.ts @@ -2,6 +2,7 @@ import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { defineMain } from '@storybook/react-vite/node' +import remarkGfm from 'remark-gfm' const __dirname = dirname(fileURLToPath(import.meta.url)) @@ -12,7 +13,16 @@ export default defineMain({ addons: [ '@storybook/addon-a11y', - '@storybook/addon-docs', + { + name: '@storybook/addon-docs', + options: { + mdxPluginOptions: { + mdxCompileOptions: { + remarkPlugins: [remarkGfm], + }, + }, + }, + }, '@storybook/addon-themes', '@storybook/addon-designs', '@storybook/addon-mcp', diff --git a/packages/ui/package.json b/packages/ui/package.json index 2ebe0aa..2696031 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -167,6 +167,7 @@ "jsdom": "^26.1.0", "playwright": "^1.57.0", "postcss": "^8.5.6", + "remark-gfm": "^4.0.1", "storybook": "^10.2.17", "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8f9ee3..c0e245f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -316,6 +316,9 @@ importers: postcss: specifier: ^8.5.6 version: 8.5.6 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 storybook: specifier: ^10.2.17 version: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -5462,13 +5465,37 @@ packages: resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} engines: {node: '>=16'} + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + mdast-util-from-markdown@2.0.2: resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + mdast-util-mdx-expression@2.0.1: resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} @@ -5511,6 +5538,27 @@ packages: micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + micromark-extension-mdx-expression@3.0.1: resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} @@ -6269,6 +6317,9 @@ packages: resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==} engines: {node: '>=4'} + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + remark-mdx@3.1.1: resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} @@ -6278,6 +6329,9 @@ packages: remark-rehype@11.1.2: resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -12952,8 +13006,17 @@ snapshots: markdown-extensions@2.0.0: {} + markdown-table@3.0.4: {} + math-intrinsics@1.1.0: {} + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + mdast-util-from-markdown@2.0.2: dependencies: '@types/mdast': 4.0.4 @@ -12971,6 +13034,63 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + mdast-util-mdx-expression@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 @@ -13080,6 +13200,64 @@ snapshots: micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + micromark-extension-mdx-expression@3.0.1: dependencies: '@types/estree': 1.0.8 @@ -14000,6 +14178,17 @@ snapshots: dependencies: es6-error: 4.1.1 + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + remark-mdx@3.1.1: dependencies: mdast-util-mdx: 3.0.0 @@ -14024,6 +14213,12 @@ snapshots: unified: 11.0.5 vfile: 6.0.3 + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + require-directory@2.1.1: {} require-from-string@2.0.2: {} From 21324973aecc06774f24167a25c27dca43206860 Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 11 Mar 2026 21:36:12 +0100 Subject: [PATCH 12/26] fix(storybook): add required props to 28 stories preventing runtime crashes Stories with missing required props (arrays, callbacks, objects) caused t.tags and other runtime errors. Added verify-stories.ts script for automated crash-risk detection across all 99 components. --- packages/ui/package.json | 2 + packages/ui/scripts/fix-stories.ts | 300 ++++++++++++++++++ packages/ui/scripts/verify-stories.ts | 204 ++++++++++++ .../blog-card/blog-card.stories.tsx | 9 + .../breadcrumb/breadcrumb.stories.tsx | 5 + .../category-filter.stories.tsx | 3 + .../components/chart/area-chart.stories.tsx | 10 + .../checklist/checklist.stories.tsx | 5 +- .../comparison/comparison.stories.tsx | 13 +- .../completion-dialog.stories.tsx | 7 + .../content-intro/content-intro.stories.tsx | 12 + .../filter-bar/filter-bar.stories.tsx | 9 + .../floating-action-button.stories.tsx | 3 + .../inline-input/inline-input.stories.tsx | 5 + .../keyboard-shortcuts-help.stories.tsx | 9 + .../learning-objectives.stories.tsx | 1 + .../model-selector/model-selector.stories.tsx | 22 ++ .../profile-section.stories.tsx | 7 + .../ui/src/components/quiz/quiz.stories.tsx | 4 +- .../search-dialog/search-dialog.stories.tsx | 8 + .../share-dialog/share-dialog.stories.tsx | 7 + .../sidebar-toggle/sidebar-toggle.stories.tsx | 3 + .../slideshow/slideshow.stories.tsx | 15 + .../social-fab/social-fab.stories.tsx | 10 + .../step-navigation.stories.tsx | 8 + .../table-of-contents-panel.stories.tsx | 13 + .../table-of-contents.stories.tsx | 3 + .../components/terminal/terminal.stories.tsx | 6 + .../tutorial-card/tutorial-card.stories.tsx | 26 ++ .../tutorial-complete.stories.tsx | 9 +- .../tutorial-filters.stories.tsx | 4 +- 31 files changed, 732 insertions(+), 10 deletions(-) create mode 100644 packages/ui/scripts/fix-stories.ts create mode 100644 packages/ui/scripts/verify-stories.ts diff --git a/packages/ui/package.json b/packages/ui/package.json index 2696031..f31c157 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -83,6 +83,8 @@ "test-storybook": "test-storybook", "storybook:generate": "tsx scripts/generate-stories.ts", "storybook:generate-docs": "tsx scripts/generate-docs.ts", + "storybook:verify": "tsx scripts/verify-stories.ts", + "storybook:fix-stories": "tsx scripts/fix-stories.ts", "check:stories": "tsx scripts/check-story-coverage.ts" }, "peerDependencies": { diff --git a/packages/ui/scripts/fix-stories.ts b/packages/ui/scripts/fix-stories.ts new file mode 100644 index 0000000..238a0d4 --- /dev/null +++ b/packages/ui/scripts/fix-stories.ts @@ -0,0 +1,300 @@ +/** + * Story Fixer Script + * + * Analyzes component source to extract required props and their types, + * then patches .stories.tsx files with proper default args. + * + * Usage: pnpm -F @vllnt/ui storybook:fix-stories [--dry-run] + */ + +import { existsSync, readdirSync, readFileSync, statSync, writeFileSync } from 'fs' +import { basename, dirname, join } from 'path' +import { fileURLToPath } from 'url' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) +const COMPONENTS_DIR = join(__dirname, '../src/components') + +interface PropInfo { + name: string + type: string + required: boolean +} + +interface TypeDef { + name: string + fields: PropInfo[] +} + +function extractTypeBlock(source: string, startIndex: number): string { + let depth = 0 + let blockStart = -1 + for (let i = startIndex; i < source.length; i++) { + if (source[i] === '{') { + if (depth === 0) blockStart = i + 1 + depth++ + } + if (source[i] === '}') { + depth-- + if (depth === 0) return source.slice(blockStart, i) + } + } + return '' +} + +function parsePropsFromBlock(block: string): PropInfo[] { + const props: PropInfo[] = [] + for (const line of block.split('\n')) { + const trimmed = line.trim() + if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('/*')) continue + const m = trimmed.match(/^(\w+)(\??)\s*:\s*(.+?)\s*;?\s*$/) + if (m?.[1] && m[3]) { + props.push({ name: m[1], type: m[3].replace(/[;,]$/, '').trim(), required: m[2] !== '?' }) + } + } + return props +} + +function extractAllTypes(source: string): TypeDef[] { + const types: TypeDef[] = [] + const re = /(?:export\s+)?type\s+(\w+)\s*=\s*\{/g + let m + while ((m = re.exec(source)) !== null) { + if (!m[1]) continue + const block = extractTypeBlock(source, m.index + m[0].length - 1) + if (block) types.push({ name: m[1], fields: parsePropsFromBlock(block) }) + } + return types +} + +function toPascalCase(str: string): string { + return str.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join('') +} + +function generateValue(prop: PropInfo, allTypes: TypeDef[], indent: number): string { + const pad = ' '.repeat(indent) + const t = prop.type.trim() + + if (t.includes('=>') || t.startsWith('(')) { + const argsMatch = t.match(/\(([^)]*)\)/) + if (argsMatch?.[1]) { + const params = argsMatch[1].trim() + if (params === '') return '() => {}' + return `(${params.split(',').map((p) => p.split(':')[0]?.trim() ?? '_').join(', ')}) => {}` + } + return '() => {}' + } + + if (t === 'boolean') return 'false' + if (t === 'number') return '0' + if (t === 'string') { + if (prop.name.includes('title') || prop.name.includes('Title')) return '"Example Title"' + if (prop.name.includes('label') || prop.name.includes('Label')) return '"Label"' + if (prop.name.includes('question')) return '"What is this?"' + if (prop.name.includes('description')) return '"A description"' + if (prop.name.includes('href') || prop.name.includes('url') || prop.name.includes('Url')) return '"#"' + if (prop.name.includes('id') || prop.name.includes('Id')) return '"1"' + if (prop.name.includes('query') || prop.name.includes('Query')) return '""' + if (prop.name.includes('lang')) return '"en"' + return `"${prop.name}"` + } + if (t === 'ReactNode' || t === 'React.ReactNode') return '"Content"' + + if (t.startsWith('Set<')) return 'new Set()' + + if (t === 'string[]') return '["example"]' + if (t.startsWith('readonly ') && t.endsWith('[]')) { + const itemType = t.replace(/^readonly\s+/, '').replace(/\[\]$/, '') + return generateArrayValue(itemType, allTypes, indent) + } + if (t.endsWith('[]')) { + const itemType = t.replace(/\[\]$/, '') + return generateArrayValue(itemType, allTypes, indent) + } + + if (t.includes('|')) { + const parts = t.split('|').map((p) => p.trim()) + const stringLiteral = parts.find((p) => p.startsWith('"') || p.startsWith("'")) + if (stringLiteral) return stringLiteral + const first = parts[0] ?? '' + if (first === 'string') return '""' + if (first === 'number') return '0' + if (first === 'boolean') return 'false' + return '""' + } + + const typeDef = allTypes.find((td) => td.name === t) + if (typeDef) return generateObjectValue(typeDef, allTypes, indent) + + if (/^[A-Z]/.test(t)) { + return `{} as ${t}` + } + + return '""' +} + +function generateArrayValue(itemType: string, allTypes: TypeDef[], indent: number): string { + const pad = ' '.repeat(indent) + const typeDef = allTypes.find((td) => td.name === itemType) + if (typeDef) { + const objVal = generateObjectValue(typeDef, allTypes, indent + 2) + return `[${objVal}]` + } + if (itemType === 'string') return '["example"]' + if (itemType === 'number') return '[0]' + return '[]' +} + +function generateObjectValue(typeDef: TypeDef, allTypes: TypeDef[], indent: number): string { + const pad = ' '.repeat(indent) + const innerPad = ' '.repeat(indent + 2) + const fields: string[] = [] + + for (const field of typeDef.fields) { + if (!field.required && field.name !== 'id' && field.name !== 'label' && field.name !== 'title' && field.name !== 'name') continue + const val = generateValue(field, allTypes, indent + 2) + fields.push(`${innerPad}${field.name}: ${val},`) + } + + if (fields.length === 0) { + for (const field of typeDef.fields.slice(0, 3)) { + const val = generateValue(field, allTypes, indent + 2) + fields.push(`${innerPad}${field.name}: ${val},`) + } + } + + return `{\n${fields.join('\n')}\n${pad}}` +} + +function extractRequiredProps(source: string, componentName: string): PropInfo[] { + const patterns = [ + new RegExp(`(?:export\\s+)?(?:type|interface)\\s+${componentName}Props\\s*=?\\s*\\{`, 's'), + /(?:export\s+)?(?:type|interface)\s+\w*Props\s*=?\s*\{/s, + ] + + for (const pattern of patterns) { + const match = source.match(pattern) + if (match?.index !== undefined) { + const block = extractTypeBlock(source, match.index + match[0].length - 1) + if (block) { + return parsePropsFromBlock(block).filter( + (p) => p.required && !['className', 'ref', 'key', 'style', 'children'].includes(p.name) + ) + } + } + } + + return [] +} + +function extractStoryArgs(storySource: string): Set { + const args = new Set() + const metaArgs = storySource.match(/(?:^|\n)\s*args\s*:\s*\{([^}]*)\}/s) + if (metaArgs?.[1]) { + for (const k of metaArgs[1].matchAll(/(\w+)\s*:/g)) { + if (k[1]) args.add(k[1]) + } + } + return args +} + +function isCrashRisk(prop: PropInfo): boolean { + const t = prop.type.trim() + if (t.endsWith('[]') || t.startsWith('Array<') || t.startsWith('readonly ')) return true + if (t.includes('=>')) return true + if (t.startsWith('Set<')) return true + if (/^[A-Z]/.test(t) && !['ReactNode', 'React.ReactNode'].includes(t)) return true + return false +} + +function patchStory(storySource: string, argsToAdd: Record): string { + const argEntries = Object.entries(argsToAdd) + if (argEntries.length === 0) return storySource + + const argsBlock = argEntries.map(([k, v]) => ` ${k}: ${v},`).join('\n') + + const metaArgsMatch = storySource.match(/(args\s*:\s*\{)([^}]*)(})/s) + if (metaArgsMatch) { + const existing = metaArgsMatch[2] ?? '' + const newArgs = existing.trimEnd() + '\n' + argsBlock + '\n ' + return storySource.replace(metaArgsMatch[0], `${metaArgsMatch[1]}${newArgs}${metaArgsMatch[3]}`) + } + + const metaMatch = storySource.match(/(const\s+meta\s*=\s*\{)\s*\n/) + if (metaMatch?.index !== undefined) { + const insertPos = metaMatch.index + metaMatch[0].length + const argsInsert = ` args: {\n${argsBlock}\n },\n` + return storySource.slice(0, insertPos) + argsInsert + storySource.slice(insertPos) + } + + return storySource +} + +function main(): void { + const dryRun = process.argv.includes('--dry-run') + let fixed = 0 + let skipped = 0 + + const componentDirs = readdirSync(COMPONENTS_DIR).filter((dir) => + statSync(join(COMPONENTS_DIR, dir)).isDirectory() + ) + + for (const dir of componentDirs) { + const dirPath = join(COMPONENTS_DIR, dir) + const name = toPascalCase(dir) + const files = readdirSync(dirPath) + const mainFile = files.find((f) => f === `${dir}.tsx`) ?? files.find((f) => + f.endsWith('.tsx') && !f.includes('.test.') && !f.includes('.visual.') && !f.includes('.stories.') + ) + const storyFileName = files.find((f) => f.endsWith('.stories.tsx')) + if (!mainFile || !storyFileName) continue + + const source = readFileSync(join(dirPath, mainFile), 'utf-8') + const storyPath = join(dirPath, storyFileName) + const storySource = readFileSync(storyPath, 'utf-8') + const allTypes = extractAllTypes(source) + const requiredProps = extractRequiredProps(source, name) + const providedArgs = extractStoryArgs(storySource) + + const missing = requiredProps.filter((p) => !providedArgs.has(p.name) && isCrashRisk(p)) + + if (missing.length === 0) { + skipped++ + continue + } + + const argsToAdd: Record = {} + for (const prop of missing) { + argsToAdd[prop.name] = generateValue(prop, allTypes, 4) + } + + if (dryRun) { + console.log(` WOULD FIX ${name}:`) + for (const [k, v] of Object.entries(argsToAdd)) { + console.log(` + ${k}: ${v}`) + } + fixed++ + continue + } + + const patched = patchStory(storySource, argsToAdd) + + let cleanedArgs = storySource.match(/args\s*:\s*\{[^}]*children\s*:\s*"[^"]*"[^}]*\}/s) + let finalSource = patched + if (cleanedArgs) { + const childrenPropInComponent = requiredProps.some((p) => p.name === 'children') || + source.includes('{children}') + if (!childrenPropInComponent) { + finalSource = finalSource.replace(/\s*children\s*:\s*"[^"]*",?\n?/g, '\n') + } + } + + writeFileSync(storyPath, finalSource) + console.log(` FIXED ${name}: added ${Object.keys(argsToAdd).join(', ')}`) + fixed++ + } + + console.log(`\nSummary: ${fixed} fixed, ${skipped} ok`) +} + +main() diff --git a/packages/ui/scripts/verify-stories.ts b/packages/ui/scripts/verify-stories.ts new file mode 100644 index 0000000..6a9cec9 --- /dev/null +++ b/packages/ui/scripts/verify-stories.ts @@ -0,0 +1,204 @@ +/** + * Story Verification Script + * + * Validates that all .stories.tsx files provide required props in their Default story. + * Catches runtime crashes before they reach the browser. + * + * Usage: pnpm -F @vllnt/ui storybook:verify + */ + +import { readdirSync, readFileSync, statSync } from 'fs' +import { basename, dirname, join } from 'path' +import { fileURLToPath } from 'url' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) +const COMPONENTS_DIR = join(__dirname, '../src/components') + +interface PropInfo { + name: string + type: string + required: boolean +} + +interface Violation { + component: string + story: string + missingProps: string[] + crashRisk: string +} + +function extractTypeBlock(source: string, startIndex: number): string { + let depth = 0 + let blockStart = -1 + for (let i = startIndex; i < source.length; i++) { + if (source[i] === '{') { + if (depth === 0) blockStart = i + 1 + depth++ + } + if (source[i] === '}') { + depth-- + if (depth === 0) return source.slice(blockStart, i) + } + } + return '' +} + +function parsePropsFromBlock(block: string): PropInfo[] { + const props: PropInfo[] = [] + const lines = block.split('\n') + + for (const line of lines) { + const trimmed = line.trim() + if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('/*')) continue + const m = trimmed.match(/^(\w+)(\??)\s*:\s*(.+?)\s*;?\s*$/) + if (m) { + const name = m[1] ?? '' + const required = m[2] !== '?' + const type = (m[3] ?? '').trim().replace(/[;,]$/, '') + if (name && type) props.push({ name, type, required }) + } + } + + return props +} + +function toPascalCase(str: string): string { + return str.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join('') +} + +function extractRequiredProps(source: string, componentName: string): PropInfo[] { + const patterns = [ + new RegExp(`(?:export\\s+)?(?:type|interface)\\s+${componentName}Props\\s*=?\\s*\\{`, 's'), + /(?:export\s+)?(?:type|interface)\s+\w*Props\s*=?\s*\{/s, + ] + + for (const pattern of patterns) { + const match = source.match(pattern) + if (match?.index !== undefined) { + const block = extractTypeBlock(source, match.index + match[0].length - 1) + if (block) { + return parsePropsFromBlock(block).filter( + (p) => p.required && !['className', 'ref', 'key', 'style'].includes(p.name) + ) + } + } + } + + return [] +} + +function extractArgsBlock(source: string): string { + const argsMatch = source.match(/\bargs\s*:\s*\{/) + if (!argsMatch?.index) return '' + const start = argsMatch.index + argsMatch[0].length + let depth = 1 + for (let i = start; i < source.length; i++) { + if (source[i] === '{') depth++ + if (source[i] === '}') { + depth-- + if (depth === 0) return source.slice(start, i) + } + } + return '' +} + +function extractTopLevelKeys(block: string): Set { + const keys = new Set() + let depth = 0 + let i = 0 + while (i < block.length) { + if (block[i] === '{' || block[i] === '[' || block[i] === '(') { depth++; i++; continue } + if (block[i] === '}' || block[i] === ']' || block[i] === ')') { depth--; i++; continue } + if (depth === 0) { + const m = block.slice(i).match(/^(\w+)\s*:/) + if (m?.[1]) { + keys.add(m[1]) + i += m[0].length + continue + } + } + i++ + } + return keys +} + +function extractStoryArgs(storySource: string): Set { + const metaBlock = extractArgsBlock(storySource) + return extractTopLevelKeys(metaBlock) +} + +function classifyCrashRisk(prop: PropInfo): string { + const t = prop.type.trim() + if (t.endsWith('[]') || t.startsWith('Array<') || t.startsWith('readonly ')) return 'CRASH: .map()/.length on undefined' + if (t.includes('=>')) return 'CRASH: callback invocation on undefined' + if (t.startsWith('Set<')) return 'CRASH: .has()/.size on undefined' + if (/^[A-Z]/.test(t) && !['ReactNode', 'React.ReactNode'].includes(t)) return 'CRASH: property access on undefined object' + if (t === 'string' || t === 'number') return 'WARN: renders undefined text' + if (t === 'boolean') return 'WARN: falsy default may hide component' + return 'WARN: missing required prop' +} + +function verify(): void { + const violations: Violation[] = [] + let checked = 0 + + const componentDirs = readdirSync(COMPONENTS_DIR).filter((dir) => { + return statSync(join(COMPONENTS_DIR, dir)).isDirectory() + }) + + for (const dir of componentDirs) { + const dirPath = join(COMPONENTS_DIR, dir) + const name = toPascalCase(dir) + + const files = readdirSync(dirPath) + const mainFile = files.find((f) => f === `${dir}.tsx`) ?? files.find((f) => f.endsWith('.tsx') && !f.includes('.test.') && !f.includes('.visual.') && !f.includes('.stories.')) + const storyFile = files.find((f) => f.endsWith('.stories.tsx')) + + if (!mainFile || !storyFile) continue + checked++ + + const source = readFileSync(join(dirPath, mainFile), 'utf-8') + const storySource = readFileSync(join(dirPath, storyFile), 'utf-8') + + const requiredProps = extractRequiredProps(source, name) + const providedArgs = extractStoryArgs(storySource) + + const missing = requiredProps.filter((p) => !providedArgs.has(p.name)) + + if (missing.length > 0) { + const crashProps = missing.filter((p) => classifyCrashRisk(p).startsWith('CRASH')) + if (crashProps.length > 0) { + violations.push({ + component: name, + story: `${dir}/${storyFile}`, + missingProps: crashProps.map((p) => `${p.name}: ${p.type}`), + crashRisk: crashProps.map((p) => classifyCrashRisk(p)).join('; '), + }) + } + } + } + + console.log(`\nStory Verification Report`) + console.log(`========================`) + console.log(`Checked: ${checked} components\n`) + + if (violations.length === 0) { + console.log('All stories provide required props. No crash risks detected.') + process.exit(0) + } + + console.log(`Found ${violations.length} stories with missing required props:\n`) + + for (const v of violations) { + console.log(` FAIL ${v.component}`) + for (const prop of v.missingProps) { + console.log(` missing: ${prop}`) + } + console.log('') + } + + process.exit(1) +} + +verify() diff --git a/packages/ui/src/components/blog-card/blog-card.stories.tsx b/packages/ui/src/components/blog-card/blog-card.stories.tsx index 047fe50..385c037 100644 --- a/packages/ui/src/components/blog-card/blog-card.stories.tsx +++ b/packages/ui/src/components/blog-card/blog-card.stories.tsx @@ -3,6 +3,15 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { BlogCard } from "./blog-card"; const meta = { + args: { + href: "#", + post: { + description: "A short description of the blog post content.", + slug: "example-post", + tags: ["example"], + title: "Example Blog Post", + }, + }, component: BlogCard, title: "Content/BlogCard", } satisfies Meta; diff --git a/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx b/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx index 72e5335..08e5a93 100644 --- a/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx +++ b/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx @@ -3,6 +3,11 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { Breadcrumb } from "./breadcrumb"; const meta = { + args: { + items: [{ + label: "Content", + }], + }, component: Breadcrumb, title: "Navigation/Breadcrumb", } satisfies Meta; diff --git a/packages/ui/src/components/category-filter/category-filter.stories.tsx b/packages/ui/src/components/category-filter/category-filter.stories.tsx index 6b5e338..c3e6026 100644 --- a/packages/ui/src/components/category-filter/category-filter.stories.tsx +++ b/packages/ui/src/components/category-filter/category-filter.stories.tsx @@ -3,6 +3,9 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { CategoryFilter } from "./category-filter"; const meta = { + args: { + categories: ["example"], + }, component: CategoryFilter, title: "Form/CategoryFilter", } satisfies Meta; diff --git a/packages/ui/src/components/chart/area-chart.stories.tsx b/packages/ui/src/components/chart/area-chart.stories.tsx index 6217beb..5ace2c1 100644 --- a/packages/ui/src/components/chart/area-chart.stories.tsx +++ b/packages/ui/src/components/chart/area-chart.stories.tsx @@ -3,6 +3,16 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { AreaChart } from "./area-chart"; const meta = { + args: { + data: [ + { label: "Jan", value: 10 }, + { label: "Feb", value: 25 }, + { label: "Mar", value: 18 }, + { label: "Apr", value: 32 }, + ], + height: 200, + width: 400, + }, component: AreaChart, title: "Data/AreaChart", } satisfies Meta; diff --git a/packages/ui/src/components/checklist/checklist.stories.tsx b/packages/ui/src/components/checklist/checklist.stories.tsx index 14854bc..7193ddc 100644 --- a/packages/ui/src/components/checklist/checklist.stories.tsx +++ b/packages/ui/src/components/checklist/checklist.stories.tsx @@ -4,7 +4,10 @@ import { Checklist } from "./checklist"; const meta = { args: { - children: "Checklist", + items: [{ + id: "1", + label: "Label", + }], }, component: Checklist, title: "Learning/Checklist", diff --git a/packages/ui/src/components/comparison/comparison.stories.tsx b/packages/ui/src/components/comparison/comparison.stories.tsx index f5d7c5a..50cd19d 100644 --- a/packages/ui/src/components/comparison/comparison.stories.tsx +++ b/packages/ui/src/components/comparison/comparison.stories.tsx @@ -4,7 +4,18 @@ import { Comparison } from "./comparison"; const meta = { args: { - children: "Comparison", + after: { + items: ["example"], + title: "Example Title", + before: { + items: ["example"], + title: "Example Title", + }, + }, + before: { + items: ["example"], + title: "Example Title", + }, }, component: Comparison, title: "Data/Comparison", diff --git a/packages/ui/src/components/completion-dialog/completion-dialog.stories.tsx b/packages/ui/src/components/completion-dialog/completion-dialog.stories.tsx index d617901..911ae86 100644 --- a/packages/ui/src/components/completion-dialog/completion-dialog.stories.tsx +++ b/packages/ui/src/components/completion-dialog/completion-dialog.stories.tsx @@ -3,6 +3,13 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { CompletionDialog } from "./completion-dialog"; const meta = { + args: { + isOpen: true, + onCancel: () => {}, + onClose: () => {}, + onConfirm: () => {}, + title: "Congratulations!", + }, component: CompletionDialog, title: "Learning/CompletionDialog", } satisfies Meta; diff --git a/packages/ui/src/components/content-intro/content-intro.stories.tsx b/packages/ui/src/components/content-intro/content-intro.stories.tsx index e36eea3..898c333 100644 --- a/packages/ui/src/components/content-intro/content-intro.stories.tsx +++ b/packages/ui/src/components/content-intro/content-intro.stories.tsx @@ -3,6 +3,18 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { ContentIntro } from "./content-intro"; const meta = { + args: { + completedSections: new Set(), + estimatedTime: "10 min", + onGoToSection: () => {}, + onStart: () => {}, + renderIntroContent: () => "Welcome to this tutorial.", + sections: [ + { id: "intro", title: "Introduction" }, + { id: "basics", title: "Basics" }, + ], + title: "Getting Started", + }, component: ContentIntro, title: "Content/ContentIntro", } satisfies Meta; diff --git a/packages/ui/src/components/filter-bar/filter-bar.stories.tsx b/packages/ui/src/components/filter-bar/filter-bar.stories.tsx index 269c8a4..7e1ab01 100644 --- a/packages/ui/src/components/filter-bar/filter-bar.stories.tsx +++ b/packages/ui/src/components/filter-bar/filter-bar.stories.tsx @@ -3,6 +3,15 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { FilterBar } from "./filter-bar"; const meta = { + args: { + currentTags: ["example"], + difficultyOptions: [{ + label: "Label", + value: "value", + tags: ["example"], + }], + tags: ["example"], + }, component: FilterBar, title: "Form/FilterBar", } satisfies Meta; diff --git a/packages/ui/src/components/floating-action-button/floating-action-button.stories.tsx b/packages/ui/src/components/floating-action-button/floating-action-button.stories.tsx index a730124..473a836 100644 --- a/packages/ui/src/components/floating-action-button/floating-action-button.stories.tsx +++ b/packages/ui/src/components/floating-action-button/floating-action-button.stories.tsx @@ -3,6 +3,9 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { FloatingActionButton } from "./floating-action-button"; const meta = { + args: { + onClick: () => {}, + }, component: FloatingActionButton, title: "Utility/FloatingActionButton", } satisfies Meta; diff --git a/packages/ui/src/components/inline-input/inline-input.stories.tsx b/packages/ui/src/components/inline-input/inline-input.stories.tsx index c262150..95a9a1c 100644 --- a/packages/ui/src/components/inline-input/inline-input.stories.tsx +++ b/packages/ui/src/components/inline-input/inline-input.stories.tsx @@ -3,6 +3,11 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { InlineInput } from "./inline-input"; const meta = { + args: { + onChange: () => {}, + onCommit: () => {}, + value: "Edit me", + }, component: InlineInput, title: "Form/InlineInput", } satisfies Meta; diff --git a/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.stories.tsx b/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.stories.tsx index 46d8618..64c06a9 100644 --- a/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.stories.tsx +++ b/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.stories.tsx @@ -3,6 +3,15 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { KeyboardShortcutsHelp } from "./keyboard-shortcuts-help"; const meta = { + args: { + isOpen: true, + onClose: () => {}, + shortcuts: [ + { description: "Go to next section", keys: ["ArrowRight"] }, + { description: "Go to previous section", keys: ["ArrowLeft"] }, + { description: "Toggle completion", keys: ["Space"] }, + ], + }, component: KeyboardShortcutsHelp, title: "Learning/KeyboardShortcutsHelp", } satisfies Meta; diff --git a/packages/ui/src/components/learning-objectives/learning-objectives.stories.tsx b/packages/ui/src/components/learning-objectives/learning-objectives.stories.tsx index 49a4c12..3aece76 100644 --- a/packages/ui/src/components/learning-objectives/learning-objectives.stories.tsx +++ b/packages/ui/src/components/learning-objectives/learning-objectives.stories.tsx @@ -5,6 +5,7 @@ import { LearningObjectives } from "./learning-objectives"; const meta = { args: { children: "LearningObjectives", + objectives: ["example"], }, component: LearningObjectives, title: "Learning/LearningObjectives", diff --git a/packages/ui/src/components/model-selector/model-selector.stories.tsx b/packages/ui/src/components/model-selector/model-selector.stories.tsx index 37df7ab..5fc65d2 100644 --- a/packages/ui/src/components/model-selector/model-selector.stories.tsx +++ b/packages/ui/src/components/model-selector/model-selector.stories.tsx @@ -3,6 +3,28 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { ModelSelector } from "./model-selector"; const meta = { + args: { + models: [ + { + contextWindow: "200K", + description: "Most capable model", + id: "claude-opus-4-6", + name: "Claude Opus 4.6", + provider: "Anthropic", + }, + { + contextWindow: "200K", + description: "Balanced performance", + id: "claude-sonnet-4-6", + name: "Claude Sonnet 4.6", + provider: "Anthropic", + }, + ], + onOpenChange: () => {}, + onSelectModel: () => {}, + open: true, + selectedModelId: "claude-opus-4-6", + }, component: ModelSelector, title: "Form/ModelSelector", } satisfies Meta; diff --git a/packages/ui/src/components/profile-section/profile-section.stories.tsx b/packages/ui/src/components/profile-section/profile-section.stories.tsx index 4cc22f6..5eed1aa 100644 --- a/packages/ui/src/components/profile-section/profile-section.stories.tsx +++ b/packages/ui/src/components/profile-section/profile-section.stories.tsx @@ -3,6 +3,13 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { ProfileSection } from "./profile-section"; const meta = { + args: { + dict: { + profile: "", + name: "name", + tagline: "tagline", + }, + }, component: ProfileSection, title: "Learning/ProfileSection", } satisfies Meta; diff --git a/packages/ui/src/components/quiz/quiz.stories.tsx b/packages/ui/src/components/quiz/quiz.stories.tsx index eb9bbf5..43a7f7c 100644 --- a/packages/ui/src/components/quiz/quiz.stories.tsx +++ b/packages/ui/src/components/quiz/quiz.stories.tsx @@ -4,7 +4,9 @@ import { Quiz } from "./quiz"; const meta = { args: { - children: "Quiz", + options: [{ + label: "Label", + }], }, component: Quiz, title: "Learning/Quiz", diff --git a/packages/ui/src/components/search-dialog/search-dialog.stories.tsx b/packages/ui/src/components/search-dialog/search-dialog.stories.tsx index b293b09..ad86453 100644 --- a/packages/ui/src/components/search-dialog/search-dialog.stories.tsx +++ b/packages/ui/src/components/search-dialog/search-dialog.stories.tsx @@ -3,6 +3,14 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { SearchDialog } from "./search-dialog"; const meta = { + args: { + items: [{ + id: "1", + title: "Example Title", + onSelect: (item) => {}, + }], + onSelect: (item) => {}, + }, component: SearchDialog, title: "Learning/SearchDialog", } satisfies Meta; diff --git a/packages/ui/src/components/share-dialog/share-dialog.stories.tsx b/packages/ui/src/components/share-dialog/share-dialog.stories.tsx index 88a14f5..697c9db 100644 --- a/packages/ui/src/components/share-dialog/share-dialog.stories.tsx +++ b/packages/ui/src/components/share-dialog/share-dialog.stories.tsx @@ -3,6 +3,13 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { ShareDialog } from "./share-dialog"; const meta = { + args: { + platforms: [{ + buildUrl: (pageUrl, pageTitle) => {}, + key: "key", + label: "Label", + }], + }, component: ShareDialog, title: "Utility/ShareDialog", } satisfies Meta; diff --git a/packages/ui/src/components/sidebar-toggle/sidebar-toggle.stories.tsx b/packages/ui/src/components/sidebar-toggle/sidebar-toggle.stories.tsx index a22e898..d1e4b2b 100644 --- a/packages/ui/src/components/sidebar-toggle/sidebar-toggle.stories.tsx +++ b/packages/ui/src/components/sidebar-toggle/sidebar-toggle.stories.tsx @@ -3,6 +3,9 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { SidebarToggle } from "./sidebar-toggle"; const meta = { + args: { + onToggle: () => {}, + }, component: SidebarToggle, title: "Navigation/SidebarToggle", } satisfies Meta; diff --git a/packages/ui/src/components/slideshow/slideshow.stories.tsx b/packages/ui/src/components/slideshow/slideshow.stories.tsx index 46387b7..c321de5 100644 --- a/packages/ui/src/components/slideshow/slideshow.stories.tsx +++ b/packages/ui/src/components/slideshow/slideshow.stories.tsx @@ -3,6 +3,21 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { Slideshow } from "./slideshow"; const meta = { + args: { + completedSections: new Set(), + currentIndex: 0, + onComplete: () => {}, + onExit: () => {}, + onNavigate: () => {}, + onToggleSection: () => {}, + renderContent: () => "Slide content here.", + sections: [ + { id: "intro", title: "Introduction" }, + { id: "setup", title: "Setup" }, + { id: "advanced", title: "Advanced" }, + ], + title: "Tutorial Slideshow", + }, component: Slideshow, title: "Content/Slideshow", } satisfies Meta; diff --git a/packages/ui/src/components/social-fab/social-fab.stories.tsx b/packages/ui/src/components/social-fab/social-fab.stories.tsx index 37a05c1..4b7161f 100644 --- a/packages/ui/src/components/social-fab/social-fab.stories.tsx +++ b/packages/ui/src/components/social-fab/social-fab.stories.tsx @@ -3,6 +3,16 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { SocialFAB } from "./social-fab"; const meta = { + args: { + actions: [ + { id: "1", label: "Copy Link", onClick: () => {} }, + { id: "2", label: "Bookmark", onClick: () => {} }, + ], + labels: { + close: "Close", + share: "Share", + }, + }, component: SocialFAB, title: "Utility/SocialFab", } satisfies Meta; diff --git a/packages/ui/src/components/step-navigation/step-navigation.stories.tsx b/packages/ui/src/components/step-navigation/step-navigation.stories.tsx index 06994e4..c4b2d6e 100644 --- a/packages/ui/src/components/step-navigation/step-navigation.stories.tsx +++ b/packages/ui/src/components/step-navigation/step-navigation.stories.tsx @@ -3,6 +3,14 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { StepNavigation } from "./step-navigation"; const meta = { + args: { + canNext: true, + canPrev: true, + currentStep: 2, + onNext: () => {}, + onPrev: () => {}, + totalSteps: 5, + }, component: StepNavigation, title: "Navigation/StepNavigation", } satisfies Meta; diff --git a/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.stories.tsx b/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.stories.tsx index 660fcff..8543fda 100644 --- a/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.stories.tsx +++ b/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.stories.tsx @@ -3,6 +3,19 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { TableOfContentsPanel } from "./table-of-contents-panel"; const meta = { + args: { + completedSections: new Set(), + completionCount: 0, + currentSectionIndex: 0, + isOpen: true, + onClose: () => {}, + onSelectSection: () => {}, + sections: [ + { id: "intro", title: "Introduction" }, + { id: "basics", title: "Basics" }, + ], + totalSections: 2, + }, component: TableOfContentsPanel, title: "Utility/TableOfContentsPanel", } satisfies Meta; diff --git a/packages/ui/src/components/table-of-contents/table-of-contents.stories.tsx b/packages/ui/src/components/table-of-contents/table-of-contents.stories.tsx index 51272cd..5d65f7c 100644 --- a/packages/ui/src/components/table-of-contents/table-of-contents.stories.tsx +++ b/packages/ui/src/components/table-of-contents/table-of-contents.stories.tsx @@ -3,6 +3,9 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { TableOfContents } from "./table-of-contents"; const meta = { + args: { + sections: [], + }, component: TableOfContents, title: "Utility/TableOfContents", } satisfies Meta; diff --git a/packages/ui/src/components/terminal/terminal.stories.tsx b/packages/ui/src/components/terminal/terminal.stories.tsx index d91ba98..46d31f1 100644 --- a/packages/ui/src/components/terminal/terminal.stories.tsx +++ b/packages/ui/src/components/terminal/terminal.stories.tsx @@ -3,6 +3,12 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { Terminal } from "./terminal"; const meta = { + args: { + lines: [{ + content: "content", + type: "command", + }], + }, component: Terminal, title: "Content/Terminal", } satisfies Meta; diff --git a/packages/ui/src/components/tutorial-card/tutorial-card.stories.tsx b/packages/ui/src/components/tutorial-card/tutorial-card.stories.tsx index 1203148..84ab5de 100644 --- a/packages/ui/src/components/tutorial-card/tutorial-card.stories.tsx +++ b/packages/ui/src/components/tutorial-card/tutorial-card.stories.tsx @@ -3,6 +3,32 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { TutorialCard } from "./tutorial-card"; const meta = { + args: { + labels: { + completed: "completed", + difficulty: { + tutorial: { + description: "A description", + difficulty: "advanced", + estimatedTime: "estimatedTime", + id: "1", + sectionCount: 0, + tags: ["example"], + title: "Example Title", + }, + } as Record, + sectionsCount: "sectionsCount", + }, + tutorial: { + description: "A description", + difficulty: "advanced", + estimatedTime: "estimatedTime", + id: "1", + sectionCount: 0, + tags: ["example"], + title: "Example Title", + }, + }, component: TutorialCard, title: "Learning/TutorialCard", } satisfies Meta; diff --git a/packages/ui/src/components/tutorial-complete/tutorial-complete.stories.tsx b/packages/ui/src/components/tutorial-complete/tutorial-complete.stories.tsx index e12f0c8..8ff90a1 100644 --- a/packages/ui/src/components/tutorial-complete/tutorial-complete.stories.tsx +++ b/packages/ui/src/components/tutorial-complete/tutorial-complete.stories.tsx @@ -2,8 +2,6 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { TutorialComplete } from "./tutorial-complete"; -const noop = (): void => undefined; - const meta = { args: { backHref: "/tutorials", @@ -23,8 +21,8 @@ const meta = { youveCompletedAll: "You've completed all sections of", youveFinishedWith: "You've finished with", }, - onGoToSection: noop, - onRestart: noop, + onGoToSection: () => {}, + onRestart: () => {}, relatedContent: [ { href: "/next-tutorial", title: "Next Steps", type: "Tutorial" }, ], @@ -34,6 +32,9 @@ const meta = { { id: "advanced", title: "Advanced Concepts" }, ], shareUrl: "https://example.com/tutorial", + socialLinks: [ + { href: "https://twitter.com", label: "Twitter" }, + ], title: "React Fundamentals", }, component: TutorialComplete, diff --git a/packages/ui/src/components/tutorial-filters/tutorial-filters.stories.tsx b/packages/ui/src/components/tutorial-filters/tutorial-filters.stories.tsx index ce3559f..5f61cd0 100644 --- a/packages/ui/src/components/tutorial-filters/tutorial-filters.stories.tsx +++ b/packages/ui/src/components/tutorial-filters/tutorial-filters.stories.tsx @@ -2,8 +2,6 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { TutorialFilters } from "./tutorial-filters"; -const noop = (): void => undefined; - const meta = { args: { currentDifficulty: "all", @@ -24,7 +22,7 @@ const meta = { searchPlaceholder: "Search by title or keyword...", tagsLabel: "Topics", }, - onFilterChange: noop, + onFilterChange: () => {}, searchQuery: "", tags: ["React", "TypeScript", "Tailwind", "Components"], }, From e74eed1127d081af391b7acfe5e62d68a3edee81 Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 11 Mar 2026 21:38:29 +0100 Subject: [PATCH 13/26] feat(ci): add storybook E2E testing and visual regression workflows - New storybook.yml: story verification, build, test-runner, visual regression - CI now includes story coverage check, prop verification, and storybook build - test-runner config with a11y checks and console error detection - Playwright CT visual tests run as visual-regression job --- .github/workflows/ci.yml | 10 ++ .github/workflows/storybook.yml | 137 +++++++++++++++++++++++++ packages/ui/package.json | 2 +- packages/ui/test-runner-jest.config.ts | 41 ++++++++ 4 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/storybook.yml create mode 100644 packages/ui/test-runner-jest.config.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0eeddd5..0113030 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,3 +35,13 @@ jobs: - name: Test run: pnpm test:once + + - name: Verify stories + working-directory: packages/ui + run: | + npx tsx scripts/check-story-coverage.ts + npx tsx scripts/verify-stories.ts + + - name: Build Storybook + working-directory: packages/ui + run: pnpm build-storybook diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml new file mode 100644 index 0000000..7f89a5f --- /dev/null +++ b/.github/workflows/storybook.yml @@ -0,0 +1,137 @@ +name: Storybook + +on: + pull_request: + branches: [main] + paths: + - "packages/ui/src/**" + - "packages/ui/.storybook/**" + - "packages/ui/scripts/**" + - "packages/ui/styles.css" + - "packages/ui/themes/**" + - ".github/workflows/storybook.yml" + push: + branches: [main] + paths: + - "packages/ui/src/**" + - "packages/ui/.storybook/**" + +concurrency: + group: storybook-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + verify-stories: + name: Verify Stories + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - name: Check story coverage + working-directory: packages/ui + run: npx tsx scripts/check-story-coverage.ts + + - name: Verify story props + working-directory: packages/ui + run: npx tsx scripts/verify-stories.ts + + build-storybook: + name: Build Storybook + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - name: Build Storybook + working-directory: packages/ui + run: pnpm build-storybook + + - name: Upload Storybook artifact + uses: actions/upload-artifact@v4 + with: + name: storybook-static + path: packages/ui/storybook-static + retention-days: 7 + + test-storybook: + name: Storybook Tests + needs: build-storybook + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - name: Install Playwright browsers + run: npx playwright install --with-deps chromium + + - name: Download Storybook artifact + uses: actions/download-artifact@v4 + with: + name: storybook-static + path: packages/ui/storybook-static + + - name: Run Storybook test-runner + working-directory: packages/ui + run: | + npx http-server storybook-static --port 6006 --silent & + sleep 3 + npx test-storybook --url http://127.0.0.1:6006 --maxWorkers=2 + + visual-regression: + name: Visual Regression + needs: build-storybook + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - name: Install Playwright browsers + run: npx playwright install --with-deps chromium + + - name: Run Playwright CT visual tests + working-directory: packages/ui + run: pnpm test:visual + continue-on-error: true + + - name: Upload visual test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: visual-test-results + path: | + packages/ui/playwright-report + packages/ui/test-results + retention-days: 7 diff --git a/packages/ui/package.json b/packages/ui/package.json index f31c157..bb91828 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -80,7 +80,7 @@ "test:generate": "tsx scripts/generate-tests.ts", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", - "test-storybook": "test-storybook", + "test-storybook": "test-storybook --config-dir .storybook", "storybook:generate": "tsx scripts/generate-stories.ts", "storybook:generate-docs": "tsx scripts/generate-docs.ts", "storybook:verify": "tsx scripts/verify-stories.ts", diff --git a/packages/ui/test-runner-jest.config.ts b/packages/ui/test-runner-jest.config.ts new file mode 100644 index 0000000..8065f88 --- /dev/null +++ b/packages/ui/test-runner-jest.config.ts @@ -0,0 +1,41 @@ +import type { TestRunnerConfig } from "@storybook/test-runner"; + +const config: TestRunnerConfig = { + async postVisit(page, context) { + const a11yViolations = await page.evaluate(() => { + const errors: string[] = []; + const images = document.querySelectorAll("img:not([alt])"); + if (images.length > 0) { + errors.push(`${images.length} image(s) missing alt text`); + } + const buttons = document.querySelectorAll( + 'button:not([aria-label]):not(:has(*))', + ); + for (const btn of buttons) { + if (!btn.textContent?.trim()) { + errors.push("Button without text or aria-label"); + } + } + return errors; + }); + + if (a11yViolations.length > 0) { + throw new Error( + `Accessibility violations in ${context.id}:\n${a11yViolations.join("\n")}`, + ); + } + + const consoleErrors = await page.evaluate(() => { + return (window as unknown as { __STORYBOOK_CONSOLE_ERRORS__?: string[] }) + .__STORYBOOK_CONSOLE_ERRORS__ ?? []; + }); + + if (consoleErrors.length > 0) { + throw new Error( + `Console errors in ${context.id}:\n${consoleErrors.join("\n")}`, + ); + } + }, +}; + +export default config; From af27af6a44d9176df6bc2812d07168b9174dadfd Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 11 Mar 2026 21:59:04 +0100 Subject: [PATCH 14/26] feat(test): add unit tests and visual regression tests for all components - 37 unit tests (vitest + testing-library) covering simple components - 96 Playwright CT visual tests with baseline snapshots - 127 visual snapshot baselines for regression detection - Removed mdx-content visual test (async component, unmountable in CT) --- .../alert-dialog/alert-dialog.visual.tsx | 10 ++++ .../ui/src/components/alert/alert.test.tsx | 44 ++++++++++++++++ .../ui/src/components/alert/alert.visual.tsx | 15 ++++++ .../aspect-ratio/aspect-ratio.visual.tsx | 10 ++++ .../ui/src/components/avatar/avatar.test.tsx | 37 +++++++++++++ .../src/components/avatar/avatar.visual.tsx | 10 ++++ .../components/blog-card/blog-card.visual.tsx | 16 +++--- .../breadcrumb/breadcrumb.visual.tsx | 16 +++--- .../src/components/calendar/calendar.test.tsx | 29 +++++++++++ .../components/calendar/calendar.visual.tsx | 10 ++++ .../src/components/carousel/carousel.test.tsx | 37 +++++++++++++ .../components/carousel/carousel.visual.tsx | 10 ++++ .../category-filter.visual.tsx | 16 +++--- .../components/checklist/checklist.visual.tsx | 16 +++--- .../code-playground.visual.tsx | 16 +++--- .../collapsible/collapsible.test.tsx | 29 +++++++++++ .../collapsible/collapsible.visual.tsx | 10 ++++ .../comparison/comparison.visual.tsx | 16 +++--- .../completion-dialog.visual.tsx | 16 +++--- .../content-intro/content-intro.visual.tsx | 16 +++--- .../context-menu/context-menu.visual.tsx | 10 ++++ .../src/components/dialog/dialog.visual.tsx | 16 +++--- .../src/components/drawer/drawer.visual.tsx | 10 ++++ .../dropdown-menu/dropdown-menu.visual.tsx | 16 +++--- .../components/exercise/exercise.visual.tsx | 16 +++--- packages/ui/src/components/faq/faq.visual.tsx | 16 +++--- .../filter-bar/filter-bar.visual.tsx | 16 +++--- .../flow-diagram/flow-diagram.visual.tsx | 16 +++--- .../hover-card/hover-card.visual.tsx | 10 ++++ .../components/input-otp/input-otp.visual.tsx | 10 ++++ .../keyboard-shortcuts-help.visual.tsx | 16 +++--- .../ui/src/components/label/label.visual.tsx | 16 +++--- .../lang-provider/lang-provider.visual.tsx | 16 +++--- .../learning-objectives.visual.tsx | 16 +++--- .../src/components/menubar/menubar.test.tsx | 37 +++++++++++++ .../src/components/menubar/menubar.visual.tsx | 10 ++++ .../model-selector/model-selector.visual.tsx | 16 +++--- .../navbar-saas/navbar-saas.visual.tsx | 16 +++--- .../navigation-menu/navigation-menu.test.tsx | 37 +++++++++++++ .../navigation-menu.visual.tsx | 10 ++++ .../src/components/popover/popover.visual.tsx | 10 ++++ .../profile-section.visual.tsx | 16 +++--- .../progress-card/progress-card.visual.tsx | 16 +++--- .../ui/src/components/quiz/quiz.visual.tsx | 16 +++--- .../radio-group/radio-group.test.tsx | 37 +++++++++++++ .../radio-group/radio-group.visual.tsx | 10 ++++ .../components/resizable/resizable.visual.tsx | 10 ++++ .../scroll-area/scroll-area.test.tsx | 37 +++++++++++++ .../scroll-area/scroll-area.visual.tsx | 10 ++++ .../search-bar/search-bar.visual.tsx | 16 +++--- .../search-dialog/search-dialog.visual.tsx | 16 +++--- .../src/components/select/select.visual.tsx | 10 ++++ .../components/separator/separator.test.tsx | 37 +++++++++++++ .../components/separator/separator.visual.tsx | 10 ++++ .../share-dialog/share-dialog.visual.tsx | 16 +++--- .../share-section/share-section.visual.tsx | 16 +++--- .../ui/src/components/sheet/sheet.visual.tsx | 25 +++++++++ .../sidebar-provider.visual.tsx | 16 +++--- .../src/components/sidebar/sidebar.visual.tsx | 16 +++--- .../src/components/skeleton/skeleton.test.tsx | 29 +++++++++++ .../components/skeleton/skeleton.visual.tsx | 10 ++++ .../src/components/slider/slider.visual.tsx | 10 ++++ .../components/slideshow/slideshow.visual.tsx | 16 +++--- .../social-fab/social-fab.visual.tsx | 16 +++--- .../src/components/spinner/spinner.test.tsx | 29 +++++++++++ .../src/components/spinner/spinner.visual.tsx | 10 ++++ .../step-by-step/step-by-step.visual.tsx | 16 +++--- .../table-of-contents-panel.visual.tsx | 16 +++--- .../table-of-contents.visual.tsx | 16 +++--- .../ui/src/components/table/table.visual.tsx | 10 ++++ .../ui/src/components/tabs/tabs.visual.tsx | 16 +++--- .../components/terminal/terminal.visual.tsx | 16 +++--- .../src/components/textarea/textarea.test.tsx | 37 +++++++++++++ .../components/textarea/textarea.visual.tsx | 10 ++++ .../theme-provider/theme-provider.visual.tsx | 16 +++--- .../theme-toggle/theme-toggle.visual.tsx | 16 +++--- .../tldr-section/tldr-section.visual.tsx | 16 +++--- .../ui/src/components/toast/toast.visual.tsx | 24 ++++----- .../toggle-group/toggle-group.visual.tsx | 10 ++++ .../ui/src/components/toggle/toggle.test.tsx | 52 +++++++++++++++++++ .../src/components/toggle/toggle.visual.tsx | 25 +++++++++ .../src/components/tooltip/tooltip.visual.tsx | 10 ++++ .../tutorial-card/tutorial-card.visual.tsx | 16 +++--- .../tutorial-complete.visual.tsx | 16 +++--- .../tutorial-filters.visual.tsx | 16 +++--- .../tutorial-intro-content.visual.tsx | 16 +++--- .../tutorial-mdx/tutorial-mdx.visual.tsx | 16 +++--- .../video-embed/video-embed.visual.tsx | 16 +++--- 88 files changed, 1195 insertions(+), 372 deletions(-) create mode 100644 packages/ui/src/components/alert-dialog/alert-dialog.visual.tsx create mode 100644 packages/ui/src/components/alert/alert.test.tsx create mode 100644 packages/ui/src/components/alert/alert.visual.tsx create mode 100644 packages/ui/src/components/aspect-ratio/aspect-ratio.visual.tsx create mode 100644 packages/ui/src/components/avatar/avatar.test.tsx create mode 100644 packages/ui/src/components/avatar/avatar.visual.tsx create mode 100644 packages/ui/src/components/calendar/calendar.test.tsx create mode 100644 packages/ui/src/components/calendar/calendar.visual.tsx create mode 100644 packages/ui/src/components/carousel/carousel.test.tsx create mode 100644 packages/ui/src/components/carousel/carousel.visual.tsx create mode 100644 packages/ui/src/components/collapsible/collapsible.test.tsx create mode 100644 packages/ui/src/components/collapsible/collapsible.visual.tsx create mode 100644 packages/ui/src/components/context-menu/context-menu.visual.tsx create mode 100644 packages/ui/src/components/drawer/drawer.visual.tsx create mode 100644 packages/ui/src/components/hover-card/hover-card.visual.tsx create mode 100644 packages/ui/src/components/input-otp/input-otp.visual.tsx create mode 100644 packages/ui/src/components/menubar/menubar.test.tsx create mode 100644 packages/ui/src/components/menubar/menubar.visual.tsx create mode 100644 packages/ui/src/components/navigation-menu/navigation-menu.test.tsx create mode 100644 packages/ui/src/components/navigation-menu/navigation-menu.visual.tsx create mode 100644 packages/ui/src/components/popover/popover.visual.tsx create mode 100644 packages/ui/src/components/radio-group/radio-group.test.tsx create mode 100644 packages/ui/src/components/radio-group/radio-group.visual.tsx create mode 100644 packages/ui/src/components/resizable/resizable.visual.tsx create mode 100644 packages/ui/src/components/scroll-area/scroll-area.test.tsx create mode 100644 packages/ui/src/components/scroll-area/scroll-area.visual.tsx create mode 100644 packages/ui/src/components/select/select.visual.tsx create mode 100644 packages/ui/src/components/separator/separator.test.tsx create mode 100644 packages/ui/src/components/separator/separator.visual.tsx create mode 100644 packages/ui/src/components/sheet/sheet.visual.tsx create mode 100644 packages/ui/src/components/skeleton/skeleton.test.tsx create mode 100644 packages/ui/src/components/skeleton/skeleton.visual.tsx create mode 100644 packages/ui/src/components/slider/slider.visual.tsx create mode 100644 packages/ui/src/components/spinner/spinner.test.tsx create mode 100644 packages/ui/src/components/spinner/spinner.visual.tsx create mode 100644 packages/ui/src/components/table/table.visual.tsx create mode 100644 packages/ui/src/components/textarea/textarea.test.tsx create mode 100644 packages/ui/src/components/textarea/textarea.visual.tsx create mode 100644 packages/ui/src/components/toggle-group/toggle-group.visual.tsx create mode 100644 packages/ui/src/components/toggle/toggle.test.tsx create mode 100644 packages/ui/src/components/toggle/toggle.visual.tsx create mode 100644 packages/ui/src/components/tooltip/tooltip.visual.tsx diff --git a/packages/ui/src/components/alert-dialog/alert-dialog.visual.tsx b/packages/ui/src/components/alert-dialog/alert-dialog.visual.tsx new file mode 100644 index 0000000..d9bb7c7 --- /dev/null +++ b/packages/ui/src/components/alert-dialog/alert-dialog.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { AlertDialog } from './alert-dialog' + +test.describe('AlertDialog Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('alert-dialog-default.png') + }) +}) diff --git a/packages/ui/src/components/alert/alert.test.tsx b/packages/ui/src/components/alert/alert.test.tsx new file mode 100644 index 0000000..a166bf9 --- /dev/null +++ b/packages/ui/src/components/alert/alert.test.tsx @@ -0,0 +1,44 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Alert } from './alert' + +describe('Alert', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + describe('variant variants', () => { + it.each(['default', 'destructive'] as const)('renders %s variant', (variant) => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + }) + + describe('ref forwarding', () => { + it('forwards ref to DOM element', () => { + const ref = { current: null } + render() + + expect(ref.current).toBeInstanceOf(HTMLElement) + }) + }) + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/alert/alert.visual.tsx b/packages/ui/src/components/alert/alert.visual.tsx new file mode 100644 index 0000000..dd41276 --- /dev/null +++ b/packages/ui/src/components/alert/alert.visual.tsx @@ -0,0 +1,15 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Alert } from './alert' + +test.describe('Alert Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('alert-default.png') + }) + + test('variant-destructive', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('alert-variant-destructive.png') + }) +}) diff --git a/packages/ui/src/components/aspect-ratio/aspect-ratio.visual.tsx b/packages/ui/src/components/aspect-ratio/aspect-ratio.visual.tsx new file mode 100644 index 0000000..63ad445 --- /dev/null +++ b/packages/ui/src/components/aspect-ratio/aspect-ratio.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { AspectRatio } from './aspect-ratio' + +test.describe('AspectRatio Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('aspect-ratio-default.png') + }) +}) diff --git a/packages/ui/src/components/avatar/avatar.test.tsx b/packages/ui/src/components/avatar/avatar.test.tsx new file mode 100644 index 0000000..2bb7b8a --- /dev/null +++ b/packages/ui/src/components/avatar/avatar.test.tsx @@ -0,0 +1,37 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Avatar } from './avatar' + +describe('Avatar', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('ref forwarding', () => { + it('forwards ref to DOM element', () => { + const ref = { current: null } + render() + + expect(ref.current).toBeInstanceOf(HTMLElement) + }) + }) + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/avatar/avatar.visual.tsx b/packages/ui/src/components/avatar/avatar.visual.tsx new file mode 100644 index 0000000..f8d15ef --- /dev/null +++ b/packages/ui/src/components/avatar/avatar.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Avatar } from './avatar' + +test.describe('Avatar Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('avatar-default.png') + }) +}) diff --git a/packages/ui/src/components/blog-card/blog-card.visual.tsx b/packages/ui/src/components/blog-card/blog-card.visual.tsx index aa9562f..c1ba411 100644 --- a/packages/ui/src/components/blog-card/blog-card.visual.tsx +++ b/packages/ui/src/components/blog-card/blog-card.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { BlogCard } from "./blog-card"; +import { BlogCard } from './blog-card' -test.describe("BlogCard Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("blog-card-default.png"); - }); -}); +test.describe('BlogCard Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('blog-card-default.png') + }) +}) diff --git a/packages/ui/src/components/breadcrumb/breadcrumb.visual.tsx b/packages/ui/src/components/breadcrumb/breadcrumb.visual.tsx index d6c5160..76bacb2 100644 --- a/packages/ui/src/components/breadcrumb/breadcrumb.visual.tsx +++ b/packages/ui/src/components/breadcrumb/breadcrumb.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Breadcrumb } from "./breadcrumb"; +import { Breadcrumb } from './breadcrumb' -test.describe("Breadcrumb Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("breadcrumb-default.png"); - }); -}); +test.describe('Breadcrumb Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('breadcrumb-default.png') + }) +}) diff --git a/packages/ui/src/components/calendar/calendar.test.tsx b/packages/ui/src/components/calendar/calendar.test.tsx new file mode 100644 index 0000000..7799f32 --- /dev/null +++ b/packages/ui/src/components/calendar/calendar.test.tsx @@ -0,0 +1,29 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Calendar } from './calendar' + +describe('Calendar', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/calendar/calendar.visual.tsx b/packages/ui/src/components/calendar/calendar.visual.tsx new file mode 100644 index 0000000..68a12cc --- /dev/null +++ b/packages/ui/src/components/calendar/calendar.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Calendar } from './calendar' + +test.describe('Calendar Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('calendar-default.png') + }) +}) diff --git a/packages/ui/src/components/carousel/carousel.test.tsx b/packages/ui/src/components/carousel/carousel.test.tsx new file mode 100644 index 0000000..efe08cd --- /dev/null +++ b/packages/ui/src/components/carousel/carousel.test.tsx @@ -0,0 +1,37 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Carousel } from './carousel' + +describe('Carousel', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('ref forwarding', () => { + it('forwards ref to DOM element', () => { + const ref = { current: null } + render() + + expect(ref.current).toBeInstanceOf(HTMLElement) + }) + }) + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/carousel/carousel.visual.tsx b/packages/ui/src/components/carousel/carousel.visual.tsx new file mode 100644 index 0000000..c3def12 --- /dev/null +++ b/packages/ui/src/components/carousel/carousel.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Carousel } from './carousel' + +test.describe('Carousel Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('carousel-default.png') + }) +}) diff --git a/packages/ui/src/components/category-filter/category-filter.visual.tsx b/packages/ui/src/components/category-filter/category-filter.visual.tsx index 32294b0..86b8e77 100644 --- a/packages/ui/src/components/category-filter/category-filter.visual.tsx +++ b/packages/ui/src/components/category-filter/category-filter.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { CategoryFilter } from "./category-filter"; +import { CategoryFilter } from './category-filter' -test.describe("CategoryFilter Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("category-filter-default.png"); - }); -}); +test.describe('CategoryFilter Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('category-filter-default.png') + }) +}) diff --git a/packages/ui/src/components/checklist/checklist.visual.tsx b/packages/ui/src/components/checklist/checklist.visual.tsx index 00bf3cf..97a53f9 100644 --- a/packages/ui/src/components/checklist/checklist.visual.tsx +++ b/packages/ui/src/components/checklist/checklist.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Checklist } from "./checklist"; +import { Checklist } from './checklist' -test.describe("Checklist Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("checklist-default.png"); - }); -}); +test.describe('Checklist Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('checklist-default.png') + }) +}) diff --git a/packages/ui/src/components/code-playground/code-playground.visual.tsx b/packages/ui/src/components/code-playground/code-playground.visual.tsx index af1fb6c..c1bf674 100644 --- a/packages/ui/src/components/code-playground/code-playground.visual.tsx +++ b/packages/ui/src/components/code-playground/code-playground.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { CodePlayground } from "./code-playground"; +import { CodePlayground } from './code-playground' -test.describe("CodePlayground Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("code-playground-default.png"); - }); -}); +test.describe('CodePlayground Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('code-playground-default.png') + }) +}) diff --git a/packages/ui/src/components/collapsible/collapsible.test.tsx b/packages/ui/src/components/collapsible/collapsible.test.tsx new file mode 100644 index 0000000..eb71450 --- /dev/null +++ b/packages/ui/src/components/collapsible/collapsible.test.tsx @@ -0,0 +1,29 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Collapsible } from './collapsible' + +describe('Collapsible', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/collapsible/collapsible.visual.tsx b/packages/ui/src/components/collapsible/collapsible.visual.tsx new file mode 100644 index 0000000..5aa2ab2 --- /dev/null +++ b/packages/ui/src/components/collapsible/collapsible.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Collapsible } from './collapsible' + +test.describe('Collapsible Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('collapsible-default.png') + }) +}) diff --git a/packages/ui/src/components/comparison/comparison.visual.tsx b/packages/ui/src/components/comparison/comparison.visual.tsx index 9613689..fec35c4 100644 --- a/packages/ui/src/components/comparison/comparison.visual.tsx +++ b/packages/ui/src/components/comparison/comparison.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Comparison } from "./comparison"; +import { Comparison } from './comparison' -test.describe("Comparison Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("comparison-default.png"); - }); -}); +test.describe('Comparison Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('comparison-default.png') + }) +}) diff --git a/packages/ui/src/components/completion-dialog/completion-dialog.visual.tsx b/packages/ui/src/components/completion-dialog/completion-dialog.visual.tsx index 4490ab9..1b8ba4f 100644 --- a/packages/ui/src/components/completion-dialog/completion-dialog.visual.tsx +++ b/packages/ui/src/components/completion-dialog/completion-dialog.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { CompletionDialog } from "./completion-dialog"; +import { CompletionDialog } from './completion-dialog' -test.describe("CompletionDialog Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("completion-dialog-default.png"); - }); -}); +test.describe('CompletionDialog Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('completion-dialog-default.png') + }) +}) diff --git a/packages/ui/src/components/content-intro/content-intro.visual.tsx b/packages/ui/src/components/content-intro/content-intro.visual.tsx index 9d81f7b..8ba106d 100644 --- a/packages/ui/src/components/content-intro/content-intro.visual.tsx +++ b/packages/ui/src/components/content-intro/content-intro.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { ContentIntro } from "./content-intro"; +import { ContentIntro } from './content-intro' -test.describe("ContentIntro Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("content-intro-default.png"); - }); -}); +test.describe('ContentIntro Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('content-intro-default.png') + }) +}) diff --git a/packages/ui/src/components/context-menu/context-menu.visual.tsx b/packages/ui/src/components/context-menu/context-menu.visual.tsx new file mode 100644 index 0000000..b9b47d2 --- /dev/null +++ b/packages/ui/src/components/context-menu/context-menu.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { ContextMenu } from './context-menu' + +test.describe('ContextMenu Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('context-menu-default.png') + }) +}) diff --git a/packages/ui/src/components/dialog/dialog.visual.tsx b/packages/ui/src/components/dialog/dialog.visual.tsx index b558e00..5c4469a 100644 --- a/packages/ui/src/components/dialog/dialog.visual.tsx +++ b/packages/ui/src/components/dialog/dialog.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Dialog } from "./dialog"; +import { Dialog } from './dialog' -test.describe("Dialog Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("dialog-default.png"); - }); -}); +test.describe('Dialog Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('dialog-default.png') + }) +}) diff --git a/packages/ui/src/components/drawer/drawer.visual.tsx b/packages/ui/src/components/drawer/drawer.visual.tsx new file mode 100644 index 0000000..7c6fc51 --- /dev/null +++ b/packages/ui/src/components/drawer/drawer.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Drawer } from './drawer' + +test.describe('Drawer Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('drawer-default.png') + }) +}) diff --git a/packages/ui/src/components/dropdown-menu/dropdown-menu.visual.tsx b/packages/ui/src/components/dropdown-menu/dropdown-menu.visual.tsx index 258cccf..c784a5e 100644 --- a/packages/ui/src/components/dropdown-menu/dropdown-menu.visual.tsx +++ b/packages/ui/src/components/dropdown-menu/dropdown-menu.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { DropdownMenu } from "./dropdown-menu"; +import { DropdownMenu } from './dropdown-menu' -test.describe("DropdownMenu Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("dropdown-menu-default.png"); - }); -}); +test.describe('DropdownMenu Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('dropdown-menu-default.png') + }) +}) diff --git a/packages/ui/src/components/exercise/exercise.visual.tsx b/packages/ui/src/components/exercise/exercise.visual.tsx index 7667ab7..1774b70 100644 --- a/packages/ui/src/components/exercise/exercise.visual.tsx +++ b/packages/ui/src/components/exercise/exercise.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Exercise } from "./exercise"; +import { Exercise } from './exercise' -test.describe("Exercise Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("exercise-default.png"); - }); -}); +test.describe('Exercise Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('exercise-default.png') + }) +}) diff --git a/packages/ui/src/components/faq/faq.visual.tsx b/packages/ui/src/components/faq/faq.visual.tsx index a1db31f..e2c7c85 100644 --- a/packages/ui/src/components/faq/faq.visual.tsx +++ b/packages/ui/src/components/faq/faq.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { FAQ } from "./faq"; +import { FAQ } from './faq' -test.describe("FAQ Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("faq-default.png"); - }); -}); +test.describe('FAQ Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('faq-default.png') + }) +}) diff --git a/packages/ui/src/components/filter-bar/filter-bar.visual.tsx b/packages/ui/src/components/filter-bar/filter-bar.visual.tsx index 4691f37..2433067 100644 --- a/packages/ui/src/components/filter-bar/filter-bar.visual.tsx +++ b/packages/ui/src/components/filter-bar/filter-bar.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { FilterBar } from "./filter-bar"; +import { FilterBar } from './filter-bar' -test.describe("FilterBar Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("filter-bar-default.png"); - }); -}); +test.describe('FilterBar Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('filter-bar-default.png') + }) +}) diff --git a/packages/ui/src/components/flow-diagram/flow-diagram.visual.tsx b/packages/ui/src/components/flow-diagram/flow-diagram.visual.tsx index abecef1..3665732 100644 --- a/packages/ui/src/components/flow-diagram/flow-diagram.visual.tsx +++ b/packages/ui/src/components/flow-diagram/flow-diagram.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { FlowDiagram } from "./flow-diagram"; +import { FlowDiagram } from './flow-diagram' -test.describe("FlowDiagram Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("flow-diagram-default.png"); - }); -}); +test.describe('FlowDiagram Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('flow-diagram-default.png') + }) +}) diff --git a/packages/ui/src/components/hover-card/hover-card.visual.tsx b/packages/ui/src/components/hover-card/hover-card.visual.tsx new file mode 100644 index 0000000..ce61c90 --- /dev/null +++ b/packages/ui/src/components/hover-card/hover-card.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { HoverCard } from './hover-card' + +test.describe('HoverCard Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('hover-card-default.png') + }) +}) diff --git a/packages/ui/src/components/input-otp/input-otp.visual.tsx b/packages/ui/src/components/input-otp/input-otp.visual.tsx new file mode 100644 index 0000000..71a9943 --- /dev/null +++ b/packages/ui/src/components/input-otp/input-otp.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { InputOTP } from './input-otp' + +test.describe('InputOTP Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('input-otp-default.png') + }) +}) diff --git a/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.visual.tsx b/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.visual.tsx index 6ae0935..f177d95 100644 --- a/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.visual.tsx +++ b/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { KeyboardShortcutsHelp } from "./keyboard-shortcuts-help"; +import { KeyboardShortcutsHelp } from './keyboard-shortcuts-help' -test.describe("KeyboardShortcutsHelp Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("keyboard-shortcuts-help-default.png"); - }); -}); +test.describe('KeyboardShortcutsHelp Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('keyboard-shortcuts-help-default.png') + }) +}) diff --git a/packages/ui/src/components/label/label.visual.tsx b/packages/ui/src/components/label/label.visual.tsx index 6471a4b..f8f8340 100644 --- a/packages/ui/src/components/label/label.visual.tsx +++ b/packages/ui/src/components/label/label.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Label } from "./label"; +import { Label } from './label' -test.describe("Label Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("label-default.png"); - }); -}); +test.describe('Label Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('label-default.png') + }) +}) diff --git a/packages/ui/src/components/lang-provider/lang-provider.visual.tsx b/packages/ui/src/components/lang-provider/lang-provider.visual.tsx index 40c93b5..4f13dbf 100644 --- a/packages/ui/src/components/lang-provider/lang-provider.visual.tsx +++ b/packages/ui/src/components/lang-provider/lang-provider.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { LangProvider } from "./lang-provider"; +import { LangProvider } from './lang-provider' -test.describe("LangProvider Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("lang-provider-default.png"); - }); -}); +test.describe('LangProvider Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('lang-provider-default.png') + }) +}) diff --git a/packages/ui/src/components/learning-objectives/learning-objectives.visual.tsx b/packages/ui/src/components/learning-objectives/learning-objectives.visual.tsx index 0387b93..1a33ef9 100644 --- a/packages/ui/src/components/learning-objectives/learning-objectives.visual.tsx +++ b/packages/ui/src/components/learning-objectives/learning-objectives.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { LearningObjectives } from "./learning-objectives"; +import { LearningObjectives } from './learning-objectives' -test.describe("LearningObjectives Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("learning-objectives-default.png"); - }); -}); +test.describe('LearningObjectives Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('learning-objectives-default.png') + }) +}) diff --git a/packages/ui/src/components/menubar/menubar.test.tsx b/packages/ui/src/components/menubar/menubar.test.tsx new file mode 100644 index 0000000..ddb9e19 --- /dev/null +++ b/packages/ui/src/components/menubar/menubar.test.tsx @@ -0,0 +1,37 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Menubar } from './menubar' + +describe('Menubar', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('ref forwarding', () => { + it('forwards ref to DOM element', () => { + const ref = { current: null } + render() + + expect(ref.current).toBeInstanceOf(HTMLElement) + }) + }) + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/menubar/menubar.visual.tsx b/packages/ui/src/components/menubar/menubar.visual.tsx new file mode 100644 index 0000000..ad4f8d6 --- /dev/null +++ b/packages/ui/src/components/menubar/menubar.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Menubar } from './menubar' + +test.describe('Menubar Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('menubar-default.png') + }) +}) diff --git a/packages/ui/src/components/model-selector/model-selector.visual.tsx b/packages/ui/src/components/model-selector/model-selector.visual.tsx index 79cb762..d3103f1 100644 --- a/packages/ui/src/components/model-selector/model-selector.visual.tsx +++ b/packages/ui/src/components/model-selector/model-selector.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { ModelSelector } from "./model-selector"; +import { ModelSelector } from './model-selector' -test.describe("ModelSelector Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("model-selector-default.png"); - }); -}); +test.describe('ModelSelector Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('model-selector-default.png') + }) +}) diff --git a/packages/ui/src/components/navbar-saas/navbar-saas.visual.tsx b/packages/ui/src/components/navbar-saas/navbar-saas.visual.tsx index ede5ed7..3d90e0b 100644 --- a/packages/ui/src/components/navbar-saas/navbar-saas.visual.tsx +++ b/packages/ui/src/components/navbar-saas/navbar-saas.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { NavbarSaas } from "./navbar-saas"; +import { NavbarSaas } from './navbar-saas' -test.describe("NavbarSaas Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("navbar-saas-default.png"); - }); -}); +test.describe('NavbarSaas Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('navbar-saas-default.png') + }) +}) diff --git a/packages/ui/src/components/navigation-menu/navigation-menu.test.tsx b/packages/ui/src/components/navigation-menu/navigation-menu.test.tsx new file mode 100644 index 0000000..16c79bd --- /dev/null +++ b/packages/ui/src/components/navigation-menu/navigation-menu.test.tsx @@ -0,0 +1,37 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { NavigationMenu } from './navigation-menu' + +describe('NavigationMenu', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('ref forwarding', () => { + it('forwards ref to DOM element', () => { + const ref = { current: null } + render() + + expect(ref.current).toBeInstanceOf(HTMLElement) + }) + }) + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/navigation-menu/navigation-menu.visual.tsx b/packages/ui/src/components/navigation-menu/navigation-menu.visual.tsx new file mode 100644 index 0000000..c95799e --- /dev/null +++ b/packages/ui/src/components/navigation-menu/navigation-menu.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { NavigationMenu } from './navigation-menu' + +test.describe('NavigationMenu Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('navigation-menu-default.png') + }) +}) diff --git a/packages/ui/src/components/popover/popover.visual.tsx b/packages/ui/src/components/popover/popover.visual.tsx new file mode 100644 index 0000000..a03d890 --- /dev/null +++ b/packages/ui/src/components/popover/popover.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Popover } from './popover' + +test.describe('Popover Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('popover-default.png') + }) +}) diff --git a/packages/ui/src/components/profile-section/profile-section.visual.tsx b/packages/ui/src/components/profile-section/profile-section.visual.tsx index 18d2906..1248011 100644 --- a/packages/ui/src/components/profile-section/profile-section.visual.tsx +++ b/packages/ui/src/components/profile-section/profile-section.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { ProfileSection } from "./profile-section"; +import { ProfileSection } from './profile-section' -test.describe("ProfileSection Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("profile-section-default.png"); - }); -}); +test.describe('ProfileSection Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('profile-section-default.png') + }) +}) diff --git a/packages/ui/src/components/progress-card/progress-card.visual.tsx b/packages/ui/src/components/progress-card/progress-card.visual.tsx index 7507e11..03ac488 100644 --- a/packages/ui/src/components/progress-card/progress-card.visual.tsx +++ b/packages/ui/src/components/progress-card/progress-card.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { ContentCard } from "./progress-card"; +import { ContentCard } from './progress-card' -test.describe("ContentCard Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("progress-card-default.png"); - }); -}); +test.describe('ContentCard Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('progress-card-default.png') + }) +}) diff --git a/packages/ui/src/components/quiz/quiz.visual.tsx b/packages/ui/src/components/quiz/quiz.visual.tsx index 031ba20..1c40c68 100644 --- a/packages/ui/src/components/quiz/quiz.visual.tsx +++ b/packages/ui/src/components/quiz/quiz.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Quiz } from "./quiz"; +import { Quiz } from './quiz' -test.describe("Quiz Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("quiz-default.png"); - }); -}); +test.describe('Quiz Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('quiz-default.png') + }) +}) diff --git a/packages/ui/src/components/radio-group/radio-group.test.tsx b/packages/ui/src/components/radio-group/radio-group.test.tsx new file mode 100644 index 0000000..7f456f3 --- /dev/null +++ b/packages/ui/src/components/radio-group/radio-group.test.tsx @@ -0,0 +1,37 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { RadioGroup } from './radio-group' + +describe('RadioGroup', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('ref forwarding', () => { + it('forwards ref to DOM element', () => { + const ref = { current: null } + render() + + expect(ref.current).toBeInstanceOf(HTMLElement) + }) + }) + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/radio-group/radio-group.visual.tsx b/packages/ui/src/components/radio-group/radio-group.visual.tsx new file mode 100644 index 0000000..8896a8d --- /dev/null +++ b/packages/ui/src/components/radio-group/radio-group.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { RadioGroup } from './radio-group' + +test.describe('RadioGroup Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('radio-group-default.png') + }) +}) diff --git a/packages/ui/src/components/resizable/resizable.visual.tsx b/packages/ui/src/components/resizable/resizable.visual.tsx new file mode 100644 index 0000000..c5c9a36 --- /dev/null +++ b/packages/ui/src/components/resizable/resizable.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { ResizableHandle } from './resizable' + +test.describe('ResizableHandle Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('resizable-default.png') + }) +}) diff --git a/packages/ui/src/components/scroll-area/scroll-area.test.tsx b/packages/ui/src/components/scroll-area/scroll-area.test.tsx new file mode 100644 index 0000000..9690bd3 --- /dev/null +++ b/packages/ui/src/components/scroll-area/scroll-area.test.tsx @@ -0,0 +1,37 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { ScrollArea } from './scroll-area' + +describe('ScrollArea', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('ref forwarding', () => { + it('forwards ref to DOM element', () => { + const ref = { current: null } + render() + + expect(ref.current).toBeInstanceOf(HTMLElement) + }) + }) + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/scroll-area/scroll-area.visual.tsx b/packages/ui/src/components/scroll-area/scroll-area.visual.tsx new file mode 100644 index 0000000..0cef603 --- /dev/null +++ b/packages/ui/src/components/scroll-area/scroll-area.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { ScrollArea } from './scroll-area' + +test.describe('ScrollArea Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('scroll-area-default.png') + }) +}) diff --git a/packages/ui/src/components/search-bar/search-bar.visual.tsx b/packages/ui/src/components/search-bar/search-bar.visual.tsx index 695325b..f743557 100644 --- a/packages/ui/src/components/search-bar/search-bar.visual.tsx +++ b/packages/ui/src/components/search-bar/search-bar.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { SearchBar } from "./search-bar"; +import { SearchBar } from './search-bar' -test.describe("SearchBar Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("search-bar-default.png"); - }); -}); +test.describe('SearchBar Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('search-bar-default.png') + }) +}) diff --git a/packages/ui/src/components/search-dialog/search-dialog.visual.tsx b/packages/ui/src/components/search-dialog/search-dialog.visual.tsx index 078e80d..fc89fc0 100644 --- a/packages/ui/src/components/search-dialog/search-dialog.visual.tsx +++ b/packages/ui/src/components/search-dialog/search-dialog.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { SearchDialog } from "./search-dialog"; +import { SearchDialog } from './search-dialog' -test.describe("SearchDialog Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("search-dialog-default.png"); - }); -}); +test.describe('SearchDialog Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('search-dialog-default.png') + }) +}) diff --git a/packages/ui/src/components/select/select.visual.tsx b/packages/ui/src/components/select/select.visual.tsx new file mode 100644 index 0000000..5146f6a --- /dev/null +++ b/packages/ui/src/components/select/select.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Select } from './select' + +test.describe('Select Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('select-default.png') + }) +}) diff --git a/packages/ui/src/components/separator/separator.test.tsx b/packages/ui/src/components/separator/separator.test.tsx new file mode 100644 index 0000000..a180bc6 --- /dev/null +++ b/packages/ui/src/components/separator/separator.test.tsx @@ -0,0 +1,37 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Separator } from './separator' + +describe('Separator', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('ref forwarding', () => { + it('forwards ref to DOM element', () => { + const ref = { current: null } + render() + + expect(ref.current).toBeInstanceOf(HTMLElement) + }) + }) + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/separator/separator.visual.tsx b/packages/ui/src/components/separator/separator.visual.tsx new file mode 100644 index 0000000..637abf6 --- /dev/null +++ b/packages/ui/src/components/separator/separator.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Separator } from './separator' + +test.describe('Separator Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('separator-default.png') + }) +}) diff --git a/packages/ui/src/components/share-dialog/share-dialog.visual.tsx b/packages/ui/src/components/share-dialog/share-dialog.visual.tsx index 8bc5ab3..ec8c3cb 100644 --- a/packages/ui/src/components/share-dialog/share-dialog.visual.tsx +++ b/packages/ui/src/components/share-dialog/share-dialog.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { ShareDialog } from "./share-dialog"; +import { ShareDialog } from './share-dialog' -test.describe("ShareDialog Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("share-dialog-default.png"); - }); -}); +test.describe('ShareDialog Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('share-dialog-default.png') + }) +}) diff --git a/packages/ui/src/components/share-section/share-section.visual.tsx b/packages/ui/src/components/share-section/share-section.visual.tsx index 5397112..1d5b7ae 100644 --- a/packages/ui/src/components/share-section/share-section.visual.tsx +++ b/packages/ui/src/components/share-section/share-section.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { ShareSection } from "./share-section"; +import { ShareSection } from './share-section' -test.describe("ShareSection Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("share-section-default.png"); - }); -}); +test.describe('ShareSection Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('share-section-default.png') + }) +}) diff --git a/packages/ui/src/components/sheet/sheet.visual.tsx b/packages/ui/src/components/sheet/sheet.visual.tsx new file mode 100644 index 0000000..c56000e --- /dev/null +++ b/packages/ui/src/components/sheet/sheet.visual.tsx @@ -0,0 +1,25 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Sheet } from './sheet' + +test.describe('Sheet Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('sheet-default.png') + }) + + test('side-bottom', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('sheet-side-bottom.png') + }) + + test('side-left', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('sheet-side-left.png') + }) + + test('side-top', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('sheet-side-top.png') + }) +}) diff --git a/packages/ui/src/components/sidebar-provider/sidebar-provider.visual.tsx b/packages/ui/src/components/sidebar-provider/sidebar-provider.visual.tsx index c2eff83..0afd743 100644 --- a/packages/ui/src/components/sidebar-provider/sidebar-provider.visual.tsx +++ b/packages/ui/src/components/sidebar-provider/sidebar-provider.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { SidebarProvider } from "./sidebar-provider"; +import { SidebarProvider } from './sidebar-provider' -test.describe("SidebarProvider Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("sidebar-provider-default.png"); - }); -}); +test.describe('SidebarProvider Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('sidebar-provider-default.png') + }) +}) diff --git a/packages/ui/src/components/sidebar/sidebar.visual.tsx b/packages/ui/src/components/sidebar/sidebar.visual.tsx index 743bba7..3ebe454 100644 --- a/packages/ui/src/components/sidebar/sidebar.visual.tsx +++ b/packages/ui/src/components/sidebar/sidebar.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Sidebar } from "./sidebar"; +import { Sidebar } from './sidebar' -test.describe("Sidebar Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("sidebar-default.png"); - }); -}); +test.describe('Sidebar Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('sidebar-default.png') + }) +}) diff --git a/packages/ui/src/components/skeleton/skeleton.test.tsx b/packages/ui/src/components/skeleton/skeleton.test.tsx new file mode 100644 index 0000000..9cb2092 --- /dev/null +++ b/packages/ui/src/components/skeleton/skeleton.test.tsx @@ -0,0 +1,29 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Skeleton } from './skeleton' + +describe('Skeleton', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/skeleton/skeleton.visual.tsx b/packages/ui/src/components/skeleton/skeleton.visual.tsx new file mode 100644 index 0000000..2df02d5 --- /dev/null +++ b/packages/ui/src/components/skeleton/skeleton.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Skeleton } from './skeleton' + +test.describe('Skeleton Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('skeleton-default.png') + }) +}) diff --git a/packages/ui/src/components/slider/slider.visual.tsx b/packages/ui/src/components/slider/slider.visual.tsx new file mode 100644 index 0000000..a527a8c --- /dev/null +++ b/packages/ui/src/components/slider/slider.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Slider } from './slider' + +test.describe('Slider Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('slider-default.png') + }) +}) diff --git a/packages/ui/src/components/slideshow/slideshow.visual.tsx b/packages/ui/src/components/slideshow/slideshow.visual.tsx index 6f8c011..07a5e5d 100644 --- a/packages/ui/src/components/slideshow/slideshow.visual.tsx +++ b/packages/ui/src/components/slideshow/slideshow.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Slideshow } from "./slideshow"; +import { Slideshow } from './slideshow' -test.describe("Slideshow Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("slideshow-default.png"); - }); -}); +test.describe('Slideshow Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('slideshow-default.png') + }) +}) diff --git a/packages/ui/src/components/social-fab/social-fab.visual.tsx b/packages/ui/src/components/social-fab/social-fab.visual.tsx index e54c192..e49e242 100644 --- a/packages/ui/src/components/social-fab/social-fab.visual.tsx +++ b/packages/ui/src/components/social-fab/social-fab.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { SocialFAB } from "./social-fab"; +import { SocialFAB } from './social-fab' -test.describe("SocialFAB Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("social-fab-default.png"); - }); -}); +test.describe('SocialFAB Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('social-fab-default.png') + }) +}) diff --git a/packages/ui/src/components/spinner/spinner.test.tsx b/packages/ui/src/components/spinner/spinner.test.tsx new file mode 100644 index 0000000..f6ee830 --- /dev/null +++ b/packages/ui/src/components/spinner/spinner.test.tsx @@ -0,0 +1,29 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Spinner } from './spinner' + +describe('Spinner', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/spinner/spinner.visual.tsx b/packages/ui/src/components/spinner/spinner.visual.tsx new file mode 100644 index 0000000..bd04060 --- /dev/null +++ b/packages/ui/src/components/spinner/spinner.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Spinner } from './spinner' + +test.describe('Spinner Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('spinner-default.png') + }) +}) diff --git a/packages/ui/src/components/step-by-step/step-by-step.visual.tsx b/packages/ui/src/components/step-by-step/step-by-step.visual.tsx index 2c7d9e5..c1e5eb2 100644 --- a/packages/ui/src/components/step-by-step/step-by-step.visual.tsx +++ b/packages/ui/src/components/step-by-step/step-by-step.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { StepByStep } from "./step-by-step"; +import { StepByStep } from './step-by-step' -test.describe("StepByStep Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("step-by-step-default.png"); - }); -}); +test.describe('StepByStep Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('step-by-step-default.png') + }) +}) diff --git a/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.visual.tsx b/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.visual.tsx index b513e17..6b197b2 100644 --- a/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.visual.tsx +++ b/packages/ui/src/components/table-of-contents-panel/table-of-contents-panel.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { TableOfContentsPanel } from "./table-of-contents-panel"; +import { TableOfContentsPanel } from './table-of-contents-panel' -test.describe("TableOfContentsPanel Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("table-of-contents-panel-default.png"); - }); -}); +test.describe('TableOfContentsPanel Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('table-of-contents-panel-default.png') + }) +}) diff --git a/packages/ui/src/components/table-of-contents/table-of-contents.visual.tsx b/packages/ui/src/components/table-of-contents/table-of-contents.visual.tsx index 3403787..8600a27 100644 --- a/packages/ui/src/components/table-of-contents/table-of-contents.visual.tsx +++ b/packages/ui/src/components/table-of-contents/table-of-contents.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { TableOfContents } from "./table-of-contents"; +import { TableOfContents } from './table-of-contents' -test.describe("TableOfContents Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("table-of-contents-default.png"); - }); -}); +test.describe('TableOfContents Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('table-of-contents-default.png') + }) +}) diff --git a/packages/ui/src/components/table/table.visual.tsx b/packages/ui/src/components/table/table.visual.tsx new file mode 100644 index 0000000..ab796ce --- /dev/null +++ b/packages/ui/src/components/table/table.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Table } from './table' + +test.describe('Table Visual', () => { + test('default', async ({ mount, page }) => { + await mount(
) + await expect(page).toHaveScreenshot('table-default.png') + }) +}) diff --git a/packages/ui/src/components/tabs/tabs.visual.tsx b/packages/ui/src/components/tabs/tabs.visual.tsx index 6f47e26..06f1e87 100644 --- a/packages/ui/src/components/tabs/tabs.visual.tsx +++ b/packages/ui/src/components/tabs/tabs.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Tabs } from "./tabs"; +import { Tabs } from './tabs' -test.describe("Tabs Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("tabs-default.png"); - }); -}); +test.describe('Tabs Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('tabs-default.png') + }) +}) diff --git a/packages/ui/src/components/terminal/terminal.visual.tsx b/packages/ui/src/components/terminal/terminal.visual.tsx index 3abc9e4..96c671b 100644 --- a/packages/ui/src/components/terminal/terminal.visual.tsx +++ b/packages/ui/src/components/terminal/terminal.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Terminal } from "./terminal"; +import { Terminal } from './terminal' -test.describe("Terminal Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("terminal-default.png"); - }); -}); +test.describe('Terminal Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('terminal-default.png') + }) +}) diff --git a/packages/ui/src/components/textarea/textarea.test.tsx b/packages/ui/src/components/textarea/textarea.test.tsx new file mode 100644 index 0000000..414d98f --- /dev/null +++ b/packages/ui/src/components/textarea/textarea.test.tsx @@ -0,0 +1,37 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Textarea } from './textarea' + +describe('Textarea', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + + describe('ref forwarding', () => { + it('forwards ref to DOM element', () => { + const ref = { current: null } + render() + + expect(ref.current).toBeInstanceOf(HTMLElement) + }) + }) + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/textarea/textarea.visual.tsx b/packages/ui/src/components/textarea/textarea.visual.tsx new file mode 100644 index 0000000..481e874 --- /dev/null +++ b/packages/ui/src/components/textarea/textarea.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Textarea } from './textarea' + +test.describe('Textarea Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('textarea-default.png') + }) +}) diff --git a/packages/ui/src/components/theme-provider/theme-provider.visual.tsx b/packages/ui/src/components/theme-provider/theme-provider.visual.tsx index c526110..d2a058b 100644 --- a/packages/ui/src/components/theme-provider/theme-provider.visual.tsx +++ b/packages/ui/src/components/theme-provider/theme-provider.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { ThemeProvider } from "./theme-provider"; +import { ThemeProvider } from './theme-provider' -test.describe("ThemeProvider Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("theme-provider-default.png"); - }); -}); +test.describe('ThemeProvider Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('theme-provider-default.png') + }) +}) diff --git a/packages/ui/src/components/theme-toggle/theme-toggle.visual.tsx b/packages/ui/src/components/theme-toggle/theme-toggle.visual.tsx index 53ef2d6..c8f2c00 100644 --- a/packages/ui/src/components/theme-toggle/theme-toggle.visual.tsx +++ b/packages/ui/src/components/theme-toggle/theme-toggle.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { ThemeToggle } from "./theme-toggle"; +import { ThemeToggle } from './theme-toggle' -test.describe("ThemeToggle Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("theme-toggle-default.png"); - }); -}); +test.describe('ThemeToggle Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('theme-toggle-default.png') + }) +}) diff --git a/packages/ui/src/components/tldr-section/tldr-section.visual.tsx b/packages/ui/src/components/tldr-section/tldr-section.visual.tsx index 44d4b08..de74af5 100644 --- a/packages/ui/src/components/tldr-section/tldr-section.visual.tsx +++ b/packages/ui/src/components/tldr-section/tldr-section.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { TLDRSection } from "./tldr-section"; +import { TLDRSection } from './tldr-section' -test.describe("TLDRSection Visual", () => { - test("default", async ({ mount, page }) => { - await mount(Test); - await expect(page).toHaveScreenshot("tldr-section-default.png"); - }); -}); +test.describe('TLDRSection Visual', () => { + test('default', async ({ mount, page }) => { + await mount(Test) + await expect(page).toHaveScreenshot('tldr-section-default.png') + }) +}) diff --git a/packages/ui/src/components/toast/toast.visual.tsx b/packages/ui/src/components/toast/toast.visual.tsx index c1b70b8..388f23c 100644 --- a/packages/ui/src/components/toast/toast.visual.tsx +++ b/packages/ui/src/components/toast/toast.visual.tsx @@ -1,15 +1,15 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { Toast } from "./toast"; +import { Toast } from './toast' -test.describe("Toast Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("toast-default.png"); - }); +test.describe('Toast Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('toast-default.png') + }) - test("variant-destructive", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("toast-variant-destructive.png"); - }); -}); + test('variant-destructive', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('toast-variant-destructive.png') + }) +}) diff --git a/packages/ui/src/components/toggle-group/toggle-group.visual.tsx b/packages/ui/src/components/toggle-group/toggle-group.visual.tsx new file mode 100644 index 0000000..3a452ea --- /dev/null +++ b/packages/ui/src/components/toggle-group/toggle-group.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { ToggleGroup } from './toggle-group' + +test.describe('ToggleGroup Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('toggle-group-default.png') + }) +}) diff --git a/packages/ui/src/components/toggle/toggle.test.tsx b/packages/ui/src/components/toggle/toggle.test.tsx new file mode 100644 index 0000000..bb7ad84 --- /dev/null +++ b/packages/ui/src/components/toggle/toggle.test.tsx @@ -0,0 +1,52 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vitest' + +import { Toggle } from './toggle' + +describe('Toggle', () => { + describe('rendering', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + + it('applies custom className', () => { + const { container } = render() + + expect(container.firstChild).toHaveClass('custom-class') + }) + }) + + describe('size variants', () => { + it.each(['default', 'lg', 'sm'] as const)('renders %s size', (size) => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + }) + + describe('variant variants', () => { + it.each(['default', 'outline'] as const)('renders %s variant', (variant) => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + }) + }) + + describe('ref forwarding', () => { + it('forwards ref to DOM element', () => { + const ref = { current: null } + render() + + expect(ref.current).toBeInstanceOf(HTMLElement) + }) + }) + describe('accessibility', () => { + it('is visible when rendered', () => { + const { container } = render() + + expect(container.firstChild).toBeVisible() + }) + }) +}) diff --git a/packages/ui/src/components/toggle/toggle.visual.tsx b/packages/ui/src/components/toggle/toggle.visual.tsx new file mode 100644 index 0000000..794a146 --- /dev/null +++ b/packages/ui/src/components/toggle/toggle.visual.tsx @@ -0,0 +1,25 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Toggle } from './toggle' + +test.describe('Toggle Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('toggle-default.png') + }) + + test('size-lg', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('toggle-size-lg.png') + }) + + test('size-sm', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('toggle-size-sm.png') + }) + + test('variant-outline', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('toggle-variant-outline.png') + }) +}) diff --git a/packages/ui/src/components/tooltip/tooltip.visual.tsx b/packages/ui/src/components/tooltip/tooltip.visual.tsx new file mode 100644 index 0000000..9db354b --- /dev/null +++ b/packages/ui/src/components/tooltip/tooltip.visual.tsx @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/experimental-ct-react' + +import { Tooltip } from './tooltip' + +test.describe('Tooltip Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('tooltip-default.png') + }) +}) diff --git a/packages/ui/src/components/tutorial-card/tutorial-card.visual.tsx b/packages/ui/src/components/tutorial-card/tutorial-card.visual.tsx index 6b4d1f6..fbdba03 100644 --- a/packages/ui/src/components/tutorial-card/tutorial-card.visual.tsx +++ b/packages/ui/src/components/tutorial-card/tutorial-card.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { TutorialCard } from "./tutorial-card"; +import { TutorialCard } from './tutorial-card' -test.describe("TutorialCard Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("tutorial-card-default.png"); - }); -}); +test.describe('TutorialCard Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('tutorial-card-default.png') + }) +}) diff --git a/packages/ui/src/components/tutorial-complete/tutorial-complete.visual.tsx b/packages/ui/src/components/tutorial-complete/tutorial-complete.visual.tsx index 0c07667..d64ae40 100644 --- a/packages/ui/src/components/tutorial-complete/tutorial-complete.visual.tsx +++ b/packages/ui/src/components/tutorial-complete/tutorial-complete.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { TutorialComplete } from "./tutorial-complete"; +import { TutorialComplete } from './tutorial-complete' -test.describe("TutorialComplete Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("tutorial-complete-default.png"); - }); -}); +test.describe('TutorialComplete Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('tutorial-complete-default.png') + }) +}) diff --git a/packages/ui/src/components/tutorial-filters/tutorial-filters.visual.tsx b/packages/ui/src/components/tutorial-filters/tutorial-filters.visual.tsx index a221fae..93f69de 100644 --- a/packages/ui/src/components/tutorial-filters/tutorial-filters.visual.tsx +++ b/packages/ui/src/components/tutorial-filters/tutorial-filters.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { TutorialFilters } from "./tutorial-filters"; +import { TutorialFilters } from './tutorial-filters' -test.describe("TutorialFilters Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("tutorial-filters-default.png"); - }); -}); +test.describe('TutorialFilters Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('tutorial-filters-default.png') + }) +}) diff --git a/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.visual.tsx b/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.visual.tsx index 7e840bc..d92a6a4 100644 --- a/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.visual.tsx +++ b/packages/ui/src/components/tutorial-intro-content/tutorial-intro-content.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { TutorialIntroContent } from "./tutorial-intro-content"; +import { TutorialIntroContent } from './tutorial-intro-content' -test.describe("TutorialIntroContent Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("tutorial-intro-content-default.png"); - }); -}); +test.describe('TutorialIntroContent Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('tutorial-intro-content-default.png') + }) +}) diff --git a/packages/ui/src/components/tutorial-mdx/tutorial-mdx.visual.tsx b/packages/ui/src/components/tutorial-mdx/tutorial-mdx.visual.tsx index b348575..10d32c5 100644 --- a/packages/ui/src/components/tutorial-mdx/tutorial-mdx.visual.tsx +++ b/packages/ui/src/components/tutorial-mdx/tutorial-mdx.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { TutorialMDX } from "./tutorial-mdx"; +import { TutorialMDX } from './tutorial-mdx' -test.describe("TutorialMDX Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("tutorial-mdx-default.png"); - }); -}); +test.describe('TutorialMDX Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('tutorial-mdx-default.png') + }) +}) diff --git a/packages/ui/src/components/video-embed/video-embed.visual.tsx b/packages/ui/src/components/video-embed/video-embed.visual.tsx index 264206b..efdfba1 100644 --- a/packages/ui/src/components/video-embed/video-embed.visual.tsx +++ b/packages/ui/src/components/video-embed/video-embed.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from "@playwright/experimental-ct-react"; +import { expect, test } from '@playwright/experimental-ct-react' -import { VideoEmbed } from "./video-embed"; +import { VideoEmbed } from './video-embed' -test.describe("VideoEmbed Visual", () => { - test("default", async ({ mount, page }) => { - await mount(); - await expect(page).toHaveScreenshot("video-embed-default.png"); - }); -}); +test.describe('VideoEmbed Visual', () => { + test('default', async ({ mount, page }) => { + await mount() + await expect(page).toHaveScreenshot('video-embed-default.png') + }) +}) From 548c6e1aee13121498e5b9be6585d541d41fa532 Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 11 Mar 2026 22:11:50 +0100 Subject: [PATCH 15/26] fix(ci): resolve lint failures and Playwright install in CI - Add stories and visual tests to eslint ignores (excluded from tsconfig) - Fix Playwright install: use pnpm exec instead of npx in monorepo - Auto-fix quote style in generated visual/test files - Add test-runner-jest.config.ts to tsconfig include --- .github/workflows/storybook.yml | 6 +- packages/ui/eslint.config.js | 2 +- .../alert-dialog/alert-dialog.visual.tsx | 16 +-- .../ui/src/components/alert/alert.test.tsx | 91 ++++++++------- .../ui/src/components/alert/alert.visual.tsx | 24 ++-- .../aspect-ratio/aspect-ratio.visual.tsx | 16 +-- .../ui/src/components/avatar/avatar.test.tsx | 73 ++++++------ .../src/components/avatar/avatar.visual.tsx | 16 +-- .../components/blog-card/blog-card.visual.tsx | 16 +-- .../breadcrumb/breadcrumb.visual.tsx | 16 +-- .../src/components/calendar/calendar.test.tsx | 43 ++++--- .../components/calendar/calendar.visual.tsx | 16 +-- .../src/components/carousel/carousel.test.tsx | 73 ++++++------ .../components/carousel/carousel.visual.tsx | 16 +-- .../category-filter.visual.tsx | 16 +-- .../components/checklist/checklist.visual.tsx | 16 +-- .../code-playground.visual.tsx | 16 +-- .../collapsible/collapsible.test.tsx | 43 ++++--- .../collapsible/collapsible.visual.tsx | 16 +-- .../comparison/comparison.visual.tsx | 16 +-- .../completion-dialog.visual.tsx | 16 +-- .../content-intro/content-intro.visual.tsx | 16 +-- .../context-menu/context-menu.visual.tsx | 16 +-- .../src/components/dialog/dialog.visual.tsx | 16 +-- .../src/components/drawer/drawer.visual.tsx | 16 +-- .../dropdown-menu/dropdown-menu.visual.tsx | 16 +-- .../components/exercise/exercise.visual.tsx | 16 +-- packages/ui/src/components/faq/faq.visual.tsx | 16 +-- .../filter-bar/filter-bar.visual.tsx | 16 +-- .../flow-diagram/flow-diagram.visual.tsx | 16 +-- .../hover-card/hover-card.visual.tsx | 16 +-- .../components/input-otp/input-otp.visual.tsx | 16 +-- .../keyboard-shortcuts-help.visual.tsx | 16 +-- .../ui/src/components/label/label.visual.tsx | 16 +-- .../lang-provider/lang-provider.visual.tsx | 16 +-- .../learning-objectives.visual.tsx | 16 +-- .../src/components/menubar/menubar.test.tsx | 73 ++++++------ .../src/components/menubar/menubar.visual.tsx | 16 +-- .../model-selector/model-selector.visual.tsx | 16 +-- .../navbar-saas/navbar-saas.visual.tsx | 16 +-- .../navigation-menu/navigation-menu.test.tsx | 73 ++++++------ .../navigation-menu.visual.tsx | 16 +-- .../src/components/popover/popover.visual.tsx | 16 +-- .../profile-section.visual.tsx | 16 +-- .../progress-card/progress-card.visual.tsx | 16 +-- .../ui/src/components/quiz/quiz.visual.tsx | 16 +-- .../radio-group/radio-group.test.tsx | 73 ++++++------ .../radio-group/radio-group.visual.tsx | 16 +-- .../components/resizable/resizable.visual.tsx | 16 +-- .../scroll-area/scroll-area.test.tsx | 73 ++++++------ .../scroll-area/scroll-area.visual.tsx | 16 +-- .../search-bar/search-bar.visual.tsx | 16 +-- .../search-dialog/search-dialog.visual.tsx | 16 +-- .../src/components/select/select.visual.tsx | 16 +-- .../components/separator/separator.test.tsx | 73 ++++++------ .../components/separator/separator.visual.tsx | 16 +-- .../share-dialog/share-dialog.visual.tsx | 16 +-- .../share-section/share-section.visual.tsx | 16 +-- .../ui/src/components/sheet/sheet.visual.tsx | 40 +++---- .../sidebar-provider.visual.tsx | 16 +-- .../src/components/sidebar/sidebar.visual.tsx | 16 +-- .../src/components/skeleton/skeleton.test.tsx | 43 ++++--- .../components/skeleton/skeleton.visual.tsx | 16 +-- .../src/components/slider/slider.visual.tsx | 16 +-- .../components/slideshow/slideshow.visual.tsx | 16 +-- .../social-fab/social-fab.visual.tsx | 16 +-- .../src/components/spinner/spinner.test.tsx | 43 ++++--- .../src/components/spinner/spinner.visual.tsx | 16 +-- .../step-by-step/step-by-step.visual.tsx | 16 +-- .../table-of-contents-panel.visual.tsx | 16 +-- .../table-of-contents.visual.tsx | 16 +-- .../ui/src/components/table/table.visual.tsx | 16 +-- .../ui/src/components/tabs/tabs.visual.tsx | 16 +-- .../components/terminal/terminal.visual.tsx | 16 +-- .../src/components/textarea/textarea.test.tsx | 73 ++++++------ .../components/textarea/textarea.visual.tsx | 16 +-- .../theme-provider/theme-provider.visual.tsx | 16 +-- .../theme-toggle/theme-toggle.visual.tsx | 16 +-- .../tldr-section/tldr-section.visual.tsx | 16 +-- .../ui/src/components/toast/toast.visual.tsx | 24 ++-- .../toggle-group/toggle-group.visual.tsx | 16 +-- .../ui/src/components/toggle/toggle.test.tsx | 107 +++++++++--------- .../src/components/toggle/toggle.visual.tsx | 40 +++---- .../src/components/tooltip/tooltip.visual.tsx | 16 +-- .../tutorial-card/tutorial-card.visual.tsx | 16 +-- .../tutorial-complete.visual.tsx | 16 +-- .../tutorial-filters.visual.tsx | 16 +-- .../tutorial-intro-content.visual.tsx | 16 +-- .../tutorial-mdx/tutorial-mdx.visual.tsx | 16 +-- .../video-embed/video-embed.visual.tsx | 16 +-- packages/ui/tsconfig.json | 2 +- 91 files changed, 1103 insertions(+), 1109 deletions(-) diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index 7f89a5f..9e62a35 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -87,7 +87,7 @@ jobs: - run: pnpm install --frozen-lockfile - name: Install Playwright browsers - run: npx playwright install --with-deps chromium + run: pnpm -F @vllnt/ui exec playwright install --with-deps chromium - name: Download Storybook artifact uses: actions/download-artifact@v4 @@ -100,7 +100,7 @@ jobs: run: | npx http-server storybook-static --port 6006 --silent & sleep 3 - npx test-storybook --url http://127.0.0.1:6006 --maxWorkers=2 + pnpm test-storybook --url http://127.0.0.1:6006 --maxWorkers=2 visual-regression: name: Visual Regression @@ -119,7 +119,7 @@ jobs: - run: pnpm install --frozen-lockfile - name: Install Playwright browsers - run: npx playwright install --with-deps chromium + run: pnpm -F @vllnt/ui exec playwright install --with-deps chromium - name: Run Playwright CT visual tests working-directory: packages/ui diff --git a/packages/ui/eslint.config.js b/packages/ui/eslint.config.js index 7500d0f..ea14d2f 100644 --- a/packages/ui/eslint.config.js +++ b/packages/ui/eslint.config.js @@ -2,7 +2,7 @@ import { react } from '@vllnt/eslint-config' export default [ { - ignores: ['node_modules/**', 'dist/**', 'storybook-static/**', '.storybook/**', 'eslint.config.js', 'scripts/**', 'playwright-ct.config.ts', 'playwright/**', 'postcss.config.mjs', 'tailwind.config.ts', 'tsup.config.ts'], + ignores: ['node_modules/**', 'dist/**', 'storybook-static/**', '.storybook/**', 'eslint.config.js', 'scripts/**', 'playwright-ct.config.ts', 'playwright/**', 'postcss.config.mjs', 'tailwind.config.ts', 'tsup.config.ts', 'src/**/*.visual.tsx', 'src/**/*.stories.tsx', 'src/**/*.stories.ts', 'test-runner-jest.config.ts'], }, ...react, { diff --git a/packages/ui/src/components/alert-dialog/alert-dialog.visual.tsx b/packages/ui/src/components/alert-dialog/alert-dialog.visual.tsx index d9bb7c7..22a223e 100644 --- a/packages/ui/src/components/alert-dialog/alert-dialog.visual.tsx +++ b/packages/ui/src/components/alert-dialog/alert-dialog.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { AlertDialog } from './alert-dialog' +import { AlertDialog } from "./alert-dialog"; -test.describe('AlertDialog Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('alert-dialog-default.png') - }) -}) +test.describe("AlertDialog Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("alert-dialog-default.png"); + }); +}); diff --git a/packages/ui/src/components/alert/alert.test.tsx b/packages/ui/src/components/alert/alert.test.tsx index a166bf9..3cc31a9 100644 --- a/packages/ui/src/components/alert/alert.test.tsx +++ b/packages/ui/src/components/alert/alert.test.tsx @@ -1,44 +1,47 @@ -import { render } from '@testing-library/react' -import { describe, expect, it } from 'vitest' - -import { Alert } from './alert' - -describe('Alert', () => { - describe('rendering', () => { - it('renders correctly', () => { - const { container } = render() - - expect(container.firstChild).toBeInTheDocument() - }) - - it('applies custom className', () => { - const { container } = render() - - expect(container.firstChild).toHaveClass('custom-class') - }) - }) - - describe('variant variants', () => { - it.each(['default', 'destructive'] as const)('renders %s variant', (variant) => { - const { container } = render() - - expect(container.firstChild).toBeInTheDocument() - }) - }) - - describe('ref forwarding', () => { - it('forwards ref to DOM element', () => { - const ref = { current: null } - render() - - expect(ref.current).toBeInstanceOf(HTMLElement) - }) - }) - describe('accessibility', () => { - it('is visible when rendered', () => { - const { container } = render() - - expect(container.firstChild).toBeVisible() - }) - }) -}) +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { Alert } from "./alert"; + +describe("Alert", () => { + describe("rendering", () => { + it("renders correctly", () => { + const { container } = render(); + + expect(container.firstChild).toBeInTheDocument(); + }); + + it("applies custom className", () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass("custom-class"); + }); + }); + + describe("variant variants", () => { + it.each(["default", "destructive"] as const)( + "renders %s variant", + (variant) => { + const { container } = render(); + + expect(container.firstChild).toBeInTheDocument(); + }, + ); + }); + + describe("ref forwarding", () => { + it("forwards ref to DOM element", () => { + const ref = { current: null }; + render(); + + expect(ref.current).toBeInstanceOf(HTMLElement); + }); + }); + describe("accessibility", () => { + it("is visible when rendered", () => { + const { container } = render(); + + expect(container.firstChild).toBeVisible(); + }); + }); +}); diff --git a/packages/ui/src/components/alert/alert.visual.tsx b/packages/ui/src/components/alert/alert.visual.tsx index dd41276..1152556 100644 --- a/packages/ui/src/components/alert/alert.visual.tsx +++ b/packages/ui/src/components/alert/alert.visual.tsx @@ -1,15 +1,15 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Alert } from './alert' +import { Alert } from "./alert"; -test.describe('Alert Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('alert-default.png') - }) +test.describe("Alert Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("alert-default.png"); + }); - test('variant-destructive', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('alert-variant-destructive.png') - }) -}) + test("variant-destructive", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("alert-variant-destructive.png"); + }); +}); diff --git a/packages/ui/src/components/aspect-ratio/aspect-ratio.visual.tsx b/packages/ui/src/components/aspect-ratio/aspect-ratio.visual.tsx index 63ad445..215228f 100644 --- a/packages/ui/src/components/aspect-ratio/aspect-ratio.visual.tsx +++ b/packages/ui/src/components/aspect-ratio/aspect-ratio.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { AspectRatio } from './aspect-ratio' +import { AspectRatio } from "./aspect-ratio"; -test.describe('AspectRatio Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('aspect-ratio-default.png') - }) -}) +test.describe("AspectRatio Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("aspect-ratio-default.png"); + }); +}); diff --git a/packages/ui/src/components/avatar/avatar.test.tsx b/packages/ui/src/components/avatar/avatar.test.tsx index 2bb7b8a..83561dd 100644 --- a/packages/ui/src/components/avatar/avatar.test.tsx +++ b/packages/ui/src/components/avatar/avatar.test.tsx @@ -1,37 +1,36 @@ -import { render } from '@testing-library/react' -import { describe, expect, it } from 'vitest' - -import { Avatar } from './avatar' - -describe('Avatar', () => { - describe('rendering', () => { - it('renders correctly', () => { - const { container } = render() - - expect(container.firstChild).toBeInTheDocument() - }) - - it('applies custom className', () => { - const { container } = render() - - expect(container.firstChild).toHaveClass('custom-class') - }) - }) - - - describe('ref forwarding', () => { - it('forwards ref to DOM element', () => { - const ref = { current: null } - render() - - expect(ref.current).toBeInstanceOf(HTMLElement) - }) - }) - describe('accessibility', () => { - it('is visible when rendered', () => { - const { container } = render() - - expect(container.firstChild).toBeVisible() - }) - }) -}) +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { Avatar } from "./avatar"; + +describe("Avatar", () => { + describe("rendering", () => { + it("renders correctly", () => { + const { container } = render(); + + expect(container.firstChild).toBeInTheDocument(); + }); + + it("applies custom className", () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass("custom-class"); + }); + }); + + describe("ref forwarding", () => { + it("forwards ref to DOM element", () => { + const ref = { current: null }; + render(); + + expect(ref.current).toBeInstanceOf(HTMLElement); + }); + }); + describe("accessibility", () => { + it("is visible when rendered", () => { + const { container } = render(); + + expect(container.firstChild).toBeVisible(); + }); + }); +}); diff --git a/packages/ui/src/components/avatar/avatar.visual.tsx b/packages/ui/src/components/avatar/avatar.visual.tsx index f8d15ef..4e21a68 100644 --- a/packages/ui/src/components/avatar/avatar.visual.tsx +++ b/packages/ui/src/components/avatar/avatar.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Avatar } from './avatar' +import { Avatar } from "./avatar"; -test.describe('Avatar Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('avatar-default.png') - }) -}) +test.describe("Avatar Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("avatar-default.png"); + }); +}); diff --git a/packages/ui/src/components/blog-card/blog-card.visual.tsx b/packages/ui/src/components/blog-card/blog-card.visual.tsx index c1ba411..aa9562f 100644 --- a/packages/ui/src/components/blog-card/blog-card.visual.tsx +++ b/packages/ui/src/components/blog-card/blog-card.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { BlogCard } from './blog-card' +import { BlogCard } from "./blog-card"; -test.describe('BlogCard Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('blog-card-default.png') - }) -}) +test.describe("BlogCard Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("blog-card-default.png"); + }); +}); diff --git a/packages/ui/src/components/breadcrumb/breadcrumb.visual.tsx b/packages/ui/src/components/breadcrumb/breadcrumb.visual.tsx index 76bacb2..d6c5160 100644 --- a/packages/ui/src/components/breadcrumb/breadcrumb.visual.tsx +++ b/packages/ui/src/components/breadcrumb/breadcrumb.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Breadcrumb } from './breadcrumb' +import { Breadcrumb } from "./breadcrumb"; -test.describe('Breadcrumb Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('breadcrumb-default.png') - }) -}) +test.describe("Breadcrumb Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("breadcrumb-default.png"); + }); +}); diff --git a/packages/ui/src/components/calendar/calendar.test.tsx b/packages/ui/src/components/calendar/calendar.test.tsx index 7799f32..00faa0e 100644 --- a/packages/ui/src/components/calendar/calendar.test.tsx +++ b/packages/ui/src/components/calendar/calendar.test.tsx @@ -1,29 +1,28 @@ -import { render } from '@testing-library/react' -import { describe, expect, it } from 'vitest' +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; -import { Calendar } from './calendar' +import { Calendar } from "./calendar"; -describe('Calendar', () => { - describe('rendering', () => { - it('renders correctly', () => { - const { container } = render() +describe("Calendar", () => { + describe("rendering", () => { + it("renders correctly", () => { + const { container } = render(); - expect(container.firstChild).toBeInTheDocument() - }) + expect(container.firstChild).toBeInTheDocument(); + }); - it('applies custom className', () => { - const { container } = render() + it("applies custom className", () => { + const { container } = render(); - expect(container.firstChild).toHaveClass('custom-class') - }) - }) + expect(container.firstChild).toHaveClass("custom-class"); + }); + }); + describe("accessibility", () => { + it("is visible when rendered", () => { + const { container } = render(); - describe('accessibility', () => { - it('is visible when rendered', () => { - const { container } = render() - - expect(container.firstChild).toBeVisible() - }) - }) -}) + expect(container.firstChild).toBeVisible(); + }); + }); +}); diff --git a/packages/ui/src/components/calendar/calendar.visual.tsx b/packages/ui/src/components/calendar/calendar.visual.tsx index 68a12cc..13bdea0 100644 --- a/packages/ui/src/components/calendar/calendar.visual.tsx +++ b/packages/ui/src/components/calendar/calendar.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Calendar } from './calendar' +import { Calendar } from "./calendar"; -test.describe('Calendar Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('calendar-default.png') - }) -}) +test.describe("Calendar Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("calendar-default.png"); + }); +}); diff --git a/packages/ui/src/components/carousel/carousel.test.tsx b/packages/ui/src/components/carousel/carousel.test.tsx index efe08cd..208755e 100644 --- a/packages/ui/src/components/carousel/carousel.test.tsx +++ b/packages/ui/src/components/carousel/carousel.test.tsx @@ -1,37 +1,36 @@ -import { render } from '@testing-library/react' -import { describe, expect, it } from 'vitest' - -import { Carousel } from './carousel' - -describe('Carousel', () => { - describe('rendering', () => { - it('renders correctly', () => { - const { container } = render() - - expect(container.firstChild).toBeInTheDocument() - }) - - it('applies custom className', () => { - const { container } = render() - - expect(container.firstChild).toHaveClass('custom-class') - }) - }) - - - describe('ref forwarding', () => { - it('forwards ref to DOM element', () => { - const ref = { current: null } - render() - - expect(ref.current).toBeInstanceOf(HTMLElement) - }) - }) - describe('accessibility', () => { - it('is visible when rendered', () => { - const { container } = render() - - expect(container.firstChild).toBeVisible() - }) - }) -}) +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { Carousel } from "./carousel"; + +describe("Carousel", () => { + describe("rendering", () => { + it("renders correctly", () => { + const { container } = render(); + + expect(container.firstChild).toBeInTheDocument(); + }); + + it("applies custom className", () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass("custom-class"); + }); + }); + + describe("ref forwarding", () => { + it("forwards ref to DOM element", () => { + const ref = { current: null }; + render(); + + expect(ref.current).toBeInstanceOf(HTMLElement); + }); + }); + describe("accessibility", () => { + it("is visible when rendered", () => { + const { container } = render(); + + expect(container.firstChild).toBeVisible(); + }); + }); +}); diff --git a/packages/ui/src/components/carousel/carousel.visual.tsx b/packages/ui/src/components/carousel/carousel.visual.tsx index c3def12..cf84951 100644 --- a/packages/ui/src/components/carousel/carousel.visual.tsx +++ b/packages/ui/src/components/carousel/carousel.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Carousel } from './carousel' +import { Carousel } from "./carousel"; -test.describe('Carousel Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('carousel-default.png') - }) -}) +test.describe("Carousel Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("carousel-default.png"); + }); +}); diff --git a/packages/ui/src/components/category-filter/category-filter.visual.tsx b/packages/ui/src/components/category-filter/category-filter.visual.tsx index 86b8e77..32294b0 100644 --- a/packages/ui/src/components/category-filter/category-filter.visual.tsx +++ b/packages/ui/src/components/category-filter/category-filter.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { CategoryFilter } from './category-filter' +import { CategoryFilter } from "./category-filter"; -test.describe('CategoryFilter Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('category-filter-default.png') - }) -}) +test.describe("CategoryFilter Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("category-filter-default.png"); + }); +}); diff --git a/packages/ui/src/components/checklist/checklist.visual.tsx b/packages/ui/src/components/checklist/checklist.visual.tsx index 97a53f9..00bf3cf 100644 --- a/packages/ui/src/components/checklist/checklist.visual.tsx +++ b/packages/ui/src/components/checklist/checklist.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Checklist } from './checklist' +import { Checklist } from "./checklist"; -test.describe('Checklist Visual', () => { - test('default', async ({ mount, page }) => { - await mount(Test) - await expect(page).toHaveScreenshot('checklist-default.png') - }) -}) +test.describe("Checklist Visual", () => { + test("default", async ({ mount, page }) => { + await mount(Test); + await expect(page).toHaveScreenshot("checklist-default.png"); + }); +}); diff --git a/packages/ui/src/components/code-playground/code-playground.visual.tsx b/packages/ui/src/components/code-playground/code-playground.visual.tsx index c1bf674..af1fb6c 100644 --- a/packages/ui/src/components/code-playground/code-playground.visual.tsx +++ b/packages/ui/src/components/code-playground/code-playground.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { CodePlayground } from './code-playground' +import { CodePlayground } from "./code-playground"; -test.describe('CodePlayground Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('code-playground-default.png') - }) -}) +test.describe("CodePlayground Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("code-playground-default.png"); + }); +}); diff --git a/packages/ui/src/components/collapsible/collapsible.test.tsx b/packages/ui/src/components/collapsible/collapsible.test.tsx index eb71450..5039c94 100644 --- a/packages/ui/src/components/collapsible/collapsible.test.tsx +++ b/packages/ui/src/components/collapsible/collapsible.test.tsx @@ -1,29 +1,28 @@ -import { render } from '@testing-library/react' -import { describe, expect, it } from 'vitest' +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; -import { Collapsible } from './collapsible' +import { Collapsible } from "./collapsible"; -describe('Collapsible', () => { - describe('rendering', () => { - it('renders correctly', () => { - const { container } = render() +describe("Collapsible", () => { + describe("rendering", () => { + it("renders correctly", () => { + const { container } = render(); - expect(container.firstChild).toBeInTheDocument() - }) + expect(container.firstChild).toBeInTheDocument(); + }); - it('applies custom className', () => { - const { container } = render() + it("applies custom className", () => { + const { container } = render(); - expect(container.firstChild).toHaveClass('custom-class') - }) - }) + expect(container.firstChild).toHaveClass("custom-class"); + }); + }); + describe("accessibility", () => { + it("is visible when rendered", () => { + const { container } = render(); - describe('accessibility', () => { - it('is visible when rendered', () => { - const { container } = render() - - expect(container.firstChild).toBeVisible() - }) - }) -}) + expect(container.firstChild).toBeVisible(); + }); + }); +}); diff --git a/packages/ui/src/components/collapsible/collapsible.visual.tsx b/packages/ui/src/components/collapsible/collapsible.visual.tsx index 5aa2ab2..9d76b67 100644 --- a/packages/ui/src/components/collapsible/collapsible.visual.tsx +++ b/packages/ui/src/components/collapsible/collapsible.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Collapsible } from './collapsible' +import { Collapsible } from "./collapsible"; -test.describe('Collapsible Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('collapsible-default.png') - }) -}) +test.describe("Collapsible Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("collapsible-default.png"); + }); +}); diff --git a/packages/ui/src/components/comparison/comparison.visual.tsx b/packages/ui/src/components/comparison/comparison.visual.tsx index fec35c4..9613689 100644 --- a/packages/ui/src/components/comparison/comparison.visual.tsx +++ b/packages/ui/src/components/comparison/comparison.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Comparison } from './comparison' +import { Comparison } from "./comparison"; -test.describe('Comparison Visual', () => { - test('default', async ({ mount, page }) => { - await mount(Test) - await expect(page).toHaveScreenshot('comparison-default.png') - }) -}) +test.describe("Comparison Visual", () => { + test("default", async ({ mount, page }) => { + await mount(Test); + await expect(page).toHaveScreenshot("comparison-default.png"); + }); +}); diff --git a/packages/ui/src/components/completion-dialog/completion-dialog.visual.tsx b/packages/ui/src/components/completion-dialog/completion-dialog.visual.tsx index 1b8ba4f..4490ab9 100644 --- a/packages/ui/src/components/completion-dialog/completion-dialog.visual.tsx +++ b/packages/ui/src/components/completion-dialog/completion-dialog.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { CompletionDialog } from './completion-dialog' +import { CompletionDialog } from "./completion-dialog"; -test.describe('CompletionDialog Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('completion-dialog-default.png') - }) -}) +test.describe("CompletionDialog Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("completion-dialog-default.png"); + }); +}); diff --git a/packages/ui/src/components/content-intro/content-intro.visual.tsx b/packages/ui/src/components/content-intro/content-intro.visual.tsx index 8ba106d..9d81f7b 100644 --- a/packages/ui/src/components/content-intro/content-intro.visual.tsx +++ b/packages/ui/src/components/content-intro/content-intro.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { ContentIntro } from './content-intro' +import { ContentIntro } from "./content-intro"; -test.describe('ContentIntro Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('content-intro-default.png') - }) -}) +test.describe("ContentIntro Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("content-intro-default.png"); + }); +}); diff --git a/packages/ui/src/components/context-menu/context-menu.visual.tsx b/packages/ui/src/components/context-menu/context-menu.visual.tsx index b9b47d2..27ec021 100644 --- a/packages/ui/src/components/context-menu/context-menu.visual.tsx +++ b/packages/ui/src/components/context-menu/context-menu.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { ContextMenu } from './context-menu' +import { ContextMenu } from "./context-menu"; -test.describe('ContextMenu Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('context-menu-default.png') - }) -}) +test.describe("ContextMenu Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("context-menu-default.png"); + }); +}); diff --git a/packages/ui/src/components/dialog/dialog.visual.tsx b/packages/ui/src/components/dialog/dialog.visual.tsx index 5c4469a..b558e00 100644 --- a/packages/ui/src/components/dialog/dialog.visual.tsx +++ b/packages/ui/src/components/dialog/dialog.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Dialog } from './dialog' +import { Dialog } from "./dialog"; -test.describe('Dialog Visual', () => { - test('default', async ({ mount, page }) => { - await mount(Test) - await expect(page).toHaveScreenshot('dialog-default.png') - }) -}) +test.describe("Dialog Visual", () => { + test("default", async ({ mount, page }) => { + await mount(Test); + await expect(page).toHaveScreenshot("dialog-default.png"); + }); +}); diff --git a/packages/ui/src/components/drawer/drawer.visual.tsx b/packages/ui/src/components/drawer/drawer.visual.tsx index 7c6fc51..0fe6c71 100644 --- a/packages/ui/src/components/drawer/drawer.visual.tsx +++ b/packages/ui/src/components/drawer/drawer.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Drawer } from './drawer' +import { Drawer } from "./drawer"; -test.describe('Drawer Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('drawer-default.png') - }) -}) +test.describe("Drawer Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("drawer-default.png"); + }); +}); diff --git a/packages/ui/src/components/dropdown-menu/dropdown-menu.visual.tsx b/packages/ui/src/components/dropdown-menu/dropdown-menu.visual.tsx index c784a5e..258cccf 100644 --- a/packages/ui/src/components/dropdown-menu/dropdown-menu.visual.tsx +++ b/packages/ui/src/components/dropdown-menu/dropdown-menu.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { DropdownMenu } from './dropdown-menu' +import { DropdownMenu } from "./dropdown-menu"; -test.describe('DropdownMenu Visual', () => { - test('default', async ({ mount, page }) => { - await mount(Test) - await expect(page).toHaveScreenshot('dropdown-menu-default.png') - }) -}) +test.describe("DropdownMenu Visual", () => { + test("default", async ({ mount, page }) => { + await mount(Test); + await expect(page).toHaveScreenshot("dropdown-menu-default.png"); + }); +}); diff --git a/packages/ui/src/components/exercise/exercise.visual.tsx b/packages/ui/src/components/exercise/exercise.visual.tsx index 1774b70..7667ab7 100644 --- a/packages/ui/src/components/exercise/exercise.visual.tsx +++ b/packages/ui/src/components/exercise/exercise.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Exercise } from './exercise' +import { Exercise } from "./exercise"; -test.describe('Exercise Visual', () => { - test('default', async ({ mount, page }) => { - await mount(Test) - await expect(page).toHaveScreenshot('exercise-default.png') - }) -}) +test.describe("Exercise Visual", () => { + test("default", async ({ mount, page }) => { + await mount(Test); + await expect(page).toHaveScreenshot("exercise-default.png"); + }); +}); diff --git a/packages/ui/src/components/faq/faq.visual.tsx b/packages/ui/src/components/faq/faq.visual.tsx index e2c7c85..a1db31f 100644 --- a/packages/ui/src/components/faq/faq.visual.tsx +++ b/packages/ui/src/components/faq/faq.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { FAQ } from './faq' +import { FAQ } from "./faq"; -test.describe('FAQ Visual', () => { - test('default', async ({ mount, page }) => { - await mount(Test) - await expect(page).toHaveScreenshot('faq-default.png') - }) -}) +test.describe("FAQ Visual", () => { + test("default", async ({ mount, page }) => { + await mount(Test); + await expect(page).toHaveScreenshot("faq-default.png"); + }); +}); diff --git a/packages/ui/src/components/filter-bar/filter-bar.visual.tsx b/packages/ui/src/components/filter-bar/filter-bar.visual.tsx index 2433067..4691f37 100644 --- a/packages/ui/src/components/filter-bar/filter-bar.visual.tsx +++ b/packages/ui/src/components/filter-bar/filter-bar.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { FilterBar } from './filter-bar' +import { FilterBar } from "./filter-bar"; -test.describe('FilterBar Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('filter-bar-default.png') - }) -}) +test.describe("FilterBar Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("filter-bar-default.png"); + }); +}); diff --git a/packages/ui/src/components/flow-diagram/flow-diagram.visual.tsx b/packages/ui/src/components/flow-diagram/flow-diagram.visual.tsx index 3665732..abecef1 100644 --- a/packages/ui/src/components/flow-diagram/flow-diagram.visual.tsx +++ b/packages/ui/src/components/flow-diagram/flow-diagram.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { FlowDiagram } from './flow-diagram' +import { FlowDiagram } from "./flow-diagram"; -test.describe('FlowDiagram Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('flow-diagram-default.png') - }) -}) +test.describe("FlowDiagram Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("flow-diagram-default.png"); + }); +}); diff --git a/packages/ui/src/components/hover-card/hover-card.visual.tsx b/packages/ui/src/components/hover-card/hover-card.visual.tsx index ce61c90..ad1a085 100644 --- a/packages/ui/src/components/hover-card/hover-card.visual.tsx +++ b/packages/ui/src/components/hover-card/hover-card.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { HoverCard } from './hover-card' +import { HoverCard } from "./hover-card"; -test.describe('HoverCard Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('hover-card-default.png') - }) -}) +test.describe("HoverCard Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("hover-card-default.png"); + }); +}); diff --git a/packages/ui/src/components/input-otp/input-otp.visual.tsx b/packages/ui/src/components/input-otp/input-otp.visual.tsx index 71a9943..cbbd1ee 100644 --- a/packages/ui/src/components/input-otp/input-otp.visual.tsx +++ b/packages/ui/src/components/input-otp/input-otp.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { InputOTP } from './input-otp' +import { InputOTP } from "./input-otp"; -test.describe('InputOTP Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('input-otp-default.png') - }) -}) +test.describe("InputOTP Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("input-otp-default.png"); + }); +}); diff --git a/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.visual.tsx b/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.visual.tsx index f177d95..6ae0935 100644 --- a/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.visual.tsx +++ b/packages/ui/src/components/keyboard-shortcuts-help/keyboard-shortcuts-help.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { KeyboardShortcutsHelp } from './keyboard-shortcuts-help' +import { KeyboardShortcutsHelp } from "./keyboard-shortcuts-help"; -test.describe('KeyboardShortcutsHelp Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('keyboard-shortcuts-help-default.png') - }) -}) +test.describe("KeyboardShortcutsHelp Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("keyboard-shortcuts-help-default.png"); + }); +}); diff --git a/packages/ui/src/components/label/label.visual.tsx b/packages/ui/src/components/label/label.visual.tsx index f8f8340..6471a4b 100644 --- a/packages/ui/src/components/label/label.visual.tsx +++ b/packages/ui/src/components/label/label.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Label } from './label' +import { Label } from "./label"; -test.describe('Label Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('label-default.png') - }) -}) +test.describe("Label Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("label-default.png"); + }); +}); diff --git a/packages/ui/src/components/lang-provider/lang-provider.visual.tsx b/packages/ui/src/components/lang-provider/lang-provider.visual.tsx index 4f13dbf..40c93b5 100644 --- a/packages/ui/src/components/lang-provider/lang-provider.visual.tsx +++ b/packages/ui/src/components/lang-provider/lang-provider.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { LangProvider } from './lang-provider' +import { LangProvider } from "./lang-provider"; -test.describe('LangProvider Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('lang-provider-default.png') - }) -}) +test.describe("LangProvider Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("lang-provider-default.png"); + }); +}); diff --git a/packages/ui/src/components/learning-objectives/learning-objectives.visual.tsx b/packages/ui/src/components/learning-objectives/learning-objectives.visual.tsx index 1a33ef9..0387b93 100644 --- a/packages/ui/src/components/learning-objectives/learning-objectives.visual.tsx +++ b/packages/ui/src/components/learning-objectives/learning-objectives.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { LearningObjectives } from './learning-objectives' +import { LearningObjectives } from "./learning-objectives"; -test.describe('LearningObjectives Visual', () => { - test('default', async ({ mount, page }) => { - await mount(Test) - await expect(page).toHaveScreenshot('learning-objectives-default.png') - }) -}) +test.describe("LearningObjectives Visual", () => { + test("default", async ({ mount, page }) => { + await mount(Test); + await expect(page).toHaveScreenshot("learning-objectives-default.png"); + }); +}); diff --git a/packages/ui/src/components/menubar/menubar.test.tsx b/packages/ui/src/components/menubar/menubar.test.tsx index ddb9e19..e8694d8 100644 --- a/packages/ui/src/components/menubar/menubar.test.tsx +++ b/packages/ui/src/components/menubar/menubar.test.tsx @@ -1,37 +1,36 @@ -import { render } from '@testing-library/react' -import { describe, expect, it } from 'vitest' - -import { Menubar } from './menubar' - -describe('Menubar', () => { - describe('rendering', () => { - it('renders correctly', () => { - const { container } = render() - - expect(container.firstChild).toBeInTheDocument() - }) - - it('applies custom className', () => { - const { container } = render() - - expect(container.firstChild).toHaveClass('custom-class') - }) - }) - - - describe('ref forwarding', () => { - it('forwards ref to DOM element', () => { - const ref = { current: null } - render() - - expect(ref.current).toBeInstanceOf(HTMLElement) - }) - }) - describe('accessibility', () => { - it('is visible when rendered', () => { - const { container } = render() - - expect(container.firstChild).toBeVisible() - }) - }) -}) +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { Menubar } from "./menubar"; + +describe("Menubar", () => { + describe("rendering", () => { + it("renders correctly", () => { + const { container } = render(); + + expect(container.firstChild).toBeInTheDocument(); + }); + + it("applies custom className", () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass("custom-class"); + }); + }); + + describe("ref forwarding", () => { + it("forwards ref to DOM element", () => { + const ref = { current: null }; + render(); + + expect(ref.current).toBeInstanceOf(HTMLElement); + }); + }); + describe("accessibility", () => { + it("is visible when rendered", () => { + const { container } = render(); + + expect(container.firstChild).toBeVisible(); + }); + }); +}); diff --git a/packages/ui/src/components/menubar/menubar.visual.tsx b/packages/ui/src/components/menubar/menubar.visual.tsx index ad4f8d6..ddc0f5b 100644 --- a/packages/ui/src/components/menubar/menubar.visual.tsx +++ b/packages/ui/src/components/menubar/menubar.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Menubar } from './menubar' +import { Menubar } from "./menubar"; -test.describe('Menubar Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('menubar-default.png') - }) -}) +test.describe("Menubar Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("menubar-default.png"); + }); +}); diff --git a/packages/ui/src/components/model-selector/model-selector.visual.tsx b/packages/ui/src/components/model-selector/model-selector.visual.tsx index d3103f1..79cb762 100644 --- a/packages/ui/src/components/model-selector/model-selector.visual.tsx +++ b/packages/ui/src/components/model-selector/model-selector.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { ModelSelector } from './model-selector' +import { ModelSelector } from "./model-selector"; -test.describe('ModelSelector Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('model-selector-default.png') - }) -}) +test.describe("ModelSelector Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("model-selector-default.png"); + }); +}); diff --git a/packages/ui/src/components/navbar-saas/navbar-saas.visual.tsx b/packages/ui/src/components/navbar-saas/navbar-saas.visual.tsx index 3d90e0b..ede5ed7 100644 --- a/packages/ui/src/components/navbar-saas/navbar-saas.visual.tsx +++ b/packages/ui/src/components/navbar-saas/navbar-saas.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { NavbarSaas } from './navbar-saas' +import { NavbarSaas } from "./navbar-saas"; -test.describe('NavbarSaas Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('navbar-saas-default.png') - }) -}) +test.describe("NavbarSaas Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("navbar-saas-default.png"); + }); +}); diff --git a/packages/ui/src/components/navigation-menu/navigation-menu.test.tsx b/packages/ui/src/components/navigation-menu/navigation-menu.test.tsx index 16c79bd..92406b8 100644 --- a/packages/ui/src/components/navigation-menu/navigation-menu.test.tsx +++ b/packages/ui/src/components/navigation-menu/navigation-menu.test.tsx @@ -1,37 +1,36 @@ -import { render } from '@testing-library/react' -import { describe, expect, it } from 'vitest' - -import { NavigationMenu } from './navigation-menu' - -describe('NavigationMenu', () => { - describe('rendering', () => { - it('renders correctly', () => { - const { container } = render() - - expect(container.firstChild).toBeInTheDocument() - }) - - it('applies custom className', () => { - const { container } = render() - - expect(container.firstChild).toHaveClass('custom-class') - }) - }) - - - describe('ref forwarding', () => { - it('forwards ref to DOM element', () => { - const ref = { current: null } - render() - - expect(ref.current).toBeInstanceOf(HTMLElement) - }) - }) - describe('accessibility', () => { - it('is visible when rendered', () => { - const { container } = render() - - expect(container.firstChild).toBeVisible() - }) - }) -}) +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { NavigationMenu } from "./navigation-menu"; + +describe("NavigationMenu", () => { + describe("rendering", () => { + it("renders correctly", () => { + const { container } = render(); + + expect(container.firstChild).toBeInTheDocument(); + }); + + it("applies custom className", () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass("custom-class"); + }); + }); + + describe("ref forwarding", () => { + it("forwards ref to DOM element", () => { + const ref = { current: null }; + render(); + + expect(ref.current).toBeInstanceOf(HTMLElement); + }); + }); + describe("accessibility", () => { + it("is visible when rendered", () => { + const { container } = render(); + + expect(container.firstChild).toBeVisible(); + }); + }); +}); diff --git a/packages/ui/src/components/navigation-menu/navigation-menu.visual.tsx b/packages/ui/src/components/navigation-menu/navigation-menu.visual.tsx index c95799e..eb00731 100644 --- a/packages/ui/src/components/navigation-menu/navigation-menu.visual.tsx +++ b/packages/ui/src/components/navigation-menu/navigation-menu.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { NavigationMenu } from './navigation-menu' +import { NavigationMenu } from "./navigation-menu"; -test.describe('NavigationMenu Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('navigation-menu-default.png') - }) -}) +test.describe("NavigationMenu Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("navigation-menu-default.png"); + }); +}); diff --git a/packages/ui/src/components/popover/popover.visual.tsx b/packages/ui/src/components/popover/popover.visual.tsx index a03d890..1ec68e7 100644 --- a/packages/ui/src/components/popover/popover.visual.tsx +++ b/packages/ui/src/components/popover/popover.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Popover } from './popover' +import { Popover } from "./popover"; -test.describe('Popover Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('popover-default.png') - }) -}) +test.describe("Popover Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("popover-default.png"); + }); +}); diff --git a/packages/ui/src/components/profile-section/profile-section.visual.tsx b/packages/ui/src/components/profile-section/profile-section.visual.tsx index 1248011..18d2906 100644 --- a/packages/ui/src/components/profile-section/profile-section.visual.tsx +++ b/packages/ui/src/components/profile-section/profile-section.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { ProfileSection } from './profile-section' +import { ProfileSection } from "./profile-section"; -test.describe('ProfileSection Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('profile-section-default.png') - }) -}) +test.describe("ProfileSection Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("profile-section-default.png"); + }); +}); diff --git a/packages/ui/src/components/progress-card/progress-card.visual.tsx b/packages/ui/src/components/progress-card/progress-card.visual.tsx index 03ac488..7507e11 100644 --- a/packages/ui/src/components/progress-card/progress-card.visual.tsx +++ b/packages/ui/src/components/progress-card/progress-card.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { ContentCard } from './progress-card' +import { ContentCard } from "./progress-card"; -test.describe('ContentCard Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('progress-card-default.png') - }) -}) +test.describe("ContentCard Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("progress-card-default.png"); + }); +}); diff --git a/packages/ui/src/components/quiz/quiz.visual.tsx b/packages/ui/src/components/quiz/quiz.visual.tsx index 1c40c68..031ba20 100644 --- a/packages/ui/src/components/quiz/quiz.visual.tsx +++ b/packages/ui/src/components/quiz/quiz.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Quiz } from './quiz' +import { Quiz } from "./quiz"; -test.describe('Quiz Visual', () => { - test('default', async ({ mount, page }) => { - await mount(Test) - await expect(page).toHaveScreenshot('quiz-default.png') - }) -}) +test.describe("Quiz Visual", () => { + test("default", async ({ mount, page }) => { + await mount(Test); + await expect(page).toHaveScreenshot("quiz-default.png"); + }); +}); diff --git a/packages/ui/src/components/radio-group/radio-group.test.tsx b/packages/ui/src/components/radio-group/radio-group.test.tsx index 7f456f3..94cb61f 100644 --- a/packages/ui/src/components/radio-group/radio-group.test.tsx +++ b/packages/ui/src/components/radio-group/radio-group.test.tsx @@ -1,37 +1,36 @@ -import { render } from '@testing-library/react' -import { describe, expect, it } from 'vitest' - -import { RadioGroup } from './radio-group' - -describe('RadioGroup', () => { - describe('rendering', () => { - it('renders correctly', () => { - const { container } = render() - - expect(container.firstChild).toBeInTheDocument() - }) - - it('applies custom className', () => { - const { container } = render() - - expect(container.firstChild).toHaveClass('custom-class') - }) - }) - - - describe('ref forwarding', () => { - it('forwards ref to DOM element', () => { - const ref = { current: null } - render() - - expect(ref.current).toBeInstanceOf(HTMLElement) - }) - }) - describe('accessibility', () => { - it('is visible when rendered', () => { - const { container } = render() - - expect(container.firstChild).toBeVisible() - }) - }) -}) +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { RadioGroup } from "./radio-group"; + +describe("RadioGroup", () => { + describe("rendering", () => { + it("renders correctly", () => { + const { container } = render(); + + expect(container.firstChild).toBeInTheDocument(); + }); + + it("applies custom className", () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass("custom-class"); + }); + }); + + describe("ref forwarding", () => { + it("forwards ref to DOM element", () => { + const ref = { current: null }; + render(); + + expect(ref.current).toBeInstanceOf(HTMLElement); + }); + }); + describe("accessibility", () => { + it("is visible when rendered", () => { + const { container } = render(); + + expect(container.firstChild).toBeVisible(); + }); + }); +}); diff --git a/packages/ui/src/components/radio-group/radio-group.visual.tsx b/packages/ui/src/components/radio-group/radio-group.visual.tsx index 8896a8d..1025a51 100644 --- a/packages/ui/src/components/radio-group/radio-group.visual.tsx +++ b/packages/ui/src/components/radio-group/radio-group.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { RadioGroup } from './radio-group' +import { RadioGroup } from "./radio-group"; -test.describe('RadioGroup Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('radio-group-default.png') - }) -}) +test.describe("RadioGroup Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("radio-group-default.png"); + }); +}); diff --git a/packages/ui/src/components/resizable/resizable.visual.tsx b/packages/ui/src/components/resizable/resizable.visual.tsx index c5c9a36..3d5c9e7 100644 --- a/packages/ui/src/components/resizable/resizable.visual.tsx +++ b/packages/ui/src/components/resizable/resizable.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { ResizableHandle } from './resizable' +import { ResizableHandle } from "./resizable"; -test.describe('ResizableHandle Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('resizable-default.png') - }) -}) +test.describe("ResizableHandle Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("resizable-default.png"); + }); +}); diff --git a/packages/ui/src/components/scroll-area/scroll-area.test.tsx b/packages/ui/src/components/scroll-area/scroll-area.test.tsx index 9690bd3..a82fe6c 100644 --- a/packages/ui/src/components/scroll-area/scroll-area.test.tsx +++ b/packages/ui/src/components/scroll-area/scroll-area.test.tsx @@ -1,37 +1,36 @@ -import { render } from '@testing-library/react' -import { describe, expect, it } from 'vitest' - -import { ScrollArea } from './scroll-area' - -describe('ScrollArea', () => { - describe('rendering', () => { - it('renders correctly', () => { - const { container } = render() - - expect(container.firstChild).toBeInTheDocument() - }) - - it('applies custom className', () => { - const { container } = render() - - expect(container.firstChild).toHaveClass('custom-class') - }) - }) - - - describe('ref forwarding', () => { - it('forwards ref to DOM element', () => { - const ref = { current: null } - render() - - expect(ref.current).toBeInstanceOf(HTMLElement) - }) - }) - describe('accessibility', () => { - it('is visible when rendered', () => { - const { container } = render() - - expect(container.firstChild).toBeVisible() - }) - }) -}) +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { ScrollArea } from "./scroll-area"; + +describe("ScrollArea", () => { + describe("rendering", () => { + it("renders correctly", () => { + const { container } = render(); + + expect(container.firstChild).toBeInTheDocument(); + }); + + it("applies custom className", () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass("custom-class"); + }); + }); + + describe("ref forwarding", () => { + it("forwards ref to DOM element", () => { + const ref = { current: null }; + render(); + + expect(ref.current).toBeInstanceOf(HTMLElement); + }); + }); + describe("accessibility", () => { + it("is visible when rendered", () => { + const { container } = render(); + + expect(container.firstChild).toBeVisible(); + }); + }); +}); diff --git a/packages/ui/src/components/scroll-area/scroll-area.visual.tsx b/packages/ui/src/components/scroll-area/scroll-area.visual.tsx index 0cef603..82a6018 100644 --- a/packages/ui/src/components/scroll-area/scroll-area.visual.tsx +++ b/packages/ui/src/components/scroll-area/scroll-area.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { ScrollArea } from './scroll-area' +import { ScrollArea } from "./scroll-area"; -test.describe('ScrollArea Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('scroll-area-default.png') - }) -}) +test.describe("ScrollArea Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("scroll-area-default.png"); + }); +}); diff --git a/packages/ui/src/components/search-bar/search-bar.visual.tsx b/packages/ui/src/components/search-bar/search-bar.visual.tsx index f743557..695325b 100644 --- a/packages/ui/src/components/search-bar/search-bar.visual.tsx +++ b/packages/ui/src/components/search-bar/search-bar.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { SearchBar } from './search-bar' +import { SearchBar } from "./search-bar"; -test.describe('SearchBar Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('search-bar-default.png') - }) -}) +test.describe("SearchBar Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("search-bar-default.png"); + }); +}); diff --git a/packages/ui/src/components/search-dialog/search-dialog.visual.tsx b/packages/ui/src/components/search-dialog/search-dialog.visual.tsx index fc89fc0..078e80d 100644 --- a/packages/ui/src/components/search-dialog/search-dialog.visual.tsx +++ b/packages/ui/src/components/search-dialog/search-dialog.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { SearchDialog } from './search-dialog' +import { SearchDialog } from "./search-dialog"; -test.describe('SearchDialog Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('search-dialog-default.png') - }) -}) +test.describe("SearchDialog Visual", () => { + test("default", async ({ mount, page }) => { + await mount(); + await expect(page).toHaveScreenshot("search-dialog-default.png"); + }); +}); diff --git a/packages/ui/src/components/select/select.visual.tsx b/packages/ui/src/components/select/select.visual.tsx index 5146f6a..1dfad2f 100644 --- a/packages/ui/src/components/select/select.visual.tsx +++ b/packages/ui/src/components/select/select.visual.tsx @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/experimental-ct-react' +import { expect, test } from "@playwright/experimental-ct-react"; -import { Select } from './select' +import { Select } from "./select"; -test.describe('Select Visual', () => { - test('default', async ({ mount, page }) => { - await mount() - await expect(page).toHaveScreenshot('select-default.png') - }) -}) +test.describe("Select Visual", () => { + test("default", async ({ mount, page }) => { + await mount() - - expect(container.firstChild).toBeInTheDocument() - }) - - it('applies custom className', () => { - const { container } = render() - - expect(container.firstChild).toHaveClass('custom-class') - }) - }) - - - describe('ref forwarding', () => { - it('forwards ref to DOM element', () => { - const ref = { current: null } - render() - - expect(ref.current).toBeInstanceOf(HTMLElement) - }) - }) - describe('accessibility', () => { - it('is visible when rendered', () => { - const { container } = render() - - expect(container.firstChild).toBeVisible() - }) - }) -}) +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { Textarea } from "./textarea"; + +describe("Textarea", () => { + describe("rendering", () => { + it("renders correctly", () => { + const { container } = render() - await expect(page).toHaveScreenshot('textarea-default.png') - }) -}) +test.describe("Textarea Visual", () => { + test("default", async ({ mount, page }) => { + await mount(