diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index c6df455..0a24c40 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -1,9 +1,9 @@ --- name: 버그 리포트 about: 버그 리포트 -title: "[페이지이름 or 공통]: " -labels: "Fix" -assignees: "" +title: '[페이지이름 or 공통]: ' +labels: 'Fix' +assignees: '' --- ## #️⃣ Related Issue diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md index 99062d5..a10e2e4 100644 --- a/.github/ISSUE_TEMPLATE/feature.md +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -1,9 +1,9 @@ --- name: 기능 구현 및 제안 이슈 about: 기능 구현 및 제안 이슈 -title: "[페이지이름 or 공통]: " -labels: "Feature" -assignees: "" +title: '[페이지이름 or 공통]: ' +labels: 'Feature' +assignees: '' --- ## #️⃣ Related Issue diff --git a/.gitignore b/.gitignore index b8d7e45..5db67e5 100644 --- a/.gitignore +++ b/.gitignore @@ -75,4 +75,6 @@ sketch .LSOverride # -# End of https://www.toptal.com/developers/gitignore/api/nextjs,react,git \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/nextjs,react,git +*storybook.log +storybook-static diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9a2eadf --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "javascript.preferences.importModuleSpecifier": "non-relative", + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "eslint.format.enable": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + } +} diff --git a/README.md b/README.md index fadefb5..3b77933 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ # Taskify -> [!NOTE] -> 프로젝트 소개 -> + +> [!NOTE] 프로젝트 소개 + # 기여자 + # 주요 기능 + ### 유저 플로우 차트 + Taskify_ User Flow # 기술 스택 + ## 프로젝트 구조 diff --git a/eslint.config.ts b/eslint.config.ts index d7dc280..388a30b 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -15,12 +15,12 @@ const sheriffOptions: SheriffSettings = { export default tseslint.config(sheriff(sheriffOptions), { languageOptions: { parserOptions: { + projectService: true, project: './tsconfig.json', - tsconfigRootDir: __dirname, + tsconfigRootDir: import.meta.dirname, }, }, rules: { - // https://typescript-eslint.io/rules/no-misused-promises/#checksvoidreturn '@typescript-eslint/no-misused-promises': [ 'error', { @@ -38,10 +38,10 @@ export default tseslint.config(sheriff(sheriffOptions), { '@typescript-eslint/no-floating-promises': 'off', 'react-refresh/only-export-components': 'off', 'react/jsx-no-useless-fragment': 'off', - 'react/jsx-boolean-value': 'off', - '@typescript-eslint/no-misused-spread': 'off', - 'fsecond/prefer-destructured-optionals': 'off', - 'unicorn/consistent-function-scoping': 'off', + '@typescript-eslint/naming-convention': 'off', + 'jsdoc/require-description-complete-sentence': 'off', 'func-style': 'off', + 'no-negated-condition': 'off', + 'unicorn/consistent-function-scoping': 'off', }, }); diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 0000000..cf149c2 --- /dev/null +++ b/middleware.ts @@ -0,0 +1,52 @@ +import { type NextRequest, NextResponse } from 'next/server'; + +const LOGIN_PATH = '/login'; +const DASHBOARD_PATH = '/dashboard'; +const MYDASHBOARD_PATH = '/mydashboard'; + +export function middleware(request: NextRequest): NextResponse { + const { pathname } = request.nextUrl; + + // 보호된 경로들 + const protectedPaths = [MYDASHBOARD_PATH, '/mypage', DASHBOARD_PATH]; + // 인증 페이지들(로그인/회원가입) + const authPages = [LOGIN_PATH, '/signup']; + + // 현재 경로가 보호된 경로인지 확인 + const isProtectedPath = protectedPaths.some((path) => + pathname.startsWith(path) + ); + + const accessToken = request.cookies.get('access_token'); + + // 이미 로그인된 사용자가 로그인/회원가입 페이지 접근 시 대시보드로 보냄 + const isAuthPage = authPages.some((path) => pathname.startsWith(path)); + + if (isAuthPage && accessToken) { + const dashUrl = new URL(MYDASHBOARD_PATH, request.url); + + return NextResponse.redirect(dashUrl); + } + + if (isProtectedPath && !accessToken) { + // 쿠키가 없으면 로그인 페이지로 리다이렉트 (next 파라미터 없이) + const loginUrl = new URL(LOGIN_PATH, request.url); + + return NextResponse.redirect(loginUrl); + } + + return NextResponse.next(); +} + +export const config = { + matcher: [ + MYDASHBOARD_PATH, + `${MYDASHBOARD_PATH}/:path*`, + '/mypage', + '/mypage/:path*', + DASHBOARD_PATH, + `${DASHBOARD_PATH}/:path*`, + LOGIN_PATH, + '/signup', + ], +}; diff --git a/next.config.ts b/next.config.ts index 3915163..281d99e 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,8 +1,18 @@ -import type { NextConfig } from "next"; +import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ reactStrictMode: true, + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'sprint-fe-project.s3.ap-northeast-2.amazonaws.com', + port: '', + pathname: '/taskify/**', + }, + ], + }, }; export default nextConfig; diff --git a/package-lock.json b/package-lock.json index a33c0fe..83a21a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,21 +19,38 @@ "zod": "^4.1.5" }, "devDependencies": { + "@chromatic-com/storybook": "^4.1.1", "@eslint/eslintrc": "^3", + "@storybook/addon-a11y": "^9.1.3", + "@storybook/addon-docs": "^9.1.3", + "@storybook/addon-vitest": "^9.1.3", + "@storybook/nextjs-vite": "^9.1.3", "@tailwindcss/postcss": "^4.1.12", "@types/node": "^20", "@types/react": "^19.1.12", "@types/react-dom": "^19", + "@vitest/browser": "^3.2.4", + "@vitest/coverage-v8": "^3.2.4", "eslint": "^9.34.0", "eslint-config-next": "15.5.2", "eslint-config-sheriff": "^28.1.0", "jiti": "^2.5.1", + "playwright": "^1.55.0", "prettier": "^3.6.2", "prettier-plugin-tailwindcss": "^0.6.14", + "storybook": "^9.1.3", "tailwindcss": "^4.1.12", - "typescript": "^5" + "typescript": "^5", + "vitest": "^3.2.4" } }, + "node_modules/@adobe/css-tools": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "dev": true, + "license": "MIT" + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -47,6 +64,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@astrojs/compiler": { "version": "2.12.2", "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.12.2.tgz", @@ -69,1193 +100,2825 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@emnapi/core": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", - "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==", + "node_modules/@babel/core": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", + "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.0.4", - "tslib": "^2.4.0" + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.3", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@emnapi/runtime": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz", - "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==", + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz", - "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==", + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.50.2", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", - "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.6", - "@typescript-eslint/types": "^8.11.0", - "comment-parser": "1.4.1", - "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~4.1.0" + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.4.3" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" }, - "funding": { - "url": "https://opencollective.com/eslint" + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "@babel/core": "^7.0.0" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=6.9.0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "license": "MIT", "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=6.9.0" } }, - "node_modules/@eslint-react/ast": { - "version": "1.52.6", - "resolved": "https://registry.npmjs.org/@eslint-react/ast/-/ast-1.52.6.tgz", - "integrity": "sha512-yBJ8dVflLezQslQ15YN2tc792ceYpXUQWR/VefN508mWMpZ4wUEwf5/BKm33nzcMdLc8IyoUhKjmgW2HZCrboA==", + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", + "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-react/eff": "1.52.6", - "@typescript-eslint/types": "^8.39.1", - "@typescript-eslint/typescript-estree": "^8.39.1", - "@typescript-eslint/utils": "^8.39.1", - "string-ts": "^2.2.1", - "ts-pattern": "^5.8.0" + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" }, "engines": { - "node": ">=18.18.0" + "node": ">=6.9.0" } }, - "node_modules/@eslint-react/core": { - "version": "1.52.6", - "resolved": "https://registry.npmjs.org/@eslint-react/core/-/core-1.52.6.tgz", - "integrity": "sha512-Nas0c5E9wwvHaD78YDTr6VB9M6xhWICtn1nWn2ChoqKHnbw3UNveYErVUwcuUcfbAGn9taVE0fqaj+MY6zQlag==", + "node_modules/@babel/parser": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", + "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-react/ast": "1.52.6", - "@eslint-react/eff": "1.52.6", - "@eslint-react/kit": "1.52.6", - "@eslint-react/shared": "1.52.6", - "@eslint-react/var": "1.52.6", - "@typescript-eslint/scope-manager": "^8.39.1", - "@typescript-eslint/type-utils": "^8.39.1", - "@typescript-eslint/types": "^8.39.1", - "@typescript-eslint/utils": "^8.39.1", - "birecord": "^0.1.1", - "ts-pattern": "^5.8.0" + "@babel/types": "^7.28.2" + }, + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { - "node": ">=18.18.0" + "node": ">=6.0.0" } }, - "node_modules/@eslint-react/eff": { - "version": "1.52.6", - "resolved": "https://registry.npmjs.org/@eslint-react/eff/-/eff-1.52.6.tgz", - "integrity": "sha512-UpiV0zSIHRFCx6rmDu48gDwrS4wn/+5Ciimukxt3c0PoTGOI/kKpPuHXsQBlP15CqvPOCD6wt8VxOnNug/cKmA==", + "node_modules/@babel/runtime": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", + "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", "dev": true, "license": "MIT", "engines": { - "node": ">=18.18.0" + "node": ">=6.9.0" } }, - "node_modules/@eslint-react/eslint-plugin": { - "version": "1.52.6", - "resolved": "https://registry.npmjs.org/@eslint-react/eslint-plugin/-/eslint-plugin-1.52.6.tgz", - "integrity": "sha512-Tj2pyYQC4795tfun6u5QIXXS80wSKMFF4Su+t4eLGhLXPX2d1heZX2lgztbaIj9ToRqiX/Mk+9PvYCbAiE+zZw==", + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-react/eff": "1.52.6", - "@eslint-react/kit": "1.52.6", - "@eslint-react/shared": "1.52.6", - "@typescript-eslint/scope-manager": "^8.39.1", - "@typescript-eslint/type-utils": "^8.39.1", - "@typescript-eslint/types": "^8.39.1", - "@typescript-eslint/utils": "^8.39.1", - "eslint-plugin-react-debug": "1.52.6", - "eslint-plugin-react-dom": "1.52.6", - "eslint-plugin-react-hooks-extra": "1.52.6", - "eslint-plugin-react-naming-convention": "1.52.6", - "eslint-plugin-react-web-api": "1.52.6", - "eslint-plugin-react-x": "1.52.6" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { - "node": ">=18.18.0" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "^4.9.5 || ^5.3.3" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": false - }, - "typescript": { - "optional": true - } + "node": ">=6.9.0" } }, - "node_modules/@eslint-react/kit": { - "version": "1.52.6", - "resolved": "https://registry.npmjs.org/@eslint-react/kit/-/kit-1.52.6.tgz", - "integrity": "sha512-4xkVhPQkeGcyjdoM9mocbjCF96lFP1jXXE2XrsThiy+U/e/BQEz0oOdHBFXdzVmmMGGFjHsbQo6MAIZCoVAAGg==", + "node_modules/@babel/traverse": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", + "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-react/eff": "1.52.6", - "@typescript-eslint/utils": "^8.39.1", - "ts-pattern": "^5.8.0", - "zod": "^4.0.17" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2", + "debug": "^4.3.1" }, "engines": { - "node": ">=18.18.0" + "node": ">=6.9.0" } }, - "node_modules/@eslint-react/shared": { - "version": "1.52.6", - "resolved": "https://registry.npmjs.org/@eslint-react/shared/-/shared-1.52.6.tgz", - "integrity": "sha512-gIvwDQtRXqxa5IoRQDjKZBGZSj7GlGOwwKUqgaLmerlmNbrEyFn/AG0E6e1NBh80WdAmFSiuJG+2Lct1p8SnZg==", + "node_modules/@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-react/eff": "1.52.6", - "@eslint-react/kit": "1.52.6", - "@typescript-eslint/utils": "^8.39.1", - "ts-pattern": "^5.8.0", - "zod": "^4.0.17" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { - "node": ">=18.18.0" + "node": ">=6.9.0" } }, - "node_modules/@eslint-react/var": { - "version": "1.52.6", - "resolved": "https://registry.npmjs.org/@eslint-react/var/-/var-1.52.6.tgz", - "integrity": "sha512-oeAexe8FhImk3RstFvSSbVBFYRMPAVvuUscOrKBbhf9xc0/3drYpLXSPceA++2VaOk/M1mD91ceca9+V0UfNkw==", + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, "license": "MIT", - "dependencies": { - "@eslint-react/ast": "1.52.6", - "@eslint-react/eff": "1.52.6", - "@typescript-eslint/scope-manager": "^8.39.1", - "@typescript-eslint/types": "^8.39.1", - "@typescript-eslint/utils": "^8.39.1", - "string-ts": "^2.2.1", - "ts-pattern": "^5.8.0" - }, "engines": { - "node": ">=18.18.0" + "node": ">=18" } }, - "node_modules/@eslint/compat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.3.2.tgz", - "integrity": "sha512-jRNwzTbd6p2Rw4sZ1CgWRS8YMtqG15YyZf7zvb6gY2rB2u6n+2Z+ELW0GtL0fQgyl0pr4Y/BzBfng/BdsereRA==", + "node_modules/@chromatic-com/storybook": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-4.1.1.tgz", + "integrity": "sha512-+Ib4cHtEjKl/Do+4LyU0U1FhLPbIU2Q/zgbOKHBCV+dTC4T3/vGzPqiGsgkdnZyTsK/zXg96LMPSPC4jjOiapg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "@neoconfetti/react": "^1.0.0", + "chromatic": "^12.0.0", + "filesize": "^10.0.12", + "jsonfile": "^6.1.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=20.0.0", + "yarn": ">=1.22.18" }, "peerDependencies": { - "eslint": "^8.40 || 9" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "storybook": "^0.0.0-0 || ^9.0.0 || ^9.1.0-0 || ^9.2.0-0 || ^10.0.0-0" } }, - "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "node_modules/@emnapi/core": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", + "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", - "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "@emnapi/wasi-threads": "1.0.4", + "tslib": "^2.4.0" } }, - "node_modules/@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@emnapi/runtime": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz", + "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==", + "license": "MIT", + "optional": true, "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "tslib": "^2.4.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz", + "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "tslib": "^2.4.0" } }, - "node_modules/@eslint/js": { - "version": "9.34.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.34.0.tgz", - "integrity": "sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw==", + "node_modules/@es-joy/jsdoccomment": { + "version": "0.50.2", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", + "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", "dev": true, "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", - "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", - "dev": true, - "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.15.2", - "levn": "^0.4.1" + "@types/estree": "^1.0.6", + "@typescript-eslint/types": "^8.11.0", + "comment-parser": "1.4.1", + "esquery": "^1.6.0", + "jsdoc-type-pratt-parser": "~4.1.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" + "node": ">=18" } }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=18.18.0" + "node": ">=18" } }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": ">=18" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": ">=18" } }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": ">=18" } }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz", - "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", "cpu": [ "arm64" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.0" + "node": ">=18" } }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz", - "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", "cpu": [ "x64" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.0" + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz", - "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ - "darwin" + "freebsd" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz", - "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", "cpu": [ "x64" ], - "license": "LGPL-3.0-or-later", - "optional": true, + "dev": true, + "license": "MIT", + "optional": true, "os": [ - "darwin" + "freebsd" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz", - "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==", + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", "cpu": [ "arm" ], - "license": "LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz", - "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz", - "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", "cpu": [ - "ppc64" + "ia32" ], - "license": "LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz", - "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", "cpu": [ - "s390x" + "loong64" ], - "license": "LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz", - "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", "cpu": [ - "x64" + "mips64el" ], - "license": "LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz", - "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", "cpu": [ - "arm64" + "ppc64" ], - "license": "LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz", - "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", "cpu": [ - "x64" + "riscv64" ], - "license": "LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz", - "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", "cpu": [ - "arm" + "s390x" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.0" + "node": ">=18" } }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz", - "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==", + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", "cpu": [ - "arm64" + "x64" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.0" + "node": ">=18" } }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz", - "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", "cpu": [ - "ppc64" + "arm64" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "netbsd" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.0" + "node": ">=18" } }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz", - "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", "cpu": [ - "s390x" + "x64" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "netbsd" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.0" + "node": ">=18" } }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz", - "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", "cpu": [ - "x64" + "arm64" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "openbsd" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.0" + "node": ">=18" } }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz", - "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", "cpu": [ - "arm64" + "x64" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "openbsd" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" + "node": ">=18" } }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz", - "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", "cpu": [ - "x64" + "arm64" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "openharmony" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.0" + "node": ">=18" } }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz", - "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", "cpu": [ - "wasm32" + "x64" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "dev": true, + "license": "MIT", "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.4.4" - }, + "os": [ + "sunos" + ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=18" } }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz", - "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", "cpu": [ "arm64" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=18" } }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz", - "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", "cpu": [ "ia32" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=18" } }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz", - "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==", + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", "cpu": [ "x64" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/libvips" + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint-react/ast": { + "version": "1.52.6", + "resolved": "https://registry.npmjs.org/@eslint-react/ast/-/ast-1.52.6.tgz", + "integrity": "sha512-yBJ8dVflLezQslQ15YN2tc792ceYpXUQWR/VefN508mWMpZ4wUEwf5/BKm33nzcMdLc8IyoUhKjmgW2HZCrboA==", + "dev": true, + "license": "MIT", "dependencies": { - "minipass": "^7.0.4" + "@eslint-react/eff": "1.52.6", + "@typescript-eslint/types": "^8.39.1", + "@typescript-eslint/typescript-estree": "^8.39.1", + "@typescript-eslint/utils": "^8.39.1", + "string-ts": "^2.2.1", + "ts-pattern": "^5.8.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=18.18.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@eslint-react/core": { + "version": "1.52.6", + "resolved": "https://registry.npmjs.org/@eslint-react/core/-/core-1.52.6.tgz", + "integrity": "sha512-Nas0c5E9wwvHaD78YDTr6VB9M6xhWICtn1nWn2ChoqKHnbw3UNveYErVUwcuUcfbAGn9taVE0fqaj+MY6zQlag==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@eslint-react/ast": "1.52.6", + "@eslint-react/eff": "1.52.6", + "@eslint-react/kit": "1.52.6", + "@eslint-react/shared": "1.52.6", + "@eslint-react/var": "1.52.6", + "@typescript-eslint/scope-manager": "^8.39.1", + "@typescript-eslint/type-utils": "^8.39.1", + "@typescript-eslint/types": "^8.39.1", + "@typescript-eslint/utils": "^8.39.1", + "birecord": "^0.1.1", + "ts-pattern": "^5.8.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@eslint-react/eff": { + "version": "1.52.6", + "resolved": "https://registry.npmjs.org/@eslint-react/eff/-/eff-1.52.6.tgz", + "integrity": "sha512-UpiV0zSIHRFCx6rmDu48gDwrS4wn/+5Ciimukxt3c0PoTGOI/kKpPuHXsQBlP15CqvPOCD6wt8VxOnNug/cKmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@eslint-react/eslint-plugin": { + "version": "1.52.6", + "resolved": "https://registry.npmjs.org/@eslint-react/eslint-plugin/-/eslint-plugin-1.52.6.tgz", + "integrity": "sha512-Tj2pyYQC4795tfun6u5QIXXS80wSKMFF4Su+t4eLGhLXPX2d1heZX2lgztbaIj9ToRqiX/Mk+9PvYCbAiE+zZw==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@eslint-react/eff": "1.52.6", + "@eslint-react/kit": "1.52.6", + "@eslint-react/shared": "1.52.6", + "@typescript-eslint/scope-manager": "^8.39.1", + "@typescript-eslint/type-utils": "^8.39.1", + "@typescript-eslint/types": "^8.39.1", + "@typescript-eslint/utils": "^8.39.1", + "eslint-plugin-react-debug": "1.52.6", + "eslint-plugin-react-dom": "1.52.6", + "eslint-plugin-react-hooks-extra": "1.52.6", + "eslint-plugin-react-naming-convention": "1.52.6", + "eslint-plugin-react-web-api": "1.52.6", + "eslint-plugin-react-x": "1.52.6" + }, + "engines": { + "node": ">=18.18.0" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "^4.9.5 || ^5.3.3" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": false + }, + "typescript": { + "optional": true + } } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@eslint-react/kit": { + "version": "1.52.6", + "resolved": "https://registry.npmjs.org/@eslint-react/kit/-/kit-1.52.6.tgz", + "integrity": "sha512-4xkVhPQkeGcyjdoM9mocbjCF96lFP1jXXE2XrsThiy+U/e/BQEz0oOdHBFXdzVmmMGGFjHsbQo6MAIZCoVAAGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-react/eff": "1.52.6", + "@typescript-eslint/utils": "^8.39.1", + "ts-pattern": "^5.8.0", + "zod": "^4.0.17" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@eslint-react/shared": { + "version": "1.52.6", + "resolved": "https://registry.npmjs.org/@eslint-react/shared/-/shared-1.52.6.tgz", + "integrity": "sha512-gIvwDQtRXqxa5IoRQDjKZBGZSj7GlGOwwKUqgaLmerlmNbrEyFn/AG0E6e1NBh80WdAmFSiuJG+2Lct1p8SnZg==", "dev": true, "license": "MIT", + "dependencies": { + "@eslint-react/eff": "1.52.6", + "@eslint-react/kit": "1.52.6", + "@typescript-eslint/utils": "^8.39.1", + "ts-pattern": "^5.8.0", + "zod": "^4.0.17" + }, "engines": { - "node": ">=6.0.0" + "node": ">=18.18.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "node_modules/@eslint-react/var": { + "version": "1.52.6", + "resolved": "https://registry.npmjs.org/@eslint-react/var/-/var-1.52.6.tgz", + "integrity": "sha512-oeAexe8FhImk3RstFvSSbVBFYRMPAVvuUscOrKBbhf9xc0/3drYpLXSPceA++2VaOk/M1mD91ceca9+V0UfNkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "1.52.6", + "@eslint-react/eff": "1.52.6", + "@typescript-eslint/scope-manager": "^8.39.1", + "@typescript-eslint/types": "^8.39.1", + "@typescript-eslint/utils": "^8.39.1", + "string-ts": "^2.2.1", + "ts-pattern": "^5.8.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.3.2.tgz", + "integrity": "sha512-jRNwzTbd6p2Rw4sZ1CgWRS8YMtqG15YyZf7zvb6gY2rB2u6n+2Z+ELW0GtL0fQgyl0pr4Y/BzBfng/BdsereRA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^8.40 || 9" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.34.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.34.0.tgz", + "integrity": "sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz", + "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.0" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz", + "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.0" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz", + "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz", + "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz", + "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz", + "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz", + "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz", + "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz", + "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz", + "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz", + "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz", + "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz", + "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz", + "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz", + "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.0" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz", + "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz", + "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.0" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz", + "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.4.4" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz", + "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz", + "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz", + "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.6.1.tgz", + "integrity": "sha512-J4BaTocTOYFkMHIra1JDWrMWpNmBl4EkplIwHEsV8aeUOtdWjwSnln9U7twjMFTAEB7mptNtSKyVi1Y2W9sDJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^10.0.0", + "magic-string": "^0.30.0", + "react-docgen-typescript": "^2.2.2" + }, + "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 + } + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", + "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", + "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", + "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.14.2", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@neoconfetti/react": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@neoconfetti/react/-/react-1.0.0.tgz", + "integrity": "sha512-klcSooChXXOzIm+SE5IISIAn3bYzYfPjbX7D7HoqZL84oAfgREeSg5vSIaSFH+DaGzzvImTyWe1OyrJ67vik4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@next/env": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.2.tgz", + "integrity": "sha512-Qe06ew4zt12LeO6N7j8/nULSOe3fMXE4dM6xgpBQNvdzyK1sv5y4oAP3bq4LamrvGCZtmRYnW8URFCeX5nFgGg==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.2.tgz", + "integrity": "sha512-lkLrRVxcftuOsJNhWatf1P2hNVfh98k/omQHrCEPPriUypR6RcS13IvLdIrEvkm9AH2Nu2YpR5vLqBuy6twH3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.2.tgz", + "integrity": "sha512-8bGt577BXGSd4iqFygmzIfTYizHb0LGWqH+qgIF/2EDxS5JsSdERJKA8WgwDyNBZgTIIA4D8qUtoQHmxIIquoQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.2.tgz", + "integrity": "sha512-2DjnmR6JHK4X+dgTXt5/sOCu/7yPtqpYt8s8hLkHFK3MGkka2snTv3yRMdHvuRtJVkPwCGsvBSwmoQCHatauFQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.2.tgz", + "integrity": "sha512-3j7SWDBS2Wov/L9q0mFJtEvQ5miIqfO4l7d2m9Mo06ddsgUK8gWfHGgbjdFlCp2Ek7MmMQZSxpGFqcC8zGh2AA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.2.tgz", + "integrity": "sha512-s6N8k8dF9YGc5T01UPQ08yxsK6fUow5gG1/axWc1HVVBYQBgOjca4oUZF7s4p+kwhkB1bDSGR8QznWrFZ/Rt5g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.2.tgz", + "integrity": "sha512-o1RV/KOODQh6dM6ZRJGZbc+MOAHww33Vbs5JC9Mp1gDk8cpEO+cYC/l7rweiEalkSm5/1WGa4zY7xrNwObN4+Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.2.tgz", + "integrity": "sha512-/VUnh7w8RElYZ0IV83nUcP/J4KJ6LLYliiBIri3p3aW2giF+PAVgZb6mk8jbQSB3WlTai8gEmCAr7kptFa1H6g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.2.tgz", + "integrity": "sha512-sMPyTvRcNKXseNQ/7qRfVRLa0VhR0esmQ29DD6pqvG71+JdVnESJaHPA8t7bc67KD5spP3+DOCNLhqlEI2ZgQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.2.tgz", + "integrity": "sha512-W5VvyZHnxG/2ukhZF/9Ikdra5fdNftxI6ybeVKYvBPDtyx7x4jPPSNduUkfH5fo3zG0JQ0bPxgy41af2JX5D4Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@regru/eslint-plugin-prefer-early-return": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@regru/eslint-plugin-prefer-early-return/-/eslint-plugin-prefer-early-return-1.0.0.tgz", + "integrity": "sha512-rOIjKi/npfNcunmrakkKQAolX/qakY8DUkp/P0PeSmQ0xnTNT6CCTHcMHxhFEvLRlrIBY3gJkUwh5rt9Z+GTyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/pluginutils": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.49.0.tgz", + "integrity": "sha512-rlKIeL854Ed0e09QGYFlmDNbka6I3EQFw7iZuugQjMb11KMpJCLPFL4ZPbMfaEhLADEL1yx0oujGkBQ7+qW3eA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.49.0.tgz", + "integrity": "sha512-cqPpZdKUSQYRtLLr6R4X3sD4jCBO1zUmeo3qrWBCqYIeH8Q3KRL4F3V7XJ2Rm8/RJOQBZuqzQGWPjjvFUcYa/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.49.0.tgz", + "integrity": "sha512-99kMMSMQT7got6iYX3yyIiJfFndpojBmkHfTc1rIje8VbjhmqBXE+nb7ZZP3A5skLyujvT0eIUCUsxAe6NjWbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.49.0.tgz", + "integrity": "sha512-y8cXoD3wdWUDpjOLMKLx6l+NFz3NlkWKcBCBfttUn+VGSfgsQ5o/yDUGtzE9HvsodkP0+16N0P4Ty1VuhtRUGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.49.0.tgz", + "integrity": "sha512-3mY5Pr7qv4GS4ZvWoSP8zha8YoiqrU+e0ViPvB549jvliBbdNLrg2ywPGkgLC3cmvN8ya3za+Q2xVyT6z+vZqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.49.0.tgz", + "integrity": "sha512-C9KzzOAQU5gU4kG8DTk+tjdKjpWhVWd5uVkinCwwFub2m7cDYLOdtXoMrExfeBmeRy9kBQMkiyJ+HULyF1yj9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.49.0.tgz", + "integrity": "sha512-OVSQgEZDVLnTbMq5NBs6xkmz3AADByCWI4RdKSFNlDsYXdFtlxS59J+w+LippJe8KcmeSSM3ba+GlsM9+WwC1w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.49.0.tgz", + "integrity": "sha512-ZnfSFA7fDUHNa4P3VwAcfaBLakCbYaxCk0jUnS3dTou9P95kwoOLAMlT3WmEJDBCSrOEFFV0Y1HXiwfLYJuLlA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.49.0.tgz", + "integrity": "sha512-Z81u+gfrobVK2iV7GqZCBfEB1y6+I61AH466lNK+xy1jfqFLiQ9Qv716WUM5fxFrYxwC7ziVdZRU9qvGHkYIJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.49.0.tgz", + "integrity": "sha512-zoAwS0KCXSnTp9NH/h9aamBAIve0DXeYpll85shf9NJ0URjSTzzS+Z9evmolN+ICfD3v8skKUPyk2PO0uGdFqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.49.0.tgz", + "integrity": "sha512-2QyUyQQ1ZtwZGiq0nvODL+vLJBtciItC3/5cYN8ncDQcv5avrt2MbKt1XU/vFAJlLta5KujqyHdYtdag4YEjYQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.49.0.tgz", + "integrity": "sha512-k9aEmOWt+mrMuD3skjVJSSxHckJp+SiFzFG+v8JLXbc/xi9hv2icSkR3U7uQzqy+/QbbYY7iNB9eDTwrELo14g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.49.0.tgz", + "integrity": "sha512-rDKRFFIWJ/zJn6uk2IdYLc09Z7zkE5IFIOWqpuU0o6ZpHcdniAyWkwSUWE/Z25N/wNDmFHHMzin84qW7Wzkjsw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.49.0.tgz", + "integrity": "sha512-FkkhIY/hYFVnOzz1WeV3S9Bd1h0hda/gRqvZCMpHWDHdiIHn6pqsY3b5eSbvGccWHMQ1uUzgZTKS4oGpykf8Tw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.49.0.tgz", + "integrity": "sha512-gRf5c+A7QiOG3UwLyOOtyJMD31JJhMjBvpfhAitPAoqZFcOeK3Kc1Veg1z/trmt+2P6F/biT02fU19GGTS529A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.49.0.tgz", + "integrity": "sha512-BR7+blScdLW1h/2hB/2oXM+dhTmpW3rQt1DeSiCP9mc2NMMkqVgjIN3DDsNpKmezffGC9R8XKVOLmBkRUcK/sA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.49.0.tgz", + "integrity": "sha512-hDMOAe+6nX3V5ei1I7Au3wcr9h3ktKzDvF2ne5ovX8RZiAHEtX1A5SNNk4zt1Qt77CmnbqT+upb/umzoPMWiPg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.49.0.tgz", + "integrity": "sha512-wkNRzfiIGaElC9kXUT+HLx17z7D0jl+9tGYRKwd8r7cUqTL7GYAvgUY++U2hK6Ar7z5Z6IRRoWC8kQxpmM7TDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.49.0.tgz", + "integrity": "sha512-gq5aW/SyNpjp71AAzroH37DtINDcX1Qw2iv9Chyz49ZgdOP3NV8QCyKZUrGsYX9Yyggj5soFiRCgsL3HwD8TdA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.49.0.tgz", + "integrity": "sha512-gEtqFbzmZLFk2xKh7g0Rlo8xzho8KrEFEkzvHbfUGkrgXOpZ4XagQ6n+wIZFNh1nTb8UD16J4nFSFKXYgnbdBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.12.0.tgz", + "integrity": "sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==", "dev": true, "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.30", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", - "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "node_modules/@storybook/addon-a11y": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-9.1.3.tgz", + "integrity": "sha512-U+In40S6HCvRN2at+/wn1ECmqFfLa7vPePkR5c9b+Zh2aVNfv+3JbjXfbp29FocTj4ooYsPRYFq7cdzXBjXZ1A==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@storybook/global": "^5.0.0", + "axe-core": "^4.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^9.1.3" } }, - "node_modules/@microsoft/tsdoc": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", - "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", + "node_modules/@storybook/addon-docs": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.3.tgz", + "integrity": "sha512-iCzuHRyUgir2+ExqPO4ouxm90zW+6dkNuB4lyyFwNU10slJhVT8yGPk8PVOT6LhXMIii+7Hqc4dB0tj+kLOW/A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@mdx-js/react": "^3.0.0", + "@storybook/csf-plugin": "9.1.3", + "@storybook/icons": "^1.4.0", + "@storybook/react-dom-shim": "9.1.3", + "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", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^9.1.3" + } }, - "node_modules/@microsoft/tsdoc-config": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", - "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", + "node_modules/@storybook/addon-vitest": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@storybook/addon-vitest/-/addon-vitest-9.1.3.tgz", + "integrity": "sha512-S47VS3a1Jo+rsrBUwCN1is45AK9xMWpgXF0Wsf0xKXmIKFNsVvqKVuUe/iKsM2Qqhocp2A1l36pFmuxxeB5BGg==", "dev": true, "license": "MIT", "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "ajv": "~6.12.6", - "jju": "~1.4.0", - "resolve": "~1.19.0" + "@storybook/global": "^5.0.0", + "@storybook/icons": "^1.4.0", + "prompts": "^2.4.0", + "ts-dedent": "^2.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@vitest/browser": "^3.0.0", + "@vitest/runner": "^3.0.0", + "storybook": "^9.1.3", + "vitest": "^3.0.0" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + }, + "@vitest/runner": { + "optional": true + }, + "vitest": { + "optional": true + } } }, - "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "node_modules/@storybook/builder-vite": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.3.tgz", + "integrity": "sha512-bstS/GsVJ5zVkRKAJociocA2omxU4CaNAP58fxS280JiRYgcrRaydDd7vwk6iGJ3xWbzwV0wH8SP54LVNyRY6Q==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" + "@storybook/csf-plugin": "9.1.3", + "ts-dedent": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^9.1.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "node_modules/@storybook/csf": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.13.tgz", + "integrity": "sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" + "type-fest": "^2.19.0" } }, - "node_modules/@next/env": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.2.tgz", - "integrity": "sha512-Qe06ew4zt12LeO6N7j8/nULSOe3fMXE4dM6xgpBQNvdzyK1sv5y4oAP3bq4LamrvGCZtmRYnW8URFCeX5nFgGg==", - "license": "MIT" - }, - "node_modules/@next/eslint-plugin-next": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.2.tgz", - "integrity": "sha512-lkLrRVxcftuOsJNhWatf1P2hNVfh98k/omQHrCEPPriUypR6RcS13IvLdIrEvkm9AH2Nu2YpR5vLqBuy6twH3Q==", + "node_modules/@storybook/csf-plugin": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.3.tgz", + "integrity": "sha512-wqh+tTCX2WZqVDVjhk/a6upsyYj/Kc85Wf6ywPx4pcFYxQZxiKF/wtuM9yzEpZC6fZHNvlKkzXWvP4wJOnm+zg==", "dev": true, "license": "MIT", "dependencies": { - "fast-glob": "3.3.1" + "unplugin": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^9.1.3" } }, - "node_modules/@next/swc-darwin-arm64": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.2.tgz", - "integrity": "sha512-8bGt577BXGSd4iqFygmzIfTYizHb0LGWqH+qgIF/2EDxS5JsSdERJKA8WgwDyNBZgTIIA4D8qUtoQHmxIIquoQ==", - "cpu": [ - "arm64" - ], + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/icons": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.4.0.tgz", + "integrity": "sha512-Td73IeJxOyalzvjQL+JXx72jlIYHgs+REaHiREOqfpo3A2AYYG71AUbcv+lg7mEDIweKVCxsMQ0UKo634c8XeA==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">= 10" + "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" } }, - "node_modules/@next/swc-darwin-x64": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.2.tgz", - "integrity": "sha512-2DjnmR6JHK4X+dgTXt5/sOCu/7yPtqpYt8s8hLkHFK3MGkka2snTv3yRMdHvuRtJVkPwCGsvBSwmoQCHatauFQ==", - "cpu": [ - "x64" - ], + "node_modules/@storybook/nextjs-vite": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@storybook/nextjs-vite/-/nextjs-vite-9.1.3.tgz", + "integrity": "sha512-kBK01aCfGU+PrbN/cWKoCgKEcqSGGNCp0zDazRHs92nQfojk7imTNbAKrjgeUT1Gum65jjH6DfZyxRPQ3BH8Qg==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@storybook/builder-vite": "9.1.3", + "@storybook/react": "9.1.3", + "@storybook/react-vite": "9.1.3", + "styled-jsx": "5.1.6", + "vite-plugin-storybook-nextjs": "^2.0.5" + }, "engines": { - "node": ">= 10" + "node": ">=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "next": "^14.1.0 || ^15.0.0", + "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": "^9.1.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.2.tgz", - "integrity": "sha512-3j7SWDBS2Wov/L9q0mFJtEvQ5miIqfO4l7d2m9Mo06ddsgUK8gWfHGgbjdFlCp2Ek7MmMQZSxpGFqcC8zGh2AA==", - "cpu": [ - "arm64" - ], + "node_modules/@storybook/react": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.3.tgz", + "integrity": "sha512-CgJMk4Y8EfoFxWiTB53QxnN+nQbAkw+NBaNjsaaeDNOE1R0ximP/fn5b2jcLvM+b5ojjJiJL1QCzFyoPWImHIQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/react-dom-shim": "9.1.3" + }, "engines": { - "node": ">= 10" + "node": ">=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "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": "^9.1.3", + "typescript": ">= 4.9.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.2.tgz", - "integrity": "sha512-s6N8k8dF9YGc5T01UPQ08yxsK6fUow5gG1/axWc1HVVBYQBgOjca4oUZF7s4p+kwhkB1bDSGR8QznWrFZ/Rt5g==", - "cpu": [ - "arm64" - ], + "node_modules/@storybook/react-dom-shim": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.3.tgz", + "integrity": "sha512-zIgFwZqV8cvE+lzJDcD13rItxoWyYNUWu7eJQAnHz5RnyHhpu6rFgQej7i6J3rPmy9xVe+Rq6XsXgDNs6pIekQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "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": "^9.1.3" } }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.2.tgz", - "integrity": "sha512-o1RV/KOODQh6dM6ZRJGZbc+MOAHww33Vbs5JC9Mp1gDk8cpEO+cYC/l7rweiEalkSm5/1WGa4zY7xrNwObN4+Q==", - "cpu": [ - "x64" - ], + "node_modules/@storybook/react-vite": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.3.tgz", + "integrity": "sha512-iNRRxA5G9Yaw5etbRdCMnJtjI1VkzA7juc+/caVhKKut25sI8cOF4GRPLCbotLz9xmitQR2X7beZMPPVIYk86A==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@joshwooding/vite-plugin-react-docgen-typescript": "0.6.1", + "@rollup/pluginutils": "^5.0.2", + "@storybook/builder-vite": "9.1.3", + "@storybook/react": "9.1.3", + "find-up": "^7.0.0", + "magic-string": "^0.30.0", + "react-docgen": "^8.0.0", + "resolve": "^1.22.8", + "tsconfig-paths": "^4.2.0" + }, "engines": { - "node": ">= 10" + "node": ">=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "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": "^9.1.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.2.tgz", - "integrity": "sha512-/VUnh7w8RElYZ0IV83nUcP/J4KJ6LLYliiBIri3p3aW2giF+PAVgZb6mk8jbQSB3WlTai8gEmCAr7kptFa1H6g==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@storybook/react-vite/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, "engines": { - "node": ">= 10" + "node": ">=6.0.0" } }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.2.tgz", - "integrity": "sha512-sMPyTvRcNKXseNQ/7qRfVRLa0VhR0esmQ29DD6pqvG71+JdVnESJaHPA8t7bc67KD5spP3+DOCNLhqlEI2ZgQg==", - "cpu": [ - "arm64" - ], + "node_modules/@storybook/react-vite/node_modules/find-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" + }, "engines": { - "node": ">= 10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.2.tgz", - "integrity": "sha512-W5VvyZHnxG/2ukhZF/9Ikdra5fdNftxI6ybeVKYvBPDtyx7x4jPPSNduUkfH5fo3zG0JQ0bPxgy41af2JX5D4Q==", - "cpu": [ - "x64" - ], + "node_modules/@storybook/react-vite/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "bin": { + "json5": "lib/cli.js" + }, "engines": { - "node": ">= 10" + "node": ">=6" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@storybook/react-vite/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "p-locate": "^6.0.0" }, "engines": { - "node": ">= 8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@storybook/react-vite/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, "engines": { - "node": ">= 8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@storybook/react-vite/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "p-limit": "^4.0.0" }, "engines": { - "node": ">= 8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@nolyfill/is-core-module": { - "version": "1.0.39", - "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", - "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "node_modules/@storybook/react-vite/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=12.4.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "node_modules/@storybook/react-vite/node_modules/react-docgen": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-8.0.1.tgz", + "integrity": "sha512-kQKsqPLplY3Hx4jGnM3jpQcG3FQDt7ySz32uTHt3C9HAe45kNXG+3o16Eqn3Fw1GtMfHoN3b4J/z2e6cZJCmqQ==", "dev": true, "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@types/babel__core": "^7.20.5", + "@types/babel__traverse": "^7.20.7", + "@types/doctrine": "^0.0.9", + "@types/resolve": "^1.20.2", + "doctrine": "^3.0.0", + "resolve": "^1.22.1", + "strip-indent": "^4.0.0" }, - "funding": { - "url": "https://opencollective.com/pkgr" + "engines": { + "node": "^20.9.0 || >=22" } }, - "node_modules/@regru/eslint-plugin-prefer-early-return": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@regru/eslint-plugin-prefer-early-return/-/eslint-plugin-prefer-early-return-1.0.0.tgz", - "integrity": "sha512-rOIjKi/npfNcunmrakkKQAolX/qakY8DUkp/P0PeSmQ0xnTNT6CCTHcMHxhFEvLRlrIBY3gJkUwh5rt9Z+GTyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "node_modules/@storybook/react-vite/node_modules/strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.12.0.tgz", - "integrity": "sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==", + "node_modules/@storybook/react-vite/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, - "node_modules/@storybook/csf": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.13.tgz", - "integrity": "sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q==", + "node_modules/@storybook/react-vite/node_modules/yocto-queue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^2.19.0" + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@stylistic/eslint-plugin": { @@ -1576,6 +3239,77 @@ "tailwindcss": "4.1.12" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.8.0.tgz", + "integrity": "sha512-WgXcWzVM6idy5JaftTVC8Vs83NKRmGJz4Hqs4oyOuO2J4r/y79vvKZsb+CaGyCSEbUPI6OsewfPd0G1A0/TUZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", @@ -1587,6 +3321,82 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/chai": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", + "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1608,6 +3418,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.19.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.11.tgz", @@ -1645,6 +3462,13 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/resolve": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", + "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/semver": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", @@ -2209,6 +4033,76 @@ "win32" ] }, + "node_modules/@vitest/browser": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-3.2.4.tgz", + "integrity": "sha512-tJxiPrWmzH8a+w9nLKlQMzAKX/7VjFs50MWgcAj7p9XQ7AQ9/35fByFYptgPELyLw+0aixTnC4pUWV+APcZ/kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@testing-library/dom": "^10.4.0", + "@testing-library/user-event": "^14.6.1", + "@vitest/mocker": "3.2.4", + "@vitest/utils": "3.2.4", + "magic-string": "^0.30.17", + "sirv": "^3.0.1", + "tinyrainbow": "^2.0.0", + "ws": "^8.18.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "playwright": "*", + "vitest": "3.2.4", + "webdriverio": "^7.0.0 || ^8.0.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": true + }, + "safaridriver": { + "optional": true + }, + "webdriverio": { + "optional": true + } + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz", + "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "ast-v8-to-istanbul": "^0.3.3", + "debug": "^4.4.1", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.9.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "3.2.4", + "vitest": "3.2.4" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, "node_modules/@vitest/eslint-plugin": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.3.4.tgz", @@ -2232,6 +4126,121 @@ } } }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -2272,6 +4281,16 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2485,6 +4504,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ast-types-flow": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", @@ -2492,6 +4534,25 @@ "dev": true, "license": "MIT" }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.5.tgz", + "integrity": "sha512-9SdXjNheSiE8bALAQCQQuT6fgQaoxJh7IRYrRGZ8/9nv8WhJeC1aXAwN8TbaOssGOukUvyvnkgD9+Yuykvl1aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.30", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/astro-eslint-parser": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/astro-eslint-parser/-/astro-eslint-parser-1.2.2.tgz", @@ -2620,6 +4681,19 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/better-opn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", + "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "open": "^8.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/birecord": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/birecord/-/birecord-0.1.1.tgz", @@ -2695,6 +4769,15 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/builtin-modules": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", @@ -2708,6 +4791,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -2788,6 +4881,23 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2805,6 +4915,16 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/chownr": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", @@ -2815,6 +4935,30 @@ "node": ">=18" } }, + "node_modules/chromatic": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-12.2.0.tgz", + "integrity": "sha512-GswmBW9ZptAoTns1BMyjbm55Z7EsIJnUvYKdQqXIBZIKbGErmpA+p4c0BYA+nzw5B0M+rb3Iqp1IaH8TFwIQew==", + "dev": true, + "license": "MIT", + "bin": { + "chroma": "dist/bin.js", + "chromatic": "dist/bin.js", + "chromatic-cli": "dist/bin.js" + }, + "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 + } + } + }, "node_modules/ci-info": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", @@ -2962,6 +5106,13 @@ "dev": true, "license": "MIT" }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/core-js-compat": { "version": "3.45.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz", @@ -2991,6 +5142,13 @@ "node": ">= 8" } }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -3090,6 +5248,16 @@ } } }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3115,6 +5283,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -3133,6 +5311,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", @@ -3169,6 +5357,13 @@ "node": ">=0.10.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -3184,6 +5379,13 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { "version": "1.5.209", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.209.tgz", @@ -3359,6 +5561,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -3419,6 +5628,61 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "node_modules/esbuild-register": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -3614,6 +5878,24 @@ "typescript": ">=5.0.0" } }, + "node_modules/eslint-config-sheriff/node_modules/eslint-plugin-storybook": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.11.6.tgz", + "integrity": "sha512-3WodYD6Bs9ACqnB+TP2TuLh774c/nacAjxSKOP9bHJ2c8rf+nrhocxjjeAWNmO9IPkFIzTKlcl0vNXI2yYpVOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf": "^0.1.11", + "@typescript-eslint/utils": "^8.8.1", + "ts-dedent": "^2.2.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, "node_modules/eslint-config-sheriff/node_modules/globals": { "version": "15.15.0", "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", @@ -4745,24 +7027,6 @@ "eslint": "^8.0.0 || ^9.0.0" } }, - "node_modules/eslint-plugin-storybook": { - "version": "0.11.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.11.6.tgz", - "integrity": "sha512-3WodYD6Bs9ACqnB+TP2TuLh774c/nacAjxSKOP9bHJ2c8rf+nrhocxjjeAWNmO9IPkFIzTKlcl0vNXI2yYpVOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@storybook/csf": "^0.1.11", - "@typescript-eslint/utils": "^8.8.1", - "ts-dedent": "^2.2.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "eslint": ">=8" - } - }, "node_modules/eslint-plugin-tsdoc": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz", @@ -4898,6 +7162,20 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -4934,6 +7212,16 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -4944,6 +7232,16 @@ "node": ">=0.10.0" } }, + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5018,6 +7316,16 @@ "node": ">=16.0.0" } }, + "node_modules/filesize": { + "version": "10.1.6", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz", + "integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 10.4.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -5098,12 +7406,44 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/fstream": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", @@ -5173,6 +7513,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -5328,6 +7678,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -5461,6 +7818,13 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5471,6 +7835,19 @@ "node": ">= 4" } }, + "node_modules/image-size": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz", + "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==", + "dev": true, + "license": "MIT", + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -5710,15 +8087,31 @@ "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-extglob": { @@ -5747,6 +8140,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-generator-function": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", @@ -5993,6 +8396,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -6007,6 +8423,76 @@ "dev": true, "license": "ISC" }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/iterator.prototype": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", @@ -6025,6 +8511,22 @@ "node": ">= 0.4" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jiti": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", @@ -6125,6 +8627,19 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -6151,6 +8666,16 @@ "json-buffer": "3.0.1" } }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.23", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", @@ -6473,6 +8998,13 @@ "loose-envify": "cli.js" } }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", @@ -6480,6 +9012,16 @@ "dev": true, "license": "ISC" }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.30.18", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", @@ -6490,6 +9032,18 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -6594,6 +9148,23 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/module-alias": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz", + "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6875,6 +9446,24 @@ "wrappy": "1" } }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -6953,6 +9542,13 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/paginator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/paginator/-/paginator-1.0.0.tgz", @@ -7056,6 +9652,23 @@ "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -7066,6 +9679,23 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -7085,6 +9715,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.0.tgz", + "integrity": "sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.55.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.0.tgz", + "integrity": "sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -7260,6 +9937,55 @@ } } }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -7311,6 +10037,16 @@ "node": ">=0.10.0" } }, + "node_modules/react-docgen-typescript": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.4.0.tgz", + "integrity": "sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">= 4.3.x" + } + }, "node_modules/react-dom": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", @@ -7592,6 +10328,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/recast": { + "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/refa": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz", @@ -7760,6 +10537,46 @@ "rimraf": "bin.js" } }, + "node_modules/rollup": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.49.0.tgz", + "integrity": "sha512-3IVq0cGJ6H7fKXXEdVt+RcYvRCt8beYY9K1760wGQwSAHZcS9eot1zDG5axUbcp/kWRi5zKIIDX8MoKv/TzvZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.49.0", + "@rollup/rollup-android-arm64": "4.49.0", + "@rollup/rollup-darwin-arm64": "4.49.0", + "@rollup/rollup-darwin-x64": "4.49.0", + "@rollup/rollup-freebsd-arm64": "4.49.0", + "@rollup/rollup-freebsd-x64": "4.49.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.49.0", + "@rollup/rollup-linux-arm-musleabihf": "4.49.0", + "@rollup/rollup-linux-arm64-gnu": "4.49.0", + "@rollup/rollup-linux-arm64-musl": "4.49.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.49.0", + "@rollup/rollup-linux-ppc64-gnu": "4.49.0", + "@rollup/rollup-linux-riscv64-gnu": "4.49.0", + "@rollup/rollup-linux-riscv64-musl": "4.49.0", + "@rollup/rollup-linux-s390x-gnu": "4.49.0", + "@rollup/rollup-linux-x64-gnu": "4.49.0", + "@rollup/rollup-linux-x64-musl": "4.49.0", + "@rollup/rollup-win32-arm64-msvc": "4.49.0", + "@rollup/rollup-win32-ia32-msvc": "4.49.0", + "@rollup/rollup-win32-x64-msvc": "4.49.0", + "fsevents": "~2.3.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -8071,6 +10888,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -8081,6 +10918,28 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/sirv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", + "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -8100,6 +10959,31 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -8154,6 +11038,20 @@ "dev": true, "license": "MIT" }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "dev": true, + "license": "MIT" + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -8168,6 +11066,42 @@ "node": ">= 0.4" } }, + "node_modules/storybook": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.3.tgz", + "integrity": "sha512-Sm+qP3iGb/QKx/jTYdfE0mIeTmA2HF+5k9fD70S9oOJq3F9UdW8MLgs+5PE+E/xAfDjZU4OWAKEOyA6EYIvQHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/user-event": "^14.6.1", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/spy": "3.2.4", + "better-opn": "^3.0.2", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0", + "esbuild-register": "^3.5.0", + "recast": "^0.23.5", + "semver": "^7.6.2", + "ws": "^8.18.0" + }, + "bin": { + "storybook": "bin/index.cjs" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, "node_modules/string-ts": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/string-ts/-/string-ts-2.2.1.tgz", @@ -8175,6 +11109,60 @@ "dev": true, "license": "MIT" }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -8288,6 +11276,49 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz", + "integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -8324,6 +11355,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-literal": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", + "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -8438,6 +11489,119 @@ "node": ">=18" } }, + "node_modules/terser": { + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.14.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", @@ -8486,6 +11650,36 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", + "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -8499,6 +11693,16 @@ "node": ">=8.0" } }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -8558,13 +11762,34 @@ "node": ">=6.10" } }, - "node_modules/ts-pattern": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.8.0.tgz", - "integrity": "sha512-kIjN2qmWiHnhgr5DAkAafF9fwb0T5OhMVSWrm8XEdTFnX6+wfXwYOFjeF86UZ54vduqiR7BfqScFmXSzSaH8oA==", - "dev": true, - "license": "MIT" - }, + "node_modules/ts-pattern": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.8.0.tgz", + "integrity": "sha512-kIjN2qmWiHnhgr5DAkAafF9fwb0T5OhMVSWrm8XEdTFnX6+wfXwYOFjeF86UZ54vduqiR7BfqScFmXSzSaH8oA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -8765,6 +11990,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unplugin": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz", + "integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/unrs-resolver": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", @@ -8870,6 +12119,268 @@ "spdx-license-ids": "^3.0.0" } }, + "node_modules/vite": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.3.tgz", + "integrity": "sha512-OOUi5zjkDxYrKhTV3V7iKsoS37VUM7v40+HuwEmcrsf11Cdx9y3DIr2Px6liIcZFwt3XSRpQvFpL3WVy7ApkGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-plugin-storybook-nextjs": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/vite-plugin-storybook-nextjs/-/vite-plugin-storybook-nextjs-2.0.7.tgz", + "integrity": "sha512-32xEq8+uLrFWQcdDB9rX9epsq0nht9nFyIY+NFjdOI68MwAAWgKWlRif6gRBsxFkT/B9shQt2jTYzWWM3U+nMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/env": "^15.0.3", + "image-size": "^2.0.0", + "magic-string": "^0.30.11", + "module-alias": "^2.2.3", + "ts-dedent": "^2.2.0", + "vite-tsconfig-paths": "^5.1.4" + }, + "peerDependencies": { + "next": "^14.1.0 || ^15.0.0", + "storybook": "^0.0.0-0 || ^9.0.0 || ^9.1.0-0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", + "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8975,6 +12486,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -8985,12 +12513,119 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "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 + } + } + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", @@ -9001,6 +12636,21 @@ "node": ">=18" } }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 2b67b35..cceab80 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "dev": "next dev --turbopack", "build": "next build --turbopack", "start": "next start", - "lint": "eslint" + "lint": "eslint", + "storybook": "storybook dev --config-dir src/storybook/ -p 6006", + "build-storybook": "storybook build" }, "dependencies": { "class-variance-authority": "^0.7.1", @@ -20,18 +22,28 @@ "zod": "^4.1.5" }, "devDependencies": { + "@chromatic-com/storybook": "^4.1.1", "@eslint/eslintrc": "^3", + "@storybook/addon-a11y": "^9.1.3", + "@storybook/addon-docs": "^9.1.3", + "@storybook/addon-vitest": "^9.1.3", + "@storybook/nextjs-vite": "^9.1.3", "@tailwindcss/postcss": "^4.1.12", "@types/node": "^20", "@types/react": "^19.1.12", "@types/react-dom": "^19", + "@vitest/browser": "^3.2.4", + "@vitest/coverage-v8": "^3.2.4", "eslint": "^9.34.0", "eslint-config-next": "15.5.2", "eslint-config-sheriff": "^28.1.0", "jiti": "^2.5.1", + "playwright": "^1.55.0", "prettier": "^3.6.2", "prettier-plugin-tailwindcss": "^0.6.14", + "storybook": "^9.1.3", "tailwindcss": "^4.1.12", - "typescript": "^5" + "typescript": "^5", + "vitest": "^3.2.4" } } diff --git a/postcss.config.mjs b/postcss.config.mjs index c7bcb4b..297374d 100644 --- a/postcss.config.mjs +++ b/postcss.config.mjs @@ -1,5 +1,7 @@ const config = { - plugins: ["@tailwindcss/postcss"], + plugins: { + '@tailwindcss/postcss': {}, + }, }; export default config; diff --git a/public/auth/icon/addimage.svg b/public/auth/icon/addimage.svg new file mode 100644 index 0000000..e342900 --- /dev/null +++ b/public/auth/icon/addimage.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/auth/icon/facebook-icon.svg b/public/auth/icon/facebook-icon.svg new file mode 100644 index 0000000..caeb826 --- /dev/null +++ b/public/auth/icon/facebook-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/auth/icon/gmail-icon.svg b/public/auth/icon/gmail-icon.svg new file mode 100644 index 0000000..ef55295 --- /dev/null +++ b/public/auth/icon/gmail-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/auth/icon/instagram-icon.svg b/public/auth/icon/instagram-icon.svg new file mode 100644 index 0000000..f42dd6e --- /dev/null +++ b/public/auth/icon/instagram-icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/auth/icon/visibility-off.svg b/public/auth/icon/visibility-off.svg new file mode 100644 index 0000000..f14c379 --- /dev/null +++ b/public/auth/icon/visibility-off.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/auth/icon/visibility.svg b/public/auth/icon/visibility.svg new file mode 100644 index 0000000..833c7d0 --- /dev/null +++ b/public/auth/icon/visibility.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/auth/image/header-logo.svg b/public/auth/image/header-logo.svg new file mode 100644 index 0000000..a8b0be1 --- /dev/null +++ b/public/auth/image/header-logo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/auth/image/hero-desktop.svg b/public/auth/image/hero-desktop.svg new file mode 100644 index 0000000..f212d8c --- /dev/null +++ b/public/auth/image/hero-desktop.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/auth/image/lading-logo.svg b/public/auth/image/lading-logo.svg new file mode 100644 index 0000000..ed1178e --- /dev/null +++ b/public/auth/image/lading-logo.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/auth/image/landing1.svg b/public/auth/image/landing1.svg new file mode 100644 index 0000000..4711d6f --- /dev/null +++ b/public/auth/image/landing1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/auth/image/landing2.svg b/public/auth/image/landing2.svg new file mode 100644 index 0000000..43da3fb --- /dev/null +++ b/public/auth/image/landing2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/auth/image/landing3.svg b/public/auth/image/landing3.svg new file mode 100644 index 0000000..3fc4cee --- /dev/null +++ b/public/auth/image/landing3.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/auth/image/landing4.svg b/public/auth/image/landing4.svg new file mode 100644 index 0000000..0fed4bc --- /dev/null +++ b/public/auth/image/landing4.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/auth/image/landing5.svg b/public/auth/image/landing5.svg new file mode 100644 index 0000000..67502f2 --- /dev/null +++ b/public/auth/image/landing5.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/logo-auth.svg b/public/auth/image/login-signup-logo.svg similarity index 100% rename from public/logo-auth.svg rename to public/auth/image/login-signup-logo.svg diff --git a/public/auth/image/logo-header.svg b/public/auth/image/logo-header.svg new file mode 100644 index 0000000..a8b0be1 --- /dev/null +++ b/public/auth/image/logo-header.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/icon/add_box.svg b/public/icon/add_box.svg new file mode 100644 index 0000000..2851ea7 --- /dev/null +++ b/public/icon/add_box.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icon/settings.svg b/public/icon/settings.svg new file mode 100644 index 0000000..86c8e94 --- /dev/null +++ b/public/icon/settings.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/side-menu/Taskify.svg b/public/side-menu/Taskify.svg new file mode 100644 index 0000000..94cc98d --- /dev/null +++ b/public/side-menu/Taskify.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/side-menu/logo.png b/public/side-menu/logo.png new file mode 100644 index 0000000..016be14 Binary files /dev/null and b/public/side-menu/logo.png differ diff --git a/src/components/auth/AuthButton.tsx b/src/components/auth/AuthButton.tsx new file mode 100644 index 0000000..15e5ba2 --- /dev/null +++ b/src/components/auth/AuthButton.tsx @@ -0,0 +1,35 @@ +// 인증 페이지용 공통 버튼 컴포넌트 (로딩 상태 포함) +interface AuthButtonProps { + type: 'submit' | 'button'; + disabled?: boolean; + isLoading?: boolean; + loadingText?: string; + children: React.ReactNode; + className?: string; +} + +export default function AuthButton({ + type, + disabled = false, + isLoading = false, + loadingText, + children, + className = '', +}: AuthButtonProps): React.JSX.Element { + const isDisabled = disabled || isLoading; + + return ( + + ); +} diff --git a/src/components/auth/AuthHero.tsx b/src/components/auth/AuthHero.tsx new file mode 100644 index 0000000..f3a1cee --- /dev/null +++ b/src/components/auth/AuthHero.tsx @@ -0,0 +1,33 @@ +// 인증 페이지용 로고 + 제목 영역 컴포넌트 +import Image from 'next/image'; +import Link from 'next/link'; +import styles from '@/styles/auth-variables.module.css'; + +interface AuthHeroProps { + title: string; +} + +export default function AuthHero({ title }: AuthHeroProps): React.JSX.Element { + return ( +
+
+
+ + Taskify Logo + +
+
+

