commit 1c8d5855e609214341163d34989545d23a6b3e34 Author: michael Date: Tue Mar 3 17:59:56 2026 -0800 initial commit diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 0000000..654c6d4 --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets). + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md). diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 0000000..ba0f177 --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.1.3/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/.changeset/initial-release.md b/.changeset/initial-release.md new file mode 100644 index 0000000..430ae2e --- /dev/null +++ b/.changeset/initial-release.md @@ -0,0 +1,11 @@ +--- +"@dangerousthings/tokens": minor +"@dangerousthings/web": minor +"@dangerousthings/react-native": minor +--- + +Initial release of the DT design system monorepo. + +- `@dangerousthings/tokens`: Canonical design tokens for DT, Classic, and Supra brands with CSS generation +- `@dangerousthings/web`: Web CSS theme with bevels, glows, form styles, and Tektur font +- `@dangerousthings/react-native`: 18 React Native themed components (DTButton, DTCard, DTTextInput, etc.) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..678840d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18, 20, 22] + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Build all packages + run: npx turbo run build + + - name: Typecheck + run: npx turbo run typecheck + + publish-check: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + - run: npm ci + - run: npx turbo run build + + - name: Check for changesets + run: npx changeset status diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..68042e6 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,37 @@ +name: Release + +on: + push: + branches: [main] + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + id-token: write + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + registry-url: https://registry.npmjs.org + + - run: npm ci + - run: npx turbo run build + + - name: Create release PR or publish + uses: changesets/action@v1 + with: + publish: npx changeset publish + title: "chore: version packages" + commit: "chore: version packages" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e864920 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Dependencies +node_modules/ + +# Build output +dist/ +*.tsbuildinfo + +# Turbo cache +.turbo/ + +# OS files +.DS_Store +Thumbs.db + +# Editor +.idea/ +.vscode/ +*.swp +*.swo + +# Env +.env +.env.local + +# Logs +*.log +npm-debug.log* diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8499018 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5378 @@ +{ + "name": "dt-design-system", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dt-design-system", + "version": "0.0.0", + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "devDependencies": { + "@changesets/cli": "^2.30.0", + "turbo": "^2.4.0", + "typescript": "^5.7.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "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/@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==", + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "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==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@callstack/react-theme-provider": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@callstack/react-theme-provider/-/react-theme-provider-3.0.9.tgz", + "integrity": "sha512-tTQ0uDSCL0ypeMa8T/E9wAZRGKWj8kXP7+6RYgPTfOPs9N07C9xM8P02GJ3feETap4Ux5S69D9nteq9mEj86NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "deepmerge": "^3.2.0", + "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, + "node_modules/@changesets/apply-release-plan": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.1.0.tgz", + "integrity": "sha512-yq8ML3YS7koKQ/9bk1PqO0HMzApIFNwjlwCnwFEXMzNe8NpzeeYYKCmnhWJGkN8g7E51MnWaSbqRcTcdIxUgnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/config": "^3.1.3", + "@changesets/get-version-range-type": "^0.4.0", + "@changesets/git": "^3.0.4", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/assemble-release-plan": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.9.tgz", + "integrity": "sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/changelog-git": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz", + "integrity": "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0" + } + }, + "node_modules/@changesets/cli": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.30.0.tgz", + "integrity": "sha512-5D3Nk2JPqMI1wK25pEymeWRSlSMdo5QOGlyfrKg0AOufrUcjEE3RQgaCpHoBiM31CSNrtSgdJ0U6zL1rLDDfBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/apply-release-plan": "^7.1.0", + "@changesets/assemble-release-plan": "^6.0.9", + "@changesets/changelog-git": "^0.2.1", + "@changesets/config": "^3.1.3", + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/get-release-plan": "^4.0.15", + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.7", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@changesets/write": "^0.4.0", + "@inquirer/external-editor": "^1.0.2", + "@manypkg/get-packages": "^1.1.3", + "ansi-colors": "^4.1.3", + "enquirer": "^2.4.1", + "fs-extra": "^7.0.1", + "mri": "^1.2.0", + "package-manager-detector": "^0.2.0", + "picocolors": "^1.1.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "spawndamnit": "^3.0.1", + "term-size": "^2.1.0" + }, + "bin": { + "changeset": "bin.js" + } + }, + "node_modules/@changesets/config": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.1.3.tgz", + "integrity": "sha512-vnXjcey8YgBn2L1OPWd3ORs0bGC4LoYcK/ubpgvzNVr53JXV5GiTVj7fWdMRsoKUH7hhhMAQnsJUqLr21EncNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/logger": "^0.1.1", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.8" + } + }, + "node_modules/@changesets/errors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz", + "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==", + "dev": true, + "license": "MIT", + "dependencies": { + "extendable-error": "^0.1.5" + } + }, + "node_modules/@changesets/get-dependents-graph": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.3.tgz", + "integrity": "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "picocolors": "^1.1.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/get-release-plan": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.15.tgz", + "integrity": "sha512-Q04ZaRPuEVZtA+auOYgFaVQQSA98dXiVe/yFaZfY7hoSmQICHGvP0TF4u3EDNHWmmCS4ekA/XSpKlSM2PyTS2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/assemble-release-plan": "^6.0.9", + "@changesets/config": "^3.1.3", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.7", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/get-version-range-type": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz", + "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@changesets/git": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.4.tgz", + "integrity": "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.8", + "spawndamnit": "^3.0.1" + } + }, + "node_modules/@changesets/logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz", + "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.0" + } + }, + "node_modules/@changesets/parse": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.3.tgz", + "integrity": "sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "js-yaml": "^4.1.1" + } + }, + "node_modules/@changesets/parse/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/@changesets/parse/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@changesets/pre": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.2.tgz", + "integrity": "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "node_modules/@changesets/read": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.7.tgz", + "integrity": "sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/parse": "^0.4.3", + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "p-filter": "^2.1.0", + "picocolors": "^1.1.0" + } + }, + "node_modules/@changesets/should-skip-package": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.2.tgz", + "integrity": "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/types": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", + "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@changesets/write": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.4.0.tgz", + "integrity": "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "human-id": "^4.1.1", + "prettier": "^2.7.1" + } + }, + "node_modules/@dangerousthings/react-native": { + "resolved": "packages/react-native", + "link": true + }, + "node_modules/@dangerousthings/tokens": { + "resolved": "packages/tokens", + "link": true + }, + "node_modules/@dangerousthings/web": { + "resolved": "packages/web", + "link": true + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.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==", + "license": "MIT", + "peer": true, + "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==", + "license": "MIT", + "peer": true, + "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==", + "license": "MIT", + "peer": true, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "peer": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@manypkg/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@manypkg/find-root/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@manypkg/find-root/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@manypkg/get-packages": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz", + "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + } + }, + "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz", + "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@manypkg/get-packages/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "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/@react-native/assets-registry": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.84.1.tgz", + "integrity": "sha512-lAJ6PDZv95FdT9s9uhc9ivhikW1Zwh4j9XdXM7J2l4oUA3t37qfoBmTSDLuPyE3Bi+Xtwa11hJm0BUTT2sc/gg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.84.1.tgz", + "integrity": "sha512-n1RIU0QAavgCg1uC5+s53arL7/mpM+16IBhJ3nCFSd/iK5tUmCwxQDcIDC703fuXfpub/ZygeSjVN8bcOWn0gA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.25.3", + "hermes-parser": "0.32.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "tinyglobby": "^0.2.15", + "yargs": "^17.6.2" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.84.1.tgz", + "integrity": "sha512-f6a+mJEJ6Joxlt/050TqYUr7uRRbeKnz8lnpL7JajhpsgZLEbkJRjH8HY5QiLcRdUwWFtizml4V+vcO3P4RxoQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@react-native/dev-middleware": "0.84.1", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.83.3", + "metro-config": "^0.83.3", + "metro-core": "^0.83.3", + "semver": "^7.1.3" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@react-native-community/cli": "*", + "@react-native/metro-config": "*" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + }, + "@react-native/metro-config": { + "optional": true + } + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.84.1.tgz", + "integrity": "sha512-rUU/Pyh3R5zT0WkVgB+yA6VwOp7HM5Hz4NYE97ajFS07OUIcv8JzBL3MXVdSSjLfldfqOuPEuKUaZcAOwPgabw==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/debugger-shell": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.84.1.tgz", + "integrity": "sha512-LIGhh4q4ette3yW5OzmukNMYwmINYrRGDZqKyTYc/VZyNpblZPw72coXVHXdfpPT6+YlxHqXzn3UjFZpNODGCQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.6", + "debug": "^4.4.0", + "fb-dotslash": "0.5.8" + }, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.84.1.tgz", + "integrity": "sha512-Z83ra+Gk6ElAhH3XRrv3vwbwCPTb04sPPlNpotxcFZb5LtRQZwT91ZQEXw3GOJCVIFp9EQ/gj8AQbVvtHKOUlQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.84.1", + "@react-native/debugger-shell": "0.84.1", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.2.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^7.5.10" + }, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.84.1.tgz", + "integrity": "sha512-7uVlPBE3uluRNRX4MW7PUJIO1LDBTpAqStKHU7LHH+GRrdZbHsWtOEAX8PiY4GFfBEvG8hEjiuTOqAxMjV+hDg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.84.1.tgz", + "integrity": "sha512-UsTe2AbUugsfyI7XIHMQq4E7xeC8a6GrYwuK+NohMMMJMxmyM3JkzIk+GB9e2il6ScEQNMJNaj+q+i5za8itxQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.84.1.tgz", + "integrity": "sha512-/UPaQ4jl95soXnLDEJ6Cs6lnRXhwbxtT4KbZz+AFDees7prMV2NOLcHfCnzmTabf5Y3oxENMVBL666n4GMLcTA==", + "license": "MIT", + "peer": true + }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.84.1.tgz", + "integrity": "sha512-sJoDunzhci8ZsqxlUiKoLut4xQeQcmbIgvDHGQKeBz6uEq9HgU+hCWOijMRr6sLP0slQVfBAza34Rq7IbXZZOA==", + "license": "MIT", + "peer": true, + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@types/react": "^19.2.0", + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "license": "MIT", + "peer": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "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==", + "license": "MIT", + "peer": true, + "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==", + "license": "MIT", + "peer": true, + "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==", + "license": "MIT", + "peer": true, + "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==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "25.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", + "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-native": { + "version": "0.72.8", + "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.72.8.tgz", + "integrity": "sha512-St6xA7+EoHN5mEYfdWnfYt0e8u6k2FR0P9s2arYgakQGFgU1f9FlPrIEcj0X24pLCF5c5i3WVuLCUdiCYHmOoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native/virtualized-lists": "^0.72.4", + "@types/react": "*" + } + }, + "node_modules/@types/react-native/node_modules/@react-native/virtualized-lists": { + "version": "0.72.8", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz", + "integrity": "sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "peerDependencies": { + "react-native": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT", + "peer": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "peer": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/anser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", + "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", + "license": "MIT", + "peer": true + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "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", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "peer": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT", + "peer": true + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.32.0.tgz", + "integrity": "sha512-m5HthL++AbyeEA2FcdwOLfVFvWYECOBObLHNqdR8ceY4TsEdn4LdX2oTvbB2QJSSElE2AWA/b2MXZ/PF/CqLZg==", + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-parser": "0.32.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "license": "MIT", + "peer": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT", + "peer": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "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==", + "license": "MIT", + "peer": true + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001776", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz", + "integrity": "sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0", + "peer": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz", + "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT", + "peer": true + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT", + "peer": true + }, + "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==", + "license": "MIT", + "peer": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/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/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz", + "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT", + "peer": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "license": "ISC", + "peer": true + }, + "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==", + "license": "MIT", + "peer": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT", + "peer": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/extendable-error": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz", + "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT", + "peer": true + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-dotslash": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/fb-dotslash/-/fb-dotslash-0.5.8.tgz", + "integrity": "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==", + "license": "(MIT OR Apache-2.0)", + "peer": true, + "bin": { + "dotslash": "bin/dotslash" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT", + "peer": true + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "license": "MIT", + "peer": true + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "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", + "peer": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "peer": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hermes-compiler": { + "version": "250829098.0.9", + "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.9.tgz", + "integrity": "sha512-hZ5O7PDz1vQ99TS7HD3FJ9zVynfU1y+VWId6U1Pldvd8hmAYrNec/XLPYJKD3dLOW6NXak6aAQAuMuSo3ji0tQ==", + "license": "MIT", + "peer": true + }, + "node_modules/hermes-estree": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz", + "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "license": "MIT", + "peer": true + }, + "node_modules/hermes-parser": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz", + "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-estree": "0.32.0" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-id": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.3.tgz", + "integrity": "sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==", + "dev": true, + "license": "MIT", + "bin": { + "human-id": "dist/cli.js" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", + "license": "MIT", + "peer": true, + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "peer": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC", + "peer": true + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "dev": true, + "license": "MIT" + }, + "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==", + "license": "MIT", + "peer": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-subdir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz", + "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "better-path-resolve": "1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "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==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", + "license": "0BSD", + "peer": true + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "peer": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT", + "peer": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT", + "peer": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "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==", + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marky": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "license": "MIT", + "peer": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT", + "peer": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/metro": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.5.tgz", + "integrity": "sha512-BgsXevY1MBac/3ZYv/RfNFf/4iuW9X7f4H8ZNkiH+r667HD9sVujxcmu4jvEzGCAm4/WyKdZCuyhAcyhTHOucQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "accepts": "^2.0.0", + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.33.3", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.83.5", + "metro-cache": "0.83.5", + "metro-cache-key": "0.83.5", + "metro-config": "0.83.5", + "metro-core": "0.83.5", + "metro-file-map": "0.83.5", + "metro-resolver": "0.83.5", + "metro-runtime": "0.83.5", + "metro-source-map": "0.83.5", + "metro-symbolicate": "0.83.5", + "metro-transform-plugins": "0.83.5", + "metro-transform-worker": "0.83.5", + "mime-types": "^3.0.1", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-babel-transformer": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.5.tgz", + "integrity": "sha512-d9FfmgUEVejTiSb7bkQeLRGl6aeno2UpuPm3bo3rCYwxewj03ymvOn8s8vnS4fBqAPQ+cE9iQM40wh7nGXR+eA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.33.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", + "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", + "license": "MIT", + "peer": true + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", + "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-estree": "0.33.3" + } + }, + "node_modules/metro-cache": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.5.tgz", + "integrity": "sha512-oH+s4U+IfZyg8J42bne2Skc90rcuESIYf86dYittcdWQtPfcaFXWpByPyTuWk3rR1Zz3Eh5HOrcVImfEhhJLng==", + "license": "MIT", + "peer": true, + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.83.5" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-cache-key": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.5.tgz", + "integrity": "sha512-Ycl8PBajB7bhbAI7Rt0xEyiF8oJ0RWX8EKkolV1KfCUlC++V/GStMSGpPLwnnBZXZWkCC5edBPzv1Hz1Yi0Euw==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-config": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.5.tgz", + "integrity": "sha512-JQ/PAASXH7yczgV6OCUSRhZYME+NU8NYjI2RcaG5ga4QfQ3T/XdiLzpSb3awWZYlDCcQb36l4Vl7i0Zw7/Tf9w==", + "license": "MIT", + "peer": true, + "dependencies": { + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.83.5", + "metro-cache": "0.83.5", + "metro-core": "0.83.5", + "metro-runtime": "0.83.5", + "yaml": "^2.6.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-core": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.5.tgz", + "integrity": "sha512-YcVcLCrf0ed4mdLa82Qob0VxYqfhmlRxUS8+TO4gosZo/gLwSvtdeOjc/Vt0pe/lvMNrBap9LlmvZM8FIsMgJQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.83.5" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-file-map": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.5.tgz", + "integrity": "sha512-ZEt8s3a1cnYbn40nyCD+CsZdYSlwtFh2kFym4lo+uvfM+UMMH+r/BsrC6rbNClSrt+B7rU9T+Te/sh/NL8ZZKQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-minify-terser": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.5.tgz", + "integrity": "sha512-Toe4Md1wS1PBqbvB0cFxBzKEVyyuYTUb0sgifAZh/mSvLH84qA1NAWik9sISWatzvfWf3rOGoUoO5E3f193a3Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-resolver": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.5.tgz", + "integrity": "sha512-7p3GtzVUpbAweJeCcUJihJeOQl1bDuimO5ueo1K0BUpUtR41q5EilbQ3klt16UTPPMpA+tISWBtsrqU556mY1A==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-runtime": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.5.tgz", + "integrity": "sha512-f+b3ue9AWTVlZe2Xrki6TAoFtKIqw30jwfk7GQ1rDUBQaE0ZQ+NkiMEtb9uwH7uAjJ87U7Tdx1Jg1OJqUfEVlA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-source-map": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.5.tgz", + "integrity": "sha512-VT9bb2KO2/4tWY9Z2yeZqTUao7CicKAOps9LUg2aQzsz+04QyuXL3qgf1cLUVRjA/D6G5u1RJAlN1w9VNHtODQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.83.5", + "nullthrows": "^1.1.1", + "ob1": "0.83.5", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-symbolicate": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.5.tgz", + "integrity": "sha512-EMIkrjNRz/hF+p0RDdxoE60+dkaTLPN3vaaGkFmX5lvFdO6HPfHA/Ywznzkev+za0VhPQ5KSdz49/MALBRteHA==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.83.5", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-transform-plugins": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.5.tgz", + "integrity": "sha512-KxYKzZL+lt3Os5H2nx7YkbkWVduLZL5kPrE/Yq+Prm/DE1VLhpfnO6HtPs8vimYFKOa58ncl60GpoX0h7Wm0Vw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-transform-worker": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.5.tgz", + "integrity": "sha512-8N4pjkNXc6ytlP9oAM6MwqkvUepNSW39LKYl9NjUMpRDazBQ7oBpQDc8Sz4aI8jnH6AGhF7s1m/ayxkN1t04yA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "metro": "0.83.5", + "metro-babel-transformer": "0.83.5", + "metro-cache": "0.83.5", + "metro-cache-key": "0.83.5", + "metro-minify-terser": "0.83.5", + "metro-source-map": "0.83.5", + "metro-transform-plugins": "0.83.5", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT", + "peer": true + }, + "node_modules/metro/node_modules/hermes-estree": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", + "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", + "license": "MIT", + "peer": true + }, + "node_modules/metro/node_modules/hermes-parser": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", + "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-estree": "0.33.3" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "peer": true + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT", + "peer": true + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "license": "MIT", + "peer": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "license": "MIT" + }, + "node_modules/ob1": { + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.5.tgz", + "integrity": "sha512-vNKPYC8L5ycVANANpF/S+WZHpfnRWKx/F3AYP4QMn6ZJTh+l2HOrId0clNkEmua58NB9vmI9Qh7YOoV/4folYg==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "peer": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/outdent": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", + "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-manager-detector": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz", + "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^0.2.7" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.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==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "license": "MIT", + "peer": true, + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-devtools-core": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.5.tgz", + "integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==", + "license": "MIT", + "peer": true, + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT", + "peer": true + }, + "node_modules/react-native": { + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.84.1.tgz", + "integrity": "sha512-0PjxOyXRu3tZ8EobabxSukvhKje2HJbsZikR0U+pvS0pYZza2hXKjcSBiBdFN4h9D0S3v6a8kkrDK6WTRKMwzg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/create-cache-key-function": "^29.7.0", + "@react-native/assets-registry": "0.84.1", + "@react-native/codegen": "0.84.1", + "@react-native/community-cli-plugin": "0.84.1", + "@react-native/gradle-plugin": "0.84.1", + "@react-native/js-polyfills": "0.84.1", + "@react-native/normalize-colors": "0.84.1", + "@react-native/virtualized-lists": "0.84.1", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "babel-jest": "^29.7.0", + "babel-plugin-syntax-hermes-parser": "0.32.0", + "base64-js": "^1.5.1", + "commander": "^12.0.0", + "flow-enums-runtime": "^0.0.6", + "hermes-compiler": "250829098.0.9", + "invariant": "^2.2.4", + "jest-environment-node": "^29.7.0", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.83.3", + "metro-source-map": "^0.83.3", + "nullthrows": "^1.1.1", + "pretty-format": "^29.7.0", + "promise": "^8.3.0", + "react-devtools-core": "^6.1.5", + "react-refresh": "^0.14.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.27.0", + "semver": "^7.1.3", + "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.15", + "whatwg-fetch": "^3.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@types/react": "^19.1.1", + "react": "^19.2.3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-native-paper": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.15.0.tgz", + "integrity": "sha512-I/1CQLfW9VM0Oo5I5dQI/hjgf1I6q2S1wwgzAdsv6whAQ3zO97GWHwtgNh9se9j8zBOJ86afPTQKxxUL0IJd9A==", + "dev": true, + "license": "MIT", + "workspaces": [ + "example", + "docs" + ], + "dependencies": { + "@callstack/react-theme-provider": "^3.0.9", + "color": "^3.1.2", + "use-latest-callback": "^0.2.3" + }, + "peerDependencies": { + "react": "*", + "react-native": "*", + "react-native-safe-area-context": "*" + } + }, + "node_modules/react-native-safe-area-context": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.7.0.tgz", + "integrity": "sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-svg": { + "version": "15.15.3", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.15.3.tgz", + "integrity": "sha512-/k4KYwPBLGcx2f5d4FjE+vCScK7QOX14cl2lIASJ28u4slHHtIhL0SZKU7u9qmRBHxTCKPoPBtN6haT1NENJNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^5.1.0", + "css-tree": "^1.1.3", + "warn-once": "0.1.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-yaml-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz", + "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.6.1", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT", + "peer": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT", + "peer": true + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT", + "peer": true + }, + "node_modules/send/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "peer": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "peer": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC", + "peer": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", + "peer": true + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "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==", + "license": "MIT", + "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==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawndamnit": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-3.0.1.tgz", + "integrity": "sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==", + "dev": true, + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "cross-spawn": "^7.0.5", + "signal-exit": "^4.0.1" + } + }, + "node_modules/spawndamnit/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/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT", + "peer": true + }, + "node_modules/stacktrace-parser": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", + "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", + "license": "MIT", + "peer": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.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==", + "license": "MIT", + "peer": true + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "license": "ISC", + "peer": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "license": "MIT", + "peer": true + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/turbo": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/turbo/-/turbo-2.8.13.tgz", + "integrity": "sha512-nyM99hwFB9/DHaFyKEqatdayGjsMNYsQ/XBNO6MITc7roncZetKb97MpHxWf3uiU+LB9c9HUlU3Jp2Ixei2k1A==", + "dev": true, + "license": "MIT", + "bin": { + "turbo": "bin/turbo" + }, + "optionalDependencies": { + "turbo-darwin-64": "2.8.13", + "turbo-darwin-arm64": "2.8.13", + "turbo-linux-64": "2.8.13", + "turbo-linux-arm64": "2.8.13", + "turbo-windows-64": "2.8.13", + "turbo-windows-arm64": "2.8.13" + } + }, + "node_modules/turbo-darwin-64": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-2.8.13.tgz", + "integrity": "sha512-PmOvodQNiOj77+Zwoqku70vwVjKzL34RTNxxoARjp5RU5FOj/CGiC6vcDQhNtFPUOWSAaogHF5qIka9TBhX4XA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/turbo-darwin-arm64": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-2.8.13.tgz", + "integrity": "sha512-kI+anKcLIM4L8h+NsM7mtAUpElkCOxv5LgiQVQR8BASyDFfc8Efj5kCk3cqxuxOvIqx0sLfCX7atrHQ2kwuNJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/turbo-linux-64": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-2.8.13.tgz", + "integrity": "sha512-j29KnQhHyzdzgCykBFeBqUPS4Wj7lWMnZ8CHqytlYDap4Jy70l4RNG46pOL9+lGu6DepK2s1rE86zQfo0IOdPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/turbo-linux-arm64": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-2.8.13.tgz", + "integrity": "sha512-OEl1YocXGZDRDh28doOUn49QwNe82kXljO1HXApjU0LapkDiGpfl3jkAlPKxEkGDSYWc8MH5Ll8S16Rf5tEBYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/turbo-windows-64": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-2.8.13.tgz", + "integrity": "sha512-717bVk1+Pn2Jody7OmWludhEirEe0okoj1NpRbSm5kVZz/yNN/jfjbxWC6ilimXMz7xoMT3IDfQFJsFR3PMANA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/turbo-windows-arm64": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-2.8.13.tgz", + "integrity": "sha512-R819HShLIT0Wj6zWVnIsYvSNtRNj1q9VIyaUz0P24SMcLCbQZIm1sV09F4SDbg+KCCumqD2lcaR2UViQ8SnUJA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-latest-callback": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.6.tgz", + "integrity": "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", + "license": "MIT", + "peer": true + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/warn-once": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz", + "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT", + "peer": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/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==", + "license": "MIT", + "peer": true, + "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/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", + "peer": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "license": "ISC", + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC", + "peer": true + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "license": "ISC", + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "peer": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/react-native": { + "name": "@dangerousthings/react-native", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@dangerousthings/tokens": "*" + }, + "devDependencies": { + "@types/react": "^19.2.14", + "@types/react-native": "^0.72.8", + "react-native-paper": "^5.15.0", + "react-native-safe-area-context": "^5.7.0", + "react-native-svg": "^15.15.3", + "typescript": "^5.9.3" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-native": ">=0.72.0", + "react-native-paper": ">=5.0.0", + "react-native-safe-area-context": ">=4.0.0", + "react-native-svg": ">=13.0.0" + }, + "peerDependenciesMeta": { + "expo-font": { + "optional": true + } + } + }, + "packages/tokens": { + "name": "@dangerousthings/tokens", + "version": "0.1.0", + "license": "MIT", + "devDependencies": { + "@types/node": "^25.3.3", + "typescript": "^5.7.0" + } + }, + "packages/web": { + "name": "@dangerousthings/web", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@dangerousthings/tokens": "*" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9bc52f0 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "dt-design-system", + "version": "0.0.0", + "private": true, + "description": "Dangerous Things design system — shared tokens, web CSS, and React Native components", + "repository": { + "type": "git", + "url": "https://github.com/dangerous-tac0s/dt-design-system" + }, + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "scripts": { + "build": "turbo run build", + "build:tokens": "npm run build -w packages/tokens", + "build:web": "npm run build -w packages/web", + "build:react-native": "npm run build -w packages/react-native", + "clean": "turbo run clean", + "typecheck": "turbo run typecheck", + "lint": "turbo run lint", + "changeset": "changeset", + "version-packages": "changeset version", + "release": "turbo run build && changeset publish" + }, + "devDependencies": { + "@changesets/cli": "^2.30.0", + "turbo": "^2.4.0", + "typescript": "^5.7.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "packageManager": "npm@10.0.0" +} diff --git a/packages/react-native/package.json b/packages/react-native/package.json new file mode 100644 index 0000000..de0164e --- /dev/null +++ b/packages/react-native/package.json @@ -0,0 +1,49 @@ +{ + "name": "@dangerousthings/react-native", + "version": "0.1.0", + "description": "React Native themed components for the Dangerous Things design system", + "license": "MIT", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsc", + "clean": "rm -rf dist", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@dangerousthings/tokens": "*" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-native": ">=0.72.0", + "react-native-paper": ">=5.0.0", + "react-native-safe-area-context": ">=4.0.0", + "react-native-svg": ">=13.0.0" + }, + "peerDependenciesMeta": { + "expo-font": { + "optional": true + } + }, + "devDependencies": { + "@types/react": "^19.2.14", + "@types/react-native": "^0.72.8", + "react-native-paper": "^5.15.0", + "react-native-safe-area-context": "^5.7.0", + "react-native-svg": "^15.15.3", + "typescript": "^5.9.3" + } +} diff --git a/packages/react-native/src/components/DTAccordion.tsx b/packages/react-native/src/components/DTAccordion.tsx new file mode 100644 index 0000000..75d64e6 --- /dev/null +++ b/packages/react-native/src/components/DTAccordion.tsx @@ -0,0 +1,276 @@ +/** + * DT Accordion Component + * + * Custom-built accordion with animated height expansion following + * the Dangerous Things angular aesthetic. + * + * Web CSS reference (FilterAccordion): + * - menu-item-clipped style headers with thick top border + * - Expand/collapse with height animation + * - Active sections switch to activeVariant color + */ + +import {useState, useCallback, useRef, useEffect} from 'react'; +import { + StyleSheet, + View, + ViewStyle, + StyleProp, + Pressable, + Animated, +} from 'react-native'; +import {Text} from 'react-native-paper'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; + +export interface DTAccordionSection { + /** + * Unique key for the section + */ + key: string; + /** + * Section header title + */ + title: string; + /** + * Section content (rendered when expanded) + */ + children: React.ReactNode; +} + +interface DTAccordionProps { + /** + * Array of accordion sections + */ + sections: DTAccordionSection[]; + /** + * Visual variant for section headers + * @default 'normal' + */ + variant?: DTVariant; + /** + * Variant color for active/expanded sections + * @default 'emphasis' + */ + activeVariant?: DTVariant; + /** + * Allow multiple sections open simultaneously + * @default false + */ + allowMultiple?: boolean; + /** + * Section keys to open initially + */ + initialOpenKeys?: string[]; + /** + * Called when a section is toggled + */ + onSectionToggle?: (key: string, isOpen: boolean) => void; + /** + * Additional styles + */ + style?: StyleProp; +} + +/** + * DT-styled Accordion with animated height expansion + * + * @example + * }, + * { key: 'color', title: 'Color', children: }, + * ]} + * variant="normal" + * /> + */ +export function DTAccordion({ + sections, + variant = 'normal', + activeVariant = 'emphasis', + allowMultiple = false, + initialOpenKeys, + onSectionToggle, + style, +}: DTAccordionProps) { + const [openKeys, setOpenKeys] = useState>( + new Set(initialOpenKeys), + ); + + const toggleSection = useCallback( + (key: string) => { + setOpenKeys(prev => { + const next = new Set(allowMultiple ? prev : []); + const isOpening = !prev.has(key); + if (isOpening) { + next.add(key); + } else { + next.delete(key); + } + onSectionToggle?.(key, isOpening); + return next; + }); + }, + [allowMultiple, onSectionToggle], + ); + + const inactiveColor = getVariantColor(variant); + const activeColor = getVariantColor(activeVariant); + + return ( + + {sections.map(section => ( + toggleSection(section.key)} + inactiveColor={inactiveColor} + activeColor={activeColor} + /> + ))} + + ); +} + +function AccordionSection({ + section, + isOpen, + onToggle, + inactiveColor, + activeColor, +}: { + section: DTAccordionSection; + isOpen: boolean; + onToggle: () => void; + inactiveColor: string; + activeColor: string; +}) { + const heightAnim = useRef(new Animated.Value(isOpen ? 1 : 0)).current; + const chevronAnim = useRef(new Animated.Value(isOpen ? 1 : 0)).current; + const [contentHeight, setContentHeight] = useState(0); + const [measured, setMeasured] = useState(false); + const sectionColor = isOpen ? activeColor : inactiveColor; + + useEffect(() => { + Animated.parallel([ + Animated.timing(heightAnim, { + toValue: isOpen ? 1 : 0, + duration: 250, + useNativeDriver: false, + }), + Animated.timing(chevronAnim, { + toValue: isOpen ? 1 : 0, + duration: 250, + useNativeDriver: true, + }), + ]).start(); + }, [isOpen, heightAnim, chevronAnim]); + + const animatedHeight = heightAnim.interpolate({ + inputRange: [0, 1], + outputRange: [0, contentHeight], + }); + + const chevronRotate = chevronAnim.interpolate({ + inputRange: [0, 1], + outputRange: ['0deg', '180deg'], + }); + + return ( + + {/* Header */} + [ + styles.header, + { + borderColor: sectionColor, + borderTopColor: sectionColor, + opacity: pressed ? 0.7 : 1, + }, + ]}> + + {section.title} + + + + + + + {/* Animated content */} + + { + const h = e.nativeEvent.layout.height; + if (h > 0 && !measured) { + setContentHeight(h); + setMeasured(true); + if (!isOpen) { + heightAnim.setValue(0); + } + } + }}> + {section.children} + + + + ); +} + +const styles = StyleSheet.create({ + container: { + gap: 4, + }, + header: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + backgroundColor: DTColors.dark, + borderWidth: 1, + borderTopWidth: 5, + paddingVertical: 12, + paddingHorizontal: 16, + }, + title: { + fontWeight: '600', + letterSpacing: 0.5, + textTransform: 'uppercase', + fontSize: 14, + }, + contentWrapper: {}, + content: { + paddingHorizontal: 16, + paddingVertical: 12, + backgroundColor: DTColors.dark, + }, + chevron: { + justifyContent: 'center', + alignItems: 'center', + width: 24, + height: 24, + }, + chevronArrow: { + width: 0, + height: 0, + borderLeftWidth: 6, + borderRightWidth: 6, + borderTopWidth: 8, + borderLeftColor: 'transparent', + borderRightColor: 'transparent', + }, +}); diff --git a/packages/react-native/src/components/DTButton.tsx b/packages/react-native/src/components/DTButton.tsx new file mode 100644 index 0000000..5676549 --- /dev/null +++ b/packages/react-native/src/components/DTButton.tsx @@ -0,0 +1,151 @@ +/** + * DT Button Component + * + * A themed button following the Dangerous Things design language + * with SVG-based beveled corners. + */ + +import {StyleSheet, View, ViewStyle, StyleProp, Pressable} from 'react-native'; +import {Text} from 'react-native-paper'; +import Svg, {Path} from 'react-native-svg'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; +import {buildButtonBevelPath} from '../utils/bevelPaths'; +import {useComponentLayout} from '../utils/useComponentLayout'; +import {useState} from 'react'; + +interface DTButtonProps { + /** + * Button content/label + */ + children: React.ReactNode; + /** + * Visual variant of the button + * @default 'normal' + */ + variant?: DTVariant; + /** + * Button display mode + * - 'outlined': Border with transparent background (default) + * - 'contained': Filled background + * @default 'outlined' + */ + mode?: 'outlined' | 'contained'; + /** + * Custom color (overrides variant) + */ + color?: string; + /** + * Press handler + */ + onPress?: () => void; + /** + * Whether button is disabled + */ + disabled?: boolean; + /** + * Additional styles for container + */ + style?: StyleProp; + /** + * Border width + * @default 2 + */ + borderWidth?: number; + /** + * Bevel size in pixels + * @default 8 + */ + bevelSize?: number; +} + +/** + * DT-styled Button component with SVG beveled corners + * + * @example + * + * Scan NFC Tag + * + * + * @example + * + * View Results + * + */ +export function DTButton({ + children, + variant = 'normal', + mode = 'outlined', + color, + onPress, + disabled = false, + style, + borderWidth = 2, + bevelSize = 8, +}: DTButtonProps) { + const {dimensions, onLayout, hasDimensions} = useComponentLayout(); + const [pressed, setPressed] = useState(false); + + const accentColor = getVariantColor(variant, color); + const isContained = mode === 'contained'; + const bgColor = isContained ? accentColor : 'transparent'; + const textColor = isContained ? DTColors.dark : accentColor; + + const {width, height} = dimensions; + const opacity = disabled ? 0.5 : pressed ? 0.7 : 1; + + return ( + setPressed(true)} + onPressOut={() => setPressed(false)} + style={[{opacity}, style]}> + + {hasDimensions && ( + + + + )} + + {typeof children === 'string' ? ( + + {children} + + ) : ( + children + )} + + + + ); +} + +const styles = StyleSheet.create({ + container: { + position: 'relative', + minHeight: 44, + }, + content: { + position: 'relative', + zIndex: 1, + paddingVertical: 12, + paddingHorizontal: 24, + alignItems: 'center', + justifyContent: 'center', + }, + label: { + fontWeight: '600', + letterSpacing: 1, + textTransform: 'uppercase', + }, +}); diff --git a/packages/react-native/src/components/DTCard.tsx b/packages/react-native/src/components/DTCard.tsx new file mode 100644 index 0000000..246bd71 --- /dev/null +++ b/packages/react-native/src/components/DTCard.tsx @@ -0,0 +1,221 @@ +/** + * DT Card Component + * + * A themed card following the Dangerous Things design language + * with SVG-based beveled corners matching the web storefront style. + * + * Web CSS reference: + * - Bottom-right bevel: 2em (~32px) + * - Bottom-left bevel: 1em (~16px) + * - Border width: 0.2em (~3px) + */ + +import {ReactNode} from 'react'; +import {StyleSheet, View, ViewStyle, StyleProp, Pressable} from 'react-native'; +import {Text} from 'react-native-paper'; +import Svg, {Path} from 'react-native-svg'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; +import {buildCardBevelPath} from '../utils/bevelPaths'; +import {useComponentLayout} from '../utils/useComponentLayout'; + +interface DTCardProps { + children: ReactNode; + /** + * Color mode for the card accent + * @default 'normal' + */ + mode?: DTVariant; + /** + * Custom border color (overrides mode) + */ + borderColor?: string; + /** + * Card title (displayed in header) + */ + title?: string; + /** + * Whether to show the accent header bar + * @default true when title is provided + */ + showHeader?: boolean; + /** + * Additional styles for the card container + */ + style?: StyleProp; + /** + * Additional styles for the content area + */ + contentStyle?: StyleProp; + /** + * Inner content padding + * @default 16 + */ + padding?: number; + /** + * Border width in pixels + * @default 3 + */ + borderWidth?: number; + /** + * Bottom-right bevel size in pixels + * @default 32 + */ + bevelSize?: number; + /** + * Bottom-left bevel size in pixels (smaller accent bevel) + * @default 16 + */ + bevelSizeSmall?: number; + /** + * Background color + * @default '#000000' + */ + backgroundColor?: string; + /** + * Press handler + */ + onPress?: () => void; +} + +/** + * DT-styled Card component with SVG beveled corners + * + * @example + * + * NTAG215 + * + * + * @example + * + * Tap to scan + * + */ +export function DTCard({ + children, + mode = 'normal', + borderColor, + title, + showHeader, + style, + contentStyle, + padding = 16, + borderWidth = 3, + bevelSize = 32, + bevelSizeSmall = 16, + backgroundColor = '#000000', + onPress, +}: DTCardProps) { + const {dimensions, onLayout, hasDimensions} = useComponentLayout(); + const accentColor = getVariantColor(mode, borderColor); + const shouldShowHeader = showHeader ?? !!title; + + const {width, height} = dimensions; + + // Outer bevel path (full card shape) + const outerPath = hasDimensions + ? buildCardBevelPath(width, height, bevelSize, bevelSizeSmall, 0) + : ''; + // Inner bevel path at border inset (for background + frame cutout) + const innerPath = hasDimensions + ? buildCardBevelPath(width, height, bevelSize - borderWidth, bevelSizeSmall - borderWidth, borderWidth) + : ''; + + const content = ( + + {/* Background fill (behind content) */} + {hasDimensions && ( + + + + )} + + {shouldShowHeader && ( + + {title && ( + + {title} + + )} + + )} + {children} + + {/* Frame overlay (above content) — clips content at beveled border */} + {hasDimensions && ( + + + + )} + + ); + + if (onPress) { + return ( + ({opacity: pressed ? 0.8 : 1})}> + {content} + + ); + } + + return content; +} + +/** + * DT design system constants matching web CSS variables + */ +export const DTCardClipPath = { + // CSS-style clip path (for web reference) + css: `polygon( + 0% 0%, + 100% 0%, + 100% calc(100% - 2em), + calc(100% - 2em) 100%, + 1em 100%, + 0% calc(100% - 1em) + )`, + // Default bevel sizes in pixels (matching 2em and 1em at 16px base) + bevelSize: 32, + bevelSizeSmall: 16, + borderWidth: 3, +}; + +const styles = StyleSheet.create({ + container: { + position: 'relative', + }, + innerContainer: { + position: 'relative', + zIndex: 1, + overflow: 'hidden', + }, + header: { + paddingHorizontal: 16, + paddingVertical: 12, + }, + headerText: { + fontWeight: '700', + letterSpacing: 0.5, + }, + content: {}, + frameOverlay: { + zIndex: 2, + }, +}); diff --git a/packages/react-native/src/components/DTCheckbox.tsx b/packages/react-native/src/components/DTCheckbox.tsx new file mode 100644 index 0000000..b7815d0 --- /dev/null +++ b/packages/react-native/src/components/DTCheckbox.tsx @@ -0,0 +1,140 @@ +/** + * DT Checkbox Component + * + * Custom-built angular checkbox following the Dangerous Things design language. + * Uses SVG for beveled shape and checkmark — RNP Checkbox enforces + * rounded corners (borderRadius: 18) so we build from scratch. + * + * Uses diagonal-symmetry bevels (top-left + bottom-right) on the indicator. + */ + +import {StyleSheet, ViewStyle, TextStyle, StyleProp, Pressable} from 'react-native'; +import {Text} from 'react-native-paper'; +import Svg, {Path} from 'react-native-svg'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; +import {buildBeveledRectPath} from '../utils/bevelPaths'; + +interface DTCheckboxProps { + /** + * Whether the checkbox is checked + */ + checked: boolean; + /** + * Press handler to toggle state + */ + onPress: () => void; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Label text displayed beside the checkbox + */ + label?: string; + /** + * Whether the checkbox is disabled + */ + disabled?: boolean; + /** + * Size of the checkbox in pixels + * @default 24 + */ + size?: number; + /** + * Custom color (overrides variant) + */ + color?: string; + /** + * Additional styles for the container + */ + style?: StyleProp; + /** + * Additional styles for the label text + */ + labelStyle?: StyleProp; +} + +/** + * DT-styled Checkbox with beveled opposing corners (top-left + bottom-right) + * + * @example + * setChecked(!isChecked)} label="Remember me" /> + * + * @example + * + */ +export function DTCheckbox({ + checked, + onPress, + variant = 'normal', + label, + disabled = false, + size = 24, + color, + style, + labelStyle, +}: DTCheckboxProps) { + const accentColor = getVariantColor(variant, color); + const opacity = disabled ? 0.5 : 1; + const borderWidth = 2; + const bevelSize = Math.round(size * 0.3); + + // Outer beveled path (border) + const outerPath = buildBeveledRectPath(size, size, { + corners: {topLeft: bevelSize, bottomRight: bevelSize}, + strokeWidth: borderWidth, + }); + + return ( + [ + styles.container, + {opacity: pressed ? 0.7 : opacity}, + style, + ]}> + + {/* Beveled border */} + + {/* Checkmark path (only when checked) */} + {checked && ( + + )} + + {label && ( + + {label} + + )} + + ); +} + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + alignItems: 'center', + gap: 12, + minHeight: 44, + paddingVertical: 8, + }, + label: { + fontSize: 14, + letterSpacing: 0.3, + }, +}); diff --git a/packages/react-native/src/components/DTChip.tsx b/packages/react-native/src/components/DTChip.tsx new file mode 100644 index 0000000..02eac8b --- /dev/null +++ b/packages/react-native/src/components/DTChip.tsx @@ -0,0 +1,95 @@ +/** + * DT Chip Component + * + * A themed chip/tag following the Dangerous Things design language. + * Useful for displaying chip types, statuses, and labels. + */ + +// React import not needed with new JSX transform +import { StyleSheet, ViewStyle, StyleProp } from 'react-native'; +import { Chip, ChipProps } from 'react-native-paper'; +import { DTColors } from '../theme/colors'; + +type DTChipVariant = 'normal' | 'emphasis' | 'warning' | 'success' | 'other'; + +interface DTChipProps extends Omit { + /** + * Visual variant of the chip + * @default 'normal' + */ + variant?: DTChipVariant; + /** + * Whether the chip is in selected state + * @default false + */ + selected?: boolean; + /** + * Additional styles + */ + style?: StyleProp; +} + +const variantColors: Record = { + normal: DTColors.modeNormal, + emphasis: DTColors.modeEmphasis, + warning: DTColors.modeWarning, + success: DTColors.modeSuccess, + other: DTColors.modeOther, +}; + +/** + * DT-styled Chip component + * + * @example + * NTAG215 + * + * @example + * Cloneable + * + * @example + * Non-Cloneable + */ +export function DTChip({ + variant = 'normal', + selected = false, + style, + children, + ...props +}: DTChipProps) { + const color = variantColors[variant]; + + const chipStyle: ViewStyle = { + backgroundColor: selected ? color : 'transparent', + borderColor: color, + borderWidth: 1, + borderRadius: 0, // Angular DT style + }; + + return ( + + {children} + + ); +} + +const styles = StyleSheet.create({ + chip: { + marginRight: 8, + marginBottom: 8, + }, + text: { + fontWeight: '600', + letterSpacing: 0.5, + fontSize: 12, + }, +}); diff --git a/packages/react-native/src/components/DTDrawer.tsx b/packages/react-native/src/components/DTDrawer.tsx new file mode 100644 index 0000000..8fcc205 --- /dev/null +++ b/packages/react-native/src/components/DTDrawer.tsx @@ -0,0 +1,279 @@ +/** + * DT Drawer Component + * + * Hybrid component: RNP Portal for layering + custom Animated panel + * for the sliding behavior. RNP has no sliding panel component. + * + * Uses the dual-SVG-path technique (outer border fill + inner dark fill) + * consistent with DTCard/DTMediaFrame for proper visual clipping at + * beveled corners. + * + * Web CSS reference (Aside.tsx): + * - Fixed sidebar sliding from right + * - Beveled left edges (top-left + bottom-left for right drawer) + * - Colored header bar + * - Overlay backdrop + * - transition: transform 200ms ease-in-out + */ + +import {useRef, useEffect} from 'react'; +import { + StyleSheet, + View, + ViewStyle, + StyleProp, + Pressable, + Animated, + BackHandler, + ScrollView, + useWindowDimensions, +} from 'react-native'; +import {Portal, Text} from 'react-native-paper'; +import Svg, {Path} from 'react-native-svg'; +import {useSafeAreaInsets} from 'react-native-safe-area-context'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; +import {buildDrawerBevelPath} from '../utils/bevelPaths'; + +interface DTDrawerProps { + /** + * Whether the drawer is visible + */ + visible: boolean; + /** + * Called when the drawer is dismissed + */ + onDismiss: () => void; + /** + * Heading text in the drawer header bar + */ + heading: string; + /** + * Visual variant for the header bar + * @default 'emphasis' + */ + headingVariant?: DTVariant; + /** + * Which side the drawer slides from + * @default 'right' + */ + position?: 'right' | 'left'; + /** + * Drawer panel width in pixels + * @default 400 + */ + width?: number; + /** + * Bevel size in pixels + * @default 32 + */ + bevelSize?: number; + /** + * Border width in pixels + * @default 2 + */ + borderWidth?: number; + /** + * Drawer content + */ + children: React.ReactNode; + /** + * Additional styles + */ + style?: StyleProp; +} + +/** + * DT-styled Drawer/Aside with beveled edges and slide animation + * + * @example + * setCartOpen(false)} heading="Cart"> + * + * + * + * @example + * + * + * + */ +export function DTDrawer({ + visible, + onDismiss, + heading, + headingVariant = 'emphasis', + position = 'right', + width: drawerWidth = 400, + bevelSize = 32, + borderWidth = 2, + children, + style, +}: DTDrawerProps) { + const slideAnim = useRef(new Animated.Value(0)).current; + const overlayAnim = useRef(new Animated.Value(0)).current; + const headerColor = getVariantColor(headingVariant); + const {width: screenWidth, height: screenHeight} = useWindowDimensions(); + const insets = useSafeAreaInsets(); + const effectiveWidth = Math.min(drawerWidth, screenWidth); + + useEffect(() => { + if (visible) { + Animated.parallel([ + Animated.timing(slideAnim, { + toValue: 1, + duration: 200, + useNativeDriver: true, + }), + Animated.timing(overlayAnim, { + toValue: 1, + duration: 200, + useNativeDriver: true, + }), + ]).start(); + } else { + Animated.parallel([ + Animated.timing(slideAnim, { + toValue: 0, + duration: 200, + useNativeDriver: true, + }), + Animated.timing(overlayAnim, { + toValue: 0, + duration: 200, + useNativeDriver: true, + }), + ]).start(); + } + }, [visible, slideAnim, overlayAnim]); + + // Android back button handling + useEffect(() => { + if (!visible) return; + const handler = BackHandler.addEventListener('hardwareBackPress', () => { + onDismiss(); + return true; + }); + return () => handler.remove(); + }, [visible, onDismiss]); + + const translateX = slideAnim.interpolate({ + inputRange: [0, 1], + outputRange: [ + position === 'right' ? effectiveWidth : -effectiveWidth, + 0, + ], + }); + + // Don't render when fully hidden + const pointerEvents = visible ? 'auto' : 'none'; + + return ( + + + {/* Overlay backdrop */} + + + + + {/* Drawer panel */} + + {/* Dual-SVG-path technique: outer border + inner dark fill */} + + + {/* Outer path: accent border color */} + + {/* Inner path: dark background (inset by borderWidth) */} + + + + + {/* Header bar */} + + {heading} + ({opacity: pressed ? 0.7 : 1})}> + + + + + {/* Content */} + + {children} + + + + + ); +} + +const styles = StyleSheet.create({ + overlay: { + backgroundColor: DTColors.overlay, + }, + panel: { + position: 'absolute', + top: 0, + bottom: 0, + }, + panelRight: { + right: 0, + }, + panelLeft: { + left: 0, + }, + header: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingHorizontal: 16, + paddingVertical: 16, + zIndex: 1, + }, + headerText: { + color: DTColors.dark, + fontWeight: '700', + fontSize: 18, + letterSpacing: 0.5, + }, + closeButton: { + color: DTColors.dark, + fontSize: 20, + fontWeight: '700', + paddingHorizontal: 8, + }, + content: { + flex: 1, + zIndex: 1, + }, + contentContainer: { + padding: 16, + }, +}); diff --git a/packages/react-native/src/components/DTGallery.tsx b/packages/react-native/src/components/DTGallery.tsx new file mode 100644 index 0000000..de0c636 --- /dev/null +++ b/packages/react-native/src/components/DTGallery.tsx @@ -0,0 +1,366 @@ +/** + * DT Gallery Component + * + * Custom-built image gallery with thumbnail navigation following + * the Dangerous Things design language. No RNP equivalent. + * + * Uses the dual-SVG-path technique for the main image frame, + * consistent with DTCard/DTMediaFrame. + * + * Web CSS reference (CyberGallery): + * - Horizontal thumbnail strip with arrow navigation + * - Active thumbnail with glow effect (box-shadow: 0 0 8px) + * - Beveled arrow buttons + * - Main image in beveled media frame + */ + +import {useRef, useCallback} from 'react'; +import { + StyleSheet, + View, + ViewStyle, + StyleProp, + Pressable, + Image, + FlatList, + Platform, +} from 'react-native'; +import Svg, {Path} from 'react-native-svg'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; +import {buildButtonBevelPath, buildMediaFrameBevelPath} from '../utils/bevelPaths'; +import {useComponentLayout} from '../utils/useComponentLayout'; + +export interface DTGalleryItem { + /** + * Unique identifier + */ + id: string; + /** + * Image URI + */ + uri: string; + /** + * Accessibility label + */ + alt?: string; +} + +interface DTGalleryProps { + /** + * Gallery items + */ + items: DTGalleryItem[]; + /** + * Currently active item index + */ + activeIndex: number; + /** + * Called when an item is selected + */ + onSelect: (index: number) => void; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Thumbnail size in pixels + * @default 64 + */ + thumbnailSize?: number; + /** + * Bevel size for the main image frame + * @default 24 + */ + bevelSize?: number; + /** + * Border width for the main image frame + * @default 3 + */ + borderWidth?: number; + /** + * Additional styles + */ + style?: StyleProp; +} + +const ARROW_SIZE = 32; +const ARROW_BEVEL = 4; +const ARROW_BORDER = 2; + +/** + * DT-styled Gallery with thumbnail strip and arrow navigation + * + * @example + * + */ +export function DTGallery({ + items, + activeIndex, + onSelect, + variant = 'normal', + thumbnailSize = 64, + bevelSize = 24, + borderWidth = 3, + style, +}: DTGalleryProps) { + const flatListRef = useRef(null); + const {dimensions, onLayout, hasDimensions} = useComponentLayout(); + const accentColor = getVariantColor(variant); + const atStart = activeIndex <= 0; + const atEnd = activeIndex >= items.length - 1; + + const handlePrev = useCallback(() => { + if (activeIndex > 0) { + onSelect(activeIndex - 1); + } + }, [activeIndex, onSelect]); + + const handleNext = useCallback(() => { + if (activeIndex < items.length - 1) { + onSelect(activeIndex + 1); + } + }, [activeIndex, items.length, onSelect]); + + const scrollToActive = useCallback( + (index: number) => { + flatListRef.current?.scrollToIndex({ + index, + animated: true, + viewPosition: 0.5, + }); + }, + [], + ); + + const handleSelect = useCallback( + (index: number) => { + onSelect(index); + scrollToActive(index); + }, + [onSelect, scrollToActive], + ); + + const getItemLayout = useCallback( + (_: unknown, index: number) => ({ + length: thumbnailSize + 8, + offset: (thumbnailSize + 8) * index, + index, + }), + [thumbnailSize], + ); + + const renderArrow = (direction: 'left' | 'right', onPress: () => void, isDisabled: boolean) => { + const center = ARROW_SIZE / 2; + const arrowSize = ARROW_SIZE * 0.2; + const iconPath = + direction === 'left' + ? `M ${center + arrowSize} ${center - arrowSize} L ${center - arrowSize} ${center} L ${center + arrowSize} ${center + arrowSize}` + : `M ${center - arrowSize} ${center - arrowSize} L ${center + arrowSize} ${center} L ${center - arrowSize} ${center + arrowSize}`; + + return ( + ({ + opacity: isDisabled ? 0.3 : pressed ? 0.7 : 1, + })}> + + + + + + ); + }; + + const renderThumbnail = ({item, index}: {item: DTGalleryItem; index: number}) => { + const isActive = index === activeIndex; + return ( + handleSelect(index)} + style={({pressed}) => ({opacity: pressed ? 0.7 : 1})}> + + {/* Android glow: colored border overlay since elevation is gray-only */} + {isActive && Platform.OS === 'android' && ( + + )} + + + + ); + }; + + if (items.length === 0) return null; + + const {width, height} = dimensions; + + // Outer and inner bevel paths for frame overlay + const outerPath = hasDimensions + ? buildMediaFrameBevelPath(width, height, bevelSize) + : ''; + const innerPath = hasDimensions + ? buildMediaFrameBevelPath(width, height, bevelSize - borderWidth, borderWidth) + : ''; + + return ( + + {/* Main image with beveled frame */} + + {/* Background fill */} + {hasDimensions && ( + + + + )} + + + + {/* Frame overlay (above content) — clips image at beveled border */} + {hasDimensions && ( + + {/* Corner mask: fill area outside outer bevel with dark to hide overflow */} + + {/* Colored border between outer and inner bevel paths */} + + + )} + + + {/* Thumbnail strip with arrows */} + {items.length > 1 && ( + + {renderArrow('left', handlePrev, atStart)} + item.id} + horizontal + showsHorizontalScrollIndicator={false} + getItemLayout={getItemLayout} + contentContainerStyle={styles.thumbnailList} + style={styles.thumbnailFlatList} + initialNumToRender={8} + maxToRenderPerBatch={4} + windowSize={5} + removeClippedSubviews={Platform.OS === 'android'} + /> + {renderArrow('right', handleNext, atEnd)} + + )} + + ); +} + +const styles = StyleSheet.create({ + container: { + gap: 12, + }, + mainImageContainer: { + aspectRatio: 1, + position: 'relative', + }, + mainImageContent: { + position: 'relative', + zIndex: 1, + flex: 1, + overflow: 'hidden', + }, + mainImage: { + flex: 1, + }, + thumbnailStrip: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + }, + thumbnailFlatList: { + flex: 1, + }, + thumbnailList: { + gap: 8, + }, + thumbnail: { + borderWidth: 2, + overflow: 'hidden', + }, + thumbnailActive: { + ...Platform.select({ + ios: { + shadowOffset: {width: 0, height: 0}, + shadowOpacity: 0.8, + shadowRadius: 8, + }, + }), + }, + thumbnailImage: { + flex: 1, + }, + frameOverlay: { + zIndex: 2, + }, +}); diff --git a/packages/react-native/src/components/DTHexagon.tsx b/packages/react-native/src/components/DTHexagon.tsx new file mode 100644 index 0000000..fe9b817 --- /dev/null +++ b/packages/react-native/src/components/DTHexagon.tsx @@ -0,0 +1,210 @@ +/** + * DT Hexagon Component + * + * Decorative hexagon shape following the Dangerous Things design language. + * No RNP equivalent — purely SVG-based. + * + * Web CSS reference (AnimatedHexagon / HexagonHamburgerMenu): + * - Flat-top hexagon shape + * - Optional rotation and pulse animations + * - Used for loading indicators, backgrounds, menu icons + */ + +import {useRef, useEffect} from 'react'; +import {StyleSheet, View, ViewStyle, StyleProp, Animated} from 'react-native'; +import Svg, {Polygon} from 'react-native-svg'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; + +interface DTHexagonProps { + /** + * Hexagon diameter in pixels + */ + size: number; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Whether the hexagon has a solid fill + * @default true + */ + filled?: boolean; + /** + * Whether to animate + * @default false + */ + animated?: boolean; + /** + * Animation type + * @default 'none' + */ + animationType?: 'rotate' | 'pulse' | 'none'; + /** + * Animation duration in milliseconds + * @default 2000 + */ + animationDuration?: number; + /** + * Stroke/border width when not filled + * @default 2 + */ + borderWidth?: number; + /** + * Custom color (overrides variant) + */ + color?: string; + /** + * Opacity + * @default 1 + */ + opacity?: number; + /** + * Additional styles + */ + style?: StyleProp; + /** + * Content rendered centered inside the hexagon + */ + children?: React.ReactNode; +} + +/** + * Build flat-top hexagon SVG polygon points + */ +function buildHexagonPoints(size: number): string { + const cx = size / 2; + const cy = size / 2; + const r = size / 2; + + return [0, 1, 2, 3, 4, 5] + .map(i => { + const angle = (Math.PI / 3) * i - Math.PI / 6; // flat-top orientation + const x = cx + r * Math.cos(angle); + const y = cy + r * Math.sin(angle); + return `${x},${y}`; + }) + .join(' '); +} + +/** + * DT-styled decorative Hexagon + * + * @example + * + * + * @example + * + * + * @example + * + */ +export function DTHexagon({ + size, + variant = 'normal', + filled = true, + animated = false, + animationType = 'none', + animationDuration = 2000, + borderWidth = 2, + color, + opacity: opacityProp = 1, + style, + children, +}: DTHexagonProps) { + const accentColor = getVariantColor(variant, color); + const rotateAnim = useRef(new Animated.Value(0)).current; + const pulseAnim = useRef(new Animated.Value(1)).current; + + useEffect(() => { + if (!animated) { + rotateAnim.setValue(0); + pulseAnim.setValue(1); + return; + } + + if (animationType === 'rotate') { + const animation = Animated.loop( + Animated.timing(rotateAnim, { + toValue: 1, + duration: animationDuration, + useNativeDriver: true, + }), + ); + animation.start(); + return () => { + animation.stop(); + rotateAnim.setValue(0); + }; + } + + if (animationType === 'pulse') { + const animation = Animated.loop( + Animated.sequence([ + Animated.timing(pulseAnim, { + toValue: 0.3, + duration: animationDuration / 2, + useNativeDriver: true, + }), + Animated.timing(pulseAnim, { + toValue: 1, + duration: animationDuration / 2, + useNativeDriver: true, + }), + ]), + ); + animation.start(); + return () => { + animation.stop(); + pulseAnim.setValue(1); + }; + } + }, [animated, animationType, animationDuration, rotateAnim, pulseAnim]); + + const rotation = rotateAnim.interpolate({ + inputRange: [0, 1], + outputRange: ['0deg', '360deg'], + }); + + const animatedOpacity = + animated && animationType === 'pulse' ? pulseAnim : opacityProp; + + const transform = + animated && animationType === 'rotate' + ? [{rotate: rotation}] + : []; + + const points = buildHexagonPoints(size); + + return ( + 0 ? {transform} : undefined, + style, + ]}> + + + + {children && ( + + {children} + + )} + + ); +} + +const styles = StyleSheet.create({ + container: {}, + childrenContainer: { + justifyContent: 'center', + alignItems: 'center', + }, +}); diff --git a/packages/react-native/src/components/DTLabel.tsx b/packages/react-native/src/components/DTLabel.tsx new file mode 100644 index 0000000..583e8cb --- /dev/null +++ b/packages/react-native/src/components/DTLabel.tsx @@ -0,0 +1,313 @@ +/** + * DT Label Component + * + * A themed label following the Dangerous Things design language + * with an SVG-based beveled top-right corner. + * + * Web CSS reference (CyberLabel): + * - Top-right bevel: 1em (~16px) + * - Solid filled background using mode color + * - Black text on colored background + */ + +import {ReactNode, useEffect, useRef} from 'react'; +import {StyleSheet, View, ViewStyle, StyleProp, Animated} from 'react-native'; +import {Text} from 'react-native-paper'; +import Svg, {Path} from 'react-native-svg'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; +import {buildLabelBevelPath} from '../utils/bevelPaths'; +import {useComponentLayout} from '../utils/useComponentLayout'; + +type DTLabelSize = 'small' | 'medium' | 'large'; + +interface SizeConfig { + fontSize: number; + fontSizeSecondary: number; + paddingHorizontal: number; + paddingVertical: number; + bevel: number; + indicatorWidth: number; + gap: number; +} + +const sizeConfigs: Record = { + small: { + fontSize: 11, + fontSizeSecondary: 11, + paddingHorizontal: 8, + paddingVertical: 4, + bevel: 10, + indicatorWidth: 12, + gap: 3, + }, + medium: { + fontSize: 14, + fontSizeSecondary: 14, + paddingHorizontal: 12, + paddingVertical: 8, + bevel: 16, + indicatorWidth: 16, + gap: 4, + }, + large: { + fontSize: 18, + fontSizeSecondary: 18, + paddingHorizontal: 16, + paddingVertical: 12, + bevel: 22, + indicatorWidth: 20, + gap: 6, + }, +}; + +interface DTLabelProps { + /** + * Primary text content + */ + primaryText: ReactNode; + /** + * Secondary text (displayed bold, after primary) + */ + secondaryText?: ReactNode; + /** + * Color mode for the label + * @default 'normal' + */ + mode?: DTVariant; + /** + * Size of the label - affects text size and scales all dimensions + * @default 'medium' + */ + size?: DTLabelSize; + /** + * Whether the label should fill its container width + * @default false + */ + fullWidth?: boolean; + /** + * Whether to animate the label on mount + * @default true + */ + animated?: boolean; + /** + * Animation delay in milliseconds + * @default 100 + */ + animationDelay?: number; + /** + * Animation duration in milliseconds + * @default 330 + */ + animationDuration?: number; + /** + * Whether to show the pinging indicator + * @default true + */ + showIndicator?: boolean; + /** + * Top-right bevel size in pixels (overrides size-based default) + */ + bevelSize?: number; + /** + * Additional styles for the label container + */ + style?: StyleProp; +} + +/** + * DT-styled Label component with SVG beveled top-right corner + * + * Based on CyberLabel from the Dangerous Things web storefront. + * Features a solid colored background with black text and an optional + * animated ping indicator. + * + * @example + * + * + * @example + * + * + * @example + * + * + * @example + * + * + * @example + * + */ +export function DTLabel({ + primaryText, + secondaryText, + mode = 'normal', + size = 'medium', + fullWidth = false, + animated = true, + animationDelay = 100, + animationDuration = 330, + showIndicator = true, + bevelSize, + style, +}: DTLabelProps) { + const {dimensions, onLayout, hasDimensions} = useComponentLayout(); + const scaleAnim = useRef(new Animated.Value(animated ? 0 : 1)).current; + const pingAnim = useRef(new Animated.Value(1)).current; + const backgroundColor = getVariantColor(mode); + const sizeConfig = sizeConfigs[size]; + const effectiveBevelSize = bevelSize ?? sizeConfig.bevel; + + // Mount animation + useEffect(() => { + if (animated) { + Animated.timing(scaleAnim, { + toValue: 1, + duration: animationDuration, + delay: animationDelay, + useNativeDriver: true, + }).start(); + } + }, [animated, animationDelay, animationDuration, scaleAnim]); + + // Ping animation loop + useEffect(() => { + if (showIndicator) { + const pingAnimation = Animated.loop( + Animated.sequence([ + Animated.timing(pingAnim, { + toValue: 0.3, + duration: 1000, + useNativeDriver: true, + }), + Animated.timing(pingAnim, { + toValue: 1, + duration: 1000, + useNativeDriver: true, + }), + ]), + ); + pingAnimation.start(); + return () => { + pingAnimation.stop(); + pingAnim.setValue(1); + }; + } + pingAnim.setValue(1); + }, [showIndicator, pingAnim]); + + const {width, height} = dimensions; + + return ( + + {hasDimensions && ( + + + + )} + + + + {primaryText} + + {secondaryText && ( + + {secondaryText} + + )} + + {showIndicator && ( + + + + )} + + + ); +} + +/** + * DT Label design constants matching web CSS + */ +export const DTLabelClipPath = { + // CSS-style clip path (for web reference) + css: `polygon( + 0% 0%, + calc(100% - 1em) 0%, + 100% 1em, + 100% 100%, + 0% 100% + )`, + // Default bevel size in pixels (matching 1em at 16px base) + bevelSize: 16, +}; + +const styles = StyleSheet.create({ + container: { + position: 'relative', + alignSelf: 'flex-start', + margin: 8, + }, + fullWidth: { + alignSelf: 'stretch', + }, + innerContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + position: 'relative', + zIndex: 1, + }, + textContainer: { + flexDirection: 'row', + flexWrap: 'wrap', + alignItems: 'center', + }, + primaryText: { + color: DTColors.dark, + fontWeight: '500', + }, + secondaryText: { + color: DTColors.dark, + fontWeight: '800', + }, + indicator: {}, + indicatorLine: { + borderBottomWidth: 2, + }, +}); diff --git a/packages/react-native/src/components/DTMediaFrame.tsx b/packages/react-native/src/components/DTMediaFrame.tsx new file mode 100644 index 0000000..af399f5 --- /dev/null +++ b/packages/react-native/src/components/DTMediaFrame.tsx @@ -0,0 +1,210 @@ +/** + * DT MediaFrame Component + * + * A beveled frame for images and video content following the + * Dangerous Things design language. No RNP equivalent. + * + * Web CSS reference (CyberMediaFrame / .media-frame-clipped): + * - Top-left + bottom-right diagonal symmetry bevels + * - Colored border with dark inner background + * - Optional mount scale animation + */ + +import {ReactNode, useRef, useEffect} from 'react'; +import {StyleSheet, View, ViewStyle, StyleProp, Animated} from 'react-native'; +import Svg, {Path, Defs, ClipPath} from 'react-native-svg'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; +import {buildMediaFrameBevelPath} from '../utils/bevelPaths'; +import {useComponentLayout} from '../utils/useComponentLayout'; + +interface DTMediaFrameProps { + /** + * Content to frame (Image, Video, etc.) + */ + children: ReactNode; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Aspect ratio (e.g., 16/9, 1, 4/3) + */ + aspectRatio?: number; + /** + * Border width in pixels + * @default 3 + */ + borderWidth?: number; + /** + * Bevel size in pixels (top-left and bottom-right) + * @default 32 + */ + bevelSize?: number; + /** + * Whether to animate on mount + * @default true + */ + animated?: boolean; + /** + * Animation delay in milliseconds + * @default 0 + */ + animationDelay?: number; + /** + * Custom color (overrides variant) + */ + color?: string; + /** + * Additional styles for outer container + */ + style?: StyleProp; + /** + * Additional styles for the content area + */ + contentStyle?: StyleProp; +} + +/** + * DT-styled MediaFrame with diagonal-symmetry beveled corners + * + * @example + * + * + * + * + * @example + * + * + */ +export function DTMediaFrame({ + children, + variant = 'normal', + aspectRatio, + borderWidth = 3, + bevelSize = 32, + animated = true, + animationDelay = 0, + color, + style, + contentStyle, +}: DTMediaFrameProps) { + const {dimensions, onLayout, hasDimensions} = useComponentLayout(); + const scaleAnim = useRef(new Animated.Value(animated ? 0 : 1)).current; + const accentColor = getVariantColor(variant, color); + + useEffect(() => { + if (animated) { + Animated.timing(scaleAnim, { + toValue: 1, + duration: 300, + delay: animationDelay, + useNativeDriver: true, + }).start(); + } + }, [animated, animationDelay, scaleAnim]); + + const {width, height} = dimensions; + + // Outer bevel path (full frame shape) + const outerPath = hasDimensions + ? buildMediaFrameBevelPath(width, height, bevelSize) + : ''; + // Inner bevel path at border inset + const innerPath = hasDimensions + ? buildMediaFrameBevelPath(width, height, bevelSize - borderWidth, borderWidth) + : ''; + + return ( + + {/* Background fill (behind content) */} + {hasDimensions && ( + + + + )} + {/* Content clipped to the inner bevel shape */} + {hasDimensions ? ( + + + + + + + + + + + ) : ( + + {children} + + )} + {/* Frame overlay (above content) — masks content at beveled corners */} + {hasDimensions && ( + + {/* Outer frame border */} + + {/* Corner masks: fill the rectangular area outside the bevel shape with black + to hide content that overflows past the beveled corners */} + + + )} + + ); +} + +const styles = StyleSheet.create({ + container: { + position: 'relative', + }, + content: { + position: 'relative', + zIndex: 1, + overflow: 'hidden', + flex: 1, + }, + frameOverlay: { + zIndex: 2, + }, +}); diff --git a/packages/react-native/src/components/DTMenu.tsx b/packages/react-native/src/components/DTMenu.tsx new file mode 100644 index 0000000..031280d --- /dev/null +++ b/packages/react-native/src/components/DTMenu.tsx @@ -0,0 +1,371 @@ +/** + * DT Menu Component + * + * Wraps React Native Paper's Menu for dropdown positioning, with custom + * menu items styled to the Dangerous Things aesthetic. + * + * Web CSS reference (CyberMenu): + * - Hierarchical items with menu-item-clipped styling + * - Active/selected state with emphasis color fill + * - borderTopWidth: 5 thick accent border + */ + +import {useState, useCallback, useRef, useEffect} from 'react'; +import { + StyleSheet, + View, + ViewStyle, + StyleProp, + Pressable, + Animated, +} from 'react-native'; +import {Menu, Text} from 'react-native-paper'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; + +export interface DTMenuItem { + /** + * Unique identifier + */ + id: string; + /** + * Display title + */ + title: string; + /** + * Press handler (leaf items) + */ + onPress?: () => void; + /** + * Sub-menu items + */ + items?: DTMenuItem[]; + /** + * Whether this item is currently active + */ + isActive?: boolean; +} + +interface DTMenuProps { + /** + * Menu items + */ + items: DTMenuItem[]; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Variant for active items + * @default 'emphasis' + */ + activeVariant?: DTVariant; + /** + * Layout direction + * @default 'vertical' + */ + layout?: 'horizontal' | 'vertical'; + /** + * Additional styles + */ + style?: StyleProp; +} + +/** + * DT-styled Menu with hierarchical items + * + * For inline menu display (not dropdown). Items with sub-items + * expand/collapse on press. + * + * @example + * + */ +export function DTMenu({ + items, + variant = 'normal', + activeVariant = 'emphasis', + layout = 'vertical', + style, +}: DTMenuProps) { + return ( + + {items.map(item => ( + + ))} + + ); +} + +/** + * For dropdown use, wraps RNP Menu for positioning/portal behavior + */ +interface DTMenuDropdownProps { + /** + * Menu items + */ + items: DTMenuItem[]; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Anchor element or position + */ + anchor: React.ReactNode; + /** + * Whether the menu is visible + */ + visible: boolean; + /** + * Called when the menu is dismissed + */ + onDismiss: () => void; + /** + * Additional styles + */ + style?: StyleProp; +} + +/** + * DT-styled dropdown Menu wrapping React Native Paper Menu + * + * @example + * Open Menu} + * visible={menuVisible} + * onDismiss={() => setMenuVisible(false)} + * /> + */ +export function DTMenuDropdown({ + items, + variant = 'normal', + anchor, + visible, + onDismiss, + style, +}: DTMenuDropdownProps) { + const accentColor = getVariantColor(variant); + + return ( + + {items.map(item => ( + { + item.onPress?.(); + onDismiss(); + }} + titleStyle={[styles.dropdownItemTitle, {color: DTColors.light}]} + style={styles.dropdownItem} + /> + ))} + + ); +} + +// --- Internal DTMenuItemRow --- + +function DTMenuItemRow({ + item, + variant, + activeVariant, + level, +}: { + item: DTMenuItem; + variant: DTVariant; + activeVariant: DTVariant; + level: number; +}) { + const [expanded, setExpanded] = useState(false); + const hasChildren = item.items && item.items.length > 0; + const isActive = item.isActive || expanded; + const itemColor = getVariantColor(isActive ? activeVariant : variant); + + const heightAnim = useRef(new Animated.Value(0)).current; + const chevronAnim = useRef(new Animated.Value(0)).current; + const [contentHeight, setContentHeight] = useState(0); + const [measured, setMeasured] = useState(false); + + useEffect(() => { + if (!hasChildren) return; + Animated.parallel([ + Animated.timing(heightAnim, { + toValue: expanded ? 1 : 0, + duration: 250, + useNativeDriver: false, + }), + Animated.timing(chevronAnim, { + toValue: expanded ? 1 : 0, + duration: 250, + useNativeDriver: true, + }), + ]).start(); + }, [expanded, heightAnim, chevronAnim, hasChildren]); + + const handlePress = useCallback(() => { + if (hasChildren) { + setExpanded(prev => !prev); + } else { + item.onPress?.(); + } + }, [hasChildren, item]); + + const animatedHeight = heightAnim.interpolate({ + inputRange: [0, 1], + outputRange: [0, contentHeight], + }); + + const chevronRotate = chevronAnim.interpolate({ + inputRange: [0, 1], + outputRange: ['0deg', '180deg'], + }); + + return ( + + [ + styles.menuItem, + { + borderColor: itemColor, + borderTopColor: itemColor, + backgroundColor: isActive + ? `${itemColor}20` + : DTColors.dark, + paddingLeft: 16 + level * 16, + opacity: pressed ? 0.7 : 1, + }, + ]}> + + {item.title} + + {hasChildren && ( + + + + )} + + {hasChildren && ( + + { + const h = e.nativeEvent.layout.height; + if (h > 0 && !measured) { + setContentHeight(h); + setMeasured(true); + if (!expanded) { + heightAnim.setValue(0); + } + } + }}> + {item.items?.map(child => ( + + ))} + + + )} + + ); +} + +const styles = StyleSheet.create({ + container: { + gap: 4, + }, + horizontal: { + flexDirection: 'row', + flexWrap: 'wrap', + }, + vertical: { + flexDirection: 'column', + }, + menuItem: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + borderWidth: 1, + borderTopWidth: 5, + paddingVertical: 12, + paddingRight: 16, + }, + menuItemTitle: { + fontWeight: '600', + letterSpacing: 0.5, + textTransform: 'uppercase', + fontSize: 14, + }, + chevron: { + justifyContent: 'center', + alignItems: 'center', + width: 24, + height: 24, + }, + chevronArrow: { + width: 0, + height: 0, + borderLeftWidth: 5, + borderRightWidth: 5, + borderTopWidth: 7, + borderLeftColor: 'transparent', + borderRightColor: 'transparent', + }, + dropdownContent: { + borderWidth: 2, + borderRadius: 0, + backgroundColor: DTColors.dark, + }, + dropdownItem: { + borderRadius: 0, + }, + dropdownItemTitle: { + letterSpacing: 0.3, + }, +}); diff --git a/packages/react-native/src/components/DTModal.tsx b/packages/react-native/src/components/DTModal.tsx new file mode 100644 index 0000000..0c33e73 --- /dev/null +++ b/packages/react-native/src/components/DTModal.tsx @@ -0,0 +1,115 @@ +/** + * DT Modal Component + * + * Wraps React Native Paper's Modal + Portal with the Dangerous Things + * aesthetic. Content is rendered inside a DTCard for the beveled look. + * + * Web CSS reference (Modal.tsx): + * - Centered overlay with dark backdrop + * - Content in beveled card container + */ + +import {StyleSheet, ViewStyle, StyleProp, KeyboardAvoidingView, Platform} from 'react-native'; +import {Portal, Modal} from 'react-native-paper'; +import {DTColors} from '../theme/colors'; +import {type DTVariant} from '../utils/variantColors'; +import {DTCard} from './DTCard'; + +interface DTModalProps { + /** + * Whether the modal is visible + */ + visible: boolean; + /** + * Called when the modal is dismissed + */ + onDismiss: () => void; + /** + * Optional title for the modal header + */ + title?: string; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Modal content + */ + children: React.ReactNode; + /** + * Whether the modal can be dismissed by tapping the backdrop + * @default true + */ + dismissable?: boolean; + /** + * Additional styles for the card content area + */ + contentStyle?: StyleProp; + /** + * Additional styles for the modal container + */ + style?: StyleProp; +} + +/** + * DT-styled Modal wrapping React Native Paper Modal + Portal + * + * @example + * setShowModal(false)} title="Confirm"> + * Are you sure? + * + * + * @example + * + * Something went wrong + * + */ +export function DTModal({ + visible, + onDismiss, + title, + variant = 'normal', + children, + dismissable = true, + contentStyle, + style, +}: DTModalProps) { + return ( + + + + + {children} + + + + + ); +} + +const styles = StyleSheet.create({ + modal: {}, + container: { + marginHorizontal: 24, + }, + keyboardAvoid: { + width: '100%', + }, +}); diff --git a/packages/react-native/src/components/DTProgressBar.tsx b/packages/react-native/src/components/DTProgressBar.tsx new file mode 100644 index 0000000..c1ce698 --- /dev/null +++ b/packages/react-native/src/components/DTProgressBar.tsx @@ -0,0 +1,183 @@ +/** + * DT ProgressBar Component + * + * A themed progress bar wrapping React Native Paper's ProgressBar + * with the Dangerous Things angular aesthetic. + * + * Web CSS reference (.progress / .progress-indicator): + * - Vertical or horizontal bar showing progress 0-100% + * - Mode-colored fill + */ + +import {StyleSheet, View, ViewStyle, StyleProp} from 'react-native'; +import {ProgressBar, Text} from 'react-native-paper'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; +import {useComponentLayout} from '../utils/useComponentLayout'; + +interface DTProgressBarProps { + /** + * Progress value between 0 and 1 + */ + value: number; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Orientation of the bar + * @default 'horizontal' + */ + orientation?: 'horizontal' | 'vertical'; + /** + * Bar thickness in pixels + * @default 4 + */ + height?: number; + /** + * Whether to animate progress changes + * @default true + */ + animated?: boolean; + /** + * Show percentage label + * @default false + */ + showLabel?: boolean; + /** + * Custom color (overrides variant) + */ + color?: string; + /** + * Additional styles + */ + style?: StyleProp; +} + +/** + * DT-styled ProgressBar wrapping React Native Paper ProgressBar + * + * @example + * + * + * @example + * + * + * @example + * + */ +export function DTProgressBar({ + value, + variant = 'normal', + orientation = 'horizontal', + height = 4, + animated: _animated = true, + showLabel = false, + color, + style, +}: DTProgressBarProps) { + const accentColor = getVariantColor(variant, color); + const clampedValue = Math.max(0, Math.min(1, value)); + + if (orientation === 'vertical') { + return ( + + ); + } + + return ( + + + {showLabel && ( + + {Math.round(clampedValue * 100)}% + + )} + + ); +} + +/** + * Vertical progress bar using measured pixel height instead of + * percentage strings (which don't animate smoothly in RN). + */ +function VerticalProgressBar({ + value, + color, + width, + showLabel, + style, +}: { + value: number; + color: string; + width: number; + showLabel: boolean; + style?: StyleProp; +}) { + const {dimensions, onLayout, hasDimensions} = useComponentLayout(); + const fillHeight = hasDimensions ? dimensions.height * value : 0; + + return ( + + + + + {showLabel && ( + + {Math.round(value * 100)}% + + )} + + ); +} + +const styles = StyleSheet.create({ + horizontalContainer: { + gap: 8, + }, + bar: { + borderRadius: 0, + }, + verticalContainer: { + alignItems: 'center', + gap: 8, + }, + verticalTrack: { + flex: 1, + width: '100%', + backgroundColor: DTColors.disabledBackground, + justifyContent: 'flex-end', + }, + verticalFill: { + width: '100%', + }, + label: { + fontSize: 11, + fontWeight: '600', + letterSpacing: 0.5, + }, +}); diff --git a/packages/react-native/src/components/DTQuantityStepper.tsx b/packages/react-native/src/components/DTQuantityStepper.tsx new file mode 100644 index 0000000..c58f213 --- /dev/null +++ b/packages/react-native/src/components/DTQuantityStepper.tsx @@ -0,0 +1,234 @@ +/** + * DT QuantityStepper Component + * + * Custom-built quantity increment/decrement control following the + * Dangerous Things design language. No RNP equivalent exists. + * + * Web CSS reference (AddOnOptionItem quantity controls): + * - Plus/minus buttons with beveled corners + * - Quantity display between buttons + */ + +import {StyleSheet, View, ViewStyle, StyleProp, Pressable} from 'react-native'; +import {Text} from 'react-native-paper'; +import Svg, {Path} from 'react-native-svg'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; +import {buildButtonBevelPath} from '../utils/bevelPaths'; + +type DTStepperSize = 'small' | 'medium' | 'large'; + +interface SizeConfig { + buttonSize: number; + fontSize: number; + bevelSize: number; + iconStrokeWidth: number; + minWidth: number; +} + +const sizeConfigs: Record = { + small: { + buttonSize: 28, + fontSize: 12, + bevelSize: 4, + iconStrokeWidth: 1.5, + minWidth: 28, + }, + medium: { + buttonSize: 36, + fontSize: 16, + bevelSize: 6, + iconStrokeWidth: 2, + minWidth: 36, + }, + large: { + buttonSize: 44, + fontSize: 20, + bevelSize: 8, + iconStrokeWidth: 2.5, + minWidth: 44, + }, +}; + +interface DTQuantityStepperProps { + /** + * Current quantity value + */ + value: number; + /** + * Called when value changes + */ + onValueChange: (value: number) => void; + /** + * Minimum value + * @default 0 + */ + min?: number; + /** + * Maximum value + * @default 99 + */ + max?: number; + /** + * Step increment + * @default 1 + */ + step?: number; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Whether the stepper is disabled + */ + disabled?: boolean; + /** + * Label text displayed above the stepper + */ + label?: string; + /** + * Size preset + * @default 'medium' + */ + size?: DTStepperSize; + /** + * Custom color (overrides variant) + */ + color?: string; + /** + * Additional styles + */ + style?: StyleProp; +} + +/** + * DT-styled QuantityStepper with beveled +/- buttons + * + * @example + * + * + * @example + * + */ +export function DTQuantityStepper({ + value, + onValueChange, + min = 0, + max = 99, + step = 1, + variant = 'normal', + disabled = false, + label, + size = 'medium', + color, + style, +}: DTQuantityStepperProps) { + const accentColor = getVariantColor(variant, color); + const config = sizeConfigs[size]; + const atMin = value <= min; + const atMax = value >= max; + const borderWidth = 2; + + const handleDecrement = () => { + const next = Math.max(min, value - step); + onValueChange(next); + }; + + const handleIncrement = () => { + const next = Math.min(max, value + step); + onValueChange(next); + }; + + const renderStepButton = ( + type: 'minus' | 'plus', + onPress: () => void, + isDisabled: boolean, + ) => { + const s = config.buttonSize; + const center = s / 2; + const iconSize = s * 0.35; + const sw = config.iconStrokeWidth; + + // Minus: horizontal line; Plus: cross + const iconPath = + type === 'minus' + ? `M ${center - iconSize} ${center} L ${center + iconSize} ${center}` + : `M ${center - iconSize} ${center} L ${center + iconSize} ${center} M ${center} ${center - iconSize} L ${center} ${center + iconSize}`; + + // Expand touch target to at least 44px + const hitSlopSize = Math.max(0, (44 - s) / 2); + const hitSlop = hitSlopSize > 0 ? hitSlopSize : undefined; + + return ( + ({ + opacity: disabled || isDisabled ? 0.3 : pressed ? 0.7 : 1, + })}> + + + + + + ); + }; + + return ( + + {label && ( + {label} + )} + + {renderStepButton('minus', handleDecrement, atMin)} + + + {value} + + + {renderStepButton('plus', handleIncrement, atMax)} + + + ); +} + +const styles = StyleSheet.create({ + wrapper: { + gap: 8, + }, + container: { + flexDirection: 'row', + alignItems: 'center', + gap: 4, + }, + label: { + fontSize: 14, + letterSpacing: 0.3, + }, + valueContainer: { + alignItems: 'center', + justifyContent: 'center', + paddingHorizontal: 8, + }, + valueText: { + fontWeight: '700', + letterSpacing: 0.5, + }, +}); diff --git a/packages/react-native/src/components/DTRadioGroup.tsx b/packages/react-native/src/components/DTRadioGroup.tsx new file mode 100644 index 0000000..2835d2a --- /dev/null +++ b/packages/react-native/src/components/DTRadioGroup.tsx @@ -0,0 +1,229 @@ +/** + * DT RadioGroup + RadioOption Components + * + * Custom-built angular radio selection following the Dangerous Things design language. + * RNP RadioButton uses circular geometry with animated SVG circles, + * so we build hexagonal indicators from scratch. + * + * Web CSS reference (AddOnSelector single-select): + * - Selected: border highlight + semi-transparent fill (var(--selected) at 70% opacity) + * - Hexagon indicator instead of circular radio button + */ + +import {createContext, useContext} from 'react'; +import {StyleSheet, View, ViewStyle, StyleProp, Pressable} from 'react-native'; +import {Text} from 'react-native-paper'; +import Svg, {Polygon} from 'react-native-svg'; +import {DTColors, getColor} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; + +// --- Context --- + +interface RadioContextValue { + value: string | null; + onValueChange: (value: string) => void; + variant: DTVariant; +} + +const RadioContext = createContext(null); + +// --- DTRadioGroup --- + +interface DTRadioGroupProps { + /** + * Currently selected value + */ + value: string | null; + /** + * Called when selection changes + */ + onValueChange: (value: string) => void; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Radio option children + */ + children: React.ReactNode; + /** + * Additional styles for the container + */ + style?: StyleProp; +} + +/** + * DT-styled RadioGroup container + * + * @example + * + * + * + * + */ +export function DTRadioGroup({ + value, + onValueChange, + variant = 'normal', + children, + style, +}: DTRadioGroupProps) { + return ( + + {children} + + ); +} + +// --- DTRadioOption --- + +interface DTRadioOptionProps { + /** + * Value identifier for this option + */ + value: string; + /** + * Label text + */ + label: string; + /** + * Optional description text + */ + description?: string; + /** + * Whether this option is disabled + */ + disabled?: boolean; + /** + * Additional styles + */ + style?: StyleProp; +} + +const INDICATOR_SIZE = 22; +const INDICATOR_INNER = 12; +const INDICATOR_BORDER = 2; + +/** Generate flat-top hexagon points string for SVG Polygon */ +function hexPoints(cx: number, cy: number, r: number): string { + const pts: string[] = []; + for (let i = 0; i < 6; i++) { + const angle = (Math.PI / 3) * i - Math.PI / 6; // flat-top: start at -30° + pts.push(`${cx + r * Math.cos(angle)},${cy + r * Math.sin(angle)}`); + } + return pts.join(' '); +} + +/** + * DT-styled RadioOption with hexagonal indicator + * + * Must be used inside a DTRadioGroup. + * + * @example + * + */ +export function DTRadioOption({ + value, + label, + description, + disabled = false, + style, +}: DTRadioOptionProps) { + const context = useContext(RadioContext); + if (!context) { + throw new Error('DTRadioOption must be used inside DTRadioGroup'); + } + + const {value: selectedValue, onValueChange, variant} = context; + const isSelected = selectedValue === value; + const accentColor = getVariantColor(variant); + const selectedBgColor = getColor( + variant === 'normal' + ? 'modeNormalSelected' + : variant === 'emphasis' + ? 'modeEmphasisSelected' + : 'modeNormal', + ); + const opacity = disabled ? 0.5 : 1; + + return ( + !disabled && onValueChange(value)} + style={({pressed}) => [ + styles.option, + { + borderColor: isSelected ? accentColor : getColor('modeNormal', 0.3), + backgroundColor: isSelected ? selectedBgColor : 'transparent', + opacity: pressed ? 0.7 : opacity, + }, + style, + ]}> + {/* Hexagon indicator */} + + + {isSelected && ( + + )} + + {/* Text content */} + + + {label} + + {description && ( + + {description} + + )} + + + ); +} + +const styles = StyleSheet.create({ + group: { + gap: 8, + }, + option: { + flexDirection: 'row', + alignItems: 'center', + gap: 12, + padding: 12, + borderWidth: 2, + }, + optionText: { + flex: 1, + gap: 2, + }, + optionLabel: { + fontSize: 14, + fontWeight: '500', + letterSpacing: 0.3, + }, + optionDescription: { + fontSize: 12, + letterSpacing: 0.2, + }, +}); diff --git a/packages/react-native/src/components/DTSearchInput.tsx b/packages/react-native/src/components/DTSearchInput.tsx new file mode 100644 index 0000000..14797c3 --- /dev/null +++ b/packages/react-native/src/components/DTSearchInput.tsx @@ -0,0 +1,163 @@ +/** + * DT SearchInput Component + * + * A themed search input wrapping React Native Paper's Searchbar + * with the Dangerous Things angular aesthetic. + * + * Styled input only — predictive results logic is app-specific + * (composable principle from CLAUDE.md). + */ + +import {useState, useRef, useEffect} from 'react'; +import {StyleSheet, View, ViewStyle, TextStyle, StyleProp, Animated} from 'react-native'; +import {Searchbar, ActivityIndicator} from 'react-native-paper'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; + +interface DTSearchInputProps { + /** + * Current search text + */ + value: string; + /** + * Called when text changes + */ + onChangeText: (text: string) => void; + /** + * Called when search is submitted + */ + onSubmit?: () => void; + /** + * Placeholder text + * @default 'Search...' + */ + placeholder?: string; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Show loading indicator instead of search icon + * @default false + */ + loading?: boolean; + /** + * Whether the input is disabled + */ + disabled?: boolean; + /** + * Auto-focus the input on mount + */ + autoFocus?: boolean; + /** + * Custom color (overrides variant) + */ + color?: string; + /** + * Additional styles for the container + */ + style?: StyleProp; + /** + * Additional styles for the input text + */ + inputStyle?: StyleProp; +} + +/** + * DT-styled SearchInput wrapping React Native Paper Searchbar + * + * @example + * + * + * @example + * + */ +export function DTSearchInput({ + value, + onChangeText, + onSubmit, + placeholder = 'Search...', + variant = 'normal', + loading = false, + disabled = false, + autoFocus = false, + color, + style, + inputStyle, +}: DTSearchInputProps) { + const accentColor = getVariantColor(variant, color); + const [focused, setFocused] = useState(false); + const focusAnim = useRef(new Animated.Value(0)).current; + + useEffect(() => { + const anim = Animated.timing(focusAnim, { + toValue: focused ? 1 : 0, + duration: 150, + useNativeDriver: false, + }); + anim.start(); + return () => anim.stop(); + }, [focused, focusAnim]); + + return ( + + setFocused(true)} + onBlur={() => setFocused(false)} + returnKeyType="search" + placeholder={placeholder} + placeholderTextColor={DTColors.disabled} + editable={!disabled} + autoFocus={autoFocus} + icon={ + loading + ? () => + : 'magnify' + } + iconColor={accentColor} + inputStyle={[styles.input, {color: DTColors.light}, inputStyle]} + style={[styles.searchbar, {borderColor: accentColor}]} + rippleColor={accentColor} + theme={{ + colors: { + elevation: {level3: DTColors.dark}, + onSurface: DTColors.light, + onSurfaceVariant: accentColor, + }, + roundness: 0, + }} + /> + {/* Focus glow bar — matches DTTextInput */} + + + ); +} + +const styles = StyleSheet.create({ + container: {}, + searchbar: { + borderWidth: 2, + backgroundColor: DTColors.dark, + elevation: 0, + }, + input: { + fontSize: 14, + letterSpacing: 0.3, + }, + focusBar: { + height: 4, + marginTop: 1, + }, +}); diff --git a/packages/react-native/src/components/DTSwitch.tsx b/packages/react-native/src/components/DTSwitch.tsx new file mode 100644 index 0000000..674ad5a --- /dev/null +++ b/packages/react-native/src/components/DTSwitch.tsx @@ -0,0 +1,152 @@ +/** + * DT Switch Component + * + * Custom-built angular toggle switch following the Dangerous Things design language. + * RNP Switch delegates to native with no shape control, + * so we build a rectangular toggle from scratch. + */ + +import {useRef, useEffect} from 'react'; +import { + StyleSheet, + ViewStyle, + StyleProp, + Pressable, + Animated, +} from 'react-native'; +import {Text} from 'react-native-paper'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; + +const TRACK_WIDTH = 48; +const TRACK_HEIGHT = 26; +const THUMB_SIZE = 20; +const THUMB_MARGIN = 3; + +interface DTSwitchProps { + /** + * Whether the switch is on + */ + value: boolean; + /** + * Called when the value changes + */ + onValueChange: (value: boolean) => void; + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Whether the switch is disabled + */ + disabled?: boolean; + /** + * Label text displayed beside the switch + */ + label?: string; + /** + * Custom color (overrides variant) + */ + color?: string; + /** + * Additional styles for the container + */ + style?: StyleProp; +} + +/** + * DT-styled angular Switch/Toggle + * + * @example + * + * + * @example + * + */ +export function DTSwitch({ + value, + onValueChange, + variant = 'normal', + disabled = false, + label, + color, + style, +}: DTSwitchProps) { + const accentColor = getVariantColor(variant, color); + const thumbAnim = useRef(new Animated.Value(value ? 1 : 0)).current; + + useEffect(() => { + Animated.timing(thumbAnim, { + toValue: value ? 1 : 0, + duration: 150, + useNativeDriver: false, + }).start(); + }, [value, thumbAnim]); + + const thumbTranslateX = thumbAnim.interpolate({ + inputRange: [0, 1], + outputRange: [THUMB_MARGIN, TRACK_WIDTH - THUMB_SIZE - THUMB_MARGIN], + }); + + const trackColor = thumbAnim.interpolate({ + inputRange: [0, 1], + outputRange: [DTColors.disabledBackground, accentColor], + }); + + + return ( + !disabled && onValueChange(!value)} + style={({pressed}) => [ + styles.container, + {opacity: disabled ? 0.5 : pressed ? 0.7 : 1}, + style, + ]}> + {label && ( + {label} + )} + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + alignItems: 'center', + gap: 12, + paddingVertical: 8, + }, + label: { + fontSize: 14, + letterSpacing: 0.3, + }, + track: { + width: TRACK_WIDTH, + height: TRACK_HEIGHT, + borderWidth: 2, + justifyContent: 'center', + }, + thumb: { + width: THUMB_SIZE, + height: THUMB_SIZE, + }, +}); diff --git a/packages/react-native/src/components/DTTextInput.tsx b/packages/react-native/src/components/DTTextInput.tsx new file mode 100644 index 0000000..6bf951b --- /dev/null +++ b/packages/react-native/src/components/DTTextInput.tsx @@ -0,0 +1,172 @@ +/** + * DT TextInput Component + * + * A themed text input wrapping React Native Paper's TextInput + * with the Dangerous Things angular aesthetic. + * + * Web CSS reference (.mode-input): + * - 2px solid border in mode color + * - Focus: box-shadow 0 4px 0 1px var(--mode) + * - border-radius: 0 + */ + +import {useState, useRef, useEffect} from 'react'; +import { + StyleSheet, + View, + ViewStyle, + TextStyle, + StyleProp, + Animated, +} from 'react-native'; +import {TextInput, TextInputProps} from 'react-native-paper'; +import {DTColors} from '../theme/colors'; +import {type DTVariant, getVariantColor} from '../utils/variantColors'; + +interface DTTextInputProps + extends Omit { + /** + * Visual variant + * @default 'normal' + */ + variant?: DTVariant; + /** + * Custom color (overrides variant) + */ + color?: string; + /** + * Border width + * @default 2 + */ + borderWidth?: number; + /** + * Whether the input is in error state + */ + error?: boolean; + /** + * Error message text displayed below input + */ + errorMessage?: string; + /** + * Additional styles for the outer wrapper + */ + containerStyle?: StyleProp; + /** + * Additional styles for the input text + */ + inputStyle?: StyleProp; +} + +/** + * DT-styled TextInput wrapping React Native Paper TextInput + * + * @example + * + * + * @example + * + */ +export function DTTextInput({ + variant = 'normal', + color, + borderWidth = 2, + error = false, + errorMessage, + containerStyle, + inputStyle, + onFocus, + onBlur, + style, + ...props +}: DTTextInputProps) { + const [focused, setFocused] = useState(false); + const focusAnim = useRef(new Animated.Value(0)).current; + + const accentColor = error + ? DTColors.modeWarning + : getVariantColor(variant, color); + + useEffect(() => { + const anim = Animated.timing(focusAnim, { + toValue: focused ? 1 : 0, + duration: 150, + useNativeDriver: false, + }); + anim.start(); + return () => anim.stop(); + }, [focused, focusAnim]); + + return ( + + + { + setFocused(true); + onFocus?.(e); + }} + onBlur={e => { + setFocused(false); + onBlur?.(e); + }} + style={[styles.input, inputStyle, style]} + textColor={DTColors.light} + placeholderTextColor={DTColors.disabled} + activeUnderlineColor="transparent" + underlineColor="transparent" + theme={{ + colors: { + primary: accentColor, + onSurfaceVariant: accentColor, + }, + roundness: 0, + }} + /> + + {/* Focus glow bar — simulates web box-shadow: 0 4px 0 1px */} + + {error && errorMessage && ( + + + {errorMessage} + + + )} + + ); +} + +const styles = StyleSheet.create({ + inputWrapper: { + backgroundColor: DTColors.dark, + }, + input: { + backgroundColor: 'transparent', + }, + focusBar: { + height: 4, + marginTop: 1, + }, + errorContainer: { + marginTop: 4, + paddingHorizontal: 4, + }, + errorText: { + fontSize: 12, + letterSpacing: 0.5, + }, +}); diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts new file mode 100644 index 0000000..d424b7c --- /dev/null +++ b/packages/react-native/src/index.ts @@ -0,0 +1,77 @@ +/** + * @anthropic-dangerous-things/react-native-theme + * + * Dangerous Things design system for React Native with React Native Paper. + * Cyberpunk aesthetic with high-contrast neon colors. + */ + +// Theme exports +export { DTColors, getColor } from './theme/colors'; +export type { DTColorKey } from './theme/colors'; + +export { + DTTypography, + DTFonts, + DTFontWeights, +} from './theme/typography'; +export type { DTTypographyKey } from './theme/typography'; + +export { + DTDarkTheme, + DTExtendedDarkTheme, + usePaperTheme, +} from './theme/paperTheme'; +export type { DTExtendedTheme } from './theme/paperTheme'; + +export { DTThemeProvider, useDTTheme } from './theme/DTThemeProvider'; + +// Shared utilities +export type { DTVariant } from './utils/variantColors'; +export { variantColorMap, getVariantColor } from './utils/variantColors'; +export { buildBeveledRectPath } from './utils/bevelPaths'; +export { useComponentLayout } from './utils/useComponentLayout'; + +// Component exports — existing +export { DTCard, DTCardClipPath } from './components/DTCard'; +export { DTButton } from './components/DTButton'; +export { DTChip } from './components/DTChip'; +export { DTLabel, DTLabelClipPath } from './components/DTLabel'; + +// Component exports — form primitives +export { DTTextInput } from './components/DTTextInput'; +export { DTCheckbox } from './components/DTCheckbox'; +export { DTSwitch } from './components/DTSwitch'; +export { DTRadioGroup, DTRadioOption } from './components/DTRadioGroup'; +export { DTQuantityStepper } from './components/DTQuantityStepper'; + +// Component exports — layout & containers +export { DTProgressBar } from './components/DTProgressBar'; +export { DTMediaFrame } from './components/DTMediaFrame'; +export { DTAccordion } from './components/DTAccordion'; +export type { DTAccordionSection } from './components/DTAccordion'; + +// Component exports — complex interactive +export { DTModal } from './components/DTModal'; +export { DTDrawer } from './components/DTDrawer'; +export { DTGallery } from './components/DTGallery'; +export type { DTGalleryItem } from './components/DTGallery'; +export { DTSearchInput } from './components/DTSearchInput'; + +// Component exports — navigation & decorative +export { DTMenu, DTMenuDropdown } from './components/DTMenu'; +export type { DTMenuItem } from './components/DTMenu'; +export { DTHexagon } from './components/DTHexagon'; + +// Re-export commonly used Paper components for convenience +export { + Text, + Surface, + IconButton, + ActivityIndicator, + Divider, + List, + Portal, + Modal, + Snackbar, + TextInput, +} from 'react-native-paper'; diff --git a/packages/react-native/src/theme/DTThemeProvider.tsx b/packages/react-native/src/theme/DTThemeProvider.tsx new file mode 100644 index 0000000..cc4c0ee --- /dev/null +++ b/packages/react-native/src/theme/DTThemeProvider.tsx @@ -0,0 +1,80 @@ +/** + * DT Theme Provider + * + * Wraps your app with the Dangerous Things theme. + * Combines React Native Paper's PaperProvider with + * custom theme context for extended DT colors. + */ + +import { createContext, useContext, ReactNode } from 'react'; +import { PaperProvider } from 'react-native-paper'; +import { SafeAreaProvider } from 'react-native-safe-area-context'; +import { StatusBar } from 'react-native'; +import { DTExtendedDarkTheme, DTExtendedTheme } from './paperTheme'; + +/** + * Context for accessing extended theme properties + */ +const DTThemeContext = createContext(DTExtendedDarkTheme); + +/** + * Hook to access the full DT theme including custom properties + * + * @example + * const theme = useDTTheme(); + * const successColor = theme.custom.success; + */ +export function useDTTheme(): DTExtendedTheme { + return useContext(DTThemeContext); +} + +interface DTThemeProviderProps { + children: ReactNode; + /** + * Override the default theme (useful for testing or custom variants) + */ + theme?: DTExtendedTheme; + /** + * Include SafeAreaProvider wrapper (default: true) + * Set to false if you already have SafeAreaProvider higher in tree + */ + includeSafeArea?: boolean; +} + +/** + * Theme provider component + * + * @example + * // In your App.tsx + * import { DTThemeProvider } from '@anthropic-dangerous-things/react-native-theme'; + * + * export default function App() { + * return ( + * + * + * + * + * + * ); + * } + */ +export function DTThemeProvider({ + children, + theme = DTExtendedDarkTheme, + includeSafeArea = true, +}: DTThemeProviderProps) { + const content = ( + + + + {children} + + + ); + + if (includeSafeArea) { + return {content}; + } + + return content; +} diff --git a/packages/react-native/src/theme/colors.ts b/packages/react-native/src/theme/colors.ts new file mode 100644 index 0000000..bc26efa --- /dev/null +++ b/packages/react-native/src/theme/colors.ts @@ -0,0 +1,69 @@ +/** + * Dangerous Things Color Palette + * + * Based on the dt-shopify-storefront design system. + * Cyberpunk aesthetic with high-contrast neon colors on dark backgrounds. + */ + +export const DTColors = { + // Base colors + dark: '#000000', + light: '#FFFFFF', + + // Mode colors (primary semantic palette) + modeNormal: '#00FFFF', // Cyan - primary actions, links, borders + modeNormalSelected: 'rgba(0, 255, 255, 0.7)', + modeEmphasis: '#FFFF00', // Yellow - highlights, emphasis, headers + modeEmphasisSelected: 'rgba(255, 255, 0, 0.7)', + modeWarning: '#FF0000', // Red - errors, warnings, destructive actions + modeSuccess: '#00FF00', // Green - success states, confirmations + modeOther: '#FF00FF', // Magenta - miscellaneous, secondary info + + // Semantic aliases + primary: '#00FFFF', + primaryVariant: 'rgba(0, 255, 255, 0.7)', + secondary: '#FFFF00', + secondaryVariant: 'rgba(255, 255, 0, 0.7)', + error: '#FF0000', + success: '#00FF00', + + // Surface colors + background: '#000000', + surface: '#000000', + surfaceVariant: '#070707', + + // Text colors + onBackground: '#FFFFFF', + onSurface: '#FFFFFF', + onPrimary: '#000000', + onSecondary: '#000000', + onError: '#000000', + + // Border colors + border: '#00FFFF', + borderEmphasis: '#FFFF00', + + // Transparency variants (for overlays, disabled states) + overlay: 'rgba(0, 0, 0, 0.7)', + disabled: 'rgba(255, 255, 255, 0.3)', + disabledBackground: 'rgba(255, 255, 255, 0.1)', +} as const; + +export type DTColorKey = keyof typeof DTColors; + +/** + * Get a color with optional opacity override + */ +export function getColor(color: DTColorKey, opacity?: number): string { + const baseColor = DTColors[color]; + if (opacity === undefined || baseColor.startsWith('rgba')) { + return baseColor; + } + + // Convert hex to rgba + const hex = baseColor.replace('#', ''); + const r = parseInt(hex.substring(0, 2), 16); + const g = parseInt(hex.substring(2, 4), 16); + const b = parseInt(hex.substring(4, 6), 16); + return `rgba(${r}, ${g}, ${b}, ${opacity})`; +} diff --git a/packages/react-native/src/theme/paperTheme.ts b/packages/react-native/src/theme/paperTheme.ts new file mode 100644 index 0000000..2162341 --- /dev/null +++ b/packages/react-native/src/theme/paperTheme.ts @@ -0,0 +1,149 @@ +/** + * React Native Paper MD3 Theme Configuration + * + * This creates a Material Design 3 compliant theme that follows + * the Dangerous Things cyberpunk aesthetic while respecting + * React Native Paper's design principles. + */ + +import { MD3DarkTheme, MD3Theme, configureFonts } from 'react-native-paper'; +import { DTColors } from './colors'; +import { DTTypography, DTFonts } from './typography'; + +/** + * MD3 Font configuration for React Native Paper + * Maps our typography to RNP's expected font config + */ +const fontConfig = { + fontFamily: DTFonts.regular, + displayLarge: DTTypography.displayLarge, + displayMedium: DTTypography.displayMedium, + displaySmall: DTTypography.displaySmall, + headlineLarge: DTTypography.headlineLarge, + headlineMedium: DTTypography.headlineMedium, + headlineSmall: DTTypography.headlineSmall, + titleLarge: DTTypography.titleLarge, + titleMedium: DTTypography.titleMedium, + titleSmall: DTTypography.titleSmall, + bodyLarge: DTTypography.bodyLarge, + bodyMedium: DTTypography.bodyMedium, + bodySmall: DTTypography.bodySmall, + labelLarge: DTTypography.labelLarge, + labelMedium: DTTypography.labelMedium, + labelSmall: DTTypography.labelSmall, +}; + +/** + * Dangerous Things Dark Theme + * + * Based on MD3DarkTheme with cyberpunk color overrides. + * Primary = Cyan, Secondary = Yellow (following DT brand) + */ +export const DTDarkTheme: MD3Theme = { + ...MD3DarkTheme, + dark: true, + roundness: 4, // Slightly rounded, but we use custom clip-path for bevels + + fonts: configureFonts({ config: fontConfig }), + + colors: { + ...MD3DarkTheme.colors, + + // Primary (Cyan) + primary: DTColors.modeNormal, + onPrimary: DTColors.dark, + primaryContainer: DTColors.modeNormalSelected, + onPrimaryContainer: DTColors.dark, + + // Secondary (Yellow) + secondary: DTColors.modeEmphasis, + onSecondary: DTColors.dark, + secondaryContainer: DTColors.modeEmphasisSelected, + onSecondaryContainer: DTColors.dark, + + // Tertiary (Magenta) + tertiary: DTColors.modeOther, + onTertiary: DTColors.dark, + tertiaryContainer: 'rgba(255, 0, 255, 0.3)', + onTertiaryContainer: DTColors.light, + + // Error (Red) + error: DTColors.modeWarning, + onError: DTColors.dark, + errorContainer: 'rgba(255, 0, 0, 0.3)', + onErrorContainer: DTColors.light, + + // Background & Surface + background: DTColors.background, + onBackground: DTColors.onBackground, + surface: DTColors.surface, + onSurface: DTColors.onSurface, + surfaceVariant: DTColors.surfaceVariant, + onSurfaceVariant: DTColors.light, + + // Surface elevation (MD3 uses tonal elevation) + elevation: { + level0: 'transparent', + level1: DTColors.surfaceVariant, + level2: '#0a0a0a', + level3: '#0f0f0f', + level4: '#121212', + level5: '#151515', + }, + + // Outline (borders) + outline: DTColors.modeNormal, + outlineVariant: 'rgba(0, 255, 255, 0.5)', + + // Inverse (for snackbars, etc.) + inverseSurface: DTColors.light, + inverseOnSurface: DTColors.dark, + inversePrimary: '#008B8B', // Darker cyan for light backgrounds + + // Misc + shadow: DTColors.dark, + scrim: DTColors.overlay, + surfaceDisabled: DTColors.disabledBackground, + onSurfaceDisabled: DTColors.disabled, + backdrop: DTColors.overlay, + }, +}; + +/** + * Extended theme with DT-specific custom properties + * Use this when you need access to non-MD3 colors + */ +export interface DTExtendedTheme extends MD3Theme { + custom: { + success: string; + warning: string; + modeNormal: string; + modeEmphasis: string; + modeWarning: string; + modeSuccess: string; + modeOther: string; + border: string; + borderEmphasis: string; + }; +} + +export const DTExtendedDarkTheme: DTExtendedTheme = { + ...DTDarkTheme, + custom: { + success: DTColors.modeSuccess, + warning: DTColors.modeWarning, + modeNormal: DTColors.modeNormal, + modeEmphasis: DTColors.modeEmphasis, + modeWarning: DTColors.modeWarning, + modeSuccess: DTColors.modeSuccess, + modeOther: DTColors.modeOther, + border: DTColors.border, + borderEmphasis: DTColors.borderEmphasis, + }, +}; + +/** + * Hook to access extended theme properties + * Usage: const { custom } = useDTTheme(); + */ +export { useTheme as usePaperTheme } from 'react-native-paper'; diff --git a/packages/react-native/src/theme/typography.ts b/packages/react-native/src/theme/typography.ts new file mode 100644 index 0000000..37fefcd --- /dev/null +++ b/packages/react-native/src/theme/typography.ts @@ -0,0 +1,190 @@ +/** + * Dangerous Things Typography + * + * Primary font: Tektur (variable font) + * Fallback: System default sans-serif + * + * Note: To use Tektur, you must: + * 1. Download Tektur from Google Fonts + * 2. Add to your project's assets/fonts/ + * 3. Link fonts in react-native.config.js or use expo-font + */ + +import { Platform, TextStyle } from 'react-native'; + +/** + * Font family configuration + * Tektur is a variable font with weights 100-900 + */ +export const DTFonts = { + regular: Platform.select({ + ios: 'Tektur', + android: 'Tektur-Regular', + default: 'Tektur', + }), + medium: Platform.select({ + ios: 'Tektur', + android: 'Tektur-Medium', + default: 'Tektur', + }), + bold: Platform.select({ + ios: 'Tektur', + android: 'Tektur-Bold', + default: 'Tektur', + }), + // Fallback when Tektur is not available + fallback: Platform.select({ + ios: 'System', + android: 'sans-serif', + default: 'sans-serif', + }), +} as const; + +/** + * Font weights for variable font + */ +export const DTFontWeights = { + thin: '100' as const, + light: '300' as const, + regular: '400' as const, + medium: '500' as const, + semibold: '600' as const, + bold: '700' as const, + extrabold: '800' as const, + black: '900' as const, +}; + +/** + * Base text styles + */ +const baseTextStyle: TextStyle = { + fontFamily: DTFonts.regular, + color: '#FFFFFF', + letterSpacing: 0.5, +}; + +/** + * Typography scale following Material Design 3 naming + */ +export const DTTypography = { + // Display styles (large headlines) + displayLarge: { + ...baseTextStyle, + fontSize: 57, + fontWeight: DTFontWeights.bold, + lineHeight: 64, + letterSpacing: -0.25, + } as TextStyle, + + displayMedium: { + ...baseTextStyle, + fontSize: 45, + fontWeight: DTFontWeights.bold, + lineHeight: 52, + } as TextStyle, + + displaySmall: { + ...baseTextStyle, + fontSize: 36, + fontWeight: DTFontWeights.bold, + lineHeight: 44, + } as TextStyle, + + // Headline styles + headlineLarge: { + ...baseTextStyle, + fontSize: 32, + fontWeight: DTFontWeights.semibold, + lineHeight: 40, + } as TextStyle, + + headlineMedium: { + ...baseTextStyle, + fontSize: 28, + fontWeight: DTFontWeights.semibold, + lineHeight: 36, + } as TextStyle, + + headlineSmall: { + ...baseTextStyle, + fontSize: 24, + fontWeight: DTFontWeights.semibold, + lineHeight: 32, + } as TextStyle, + + // Title styles + titleLarge: { + ...baseTextStyle, + fontSize: 22, + fontWeight: DTFontWeights.medium, + lineHeight: 28, + } as TextStyle, + + titleMedium: { + ...baseTextStyle, + fontSize: 16, + fontWeight: DTFontWeights.medium, + lineHeight: 24, + letterSpacing: 0.15, + } as TextStyle, + + titleSmall: { + ...baseTextStyle, + fontSize: 14, + fontWeight: DTFontWeights.medium, + lineHeight: 20, + letterSpacing: 0.1, + } as TextStyle, + + // Body styles + bodyLarge: { + ...baseTextStyle, + fontSize: 16, + fontWeight: DTFontWeights.regular, + lineHeight: 24, + letterSpacing: 0.5, + } as TextStyle, + + bodyMedium: { + ...baseTextStyle, + fontSize: 14, + fontWeight: DTFontWeights.regular, + lineHeight: 20, + letterSpacing: 0.25, + } as TextStyle, + + bodySmall: { + ...baseTextStyle, + fontSize: 12, + fontWeight: DTFontWeights.regular, + lineHeight: 16, + letterSpacing: 0.4, + } as TextStyle, + + // Label styles + labelLarge: { + ...baseTextStyle, + fontSize: 14, + fontWeight: DTFontWeights.medium, + lineHeight: 20, + letterSpacing: 0.1, + } as TextStyle, + + labelMedium: { + ...baseTextStyle, + fontSize: 12, + fontWeight: DTFontWeights.medium, + lineHeight: 16, + letterSpacing: 0.5, + } as TextStyle, + + labelSmall: { + ...baseTextStyle, + fontSize: 11, + fontWeight: DTFontWeights.medium, + lineHeight: 16, + letterSpacing: 0.5, + } as TextStyle, +} as const; + +export type DTTypographyKey = keyof typeof DTTypography; diff --git a/packages/react-native/src/utils/bevelPaths.ts b/packages/react-native/src/utils/bevelPaths.ts new file mode 100644 index 0000000..0f75dc1 --- /dev/null +++ b/packages/react-native/src/utils/bevelPaths.ts @@ -0,0 +1,152 @@ +/** + * Shared SVG bevel path builders + * + * Generic and preset functions for generating SVG path data + * for beveled rectangle shapes used across DT components. + */ + +type BevelCorner = 'topLeft' | 'topRight' | 'bottomRight' | 'bottomLeft'; + +interface BevelConfig { + corners: Partial>; + strokeWidth?: number; + /** Additional inset applied to all coordinates (used for frame overlays) */ + offset?: number; +} + +/** + * Build an SVG path for a rectangle with any combination of beveled corners. + * + * Each corner can have an independent bevel size. Corners without a bevel + * value (or with 0) are rendered as sharp 90-degree angles. + */ +export function buildBeveledRectPath( + width: number, + height: number, + config: BevelConfig, +): string { + const sw = config.strokeWidth ?? 0; + const off = config.offset ?? 0; + const inset = sw / 2 + off; + const w = width - sw - off * 2; + const h = height - sw - off * 2; + + if (w <= 0 || h <= 0) return ''; + + const maxBevel = Math.min(w / 3, h / 3); + const tl = Math.min(config.corners.topLeft ?? 0, maxBevel); + const tr = Math.min(config.corners.topRight ?? 0, maxBevel); + const br = Math.min(config.corners.bottomRight ?? 0, maxBevel); + const bl = Math.min(config.corners.bottomLeft ?? 0, maxBevel); + + // Build path clockwise from top-left + return [ + // Top-left corner + `M ${inset + tl} ${inset}`, + // Top edge → top-right corner + `L ${w + inset - tr} ${inset}`, + tr > 0 ? `L ${w + inset} ${inset + tr}` : `L ${w + inset} ${inset}`, + // Right edge → bottom-right corner + br > 0 + ? `L ${w + inset} ${h + inset - br} L ${w + inset - br} ${h + inset}` + : `L ${w + inset} ${h + inset}`, + // Bottom edge → bottom-left corner + bl > 0 + ? `L ${inset + bl} ${h + inset} L ${inset} ${h + inset - bl}` + : `L ${inset} ${h + inset}`, + // Left edge → back to top-left + tl > 0 ? `L ${inset} ${inset + tl}` : `L ${inset} ${inset}`, + 'Z', + ].join(' '); +} + +/** + * DTButton shape: bottom-right bevel only + */ +export function buildButtonBevelPath( + width: number, + height: number, + bevelSize: number, + strokeWidth: number, +): string { + return buildBeveledRectPath(width, height, { + corners: {bottomRight: bevelSize}, + strokeWidth, + }); +} + +/** + * DTCard shape: bottom-right (large) + bottom-left (small) bevels + */ +export function buildCardBevelPath( + width: number, + height: number, + bevelBR: number, + bevelBL: number, + inset: number, +): string { + const w = width - inset * 2; + const h = height - inset * 2; + + if (w <= 0 || h <= 0) return ''; + + const br = Math.min(bevelBR, w / 3, h / 3); + const bl = Math.min(bevelBL, w / 3, h / 3); + + return ` + M ${inset} ${inset} + L ${w + inset} ${inset} + L ${w + inset} ${h - br + inset} + L ${w - br + inset} ${h + inset} + L ${bl + inset} ${h + inset} + L ${inset} ${h - bl + inset} + Z + `; +} + +/** + * DTLabel shape: top-right bevel only + */ +export function buildLabelBevelPath( + width: number, + height: number, + bevelSize: number, +): string { + return buildBeveledRectPath(width, height, { + corners: {topRight: bevelSize}, + }); +} + +/** + * DTMediaFrame shape: top-left + bottom-right (diagonal symmetry) + */ +export function buildMediaFrameBevelPath( + width: number, + height: number, + bevelSize: number, + offset = 0, +): string { + return buildBeveledRectPath(width, height, { + corners: {topLeft: bevelSize, bottomRight: bevelSize}, + offset, + }); +} + +/** + * DTDrawer shape (right-side): top-left + bottom-left bevels + */ +export function buildDrawerBevelPath( + width: number, + height: number, + bevelSize: number, + position: 'left' | 'right' = 'right', +): string { + if (position === 'right') { + return buildBeveledRectPath(width, height, { + corners: {topLeft: bevelSize, bottomLeft: bevelSize}, + }); + } + return buildBeveledRectPath(width, height, { + corners: {topRight: bevelSize, bottomRight: bevelSize}, + }); +} diff --git a/packages/react-native/src/utils/useComponentLayout.ts b/packages/react-native/src/utils/useComponentLayout.ts new file mode 100644 index 0000000..3abeff7 --- /dev/null +++ b/packages/react-native/src/utils/useComponentLayout.ts @@ -0,0 +1,33 @@ +/** + * Shared layout measurement hook + * + * Extracts the common pattern of tracking component dimensions + * via onLayout for SVG rendering. + */ + +import {useState, useCallback} from 'react'; +import {LayoutChangeEvent} from 'react-native'; + +interface ComponentDimensions { + width: number; + height: number; +} + +export function useComponentLayout() { + const [dimensions, setDimensions] = useState({ + width: 0, + height: 0, + }); + + const onLayout = useCallback((event: LayoutChangeEvent) => { + const {width, height} = event.nativeEvent.layout; + setDimensions(prev => { + if (prev.width === width && prev.height === height) return prev; + return {width, height}; + }); + }, []); + + const hasDimensions = dimensions.width > 0 && dimensions.height > 0; + + return {dimensions, onLayout, hasDimensions}; +} diff --git a/packages/react-native/src/utils/variantColors.ts b/packages/react-native/src/utils/variantColors.ts new file mode 100644 index 0000000..324fb97 --- /dev/null +++ b/packages/react-native/src/utils/variantColors.ts @@ -0,0 +1,27 @@ +/** + * Centralized variant type and color mapping + * + * Used by all DT components for consistent mode/variant color resolution. + */ + +import {DTColors} from '../theme/colors'; + +export type DTVariant = 'normal' | 'emphasis' | 'warning' | 'success' | 'other'; + +export const variantColorMap: Record = { + normal: DTColors.modeNormal, + emphasis: DTColors.modeEmphasis, + warning: DTColors.modeWarning, + success: DTColors.modeSuccess, + other: DTColors.modeOther, +}; + +/** + * Resolve variant to color, with optional custom color override. + */ +export function getVariantColor( + variant: DTVariant, + customColor?: string, +): string { + return customColor ?? variantColorMap[variant]; +} diff --git a/packages/react-native/tsconfig.json b/packages/react-native/tsconfig.json new file mode 100644 index 0000000..498e325 --- /dev/null +++ b/packages/react-native/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "jsx": "react-jsx", + "lib": ["ES2022"], + "allowSyntheticDefaultImports": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/tokens/package.json b/packages/tokens/package.json new file mode 100644 index 0000000..32599b9 --- /dev/null +++ b/packages/tokens/package.json @@ -0,0 +1,36 @@ +{ + "name": "@dangerousthings/tokens", + "version": "0.1.0", + "description": "Canonical design tokens for the Dangerous Things design system", + "license": "MIT", + "type": "module", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + }, + "./brands/*": { + "types": "./dist/brands/*.d.ts", + "import": "./dist/brands/*.js" + }, + "./css/*": "./dist/css/*" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "publishConfig": { + "access": "public" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsc && node dist/scripts/generate-css.js", + "clean": "rm -rf dist", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@types/node": "^25.3.3", + "typescript": "^5.7.0" + } +} diff --git a/packages/tokens/src/brands/classic.ts b/packages/tokens/src/brands/classic.ts new file mode 100644 index 0000000..0c78530 --- /dev/null +++ b/packages/tokens/src/brands/classic.ts @@ -0,0 +1,66 @@ +import type { BrandTokens } from "../types.js"; + +export const classic: BrandTokens = { + id: "classic", + name: "Classic Cyberpunk", + description: "Original dark navy aesthetic with magenta accents", + + dark: { + bg: "#0a0e1a", + surface: "#121827", + surfaceHover: "#1a2332", + border: "#1e293b", + + textPrimary: "#e2e8f0", + textSecondary: "#94a3b8", + textMuted: "#64748b", + + primary: "#00ffff", + primaryDim: "#0891b2", + secondary: "#ff00ff", + accent: "#00ff88", + other: "#ff00ff", + + success: "#00ff88", + warning: "#ffaa00", + error: "#ff0055", + info: "#00ffff", + }, + + light: { + bg: "#ffffff", + surface: "#f8fafc", + surfaceHover: "#f1f5f9", + border: "#e2e8f0", + + textPrimary: "#0f172a", + textSecondary: "#475569", + textMuted: "#94a3b8", + + primary: "#0891b2", + primaryDim: "#0e7490", + secondary: "#c026d3", + accent: "#00ff88", + other: "#c026d3", + + success: "#16a34a", + warning: "#d97706", + error: "#dc2626", + info: "#0891b2", + }, + + typography: { + heading: "var(--font-sans)", + body: "var(--font-sans)", + mono: "'SF Mono', Monaco, 'Cascadia Code', monospace", + }, + + shape: { + bevelSm: "0px", + bevelMd: "0px", + bevelLg: "0px", + radiusSm: "0.25rem", + radius: "0.5rem", + radiusLg: "0.75rem", + }, +}; diff --git a/packages/tokens/src/brands/dt.ts b/packages/tokens/src/brands/dt.ts new file mode 100644 index 0000000..2ef9d07 --- /dev/null +++ b/packages/tokens/src/brands/dt.ts @@ -0,0 +1,66 @@ +import type { BrandTokens } from "../types.js"; + +export const dt: BrandTokens = { + id: "dt", + name: "Dangerous Things", + description: "Official DT brand — Tektur font, neon cyberpunk, beveled corners", + + dark: { + bg: "#000000", + surface: "#0a0a0a", + surfaceHover: "#141414", + border: "#00ffff", + + textPrimary: "#ffffff", + textSecondary: "#e2e8f0", + textMuted: "#94a3b8", + + primary: "#00ffff", + primaryDim: "#0891b2", + secondary: "#ffff00", + accent: "#00ff00", + other: "#ff00ff", + + success: "#00ff00", + warning: "#ffff00", + error: "#ff0000", + info: "#00ffff", + }, + + light: { + bg: "#ffffff", + surface: "#f8fafc", + surfaceHover: "#f1f5f9", + border: "#000000", + + textPrimary: "#000000", + textSecondary: "#475569", + textMuted: "#94a3b8", + + primary: "#0891b2", + primaryDim: "#0e7490", + secondary: "#a16207", + accent: "#15803d", + other: "#ff00ff", + + success: "#15803d", + warning: "#a16207", + error: "#dc2626", + info: "#0891b2", + }, + + typography: { + heading: "'Tektur', var(--font-sans)", + body: "'Tektur', var(--font-sans)", + mono: "'SF Mono', Monaco, 'Cascadia Code', monospace", + }, + + shape: { + bevelSm: "1rem", + bevelMd: "2rem", + bevelLg: "2.5rem", + radiusSm: "0", + radius: "0", + radiusLg: "0", + }, +}; diff --git a/packages/tokens/src/brands/supra.ts b/packages/tokens/src/brands/supra.ts new file mode 100644 index 0000000..40d5cc4 --- /dev/null +++ b/packages/tokens/src/brands/supra.ts @@ -0,0 +1,66 @@ +import type { BrandTokens } from "../types.js"; + +export const supra: BrandTokens = { + id: "supra", + name: "VivoKey Supra", + description: "Material Design 3 with VivoKey blue, rounded corners, elevation shadows", + + dark: { + bg: "#000000", + surface: "#28292E", + surfaceHover: "#303136", + border: "#42667E", + + textPrimary: "#ffffff", + textSecondary: "#e2e8f0", + textMuted: "#94a3b8", + + primary: "#42667E", + primaryDim: "#385872", + secondary: "#8BAEC7", + accent: "#8BAEC7", + other: "#F67448", + + success: "#8BB174", + warning: "#F67448", + error: "#ED4337", + info: "#42667E", + }, + + light: { + bg: "#ffffff", + surface: "#AFB8C2", + surfaceHover: "#C5CCD4", + border: "#000000", + + textPrimary: "#000000", + textSecondary: "#374151", + textMuted: "#6b7280", + + primary: "#000000", + primaryDim: "#1f2937", + secondary: "#F67448", + accent: "#FDFE1B", + other: "#F67448", + + success: "#8BB174", + warning: "#F67448", + error: "#ED4337", + info: "#42667E", + }, + + typography: { + heading: "var(--font-sans)", + body: "var(--font-sans)", + mono: "'SF Mono', Monaco, 'Cascadia Code', monospace", + }, + + shape: { + bevelSm: "0px", + bevelMd: "0px", + bevelLg: "0px", + radiusSm: "0.5rem", + radius: "0.625rem", + radiusLg: "0.75rem", + }, +}; diff --git a/packages/tokens/src/index.ts b/packages/tokens/src/index.ts new file mode 100644 index 0000000..a27a127 --- /dev/null +++ b/packages/tokens/src/index.ts @@ -0,0 +1,46 @@ +export type { + ThemeBrand, + ThemeMode, + ThemeDefinition, + ColorTokens, + TypographyTokens, + ShapeTokens, + BrandTokens, +} from "./types.js"; + +export { dt } from "./brands/dt.js"; +export { classic } from "./brands/classic.js"; +export { supra } from "./brands/supra.js"; + +import { dt } from "./brands/dt.js"; +import { classic } from "./brands/classic.js"; +import { supra } from "./brands/supra.js"; +import type { BrandTokens, ThemeDefinition } from "./types.js"; + +/** All brand tokens keyed by id */ +export const brands: Record = { dt, classic, supra }; + +/** Theme registry for UI selectors */ +export const themes: ThemeDefinition[] = [ + { + id: "dt", + name: dt.name, + description: dt.description, + supportsModes: ["dark", "light", "auto"], + defaultMode: "dark", + }, + { + id: "classic", + name: classic.name, + description: classic.description, + supportsModes: ["dark", "light", "auto"], + defaultMode: "dark", + }, + { + id: "supra", + name: supra.name, + description: supra.description, + supportsModes: ["dark", "light", "auto"], + defaultMode: "dark", + }, +]; diff --git a/packages/tokens/src/scripts/generate-css.ts b/packages/tokens/src/scripts/generate-css.ts new file mode 100644 index 0000000..7180787 --- /dev/null +++ b/packages/tokens/src/scripts/generate-css.ts @@ -0,0 +1,129 @@ +/** + * Generates CSS custom property files from canonical TypeScript token definitions. + * Run via: node dist/scripts/generate-css.js + * Output: dist/css/{brand}.css + */ +import { writeFileSync, mkdirSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import type { BrandTokens, ColorTokens } from "../types.js"; +import { dt } from "../brands/dt.js"; +import { classic } from "../brands/classic.js"; +import { supra } from "../brands/supra.js"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const outDir = join(__dirname, "..", "css"); + +/** Convert hex #rrggbb to "r, g, b" triplet for rgba() usage */ +function hexToRgb(hex: string): string { + const h = hex.replace("#", ""); + const r = parseInt(h.substring(0, 2), 16); + const g = parseInt(h.substring(2, 4), 16); + const b = parseInt(h.substring(4, 6), 16); + return `${r}, ${g}, ${b}`; +} + +/** Generate CSS custom properties from color tokens */ +function colorVars(colors: ColorTokens): string { + return ` /* Backgrounds */ + --color-bg: ${colors.bg}; + --color-bg-rgb: ${hexToRgb(colors.bg)}; + --color-surface: ${colors.surface}; + --color-surface-rgb: ${hexToRgb(colors.surface)}; + --color-surface-hover: ${colors.surfaceHover}; + --color-border: ${colors.border}; + + /* Text */ + --color-text-primary: ${colors.textPrimary}; + --color-text-secondary: ${colors.textSecondary}; + --color-text-muted: ${colors.textMuted}; + + /* Brand Palette */ + --color-primary: ${colors.primary}; + --color-primary-rgb: ${hexToRgb(colors.primary)}; + --color-primary-dim: ${colors.primaryDim}; + --color-secondary: ${colors.secondary}; + --color-secondary-rgb: ${hexToRgb(colors.secondary)}; + --color-accent: ${colors.accent}; + --color-accent-rgb: ${hexToRgb(colors.accent)}; + --color-other: ${colors.other}; + --color-other-rgb: ${hexToRgb(colors.other)}; + + /* Status */ + --color-success: ${colors.success}; + --color-success-rgb: ${hexToRgb(colors.success)}; + --color-warning: ${colors.warning}; + --color-warning-rgb: ${hexToRgb(colors.warning)}; + --color-error: ${colors.error}; + --color-error-rgb: ${hexToRgb(colors.error)}; + --color-info: ${colors.info}; + --color-info-rgb: ${hexToRgb(colors.info)};`; +} + +/** Generate a full brand CSS file */ +function generateBrandCSS(brand: BrandTokens): string { + const id = brand.id; + + // DT is also the default (when no data-brand is set) + const darkSelector = + id === "dt" + ? `:root[data-brand="${id}"],\n:root:not([data-brand])` + : `:root[data-brand="${id}"]`; + + let css = `/* @dangerousthings/tokens — Generated CSS for "${brand.name}" */\n/* DO NOT EDIT — regenerate with: npm run build -w packages/tokens */\n\n`; + + // Dark mode (default) + css += `/* ${brand.name} — Dark Mode (Default) */\n`; + css += `${darkSelector} {\n`; + css += colorVars(brand.dark) + "\n\n"; + css += ` /* Typography */\n`; + css += ` --font-heading: ${brand.typography.heading};\n`; + css += ` --font-body: ${brand.typography.body};\n\n`; + css += ` /* Shape */\n`; + css += ` --bevel-sm: ${brand.shape.bevelSm};\n`; + css += ` --bevel-md: ${brand.shape.bevelMd};\n`; + css += ` --bevel-lg: ${brand.shape.bevelLg};\n`; + css += ` --radius-sm: ${brand.shape.radiusSm};\n`; + css += ` --radius: ${brand.shape.radius};\n`; + css += ` --radius-lg: ${brand.shape.radiusLg};\n\n`; + css += ` color-scheme: dark;\n`; + css += `}\n\n`; + + // Light mode (explicit) + css += `/* ${brand.name} — Light Mode */\n`; + css += `:root[data-brand="${id}"][data-theme="light"] {\n`; + css += colorVars(brand.light) + "\n\n"; + css += ` color-scheme: light;\n`; + css += `}\n\n`; + + // Auto mode (prefers-color-scheme) + css += `/* ${brand.name} — Auto Mode (follows system preference) */\n`; + css += `@media (prefers-color-scheme: light) {\n`; + css += ` :root[data-brand="${id}"][data-theme="auto"] {\n`; + css += colorVars(brand.light).replace(/^/gm, " ") + "\n\n"; + css += ` color-scheme: light;\n`; + css += ` }\n`; + css += `}\n`; + + // DT gets explicit dark override + if (id === "dt") { + css += `\n/* Force dark explicitly */\n`; + css += `:root[data-brand="${id}"][data-theme="dark"] {\n`; + css += ` color-scheme: dark;\n`; + css += `}\n`; + } + + return css; +} + +// --- Main --- +mkdirSync(outDir, { recursive: true }); + +for (const brand of [dt, classic, supra]) { + const css = generateBrandCSS(brand); + const path = join(outDir, `${brand.id}.css`); + writeFileSync(path, css, "utf-8"); + console.log(` tokens: generated ${path}`); +} + +console.log(" tokens: CSS generation complete"); diff --git a/packages/tokens/src/types.ts b/packages/tokens/src/types.ts new file mode 100644 index 0000000..9818bf7 --- /dev/null +++ b/packages/tokens/src/types.ts @@ -0,0 +1,65 @@ +/** Brand identifiers */ +export type ThemeBrand = "dt" | "classic" | "supra"; + +/** Color mode */ +export type ThemeMode = "dark" | "light" | "auto"; + +/** Theme metadata for UI selectors */ +export interface ThemeDefinition { + id: ThemeBrand; + name: string; + description: string; + supportsModes: ThemeMode[]; + defaultMode: ThemeMode; +} + +/** Color tokens for a single mode */ +export interface ColorTokens { + bg: string; + surface: string; + surfaceHover: string; + border: string; + + textPrimary: string; + textSecondary: string; + textMuted: string; + + primary: string; + primaryDim: string; + secondary: string; + accent: string; + other: string; + + success: string; + warning: string; + error: string; + info: string; +} + +/** Typography tokens */ +export interface TypographyTokens { + heading: string; + body: string; + mono: string; +} + +/** Shape tokens */ +export interface ShapeTokens { + bevelSm: string; + bevelMd: string; + bevelLg: string; + radiusSm: string; + radius: string; + radiusLg: string; +} + +/** Complete brand definition */ +export interface BrandTokens { + id: ThemeBrand; + name: string; + description: string; + dark: ColorTokens; + light: ColorTokens; + typography: TypographyTokens; + shape: ShapeTokens; +} diff --git a/packages/tokens/tsconfig.json b/packages/tokens/tsconfig.json new file mode 100644 index 0000000..5a24989 --- /dev/null +++ b/packages/tokens/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"] +} diff --git a/packages/web/fonts/Tektur-VariableFont_wdth,wght.ttf b/packages/web/fonts/Tektur-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..05d4221 Binary files /dev/null and b/packages/web/fonts/Tektur-VariableFont_wdth,wght.ttf differ diff --git a/packages/web/package.json b/packages/web/package.json new file mode 100644 index 0000000..6e2fe8e --- /dev/null +++ b/packages/web/package.json @@ -0,0 +1,30 @@ +{ + "name": "@dangerousthings/web", + "version": "0.1.0", + "description": "Web CSS theme for the Dangerous Things design system — bevels, glows, form styles", + "license": "MIT", + "main": "dist/index.css", + "exports": { + ".": "./dist/index.css", + "./tokens/*": "./dist/tokens/*", + "./components/*": "./dist/components/*", + "./fonts/*": "./dist/fonts/*", + "./theme-registry": { + "types": "./dist/theme-registry.d.ts", + "import": "./dist/theme-registry.js", + "default": "./dist/theme-registry.js" + }, + "./dist/*": "./dist/*" + }, + "publishConfig": { + "access": "public" + }, + "files": ["dist"], + "scripts": { + "build": "node scripts/build.js", + "clean": "rm -rf dist" + }, + "dependencies": { + "@dangerousthings/tokens": "*" + } +} diff --git a/packages/web/scripts/build.js b/packages/web/scripts/build.js new file mode 100644 index 0000000..a9ddc6e --- /dev/null +++ b/packages/web/scripts/build.js @@ -0,0 +1,87 @@ +#!/usr/bin/env node + +/** + * @dangerousthings/web build script + * + * 1. Copies src/ to dist/ (component CSS, base tokens, index.css) + * 2. Copies fonts/ to dist/fonts/ + * 3. Copies generated token CSS from @dangerousthings/tokens/dist/css/ into dist/tokens/ + * 4. Copies theme-registry from @dangerousthings/tokens + * + * Consumers (Vite, webpack) resolve @import chains at build time. + */ + +const fs = require("fs"); +const path = require("path"); + +const root = path.join(__dirname, ".."); +const src = path.join(root, "src"); +const dist = path.join(root, "dist"); +const fontsDir = path.join(root, "fonts"); + +// Resolve @dangerousthings/tokens dist directory +const tokensDir = path.join(root, "..", "tokens", "dist"); + +function copyDir(srcDir, destDir) { + fs.mkdirSync(destDir, { recursive: true }); + for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) { + const srcPath = path.join(srcDir, entry.name); + const destPath = path.join(destDir, entry.name); + if (entry.isDirectory()) { + copyDir(srcPath, destPath); + } else { + fs.copyFileSync(srcPath, destPath); + } + } +} + +// Clean dist +if (fs.existsSync(dist)) { + fs.rmSync(dist, { recursive: true }); +} + +// 1. Copy src → dist +copyDir(src, dist); + +// 2. Copy fonts → dist/fonts +if (fs.existsSync(fontsDir)) { + copyDir(fontsDir, path.join(dist, "fonts")); +} + +// 3. Copy generated token CSS from @dangerousthings/tokens → dist/tokens/ +const tokensCssDir = path.join(tokensDir, "css"); +if (fs.existsSync(tokensCssDir)) { + const destTokens = path.join(dist, "tokens"); + fs.mkdirSync(destTokens, { recursive: true }); + for (const file of fs.readdirSync(tokensCssDir)) { + if (file.endsWith(".css")) { + fs.copyFileSync( + path.join(tokensCssDir, file), + path.join(destTokens, file) + ); + } + } +} else { + console.error("ERROR: @dangerousthings/tokens CSS not found at", tokensCssDir); + console.error("Run: npm run build -w packages/tokens first"); + process.exit(1); +} + +// 4. Copy theme-registry from tokens +const registryFiles = ["theme-registry.js", "theme-registry.d.ts"]; +// The theme-registry is now in @dangerousthings/tokens as index.js — consumers +// import types from @dangerousthings/tokens directly. We generate a thin re-export +// for backward compatibility with dt-web-theme consumers. +const reExport = `// Re-export from @dangerousthings/tokens for backward compatibility +export { themes, brands } from "@dangerousthings/tokens"; +export { DEFAULT_THEME } from "@dangerousthings/tokens"; +`; +const reExportDts = `export { ThemeDefinition, ThemeBrand, ThemeMode } from "@dangerousthings/tokens"; +export declare const themes: import("@dangerousthings/tokens").ThemeDefinition[]; +export declare const brands: Record; +export declare const DEFAULT_THEME: string; +`; +fs.writeFileSync(path.join(dist, "theme-registry.js"), reExport); +fs.writeFileSync(path.join(dist, "theme-registry.d.ts"), reExportDts); + +console.log("@dangerousthings/web: built to dist/"); diff --git a/packages/web/src/base.css b/packages/web/src/base.css new file mode 100644 index 0000000..b0d4e8a --- /dev/null +++ b/packages/web/src/base.css @@ -0,0 +1,31 @@ +/* @dangerousthings/web: Base Tokens (shared across all brands) */ + +:root { + /* Spacing (4px base) */ + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-6: 1.5rem; + --space-8: 2rem; + + /* Transitions */ + --transition-fast: 150ms ease; + --transition: 250ms ease; + + /* Font stacks — brands override --font-heading and --font-body */ + --font-mono: "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, monospace; + --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + --font-heading: var(--font-sans); + --font-body: var(--font-sans); + + /* Border Radius — brands override these */ + --radius-sm: 0.25rem; + --radius: 0.5rem; + --radius-lg: 0.75rem; + + /* Bevel sizes — DT sets real values; Classic/Supra leave at 0 */ + --bevel-sm: 0px; + --bevel-md: 0px; + --bevel-lg: 0px; +} diff --git a/packages/web/src/components/bevels.css b/packages/web/src/components/bevels.css new file mode 100644 index 0000000..439d261 --- /dev/null +++ b/packages/web/src/components/bevels.css @@ -0,0 +1,290 @@ +/* dt-web-theme: Bevel Utilities */ +/* Angular/beveled clip-path patterns from the DT design system */ +/* Source: dt-shopify-storefront clip-path patterns + react-native-dt-theme bevelPaths.ts */ +/* */ +/* clip-path clips CSS borders and box-shadow. This file uses the storefront's */ +/* dual-element technique: the element's own background serves as the "border" color, */ +/* and a ::before pseudo-element provides the inner surface fill. The gap between */ +/* them follows the clip-path shape perfectly. */ +/* */ +/* For glow effects on clipped elements, use filter: drop-shadow() (not box-shadow). */ + +/* ============================================================================ + Card Bevels — dual bottom bevels (bottom-right large + bottom-left small) + Source: storefront .card-container + .clip-corners-inner pattern + Outer bg = border color, ::before = surface fill + Border width: ~3px uniform (storefront --card-border-width: 0.2em) + ============================================================================ */ +[data-brand="dt"] .dt-bevel-card, +[data-brand="dt"] .card { + position: relative; + isolation: isolate; + background: var(--color-primary); + border: none; + border-radius: 0; + clip-path: polygon( + 0% 0%, + 100% 0%, + 100% calc(100% - var(--bevel-md)), + calc(100% - var(--bevel-md)) 100%, + var(--bevel-sm) 100%, + 0% calc(100% - var(--bevel-sm)) + ); +} + +[data-brand="dt"] .dt-bevel-card::before, +[data-brand="dt"] .card::before { + content: ''; + position: absolute; + inset: 0; + background: var(--color-surface); + z-index: -1; + /* Inner clip-path mirrors outer shape, inset 3px on all edges. + This creates a uniform cyan border along both straight edges AND bevel diagonals. */ + clip-path: polygon( + 3px 3px, + calc(100% - 3px) 3px, + calc(100% - 3px) calc(100% - var(--bevel-md)), + calc(100% - var(--bevel-md)) calc(100% - 3px), + var(--bevel-sm) calc(100% - 3px), + 3px calc(100% - var(--bevel-sm)) + ); +} + +/* Card Header — storefront .card-header pattern + Title extends edge-to-edge on the card's primary bg (cyan). + Below it, the ::before dark surface shows through for the body area. */ +[data-brand="dt"] .card > .card-title, +[data-brand="dt"] .dt-bevel-card > .card-title { + /* Pull title to card edges, canceling card padding */ + margin: calc(-1 * var(--space-6)) calc(-1 * var(--space-6)) var(--space-4) calc(-1 * var(--space-6)); + padding: 1rem var(--space-6); + /* Sits above ::before so its own bg covers the dark surface */ + background: var(--color-primary); + color: var(--color-bg); + font-weight: 900; + text-transform: uppercase; + letter-spacing: 0.05em; + font-size: 1rem; + position: relative; +} + +/* Force icon spans to inherit header color (overrides inline styles) */ +[data-brand="dt"] .card > .card-title > * { + color: inherit !important; +} + +/* ============================================================================ + Button Bevels — top-right corner cut + Source: storefront .label-clipped pattern (solid fill + clip-path) + Filled buttons (primary/danger): direct clip-path, solid bg + Outline button (secondary): dual-element technique via ::before + ============================================================================ */ +[data-brand="dt"] .btn-primary, +[data-brand="dt"] .btn-danger { + border: none; + clip-path: polygon( + 0% 0%, + calc(100% - var(--bevel-sm)) 0%, + 100% var(--bevel-sm), + 100% 100%, + 0% 100% + ); +} + +[data-brand="dt"] .btn-secondary { + position: relative; + isolation: isolate; + background: var(--color-primary); + border: none; + clip-path: polygon( + 0% 0%, + calc(100% - var(--bevel-sm)) 0%, + 100% var(--bevel-sm), + 100% 100%, + 0% 100% + ); +} + +[data-brand="dt"] .btn-secondary::before { + content: ''; + position: absolute; + inset: 0; + background: var(--color-bg); + z-index: -1; + clip-path: polygon( + 2px 2px, + calc(100% - var(--bevel-sm)) 2px, + calc(100% - 2px) var(--bevel-sm), + calc(100% - 2px) calc(100% - 2px), + 2px calc(100% - 2px) + ); +} + +[data-brand="dt"] .btn-secondary:hover { + background: var(--color-accent); +} + +[data-brand="dt"] .btn-secondary:hover::before { + background: rgba(var(--color-primary-rgb), 0.1); +} + +/* ============================================================================ + Badge/Label Bevels — top-right bevel + Source: storefront .label-clipped pattern + Dual-element technique: badge bg = border color, ::before = inner fill + ============================================================================ */ +[data-brand="dt"] .badge { + --badge-border-color: var(--color-border); + --badge-fill: var(--color-surface); + position: relative; + isolation: isolate; + background: var(--badge-border-color); + color: var(--color-text-primary); + clip-path: polygon( + 0% 0%, + calc(100% - var(--bevel-sm)) 0%, + 100% var(--bevel-sm), + 100% 100%, + 0% 100% + ); + border: none; + border-radius: 0; +} + +[data-brand="dt"] .badge::before { + content: ''; + position: absolute; + inset: 0; + background: var(--badge-fill); + z-index: -1; + clip-path: polygon( + 2px 2px, + calc(100% - var(--bevel-sm)) 2px, + calc(100% - 2px) var(--bevel-sm), + calc(100% - 2px) calc(100% - 2px), + 2px calc(100% - 2px) + ); +} + +[data-brand="dt"] .badge-success { + --badge-border-color: var(--color-success); + --badge-fill: rgba(var(--color-success-rgb), 0.25); +} + +[data-brand="dt"] .badge-error { + --badge-border-color: var(--color-error); + --badge-fill: rgba(var(--color-error-rgb), 0.25); +} + +[data-brand="dt"] .badge-warning { + --badge-border-color: var(--color-warning); + --badge-fill: rgba(var(--color-warning-rgb), 0.25); +} + +[data-brand="dt"] .badge-info { + --badge-border-color: var(--color-info); + --badge-fill: rgba(var(--color-info-rgb), 0.25); +} + +/* ============================================================================ + Opt-in Bevel Utility Classes + Use these for custom elements that need bevel shapes + ============================================================================ */ +[data-brand="dt"] .dt-bevel-btn { + clip-path: polygon( + 0% 0%, + calc(100% - var(--bevel-sm)) 0%, + 100% var(--bevel-sm), + 100% 100%, + 0% 100% + ); +} + +[data-brand="dt"] .dt-bevel-label { + clip-path: polygon( + 0% 0%, + calc(100% - var(--bevel-sm)) 0%, + 100% var(--bevel-sm), + 100% 100%, + 0% 100% + ); + border-radius: 0; +} + +/* ============================================================================ + Media Frame Bevels — diagonal opposite corners (top-left + bottom-right) + Source: storefront .media-frame-clipped pattern + ============================================================================ */ +.dt-bevel-media { + clip-path: polygon( + var(--bevel-md) 0%, + 100% 0%, + 100% calc(100% - var(--bevel-md)), + calc(100% - var(--bevel-md)) 100%, + 0% 100%, + 0% var(--bevel-md) + ); +} + +/* ============================================================================ + Modal/Drawer Bevels — dual bottom bevels (bottom-right + bottom-left) + ============================================================================ */ +.dt-bevel-modal { + clip-path: polygon( + 0% 0%, + 100% 0%, + 100% calc(100% - var(--bevel-lg)), + calc(100% - var(--bevel-lg)) 100%, + var(--bevel-lg) 100%, + 0% calc(100% - var(--bevel-lg)) + ); +} + +/* ============================================================================ + Drawer Bevels — exposed-edge bevels + Source: storefront aside clip-path pattern + ============================================================================ */ +.dt-bevel-drawer-right { + clip-path: polygon( + 0% var(--bevel-lg), + var(--bevel-lg) 0%, + 100% 0%, + 100% 100%, + var(--bevel-lg) 100%, + 0% calc(100% - var(--bevel-lg)) + ); +} + +.dt-bevel-drawer-left { + clip-path: polygon( + 0% 0%, + calc(100% - var(--bevel-lg)) 0%, + 100% var(--bevel-lg), + 100% calc(100% - var(--bevel-lg)), + calc(100% - var(--bevel-lg)) 100%, + 0% 100% + ); +} + +/* ============================================================================ + Small Bevels — for compact elements (arrows, stepper buttons) + ============================================================================ */ +.dt-bevel-sm { + clip-path: polygon( + var(--bevel-sm) 0%, + 100% 0%, + 100% calc(100% - var(--bevel-sm)), + calc(100% - var(--bevel-sm)) 100%, + 0% 100%, + 0% var(--bevel-sm) + ); +} + +/* ============================================================================ + Accordion/Menu — thick top border accent (storefront menu-item-clipped) + ============================================================================ */ +[data-brand="dt"] .dt-accent-top, +[data-brand="dt"] .terminal { + border-top: 3px solid var(--color-primary); +} diff --git a/packages/web/src/components/elevation.css b/packages/web/src/components/elevation.css new file mode 100644 index 0000000..e4b7eef --- /dev/null +++ b/packages/web/src/components/elevation.css @@ -0,0 +1,96 @@ +/* dt-web-theme: Supra Elevation & MD3 Styles */ +/* Source: react-native-supra-theme/src/theme/paperTheme.ts */ +/* Rounded Material Design 3 aesthetic with elevation shadows */ + +/* ============================================================================ + Card Elevation + ============================================================================ */ +[data-brand="supra"] .card { + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.18); + border-radius: var(--radius-lg); +} + +[data-brand="supra"] .card:hover { + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.22); +} + +/* ============================================================================ + Button — Dual-layer inset shadow (hardware button feel) + Source: SupraButton.tsx — inner shadow for tactile appearance + ============================================================================ */ +[data-brand="supra"] .btn-primary { + box-shadow: + inset -2px -2px 4px rgba(0, 0, 0, 0.18), + inset 2px 2px 4px rgba(255, 255, 255, 0.25); + border-radius: var(--radius); +} + +[data-brand="supra"] .btn-primary:hover { + box-shadow: + inset -2px -2px 6px rgba(0, 0, 0, 0.22), + inset 2px 2px 6px rgba(255, 255, 255, 0.3); + transform: translateY(-1px); +} + +[data-brand="supra"] .btn-secondary { + border-radius: var(--radius); +} + +[data-brand="supra"] .btn-danger { + border-radius: var(--radius); +} + +/* ============================================================================ + Badge — Rounded pill (MD3 chip style) + ============================================================================ */ +[data-brand="supra"] .badge { + border-radius: 8px; +} + +/* ============================================================================ + Input — Rounded with standard focus ring + ============================================================================ */ +[data-brand="supra"] .input, +[data-brand="supra"] input, +[data-brand="supra"] textarea, +[data-brand="supra"] select { + border-radius: var(--radius); +} + +[data-brand="supra"] .input:focus, +[data-brand="supra"] input:focus, +[data-brand="supra"] textarea:focus, +[data-brand="supra"] select:focus { + box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.2); +} + +/* ============================================================================ + Terminal — Rounded with subtle elevation + ============================================================================ */ +[data-brand="supra"] .terminal { + border-radius: var(--radius); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.18); +} + +/* ============================================================================ + Elevation Utility Classes + ============================================================================ */ +.supra-elevation-1 { + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12); +} + +.supra-elevation-2 { + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.18); +} + +.supra-elevation-3 { + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.22); +} + +.supra-elevation-4 { + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.25); +} + +.supra-elevation-5 { + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3); +} diff --git a/packages/web/src/components/forms-dt.css b/packages/web/src/components/forms-dt.css new file mode 100644 index 0000000..2c35547 --- /dev/null +++ b/packages/web/src/components/forms-dt.css @@ -0,0 +1,329 @@ +/* dt-web-theme: DT Form Component Styles */ +/* Source: react-native-dt-theme/src/components/DT*.tsx */ +/* These styles exist in the RN DT theme but NOT the Shopify storefront */ + +/* ============================================================================ + Text Input — Sharp corners + focus glow bar + Source: DTTextInput.tsx + ============================================================================ */ +[data-brand="dt"] input[type="text"], +[data-brand="dt"] input[type="password"], +[data-brand="dt"] input[type="email"], +[data-brand="dt"] input[type="number"], +[data-brand="dt"] input[type="search"], +[data-brand="dt"] input[type="url"], +[data-brand="dt"] input[type="tel"], +[data-brand="dt"] textarea, +[data-brand="dt"] select, +[data-brand="dt"] .input { + border: 2px solid var(--color-primary); + border-radius: 0; + background: var(--color-bg); + color: var(--color-text-primary); + transition: border-color var(--transition-fast), box-shadow var(--transition-fast); +} + +[data-brand="dt"] input:focus, +[data-brand="dt"] textarea:focus, +[data-brand="dt"] select:focus, +[data-brand="dt"] .input:focus { + outline: none; + border-color: var(--color-primary); + box-shadow: 0 4px 0 1px var(--color-primary); +} + +[data-brand="dt"] input.error, +[data-brand="dt"] .input.error { + border-color: var(--color-error); +} + +[data-brand="dt"] input.error:focus, +[data-brand="dt"] .input.error:focus { + box-shadow: 0 4px 0 1px var(--color-error); +} + +/* ============================================================================ + Checkbox — Beveled opposing corners (top-left + bottom-right) + Source: DTCheckbox.tsx — bevel at 30% of size + Uses drop-shadow instead of border (clip-path clips CSS borders) + ============================================================================ */ +[data-brand="dt"] input[type="checkbox"] { + appearance: none; + -webkit-appearance: none; + width: 24px; + height: 24px; + border: none; + background: rgba(var(--color-primary-rgb), 0.1); + cursor: pointer; + position: relative; + clip-path: polygon( + 30% 0%, 100% 0%, 100% 70%, 70% 100%, 0% 100%, 0% 30% + ); + filter: drop-shadow(0 0 1px var(--color-primary)); + transition: background var(--transition-fast), filter var(--transition-fast); +} + +[data-brand="dt"] input[type="checkbox"]:checked { + background: var(--color-primary); + filter: drop-shadow(0 0 2px var(--color-primary)); +} + +[data-brand="dt"] input[type="checkbox"]:checked::after { + content: ''; + position: absolute; + left: 6px; + top: 8px; + width: 10px; + height: 6px; + border: 2px solid var(--color-bg); + border-top: none; + border-right: none; + transform: rotate(-45deg); +} + +[data-brand="dt"] input[type="checkbox"]:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* ============================================================================ + Switch / Toggle — Angular track + sliding square thumb + Source: DTSwitch.tsx — 48x26 track, 20x20 thumb, 150ms + ============================================================================ */ +.dt-switch { + position: relative; + display: inline-block; + width: 48px; + height: 26px; + cursor: pointer; +} + +.dt-switch input { + opacity: 0; + width: 0; + height: 0; + position: absolute; +} + +.dt-switch-track { + position: absolute; + inset: 0; + border: 2px solid var(--color-primary); + border-radius: 0; + background: rgba(var(--color-primary-rgb), 0.1); + transition: background var(--transition-fast); +} + +.dt-switch input:checked + .dt-switch-track { + background: var(--color-primary); +} + +.dt-switch-thumb { + position: absolute; + top: 3px; + left: 3px; + width: 20px; + height: 20px; + background: #ffffff; + transition: left var(--transition-fast); +} + +.dt-switch input:checked ~ .dt-switch-thumb, +.dt-switch input:checked + .dt-switch-track + .dt-switch-thumb { + left: 25px; + background: var(--color-bg); +} + +.dt-switch input:disabled + .dt-switch-track { + opacity: 0.5; + cursor: not-allowed; +} + +/* ============================================================================ + Radio Button — Hexagonal indicator + Source: DTRadioGroup.tsx — flat-top hexagon, 22px default + Uses drop-shadow instead of border (clip-path clips CSS borders) + ============================================================================ */ +[data-brand="dt"] input[type="radio"] { + appearance: none; + -webkit-appearance: none; + width: 22px; + height: 22px; + border: none; + background: rgba(var(--color-primary-rgb), 0.1); + cursor: pointer; + clip-path: polygon( + 50% 0%, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25% + ); + filter: drop-shadow(0 0 1px var(--color-primary)); + transition: background var(--transition-fast), filter var(--transition-fast); +} + +[data-brand="dt"] input[type="radio"]:checked { + background: var(--color-primary); + filter: drop-shadow(0 0 2px var(--color-primary)); +} + +[data-brand="dt"] input[type="radio"]:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* Radio group option container */ +.dt-radio-option { + display: flex; + align-items: center; + gap: 12px; + padding: 12px; + border: 2px solid rgba(var(--color-primary-rgb), 0.3); + cursor: pointer; + transition: all var(--transition-fast); +} + +.dt-radio-option.selected { + background: rgba(var(--color-primary-rgb), 0.15); + border-color: var(--color-primary); +} + +/* ============================================================================ + Progress Bar — Angular, no radius + Source: DTProgressBar.tsx — 4px height, no border-radius + ============================================================================ */ +.dt-progress { + width: 100%; + height: 4px; + background: rgba(255, 255, 255, 0.1); + border-radius: 0; + overflow: hidden; +} + +.dt-progress-fill { + height: 100%; + background: var(--color-primary); + transition: width 300ms ease-out; +} + +.dt-progress-label { + font-size: 11px; + font-weight: 600; + color: var(--color-primary); + margin-top: 4px; + font-family: var(--font-mono); +} + +/* Vertical variant */ +.dt-progress.vertical { + width: 8px; + height: 200px; + display: flex; + flex-direction: column-reverse; +} + +.dt-progress.vertical .dt-progress-fill { + width: 100%; + height: 0%; + transition: height 300ms ease-out; +} + +/* ============================================================================ + Accordion — 5px top border, chevron rotation + Source: DTAccordion.tsx — 250ms animation + ============================================================================ */ +.dt-accordion { + display: flex; + flex-direction: column; + gap: 4px; +} + +.dt-accordion-header { + background: var(--color-bg); + border: 1px solid var(--color-primary); + border-top: 5px solid var(--color-primary); + padding: 12px 16px; + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + text-transform: uppercase; + font-weight: 600; + font-size: 0.875rem; + letter-spacing: 0.05em; + color: var(--color-text-primary); + transition: opacity var(--transition-fast); +} + +.dt-accordion-header:hover { + opacity: 0.7; +} + +.dt-accordion-header[aria-expanded="true"] { + color: var(--color-secondary); + border-top-color: var(--color-secondary); +} + +.dt-accordion-chevron { + display: inline-block; + transition: transform 250ms ease-in-out; + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 7px solid currentColor; +} + +.dt-accordion-header[aria-expanded="true"] .dt-accordion-chevron { + transform: rotate(180deg); +} + +.dt-accordion-content { + max-height: 0; + overflow: hidden; + transition: max-height 250ms ease-in-out; +} + +.dt-accordion-content[data-open="true"] { + max-height: 2000px; +} + +/* ============================================================================ + Quantity Stepper — Beveled +/- buttons + Source: DTQuantityStepper.tsx — bottom-right bevel + ============================================================================ */ +.dt-stepper { + display: inline-flex; + gap: 4px; + align-items: center; +} + +.dt-stepper-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + border: 2px solid var(--color-primary); + background: transparent; + color: var(--color-primary); + font-size: 1.25rem; + font-weight: bold; + cursor: pointer; + border-radius: 0; + transition: opacity var(--transition-fast); +} + +.dt-stepper-btn:hover { + opacity: 0.7; +} + +.dt-stepper-btn:disabled { + opacity: 0.3; + cursor: not-allowed; +} + +.dt-stepper-value { + min-width: 36px; + text-align: center; + color: var(--color-primary); + font-weight: 700; + font-family: var(--font-mono); +} diff --git a/packages/web/src/components/glows.css b/packages/web/src/components/glows.css new file mode 100644 index 0000000..758f5fe --- /dev/null +++ b/packages/web/src/components/glows.css @@ -0,0 +1,80 @@ +/* dt-web-theme: Glow & Neon Effects */ +/* Source: dt-shopify-storefront glow patterns */ +/* */ +/* Elements with clip-path use filter: drop-shadow() instead of box-shadow */ +/* because clip-path clips box-shadow but filter follows the clipped shape. */ + +/* ============================================================================ + Button Glows — filter: drop-shadow (buttons have clip-path) + ============================================================================ */ +[data-brand="dt"] .btn-primary { + box-shadow: none; + filter: drop-shadow(0 0 10px rgba(var(--color-primary-rgb), 0.3)); +} + +[data-brand="dt"] .btn-primary:hover { + box-shadow: none; + filter: drop-shadow(0 0 15px rgba(var(--color-accent-rgb), 0.4)); +} + +[data-brand="dt"] .btn-secondary:hover { + filter: drop-shadow(0 0 8px rgba(var(--color-primary-rgb), 0.3)); +} + +[data-brand="dt"] .btn-danger { + box-shadow: none; + filter: drop-shadow(0 0 10px rgba(var(--color-error-rgb), 0.3)); +} + +[data-brand="dt"] .btn-danger:hover { + box-shadow: none; + filter: drop-shadow(0 0 15px rgba(var(--color-error-rgb), 0.4)); +} + +/* ============================================================================ + Link Glow + ============================================================================ */ +[data-brand="dt"] a:hover { + text-shadow: 0 0 8px var(--color-primary); +} + +/* ============================================================================ + Terminal Inset Glow (no clip-path, box-shadow OK) + ============================================================================ */ +[data-brand="dt"] .terminal { + box-shadow: inset 0 0 10px rgba(var(--color-accent-rgb), 0.05), + 0 0 10px rgba(var(--color-accent-rgb), 0.1); +} + +/* ============================================================================ + Card Hover Glow — filter: drop-shadow (cards have clip-path) + ============================================================================ */ +[data-brand="dt"] .card:hover { + filter: drop-shadow(0 0 8px rgba(var(--color-primary-rgb), 0.3)); +} + +/* ============================================================================ + Input Focus Glow (no clip-path on inputs, box-shadow OK) + ============================================================================ */ +[data-brand="dt"] .input:focus { + box-shadow: 0 4px 0 1px var(--color-primary); +} + +/* ============================================================================ + Generic Glow Utilities + ============================================================================ */ +.dt-glow { + filter: drop-shadow(0 0 10px rgba(var(--color-primary-rgb), 0.3)); +} + +.dt-glow-strong { + filter: drop-shadow(0 0 15px rgba(var(--color-primary-rgb), 0.5)); +} + +.dt-glow-inset { + box-shadow: inset 0 0 10px rgba(var(--color-primary-rgb), 0.1); +} + +.dt-text-glow { + text-shadow: 0 0 8px currentColor; +} diff --git a/packages/web/src/dt-font.css b/packages/web/src/dt-font.css new file mode 100644 index 0000000..79a4e32 --- /dev/null +++ b/packages/web/src/dt-font.css @@ -0,0 +1,9 @@ +/* @dangerousthings/web: Tektur Font Face */ +@font-face { + font-family: 'Tektur'; + src: url('../fonts/Tektur-VariableFont_wdth,wght.ttf') format('truetype'); + font-weight: 100 900; + font-stretch: 75% 125%; + font-style: normal; + font-display: swap; +} diff --git a/packages/web/src/index.css b/packages/web/src/index.css new file mode 100644 index 0000000..bc84266 --- /dev/null +++ b/packages/web/src/index.css @@ -0,0 +1,21 @@ +/* @dangerousthings/web: Main Entry Point */ +/* Import this file to get all tokens and component styles */ + +/* Base tokens (spacing, transitions, font stacks) */ +@import './base.css'; + +/* Tektur font face (used by DT brand) */ +@import './dt-font.css'; + +/* Brand tokens — generated from @dangerousthings/tokens */ +@import './tokens/dt.css'; +@import './tokens/classic.css'; +@import './tokens/supra.css'; + +/* Component styles — DT visual identity */ +@import './components/bevels.css'; +@import './components/glows.css'; +@import './components/forms-dt.css'; + +/* Component styles — Supra/MD3 visual identity */ +@import './components/elevation.css'; diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..5673e2c --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "isolatedModules": true + } +} diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..d35f080 --- /dev/null +++ b/turbo.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist/**"] + }, + "clean": { + "cache": false + }, + "typecheck": { + "dependsOn": ["^build"] + }, + "lint": {} + } +}