diff --git a/.github/workflows/test.yml b/.github/workflows/codecov-coverage.yml similarity index 75% rename from .github/workflows/test.yml rename to .github/workflows/codecov-coverage.yml index cd22b65d..3b05a3e1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/codecov-coverage.yml @@ -3,7 +3,6 @@ name: Run tests and upload coverage on: push: branches: - - develop - test pull_request: branches: @@ -37,10 +36,14 @@ jobs: - name: Install dependencies run: pnpm install - - name: Run tests + - name: Run tests with coverage run: pnpm vitest run --coverage - - name: Upload results to Codecov + - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 with: + working-directory: ../.. + files: coverage/apps-web/lcov.info + fail_ci_if_error: false + verbose: true token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/codecov-test.yml b/.github/workflows/codecov-test.yml new file mode 100644 index 00000000..5c7f0ef5 --- /dev/null +++ b/.github/workflows/codecov-test.yml @@ -0,0 +1,56 @@ +name: Codecov Test Results + +on: + push: + branches: + - test + pull_request: + branches: + - develop + - staging + workflow_dispatch: + +jobs: + test: + name: Run tests and upload results to Codecov + runs-on: ubuntu-latest + + defaults: + run: + working-directory: apps/web + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Install dependencies + run: pnpm install + + - name: Run tests with coverage and junit output + run: pnpm vitest run --coverage --reporter=junit --outputFile=test-report.junit.xml + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + working-directory: ../.. + files: coverage/apps-web/lcov.info + fail_ci_if_error: false + verbose: true + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Upload test results to Codecov + if: ${{ !cancelled() }} + uses: codecov/test-results-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + working-directory: apps/web diff --git a/.gitignore b/.gitignore index ba756d16..9dc2613f 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,7 @@ next-env.d.ts # apps/web apps/web/.env.sentry-build-plugin +apps/web/*.xml + +*storybook.log +storybook-static diff --git a/apps/web/.env.example b/apps/web/.env.example index 11bd1bd8..67a3f6de 100644 --- a/apps/web/.env.example +++ b/apps/web/.env.example @@ -13,3 +13,4 @@ VITE_API_TIMEOUT=30000 SENTRY_AUTH_TOKEN= +CODECOV_TOKEN= diff --git a/apps/web/.storybook/main.ts b/apps/web/.storybook/main.ts new file mode 100644 index 00000000..2c1c3d99 --- /dev/null +++ b/apps/web/.storybook/main.ts @@ -0,0 +1,27 @@ +import type { StorybookConfig } from '@storybook/react-vite' + +import { dirname } from 'path' + +import { fileURLToPath } from 'url' + +/** + * This function is used to resolve the absolute path of a package. + * It is needed in projects that use Yarn PnP or are set up within a monorepo. + */ +function getAbsolutePath(value: string): any { + return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`))) +} +const config: StorybookConfig = { + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: [ + getAbsolutePath('@chromatic-com/storybook'), + getAbsolutePath('@storybook/addon-docs'), + getAbsolutePath('@storybook/addon-a11y'), + getAbsolutePath('@storybook/addon-vitest'), + ], + framework: { + name: getAbsolutePath('@storybook/react-vite'), + options: {}, + }, +} +export default config diff --git a/apps/web/.storybook/preview.ts b/apps/web/.storybook/preview.ts new file mode 100644 index 00000000..1dcf872f --- /dev/null +++ b/apps/web/.storybook/preview.ts @@ -0,0 +1,14 @@ +import type { Preview } from '@storybook/react-vite' + +const preview: Preview = { + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + }, +} + +export default preview diff --git a/apps/web/eslint.config.js b/apps/web/eslint.config.js index 69da3ed0..d1aba66a 100644 --- a/apps/web/eslint.config.js +++ b/apps/web/eslint.config.js @@ -1,4 +1,6 @@ -import { config } from "@workspace/eslint-config/react-internal" - -/** @type {import("eslint").Linter.Config} */ -export default config +// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format + +import { config } from '@workspace/eslint-config/react-internal' + +/** @type {import("eslint").Linter.Config} */ +export default config diff --git a/apps/web/package.json b/apps/web/package.json index c5f984b7..53005249 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -6,7 +6,9 @@ "dev": "vite", "build": "vite build && tsc --noEmit", "serve": "vite preview", - "start": "vite" + "start": "vite", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" }, "dependencies": { "@hookform/resolvers": "^5.2.2", @@ -45,14 +47,28 @@ "zod": "^4.1.12" }, "devDependencies": { + "@chromatic-com/storybook": "^4.1.3", + "@codecov/vite-plugin": "^1.9.1", + "@storybook/addon-a11y": "^10.0.8", + "@storybook/addon-docs": "^10.0.8", + "@storybook/addon-vitest": "^10.0.8", + "@storybook/react-vite": "^10.0.8", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.0", + "@testing-library/user-event": "^14.6.1", "@types/js-cookie": "^3.0.6", "@types/node": "^24.10.0", "@types/react": "^19.1.9", "@types/react-dom": "^19.1.7", "@vitejs/plugin-react": "^4.3.4", + "@vitest/browser-playwright": "4.0.14", "@vitest/coverage-v8": "^4.0.14", "@workspace/eslint-config": "workspace:^", "@workspace/typescript-config": "workspace:*", + "eslint-plugin-storybook": "^10.0.8", + "jsdom": "^27.2.0", + "playwright": "^1.57.0", + "storybook": "^10.0.8", "typescript": "^5.9.2", "vite": "^7.1.7", "vitest": "^4.0.14" diff --git a/apps/web/src/feature/auth/component/SigninForm.test.tsx b/apps/web/src/feature/auth/component/SigninForm.test.tsx new file mode 100644 index 00000000..1d25b9ca --- /dev/null +++ b/apps/web/src/feature/auth/component/SigninForm.test.tsx @@ -0,0 +1,413 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +import { configureStore } from '@reduxjs/toolkit' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { render, screen, waitFor } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import { Provider } from 'react-redux' +import { beforeEach, describe, expect, it, vi } from 'vitest' +import appReducer from '../../app/store' +import authReducer from '../store' +import SignInForm from './SigninForm' + +// Mock TanStack Router +vi.mock('@tanstack/react-router', () => ({ + Link: ({ children, to, className }: any) => ( + + {children} + + ), + useNavigate: () => vi.fn(), +})) + +// Mock the toast function +vi.mock('@workspace/ui/components/Sonner', () => ({ + toast: { + warning: vi.fn(), + error: vi.fn(), + }, +})) + +// Mock the OAuth2 hook +vi.mock('../hook/useOAuth2', () => ({ + useGoogleOAuth2Config: () => ({ + data: { + authorizationUrl: 'https://accounts.google.com/oauth/authorize?test=true', + }, + isError: false, + error: null, + }), +})) + +// Mock window.location +Object.defineProperty(window, 'location', { + value: { + href: '', + }, + writable: true, +}) + +// Helper function to create a test store +const createTestStore = (initialState = {}) => { + return configureStore({ + reducer: { + auth: authReducer, + app: appReducer, + }, + preloadedState: { + auth: { + isLoading: false, + isAuthenticated: false, + userInfo: null, + errorMsg: null, + ...initialState.auth, + }, + app: { + isLoading: false, + theme: 'light', + language: 'vi', + sidebarOpen: false, + ...initialState.app, + }, + }, + }) +} + +// Wrapper component for tests +const TestWrapper = ({ children, store }: { children: React.ReactNode; store: any }) => { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + staleTime: 0, + }, + }, + }) + + return ( + + {children} + + ) +} + +describe('SignInForm', () => { + let store: any + const user = userEvent.setup() + + beforeEach(() => { + store = createTestStore() + vi.clearAllMocks() + }) + + describe('Rendering', () => { + it('should render all form elements', () => { + render( + + + , + ) + + expect(screen.getByText('Chào mừng trở lại!')).toBeInTheDocument() + expect(screen.getByText('Đăng nhập để truy cập tài khoản của bạn')).toBeInTheDocument() + expect(screen.getByPlaceholderText('Nhập email của bạn')).toBeInTheDocument() + expect(screen.getByPlaceholderText('Nhập mật khẩu của bạn')).toBeInTheDocument() + expect(screen.getByRole('button', { name: /đăng nhập với google/i })).toBeInTheDocument() + expect(screen.getByRole('button', { name: /đăng nhập$/i })).toBeInTheDocument() + expect(screen.getByText('Ghi nhớ đăng nhập')).toBeInTheDocument() + expect(screen.getByText('Quên mật khẩu?')).toBeInTheDocument() + expect(screen.getByText('Đăng ký ngay')).toBeInTheDocument() + }) + + it('should render logo images', () => { + render( + + + , + ) + + const logoImages = screen.getAllByAltText('Bithub Logo') + expect(logoImages).toHaveLength(2) // One for mobile, one for form + }) + }) + + describe('Form Validation', () => { + it('should show email validation error for invalid email', async () => { + render( + + + , + ) + + const emailInput = screen.getByPlaceholderText('Nhập email của bạn') + const submitButton = screen.getByRole('button', { name: /đăng nhập$/i }) + + await user.type(emailInput, 'invalid-email') + await user.click(submitButton) + + await waitFor(() => { + expect(screen.getByText('Email không hợp lệ')).toBeInTheDocument() + }) + }) + + it('should show email length validation error', async () => { + render( + + + , + ) + + const emailInput = screen.getByPlaceholderText('Nhập email của bạn') + const submitButton = screen.getByRole('button', { name: /đăng nhập$/i }) + + // Create an email longer than 50 characters + const longEmail = 'a'.repeat(40) + '@example.com' + await user.type(emailInput, longEmail) + await user.click(submitButton) + + await waitFor(() => { + expect(screen.getByText('Email không được vượt quá 50 ký tự')).toBeInTheDocument() + }) + }) + + it('should show password validation error for short password', async () => { + render( + + + , + ) + + const passwordInput = screen.getByPlaceholderText('Nhập mật khẩu của bạn') + const submitButton = screen.getByRole('button', { name: /đăng nhập$/i }) + + await user.type(passwordInput, 'ab') // Less than 3 characters + await user.click(submitButton) + + await waitFor(() => { + expect(screen.getByText('Mật khẩu phải có ít nhất 3 ký tự')).toBeInTheDocument() + }) + }) + + it('should show password length validation error', async () => { + render( + + + , + ) + + const passwordInput = screen.getByPlaceholderText('Nhập mật khẩu của bạn') + const submitButton = screen.getByRole('button', { name: /đăng nhập$/i }) + + const longPassword = 'a'.repeat(51) // More than 50 characters + await user.type(passwordInput, longPassword) + await user.click(submitButton) + + await waitFor(() => { + expect(screen.getByText('Mật khẩu không được vượt quá 50 ký tự')).toBeInTheDocument() + }) + }) + }) + + describe('User Interactions', () => { + it('should toggle password visibility', async () => { + render( + + + , + ) + + const passwordInput = screen.getByPlaceholderText('Nhập mật khẩu của bạn') + const toggleButton = screen.getByRole('button', { name: '' }) // Eye icon button + + expect(passwordInput).toHaveAttribute('type', 'password') + + await user.click(toggleButton) + expect(passwordInput).toHaveAttribute('type', 'text') + + await user.click(toggleButton) + expect(passwordInput).toHaveAttribute('type', 'password') + }) + + it('should allow typing in email and password fields', async () => { + render( + + + , + ) + + const emailInput = screen.getByPlaceholderText('Nhập email của bạn') + const passwordInput = screen.getByPlaceholderText('Nhập mật khẩu của bạn') + + await user.type(emailInput, 'test@example.com') + await user.type(passwordInput, 'password123') + + expect(emailInput).toHaveValue('test@example.com') + expect(passwordInput).toHaveValue('password123') + }) + + it('should handle Google OAuth button click', async () => { + render( + + + , + ) + + const googleButton = screen.getByRole('button', { name: /đăng nhập với google/i }) + + await user.click(googleButton) + + expect(window.location.href).toBe('https://accounts.google.com/oauth/authorize?test=true') + }) + }) + + describe('Loading State', () => { + it('should show loading overlay when isLoading is true', () => { + const loadingStore = createTestStore({ + auth: { isLoading: true }, + }) + + render( + + + , + ) + + const loadingTexts = screen.getAllByText('Đang đăng nhập...') + expect(loadingTexts).toHaveLength(2) // One in overlay, one in button + expect(screen.getByRole('button', { name: 'Đang đăng nhập...' })).toBeDisabled() + }) + + it('should show loading text on submit button when loading', () => { + const loadingStore = createTestStore({ + auth: { isLoading: true }, + }) + + render( + + + , + ) + + const submitButton = screen.getByRole('button', { name: 'Đang đăng nhập...' }) + expect(submitButton).toHaveTextContent('Đang đăng nhập...') + expect(submitButton).toBeDisabled() + }) + }) + + describe('Error State', () => { + it('should display error message when errorMsg is present', () => { + const errorStore = createTestStore({ + auth: { errorMsg: 'Email hoặc mật khẩu không đúng' }, + }) + + render( + + + , + ) + + expect(screen.getByText('Email hoặc mật khẩu không đúng')).toBeInTheDocument() + }) + + it('should not display error message when errorMsg is null', () => { + render( + + + , + ) + + expect(screen.queryByText('Email hoặc mật khẩu không đúng')).not.toBeInTheDocument() + }) + }) + + describe('Form Submission', () => { + it('should call onSubmit with valid form data', async () => { + const mockDispatch = vi.fn() + store.dispatch = mockDispatch + + render( + + + , + ) + + const emailInput = screen.getByPlaceholderText('Nhập email của bạn') + const passwordInput = screen.getByPlaceholderText('Nhập mật khẩu của bạn') + const submitButton = screen.getByRole('button', { name: /đăng nhập$/i }) + + await user.type(emailInput, 'test@example.com') + await user.type(passwordInput, 'password123') + await user.click(submitButton) + + await waitFor(() => { + expect(mockDispatch).toHaveBeenCalled() + }) + }) + + it('should not submit form with invalid data', async () => { + const mockDispatch = vi.fn() + store.dispatch = mockDispatch + + render( + + + , + ) + + const submitButton = screen.getByRole('button', { name: /đăng nhập$/i }) + await user.click(submitButton) + + // Should show validation errors but not call dispatch + await waitFor(() => { + expect(screen.getByText('Email không hợp lệ')).toBeInTheDocument() + }) + + expect(mockDispatch).not.toHaveBeenCalledWith( + expect.objectContaining({ + type: expect.stringContaining('requestLogin'), + }), + ) + }) + }) + + describe('Navigation Links', () => { + it('should render navigation links with correct text', () => { + render( + + + , + ) + + expect(screen.getByText('Trang chủ')).toBeInTheDocument() + expect(screen.getByText('Quên mật khẩu?')).toBeInTheDocument() + expect(screen.getByText('Đăng ký ngay')).toBeInTheDocument() + }) + }) + + describe('Accessibility', () => { + it('should have proper labels and roles', () => { + render( + + + , + ) + + expect(screen.getByPlaceholderText('Nhập email của bạn')).toBeInTheDocument() + expect(screen.getByPlaceholderText('Nhập mật khẩu của bạn')).toBeInTheDocument() + expect(screen.getByRole('checkbox')).toBeInTheDocument() + expect(screen.getByRole('button', { name: /đăng nhập với google/i })).toBeInTheDocument() + expect(screen.getByRole('button', { name: /đăng nhập$/i })).toBeInTheDocument() + }) + + it('should have required field indicators', () => { + render( + + + , + ) + + const requiredIndicators = screen.getAllByText('*') + expect(requiredIndicators).toHaveLength(2) // Email and password fields + }) + }) +}) diff --git a/apps/web/src/feature/auth/component/SigninForm.tsx b/apps/web/src/feature/auth/component/SigninForm.tsx index 4ad4bb6b..253796ec 100644 --- a/apps/web/src/feature/auth/component/SigninForm.tsx +++ b/apps/web/src/feature/auth/component/SigninForm.tsx @@ -1,295 +1,322 @@ -import { useAppDispatch } from '@/shared/redux/store' -import { zodResolver } from '@hookform/resolvers/zod' -import { Link, useNavigate } from '@tanstack/react-router' -import { Button } from '@workspace/ui/components/Button' -import { Checkbox } from '@workspace/ui/components/Checkbox' -import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@workspace/ui/components/Form' -import { Input } from '@workspace/ui/components/Input' -import { toast } from '@workspace/ui/components/Sonner' -import { Label } from '@workspace/ui/components/label' -import { ChevronLeftIcon, EyeClosedIcon, EyeIcon, Mail } from 'lucide-react' -import React from 'react' -import { useForm } from 'react-hook-form' -import { useSelector } from 'react-redux' -import { z } from 'zod' -import { setErrorAction } from '../../auth/store' -import { requestLogin } from '../../auth/store/auth.actions' -import { selectAuthStateInfo } from '../../auth/store/auth.selectors' -import { useGoogleOAuth2Config } from '../hook/useOAuth2' -import type { TLoginRequest } from '../type/authState' - -const formSchema = z.object({ - email: z - .string() - .max(50, { message: 'Email không được vượt quá 50 ký tự' }) - .email({ message: 'Email không hợp lệ' }), - password: z - .string() - .min(3, { message: 'Mật khẩu phải có ít nhất 3 ký tự' }) - .max(50, { message: 'Mật khẩu không được vượt quá 50 ký tự' }), -}) - -const SignInForm: React.FC = () => { - const { isLoading, isAuthenticated } = useSelector(selectAuthStateInfo) - const [showPassword, setShowPassword] = React.useState(false) - const [hasRedirected, setHasRedirected] = React.useState(false) - const dispatch = useAppDispatch() - const navigate = useNavigate() - - // Fetch Google OAuth2 configuration using TanStack Query - const { data: googleOAuth2Config, isError: isOAuth2Error, error: oauthError } = useGoogleOAuth2Config() - const [hasShownOAuthError, setHasShownOAuthError] = React.useState(false) - - const form = useForm>({ - resolver: zodResolver(formSchema), - defaultValues: { - email: '', - password: '', - }, - }) - - React.useEffect(() => { - console.log('SignInForm: isAuthenticated changed:', isAuthenticated, 'hasRedirected:', hasRedirected) - if (isAuthenticated && !hasRedirected) { - console.log('SignInForm: Redirecting to home...') - setHasRedirected(true) - navigate({ to: '/' }) - } - }, [isAuthenticated, navigate, hasRedirected]) - - // Show OAuth error only once when it first occurs - React.useEffect(() => { - if (isOAuth2Error && !hasShownOAuthError) { - console.error('[OAuth2] Failed to load Google OAuth2 configuration:', oauthError) - setHasShownOAuthError(true) - // Don't show toast here - only show when user tries to click the button - } - }, [isOAuth2Error, hasShownOAuthError, oauthError]) - - async function onSubmit(values: z.infer) { - // Clear any previous errors - dispatch(setErrorAction(null)) - - const body: TLoginRequest = { - email: values.email, - password: values.password, - } - const result: any = await dispatch(requestLogin(body)) - - // Only show warning for activation - success/error toasts are handled in actions - if (result?.needsActivation) { - toast.warning({ - title: 'Tài khoản chưa kích hoạt', - description: result.message, - }) - } else if (result?.success === false) { - toast.error({ - title: 'Đăng nhập thất bại', - description: result.message, - }) - } - } - - return ( -
- {isLoading &&
} - - {/* Header */} -
- - - Trang chủ - -
- - {/* Main Content */} -
-
- {/* Logo for mobile */} -
-
- Bithub Logo -
-
- - {/* Form Card */} -
-
-
-
- Bithub Logo -
-
-