+ {title} +

+
+ ); +} diff --git a/src/components/auth/EmailInput.tsx b/src/components/auth/EmailInput.tsx new file mode 100644 index 0000000..a2704c3 --- /dev/null +++ b/src/components/auth/EmailInput.tsx @@ -0,0 +1,63 @@ +// 인증 페이지용 이메일 입력 컴포넌트 +import styles from '@/styles/auth-variables.module.css'; + +interface EmailInputProps { + id: string; + label: string; + value: string; + onChange: (value: string) => void; + onBlur: () => void; + placeholder: string; + error?: string; + className?: string; +} + +export default function EmailInput({ + id, + label, + value, + onChange, + onBlur, + placeholder, + error, + className = '', +}: EmailInputProps): React.JSX.Element { + return ( +
+ + { + onChange(e.target.value); + }} + /> + {error && ( +

+ {error} +

+ )} +
+ ); +} diff --git a/src/components/auth/PasswordInput.tsx b/src/components/auth/PasswordInput.tsx new file mode 100644 index 0000000..f2de5a0 --- /dev/null +++ b/src/components/auth/PasswordInput.tsx @@ -0,0 +1,95 @@ +// 인증 페이지용 비밀번호 입력 컴포넌트 (토글 버튼 포함) +import Image from 'next/image'; +import styles from '@/styles/auth-variables.module.css'; + +interface PasswordInputProps { + id: string; + label: string; + value: string; + onChange: (value: string) => void; + onBlur: () => void; + placeholder: string; + error?: string; + showPassword?: boolean; + onTogglePassword?: () => void; + className?: string; +} + +export default function PasswordInput({ + id, + label, + value, + onChange, + onBlur, + placeholder, + error, + showPassword = false, + onTogglePassword, + className = '', +}: PasswordInputProps): React.JSX.Element { + return ( +
+ +
+ { + onChange(e.target.value); + }} + /> + {onTogglePassword && ( + + )} +
+ {error && ( +

+ {error} +

+ )} +
+ ); +} diff --git a/src/components/auth/TextInput.tsx b/src/components/auth/TextInput.tsx new file mode 100644 index 0000000..3b9301d --- /dev/null +++ b/src/components/auth/TextInput.tsx @@ -0,0 +1,63 @@ +// 인증 페이지용 텍스트 입력 컴포넌트 (닉네임 등) +import styles from '@/styles/auth-variables.module.css'; + +interface TextInputProps { + id: string; + label: string; + value: string; + onChange: (value: string) => void; + onBlur: () => void; + placeholder: string; + error?: string; + className?: string; +} + +export default function TextInput({ + id, + label, + value, + onChange, + onBlur, + placeholder, + error, + className = '', +}: TextInputProps): React.JSX.Element { + return ( +
+ + { + onChange(e.target.value); + }} + /> + {error && ( +

+ {error} +

+ )} +
+ ); +} diff --git a/src/components/auth/UnifiedModal.tsx b/src/components/auth/UnifiedModal.tsx new file mode 100644 index 0000000..53caa96 --- /dev/null +++ b/src/components/auth/UnifiedModal.tsx @@ -0,0 +1,70 @@ +// 인증 페이지용 통합 모달 컴포넌트 (성공/에러 메시지) +import type React from 'react'; +import { createPortal } from 'react-dom'; + +interface UnifiedModalProps { + isOpen: boolean; + onClose: () => void; + message: string; + type?: 'success' | 'error'; +} + +export default function UnifiedModal({ + isOpen, + onClose, + message, +}: UnifiedModalProps): React.ReactElement | null { + if (!isOpen) { + return null; + } + + const modalContent = ( + + + + + ); + + // 클라이언트 사이드에서만 Portal 사용 + if (typeof window !== 'undefined') { + return createPortal(modalContent, document.body); + } + + return modalContent; +} diff --git a/src/components/auth/back-button/back-button.tsx b/src/components/auth/back-button/back-button.tsx new file mode 100644 index 0000000..4024642 --- /dev/null +++ b/src/components/auth/back-button/back-button.tsx @@ -0,0 +1,49 @@ +import Image from 'next/image'; +import { useRouter } from 'next/router'; +import { type ReactNode, useCallback } from 'react'; + +interface BackButtonProps { + /** 클릭 시 이동할 경로 (기본값: 이전 페이지) */ + href?: string; + /** 추가 CSS 클래스 */ + className?: string; +} + +export default function BackButton({ + href, + className = '', +}: BackButtonProps): ReactNode { + const router = useRouter(); + + const handleClick = useCallback(() => { + if (href) { + router.push(href); + } else { + router.back(); + } + }, [href, router]); + + return ( + + ); +} diff --git a/src/components/auth/back-button/index.ts b/src/components/auth/back-button/index.ts new file mode 100644 index 0000000..92cf7df --- /dev/null +++ b/src/components/auth/back-button/index.ts @@ -0,0 +1 @@ +export { default } from '@/components/auth/back-button/back-button'; diff --git a/src/components/home/FeatureOne.tsx b/src/components/home/FeatureOne.tsx new file mode 100644 index 0000000..ea0f051 --- /dev/null +++ b/src/components/home/FeatureOne.tsx @@ -0,0 +1,29 @@ +// 랜딩페이지 첫 번째 기능 소개 컴포넌트 +import Image from 'next/image'; +import type { ReactElement } from 'react'; + +export default function FeatureOne(): ReactElement { + return ( +
+ {/* 배경 이미지 */} + 일의 우선순위 관리 일러스트 + + {/* 텍스트 컨테이너 */} +
+