Chào mừng trở lại!

-

Đăng nhập để truy cập tài khoản của bạn

-
- -
- -
- -
-
-
-
-
- hoặc đăng nhập với email -
-
- -
- - ( - - - Email * - - -
- - -
-
- -
- )} - /> - - ( - - - Mật khẩu * - - -
-
-
-
- - -
-
- -
- )} - /> - -
-
- - -
- - Quên mật khẩu? - -
- - - - - -
-

- Chưa có tài khoản?{' '} - - Đăng ký ngay - -

-
-
-
-
-
- ) -} - -export default SignInForm +import { useAppDispatch } from '@/shared/redux/store' +import { zodResolver } from '@hookform/resolvers/zod' +import { Link, useNavigate } from '@tanstack/react-router' +import { Button } from '@workspace/ui/components/Button' +import { Checkbox } from '@workspace/ui/components/Checkbox' +import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@workspace/ui/components/Form' +import { Input } from '@workspace/ui/components/Input' +import { toast } from '@workspace/ui/components/Sonner' +import { Label } from '@workspace/ui/components/label' +import { ChevronLeftIcon, EyeClosedIcon, EyeIcon, Mail } from 'lucide-react' +import React from 'react' +import { useForm } from 'react-hook-form' +import { useSelector } from 'react-redux' +import { z } from 'zod' +import { setErrorAction } from '../../auth/store' +import { requestLogin } from '../../auth/store/auth.actions' +import { selectAuthStateInfo } from '../../auth/store/auth.selectors' +import { useGoogleOAuth2Config } from '../hook/useOAuth2' +import type { TLoginRequest } from '../type/authState' + +const formSchema = z.object({ + email: z + .string() + .max(50, { message: 'Email không được vượt quá 50 ký tự' }) + .email({ message: 'Email không hợp lệ' }), + password: z + .string() + .min(3, { message: 'Mật khẩu phải có ít nhất 3 ký tự' }) + .max(50, { message: 'Mật khẩu không được vượt quá 50 ký tự' }), +}) + +const SignInForm: React.FC = () => { + const { isLoading, isAuthenticated, errorMsg } = useSelector(selectAuthStateInfo) + const [showPassword, setShowPassword] = React.useState(false) + const [hasRedirected, setHasRedirected] = React.useState(false) + const dispatch = useAppDispatch() + const navigate = useNavigate() + + // Fetch Google OAuth2 configuration using TanStack Query + const { data: googleOAuth2Config, isError: isOAuth2Error, error: oauthError } = useGoogleOAuth2Config() + const [hasShownOAuthError, setHasShownOAuthError] = React.useState(false) + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + email: '', + password: '', + }, + }) + + React.useEffect(() => { + console.log('SignInForm: isAuthenticated changed:', isAuthenticated, 'hasRedirected:', hasRedirected) + if (isAuthenticated && !hasRedirected) { + console.log('SignInForm: Redirecting to home...') + setHasRedirected(true) + navigate({ to: '/' }) + } + }, [isAuthenticated, navigate, hasRedirected]) + + // Show OAuth error only once when it first occurs + React.useEffect(() => { + if (isOAuth2Error && !hasShownOAuthError) { + console.error('[OAuth2] Failed to load Google OAuth2 configuration:', oauthError) + setHasShownOAuthError(true) + // Don't show toast here - only show when user tries to click the button + } + }, [isOAuth2Error, hasShownOAuthError, oauthError]) + + async function onSubmit(values: z.infer) { + // Clear any previous errors + dispatch(setErrorAction(null)) + + const body: TLoginRequest = { + email: values.email, + password: values.password, + } + const result: any = await dispatch(requestLogin(body)) + + // Only show warning for activation - success/error toasts are handled in actions + if (result?.needsActivation) { + toast.warning({ + title: 'Tài khoản chưa kích hoạt', + description: result.message, + }) + } else if (result?.success === false) { + toast.error({ + title: 'Đăng nhập thất bại', + description: result.message, + }) + } + } + + return ( +
+ {isLoading && ( +
+
+
+

Đang đăng nhập...

+
+
+ )} + + {/* Header */} +
+ + + Trang chủ + +
+ + {/* Main Content */} +
+
+ {/* Logo for mobile */} +
+
+ Bithub Logo +
+
+ + {/* Form Card */} +
+
+
+
+ Bithub Logo +
+
+

Chào mừng trở lại!

+

Đăng nhập để truy cập tài khoản của bạn

+
+ + {/* Error Display */} + {errorMsg && ( +
+
+
+ + + +
+
+

{errorMsg}

+
+
+
+ )} + +
+ +
+ +
+
+
+
+
+ hoặc đăng nhập với email +
+
+ +
+ + ( + + + Email * + + +
+ + +
+
+ +
+ )} + /> + + ( + + + Mật khẩu * + + +
+
+
+
+ + +
+
+ +
+ )} + /> + +
+
+ + +
+ + Quên mật khẩu? + +
+ + + + + +
+

+ Chưa có tài khoản?{' '} + + Đăng ký ngay + +