+ Point 1 +

+

+ 일의 우선순위를 + 관리하세요 +

+
+
+ ); +} diff --git a/src/components/home/FeatureTwo.tsx b/src/components/home/FeatureTwo.tsx new file mode 100644 index 0000000..552e04f --- /dev/null +++ b/src/components/home/FeatureTwo.tsx @@ -0,0 +1,29 @@ +// 랜딩페이지 두 번째 기능 소개 컴포넌트 +import Image from 'next/image'; +import type { ReactElement } from 'react'; + +export default function FeatureTwo(): ReactElement { + return ( +
+ {/* 배경 이미지 */} + 할 일 등록 일러스트 + + {/* 텍스트 컨테이너 */} +
+

+ Point 2 +

+

+ 해야 할 일을 + 등록하세요 +

+
+
+ ); +} diff --git a/src/components/home/Footer.tsx b/src/components/home/Footer.tsx new file mode 100644 index 0000000..a1c09a7 --- /dev/null +++ b/src/components/home/Footer.tsx @@ -0,0 +1,101 @@ +// 랜딩페이지 하단 푸터 컴포넌트 (소셜 링크 + 저작권) +import type { ReactElement } from 'react'; + +export default function Footer(): ReactElement { + return ( + + ); +} diff --git a/src/components/home/Header.tsx b/src/components/home/Header.tsx new file mode 100644 index 0000000..ae5adb3 --- /dev/null +++ b/src/components/home/Header.tsx @@ -0,0 +1,62 @@ +// 랜딩페이지 상단 헤더 컴포넌트 (로고 + 네비게이션) +import Image from 'next/image'; +import { type ReactElement, useEffect, useState } from 'react'; + +export default function Header(): ReactElement { + const [isAuth, setIsAuth] = useState(false); + + useEffect(() => { + let mounted = true; + + const checkAuth = async () => { + try { + const res = await fetch('/api/me'); + + if (mounted) { + setIsAuth(res.ok); + } + } catch { + if (mounted) { + setIsAuth(false); + } + } + }; + + checkAuth(); + + return () => { + mounted = false; + }; + }, []); + + return ( +
+ {/* 로고 */} +
+ Taskify 로고 +
+ + {/* 네비게이션 */} + +
+ ); +} diff --git a/src/components/home/Hero.tsx b/src/components/home/Hero.tsx new file mode 100644 index 0000000..2970a43 --- /dev/null +++ b/src/components/home/Hero.tsx @@ -0,0 +1,53 @@ +// 랜딩페이지 메인 히어로 섹션 컴포넌트 (로고 + 제목 + 로그인 버튼) +import Image from 'next/image'; +import { type ReactElement, useEffect, useState } from 'react'; + +export default function Hero(): ReactElement { + const [isAuth, setIsAuth] = useState(false); + + useEffect(() => { + (async () => { + try { + const res = await fetch('/api/me'); + + setIsAuth(res.ok); + } catch { + setIsAuth(false); + } + })(); + }, []); + + return ( +
+ {/* desktop 이미지 */} + 메인 히어로 일러스트 + + {/* 제목 */} +

+ + 새로운 일정 관리 + + + Taskify + +

+ + {/* 로그인하기 버튼 */} + + 로그인하기 + +
+ ); +} diff --git a/src/components/home/SettingsGrid.tsx b/src/components/home/SettingsGrid.tsx new file mode 100644 index 0000000..c6dc6e4 --- /dev/null +++ b/src/components/home/SettingsGrid.tsx @@ -0,0 +1,113 @@ +// 랜딩페이지 설정 카드 그리드 컴포넌트 (생산성 기능 소개) +import Image from 'next/image'; +import type { ReactElement } from 'react'; + +interface Item { + title: string; + desc: string; + img: string; + alt: string; + w: number; + h: number; + mobileW: number; + mobileH: number; +} + +const items: Item[] = [ + { + title: '대시보드 설정', + desc: '대시보드 사진과 이름을 변경할 수 있어요.', + img: '/auth/image/landing3.svg', + alt: '대시보드 설정', + w: 300, + h: 123.87, + mobileW: 260, + mobileH: 107.35, + }, + { + title: '초대', + desc: '새로운 팀원을 초대할 수 있어요.', + img: '/auth/image/landing4.svg', + alt: '초대', + w: 300, + h: 230.81, + mobileW: 260, + mobileH: 200.03, + }, + { + title: '구성원', + desc: '구성원을 초대하고 내보낼 수 있어요.', + img: '/auth/image/landing5.svg', + alt: '구성원', + w: 300, + h: 195.48, + mobileW: 260, + mobileH: 169.42, + }, +]; + +export default function SettingsGrid(): ReactElement { + return ( +
+

+ 생산성을 높이는 다양한 설정 ⚡ +