+
+
+
+
+
+ ) +} + +export default SignInForm diff --git a/apps/web/src/feature/auth/component/SigninForm.validation.test.ts b/apps/web/src/feature/auth/component/SigninForm.validation.test.ts new file mode 100644 index 00000000..296705cf --- /dev/null +++ b/apps/web/src/feature/auth/component/SigninForm.validation.test.ts @@ -0,0 +1,130 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +import { describe, expect, it } from 'vitest' +import { z } from 'zod' + +// Import the form schema from SigninForm (we'll extract it) +const formSchema = z.object({ + email: z + .string() + .max(50, { message: 'Email không được vượt quá 50 ký tự' }) + .email({ message: 'Email không hợp lệ' }), + password: z + .string() + .min(3, { message: 'Mật khẩu phải có ít nhất 3 ký tự' }) + .max(50, { message: 'Mật khẩu không được vượt quá 50 ký tự' }), +}) + +describe('SignIn Form Validation', () => { + describe('Email validation', () => { + it('should accept valid email addresses', () => { + const validEmails = [ + 'test@example.com', + 'user.name@domain.co.uk', + 'firstname+lastname@company.org', + 'a@b.co', + ] + + validEmails.forEach(email => { + const result = formSchema.shape.email.safeParse(email) + expect(result.success).toBe(true) + }) + }) + + it('should reject invalid email addresses', () => { + const invalidEmails = ['invalid-email', '@domain.com', 'user@', 'user.domain.com', ''] + + invalidEmails.forEach(email => { + const result = formSchema.shape.email.safeParse(email) + expect(result.success).toBe(false) + if (!result.success) { + expect(result.error?.issues[0].message).toBe('Email không hợp lệ') + } + }) + }) + + it('should reject emails longer than 50 characters', () => { + const longEmail = 'a'.repeat(40) + '@example.com' // 51 characters + const result = formSchema.shape.email.safeParse(longEmail) + + expect(result.success).toBe(false) + if (!result.success) { + expect(result.error?.issues[0].message).toBe('Email không được vượt quá 50 ký tự') + } + }) + }) + + describe('Password validation', () => { + it('should accept valid passwords', () => { + const validPasswords = [ + 'abc', + 'password123', + 'MySecurePassword!', + '123', + 'a'.repeat(50), // Exactly 50 characters + ] + + validPasswords.forEach(password => { + const result = formSchema.shape.password.safeParse(password) + expect(result.success).toBe(true) + }) + }) + + it('should reject passwords shorter than 3 characters', () => { + const shortPasswords = ['', 'a', 'ab'] + + shortPasswords.forEach(password => { + const result = formSchema.shape.password.safeParse(password) + expect(result.success).toBe(false) + if (!result.success) { + expect(result.error?.issues[0].message).toBe('Mật khẩu phải có ít nhất 3 ký tự') + } + }) + }) + + it('should reject passwords longer than 50 characters', () => { + const longPassword = 'a'.repeat(51) + const result = formSchema.shape.password.safeParse(longPassword) + + expect(result.success).toBe(false) + if (!result.success) { + expect(result.error?.issues[0].message).toBe('Mật khẩu không được vượt quá 50 ký tự') + } + }) + }) + + describe('Complete form validation', () => { + it('should validate complete valid form data', () => { + const validData = { + email: 'test@example.com', + password: 'password123', + } + + const result = formSchema.safeParse(validData) + expect(result.success).toBe(true) + }) + + it('should reject form with invalid data', () => { + const invalidData = { + email: 'invalid-email', + password: 'ab', + } + + const result = formSchema.safeParse(invalidData) + expect(result.success).toBe(false) + if (!result.success) { + expect(result.error.issues).toHaveLength(2) // Both email and password errors + } + }) + + it('should handle missing fields', () => { + const incompleteData = { + email: 'test@example.com', + // password missing + } + + const result = formSchema.safeParse(incompleteData) + expect(result.success).toBe(false) + }) + }) +}) diff --git a/apps/web/src/shared/lib/string-utils.test.ts b/apps/web/src/shared/lib/string-utils.test.ts new file mode 100644 index 00000000..3c83e597 --- /dev/null +++ b/apps/web/src/shared/lib/string-utils.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, it } from 'vitest' +import { mergeName } from './string-utils' + +describe('String Utils', () => { + describe('mergeName', () => { + it('should merge first and last name correctly', () => { + const result = mergeName('John', 'Doe') + expect(result).toBe('John Doe') + }) + + it('should handle empty first name', () => { + const result = mergeName('', 'Doe') + expect(result).toBe(' Doe') + }) + + it('should handle empty last name', () => { + const result = mergeName('John', '') + expect(result).toBe('John ') + }) + + it('should handle both empty names', () => { + const result = mergeName('', '') + expect(result).toBe(' ') + }) + + it('should handle undefined names', () => { + const result = mergeName(undefined as any, undefined as any) + expect(result).toBe('undefined undefined') + }) + }) +}) diff --git a/apps/web/src/stories/Button.stories.ts b/apps/web/src/stories/Button.stories.ts new file mode 100644 index 00000000..fa4548ab --- /dev/null +++ b/apps/web/src/stories/Button.stories.ts @@ -0,0 +1,54 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' + +import { fn } from 'storybook/test' + +import { Button } from './Button' + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export +const meta = { + title: 'Example/Button', + component: Button, + parameters: { + // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout + layout: 'centered', + }, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + // More on argTypes: https://storybook.js.org/docs/api/argtypes + argTypes: { + backgroundColor: { control: 'color' }, + }, + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args + args: { onClick: fn() }, +} satisfies Meta + +export default meta +type Story = StoryObj + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary: Story = { + args: { + primary: true, + label: 'Button', + }, +} + +export const Secondary: Story = { + args: { + label: 'Button', + }, +} + +export const Large: Story = { + args: { + size: 'large', + label: 'Button', + }, +} + +export const Small: Story = { + args: { + size: 'small', + label: 'Button', + }, +} diff --git a/apps/web/src/stories/Button.tsx b/apps/web/src/stories/Button.tsx new file mode 100644 index 00000000..68e3d4f3 --- /dev/null +++ b/apps/web/src/stories/Button.tsx @@ -0,0 +1,29 @@ +import './button.css' + +export interface ButtonProps { + /** Is this the principal call to action on the page? */ + primary?: boolean + /** What background color to use */ + backgroundColor?: string + /** How large should the button be? */ + size?: 'small' | 'medium' | 'large' + /** Button contents */ + label: string + /** Optional click handler */ + onClick?: () => void +} + +/** Primary UI component for user interaction */ +export const Button = ({ primary = false, size = 'medium', backgroundColor, label, ...props }: ButtonProps) => { + const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary' + return ( + + ) +} diff --git a/apps/web/src/stories/Configure.mdx b/apps/web/src/stories/Configure.mdx new file mode 100644 index 00000000..dca091c1 --- /dev/null +++ b/apps/web/src/stories/Configure.mdx @@ -0,0 +1,364 @@ +import { Meta } from "@storybook/addon-docs/blocks"; + +import Github from "./assets/github.svg"; +import Discord from "./assets/discord.svg"; +import Youtube from "./assets/youtube.svg"; +import Tutorials from "./assets/tutorials.svg"; +import Styling from "./assets/styling.png"; +import Context from "./assets/context.png"; +import Assets from "./assets/assets.png"; +import Docs from "./assets/docs.png"; +import Share from "./assets/share.png"; +import FigmaPlugin from "./assets/figma-plugin.png"; +import Testing from "./assets/testing.png"; +import Accessibility from "./assets/accessibility.png"; +import Theming from "./assets/theming.png"; +import AddonLibrary from "./assets/addon-library.png"; + +export const RightArrow = () => + + + + + +
+
+ # Configure your project + + Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community. +
+
+
+ A wall of logos representing different styling technologies +

Add styling and CSS

+

Like with web applications, there are many ways to include CSS within Storybook. Learn more about setting up styling within Storybook.

+ Learn more +
+
+ An abstraction representing the composition of data for a component +

Provide context and mocking

+

Often when a story doesn't render, it's because your component is expecting a specific environment or context (like a theme provider) to be available.

+ Learn more +
+
+ A representation of typography and image assets +
+

Load assets and resources

+

To link static files (like fonts) to your projects and stories, use the + `staticDirs` configuration option to specify folders to load when + starting Storybook.

+ Learn more +
+
+
+
+
+
+ # Do more with Storybook + + Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs. +
+ +
+
+
+ A screenshot showing the autodocs tag being set, pointing a docs page being generated +

Autodocs

+

Auto-generate living, + interactive reference documentation from your components and stories.

+ Learn more +
+
+ A browser window showing a Storybook being published to a chromatic.com URL +

Publish to Chromatic

+

Publish your Storybook to review and collaborate with your entire team.

+ Learn more +
+
+ Windows showing the Storybook plugin in Figma +

Figma Plugin

+

Embed your stories into Figma to cross-reference the design and live + implementation in one place.

+ Learn more +
+
+ Screenshot of tests passing and failing +

Testing

+

Use stories to test a component in all its variations, no matter how + complex.

+ Learn more +
+
+ Screenshot of accessibility tests passing and failing +

Accessibility

+

Automatically test your components for a11y issues as you develop.

+ Learn more +
+
+ Screenshot of Storybook in light and dark mode +

Theming

+

Theme Storybook's UI to personalize it to your project.

+ Learn more +
+
+
+
+
+
+

Addons

+

Integrate your tools with Storybook to connect workflows.

+ Discover all addons +
+
+ Integrate your tools with Storybook to connect workflows. +
+
+ +
+
+ Github logo + Join our contributors building the future of UI development. + + Star on GitHub +
+
+ Discord logo +
+ Get support and chat with frontend developers. + + Join Discord server +
+
+
+ Youtube logo +
+ Watch tutorials, feature previews and interviews. + + Watch on YouTube +
+
+
+ A book +

Follow guided walkthroughs on for key workflows.

+ + Discover tutorials +
+
+ + diff --git a/apps/web/src/stories/Header.stories.ts b/apps/web/src/stories/Header.stories.ts new file mode 100644 index 00000000..aece3db3 --- /dev/null +++ b/apps/web/src/stories/Header.stories.ts @@ -0,0 +1,34 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' + +import { fn } from 'storybook/test' + +import { Header } from './Header' + +const meta = { + title: 'Example/Header', + component: Header, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, +} satisfies Meta + +export default meta +type Story = StoryObj + +export const LoggedIn: Story = { + args: { + user: { + name: 'Jane Doe', + }, + }, +} + +export const LoggedOut: Story = {} diff --git a/apps/web/src/stories/Header.tsx b/apps/web/src/stories/Header.tsx new file mode 100644 index 00000000..bcd12af8 --- /dev/null +++ b/apps/web/src/stories/Header.tsx @@ -0,0 +1,48 @@ +import { Button } from './Button' +import './header.css' + +type User = { + name: string +} + +export interface HeaderProps { + user?: User + onLogin?: () => void + onLogout?: () => void + onCreateAccount?: () => void +} + +export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => ( +
+
+
+ + + + + + + +

Acme