+ + {/* 타이틀과 그리드 간격 36px */} +
+ {items.map((it) => { + return ( +
+ {/* 썸네일 영역 378×260 안에 실제 이미지 크기 중앙 배치 */} +
+ {it.alt} { + let mobileClass = ''; + + switch (it.img) { + case '/auth/image/landing3.svg': { + mobileClass = + 'max-[375px]:h-[107.35px] max-[375px]:w-[260px]'; + break; + } + case '/auth/image/landing4.svg': { + mobileClass = + 'max-[375px]:h-[200.03px] max-[375px]:w-[260px]'; + break; + } + case '/auth/image/landing5.svg': { + mobileClass = + 'max-[375px]:h-[169.42px] max-[375px]:w-[260px]'; + break; + } + default: { + break; + } + } + + return `h-auto max-h-full w-auto max-w-full ${mobileClass}`; + })()} + /> +
+
+

+ {it.title} +

+

+ {it.desc} +

+
+
+ ); + })} +
+
+ ); +} diff --git a/src/components/layout/dashboard-layout.tsx b/src/components/layout/dashboard-layout.tsx new file mode 100644 index 0000000..19be7f8 --- /dev/null +++ b/src/components/layout/dashboard-layout.tsx @@ -0,0 +1,17 @@ +import type { ReactNode } from 'react'; +import DashboardHeader from '@/components/ui/dashboard-header'; +import SideMenu from '@/components/ui/side-menu'; + +export default function DashboardLayout({ + children, +}: { + children: ReactNode; +}): ReactNode { + return ( +
+ + + {children} +
+ ); +} diff --git a/src/components/mydashboard/invite-list.tsx b/src/components/mydashboard/invite-list.tsx index f4d1edf..70dcd3e 100644 --- a/src/components/mydashboard/invite-list.tsx +++ b/src/components/mydashboard/invite-list.tsx @@ -1,3 +1,4 @@ +// 마이 대시보드 초대 목록 컴포넌트 import Image from 'next/image'; import type { ReactNode } from 'react'; diff --git a/src/components/ui/button/button-pagination.tsx b/src/components/ui/button/button-pagination.tsx new file mode 100644 index 0000000..0e09a71 --- /dev/null +++ b/src/components/ui/button/button-pagination.tsx @@ -0,0 +1,68 @@ +import type { ReactNode } from 'react'; +import { cn } from '@/utils/cn'; + +interface ButtonPaginationProps { + onPrevClick: () => void; + onNextClick: () => void; + /** 왼쪽 버튼 disabled 여부 */ + isPrevDisabled?: boolean; + /** 오른쪽 버튼 disabled 여부 */ + isNextDisabled?: boolean; + /** 추가적인 tailwind className */ + additionalClass?: string; +} +export default function ButtonPagination({ + onPrevClick, + onNextClick, + isPrevDisabled = false, + isNextDisabled = false, + additionalClass = '', +}: ButtonPaginationProps): ReactNode { + const buttonClassName = + 'border-gray-3 flex-center *:fill-black-2 disabled:*:fill-gray-3 h-9 w-9 cursor-pointer border-1 hover:bg-gray-4 active:bg-gray-3'; + + return ( +
+ + +
+ ); +} +function NextPageIcon() { + return ( + + + + ); +} +function PrevPageIcon() { + return ( + + + + ); +} diff --git a/src/components/ui/button/button.tsx b/src/components/ui/button/button.tsx new file mode 100644 index 0000000..f519f80 --- /dev/null +++ b/src/components/ui/button/button.tsx @@ -0,0 +1,88 @@ +import { cva, type VariantProps } from 'class-variance-authority'; +import type { ButtonHTMLAttributes, ReactNode } from 'react'; +import { cn } from '@/utils/cn'; + +export const ButtonVariants = cva( + `flex-center w-full p-3.5 + bg-violet disabled:bg-gray-2 text-white text-2lg font-medium + disabled:hover:bg-gray-2 disabled:hover:scale-100 disabled:cursor-not-allowed cursor-pointer + `, + { + variants: { + variant: { + primary: 'rounded-lg', + invitation: + 'text-md h-8 tablet:h-[1.875rem] mobile:h-8 max-w-[5.25rem] tablet:max-w-[4.5rem] mobile:max-w-full py-2 rounded-sm', + modal: 'h-[2.625rem] mobile:h-12 py-3 mobile:py-3.5 rounded-lg', + }, + backgroundColor: { + violet: 'bg-violet hover:bg-violet-800 active:bg-violet-900 ', + white: + 'bg-white border-2 border-gray-3 text-violet hover:bg-gray-4 active:bg-gray-3 disabled:hover:bg-white', + }, + labelColor: { + gray: 'text-gray-1', + }, + }, + defaultVariants: { + variant: 'primary', + backgroundColor: 'violet', + }, + } +); +interface ButtonProps + extends ButtonHTMLAttributes, + VariantProps { + /** 버튼 형태 */ + variant: 'primary' | 'invitation' | 'modal'; + /** 배경 색상 */ + backgroundColor: 'violet' | 'white'; + /** 텍스트 색상: button-modal만 사용 (gray)*/ + labelColor?: 'gray'; + /** 버튼 내부 텍스트 */ + label: string; + /** 추가적인 tailwind className */ + additionalClass?: string; + /** button disabled 여부 */ + disabled?: boolean; + /** 클릭 이벤트 핸들러 */ + onClick?: () => void; + children?: ReactNode; +} +/** + * primary, modal, invitation 세가지 형태의 버튼을 표시합니다. + * ## width 반응형 규칙 + * ### 1.primary, modal + * - PC/Tablet/Mobile: width: 100%로 동일 (컨테이너 크기에 맞춰서 변화) + * + * ### 2.invitation + * - PC(1280px+): max-width: 5.25rem (84px) + * - tablet(768px+): max-width: 4.5rem (72px) + * - Mobile (767px 이하): max-width: 100% (컨테이너 크기에 맞춰서 변화) + */ +export default function Button({ + variant, + backgroundColor = 'violet', + children, + label, + labelColor, + additionalClass = '', + onClick, + ...props +}: ButtonProps): ReactNode { + return ( + <> + + + ); +} diff --git a/src/components/ui/chip/chip-profile.tsx b/src/components/ui/chip/chip-profile.tsx new file mode 100644 index 0000000..de95c60 --- /dev/null +++ b/src/components/ui/chip/chip-profile.tsx @@ -0,0 +1,58 @@ +import { cva, type VariantProps } from 'class-variance-authority'; +import type { HTMLAttributes, ReactNode } from 'react'; +import { cn } from '@/utils/cn'; + +export const ChipVariants = cva( + `flex-center rounded-full font-semibold text-lg text-white border-2 border-white cursor-pointer font-montserrat`, + { + variants: { + color: { + green: 'bg-green-500', + blue: 'bg-sky-400', + orange: 'bg-orange-400', + yellow: 'bg-yellow-400', + brown: 'bg-chip-brown', + red: 'bg-chip-red-bg text-chip-red', + }, + size: { + sm: 'w-[1.375rem] h-[1.375rem] text-[0.625rem]', + md: 'w-6 h-6 text-xs', + lg: 'w-[2.375rem] h-[2.375rem] text-lg mobile:w-[2.125rem] mobile:h-[2.125rem]', + }, + }, + defaultVariants: { + color: 'green', + size: 'md', + }, + } +); +interface ChipProps + extends HTMLAttributes, + VariantProps { + children?: ReactNode; + /** 버튼 내부 텍스트 */ + label: string; + /** 사이즈: 'sm' | 'md' | 'lg' */ + size: 'sm' | 'md' | 'lg'; + /** 색상: 'green' | 'blue' | 'orange' | 'yellow' | 'brown' */ + color: 'green' | 'blue' | 'orange' | 'yellow' | 'brown' | 'red'; +} +/** 사이즈: + * - 'sm' : 1.375rem(22px) + * - 'md' : 1.5rem (24px) + * - 'lg' : 2.375rem (38px). + */ +export default function ChipProfile({ + label, + size = 'md', + color = 'green', + ...props +}: ChipProps): ReactNode { + return ( + <> +
+ {label} +
+ + ); +} diff --git a/src/components/ui/chip/chip-state.tsx b/src/components/ui/chip/chip-state.tsx new file mode 100644 index 0000000..438239c --- /dev/null +++ b/src/components/ui/chip/chip-state.tsx @@ -0,0 +1,40 @@ +import type { ReactNode } from 'react'; +import { cn } from '@/utils/cn'; + +interface ChipProps { + children?: ReactNode; + label: string; + /** 사이즈: md | lg*/ + size: 'md' | 'lg'; +} +export default function ChipState({ + children, + size = 'md', + label, + ...props +}: ChipProps): ReactNode { + return ( + <> +
+ {children} + + + + + + {label} +
+ + ); +} diff --git a/src/components/ui/chip/chip-tag.tsx b/src/components/ui/chip/chip-tag.tsx new file mode 100644 index 0000000..2f2ce09 --- /dev/null +++ b/src/components/ui/chip/chip-tag.tsx @@ -0,0 +1,46 @@ +import { cva, type VariantProps } from 'class-variance-authority'; +import type { HTMLAttributes, ReactNode } from 'react'; +import { cn } from '@/utils/cn'; + +export const ChipVariants = cva(`flex-center gap-1.5 rounded-sm font-normal`, { + variants: { + color: { + blue: 'bg-chip-blue-bg text-chip-blue', + pink: 'bg-chip-pink-bg text-chip-pink', + green: 'bg-chip-green-bg text-chip-green', + brown: 'bg-chip-brown-bg text-chip-brown', + }, + size: { + md: 'text-xs px-1.5 py-1 h-[1.625rem]', + lg: 'text-md px-1.5 py-0.5 h-7', + }, + }, + defaultVariants: { + color: 'blue', + size: 'md', + }, +}); +interface ChipProps + extends HTMLAttributes, + VariantProps { + /** 버튼 내부 텍스트 */ + label: string; + /** 사이즈: 'md' | 'lg'*/ + size: 'md' | 'lg'; + /** 색상: 'blue' | 'pink' | 'green' | 'brown'*/ + color: 'blue' | 'pink' | 'green' | 'brown'; +} +export default function ChipTag({ + label, + size = 'md', + color = 'blue', + ...props +}: ChipProps): ReactNode { + return ( + <> +
+ {label} +
+ + ); +} diff --git a/src/components/ui/dashboard-header/index.tsx b/src/components/ui/dashboard-header/index.tsx new file mode 100644 index 0000000..da7fd40 --- /dev/null +++ b/src/components/ui/dashboard-header/index.tsx @@ -0,0 +1,194 @@ +import Image from 'next/image'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; +import { + type ReactNode, + useCallback, + useEffect, + useRef, + useState, +} from 'react'; +import ChipProfile from '@/components/ui/chip/chip-profile'; +import ProfileList from '@/components/ui/dashboard-header/profile-list'; + +const buttonClass = + 'flex-center border-gray-3 text-md mobile:px-3 mobile:py-1.5 h-9 cursor-pointer gap-2 rounded-lg border-1 px-4 py-2.5 hover:bg-gray-4 active:bg-gray-3'; + +export default function DashboardHeader(): ReactNode { + const router = useRouter(); + const [open, setOpen] = useState(false); + const menuRef = useRef(null); + const dashboardId = 1; + + const toggle = useCallback(() => { + setOpen((v) => !v); + }, []); + const close = useCallback(() => { + setOpen(false); + }, []); + + useEffect(() => { + const handleDocClick = (e: MouseEvent) => { + if (!menuRef.current) { + return; + } + if (!menuRef.current.contains(e.target as Node)) { + setOpen(false); + } + }; + + document.addEventListener('mousedown', handleDocClick); + + return () => { + document.removeEventListener('mousedown', handleDocClick); + }; + }, []); + + // 이재준 작성 - 내 정보 페이지로 이동하는 기능 추가 + const goMyPage = useCallback(() => { + close(); + router.push('/mypage'); + }, [close, router]); + + // 이재준 작성 - 내 대시보드 페이지로 이동하는 기능 추가 + const goMyDashboard = useCallback(() => { + close(); + router.push('/mydashboard'); + }, [close, router]); + + // 이재준 작성 - 로그아웃 기능 추가 + const doLogout = useCallback(async () => { + try { + await fetch('/api/logout', { method: 'POST' }); + } catch { + // 로그아웃 실패 시 무시 + } + close(); + router.push('/'); + }, [close, router]); + + return ( +
+
+

내 대시보드

+ 왕관: 내 대시보드 아이콘 +
+ +
+ ); +} + +function SettingIcon() { + return ( + + + + ); +} +function AddBoxIcon() { + return ( + + + + ); +} diff --git a/src/components/ui/dashboard-header/profile-list.tsx b/src/components/ui/dashboard-header/profile-list.tsx new file mode 100644 index 0000000..9a07729 --- /dev/null +++ b/src/components/ui/dashboard-header/profile-list.tsx @@ -0,0 +1,21 @@ +import type { ReactNode } from 'react'; +import ChipProfile from '@/components/ui/chip/chip-profile'; + +export default function ProfileList(): ReactNode { + return ( +
    + {Array(2) + .fill('0') + .map((num: number) => { + return ( +
  • + +
  • + ); + })} +
  • + +
  • +
+ ); +} diff --git a/src/components/ui/side-menu/dashboard-list.tsx b/src/components/ui/side-menu/dashboard-list.tsx new file mode 100644 index 0000000..2360cb5 --- /dev/null +++ b/src/components/ui/side-menu/dashboard-list.tsx @@ -0,0 +1,47 @@ +import Image from 'next/image'; +import type { ReactNode } from 'react'; +import { cn } from '@/utils/cn'; + +export default function DashboardList(): ReactNode { + const selectedId = 0; + + return ( +
    + {Array(10) + .fill('') + .map((num, i) => { + return ( +
  • + +
  • + ); + })} +
+ ); +} diff --git a/src/components/ui/side-menu/index.tsx b/src/components/ui/side-menu/index.tsx new file mode 100644 index 0000000..2dcc5a4 --- /dev/null +++ b/src/components/ui/side-menu/index.tsx @@ -0,0 +1,63 @@ +import Image from 'next/image'; +import Link from 'next/link'; +import type { ReactNode } from 'react'; +import ButtonPagination from '@/components/ui/button/button-pagination'; +import DashboardList from '@/components/ui/side-menu/dashboard-list'; + +export default function SideMenu(): ReactNode { + const handleClickPrev = () => { + console.log('click'); + }; + const handleClickNext = () => { + console.log('click'); + }; + + return ( +
+ + 깃펜 그림 + Taskify + + +
+ ); +} diff --git a/src/hooks/test.ts b/src/hooks/test.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/hooks/useFormValidation.ts b/src/hooks/useFormValidation.ts new file mode 100644 index 0000000..0fe6a4a --- /dev/null +++ b/src/hooks/useFormValidation.ts @@ -0,0 +1,148 @@ +import { useCallback, useState } from 'react'; + +export interface ValidationRule { + validator: (value: string) => boolean; + errorMessage: string; +} + +export interface ValidationRules { + [key: string]: ValidationRule; +} + +export interface FormErrors { + [key: string]: string; +} + +export interface UseFormValidationReturn { + errors: FormErrors; + validateField: (fieldName: string, value: string) => boolean; + validateAllFields: (values: Record) => boolean; + clearError: (fieldName: string) => void; + clearAllErrors: () => void; + isFieldValid: (fieldName: string, value: string) => boolean; + isFormValid: (values: Record) => boolean; +} + +export function useFormValidation( + rules: ValidationRules +): UseFormValidationReturn { + const [errors, setErrors] = useState({}); + + const validateField = useCallback( + (fieldName: string, value: string): boolean => { + const rule = rules[fieldName]; + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (!rule) { + return true; + } + + // 빈 값이면 오류를 표시하지 않음 + if (!value.trim()) { + setErrors((prev) => { + return { + ...prev, + [fieldName]: '', + }; + }); + + return true; + } + + const isValid = rule.validator(value); + + setErrors((prev) => { + return { + ...prev, + [fieldName]: isValid ? '' : rule.errorMessage, + }; + }); + + return isValid; + }, + [rules] + ); + + const validateAllFields = useCallback( + (values: Record): boolean => { + let allValid = true; + const newErrors: FormErrors = {}; + + Object.keys(rules).forEach((fieldName) => { + const rule = rules[fieldName]; + const value = values[fieldName] || ''; + + // 빈 값이면 검증하지 않음 + if (!value.trim()) { + return; + } + + const isValid = rule.validator(value); + + if (!isValid) { + allValid = false; + newErrors[fieldName] = rule.errorMessage; + } + }); + + setErrors(newErrors); + + return allValid; + }, + [rules] + ); + + const clearError = useCallback((fieldName: string) => { + setErrors((prev) => { + return { + ...prev, + [fieldName]: '', + }; + }); + }, []); + + const clearAllErrors = useCallback(() => { + setErrors({}); + }, []); + + const isFieldValid = useCallback( + (fieldName: string, value: string): boolean => { + const rule = rules[fieldName]; + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (!rule) { + return true; + } + + return rule.validator(value); + }, + [rules] + ); + + const isFormValid = useCallback( + (values: Record): boolean => { + return Object.keys(rules).every((fieldName) => { + const rule = rules[fieldName]; + const value = values[fieldName] || ''; + + // 빈 값이면 검증하지 않음 + if (!value.trim()) { + return true; + } + + return rule.validator(value); + }); + }, + [rules] + ); + + return { + errors, + validateField, + validateAllFields, + clearError, + clearAllErrors, + isFieldValid, + isFormValid, + }; +} diff --git a/src/lib/auth/api.ts b/src/lib/auth/api.ts new file mode 100644 index 0000000..ced301a --- /dev/null +++ b/src/lib/auth/api.ts @@ -0,0 +1,30 @@ +import type * as i from '@/lib/auth/interface'; +import { + changePasswordSchema, + loginSchema, + type LoginType, +} from '@/lib/auth/type'; +import { BASE_API_URL } from '@/lib/constants'; +import customFetch from '@/lib/custom-fetch'; + +export const login = async (params: i.LoginParams): Promise => { + const { email, password } = params; + + const data = await customFetch(`${BASE_API_URL}/auth/login`, loginSchema, { + method: 'POST', + body: JSON.stringify({ email, password }), + }); + + return data; +}; + +export const changePassword = async ( + params: i.ChangePasswordParams +): Promise => { + const { password, newPassword } = params; + + await customFetch(`${BASE_API_URL}/auth/password`, changePasswordSchema, { + method: 'PUT', + body: JSON.stringify({ password, newPassword }), + }); +}; diff --git a/src/lib/auth/interface.ts b/src/lib/auth/interface.ts new file mode 100644 index 0000000..a4b38f0 --- /dev/null +++ b/src/lib/auth/interface.ts @@ -0,0 +1,9 @@ +export interface LoginParams { + email: string; + password: string; +} + +export interface ChangePasswordParams { + password: string; + newPassword: string; +} diff --git a/src/lib/auth/type.ts b/src/lib/auth/type.ts index c5f54dd..6ffcfbb 100644 --- a/src/lib/auth/type.ts +++ b/src/lib/auth/type.ts @@ -8,10 +8,13 @@ export const userSchema = z.object({ createdAt: z.string(), updatedAt: z.string(), }); + export const loginSchema = z.object({ + user: userSchema, accessToken: z.string(), - user: z.object(userSchema), }); +export const changePasswordSchema = z.object({}); + export type UserType = z.infer; export type LoginType = z.infer; diff --git a/src/lib/users/api.ts b/src/lib/users/api.ts new file mode 100644 index 0000000..ee46846 --- /dev/null +++ b/src/lib/users/api.ts @@ -0,0 +1,68 @@ +import { BASE_API_URL } from '@/lib/constants'; +import customFetch from '@/lib/custom-fetch'; +import type * as i from '@/lib/users/interface'; +import { + signupSchema, + type SignupType, + updateMyInfoSchema, + type UpdateMyInfoType, + uploadProfileImageSchema, + type UploadProfileImageType, + userSchema, + type UserType, +} from '@/lib/users/type'; + +export const signup = async (params: i.SignupParams): Promise => { + const { email, nickname, password } = params; + + const data = await customFetch(`${BASE_API_URL}/users`, signupSchema, { + method: 'POST', + body: JSON.stringify({ email, nickname, password }), + }); + + return data; +}; + +export const getMyInfo = async (): Promise => { + const data = await customFetch(`${BASE_API_URL}/users/me`, userSchema); + + return data; +}; + +export const updateMyInfo = async ( + params: i.UpdateMyInfoParams +): Promise => { + const { nickname, profileImageUrl } = params; + + const data = await customFetch( + `${BASE_API_URL}/users/me`, + updateMyInfoSchema, + { + method: 'PUT', + body: JSON.stringify({ nickname, profileImageUrl }), + } + ); + + return data; +}; + +export const uploadProfileImage = async ( + params: i.UploadProfileImageParams +): Promise => { + const { image } = params; + + const formData = new FormData(); + + formData.append('image', image); + + const data = await customFetch( + `${BASE_API_URL}/users/me/image`, + uploadProfileImageSchema, + { + method: 'POST', + body: formData, + } + ); + + return data; +}; diff --git a/src/lib/users/interface.ts b/src/lib/users/interface.ts new file mode 100644 index 0000000..1106a1e --- /dev/null +++ b/src/lib/users/interface.ts @@ -0,0 +1,14 @@ +export interface SignupParams { + email: string; + nickname: string; + password: string; +} + +export interface UpdateMyInfoParams { + nickname: string; + profileImageUrl: string; +} + +export interface UploadProfileImageParams { + image: File; +} diff --git a/src/lib/users/type.ts b/src/lib/users/type.ts new file mode 100644 index 0000000..ae43c5d --- /dev/null +++ b/src/lib/users/type.ts @@ -0,0 +1,37 @@ +import z from 'zod'; + +export const userSchema = z.object({ + id: z.number(), + email: z.string(), + nickname: z.string(), + profileImageUrl: z.union([z.null(), z.string()]), + createdAt: z.string(), + updatedAt: z.string(), +}); + +export const signupSchema = z.object({ + id: z.number(), + email: z.string(), + nickname: z.string(), + profileImageUrl: z.union([z.null(), z.string()]), + createdAt: z.string(), + updatedAt: z.string(), +}); + +export const updateMyInfoSchema = z.object({ + id: z.number(), + email: z.string(), + nickname: z.string(), + profileImageUrl: z.union([z.null(), z.string()]), + createdAt: z.string(), + updatedAt: z.string(), +}); + +export const uploadProfileImageSchema = z.object({ + profileImageUrl: z.string(), +}); + +export type UserType = z.infer; +export type SignupType = z.infer; +export type UpdateMyInfoType = z.infer; +export type UploadProfileImageType = z.infer; diff --git a/src/lib/validation/rules.ts b/src/lib/validation/rules.ts new file mode 100644 index 0000000..16c6127 --- /dev/null +++ b/src/lib/validation/rules.ts @@ -0,0 +1,202 @@ +import { useCallback, useMemo, useState } from 'react'; +import { + useFormValidation, + type ValidationRules, +} from '@/hooks/useFormValidation'; + +/** + * 이메일 검증 + */ +export const validateEmail = (email: string): boolean => { + // 빈 값이면 검증하지 않음 + if (!email.trim()) { + return true; + } + const emailRegex = /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/; + + return emailRegex.test(email); +}; + +/** + * 비밀번호 검증 (8자 이상) + */ +export const validatePassword = (password: string): boolean => { + // 빈 값이면 검증하지 않음 + if (!password.trim()) { + return true; + } + + return password.length >= 8; +}; + +/** + * 닉네임 검증 (10자 이하) + */ +export const validateNickname = (nickname: string): boolean => { + // 빈 값이면 검증하지 않음 + if (!nickname.trim()) { + return true; + } + + return nickname.length <= 10; +}; + +/** + * 비밀번호 확인 검증 + */ +export const validateConfirmPassword = ( + password: string, + confirmPassword: string +): boolean => { + return password === confirmPassword; +}; + +/** + * 로그인용 이메일 검증 (빈 값 허용하지 않음) + */ +const validateLoginEmail = (email: string): boolean => { + if (!email.trim()) { + return false; + } + const emailRegex = /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/; + + return emailRegex.test(email); +}; + +/** + * 로그인용 비밀번호 검증 (빈 값 허용하지 않음) + */ +const validateLoginPassword = (password: string): boolean => { + if (!password.trim()) { + return false; + } + + return password.length >= 8; +}; + +// 로그인 폼 검증 규칙 +export const loginValidationRules: ValidationRules = { + email: { + validator: validateLoginEmail, + errorMessage: '이메일 형식으로 작성해 주세요.', + }, + password: { + validator: validateLoginPassword, + errorMessage: '8자 이상 입력해주세요.', + }, +}; + +/** + * 로그인 전용 검증 훅 + */ +export const useLoginValidation = (): ReturnType & { + isFormValid: (values: Record) => boolean; +} => { + const baseValidation = useFormValidation(loginValidationRules); + + // 로그인용 isFormValid (빈 값 허용하지 않음) + const isLoginFormValid = useCallback( + (values: Record): boolean => { + return Object.keys(loginValidationRules).every((fieldName) => { + const rule = loginValidationRules[fieldName]; + const value = values[fieldName] || ''; + + // 빈 값이면 false 반환 + if (!value.trim()) { + return false; + } + + return rule.validator(value); + }); + }, + [] + ); + + return { + ...baseValidation, + isFormValid: isLoginFormValid, + }; +}; + +/** + * 회원가입 폼 검증 규칙 (안정적인 참조를 위해 함수로 변경) + */ +export const getSignupValidationRules = (): ValidationRules => { + return { + nickname: { + validator: validateNickname, + errorMessage: '열 자 이하로 작성해주세요.', + }, + email: { + validator: validateEmail, + errorMessage: '이메일 형식으로 작성해 주세요.', + }, + password: { + validator: validatePassword, + errorMessage: '8자 이상 입력해주세요.', + }, + }; +}; + +/** + * 비밀번호 확인 검증을 위한 커스텀 훅 + */ +export const useSignupValidation = (): ReturnType & { + confirmPasswordError: string; + validateConfirmPassword: ( + password: string, + confirmPassword: string + ) => boolean; + isSignupFormValid: ( + values: Record, + options?: { skipConfirmPassword?: boolean } + ) => boolean; +} => { + // 검증 규칙을 useMemo로 메모이제이션하여 안정적인 참조 보장 + const signupRules = useMemo(() => getSignupValidationRules(), []); + const baseValidation = useFormValidation(signupRules); + const [confirmPasswordError, setConfirmPasswordError] = useState(''); + + const validateConfirmPasswordField = useCallback( + (password: string, confirmPassword: string): boolean => { + // 비밀번호가 비어있으면 검증하지 않음 + if (!password.trim() || !confirmPassword.trim()) { + setConfirmPasswordError(''); + + return true; + } + + const isValid = password === confirmPassword; + + setConfirmPasswordError(isValid ? '' : '비밀번호가 일치하지 않습니다.'); + + return isValid; + }, + [] + ); + + const isSignupFormValid = useCallback( + (values: Record, { skipConfirmPassword = false } = {}) => { + const baseValid = baseValidation.isFormValid(values); + + // skipConfirmPassword가 true이거나 비밀번호가 비어있으면 확인 비밀번호 검증을 건너뛰기 + const confirmValid = + skipConfirmPassword || !values.password || !values.confirmPassword + ? true + : validateConfirmPasswordField( + values.password, + values.confirmPassword + ); + + return baseValid && confirmValid; + }, + [baseValidation.isFormValid, validateConfirmPasswordField] + ); + + return { + ...baseValidation, + confirmPasswordError, + validateConfirmPassword: validateConfirmPasswordField, + isSignupFormValid, + }; +}; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 4fcbe88..c965745 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,5 +1,8 @@ import '@/styles/globals.css'; +import '@/styles/landing.css'; // SPEC: 랜딩 페이지 전용 스타일 변수 +import type { NextPage } from 'next'; import type { AppProps } from 'next/app'; +import { Montserrat } from 'next/font/google'; import localFont from 'next/font/local'; import type { ReactNode } from 'react'; @@ -8,10 +11,24 @@ const pretendardVariable = localFont({ variable: '--font-pretendard', weight: '100 900', }); +const montserrat = Montserrat({ variable: '--font-montserrat' }); -export default function App({ Component, pageProps }: AppProps): ReactNode { - return ( -
+type NextPageWithLayout = NextPage & { + getLayout?: (page: ReactNode) => ReactNode; +}; + +export default function App({ + Component, + pageProps, +}: AppProps & { + Component: NextPageWithLayout; +}): ReactNode { + const getLayout = Component.getLayout ?? ((page: ReactNode) => page); + + return getLayout( +
); diff --git a/src/pages/api/logout.ts b/src/pages/api/logout.ts new file mode 100644 index 0000000..0319955 --- /dev/null +++ b/src/pages/api/logout.ts @@ -0,0 +1,26 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default function handler( + req: NextApiRequest, + res: NextApiResponse +): void { + if (req.method !== 'POST') { + res.status(405).json({ message: 'Method not allowed' }); + + return; + } + + // access_token 쿠키 만료 + const cookieOptions = [ + 'access_token=', + 'HttpOnly', + 'SameSite=Lax', + 'Path=/', + 'Max-Age=0', // 즉시 만료 + // 배포 시 Secure 옵션 추가: 'Secure' + ].join('; '); + + res.setHeader('Set-Cookie', cookieOptions); + + res.status(200).json({ message: 'Logged out successfully' }); +} diff --git a/src/pages/api/me.ts b/src/pages/api/me.ts new file mode 100644 index 0000000..a999b3e --- /dev/null +++ b/src/pages/api/me.ts @@ -0,0 +1,32 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default function handler( + req: NextApiRequest, + res: NextApiResponse +): void { + if (req.method !== 'GET') { + res.status(405).json({ message: 'Method not allowed' }); + + return; + } + + // HttpOnly 쿠키에서 access_token 확인 + const accessToken = req.cookies.access_token; + + if (!accessToken) { + res.status(401).json({ message: 'Unauthorized' }); + + return; + } + + // TODO: 실제로는 accessToken을 검증하고 사용자 정보를 가져와야 함 + // 현재는 임시로 성공 응답만 반환 + res.status(200).json({ + message: 'Authenticated', + user: { + id: 1, + email: 'test@example.com', + nickname: '권수형', + }, + }); +} diff --git a/src/pages/api/session.ts b/src/pages/api/session.ts new file mode 100644 index 0000000..51c6988 --- /dev/null +++ b/src/pages/api/session.ts @@ -0,0 +1,34 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default function handler( + req: NextApiRequest, + res: NextApiResponse +): void { + if (req.method !== 'POST') { + res.status(405).json({ message: 'Method not allowed' }); + + return; + } + + const { accessToken } = req.body; + + if (!accessToken) { + res.status(400).json({ message: 'Access token is required' }); + + return; + } + + // HttpOnly 쿠키 설정 + const cookieOptions = [ + `access_token=${String(accessToken)}`, + 'HttpOnly', + 'SameSite=Lax', + 'Path=/', + `Max-Age=${String(24 * 60 * 60)}`, // 1일 + // 배포 시 Secure 옵션 추가: 'Secure' + ].join('; '); + + res.setHeader('Set-Cookie', cookieOptions); + + res.status(200).json({ message: 'Session created successfully' }); +} diff --git a/src/pages/dashboard/[dashboardId].tsx b/src/pages/dashboard/[dashboardId].tsx new file mode 100644 index 0000000..2362937 --- /dev/null +++ b/src/pages/dashboard/[dashboardId].tsx @@ -0,0 +1,25 @@ +import type { GetServerSideProps } from 'next'; + +/** + * 이재준 작성 - 인증되지 않은 사용자가 대시보드 페이지에 접근할 때 로그인 페이지로 리다이렉트하기 위해 추가 + */ +export const getServerSideProps: GetServerSideProps = async (context) => { + const { req } = context; + + const accessToken = req.cookies.access_token; + + if (!accessToken) { + return { + redirect: { + destination: `/login`, + permanent: false, + }, + }; + } + + return { props: {} }; +}; + +export default function DashboardPage(): null { + return null; +} diff --git a/src/pages/dashboard/[dashboardId]/edit.tsx b/src/pages/dashboard/[dashboardId]/edit.tsx index 92954f2..745377e 100644 --- a/src/pages/dashboard/[dashboardId]/edit.tsx +++ b/src/pages/dashboard/[dashboardId]/edit.tsx @@ -1,3 +1,4 @@ +import type { GetServerSideProps } from 'next'; import Image from 'next/image'; import { useRouter } from 'next/router'; import { type ReactNode, useState } from 'react'; @@ -293,3 +294,23 @@ export default function MydashboardEdit(): ReactNode { ); } + +/** + * 이재준 작성 - 인증되지 않은 사용자가 대시보드 편집 페이지에 접근할 때 로그인 페이지로 리다이렉트하기 위해 추가 + */ +export const getServerSideProps: GetServerSideProps = async (context) => { + const { req } = context; + + const accessToken = req.cookies.access_token; + + if (!accessToken) { + return { + redirect: { + destination: `/login`, + permanent: false, + }, + }; + } + + return { props: {} }; +}; diff --git a/src/pages/dashboard/[dashboardid].tsx b/src/pages/dashboard/[dashboardid].tsx deleted file mode 100644 index 0d08632..0000000 --- a/src/pages/dashboard/[dashboardid].tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useRouter } from 'next/router'; - -export default function DashboardPage() { - const router = useRouter(); - const { dashboardid } = router.query; - - return ( -
-
-

- Dashboard -

-

- 대시보드 ID: {dashboardid} -

-

- 이 페이지는 동적 라우팅으로 생성되었습니다 -

-
-
- ); -} - - - diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 0e408dc..5e86d36 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,70 +1,36 @@ -import { useEffect } from 'react'; -import { useRouter } from 'next/router'; -import Link from 'next/link'; -import Image from 'next/image'; -import styles from '@/styles/auth-variables.module.css'; - -export default function LandingPage() { - const router = useRouter(); - - // API 기능은 나중에 구현 예정 - // useEffect(() => { - // const checkAuth = async () => { - // try { - // const user = await me(); - // if (user.dashboards && user.dashboards.length > 0) { - // router.push(`/dashboard/${user.dashboards[0].id}`); - // } - // } catch (error) { - // // 로그인되지 않은 상태, 랜딩 페이지 유지 - // } - // }; - // checkAuth(); - // }, [router]); +import type { GetStaticProps } from 'next'; +import type { ReactElement } from 'react'; +import FeatureOne from '@/components/home/FeatureOne'; +import FeatureTwo from '@/components/home/FeatureTwo'; +import Footer from '@/components/home/Footer'; +import Header from '@/components/home/Header'; +import Hero from '@/components/home/Hero'; +import SettingsGrid from '@/components/home/SettingsGrid'; +export default function LandingPage(): ReactElement { return ( -
-
- {/* Hero Block */} -
-
-
- - Taskify Logo - -
-
-

- 오늘도 만나서 반가워요! -

-
- - {/* Action Buttons */} -
- - 로그인 - - - 회원가입 - -
+
+
+
+ + + + +
+ {/* Footer 상단 간격 160px */} +
+
-
+ ); } + +/** + * 정적 생성 설정. + */ +export const getStaticProps: GetStaticProps = async () => { + return { + props: {}, + revalidate: false, // 완전 정적 (재생성 안함) + }; +}; diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index 440d8d6..9fa2c9d 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -1,266 +1,194 @@ -import { useState, useEffect } from 'react'; -import { useRouter } from 'next/router'; +import type { GetServerSideProps } from 'next'; import Link from 'next/link'; -import Image from 'next/image'; +import { useRouter } from 'next/router'; +import { type JSX, useCallback, useMemo, useState } from 'react'; +import AuthButton from '@/components/auth/AuthButton'; +import AuthHero from '@/components/auth/AuthHero'; +import EmailInput from '@/components/auth/EmailInput'; +import PasswordInput from '@/components/auth/PasswordInput'; +import UnifiedModal from '@/components/auth/UnifiedModal'; +import { login } from '@/lib/auth/api'; +import type { LoginParams } from '@/lib/auth/interface'; +import { useLoginValidation } from '@/lib/validation/rules'; import styles from '@/styles/auth-variables.module.css'; -export default function LoginPage() { +export default function LoginPage(): JSX.Element { const router = useRouter(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [showPassword, setShowPassword] = useState(false); - const [emailError, setEmailError] = useState(''); - const [passwordError, setPasswordError] = useState(''); const [isLoading, setIsLoading] = useState(false); + const [showModal, setShowModal] = useState(false); + const [modalMessage, setModalMessage] = useState(''); + + const { errors, validateField } = useLoginValidation(); + + const handleEmailBlur = useCallback(() => { + validateField('email', email); + }, [validateField, email]); + + const handlePasswordBlur = useCallback(() => { + validateField('password', password); + }, [validateField, password]); + + const isFormValidNow = useMemo(() => { + // 로그인 폼 유효성 직접 계산 + const isEmailValid = + email.trim() && /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/.test(email); + const isPasswordValid = password.trim() && password.length >= 8; + const result = isEmailValid && isPasswordValid; - const validateEmail = (email: string) => { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - return emailRegex.test(email); - }; + console.log('로그인 폼 유효성:', { + email, + password, + isEmailValid, + isPasswordValid, + result, + }); - const validatePassword = (password: string) => { - return password.length >= 8; - }; + return result; + }, [email, password]); - const handleEmailBlur = () => { - if (email && !validateEmail(email)) { - setEmailError('이메일 형식으로 작성해 주세요.'); - } else { - setEmailError(''); - } - }; + const handleModalClose = useCallback(() => { + setShowModal(false); + setModalMessage(''); + }, []); - const handlePasswordBlur = () => { - if (password && !validatePassword(password)) { - setPasswordError('8자 이상 입력해주세요.'); - } else { - setPasswordError(''); - } - }; + const handleSubmit = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); - const isFormValid = - email && password && validateEmail(email) && validatePassword(password); + // 로그인 폼 유효성 직접 검증 + const isEmailValid = + email.trim() && /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/.test(email); + const isPasswordValid = password.trim() && password.length >= 8; - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if (!isFormValid) return; + if (!isEmailValid || !isPasswordValid) { + return; + } - setIsLoading(true); - try { - // API 기능은 나중에 구현 예정 - // await login({ email, password }); - console.log('로그인 시도:', { email, password }); + setIsLoading(true); - // 임시로 로그인 성공 처리 - setTimeout(() => { - router.push('/mydashboard'); - }, 1000); - } catch (error: any) { - console.error('Login failed:', error); - // 로그인 실패 시 에러 처리 - } finally { - setIsLoading(false); - } - }; + try { + // 로그인 API 호출 + const loginParams: LoginParams = { + email, + password, + }; + + const response = await login(loginParams); + + // accessToken을 HttpOnly 쿠키로 설정 + try { + const sessionResponse = await fetch('/api/session', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + accessToken: response.accessToken, + }), + }); + + if (!sessionResponse.ok) { + throw new Error('Session creation failed'); + } + + // 리다이렉트 경로 결정: 대시보드 경로로 향하던 경우에도 디폴트는 mydashboard + const nextParam = router.query.next as string | undefined; + const nextPath = + nextParam && !nextParam.startsWith('/dashboard') + ? nextParam + : '/mydashboard'; + + router.push(nextPath); + } catch { + setModalMessage( + '로그인 처리 중 오류가 발생했습니다. 다시 시도해주세요.' + ); + setShowModal(true); + } + } catch (error: unknown) { + // 에러 메시지 처리 + const errorMessage = + error instanceof Error ? error.message : '알 수 없는 오류'; + + if (errorMessage.includes('[400]')) { + setModalMessage('비밀번호가 일치하지 않습니다.'); + setShowModal(true); + } else if (errorMessage.includes('[404]')) { + setModalMessage('존재하지 않는 유저입니다.'); + setShowModal(true); + } else { + setModalMessage('로그인에 실패했습니다. 다시 시도해주세요.'); + setShowModal(true); + } + } finally { + setIsLoading(false); + } + }, + [email, password, router] + ); return (
-
+
{/* Hero Block */} -
-
-
- - Taskify Logo - -
-
-

- 오늘도 만나서 반가워요! -

-
+ {/* Form Wrapper */} -
+
{/* Form Stack - 입력 + 버튼 + 하단 안내 */} -
+
{/* Input Group */} -
+
{/* Email Input */} -
- - setEmail(e.target.value)} - onBlur={handleEmailBlur} - placeholder='이메일을 입력해 주세요' - className={`h-[50px] w-[520px] rounded-[8px] bg-white px-[16px] py-[15px] ring-1 placeholder:text-[var(--auth-placeholder)] focus:ring-2 focus:ring-[var(--auth-primary)] focus:outline-none focus-visible:outline-none ${ - emailError - ? 'ring-[var(--auth-error)] focus:ring-[var(--auth-error)]' - : 'ring-[var(--auth-border)]' - }`} - aria-invalid={!!emailError} - aria-describedby={emailError ? 'email-error' : undefined} - /> - {emailError && ( -

- {emailError} -

- )} -
+ {/* Password Input */} -
- -
- setPassword(e.target.value)} - onBlur={handlePasswordBlur} - placeholder='비밀번호를 입력해 주세요' - className={`h-[50px] w-[520px] rounded-[8px] bg-white px-[16px] py-[12px] pr-10 ring-1 placeholder:text-[var(--auth-placeholder)] focus:ring-2 focus:ring-[var(--auth-primary)] focus:outline-none focus-visible:outline-none ${ - passwordError - ? 'ring-[var(--auth-error)] focus:ring-[var(--auth-error)]' - : 'ring-[var(--auth-border)]' - }`} - aria-invalid={!!passwordError} - aria-describedby={ - passwordError ? 'password-error' : undefined - } - /> - -
- {passwordError && ( -

- {passwordError} -

- )} -
+ { + setShowPassword(!showPassword); + }, [showPassword])} + />
{/* Login Button */} - + 로그인 + {/* Bottom Info */}
계정이 없으신가요?
+ + {/* 통합 모달 */} +
); } + +/** + * 정적 생성 설정 + */ +export const getServerSideProps: GetServerSideProps = async (context) => { + const { req } = context; + const accessToken = req.cookies.access_token; + + if (accessToken) { + // 이미 로그인 상태: mydashboard로 보냄 + return Promise.resolve({ + redirect: { + destination: '/mydashboard', + permanent: false, + }, + }); + } + + return Promise.resolve({ props: {} }); +}; diff --git a/src/pages/mydashboard/index.tsx b/src/pages/mydashboard/index.tsx index 4ab2c2b..fc02973 100644 --- a/src/pages/mydashboard/index.tsx +++ b/src/pages/mydashboard/index.tsx @@ -1,52 +1,88 @@ +import type { GetServerSideProps } from 'next'; import Image from 'next/image'; import Link from 'next/link'; import type { ReactNode } from 'react'; +import DashboardLayout from '@/components/layout/dashboard-layout'; -export default function Mydashboard(): ReactNode { +// 인증 상태를 받기 위한 props 타입 정의 +interface MydashboardProps { + /** + * 서버에서 전달받은 로그인 상태 + */ + isLoggedIn: boolean; +} + +export default function Mydashboard({ + isLoggedIn, +}: MydashboardProps): ReactNode { return ( - // 헤더, 사이드바 공간 필요
{/* BG global 생성되면 수정 예정 */} - {/* 헤더 공간 */} -
- {/* 사이드바 공간 */} -
- {/* 새로운 대시보드 */} -
- - - - {/* 초대받은 대시보드 */} -
-

- 초대받은 대시보드 -

- {/* 빈 상태 표시 */} -
- 초대받은 대시보드 -

- 아직 초대받은 대시보드가 없어요 -

-
-
+ {/* 새로운 대시보드 */} +
+ + + + {/* 초대받은 대시보드 */} +
+

+ 초대받은 대시보드 +

+ {/* 빈 상태 표시 */} +
+ 초대받은 대시보드 +

+ 아직 초대받은 대시보드가 없어요 +

+ + {/* 비로그인 시 서버사이드에서 로그인 페이지로 리다이렉트되므로 모달 없음 */}
); } + +/** + * 서버 사이드에서 실행되는 함수 - 페이지 렌더링 전에 로그인 상태 확인 + */ +export const getServerSideProps: GetServerSideProps = async (context) => { + const { req } = context; + + // HttpOnly 쿠키에서 access_token 확인 + const accessToken = req.cookies.access_token; + + if (!accessToken) { + return { + redirect: { + destination: '/login', + permanent: false, + }, + }; + } + + return { + props: { + isLoggedIn: true, + }, + }; +}; + +Mydashboard.getLayout = function getLayout(page: ReactNode) { + return {page}; +}; diff --git a/src/pages/mypage/index.tsx b/src/pages/mypage/index.tsx new file mode 100644 index 0000000..1dba49a --- /dev/null +++ b/src/pages/mypage/index.tsx @@ -0,0 +1,639 @@ +import type { GetServerSideProps } from 'next'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; +import { + type ReactElement, + type ReactNode, + useCallback, + useEffect, + useState, +} from 'react'; +import BackButton from '@/components/auth/back-button'; +import UnifiedModal from '@/components/auth/UnifiedModal'; +import DashboardLayout from '@/components/layout/dashboard-layout'; +import { BASE_API_URL } from '@/lib/constants'; +import type { UserType } from '@/lib/users/type'; +import styles from '@/styles/auth-variables.module.css'; + +interface MyPageProps { + isAuthenticated: boolean; + userInfo: UserType | null; + accessToken: string; +} + +export default function MyPage({ + isAuthenticated, + userInfo: initialUserInfo, + accessToken, +}: MyPageProps): ReactElement { + const router = useRouter(); + + // 사용자 정보 상태 + const [userInfo, setUserInfo] = useState(initialUserInfo); + const [nickname, setNickname] = useState(initialUserInfo?.nickname || ''); + const [isLoading, setIsLoading] = useState(false); + + // 모달 상태 + const [isModalOpen, setIsModalOpen] = useState(false); + const [modalMessage, setModalMessage] = useState(''); + const [modalType, setModalType] = useState<'success' | 'error'>('success'); + + // 모달 열기 헬퍼 함수 + const showModal = useCallback( + ({ + message, + type = 'success', + }: { + message: string; + type?: 'success' | 'error'; + }) => { + setModalMessage(message); + setModalType(type); + setIsModalOpen(true); + }, + [] + ); + + // 모달 닫기 함수 + const closeModal = useCallback(() => { + setIsModalOpen(false); + }, []); + + // API 호출 헬퍼 함수 + const apiCall = useCallback( + async ({ url, options = {} }: { url: string; options?: RequestInit }) => { + const response = await fetch(url, { + ...options, + headers: { + 'Content-Type': 'application/json', + ...(accessToken && { Authorization: `Bearer ${accessToken}` }), + ...(options.headers as Record), + }, + }); + + if (!response.ok) { + const errorText = await response.text(); + + throw new Error(`[${String(response.status)}] ${errorText}`); + } + + // 응답이 비어있을 수 있는 경우 처리 + const contentType = response.headers.get('content-type'); + + if (contentType?.includes('application/json')) { + const text = await response.text(); + + return text ? (JSON.parse(text) as unknown) : null; + } + + return null; + }, + [accessToken] + ); + + // 비밀번호 변경 폼 상태 + const [currentPassword, setCurrentPassword] = useState(''); + const [newPassword, setNewPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + + // 인증되지 않은 경우 로그인 페이지로 리다이렉트 + useEffect(() => { + if (!isAuthenticated) { + router.replace('/login'); + } + }, [isAuthenticated, router]); + + // 프로필 이미지 업로드 핸들러 + const handleImageUpload = useCallback( + async (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + + if (!file) { + return; + } + + try { + setIsLoading(true); + + // FormData 생성 + const formData = new FormData(); + + formData.append('image', file); + + // 프로필 이미지 업로드 + const response = await fetch(`${BASE_API_URL}/users/me/image`, { + method: 'POST', + headers: { + ...(accessToken && { Authorization: `Bearer ${accessToken}` }), + }, + body: formData, + }); + + if (!response.ok) { + const errorText = await response.text(); + + throw new Error(`[${String(response.status)}] ${errorText}`); + } + + const result = await response.json(); + + // 사용자 정보 업데이트 + if (userInfo) { + const updatedUserInfo = { + ...userInfo, + profileImageUrl: (result as { profileImageUrl: string }) + .profileImageUrl, + }; + + setUserInfo(updatedUserInfo); + } + } catch { + showModal({ message: '이미지 업로드에 실패했습니다.', type: 'error' }); + } finally { + setIsLoading(false); + } + }, + [accessToken, userInfo, showModal] + ); + + // 닉네임 수정 핸들러 + const handleUpdateNickname = useCallback(async () => { + if (!userInfo || !nickname.trim()) { + return; + } + + // 닉네임 길이 검증 (10자 이하) + if (nickname.trim().length > 10) { + showModal({ + message: '닉네임은 10자 이하로 작성해주세요.', + type: 'error', + }); + + return; + } + + try { + setIsLoading(true); + const updatedUserInfo = await apiCall({ + url: `${BASE_API_URL}/users/me`, + options: { + method: 'PUT', + body: JSON.stringify({ + nickname: nickname.trim(), + ...(userInfo.profileImageUrl && { + profileImageUrl: userInfo.profileImageUrl, + }), + }), + }, + }); + + setUserInfo(updatedUserInfo as UserType); + showModal({ message: '닉네임이 변경되었습니다.', type: 'success' }); + } catch (error) { + // API에서 반환한 구체적인 에러 메시지 추출 + let errorMessage = '닉네임 변경에 실패했습니다.'; + + if (error instanceof Error) { + try { + // "[400] {"message":"닉네임은 10자 이하로 작성해주세요."}" 형태에서 message 추출 + const match = error.message.match( + /\{[^}]*"message"\s*:\s*"([^"]*)"[^}]*\}/ + ); + + if (match?.[1]) { + errorMessage = match[1]; + } + } catch { + // JSON 파싱 실패 시 기본 메시지 사용 + } + } + + showModal({ message: errorMessage, type: 'error' }); + } finally { + setIsLoading(false); + } + }, [userInfo, nickname, apiCall, showModal]); + + // 비밀번호 변경 핸들러 + const handlePasswordChange = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + + if (newPassword !== confirmPassword) { + showModal({ message: '비밀번호가 일치하지 않습니다.', type: 'error' }); + + return; + } + + if (newPassword.length < 8) { + showModal({ + message: '비밀번호는 8자 이상이어야 합니다.', + type: 'error', + }); + + return; + } + + try { + setIsLoading(true); + await apiCall({ + url: `${BASE_API_URL}/auth/password`, + options: { + method: 'PUT', + body: JSON.stringify({ + password: currentPassword, + newPassword, + }), + }, + }); + + // 폼 초기화 + setCurrentPassword(''); + setNewPassword(''); + setConfirmPassword(''); + + showModal({ message: '비밀번호가 변경되었습니다.', type: 'success' }); + } catch (error) { + // API에서 반환한 구체적인 에러 메시지 추출 + let errorMessage = '비밀번호 변경에 실패했습니다.'; + + if (error instanceof Error) { + try { + // "[400] {"message":"현재 비밀번호가 틀렸습니다."}" 형태에서 message 추출 + const match = error.message.match( + /\{[^}]*"message"\s*:\s*"([^"]*)"[^}]*\}/ + ); + + if (match?.[1]) { + errorMessage = match[1]; + } + } catch { + // JSON 파싱 실패 시 기본 메시지 사용 + } + } + + showModal({ message: errorMessage, type: 'error' }); + } finally { + setIsLoading(false); + } + }, + [newPassword, confirmPassword, currentPassword, apiCall, showModal] + ); + + // 프로필 이미지 클릭 핸들러 + const handleProfileImageClick = useCallback(() => { + const input = document.querySelector( + '#profile-image-input' + ) as HTMLInputElement; + + input.click(); + }, []); + + if (!isAuthenticated) { + return
인증 확인 중...
; + } + + return ( + +
+
+ +
+ + {/* 메인 컨테이너 */} +
+ {/* 프로필 컨테이너 */} +
+

+ 프로필 +

+ + {/* 프로필 영역 */} +
+ {/* 프로필 정사각형 상자 */} + + + {/* 프로필 폼 */} +
+ {/* 이메일 */} +
+ + +
+ + {/* 닉네임 */} +
+ + { + setNickname(e.target.value); + }} + /> +
+ + {/* 저장 버튼 */} + +
+
+
+ + {/* 비밀번호 변경 컨테이너 */} +
+