+
+
+ {user ? ( + <> + + Welcome, {user.name}! + +
+
+
+) diff --git a/apps/web/src/stories/LoginPage.stories.tsx b/apps/web/src/stories/LoginPage.stories.tsx new file mode 100644 index 00000000..be8dffb3 --- /dev/null +++ b/apps/web/src/stories/LoginPage.stories.tsx @@ -0,0 +1,531 @@ +import { configureStore } from '@reduxjs/toolkit' +import type { Meta, StoryObj } from '@storybook/react-vite' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { RouterProvider, createMemoryHistory, createRootRoute, createRouter } from '@tanstack/react-router' +import '@workspace/ui/globals.css' +import { Provider } from 'react-redux' +import appReducer from '../feature/app/store' +import SignInForm from '../feature/auth/component/SigninForm' +import authReducer from '../feature/auth/store' + +// Create a mock Redux store with proper reducers +const createMockStore = (initialState = {}) => + configureStore({ + reducer: { + auth: authReducer, + app: appReducer, + }, + preloadedState: initialState, + }) + +// Create QueryClient with mock handlers +const createQueryClient = (mockOAuthConfig?: any) => + new QueryClient({ + defaultOptions: { + queries: { + retry: false, + staleTime: 0, + }, + }, + }) + +// Wrapper component with all necessary providers +interface LoginPageWrapperProps { + initialState?: any + mockOAuthConfig?: { + authorizationUrl?: string + isError?: boolean + } + onSubmit?: (values: any) => void +} + +const LoginPageWrapper = ({ initialState = {}, mockOAuthConfig, onSubmit }: LoginPageWrapperProps) => { + const store = createMockStore(initialState) + const queryClient = createQueryClient(mockOAuthConfig) + + // Create a minimal router setup + const rootRoute = createRootRoute({ + component: () => ( +
+
+ +
+
+ ), + }) + + const router = createRouter({ + routeTree: rootRoute, + history: createMemoryHistory({ + initialEntries: ['/signin'], + }), + }) + + return ( + + + + + + ) +} + +const meta = { + title: 'Pages/Authentication/SignIn', + component: LoginPageWrapper, + parameters: { + layout: 'fullscreen', + docs: { + description: { + component: ` +# Sign In Page + +A comprehensive authentication page featuring: +- Email/password login +- Google OAuth integration +- Form validation with Zod +- Remember me functionality +- Password visibility toggle +- Responsive design for mobile, tablet, and desktop + +## Features +- 📧 Email/password authentication +- 🔐 Secure password input with show/hide toggle +- 🔄 Loading states +- ⚠️ Error handling and display +- 📱 Fully responsive design +- 🎨 Modern UI with Tailwind CSS +- ♿ Accessible form controls + `, + }, + }, + }, + tags: ['autodocs'], + argTypes: { + initialState: { + description: 'Initial Redux state for the component', + control: 'object', + }, + mockOAuthConfig: { + description: 'Mock OAuth configuration for testing', + control: 'object', + }, + }, +} satisfies Meta + +export default meta +type Story = StoryObj + +// Default state +const defaultAuthState = { + auth: { + isLoading: false, + isAuthenticated: false, + userInfo: null, + errorMsg: null, + }, + app: { + isLoading: false, + theme: 'light', + language: 'vi', + sidebarOpen: false, + }, +} + +/** + * Default sign-in page state + */ +export const Default: Story = { + args: { + initialState: defaultAuthState, + }, +} + +/** + * Loading state while authenticating + */ +export const Loading: Story = { + args: { + initialState: { + auth: { + isLoading: true, + isAuthenticated: false, + userInfo: null, + errorMsg: null, + }, + app: defaultAuthState.app, + }, + }, + parameters: { + docs: { + description: { + story: 'Shows the loading state when the user submits the login form', + }, + }, + }, +} + +/** + * Error state - Invalid credentials + */ +export const WithInvalidCredentialsError: Story = { + args: { + initialState: { + auth: { + isLoading: false, + isAuthenticated: false, + userInfo: null, + errorMsg: 'Email hoặc mật khẩu không đúng', + }, + app: defaultAuthState.app, + }, + }, + parameters: { + docs: { + description: { + story: 'Displays error message when user enters incorrect credentials', + }, + }, + }, +} + +/** + * Error state - Account not activated + */ +export const AccountNotActivated: Story = { + args: { + initialState: { + auth: { + isLoading: false, + isAuthenticated: false, + userInfo: null, + errorMsg: 'Tài khoản chưa được kích hoạt. Vui lòng kiểm tra email để kích hoạt.', + }, + app: defaultAuthState.app, + }, + }, + parameters: { + docs: { + description: { + story: 'Shows warning when account needs activation', + }, + }, + }, +} + +/** + * Error state - Network error + */ +export const NetworkError: Story = { + args: { + initialState: { + auth: { + isLoading: false, + isAuthenticated: false, + userInfo: null, + errorMsg: 'Không thể kết nối đến máy chủ. Vui lòng kiểm tra kết nối mạng.', + }, + app: defaultAuthState.app, + }, + }, + parameters: { + docs: { + description: { + story: 'Handles network connectivity errors', + }, + }, + }, +} + +/** + * OAuth configuration error + */ +export const OAuthConfigError: Story = { + args: { + initialState: defaultAuthState, + mockOAuthConfig: { + isError: true, + }, + }, + parameters: { + docs: { + description: { + story: 'Shows disabled Google OAuth button when configuration fails', + }, + }, + }, +} + +/** + * Successfully authenticated + */ +export const Authenticated: Story = { + args: { + initialState: { + auth: { + isLoading: false, + isAuthenticated: true, + userInfo: { + id: '1', + email: 'user@example.com', + name: 'John Doe', + }, + errorMsg: null, + }, + app: defaultAuthState.app, + }, + }, + parameters: { + docs: { + description: { + story: 'User is successfully authenticated (will redirect to home)', + }, + }, + }, +} + +/** + * Mobile viewport (iPhone 12 Pro) + */ +export const Mobile: Story = { + args: { + initialState: defaultAuthState, + }, + parameters: { + viewport: { + defaultViewport: 'mobile1', + }, + docs: { + description: { + story: 'Sign-in page optimized for mobile devices (390x844)', + }, + }, + }, +} + +/** + * Tablet viewport (iPad) + */ +export const Tablet: Story = { + args: { + initialState: defaultAuthState, + }, + parameters: { + viewport: { + defaultViewport: 'tablet', + }, + docs: { + description: { + story: 'Sign-in page optimized for tablet devices (768x1024)', + }, + }, + }, +} + +/** + * Desktop large viewport + */ +export const DesktopLarge: Story = { + args: { + initialState: defaultAuthState, + }, + parameters: { + viewport: { + defaultViewport: 'desktop', + }, + docs: { + description: { + story: 'Sign-in page on large desktop screens (1920x1080)', + }, + }, + }, +} + +/** + * With pre-filled email (e.g., from signup) + */ +export const PreFilledEmail: Story = { + args: { + initialState: defaultAuthState, + }, + play: async ({ canvasElement }) => { + const canvas = canvasElement as HTMLElement + const emailInput = canvas.querySelector('input[type="email"]') as HTMLInputElement + if (emailInput) { + emailInput.value = 'user@example.com' + emailInput.dispatchEvent(new Event('input', { bubbles: true })) + } + }, + parameters: { + docs: { + description: { + story: 'Email field pre-filled (e.g., user coming from signup page)', + }, + }, + }, +} + +/** + * Password visible state + */ +export const PasswordVisible: Story = { + args: { + initialState: defaultAuthState, + }, + play: async ({ canvasElement }) => { + const canvas = canvasElement as HTMLElement + const toggleButton = canvas.querySelector('button[type="button"]') as HTMLButtonElement + if (toggleButton) { + toggleButton.click() + } + }, + parameters: { + docs: { + description: { + story: 'Shows password in plain text when visibility toggle is clicked', + }, + }, + }, +} + +/** + * Form validation - Invalid email + */ +export const ValidationInvalidEmail: Story = { + args: { + initialState: defaultAuthState, + }, + play: async ({ canvasElement }) => { + const canvas = canvasElement as HTMLElement + const emailInput = canvas.querySelector('input[type="email"]') as HTMLInputElement + const form = canvas.querySelector('form') as HTMLFormElement + + if (emailInput && form) { + emailInput.value = 'invalid-email' + emailInput.dispatchEvent(new Event('input', { bubbles: true })) + emailInput.dispatchEvent(new Event('blur', { bubbles: true })) + } + }, + parameters: { + docs: { + description: { + story: 'Shows validation error for invalid email format', + }, + }, + }, +} + +/** + * Form validation - Short password + */ +export const ValidationShortPassword: Story = { + args: { + initialState: defaultAuthState, + }, + play: async ({ canvasElement }) => { + const canvas = canvasElement as HTMLElement + const passwordInput = canvas.querySelector('input[type="password"]') as HTMLInputElement + + if (passwordInput) { + passwordInput.value = 'ab' + passwordInput.dispatchEvent(new Event('input', { bubbles: true })) + passwordInput.dispatchEvent(new Event('blur', { bubbles: true })) + } + }, + parameters: { + docs: { + description: { + story: 'Shows validation error when password is too short (< 3 characters)', + }, + }, + }, +} + +/** + * Dark mode (if supported) + */ +export const DarkMode: Story = { + args: { + initialState: { + auth: defaultAuthState.auth, + app: { + ...defaultAuthState.app, + theme: 'dark', + }, + }, + }, + parameters: { + backgrounds: { + default: 'dark', + }, + docs: { + description: { + story: 'Sign-in page with dark mode theme applied', + }, + }, + }, +} + +/** + * Accessibility test - Keyboard navigation + */ +export const KeyboardNavigation: Story = { + args: { + initialState: defaultAuthState, + }, + parameters: { + docs: { + description: { + story: 'All interactive elements are keyboard accessible (Tab, Enter, Space)', + }, + }, + a11y: { + config: { + rules: [ + { + id: 'color-contrast', + enabled: true, + }, + { + id: 'label', + enabled: true, + }, + ], + }, + }, + }, +} + +/** + * Loading with pre-filled form + */ +export const LoadingWithData: Story = { + args: { + initialState: { + auth: { + isLoading: true, + isAuthenticated: false, + userInfo: null, + errorMsg: null, + }, + app: defaultAuthState.app, + }, + }, + play: async ({ canvasElement }) => { + const canvas = canvasElement as HTMLElement + const emailInput = canvas.querySelector('input[type="email"]') as HTMLInputElement + const passwordInput = canvas.querySelector('input[type="password"]') as HTMLInputElement + + if (emailInput && passwordInput) { + emailInput.value = 'user@example.com' + passwordInput.value = 'password123' + } + }, + parameters: { + docs: { + description: { + story: 'Shows loading state with form data entered', + }, + }, + }, +} diff --git a/apps/web/src/stories/Page.stories.ts b/apps/web/src/stories/Page.stories.ts new file mode 100644 index 00000000..ac8122cb --- /dev/null +++ b/apps/web/src/stories/Page.stories.ts @@ -0,0 +1,33 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' + +import { expect, userEvent, within } from 'storybook/test' + +import { Page } from './Page' + +const meta = { + title: 'Example/Page', + component: Page, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +} satisfies Meta + +export default meta +type Story = StoryObj + +export const LoggedOut: Story = {} + +// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing +export const LoggedIn: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement) + const loginButton = canvas.getByRole('button', { name: /Log in/i }) + await expect(loginButton).toBeInTheDocument() + await userEvent.click(loginButton) + await expect(loginButton).not.toBeInTheDocument() + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }) + await expect(logoutButton).toBeInTheDocument() + }, +} diff --git a/apps/web/src/stories/Page.tsx b/apps/web/src/stories/Page.tsx new file mode 100644 index 00000000..7fe5ac29 --- /dev/null +++ b/apps/web/src/stories/Page.tsx @@ -0,0 +1,72 @@ +import React from 'react' + +import { Header } from './Header' +import './page.css' + +type User = { + name: string +} + +export const Page: React.FC = () => { + const [user, setUser] = React.useState() + + return ( +
+
setUser({ name: 'Jane Doe' })} + onLogout={() => setUser(undefined)} + onCreateAccount={() => setUser({ name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a{' '} + + component-driven + {' '} + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without needing to + navigate to them in your app. Here are some handy patterns for managing page data in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the "args" of + child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out using + Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at{' '} + + Storybook tutorials + + . Read more in the{' '} + + docs + + . +

+
+ Tip Adjust the width of the canvas with the{' '} + + + + + + Viewports addon in the toolbar +
+
+
+ ) +} diff --git a/apps/web/src/stories/assets/accessibility.png b/apps/web/src/stories/assets/accessibility.png new file mode 100644 index 00000000..6ffe6fea Binary files /dev/null and b/apps/web/src/stories/assets/accessibility.png differ diff --git a/apps/web/src/stories/assets/accessibility.svg b/apps/web/src/stories/assets/accessibility.svg new file mode 100644 index 00000000..107e93f8 --- /dev/null +++ b/apps/web/src/stories/assets/accessibility.svg @@ -0,0 +1 @@ +Accessibility \ No newline at end of file diff --git a/apps/web/src/stories/assets/addon-library.png b/apps/web/src/stories/assets/addon-library.png new file mode 100644 index 00000000..95deb38a Binary files /dev/null and b/apps/web/src/stories/assets/addon-library.png differ diff --git a/apps/web/src/stories/assets/assets.png b/apps/web/src/stories/assets/assets.png new file mode 100644 index 00000000..cfba6817 Binary files /dev/null and b/apps/web/src/stories/assets/assets.png differ diff --git a/apps/web/src/stories/assets/avif-test-image.avif b/apps/web/src/stories/assets/avif-test-image.avif new file mode 100644 index 00000000..530709bc Binary files /dev/null and b/apps/web/src/stories/assets/avif-test-image.avif differ diff --git a/apps/web/src/stories/assets/context.png b/apps/web/src/stories/assets/context.png new file mode 100644 index 00000000..e5cd249a Binary files /dev/null and b/apps/web/src/stories/assets/context.png differ diff --git a/apps/web/src/stories/assets/discord.svg b/apps/web/src/stories/assets/discord.svg new file mode 100644 index 00000000..d638958b --- /dev/null +++ b/apps/web/src/stories/assets/discord.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/src/stories/assets/docs.png b/apps/web/src/stories/assets/docs.png new file mode 100644 index 00000000..a749629d Binary files /dev/null and b/apps/web/src/stories/assets/docs.png differ diff --git a/apps/web/src/stories/assets/figma-plugin.png b/apps/web/src/stories/assets/figma-plugin.png new file mode 100644 index 00000000..8f79b08c Binary files /dev/null and b/apps/web/src/stories/assets/figma-plugin.png differ diff --git a/apps/web/src/stories/assets/github.svg b/apps/web/src/stories/assets/github.svg new file mode 100644 index 00000000..dc513528 --- /dev/null +++ b/apps/web/src/stories/assets/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/src/stories/assets/share.png b/apps/web/src/stories/assets/share.png new file mode 100644 index 00000000..8097a370 Binary files /dev/null and b/apps/web/src/stories/assets/share.png differ diff --git a/apps/web/src/stories/assets/styling.png b/apps/web/src/stories/assets/styling.png new file mode 100644 index 00000000..d341e826 Binary files /dev/null and b/apps/web/src/stories/assets/styling.png differ diff --git a/apps/web/src/stories/assets/testing.png b/apps/web/src/stories/assets/testing.png new file mode 100644 index 00000000..d4ac39a0 Binary files /dev/null and b/apps/web/src/stories/assets/testing.png differ diff --git a/apps/web/src/stories/assets/theming.png b/apps/web/src/stories/assets/theming.png new file mode 100644 index 00000000..1535eb9b Binary files /dev/null and b/apps/web/src/stories/assets/theming.png differ diff --git a/apps/web/src/stories/assets/tutorials.svg b/apps/web/src/stories/assets/tutorials.svg new file mode 100644 index 00000000..b492a9c6 --- /dev/null +++ b/apps/web/src/stories/assets/tutorials.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/src/stories/assets/youtube.svg b/apps/web/src/stories/assets/youtube.svg new file mode 100644 index 00000000..a7515d7e --- /dev/null +++ b/apps/web/src/stories/assets/youtube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/src/stories/button.css b/apps/web/src/stories/button.css new file mode 100644 index 00000000..4e3620b0 --- /dev/null +++ b/apps/web/src/stories/button.css @@ -0,0 +1,30 @@ +.storybook-button { + display: inline-block; + cursor: pointer; + border: 0; + border-radius: 3em; + font-weight: 700; + line-height: 1; + font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; +} +.storybook-button--primary { + background-color: #555ab9; + color: white; +} +.storybook-button--secondary { + box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; + background-color: transparent; + color: #333; +} +.storybook-button--small { + padding: 10px 16px; + font-size: 12px; +} +.storybook-button--medium { + padding: 11px 20px; + font-size: 14px; +} +.storybook-button--large { + padding: 12px 24px; + font-size: 16px; +} diff --git a/apps/web/src/stories/header.css b/apps/web/src/stories/header.css new file mode 100644 index 00000000..5efd46c2 --- /dev/null +++ b/apps/web/src/stories/header.css @@ -0,0 +1,32 @@ +.storybook-header { + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + padding: 15px 20px; + font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +.storybook-header svg { + display: inline-block; + vertical-align: top; +} + +.storybook-header h1 { + display: inline-block; + vertical-align: top; + margin: 6px 0 6px 10px; + font-weight: 700; + font-size: 20px; + line-height: 1; +} + +.storybook-header button + button { + margin-left: 10px; +} + +.storybook-header .welcome { + margin-right: 10px; + color: #333; + font-size: 14px; +} diff --git a/apps/web/src/stories/page.css b/apps/web/src/stories/page.css new file mode 100644 index 00000000..77c81d2d --- /dev/null +++ b/apps/web/src/stories/page.css @@ -0,0 +1,68 @@ +.storybook-page { + margin: 0 auto; + padding: 48px 20px; + max-width: 600px; + color: #333; + font-size: 14px; + line-height: 24px; + font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +.storybook-page h2 { + display: inline-block; + vertical-align: top; + margin: 0 0 4px; + font-weight: 700; + font-size: 32px; + line-height: 1; +} + +.storybook-page p { + margin: 1em 0; +} + +.storybook-page a { + color: inherit; +} + +.storybook-page ul { + margin: 1em 0; + padding-left: 30px; +} + +.storybook-page li { + margin-bottom: 8px; +} + +.storybook-page .tip { + display: inline-block; + vertical-align: top; + margin-right: 10px; + border-radius: 1em; + background: #e7fdd8; + padding: 4px 12px; + color: #357a14; + font-weight: 700; + font-size: 11px; + line-height: 12px; +} + +.storybook-page .tip-wrapper { + margin-top: 40px; + margin-bottom: 40px; + font-size: 13px; + line-height: 20px; +} + +.storybook-page .tip-wrapper svg { + display: inline-block; + vertical-align: top; + margin-top: 3px; + margin-right: 4px; + width: 12px; + height: 12px; +} + +.storybook-page .tip-wrapper svg path { + fill: #1ea7fd; +} diff --git a/apps/web/src/test/setup.ts b/apps/web/src/test/setup.ts new file mode 100644 index 00000000..9f02cefb --- /dev/null +++ b/apps/web/src/test/setup.ts @@ -0,0 +1,42 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +import '@testing-library/jest-dom' +import { vi } from 'vitest' + +// Mock IntersectionObserver +class MockIntersectionObserver { + root: Element | null = null + rootMargin: string = '' + thresholds: ReadonlyArray = [] + observe = vi.fn() + unobserve = vi.fn() + disconnect = vi.fn() + takeRecords = vi.fn() + constructor() {} +} +global.IntersectionObserver = MockIntersectionObserver as unknown as typeof IntersectionObserver + +// Mock ResizeObserver +global.ResizeObserver = vi.fn(() => ({ + observe: vi.fn(), + disconnect: vi.fn(), + unobserve: vi.fn(), +})) + +// Mock matchMedia +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // deprecated + removeListener: vi.fn(), // deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), +}) + +// Mock HTMLCanvasElement.getContext +HTMLCanvasElement.prototype.getContext = vi.fn() diff --git a/apps/web/vite.config.js b/apps/web/vite.config.js index eebe485f..6a5e0e0b 100644 --- a/apps/web/vite.config.js +++ b/apps/web/vite.config.js @@ -1,32 +1,51 @@ -import { sentryVitePlugin } from "@sentry/vite-plugin"; -import { tanstackRouter } from '@tanstack/router-plugin/vite' -import react from '@vitejs/plugin-react' -import { resolve } from 'node:path' -import { defineConfig } from 'vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [ - tanstackRouter({ target: 'react', autoCodeSplitting: true }), - react(), - sentryVitePlugin({ - org: "bithub-learning", - project: "bithub-web" - }) - ], - resolve: { - alias: { - '@': resolve(__dirname, './src'), - }, - }, - build: { sourcemap: true }, - // server: { - // port: 5173, - // proxy: { - // '/api': { - // target: 'http://localhost:4000', - // changeOrigin: true, - // }, - // }, - // }, -}) \ No newline at end of file +import { codecovVitePlugin } from '@codecov/vite-plugin' +import { sentryVitePlugin } from '@sentry/vite-plugin' +import { tanstackRouter } from '@tanstack/router-plugin/vite' +import react from '@vitejs/plugin-react' +import { resolve } from 'node:path' +import { defineConfig } from 'vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + tanstackRouter({ target: 'react', autoCodeSplitting: true }), + react(), + sentryVitePlugin({ + org: 'bithub-learning', + project: 'bithub-web', + }), + codecovVitePlugin({ + enableBundleAnalysis: process.env.CODECOV_TOKEN !== undefined, + bundleName: 'web', + uploadToken: process.env.CODECOV_TOKEN, + }), + ], + resolve: { + alias: { + '@': resolve(__dirname, './src'), + }, + }, + test: { + globals: true, + environment: 'jsdom', + setupFiles: ['src/test/setup.ts'], + coverage: { + provider: 'v8', + reporter: ['text', 'lcov'], + reportsDirectory: '../../coverage/apps-web', + exclude: ['node_modules/', 'src/test/', '**/*.d.ts', '**/*.config.*', '**/coverage/**'], + }, + reporters: ['default'], + include: ['src/**/*.{test,spec}.{ts,tsx}'], + }, + build: { sourcemap: false }, + // server: { + // port: 5173, + // proxy: { + // '/api': { + // target: 'http://localhost:4000', + // changeOrigin: true, + // }, + // }, + // }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c5a3b28a..043ad24f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -485,6 +485,33 @@ importers: specifier: ^4.1.12 version: 4.1.12 devDependencies: + '@chromatic-com/storybook': + specifier: ^4.1.3 + version: 4.1.3(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))) + '@codecov/vite-plugin': + specifier: ^1.9.1 + version: 1.9.1(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + '@storybook/addon-a11y': + specifier: ^10.0.8 + version: 10.0.8(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))) + '@storybook/addon-docs': + specifier: ^10.0.8 + version: 10.0.8(@types/react@19.2.2)(esbuild@0.25.11)(rollup@4.52.5)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + '@storybook/addon-vitest': + specifier: ^10.0.8 + version: 10.0.8(@vitest/browser-playwright@4.0.14)(@vitest/browser@4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14))(@vitest/runner@4.0.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.14) + '@storybook/react-vite': + specifier: ^10.0.8 + version: 10.0.8(esbuild@0.25.11)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.9.3)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + '@testing-library/jest-dom': + specifier: ^6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: ^16.3.0 + version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@testing-library/user-event': + specifier: ^14.6.1 + version: 14.6.1(@testing-library/dom@10.4.1) '@types/js-cookie': specifier: ^3.0.6 version: 3.0.6 @@ -500,15 +527,30 @@ importers: '@vitejs/plugin-react': specifier: ^4.3.4 version: 4.7.0(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/browser-playwright': + specifier: 4.0.14 + version: 4.0.14(playwright@1.57.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14) '@vitest/coverage-v8': specifier: ^4.0.14 - version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 4.0.14(@vitest/browser@4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14))(vitest@4.0.14) '@workspace/eslint-config': specifier: workspace:^ version: link:../../packages/eslint-config '@workspace/typescript-config': specifier: workspace:* version: link:../../packages/typescript-config + eslint-plugin-storybook: + specifier: ^10.0.8 + version: 10.0.8(eslint@9.38.0(jiti@2.6.1))(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.9.3) + jsdom: + specifier: ^27.2.0 + version: 27.2.0 + playwright: + specifier: ^1.57.0 + version: 1.57.0 + storybook: + specifier: ^10.0.8 + version: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) typescript: specifier: ^5.9.2 version: 5.9.3 @@ -517,7 +559,7 @@ importers: version: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) vitest: specifier: ^4.0.14 - version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(@vitest/browser-playwright@4.0.14)(jiti@2.6.1)(jsdom@27.2.0)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) packages/eslint-config: devDependencies: @@ -774,6 +816,27 @@ importers: packages: + '@acemir/cssom@0.9.24': + resolution: {integrity: sha512-5YjgMmAiT2rjJZU7XK1SNI7iqTy92DpaYVgG6x63FxkJ11UpYfLndHJATtinWJClAXiOlW9XWaUyAQf8pMrQPg==} + + '@actions/core@1.11.1': + resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==} + + '@actions/exec@1.1.1': + resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==} + + '@actions/github@6.0.1': + resolution: {integrity: sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw==} + + '@actions/http-client@2.2.3': + resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==} + + '@actions/io@1.1.3': + resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==} + + '@adobe/css-tools@4.4.4': + resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -789,6 +852,15 @@ packages: '@antfu/utils@9.3.0': resolution: {integrity: sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==} + '@asamuzakjp/css-color@4.1.0': + resolution: {integrity: sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==} + + '@asamuzakjp/dom-selector@6.7.4': + resolution: {integrity: sha512-buQDjkm+wDPXd6c13534URWZqbz0RP5PAhXZ+LIoa5LgwInT9HVJvGIJivg75vi8I13CxDGdTnz+aY5YUJlIAA==} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -982,6 +1054,12 @@ packages: '@chevrotain/utils@11.0.3': resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} + '@chromatic-com/storybook@4.1.3': + resolution: {integrity: sha512-hc0HO9GAV9pxqDE6fTVOV5KeLpTiCfV8Jrpk5ogKLiIgeq2C+NPjpt74YnrZTjiK8E19fYcMP+2WY9ZtX7zHmw==} + engines: {node: '>=20.0.0', yarn: '>=1.22.18'} + peerDependencies: + storybook: ^0.0.0-0 || ^9.0.0 || ^9.1.0-0 || ^9.2.0-0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 + '@clerk/clerk-react@5.53.2': resolution: {integrity: sha512-/ckRJC1dDS6hUVv+zzNX5VUCC49/UlbhKElN5LQqv172ntrx4Mw1TKBCJ3aO5Rct/RiJxhf1PfTUEohtY4QjUg==} engines: {node: '>=18.17.0'} @@ -1005,6 +1083,16 @@ packages: resolution: {integrity: sha512-K1kI3BjvufG1mZBZJ5Q8Yu9wV6AFpjjITml5vhvP95xibJWOi3eYvlRCTKXDNKBFGvQfrTJbwn67jSG2VdyLKw==} engines: {node: '>=18.17.0'} + '@codecov/bundler-plugin-core@1.9.1': + resolution: {integrity: sha512-dt3ic7gMswz4p/qdkYPVJwXlLiLsz55rBBn2I7mr0HTG8pCoLRqnANJIwo5WrqGBZgPyVSMPBqBra6VxLWfDyA==} + engines: {node: '>=18.0.0'} + + '@codecov/vite-plugin@1.9.1': + resolution: {integrity: sha512-S6Yne7comVulJ1jD3T7rCfYFHPR0zUjAYoLjUDPXNJCUrdzWJdf/ak/UepE7TicqQG+yBa6eb5WusqcPgg+1AQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + vite: 4.x || 5.x || 6.x + '@contentlayer2/cli@0.4.3': resolution: {integrity: sha512-ZJ+Iiu2rVI50x60XoqnrsO/Q8eqFX5AlP1L0U/3ygaAas3tnOqTzQZ1UsxYQMpJzcLok24ddlhKfQKbCMUJPiQ==} @@ -1040,6 +1128,38 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@csstools/color-helpers@5.1.0': + resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} + engines: {node: '>=18'} + + '@csstools/css-calc@2.1.4': + resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-color-parser@3.1.0': + resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-parser-algorithms@3.0.5': + resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-syntax-patches-for-csstree@1.0.17': + resolution: {integrity: sha512-LCC++2h8pLUSPY+EsZmrrJ1EOUu+5iClpEiDhhdw3zRJpPbABML/N5lmRuBHjxtKm9VnRcsUzioyD0sekFMF0A==} + engines: {node: '>=18'} + + '@csstools/css-tokenizer@3.0.4': + resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} + engines: {node: '>=18'} + '@date-fns/tz@1.4.1': resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} @@ -1293,6 +1413,10 @@ packages: '@fal-works/esbuild-plugin-global-externals@2.1.2': resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==} + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} @@ -1526,6 +1650,15 @@ packages: resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.1': + resolution: {integrity: sha512-J4BaTocTOYFkMHIra1JDWrMWpNmBl4EkplIwHEsV8aeUOtdWjwSnln9U7twjMFTAEB7mptNtSKyVi1Y2W9sDJw==} + 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==} @@ -1617,12 +1750,21 @@ packages: '@mdx-js/mdx@3.1.1': resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + '@mdx-js/react@3.1.1': + resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==} + peerDependencies: + '@types/react': '>=16' + react: '>=16' + '@mermaid-js/parser@0.6.3': resolution: {integrity: sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==} '@napi-rs/wasm-runtime@1.0.7': resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} + '@neoconfetti/react@1.0.0': + resolution: {integrity: sha512-klcSooChXXOzIm+SE5IISIAn3bYzYfPjbX7D7HoqZL84oAfgREeSg5vSIaSFH+DaGzzvImTyWe1OyrJ67vik4A==} + '@next/env@15.5.6': resolution: {integrity: sha512-3qBGRW+sCGzgbpc5TS1a0p7eNxnOarGVQhZxfvTdnV0gFI61lX7QNtQ4V1TSREctXzYn5NetbUsLvyqwLFJM6Q==} @@ -1693,6 +1835,54 @@ packages: resolution: {integrity: sha512-ze46EW5xW+UxDvinvPkYt2MzR355Az1lA3bpX8KDialgnCwr+IbkBij/udbUEC6ZFbidPkfK1eKl4ESN7gMY+w==} engines: {node: '>=18.12.0'} + '@octokit/auth-token@4.0.0': + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} + + '@octokit/core@5.2.2': + resolution: {integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==} + engines: {node: '>= 18'} + + '@octokit/endpoint@9.0.6': + resolution: {integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==} + engines: {node: '>= 18'} + + '@octokit/graphql@7.1.1': + resolution: {integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==} + engines: {node: '>= 18'} + + '@octokit/openapi-types@20.0.0': + resolution: {integrity: sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==} + + '@octokit/openapi-types@24.2.0': + resolution: {integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==} + + '@octokit/plugin-paginate-rest@9.2.2': + resolution: {integrity: sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/plugin-rest-endpoint-methods@10.4.1': + resolution: {integrity: sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/request-error@5.1.1': + resolution: {integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==} + engines: {node: '>= 18'} + + '@octokit/request@8.4.1': + resolution: {integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==} + engines: {node: '>= 18'} + + '@octokit/types@12.6.0': + resolution: {integrity: sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==} + + '@octokit/types@13.10.0': + resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==} + '@opentelemetry/api-logs@0.51.1': resolution: {integrity: sha512-E3skn949Pk1z2XtXu/lxf6QAZpawuTM/IUEXcAzpiUkTd73Hmvw26FiN3cJuTmkpM5hZzHwkomVdtrh/n/zzwA==} engines: {node: '>=14'} @@ -3070,6 +3260,15 @@ packages: '@rolldown/pluginutils@1.0.0-beta.35': resolution: {integrity: sha512-slYrCpoxJUqzFDDNlvrOYRazQUNRvWPjXA17dAOISY3rDMxX6k8K4cj2H+hEYMHF81HO3uNd5rHVigAWRM5dSg==} + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.52.5': resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} cpu: [arm] @@ -3375,6 +3574,94 @@ packages: '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + '@storybook/addon-a11y@10.0.8': + resolution: {integrity: sha512-rXJuSfujuRqkz1v26wLttVRkXzZur3LtMTH1/K+rb1epXq305vRm/bYql0FYGvrq0idJWYo4WbU65YRig9sfuA==} + peerDependencies: + storybook: ^10.0.8 + + '@storybook/addon-docs@10.0.8': + resolution: {integrity: sha512-PYuaGXGycsamK/7OrFoE4syHGy22mdqqArl67cfosRwmRxZEI9ManQK0jTjNQM9ZX14NpThMOSWNGoWLckkxog==} + peerDependencies: + storybook: ^10.0.8 + + '@storybook/addon-vitest@10.0.8': + resolution: {integrity: sha512-f9LoBPNz3cLBUWbkeYV7OFSrcONKxVT/NXeMek0/H1VwRwU/caYMoIAQzQwK4AueXkMUeba4DZfB/FvzB8mM6A==} + peerDependencies: + '@vitest/browser': ^3.0.0 || ^4.0.0 + '@vitest/browser-playwright': ^4.0.0 + '@vitest/runner': ^3.0.0 || ^4.0.0 + storybook: ^10.0.8 + vitest: ^3.0.0 || ^4.0.0 + peerDependenciesMeta: + '@vitest/browser': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/runner': + optional: true + vitest: + optional: true + + '@storybook/builder-vite@10.0.8': + resolution: {integrity: sha512-kaf/pUENzXxYgQMHGGPNiIk1ieb+SOMuSeLKx8wAUOlQOrzhtSH+ItACW/l43t+O6YZ8jYHoNBMF1kdQ1+Y5+w==} + peerDependencies: + storybook: ^10.0.8 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@storybook/csf-plugin@10.0.8': + resolution: {integrity: sha512-OtLUWHIm3SDGtclQn6Mdd/YsWizLBgdEBRAdekGtwI/TvICfT7gpWYIycP53v2t9ufu2MIXjsxtV2maZKs8sZg==} + peerDependencies: + esbuild: '*' + rollup: '*' + storybook: ^10.0.8 + 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@1.6.0': + resolution: {integrity: sha512-hcFZIjW8yQz8O8//2WTIXylm5Xsgc+lW9ISLgUk1xGmptIJQRdlhVIXCpSyLrQaaRiyhQRaVg7l3BD9S216BHw==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + + '@storybook/react-dom-shim@10.0.8': + resolution: {integrity: sha512-ojuH22MB9Sz6rWbhTmC5IErZr0ZADbZijtPteUdydezY7scORT00UtbNoBcG0V6iVjdChgDtSKw2KHUUfchKqg==} + 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.0.8 + + '@storybook/react-vite@10.0.8': + resolution: {integrity: sha512-HS2X4qlitrZr3/sN2+ollxAaNE813IasZRE8lOez1Ey1ISGBtYIb9rmJs82MK35+yDM0pHdiDjkFMD4SkNYh2g==} + 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.0.8 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@storybook/react@10.0.8': + resolution: {integrity: sha512-PkuPb8sAqmjjkowSzm3rutiSuETvZI2F8SnjbHE6FRqZWWK4iFoaUrQbrg5kpPAtX//xIrqkdFwlbmQ3skhiPA==} + 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.0.8 + typescript: '>= 4.9.x' + peerDependenciesMeta: + typescript: + optional: true + '@swc/core-darwin-arm64@1.13.5': resolution: {integrity: sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ==} engines: {node: '>=10'} @@ -3664,6 +3951,35 @@ packages: resolution: {integrity: sha512-6d2AP9hAjEi8mcIew2RkxBX+wClH1xedhfaYhs8fUiX+V2Cedk7RBD9E9ww2z6BGUYD8Es4fS0OIrzXZWHKGhw==} engines: {node: '>=12'} + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.3.0': + resolution: {integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@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' + '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} @@ -3706,6 +4022,9 @@ packages: '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -3820,6 +4139,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==} @@ -4120,6 +4442,17 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 vue: ^3.2.25 + '@vitest/browser-playwright@4.0.14': + resolution: {integrity: sha512-rUvyz6wX6wDjcYzf/7fgXYfca2bAu0Axoq/v9LYdELzcBSS9UKjnZ7MaMY4UDP78HHHCdmdtceuSao1s51ON8A==} + peerDependencies: + playwright: '*' + vitest: 4.0.14 + + '@vitest/browser@4.0.14': + resolution: {integrity: sha512-vO0uqR8SnPTd8ykp14yaIuUyMZ9HEBYuoZrVdUp7RrEp76VEnkrX9fDkGnK0NyBdfWXB6cqp7BmqVekd8yKHFQ==} + peerDependencies: + vitest: 4.0.14 + '@vitest/coverage-v8@4.0.14': resolution: {integrity: sha512-EYHLqN/BY6b47qHH7gtMxAg++saoGmsjWmAq9MlXxAz4M0NcHh9iOyKhBZyU4yxZqOd8Xnqp80/5saeitz4Cng==} peerDependencies: @@ -4129,9 +4462,23 @@ packages: '@vitest/browser': optional: true + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@vitest/expect@4.0.14': resolution: {integrity: sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==} + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/mocker@4.0.14': resolution: {integrity: sha512-RzS5NujlCzeRPF1MK7MXLiEFpkIXeMdQ+rN3Kk3tDI9j0mtbr7Nmuq67tpkOJQpgyClbOltCXMjLZicJHsH5Cg==} peerDependencies: @@ -4143,6 +4490,9 @@ packages: vite: optional: true + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@vitest/pretty-format@4.0.14': resolution: {integrity: sha512-SOYPgujB6TITcJxgd3wmsLl+wZv+fy3av2PpiPpsWPZ6J1ySUYfScfpIt2Yv56ShJXR2MOA6q2KjKHN4EpdyRQ==} @@ -4152,9 +4502,15 @@ packages: '@vitest/snapshot@4.0.14': resolution: {integrity: sha512-aQVBfT1PMzDSA16Y3Fp45a0q8nKexx6N5Amw3MX55BeTeZpoC08fGqEZqVmPcqN0ueZsuUQ9rriPMhZ3Mu19Ag==} + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + '@vitest/spy@4.0.14': resolution: {integrity: sha512-JmAZT1UtZooO0tpY3GRyiC/8W7dCs05UOq9rfsUUgEZEdq+DuHLmWhPsrTt0TiW7WYeL/hXpaE07AZ2RCk44hg==} + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vitest/utils@4.0.14': resolution: {integrity: sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==} @@ -4315,6 +4671,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} @@ -4340,6 +4700,13 @@ packages: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + array-buffer-byte-length@1.0.2: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} @@ -4405,6 +4772,10 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + axe-core@4.11.0: + resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + engines: {node: '>=4'} + axios@1.12.2: resolution: {integrity: sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==} @@ -4428,6 +4799,12 @@ packages: resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} + before-after-hook@2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -4506,6 +4883,10 @@ packages: 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.1: resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} engines: {node: '>=18'} @@ -4543,6 +4924,10 @@ packages: chardet@2.1.0: resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + chevrotain-allstar@0.3.1: resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} peerDependencies: @@ -4563,6 +4948,18 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} + chromatic@13.3.4: + resolution: {integrity: sha512-TR5rvyH0ESXobBB3bV8jc87AEAFQC7/n+Eb4XWhJz6hW3YNxIQPVjcbgLv+a4oKHEl1dUBueWSoIQsOVGTd+RQ==} + hasBin: true + peerDependencies: + '@chromatic-com/cypress': ^0.*.* || ^1.0.0 + '@chromatic-com/playwright': ^0.*.* || ^1.0.0 + peerDependenciesMeta: + '@chromatic-com/cypress': + optional: true + '@chromatic-com/playwright': + optional: true + citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} @@ -4736,11 +5133,18 @@ packages: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true + cssstyle@5.3.3: + resolution: {integrity: sha512-OytmFH+13/QXONJcC75QNdMtKpceNk3u8ThBjyyYjkEcy/ekBwR1mMAuNvi3gdBPW3N5TlCzQ0WZw8H0lN/bDw==} + engines: {node: '>=20'} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -4904,6 +5308,10 @@ packages: resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} + data-urls@6.0.0: + resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} + engines: {node: '>=20'} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -4951,6 +5359,10 @@ packages: decode-named-character-reference@1.2.0: resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -4999,6 +5411,9 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -5043,10 +5458,20 @@ 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'} + docx@9.5.1: resolution: {integrity: sha512-ABDI7JEirFD2+bHhOBlsGZxaG1UgZb2M/QMKhLSDGgVNhxDesTCDcP+qoDnDGjZ4EOXTRfUjUgwHVuZ6VSTfWQ==} engines: {node: '>=10'} + 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@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -5136,6 +5561,10 @@ 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@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -5264,6 +5693,12 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + eslint-plugin-storybook@10.0.8: + resolution: {integrity: sha512-ZKEMFhF/z/HRVvIgnEIYG2uAqmuLbkebUdHH3DpGHE64GPgk+KozcpqnD6zNk5vJ407bFmcWsGinBc2zi74f0g==} + peerDependencies: + eslint: '>=8' + storybook: ^10.0.8 + eslint-plugin-turbo@2.5.8: resolution: {integrity: sha512-bVjx4vTH0oTKIyQ7EGFAXnuhZMrKIfu17qlex/dps7eScPnGQLJ3r1/nFq80l8xA+8oYjsSirSQ2tXOKbz3kEw==} peerDependencies: @@ -5415,6 +5850,10 @@ packages: file-saver@2.0.5: resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==} + filesize@10.1.6: + resolution: {integrity: sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==} + engines: {node: '>= 10.4.0'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -5497,6 +5936,11 @@ packages: 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} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -5737,6 +6181,10 @@ packages: hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -6022,6 +6470,9 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -6145,6 +6596,15 @@ packages: jsbi@4.3.2: resolution: {integrity: sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==} + jsdom@27.2.0: + resolution: {integrity: sha512-454TI39PeRDW1LgpyLPyURtB4Zx1tklSr6+OFOipsxGUH1WMTvk6C65JQdrj455+DP2uJ1+veBEHTGFKWVLFoA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -6390,6 +6850,9 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lower-case-first@1.0.2: resolution: {integrity: sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==} @@ -6402,6 +6865,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.2.2: + resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -6681,6 +7148,10 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} @@ -6999,6 +7470,9 @@ packages: parse-entities@4.0.2: resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse5@8.0.0: + resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -7047,6 +7521,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'} + pdf-lib@1.17.1: resolution: {integrity: sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==} @@ -7070,6 +7548,10 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pixelmatch@7.1.0: + resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==} + hasBin: true + pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -7079,6 +7561,20 @@ packages: plantuml-encoder@1.4.0: resolution: {integrity: sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==} + playwright-core@1.57.0: + resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.57.0: + resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==} + engines: {node: '>=18'} + hasBin: true + + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + points-on-curve@0.2.0: resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} @@ -7204,6 +7700,10 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + prism-theme-vars@0.2.5: resolution: {integrity: sha512-/D8gBTScYzi9afwE6v3TC1U/1YFZ6k+ly17mtVRdLpGy7E79YjJJWkXFgUDHJ2gDksV/ZnXF7ydJ4TvoDm2z/Q==} @@ -7291,6 +7791,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.0: resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} peerDependencies: @@ -7329,6 +7838,9 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-is@19.2.0: resolution: {integrity: sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==} @@ -7442,6 +7954,10 @@ packages: recordrtc@5.6.2: resolution: {integrity: sha512-1QNKKNtl7+KcwD1lyOgP3ZlbiJ1d0HtXnypUy7yq49xEERxk31PHvE9RCciDrulPCY7WJ+oz0R9hpNxgsIurGQ==} + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + redux-persist@6.0.0: resolution: {integrity: sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==} peerDependencies: @@ -7526,6 +8042,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + reselect@5.1.1: resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} @@ -7622,6 +8142,10 @@ packages: sax@1.4.3: resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -7818,6 +8342,15 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} + storybook@10.0.8: + resolution: {integrity: sha512-vQMufKKA9TxgoEDHJv3esrqUkjszuuRiDkThiHxENFPdQawHhm2Dei+iwNRwH5W671zTDy9iRT9P1KDjcU5Iyw==} + hasBin: true + peerDependencies: + prettier: ^2 || ^3 + peerDependenciesMeta: + prettier: + optional: true + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -7870,10 +8403,22 @@ packages: resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} engines: {node: '>=0.10.0'} + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + strip-indent@4.1.1: + resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} + engines: {node: '>=12'} + strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} @@ -7948,6 +8493,9 @@ packages: peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tailwind-merge@3.3.1: resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} @@ -8010,13 +8558,28 @@ packages: tinygradient@1.1.5: resolution: {integrity: sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw==} + 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'} + title-case@2.1.1: resolution: {integrity: sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==} + tldts-core@7.0.19: + resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} + + tldts@7.0.19: + resolution: {integrity: sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==} + hasBin: true + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -8032,9 +8595,17 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + tough-cookie@6.0.0: + resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} + engines: {node: '>=16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + tree-dump@1.1.0: resolution: {integrity: sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==} engines: {node: '>=10.0'} @@ -8074,6 +8645,10 @@ packages: ts-pattern@5.8.0: resolution: {integrity: sha512-kIjN2qmWiHnhgr5DAkAafF9fwb0T5OhMVSWrm8XEdTFnX6+wfXwYOFjeF86UZ54vduqiR7BfqScFmXSzSaH8oA==} + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -8094,6 +8669,10 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + turbo-darwin-64@2.5.8: resolution: {integrity: sha512-Dh5bCACiHO8rUXZLpKw+m3FiHtAp2CkanSyJre+SInEvEr5kIxjGvCK/8MFX8SFRjQuhjtvpIvYYZJB4AGCxNQ==} cpu: [x64] @@ -8217,6 +8796,10 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici@5.29.0: + resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} + engines: {node: '>=14.0'} + unhead@2.0.19: resolution: {integrity: sha512-gEEjkV11Aj+rBnY6wnRfsFtF2RxKOLaPN4i+Gx3UhBxnszvV6ApSNZbGk7WKyy/lErQ6ekPN63qdFL7sa1leow==} @@ -8245,6 +8828,9 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + universal-user-agent@6.0.1: + resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -8314,6 +8900,10 @@ packages: unplugin@1.0.1: resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==} + unplugin@1.16.1: + resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} + engines: {node: '>=14.0.0'} + unplugin@2.3.10: resolution: {integrity: sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==} engines: {node: '>=18.12.0'} @@ -8576,6 +9166,10 @@ packages: typescript: optional: true + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + walk-up-path@4.0.0: resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} engines: {node: 20 || >=22} @@ -8586,6 +9180,10 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@8.0.0: + resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} + engines: {node: '>=20'} + webpack-sources@3.3.3: resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} engines: {node: '>=10.13.0'} @@ -8596,6 +9194,18 @@ packages: 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'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@15.1.0: + resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} + engines: {node: '>=20'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -8651,6 +9261,18 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + wsl-utils@0.1.0: resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} engines: {node: '>=18'} @@ -8659,9 +9281,16 @@ packages: resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==} hasBin: true + 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==} + xstate@5.23.0: resolution: {integrity: sha512-jo126xWXkU6ySQ91n51+H2xcgnMuZcCQpQoD3FQ79d32a6RQvryRh8rrDHnH4WDdN/yg5xNjlIRol9ispMvzeg==} @@ -8743,6 +9372,36 @@ packages: snapshots: + '@acemir/cssom@0.9.24': {} + + '@actions/core@1.11.1': + dependencies: + '@actions/exec': 1.1.1 + '@actions/http-client': 2.2.3 + + '@actions/exec@1.1.1': + dependencies: + '@actions/io': 1.1.3 + + '@actions/github@6.0.1': + dependencies: + '@actions/http-client': 2.2.3 + '@octokit/core': 5.2.2 + '@octokit/plugin-paginate-rest': 9.2.2(@octokit/core@5.2.2) + '@octokit/plugin-rest-endpoint-methods': 10.4.1(@octokit/core@5.2.2) + '@octokit/request': 8.4.1 + '@octokit/request-error': 5.1.1 + undici: 5.29.0 + + '@actions/http-client@2.2.3': + dependencies: + tunnel: 0.0.6 + undici: 5.29.0 + + '@actions/io@1.1.3': {} + + '@adobe/css-tools@4.4.4': {} + '@alloc/quick-lru@5.2.0': {} '@antfu/install-pkg@1.1.0': @@ -8760,6 +9419,24 @@ snapshots: '@antfu/utils@9.3.0': {} + '@asamuzakjp/css-color@4.1.0': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 11.2.2 + + '@asamuzakjp/dom-selector@6.7.4': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.1.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.2.2 + + '@asamuzakjp/nwsapi@2.3.9': {} + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -8798,7 +9475,7 @@ snapshots: '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-compilation-targets@7.27.2': dependencies: @@ -8826,14 +9503,14 @@ snapshots: '@babel/helper-member-expression-to-functions@7.27.1': dependencies: '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color @@ -8848,7 +9525,7 @@ snapshots: '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-plugin-utils@7.27.1': {} @@ -8864,7 +9541,7 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color @@ -8883,7 +9560,7 @@ snapshots: '@babel/parser@7.27.7': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/parser@7.28.4': dependencies: @@ -8961,7 +9638,7 @@ snapshots: '@babel/generator': 7.28.3 '@babel/parser': 7.28.4 '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 debug: 4.4.3 globals: 11.12.0 transitivePeerDependencies: @@ -9010,6 +9687,18 @@ snapshots: '@chevrotain/utils@11.0.3': {} + '@chromatic-com/storybook@4.1.3(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))': + dependencies: + '@neoconfetti/react': 1.0.0 + chromatic: 13.3.4 + filesize: 10.1.6 + jsonfile: 6.2.0 + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + strip-ansi: 7.1.2 + transitivePeerDependencies: + - '@chromatic-com/cypress' + - '@chromatic-com/playwright' + '@clerk/clerk-react@5.53.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@clerk/shared': 3.28.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -9034,6 +9723,21 @@ snapshots: dependencies: csstype: 3.1.3 + '@codecov/bundler-plugin-core@1.9.1': + dependencies: + '@actions/core': 1.11.1 + '@actions/github': 6.0.1 + chalk: 4.1.2 + semver: 7.7.3 + unplugin: 1.16.1 + zod: 3.25.76 + + '@codecov/vite-plugin@1.9.1(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + '@codecov/bundler-plugin-core': 1.9.1 + unplugin: 1.16.1 + vite: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + '@contentlayer2/cli@0.4.3(esbuild@0.25.11)': dependencies: '@contentlayer2/core': 0.4.3(esbuild@0.25.11) @@ -9130,6 +9834,28 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@csstools/color-helpers@5.1.0': {} + + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/color-helpers': 5.1.0 + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-syntax-patches-for-csstree@1.0.17': {} + + '@csstools/css-tokenizer@3.0.4': {} + '@date-fns/tz@1.4.1': {} '@drauu/core@0.4.3': {} @@ -9318,6 +10044,8 @@ snapshots: '@fal-works/esbuild-plugin-global-externals@2.1.2': {} + '@fastify/busboy@2.1.1': {} + '@floating-ui/core@1.7.3': dependencies: '@floating-ui/utils': 0.2.10 @@ -9546,6 +10274,15 @@ snapshots: dependencies: minipass: 7.1.2 + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.1(typescript@5.9.3)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + glob: 10.5.0 + magic-string: 0.30.21 + react-docgen-typescript: 2.4.0(typescript@5.9.3) + vite: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + optionalDependencies: + typescript: 5.9.3 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -9677,6 +10414,12 @@ snapshots: transitivePeerDependencies: - supports-color + '@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@types/mdx': 2.0.13 + '@types/react': 19.2.2 + react: 19.2.0 + '@mermaid-js/parser@0.6.3': dependencies: langium: 3.3.1 @@ -9688,6 +10431,8 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@neoconfetti/react@1.0.0': {} + '@next/env@15.5.6': {} '@next/eslint-plugin-next@15.5.6': @@ -9759,6 +10504,64 @@ snapshots: - magicast optional: true + '@octokit/auth-token@4.0.0': {} + + '@octokit/core@5.2.2': + dependencies: + '@octokit/auth-token': 4.0.0 + '@octokit/graphql': 7.1.1 + '@octokit/request': 8.4.1 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + + '@octokit/endpoint@9.0.6': + dependencies: + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + + '@octokit/graphql@7.1.1': + dependencies: + '@octokit/request': 8.4.1 + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + + '@octokit/openapi-types@20.0.0': {} + + '@octokit/openapi-types@24.2.0': {} + + '@octokit/plugin-paginate-rest@9.2.2(@octokit/core@5.2.2)': + dependencies: + '@octokit/core': 5.2.2 + '@octokit/types': 12.6.0 + + '@octokit/plugin-rest-endpoint-methods@10.4.1(@octokit/core@5.2.2)': + dependencies: + '@octokit/core': 5.2.2 + '@octokit/types': 12.6.0 + + '@octokit/request-error@5.1.1': + dependencies: + '@octokit/types': 13.10.0 + deprecation: 2.3.1 + once: 1.4.0 + + '@octokit/request@8.4.1': + dependencies: + '@octokit/endpoint': 9.0.6 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + + '@octokit/types@12.6.0': + dependencies: + '@octokit/openapi-types': 20.0.0 + + '@octokit/types@13.10.0': + dependencies: + '@octokit/openapi-types': 24.2.0 + '@opentelemetry/api-logs@0.51.1': dependencies: '@opentelemetry/api': 1.9.0 @@ -11572,6 +12375,14 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.35': {} + '@rollup/pluginutils@5.3.0(rollup@4.52.5)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.52.5 + '@rollup/rollup-android-arm-eabi@4.52.5': optional: true @@ -11832,7 +12643,7 @@ snapshots: '@shikijs/twoslash': 3.13.0(typescript@5.9.3) floating-vue: 5.2.2(@nuxt/kit@3.19.3)(vue@3.5.22(typescript@5.9.3)) lz-string: 1.5.0 - magic-string: 0.30.19 + magic-string: 0.30.21 markdown-it: 14.1.0 mdast-util-from-markdown: 2.0.2 mdast-util-gfm: 3.1.0 @@ -12078,6 +12889,110 @@ snapshots: '@standard-schema/utils@0.3.0': {} + '@storybook/addon-a11y@10.0.8(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))': + dependencies: + '@storybook/global': 5.0.0 + axe-core: 4.11.0 + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + + '@storybook/addon-docs@10.0.8(@types/react@19.2.2)(esbuild@0.25.11)(rollup@4.52.5)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + '@mdx-js/react': 3.1.1(@types/react@19.2.2)(react@19.2.0) + '@storybook/csf-plugin': 10.0.8(esbuild@0.25.11)(rollup@4.52.5)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@storybook/react-dom-shim': 10.0.8(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + ts-dedent: 2.2.0 + transitivePeerDependencies: + - '@types/react' + - esbuild + - rollup + - vite + - webpack + + '@storybook/addon-vitest@10.0.8(@vitest/browser-playwright@4.0.14)(@vitest/browser@4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14))(@vitest/runner@4.0.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.14)': + dependencies: + '@storybook/global': 5.0.0 + '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + prompts: 2.4.2 + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + ts-dedent: 2.2.0 + optionalDependencies: + '@vitest/browser': 4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14) + '@vitest/browser-playwright': 4.0.14(playwright@1.57.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14) + '@vitest/runner': 4.0.14 + vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(@vitest/browser-playwright@4.0.14)(jiti@2.6.1)(jsdom@27.2.0)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + transitivePeerDependencies: + - react + - react-dom + + '@storybook/builder-vite@10.0.8(esbuild@0.25.11)(rollup@4.52.5)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + '@storybook/csf-plugin': 10.0.8(esbuild@0.25.11)(rollup@4.52.5)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + ts-dedent: 2.2.0 + vite: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + transitivePeerDependencies: + - esbuild + - rollup + - webpack + + '@storybook/csf-plugin@10.0.8(esbuild@0.25.11)(rollup@4.52.5)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + unplugin: 2.3.10 + optionalDependencies: + esbuild: 0.25.11 + rollup: 4.52.5 + vite: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + + '@storybook/global@5.0.0': {} + + '@storybook/icons@1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@storybook/react-dom-shim@10.0.8(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))': + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + + '@storybook/react-vite@10.0.8(esbuild@0.25.11)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.9.3)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@5.9.3)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + '@rollup/pluginutils': 5.3.0(rollup@4.52.5) + '@storybook/builder-vite': 10.0.8(esbuild@0.25.11)(rollup@4.52.5)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + '@storybook/react': 10.0.8(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.9.3) + empathic: 2.0.0 + magic-string: 0.30.21 + react: 19.2.0 + react-docgen: 8.0.2 + react-dom: 19.2.0(react@19.2.0) + resolve: 1.22.10 + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + tsconfig-paths: 4.2.0 + vite: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + transitivePeerDependencies: + - esbuild + - rollup + - supports-color + - typescript + - webpack + + '@storybook/react@10.0.8(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.9.3)': + dependencies: + '@storybook/global': 5.0.0 + '@storybook/react-dom-shim': 10.0.8(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + optionalDependencies: + typescript: 5.9.3 + '@swc/core-darwin-arm64@1.13.5': optional: true @@ -12145,7 +13060,7 @@ snapshots: enhanced-resolve: 5.18.3 jiti: 2.6.1 lightningcss: 1.30.1 - magic-string: 0.30.19 + magic-string: 0.30.21 source-map-js: 1.2.1 tailwindcss: 4.1.14 @@ -12452,6 +13367,40 @@ snapshots: '@tanstack/virtual-file-routes@1.133.3': {} + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/runtime': 7.28.4 + '@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.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@babel/runtime': 7.28.4 + '@testing-library/dom': 10.4.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': + dependencies: + '@testing-library/dom': 10.4.1 + '@tootallnate/quickjs-emscripten@0.23.0': {} '@trivago/prettier-plugin-sort-imports@5.2.2(@vue/compiler-sfc@3.5.22)(prettier@3.6.2)': @@ -12517,6 +13466,8 @@ snapshots: tslib: 2.8.1 optional: true + '@types/aria-query@5.0.4': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.28.4 @@ -12666,6 +13617,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 @@ -12898,7 +13851,7 @@ snapshots: chokidar: 3.6.0 colorette: 2.0.20 consola: 3.4.2 - magic-string: 0.30.19 + magic-string: 0.30.21 pathe: 2.0.3 perfect-debounce: 1.0.0 tinyglobby: 0.2.15 @@ -12994,7 +13947,7 @@ snapshots: '@unocss/rule-utils@66.5.4': dependencies: '@unocss/core': 66.5.4 - magic-string: 0.30.19 + magic-string: 0.30.21 '@unocss/transformer-attributify-jsx@66.5.4': dependencies: @@ -13025,7 +13978,7 @@ snapshots: '@unocss/core': 66.5.4 '@unocss/inspector': 66.5.4 chokidar: 3.6.0 - magic-string: 0.30.19 + magic-string: 0.30.21 pathe: 2.0.3 tinyglobby: 0.2.15 unplugin-utils: 0.3.1 @@ -13069,7 +14022,37 @@ snapshots: vite: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) vue: 3.5.22(typescript@5.9.3) - '@vitest/coverage-v8@4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))': + '@vitest/browser-playwright@4.0.14(playwright@1.57.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14)': + dependencies: + '@vitest/browser': 4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14) + '@vitest/mocker': 4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + playwright: 1.57.0 + tinyrainbow: 3.0.3 + vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(@vitest/browser-playwright@4.0.14)(jiti@2.6.1)(jsdom@27.2.0)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/browser@4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14)': + dependencies: + '@vitest/mocker': 4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/utils': 4.0.14 + magic-string: 0.30.21 + pixelmatch: 7.1.0 + pngjs: 7.0.0 + sirv: 3.0.2 + tinyrainbow: 3.0.3 + vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(@vitest/browser-playwright@4.0.14)(jiti@2.6.1)(jsdom@27.2.0)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/coverage-v8@4.0.14(@vitest/browser@4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14))(vitest@4.0.14)': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.0.14 @@ -13082,10 +14065,20 @@ snapshots: obug: 2.1.1 std-env: 3.10.0 tinyrainbow: 3.0.3 - vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(@vitest/browser-playwright@4.0.14)(jiti@2.6.1)(jsdom@27.2.0)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + optionalDependencies: + '@vitest/browser': 4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14) transitivePeerDependencies: - supports-color + '@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.14': dependencies: '@standard-schema/spec': 1.0.0 @@ -13095,6 +14088,14 @@ snapshots: chai: 6.2.1 tinyrainbow: 3.0.3 + '@vitest/mocker@3.2.4(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + '@vitest/mocker@4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@vitest/spy': 4.0.14 @@ -13103,6 +14104,10 @@ snapshots: optionalDependencies: vite: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + '@vitest/pretty-format@4.0.14': dependencies: tinyrainbow: 3.0.3 @@ -13118,8 +14123,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.14': {} + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + '@vitest/utils@4.0.14': dependencies: '@vitest/pretty-format': 4.0.14 @@ -13140,7 +14155,7 @@ snapshots: '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) '@babel/template': 7.27.2 '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@vue/babel-helper-vue-transform-on': 1.5.0 '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.28.4) '@vue/shared': 3.5.22 @@ -13181,7 +14196,7 @@ snapshots: '@vue/compiler-ssr': 3.5.22 '@vue/shared': 3.5.22 estree-walker: 2.0.2 - magic-string: 0.30.19 + magic-string: 0.30.21 postcss: 8.5.6 source-map-js: 1.2.1 @@ -13323,6 +14338,8 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} ansis@4.2.0: {} @@ -13344,6 +14361,12 @@ snapshots: dependencies: tslib: 2.8.1 + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + aria-query@5.3.2: {} + array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.4 @@ -13431,6 +14454,8 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + axe-core@4.11.0: {} + axios@1.12.2: dependencies: follow-redirects: 1.15.11 @@ -13458,6 +14483,12 @@ snapshots: basic-ftp@5.0.5: {} + before-after-hook@2.2.3: {} + + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + binary-extensions@2.3.0: {} birpc@2.6.1: {} @@ -13553,6 +14584,14 @@ snapshots: ccount@2.0.1: {} + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + chai@6.2.1: {} chalk@2.4.2: @@ -13604,6 +14643,8 @@ snapshots: chardet@2.1.0: {} + check-error@2.1.1: {} + chevrotain-allstar@0.3.1(chevrotain@11.0.3): dependencies: chevrotain: 11.0.3 @@ -13636,6 +14677,8 @@ snapshots: chownr@3.0.0: {} + chromatic@13.3.4: {} + citty@0.1.6: dependencies: consola: 3.4.2 @@ -13809,8 +14852,16 @@ snapshots: mdn-data: 2.12.2 source-map-js: 1.2.1 + css.escape@1.5.1: {} + cssesc@3.0.0: {} + cssstyle@5.3.3: + dependencies: + '@asamuzakjp/css-color': 4.1.0 + '@csstools/css-syntax-patches-for-csstree': 1.0.17 + css-tree: 3.1.0 + csstype@3.1.3: {} cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): @@ -13999,6 +15050,11 @@ snapshots: data-uri-to-buffer@6.0.2: {} + data-urls@6.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 15.1.0 + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -14039,6 +15095,8 @@ snapshots: dependencies: character-entities: 2.0.2 + deep-eql@5.0.2: {} + deep-extend@0.6.0: {} deep-is@0.1.4: {} @@ -14093,6 +15151,8 @@ snapshots: delayed-stream@1.0.0: {} + deprecation@2.3.1: {} + dequal@2.0.3: {} destr@2.0.5: {} @@ -14127,6 +15187,10 @@ snapshots: dependencies: esutils: 2.0.3 + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + docx@9.5.1: dependencies: '@types/node': 24.10.0 @@ -14136,6 +15200,10 @@ snapshots: xml: 1.0.1 xml-js: 1.6.11 + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -14223,6 +15291,8 @@ snapshots: emoji-regex@9.2.2: {} + empathic@2.0.0: {} + encodeurl@1.0.2: {} enhanced-resolve@5.18.3: @@ -14452,6 +15522,15 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 + eslint-plugin-storybook@10.0.8(eslint@9.38.0(jiti@2.6.1))(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.9.3): + dependencies: + '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.38.0(jiti@2.6.1) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + transitivePeerDependencies: + - supports-color + - typescript + eslint-plugin-turbo@2.5.8(eslint@9.38.0(jiti@2.6.1))(turbo@2.5.8): dependencies: dotenv: 16.0.3 @@ -14645,6 +15724,8 @@ snapshots: file-saver@2.0.5: {} + filesize@10.1.6: {} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -14728,6 +15809,9 @@ snapshots: fs.realpath@1.0.0: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -15026,6 +16110,10 @@ snapshots: hookable@5.5.3: {} + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + html-escaper@2.0.2: {} html-parse-stringify@3.0.1: @@ -15314,6 +16402,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-potential-custom-element-name@1.0.1: {} + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -15434,6 +16524,33 @@ snapshots: jsbi@4.3.2: {} + jsdom@27.2.0: + dependencies: + '@acemir/cssom': 0.9.24 + '@asamuzakjp/dom-selector': 6.7.4 + cssstyle: 5.3.3 + data-urls: 6.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + parse5: 8.0.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 15.1.0 + ws: 8.18.3 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -15652,6 +16769,8 @@ snapshots: dependencies: js-tokens: 4.0.0 + loupe@3.2.1: {} + lower-case-first@1.0.2: dependencies: lower-case: 1.1.4 @@ -15664,6 +16783,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.2.2: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -15683,7 +16804,7 @@ snapshots: magic-string-stack@1.1.0: dependencies: '@jridgewell/remapping': 2.3.5 - magic-string: 0.30.19 + magic-string: 0.30.21 magic-string@0.30.19: dependencies: @@ -16264,6 +17385,8 @@ snapshots: mimic-fn@2.1.0: {} + min-indent@1.0.1: {} + minimalistic-assert@1.0.1: {} minimatch@3.1.2: @@ -16632,6 +17755,10 @@ snapshots: is-decimal: 2.0.1 is-hexadecimal: 2.0.1 + parse5@8.0.0: + dependencies: + entities: 6.0.1 + parseurl@1.3.3: {} pascal-case@2.0.1: @@ -16671,6 +17798,8 @@ snapshots: pathe@2.0.3: {} + pathval@2.0.1: {} + pdf-lib@1.17.1: dependencies: '@pdf-lib/standard-fonts': 1.0.0 @@ -16690,6 +17819,10 @@ snapshots: picomatch@4.0.3: {} + pixelmatch@7.1.0: + dependencies: + pngjs: 7.0.0 + pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -16704,6 +17837,16 @@ snapshots: plantuml-encoder@1.4.0: {} + playwright-core@1.57.0: {} + + playwright@1.57.0: + dependencies: + playwright-core: 1.57.0 + optionalDependencies: + fsevents: 2.3.2 + + pngjs@7.0.0: {} + points-on-curve@0.2.0: {} points-on-path@0.2.1: @@ -16778,6 +17921,12 @@ snapshots: prettier@3.6.2: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + prism-theme-vars@0.2.5: {} prismjs@1.30.0: {} @@ -16951,6 +18100,25 @@ snapshots: date-fns-jalali: 4.1.0-0 react: 19.2.0 + react-docgen-typescript@2.4.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + react-docgen@8.0.2: + dependencies: + '@babel/core': 7.28.4 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.5 + '@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.10 + strip-indent: 4.1.1 + transitivePeerDependencies: + - supports-color + react-dom@19.2.0(react@19.2.0): dependencies: react: 19.2.0 @@ -16981,6 +18149,8 @@ snapshots: react-is@16.13.1: {} + react-is@17.0.2: {} + react-is@19.2.0: {} react-paginate@8.3.0(react@19.2.0): @@ -17143,6 +18313,11 @@ snapshots: recordrtc@5.6.2: {} + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + redux-persist@6.0.0(react@19.2.0)(redux@5.0.1): dependencies: redux: 5.0.1 @@ -17295,6 +18470,8 @@ snapshots: require-directory@2.1.1: {} + require-from-string@2.0.2: {} + reselect@5.1.1: {} resolve-from@4.0.0: {} @@ -17412,6 +18589,10 @@ snapshots: sax@1.4.3: {} + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.27.0: {} scule@1.3.0: @@ -17637,6 +18818,30 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 + storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)): + dependencies: + '@storybook/global': 5.0.0 + '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@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/mocker': 3.2.4(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/spy': 3.2.4 + esbuild: 0.25.11 + recast: 0.23.11 + semver: 7.7.3 + ws: 8.18.3 + optionalDependencies: + prettier: 3.6.2 + transitivePeerDependencies: + - '@testing-library/dom' + - bufferutil + - msw + - react + - react-dom + - utf-8-validate + - vite + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -17722,8 +18927,16 @@ snapshots: strip-bom-string@1.0.0: {} + strip-bom@3.0.0: {} + strip-final-newline@2.0.0: {} + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + + strip-indent@4.1.1: {} + strip-json-comments@2.0.1: {} strip-json-comments@3.1.1: {} @@ -17798,6 +19011,8 @@ snapshots: react: 19.2.0 use-sync-external-store: 1.6.0(react@19.2.0) + symbol-tree@3.2.4: {} + tailwind-merge@3.3.1: {} tailwind-variants@2.1.0(tailwind-merge@3.3.1)(tailwindcss@4.1.14): @@ -17850,13 +19065,23 @@ snapshots: '@types/tinycolor2': 1.4.6 tinycolor2: 1.6.0 + tinyrainbow@2.0.0: {} + tinyrainbow@3.0.3: {} + tinyspy@4.0.4: {} + title-case@2.1.1: dependencies: no-case: 2.3.2 upper-case: 1.1.3 + tldts-core@7.0.19: {} + + tldts@7.0.19: + dependencies: + tldts-core: 7.0.19 + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -17869,8 +19094,16 @@ snapshots: totalist@3.0.1: {} + tough-cookie@6.0.0: + dependencies: + tldts: 7.0.19 + tr46@0.0.3: {} + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + tree-dump@1.1.0(tslib@2.8.1): dependencies: tslib: 2.8.1 @@ -17907,6 +19140,12 @@ snapshots: ts-pattern@5.8.0: {} + tsconfig-paths@4.2.0: + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + tslib@1.14.1: {} tslib@2.3.0: {} @@ -17924,6 +19163,8 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tunnel@0.0.6: {} + turbo-darwin-64@2.5.8: optional: true @@ -18053,7 +19294,7 @@ snapshots: dependencies: acorn: 8.15.0 estree-walker: 3.0.3 - magic-string: 0.30.19 + magic-string: 0.30.21 unplugin: 2.3.10 optional: true @@ -18063,6 +19304,10 @@ snapshots: undici-types@7.16.0: {} + undici@5.29.0: + dependencies: + '@fastify/busboy': 2.1.1 + unhead@2.0.19: dependencies: hookable: 5.5.3 @@ -18083,7 +19328,7 @@ snapshots: escape-string-regexp: 5.0.0 estree-walker: 3.0.3 local-pkg: 1.1.2 - magic-string: 0.30.19 + magic-string: 0.30.21 mlly: 1.8.0 pathe: 2.0.3 picomatch: 4.0.3 @@ -18122,6 +19367,8 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 + universal-user-agent@6.0.1: {} + universalify@2.0.1: {} unocss@66.5.4(postcss@8.5.6)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)): @@ -18175,7 +19422,7 @@ snapshots: chokidar: 4.0.3 debug: 4.4.3 local-pkg: 1.1.2 - magic-string: 0.30.19 + magic-string: 0.30.21 mlly: 1.8.0 tinyglobby: 0.2.15 unplugin: 2.3.10 @@ -18206,6 +19453,11 @@ snapshots: webpack-sources: 3.3.3 webpack-virtual-modules: 0.5.0 + unplugin@1.16.1: + dependencies: + acorn: 8.15.0 + webpack-virtual-modules: 0.6.2 + unplugin@2.3.10: dependencies: '@jridgewell/remapping': 2.3.5 @@ -18345,7 +19597,7 @@ snapshots: vite-plugin-remote-assets@2.1.0(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)): dependencies: debug: 4.4.3 - magic-string: 0.30.19 + magic-string: 0.30.21 node-fetch-native: 1.6.7 ohash: 2.0.11 vite: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) @@ -18407,7 +19659,7 @@ snapshots: optionalDependencies: vite: 7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1) - vitest@4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1): + vitest@4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.0)(@vitest/browser-playwright@4.0.14)(jiti@2.6.1)(jsdom@27.2.0)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: '@vitest/expect': 4.0.14 '@vitest/mocker': 4.0.14(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1)) @@ -18432,6 +19684,8 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.10.0 + '@vitest/browser-playwright': 4.0.14(playwright@1.57.0)(vite@7.1.10(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14) + jsdom: 27.2.0 transitivePeerDependencies: - jiti - less @@ -18485,6 +19739,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + walk-up-path@4.0.0: {} wcwidth@1.0.1: @@ -18493,12 +19751,25 @@ snapshots: webidl-conversions@3.0.1: {} + webidl-conversions@8.0.0: {} + webpack-sources@3.3.3: {} webpack-virtual-modules@0.5.0: {} webpack-virtual-modules@0.6.2: {} + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@15.1.0: + dependencies: + tr46: 6.0.0 + webidl-conversions: 8.0.0 + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -18584,6 +19855,8 @@ snapshots: wrappy@1.0.2: {} + ws@8.18.3: {} + wsl-utils@0.1.0: dependencies: is-wsl: 3.1.0 @@ -18592,8 +19865,12 @@ snapshots: dependencies: sax: 1.4.3 + xml-name-validator@5.0.0: {} + xml@1.0.1: {} + xmlchars@2.2.0: {} + xstate@5.23.0: {} y18n@5.0.8: {}