+ 비밀번호 변경 +

+ + {/* 비밀번호 변경 폼 */} + + {/* 현재 비밀번호 */} +
+ + { + setCurrentPassword(e.target.value); + }} + /> +
+ + {/* 새 비밀번호 */} +
+ + { + setNewPassword(e.target.value); + }} + /> +
+ + {/* 새 비밀번호 확인 */} +
+ + { + setConfirmPassword(e.target.value); + }} + /> +
+ + {/* 변경 버튼 */} + + +
+
+
+ + {/* 모달 */} + +
+ ); +} + +/** + * 서버사이드에서 인증 상태 확인 및 사용자 정보 가져오기 + */ +export const getServerSideProps: GetServerSideProps = async (context) => { + const { req } = context; + + // HttpOnly 쿠키에서 access_token 확인 + const accessToken = req.cookies.access_token; + const isAuthenticated = Boolean(accessToken); + + if (!isAuthenticated) { + return { + redirect: { + destination: '/login', + permanent: false, + }, + }; + } + + // 서버에서 사용자 정보 가져오기 + let userInfo = null; + + try { + const response = await fetch(`${BASE_API_URL}/users/me`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${String(accessToken)}`, + }, + }); + + if (response.ok) { + userInfo = await response.json(); + } + } catch { + // 서버에서 사용자 정보 조회 실패 시 기본값 사용 + } + + return { + props: { + isAuthenticated, + userInfo, + accessToken, + }, + }; +}; + +MyPage.getLayout = function getLayout(page: ReactNode) { + return page; +}; diff --git a/src/pages/signup/index.tsx b/src/pages/signup/index.tsx index 97766b5..8c15ada 100644 --- a/src/pages/signup/index.tsx +++ b/src/pages/signup/index.tsx @@ -1,10 +1,21 @@ -import { useState } from 'react'; -import { useRouter } from 'next/router'; +import type { GetServerSideProps } from 'next'; import Link from 'next/link'; -import Image from 'next/image'; +import { useRouter } from 'next/router'; +import { useCallback, useMemo, useState } from 'react'; +import AuthButton from '@/components/auth/AuthButton'; +import AuthHero from '@/components/auth/AuthHero'; +import EmailInput from '@/components/auth/EmailInput'; +import PasswordInput from '@/components/auth/PasswordInput'; +import TextInput from '@/components/auth/TextInput'; +import UnifiedModal from '@/components/auth/UnifiedModal'; +import { signup } from '@/lib/users/api'; +import type { SignupParams } from '@/lib/users/interface'; +import { useSignupValidation } from '@/lib/validation/rules'; import styles from '@/styles/auth-variables.module.css'; -export default function SignupPage() { +const SUCCESS_MESSAGE = '가입이 완료되었습니다!'; + +export default function SignupPage(): React.JSX.Element { const router = useRouter(); const [nickname, setNickname] = useState(''); const [email, setEmail] = useState(''); @@ -12,438 +23,212 @@ export default function SignupPage() { const [confirmPassword, setConfirmPassword] = useState(''); const [showPassword, setShowPassword] = useState(false); const [showConfirmPassword, setShowConfirmPassword] = useState(false); - const [nicknameError, setNicknameError] = useState(''); - const [emailError, setEmailError] = useState(''); - const [passwordError, setPasswordError] = useState(''); - const [confirmPasswordError, setConfirmPasswordError] = useState(''); const [isLoading, setIsLoading] = useState(false); const [agreedToTerms, setAgreedToTerms] = useState(false); + const [showModal, setShowModal] = useState(false); + const [modalMessage, setModalMessage] = useState(''); - const validateNickname = (nickname: string) => { - return nickname.length <= 10; - }; - - const validateEmail = (email: string) => { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - return emailRegex.test(email); - }; - - const validatePassword = (password: string) => { - return password.length >= 8; - }; - - const validateConfirmPassword = ( - password: string, - confirmPassword: string - ) => { - return password === confirmPassword; - }; - - const handleNicknameBlur = () => { - if (nickname && !validateNickname(nickname)) { - setNicknameError('열 자 이하로 작성해주세요.'); - } else { - setNicknameError(''); - } - }; + const { + errors, + validateField, + confirmPasswordError, + validateConfirmPassword, + isSignupFormValid, + } = useSignupValidation(); - const handleEmailBlur = () => { - if (email && !validateEmail(email)) { - setEmailError('이메일 형식으로 작성해 주세요.'); - } else { - setEmailError(''); - } - }; + const handleNicknameBlur = useCallback(() => { + validateField('nickname', nickname); + }, [validateField, nickname]); - const handlePasswordBlur = () => { - if (password && !validatePassword(password)) { - setPasswordError('8자 이상 입력해주세요.'); - } else { - setPasswordError(''); + const handleEmailBlur = useCallback(() => { + validateField('email', email); + }, [validateField, email]); + + const handlePasswordBlur = useCallback(() => { + validateField('password', password); + // 비밀번호가 변경되면 확인 비밀번호도 다시 검증 (둘 다 입력된 경우에만) + if (password && confirmPassword && confirmPassword.length > 0) { + validateConfirmPassword(password, confirmPassword); } - }; + }, [validateField, password, confirmPassword, validateConfirmPassword]); - const handleConfirmPasswordBlur = () => { + const handleConfirmPasswordBlur = useCallback(() => { + // 비밀번호와 확인 비밀번호가 모두 입력된 경우에만 검증 if ( + password && confirmPassword && - !validateConfirmPassword(password, confirmPassword) + password.length > 0 && + confirmPassword.length > 0 ) { - setConfirmPasswordError('비밀번호가 일치하지 않습니다.'); - } else { - setConfirmPasswordError(''); + validateConfirmPassword(password, confirmPassword); } - }; - - const isFormValid = - nickname && - email && - password && - confirmPassword && - validateNickname(nickname) && - validateEmail(email) && - validatePassword(password) && - validateConfirmPassword(password, confirmPassword) && - !nicknameError && - !emailError && - !passwordError && - !confirmPasswordError && - agreedToTerms; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if (!isFormValid) return; - - setIsLoading(true); - try { - // API 기능은 나중에 구현 예정 - console.log('회원가입 시도:', { - nickname, - email, - password, - confirmPassword, - }); - - // 임시로 회원가입 성공 처리 - alert('가입이 완료되었습니다'); + }, [validateConfirmPassword, password, confirmPassword]); + + const isFormValidNow = useMemo(() => { + return ( + isSignupFormValid( + { nickname, email, password, confirmPassword }, + { skipConfirmPassword: true } + ) && agreedToTerms + ); + }, [ + isSignupFormValid, + nickname, + email, + password, + confirmPassword, + agreedToTerms, + ]); + + const handleModalClose = useCallback(() => { + setShowModal(false); + setModalMessage(''); + // 성공 모달인 경우 로그인 페이지로 이동 + if (modalMessage === SUCCESS_MESSAGE) { router.push('/login'); - } catch (error: any) { - console.error('Signup failed:', error); - // 회원가입 실패 시 에러 처리 - } finally { - setIsLoading(false); } - }; + }, [modalMessage, router]); + + const handleSubmit = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + + // 폼 유효성 검사 + const isFormValid = + isSignupFormValid( + { nickname, email, password, confirmPassword }, + { skipConfirmPassword: false } + ) && agreedToTerms; + + if (!isFormValid) { + return; + } + + setIsLoading(true); + + try { + // 회원가입 API 호출 + const signupParams: SignupParams = { + nickname, + email, + password, + }; + + await signup(signupParams); + + // 회원가입 성공 모달 표시 + setModalMessage(SUCCESS_MESSAGE); + setShowModal(true); + } catch (error: unknown) { + // 에러 메시지 처리 + const errorMessage = error instanceof Error ? error.message : ''; + + if (errorMessage.includes('[409]') || errorMessage.includes('[400]')) { + setModalMessage('이미 사용중인 이메일입니다'); + setShowModal(true); + } else { + setModalMessage('회원가입에 실패했습니다. 다시 시도해주세요.'); + setShowModal(true); + } + } finally { + setIsLoading(false); + } + }, + [ + nickname, + email, + password, + confirmPassword, + agreedToTerms, + isSignupFormValid, + ] + ); + + // 비밀번호 표시/숨김 토글 핸들러들 + const handleTogglePassword = useCallback(() => { + setShowPassword(!showPassword); + }, [showPassword]); + + const handleToggleConfirmPassword = useCallback(() => { + setShowConfirmPassword(!showConfirmPassword); + }, [showConfirmPassword]); + + // 약관 동의 체크박스 핸들러 + const handleTermsChange = useCallback( + (e: React.ChangeEvent) => { + setAgreedToTerms(e.target.checked); + }, + [] + ); return (
-
+
{/* Hero Block */} -
-
-
- - Taskify Logo - -
-
-

- 첫 방문을 환영합니다! -

-
+ {/* Form Wrapper */} -
+
{/* Form Stack - 입력 + 버튼 + 하단 안내 */} -
+
{/* Input Group */} -
+
{/* Nickname Input */} -
- - setNickname(e.target.value)} - onBlur={handleNicknameBlur} - placeholder='닉네임을 입력해 주세요' - className={`h-[50px] w-[520px] rounded-[8px] bg-white px-[16px] py-[15px] ring-1 placeholder:text-[var(--auth-placeholder)] focus:ring-2 focus:ring-[var(--auth-primary)] focus:outline-none focus-visible:outline-none ${ - nicknameError - ? 'ring-[var(--auth-error)] focus:ring-[var(--auth-error)]' - : 'ring-[var(--auth-border)]' - }`} - aria-invalid={!!nicknameError} - aria-describedby={ - nicknameError ? 'nickname-error' : undefined - } - /> - {nicknameError && ( -

- {nicknameError} -

- )} -
+ {/* Email Input */} -
- - setEmail(e.target.value)} - onBlur={handleEmailBlur} - placeholder='이메일을 입력해 주세요' - className={`h-[50px] w-[520px] rounded-[8px] bg-white px-[16px] py-[15px] ring-1 placeholder:text-[var(--auth-placeholder)] focus:ring-2 focus:ring-[var(--auth-primary)] focus:outline-none focus-visible:outline-none ${ - emailError - ? 'ring-[var(--auth-error)] focus:ring-[var(--auth-error)]' - : 'ring-[var(--auth-border)]' - }`} - aria-invalid={!!emailError} - aria-describedby={emailError ? 'email-error' : undefined} - /> - {emailError && ( -

- {emailError} -

- )} -
+ {/* Password Input */} -
- -
- setPassword(e.target.value)} - onBlur={handlePasswordBlur} - placeholder='비밀번호를 입력해 주세요' - className={`h-[50px] w-[520px] rounded-[8px] bg-white px-[16px] py-[12px] pr-10 ring-1 placeholder:text-[var(--auth-placeholder)] focus:ring-2 focus:ring-[var(--auth-primary)] focus:outline-none focus-visible:outline-none ${ - passwordError - ? 'ring-[var(--auth-error)] focus:ring-[var(--auth-error)]' - : 'ring-[var(--auth-border)]' - }`} - aria-invalid={!!passwordError} - aria-describedby={ - passwordError ? 'password-error' : undefined - } - /> - -
- {passwordError && ( -

- {passwordError} -

- )} -
+ {/* Confirm Password Input */} -
- -
- setConfirmPassword(e.target.value)} - onBlur={handleConfirmPasswordBlur} - placeholder='비밀번호를 다시 입력해 주세요' - className={`h-[50px] w-[520px] rounded-[8px] bg-white px-[16px] py-[12px] pr-10 ring-1 placeholder:text-[var(--auth-placeholder)] focus:ring-2 focus:ring-[var(--auth-primary)] focus:outline-none focus-visible:outline-none ${ - confirmPasswordError - ? 'ring-[var(--auth-error)] focus:ring-[var(--auth-error)]' - : 'ring-[var(--auth-border)]' - }`} - aria-invalid={!!confirmPasswordError} - aria-describedby={ - confirmPasswordError - ? 'confirm-password-error' - : undefined - } - /> - -
- {confirmPasswordError && ( -

- {confirmPasswordError} -

- )} -
+
{/* Terms Agreement */} @@ -452,8 +237,8 @@ export default function SignupPage() { id='terms' type='checkbox' checked={agreedToTerms} - onChange={(e) => setAgreedToTerms(e.target.checked)} className='h-5 w-5 rounded border-gray-300 text-[var(--auth-primary)] focus:ring-[var(--auth-primary)]' + onChange={handleTermsChange} />
+ + {/* 통합 모달 */} +
); } + +/** + * 정적 생성 설정 + */ +export const getServerSideProps: GetServerSideProps = async (context) => { + const { req } = context; + const accessToken = req.cookies.access_token; + + if (accessToken) { + return { + redirect: { + destination: '/mydashboard', + permanent: false, + }, + }; + } + + return { props: {} }; +}; diff --git a/src/stories/Button.stories.ts b/src/stories/Button.stories.ts new file mode 100644 index 0000000..c4915d1 --- /dev/null +++ b/src/stories/Button.stories.ts @@ -0,0 +1,76 @@ +import { fn } from 'storybook/test'; +import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from 'storybook/viewport'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import Button from '@/components/ui/button/button'; + +const meta = { + title: 'button', + component: Button, + parameters: { + viewport: { ...MINIMAL_VIEWPORTS, ...INITIAL_VIEWPORTS }, + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + variant: { + control: { type: 'radio' }, + options: ['primary', 'invitation', 'modal'], + }, + backgroundColor: { + control: { type: 'radio' }, + options: ['violet', 'white'], + }, + labelColor: { + control: { type: 'radio' }, + options: ['gray'], + }, + label: { + control: 'text', + }, + disabled: { + control: 'boolean', + }, + }, + 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: { + variant: 'primary', + backgroundColor: 'violet', + label: '로그인', + }, +}; +export const Invitation: Story = { + args: { + variant: 'invitation', + backgroundColor: 'violet', + label: '수락', + }, +}; +export const WhiteInvitation: Story = { + args: { + variant: 'invitation', + backgroundColor: 'white', + label: '거절', + }, +}; +export const Modal: Story = { + args: { + variant: 'modal', + backgroundColor: 'violet', + label: '확인', + }, +}; +export const WhiteModalWithGrayLabel: Story = { + args: { + variant: 'modal', + backgroundColor: 'white', + labelColor: 'gray', + label: '취소', + }, +}; diff --git a/src/stories/ButtonPagination.stories.ts b/src/stories/ButtonPagination.stories.ts new file mode 100644 index 0000000..4602ae2 --- /dev/null +++ b/src/stories/ButtonPagination.stories.ts @@ -0,0 +1,35 @@ +import { fn } from 'storybook/internal/test'; +import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from 'storybook/viewport'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import ButtonPagination from '@/components/ui/button/button-pagination'; + +const meta = { + title: 'button-pagination', + component: ButtonPagination, + parameters: { + viewport: { ...MINIMAL_VIEWPORTS, ...INITIAL_VIEWPORTS }, + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + isNextDisabled: { + control: 'boolean', + }, + isPrevDisabled: { + control: 'boolean', + }, + additionalClass: {}, + }, + args: { onPrevClick: fn(), onNextClick: fn() }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; +export const Disabled: Story = { + args: { + isPrevDisabled: true, + isNextDisabled: true, + }, +}; diff --git a/src/stories/ChipProfile.stories.ts b/src/stories/ChipProfile.stories.ts new file mode 100644 index 0000000..eff847b --- /dev/null +++ b/src/stories/ChipProfile.stories.ts @@ -0,0 +1,51 @@ +import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from 'storybook/viewport'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import ChipProfile from '@/components/ui/chip/chip-profile'; + +const meta = { + title: 'chip-profile', + component: ChipProfile, + parameters: { + viewport: { ...MINIMAL_VIEWPORTS, ...INITIAL_VIEWPORTS }, + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + size: { + control: 'radio', + options: ['sm', 'md', 'lg'], + }, + color: { + control: 'radio', + options: ['green', 'blue', 'orange', 'yellow', 'brown', 'red'], + }, + label: { + control: 'text', + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const GreenSM: Story = { + args: { + size: 'sm', + color: 'green', + label: 'K', + }, +}; +export const BlueMD: Story = { + args: { + size: 'md', + color: 'blue', + label: 'L', + }, +}; +export const RedLG: Story = { + args: { + size: 'lg', + color: 'red', + label: 'P', + }, +}; diff --git a/src/stories/ChipState.stories.ts b/src/stories/ChipState.stories.ts new file mode 100644 index 0000000..6d2ace0 --- /dev/null +++ b/src/stories/ChipState.stories.ts @@ -0,0 +1,38 @@ +import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from 'storybook/viewport'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import ChipState from '@/components/ui/chip/chip-state'; + +const meta = { + title: 'chip-state', + component: ChipState, + parameters: { + viewport: { ...MINIMAL_VIEWPORTS, ...INITIAL_VIEWPORTS }, + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + size: { + control: 'radio', + options: ['md', 'lg'], + }, + label: { + control: 'text', + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Md: Story = { + args: { + size: 'md', + label: 'On Progress', + }, +}; +export const Lg: Story = { + args: { + size: 'lg', + label: 'On Progress', + }, +}; diff --git a/src/stories/ChipTag.stories.ts b/src/stories/ChipTag.stories.ts new file mode 100644 index 0000000..09f4eab --- /dev/null +++ b/src/stories/ChipTag.stories.ts @@ -0,0 +1,58 @@ +import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from 'storybook/viewport'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import ChipTag from '@/components/ui/chip/chip-tag'; + +const meta = { + title: 'chip-tag', + component: ChipTag, + parameters: { + viewport: { ...MINIMAL_VIEWPORTS, ...INITIAL_VIEWPORTS }, + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + size: { + control: 'radio', + options: ['md', 'lg'], + }, + color: { + control: 'radio', + options: ['blue', 'pink', 'green', 'brown'], + }, + label: { + control: 'text', + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const BrownMD: Story = { + args: { + size: 'md', + color: 'brown', + label: '프로젝트', + }, +}; +export const GreenMD: Story = { + args: { + size: 'md', + color: 'green', + label: '일반', + }, +}; +export const PinkLG: Story = { + args: { + size: 'lg', + color: 'pink', + label: '백엔드', + }, +}; +export const BlueLG: Story = { + args: { + size: 'lg', + color: 'blue', + label: '상', + }, +}; diff --git a/src/stories/DashboardHeader.stories.tsx b/src/stories/DashboardHeader.stories.tsx new file mode 100644 index 0000000..8bf4634 --- /dev/null +++ b/src/stories/DashboardHeader.stories.tsx @@ -0,0 +1,38 @@ +import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from 'storybook/viewport'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import DashboardHeader from '@/components/ui/dashboard-header'; + +const meta = { + title: 'dashboard-header', + component: DashboardHeader, + parameters: { + viewport: { ...MINIMAL_VIEWPORTS, ...INITIAL_VIEWPORTS }, + layout: 'centered', + }, + decorators: [ + (Story) => { + return ( +
+ +
+ ); + }, + ], + tags: ['autodocs'], + argTypes: { + title: { + control: { type: 'string' }, + }, + members: {}, + me: {}, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + title: '나의 대시보드', + }, +}; diff --git a/src/stories/SideMenu.stories.tsx b/src/stories/SideMenu.stories.tsx new file mode 100644 index 0000000..2a757b2 --- /dev/null +++ b/src/stories/SideMenu.stories.tsx @@ -0,0 +1,28 @@ +import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from 'storybook/viewport'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import SideMenu from '@/components/ui/side-menu'; + +const meta = { + title: 'side-menu', + component: SideMenu, + decorators: [ + (Story) => { + return ( +
+ +
+ ); + }, + ], + parameters: { + viewport: { ...MINIMAL_VIEWPORTS, ...INITIAL_VIEWPORTS }, + layout: 'padded', + }, + tags: ['autodocs'], + argTypes: {}, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/storybook/StorybookTemplate.tsx b/src/storybook/StorybookTemplate.tsx new file mode 100644 index 0000000..1aaa306 --- /dev/null +++ b/src/storybook/StorybookTemplate.tsx @@ -0,0 +1,25 @@ +import type { ReactNode } from 'react'; +import { + ArgTypes, + Description, + Primary, + Stories, + Title, +} from '@storybook/addon-docs/blocks'; + +function StorybookTemplate(): ReactNode { + return ( + <> +
+ + <Description /> + <Primary /> + <ArgTypes /> + <Stories /> + <br /> + <br /> + </> + ); +} + +export default StorybookTemplate; diff --git a/src/storybook/main.ts b/src/storybook/main.ts new file mode 100644 index 0000000..c378d10 --- /dev/null +++ b/src/storybook/main.ts @@ -0,0 +1,21 @@ +import type { StorybookConfig } from '@storybook/nextjs-vite'; + +const config: StorybookConfig = { + stories: [ + '../stories/**/*.mdx', + '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)', + ], + addons: [ + '@chromatic-com/storybook', + '@storybook/addon-docs', + '@storybook/addon-a11y', + '@storybook/addon-vitest', + ], + framework: { + name: '@storybook/nextjs-vite', + options: {}, + }, + staticDirs: ['../../public'], +}; + +export default config; diff --git a/src/storybook/preview.ts b/src/storybook/preview.ts new file mode 100644 index 0000000..4d2fe01 --- /dev/null +++ b/src/storybook/preview.ts @@ -0,0 +1,30 @@ +import '@/styles/globals.css'; +import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from 'storybook/viewport'; +import type { Preview } from '@storybook/nextjs-vite'; +import StorybookTemplate from '@/storybook/StorybookTemplate'; + +const preview: Preview = { + parameters: { + docs: { + page: StorybookTemplate, + }, + viewport: { + options: { ...INITIAL_VIEWPORTS, ...MINIMAL_VIEWPORTS }, + }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + + a11y: { + // 'todo' - show a11y violations in the test UI only + // 'error' - fail CI on a11y violations + // 'off' - skip a11y checks entirely + test: 'todo', + }, + }, +}; + +export default preview; diff --git a/src/storybook/vitest.setup.ts b/src/storybook/vitest.setup.ts new file mode 100644 index 0000000..9975e9d --- /dev/null +++ b/src/storybook/vitest.setup.ts @@ -0,0 +1,7 @@ +import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview'; +import { setProjectAnnotations } from '@storybook/nextjs-vite'; +import * as projectAnnotations from '@/storybook/preview'; + +// This is an important step to apply the right configuration when testing your stories. +// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations +setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]); diff --git a/src/styles/globals.css b/src/styles/globals.css index 58cde82..924c422 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -27,6 +27,18 @@ --color-blue: #76a5ea; --color-pink: #e876ea; + --color-chip-blue: #4981d5; + --color-chip-blue-bg: #dbe6f7; + --color-chip-pink: #d549b6; + --color-chip-pink-bg: #f7dbf0; + --color-chip-green: #86d549; + --color-chip-green-bg: #e7f7db; + --color-chip-brown: #d58d49; + --color-chip-brown-bg: #f9eee3; + + --color-chip-red: #d25b68; + --color-chip-red-bg: #f4d7da; + /** @text */ --text-3xl: 2rem; --text-2xl: 1.5rem; @@ -48,6 +60,10 @@ /** @font */ --font-pretendard: var(--font-pretendard); + --font-montserrat: var(--font-montserrat); + + /** @radius */ + --radius-xl: 0.75rem; } /** @break-point */ @theme { diff --git a/src/styles/landing.css b/src/styles/landing.css new file mode 100644 index 0000000..49f357b --- /dev/null +++ b/src/styles/landing.css @@ -0,0 +1,51 @@ +/* ===== 랜딩 페이지 전용 토큰 ===== */ +/* SPEC: 채팅 로그 기반 랜딩 페이지 스타일 변수 */ +/* 전역 오염 방지를 위한 명확한 네이밍 */ + +:root { + --landing-brand-violet: #5534da; + --landing-black-000: #000000; + --landing-black-171: #171717; + --landing-gray-9fa: #9fa6b2; + --landing-radius-lg: 8px; + + /* ===== [landing] footer tokens ===== */ + --color-inverse: #000000; /* footer bg (Figma) */ + --on-inverse: #ffffff; /* text on black */ + --muted-on-inverse: #9fa6b2; /* subtle text on black (Figma text color) */ +} + +/* ===== 랜딩 페이지 전용 유틸리티 ===== */ +@layer utilities { + .bg-brand { + background: var(--landing-brand-violet) !important; + } + + .text-brand { + color: var(--landing-brand-violet) !important; + } + + .bg-black-171 { + background: var(--landing-black-171) !important; + } + + .text-gray-9fa { + color: var(--landing-gray-9fa) !important; + } + + /* [landing] 한글 줄바꿈 제어 */ + .break-keep { + word-break: keep-all !important; + } /* 한글/동아시아 단어 중간 줄바꿈 금지 */ + + /* ===== [landing] footer utilities ===== */ + .bg-inverse { + background: var(--color-inverse); + } + .text-on-inverse { + color: var(--on-inverse); + } + .text-muted-on-inverse { + color: var(--muted-on-inverse); + } +} diff --git a/src/utils/cn.ts b/src/utils/cn.ts new file mode 100644 index 0000000..1659b5e --- /dev/null +++ b/src/utils/cn.ts @@ -0,0 +1,4 @@ +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export const cn = (...inputs: ClassValue[]): string => twMerge(clsx(inputs)); diff --git a/src/vitest.config.ts b/src/vitest.config.ts new file mode 100644 index 0000000..f57bf0f --- /dev/null +++ b/src/vitest.config.ts @@ -0,0 +1,35 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { defineConfig } from 'vitest/config'; +import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; + +const dirname = + typeof __dirname !== 'undefined' + ? __dirname + : path.dirname(fileURLToPath(import.meta.url)); + +// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon +export default defineConfig({ + test: { + projects: [ + { + extends: true, + plugins: [ + // The plugin will run tests for the stories defined in your Storybook config + // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest + storybookTest({ configDir: path.join(dirname, '.storybook') }), + ], + test: { + name: 'storybook', + browser: { + enabled: true, + headless: true, + provider: 'playwright', + instances: [{ browser: 'chromium' }], + }, + setupFiles: ['.storybook/vitest.setup.ts'], + }, + }, + ], + }, +}); diff --git a/src/vitest.shims.d.ts b/src/vitest.shims.d.ts new file mode 100644 index 0000000..a1d31e5 --- /dev/null +++ b/src/vitest.shims.d.ts @@ -0,0 +1 @@ +/// <reference types="@vitest/browser/providers/playwright" /> diff --git a/tall b/tall new file mode 100644 index 0000000..d60848b --- /dev/null +++ b/tall @@ -0,0 +1,4 @@ +eslint.config.ts +src/pages/_app.tsx +src/pages/index.tsx +src/pages/mydashboard/index.tsx diff --git a/tsconfig.json b/tsconfig.json index ce64015..9d36756 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,6 @@ "@/*": ["./src/*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.mjs"], + "include": ["svgr.d.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.mjs"], "exclude": ["node_modules"] }