From 191561ed901b8d02a072c26952bbc19039926467 Mon Sep 17 00:00:00 2001 From: levinismynameirl Date: Tue, 24 Feb 2026 19:27:21 +0100 Subject: [PATCH 01/12] Add more comprehensive template, rules, etc .md files, add some folders to .prettierignore, create a blank readTheDocs.yml folder for future use, and make a forReadTheDocs folder in docs/ with a .gitkeep and placeholder index.rst --- .github/CODE_OF_CONDUCT.md | 20 ++++++++ .github/ISSUE_TEMPLATE.md | 86 ++++++++++++++++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 29 +++++++++++ .prettierignore | 4 ++ CONTRIBUTING.md | 46 +++++++++++------ docs/PROJECT_STRUCTURE.md | 2 + docs/QUICK_START.md | 6 +-- docs/forReadTheDocs/.gitkeep | 0 docs/forReadTheDocs/index.rst | 3 ++ readTheDocs.yml | 0 10 files changed, 178 insertions(+), 18 deletions(-) create mode 100644 .github/CODE_OF_CONDUCT.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 docs/forReadTheDocs/.gitkeep create mode 100644 docs/forReadTheDocs/index.rst create mode 100644 readTheDocs.yml diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..0511f39 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,20 @@ +# Code of Conduct + +**What is a Code of Conduct?** +A code of conduct is a set of guidelines and expectations for behavior within a community. It helps create a positive and inclusive environment for all members of the community, and it sets clear standards for how members should interact with each other. A code of conduct can help prevent harassment, discrimination, and other forms of harmful behavior, and it can also provide a framework for addressing any issues that may arise. + +## Our Code of Conduct +We are committed to creating a welcoming and inclusive environment for all members of our community. We expect all members to adhere to the following code of conduct: + +**1. Be respectful:** Treat all members of the community with respect and kindness. Avoid using language or behavior that is offensive, discriminatory, or harassing. Some might be less experienced than others, so be patient and understanding. + +**2. Be inclusive:** We welcome and encourage participation from people of all backgrounds, identities, and experiences. Avoid making assumptions about others based on their race, gender, sexual orientation, religion, or any other characteristic. We also ask that you use inclusive language and avoid making jokes or comments that could be hurtful to others. + +**3. Be professional:** We expect all members of the community to conduct themselves in a professional manner. Avoid engaging in behavior that is disruptive, disrespectful, or unprofessional. This includes but is not limited to trolling, flaming, and spamming. + +**4. Be collaborative:** We encourage collaboration and teamwork within our community. Avoid engaging in behavior that is divisive or that undermines the efforts of others. This includes but is not limited to creating duplicate issues or pull requests, or engaging in arguments or conflicts with other members. + +**5. Report issues:** If you witness or experience any behavior that violates this code of conduct, please report it to the a maintainer or the authors of the library. We take all reports seriously and will take appropriate action to address any issues that arise. + +## Conclusion +We may update this code of conduct from time to time, and we encourage all members of our community to review it regularly. By adhering to this code of conduct, we can create a positive and inclusive environment for everyone in our community. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index e69de29..8a056a5 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,86 @@ +## Issue type + + +- [ ] Bug report +- [ ] New component request +- [ ] Feature request / improvement +- [ ] Other + +--- + + + +## Component affected + + + +## What happened? + +## What did you expect? + +## Steps to reproduce + +1. +2. +3. + +## Environment + +- **liquid-react version:** +- **React Native version:** +- **iOS version:** +- **Device / Simulator:** + +--- + + + +## UIKit class name + + + +## Suggested name in liquid-react + + + +## Why do you need it? + +## Props / API you'd expect + + + +## Minimum iOS version + +- [ ] This is part of Apple's **public** UIKit API (no private frameworks) + +--- + + + +## What do you want to improve? + +## What's the problem right now? + +## What would you like instead? + +- [ ] I believe this is doable with Apple's public APIs + +--- + +## Anything else? + + + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..a5f494c --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,29 @@ +## What does this PR do? + + + +## Type of change + +- [ ] Bug fix +- [ ] New component +- [ ] Refactor / cleanup +- [ ] Docs update +- [ ] Other (describe above) + +## Related issue + +Closes # + +## Notes for reviewers + + + +--- + +## Checklist + +- [ ] Follows Code of Conduct and contributing guidelines +- [ ] If code changes were made, they were tested and verified to work + - [ ] I've updated the documentation to reflect said changes (if applicable) +- [ ] This is *not* a code change (e.g. a documentation update) +- [ ] Code passes CI/CD checks (if PR is ready for review, otherwise mark as draft) diff --git a/.prettierignore b/.prettierignore index e69de29..e4617a1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -0,0 +1,4 @@ +lib/ +node_modules/ +dist/ +build/ \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4139211..edefa65 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,27 +1,41 @@ -# Introduction +# Thanks for your interest in contributing -First of all, we want to thank you for your interest in contributing to Liquid-React! We are always looking for help in improving the library and adding new features, and we welcome contributions from the community. +Hello! We appreciate your interest in contributing to the liquidReact library. We welcome contributions of all kinds, including but not limited to bug fixes, new features, documentation improvements, code refactoring, suggestions, and more, especially since we are a group of teenagers who also have to focus on their personal lives. To ensure a smooth collaboration process, we have outlined some guidelines and best practices for contributing to this project. Please take a moment to review the following information before submitting your contribution. Aside from the guidelines below, we also encourage you to check out our [Code of Conduct](.github/CODE_OF_CONDUCT.md) to ensure a positive and friendly environment for all contributors. -## How to Contribute +## First off, how do I contribute? -If you want to contribute to Liquid-React, there are a few ways you can get involved: +Contributing to liquidReact is just like any other open source project. There are 2 main methods you can contribute: -1. **Report Issues**: If you find a bug or have an idea for a new feature, please open an issue on our GitHub repository. This helps us and other contributors keep track of what needs to be done and allows us to prioritize our work. +**Pull Requests:** After you figure out how and what you want to add/change/remove/etc, you can fork the repository, make your changes in a *new branch* (this is mandatory), and then submit a pull request to *staging* (not main). It is best to submit your pull request as a draft after the first commit, and fill out the pull request template with the necessary information. We will review your pull request and provide feedback or merge it if it meets our standards. -2. **Work on Issues**: If you want to contribute code, you can check out the open issues on our GitHub repository and see if there is anything you would like to work on. If you find an issue that you want to work on, please comment on the issue to let us know that you are working on it. Make sure that someone else is not already working on the same issue to avoid duplication of effort, you can also offer to help with an issue if you see that someone is struggling with it. +**Issues:** Another way to contribute is to simply submit an issue in the repository's issue tracker. If you find a bug or have a feature request, please submit it there so that we can track and address it. Make sure it follows the issue template and provides enough information for us to understand and reproduce the problem or implement the feature. -## Working on Issues +## Ok, but what are the guidelines? -To start work on an issue, you can follow these steps: -1. Fork the repository and create a new branch for your work. -2. Make a draft pull request to the main branch of the repository. This allows us to see your changes and provide feedback before you finalize your pull request. -3. Commit your changes and push them to your forked repository. -4. Make sure you follow the style guidelines and write clear commit messages to help us understand your changes. +We have a few standards that we ask all contributors to follow when submitting a pull request. These standards are in place to ensure that our codebase remains clear, consistent and maintainable for future helpers. It's also to make sure that no arguments arise (for example from a duplicate pull request or issue). + +**1. Follow the Code of Conduct:** We expect all contributors to adhere to our [Code of Conduct](.github/CODE_OF_CONDUCT.md) to maintain a respectful and inclusive environment for everyone. + +**2. Make sure you know what you're doing:** All code, documentation, and other contributions you make should be well thought out and intentional. If you are unsure about how to implement a feature or fix a bug, please ask for help in the discussions or open an issue to get feedback before submitting a pull request. + +**2.1. No AI Generated Content:** We prohibit AI-generated content in contributions to this project (with some exceptions for trusted contributors). This is because AI-generated content is often inaccurate, lacks context, clouds code quality (which can lead to confusion and bugs) and can sometimes infringe on intellectual property rights (we cannot verify the source of the model's training data, which could lead to unwanted legal issues). We encourage you to write your own original content to ensure the quality and integrity of our project. + +**3. Make sure your PR passes CI/CD checks:** We have automated checks in place to ensure that all contributions meet our quality standards. Please make sure your pull request passes all checks before submitting it. This includes linting, testing, and other checks that we have set up. + +**4. Follow the pull request template:** When submitting a pull request, please fill out the pull request template with all the necessary information. This helps us understand the purpose and scope of your contribution and makes it easier for us to review and merge it. + +**5. Be responsive to feedback:** We may provide feedback on your pull request, and we ask that you be responsive and open to making changes based on that feedback. This helps us maintain a high-quality codebase and ensures that your contribution is in line with our standards. + +**6. Be patient:** We receive many contributions, and it may take some time for us to review and merge your pull request. Please be patient and understand that we are doing our best to review all contributions in a timely manner. + +**7. Considering:** Considering the fact that this library is a strictly component-based library, we ask that, unless it's a documentation or bug fix contribution, all contributions should be in the form of a new component or an improvement to an existing component. This is not a hard rule, but it is a general guideline to help maintain the focus and structure of our library. + +**7.1. NOTE:** As the library is focused specifically on iOS Liquid-Glass components, which can be difficult to implement and often require a lot of knowledge on how the infrastructure of the library works, we ask that all contributions related to new components (this doesn't include improvements, bug fixes, documentation, etc) be made by trusted contributors and/or maintainers. This is not a hard rule, but if you're unexperienced with the library, it's easier to let someone with more expertise handle the implementation of new components so no confusion arises from who does what and no duplicate pull requests come up. ## Style guidelines When contributing to Liquid-React, please follow our style guidelines to ensure that your code is consistent with the rest of the library. This includes using clear and descriptive variable names, writing comments where necessary, and following the existing code structure. -Style guide: + - Use camelCase for variable and function names. - Use PascalCase for component names. - Write clear and concise comments to explain the purpose of your code. @@ -31,7 +45,9 @@ Style guide: ``` - Use the present tense in commit messages (e.g., "Add new feature" instead of "Added new feature"). - Keep commit messages concise and to the point, ideally under 50 characters for the subject line and 72 characters for the body. +- Use present tense in commit messages (e.g., "Add new feature" instead of "Added new feature"). - Use eslint and prettier to ensure that your code is properly formatted and follows our style guidelines. -## Code of Conduct -We expect all contributors to follow our code of conduct, which can be found in the CODE_OF_CONDUCT.md file in our repository. This code of conduct outlines our expectations for behavior when contributing to the project, and we take it very seriously. We want to create a welcoming and inclusive environment for all contributors, and we will not tolerate any form of harassment or discrimination. +## Conclusion + +We appreciate your interest in contributing to liquidReact and we look forward to collaborating with you. By following these guidelines, you can help us maintain a high-quality codebase and ensure that your contributions are valuable and impactful. If you have any questions or need help, please don't hesitate to reach out to us in the discussions or open an issue. Thank you for being a part of our community! diff --git a/docs/PROJECT_STRUCTURE.md b/docs/PROJECT_STRUCTURE.md index b3ed82d..81df080 100644 --- a/docs/PROJECT_STRUCTURE.md +++ b/docs/PROJECT_STRUCTURE.md @@ -4,6 +4,8 @@ Complete file structure of the Liquid-React module. ``` liquid-react/ +| +├── .github/ # GitHub configuration files │ ├── 📦 Package Configuration │ ├── package.json # NPM package configuration diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md index 0b5c52d..4ca9a6f 100644 --- a/docs/QUICK_START.md +++ b/docs/QUICK_START.md @@ -47,7 +47,7 @@ import { NativeMaterialView, NativeButton } from 'liquid-react'; export default function App() { return ( - @@ -55,7 +55,7 @@ export default function App() { Native iOS components in React Native - + setEnabled(e.nativeEvent.value)} /> - + Date: Tue, 24 Feb 2026 20:33:14 +0100 Subject: [PATCH 02/12] Add workflows for production --- .eslintrc.json | 29 +++++++++++++++ .github/workflows/lint-and-build.yml | 37 +++++++++++++++++++ .github/workflows/native-build.yml | 55 ++++++++++++++++++++++++++++ .github/workflows/publish.yml | 42 +++++++++++++++++++++ .github/workflows/swift-lint.yml | 25 +++++++++++++ .prettierrc | 9 +++++ .swiftlint.yml | 42 +++++++++++++++++++++ package.json | 13 ++++++- 8 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 .eslintrc.json create mode 100644 .github/workflows/lint-and-build.yml create mode 100644 .github/workflows/native-build.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/swift-lint.yml create mode 100644 .swiftlint.yml diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..7f2bef8 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,29 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2019, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + } + }, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "camelcase": ["warn", { "properties": "always" }], + "@typescript-eslint/naming-convention": [ + "warn", + { "selector": "variable", "format": ["camelCase", "PascalCase", "UPPER_CASE"] }, + { "selector": "function", "format": ["camelCase", "PascalCase"] }, + { "selector": "typeLike", "format": ["PascalCase"] } + ], + "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], + "@typescript-eslint/explicit-module-boundary-types": "off", + "no-console": "warn" + }, + "ignorePatterns": ["lib/", "node_modules/", "ios/"] +} diff --git a/.github/workflows/lint-and-build.yml b/.github/workflows/lint-and-build.yml new file mode 100644 index 0000000..30933db --- /dev/null +++ b/.github/workflows/lint-and-build.yml @@ -0,0 +1,37 @@ +name: Lint & Build + +on: + push: + branches: [main, staging, forProduction] + pull_request: + branches: [main, staging] + +jobs: + lint-and-build: + name: ESLint, Prettier & TypeScript + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: ESLint + run: npm run lint + + - name: Prettier check + run: npm run format:check + + - name: TypeScript type-check + run: npm run typecheck + + - name: TypeScript build + run: npm run build diff --git a/.github/workflows/native-build.yml b/.github/workflows/native-build.yml new file mode 100644 index 0000000..8b9d005 --- /dev/null +++ b/.github/workflows/native-build.yml @@ -0,0 +1,55 @@ +name: Full Build Check + +on: + workflow_dispatch: + +jobs: + build: + name: TypeScript + Native Compilation + runs-on: macos-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install JS dependencies + run: npm ci + + - name: ESLint + run: npm run lint + + - name: Prettier check + run: npm run format:check + + - name: TypeScript type-check + run: npm run typecheck + + - name: TypeScript build + run: npm run build + + - name: Install SwiftLint + run: brew install swiftlint + + - name: SwiftLint + run: swiftlint lint --config .swiftlint.yml + + - name: Install CocoaPods + run: | + cd ios + pod install --repo-update || echo "No Podfile found, skipping pod install" + + - name: Build with xcodebuild + run: | + xcodebuild \ + -workspace ios/*.xcworkspace \ + -scheme LiquidReact \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 16' \ + build \ + CODE_SIGNING_ALLOWED=NO | xcpretty || true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..9bf9d58 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,42 @@ +name: Publish to npm + +on: + push: + tags: + - 'v*.*.*' + +jobs: + publish: + name: Publish Package + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + registry-url: https://registry.npmjs.org + + - name: Install dependencies + run: npm ci + + - name: Lint + run: npm run lint + + - name: Type-check + run: npm run typecheck + + - name: Build + run: npm run build + + - name: Publish + run: npm publish --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/swift-lint.yml b/.github/workflows/swift-lint.yml new file mode 100644 index 0000000..73f0543 --- /dev/null +++ b/.github/workflows/swift-lint.yml @@ -0,0 +1,25 @@ +name: SwiftLint + +on: + push: + branches: [main, staging, forProduction] + paths: + - 'ios/**' + pull_request: + branches: [main, staging] + paths: + - 'ios/**' + +jobs: + swiftlint: + name: Swift Lint + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Run SwiftLint + uses: norio-nomura/action-swiftlint@3.2.1 + with: + args: --config .swiftlint.yml diff --git a/.prettierrc b/.prettierrc index e69de29..2fcf5a0 100644 --- a/.prettierrc +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "semi": true, + "singleQuote": true, + "trailingComma": "all", + "tabWidth": 2, + "printWidth": 100, + "bracketSpacing": true, + "arrowParens": "always" +} diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 0000000..c3bcd0a --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,42 @@ +included: + - ios + +excluded: + - Pods + - node_modules + - lib + +disabled_rules: + - trailing_whitespace + - line_length + +opt_in_rules: + - empty_count + - closure_spacing + - force_unwrapping + - implicit_return + - modifier_order + +type_name: + min_length: 2 + max_length: 50 + +identifier_name: + min_length: 2 + max_length: 50 + excluded: + - id + - x + - y + - i + - e + +file_length: + warning: 500 + error: 1000 + +function_body_length: + warning: 60 + error: 100 + +reporter: "xcode" diff --git a/package.json b/package.json index 81e8866..8a27433 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,14 @@ "types": "dist/index.d.ts", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "lint": "eslint . --ext .js,.jsx,.ts,.tsx" + "lint": "eslint . --ext .js,.jsx,.ts,.tsx", + "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx}\"", + "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx}\"", + "typecheck": "tsc --noEmit", + "build": "tsc" + }, + "engines": { + "node": ">=20.0.0" }, "keywords": [ "react-native", @@ -30,6 +37,10 @@ "devDependencies": { "@types/react": "^18.0.0", "@types/react-native": "^0.73.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0", + "prettier": "^3.2.0", "typescript": "^5.0.0" }, "files": [ From c42cb813904f93006e096ac82451eb106f0d8568 Mon Sep 17 00:00:00 2001 From: levinismynameirl Date: Tue, 24 Feb 2026 20:44:06 +0100 Subject: [PATCH 03/12] Update workflows to use npm ci with --legacy-peer-deps and remove redundant branch specification in swift-lint --- .github/workflows/lint-and-build.yml | 3 +-- .github/workflows/native-build.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/swift-lint.yml | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint-and-build.yml b/.github/workflows/lint-and-build.yml index 30933db..5034c24 100644 --- a/.github/workflows/lint-and-build.yml +++ b/.github/workflows/lint-and-build.yml @@ -4,7 +4,6 @@ on: push: branches: [main, staging, forProduction] pull_request: - branches: [main, staging] jobs: lint-and-build: @@ -22,7 +21,7 @@ jobs: cache: npm - name: Install dependencies - run: npm ci + run: npm ci --legacy-peer-deps - name: ESLint run: npm run lint diff --git a/.github/workflows/native-build.yml b/.github/workflows/native-build.yml index 8b9d005..14f068b 100644 --- a/.github/workflows/native-build.yml +++ b/.github/workflows/native-build.yml @@ -19,7 +19,7 @@ jobs: cache: npm - name: Install JS dependencies - run: npm ci + run: npm ci --legacy-peer-deps - name: ESLint run: npm run lint diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9bf9d58..be7a1ff 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -25,7 +25,7 @@ jobs: registry-url: https://registry.npmjs.org - name: Install dependencies - run: npm ci + run: npm ci --legacy-peer-deps - name: Lint run: npm run lint diff --git a/.github/workflows/swift-lint.yml b/.github/workflows/swift-lint.yml index 73f0543..e1afdac 100644 --- a/.github/workflows/swift-lint.yml +++ b/.github/workflows/swift-lint.yml @@ -6,7 +6,6 @@ on: paths: - 'ios/**' pull_request: - branches: [main, staging] paths: - 'ios/**' From c0c6b9bdd4a0023bcb059c5fdd2537f67fc0a9c2 Mon Sep 17 00:00:00 2001 From: levinismynameirl Date: Tue, 24 Feb 2026 20:46:56 +0100 Subject: [PATCH 04/12] Implement feature X to enhance user experience and optimize performance --- package-lock.json | 1263 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1247 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index b2aaf6a..f47ce29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,15 @@ "devDependencies": { "@types/react": "^18.0.0", "@types/react-native": "^0.73.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0", + "prettier": "^3.2.0", "typescript": "^5.0.0" }, + "engines": { + "node": ">=20.0.0" + }, "peerDependencies": { "react": ">=16.8.0", "react-native": ">=0.65.0" @@ -525,6 +532,127 @@ "node": ">=6.9.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/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/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/@isaacs/ttlcache": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", @@ -728,6 +856,44 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "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.0", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.84.0.tgz", @@ -1063,6 +1229,245 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", + "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -1103,6 +1508,16 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -1113,6 +1528,23 @@ "node": ">= 14" } }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/anser": { "version": "1.4.10", "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", @@ -1170,6 +1602,16 @@ "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", @@ -1399,6 +1841,16 @@ "dev": true, "license": "MIT" }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -1629,6 +2081,13 @@ } } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1650,6 +2109,32 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "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/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1721,6 +2206,196 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/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/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1735,6 +2410,52 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -1762,6 +2483,43 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "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-glob/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/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", @@ -1769,6 +2527,23 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "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", @@ -1810,6 +2585,19 @@ } } }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -1873,6 +2661,28 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, "node_modules/flow-enums-runtime": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", @@ -1937,31 +2747,94 @@ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, - "license": "MIT", + "license": "MIT", + "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", + "dev": true, + "license": "ISC", + "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": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=8.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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", + "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": "ISC", + "license": "MIT", "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" + "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": "*" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/graceful-fs": { @@ -1971,6 +2844,13 @@ "dev": true, "license": "ISC" }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2050,6 +2930,16 @@ "node": ">= 14" } }, + "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", @@ -2066,6 +2956,33 @@ "node": ">=16.x" } }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2121,6 +3038,16 @@ "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", @@ -2131,6 +3058,19 @@ "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", @@ -2141,6 +3081,16 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -2420,6 +3370,27 @@ "node": ">=6" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -2433,6 +3404,16 @@ "node": ">=6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -2443,6 +3424,20 @@ "node": ">=6" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lighthouse-logger": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", @@ -2484,6 +3479,13 @@ "node": ">=8" } }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "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", @@ -2545,6 +3547,16 @@ "dev": true, "license": "MIT" }, + "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.3", "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.3.tgz", @@ -2918,6 +3930,13 @@ "dev": true, "license": "MIT" }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -3012,6 +4031,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -3051,6 +4088,19 @@ "node": ">=6" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -3091,6 +4141,16 @@ "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", @@ -3121,6 +4181,32 @@ "node": ">= 6" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "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", @@ -3159,6 +4245,16 @@ "asap": "~2.0.6" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/queue": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", @@ -3169,6 +4265,27 @@ "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", @@ -3293,6 +4410,17 @@ "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", @@ -3310,6 +4438,30 @@ "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/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -3620,6 +4772,19 @@ "node": ">=8" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3674,6 +4839,13 @@ "node": ">=8" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, "node_modules/throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", @@ -3741,6 +4913,32 @@ "node": ">=0.6" } }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -3823,6 +5021,16 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -3873,6 +5081,16 @@ "node": ">= 8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3995,6 +5213,19 @@ "engines": { "node": ">=12" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } From fc4020511682fc05349fa7a9368041d1b50336bc Mon Sep 17 00:00:00 2001 From: levinismynameirl Date: Tue, 24 Feb 2026 20:48:47 +0100 Subject: [PATCH 05/12] Refactor native component prop types to use more specific event handler types --- src/nativeComponents.ts | 2 +- src/types.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/nativeComponents.ts b/src/nativeComponents.ts index 1b5b44e..17ef0c2 100644 --- a/src/nativeComponents.ts +++ b/src/nativeComponents.ts @@ -18,7 +18,7 @@ import type { // On web, requireNativeComponent doesn't exist — fall back to View. const req = Platform.OS === 'web' - ? () => View as any + ? () => View as unknown : requireNativeComponent; // Native component registration diff --git a/src/types.ts b/src/types.ts index 808f6a6..036cf7f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { requireNativeComponent, ViewProps } from 'react-native'; +import { ViewProps } from 'react-native'; import type { BubblingEventHandler, DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes'; // Material types @@ -111,13 +111,13 @@ index: number; // Component prop types export interface NativeMaterialViewProps extends ViewProps { material?: MaterialType; -onPress?: BubblingEventHandler<{}>; +onPress?: BubblingEventHandler>; } export interface NativeButtonProps extends ViewProps { title: string; buttonStyle?: ButtonStyle; -onPress?: BubblingEventHandler<{}>; +onPress?: BubblingEventHandler>; } export interface NativeSwitchProps extends ViewProps { @@ -139,7 +139,7 @@ placeholder?: string; text?: string; onTextChanged?: DirectEventHandler; onSearchPressed?: DirectEventHandler; -onCancelPressed?: DirectEventHandler<{}>; +onCancelPressed?: DirectEventHandler>; } export interface NativeNavigationBarProps extends ViewProps { @@ -157,7 +157,7 @@ icon?: string; title?: string; systemItem?: ToolbarSystemItem; disabled?: boolean; -onPress?: BubblingEventHandler<{}>; +onPress?: BubblingEventHandler>; } export interface NativeToolbarMenuProps extends ViewProps { From 49e4bc3e6b1d65e7fc09c793a366c14dce759cab Mon Sep 17 00:00:00 2001 From: levinismynameirl Date: Tue, 24 Feb 2026 20:52:58 +0100 Subject: [PATCH 06/12] Refactor component documentation and improve type definitions for better clarity and consistency --- src/components.tsx | 32 ++--- src/index.ts | 1 - src/nativeComponents.ts | 13 ++- src/types.ts | 252 +++++++++++++++++++++------------------- 4 files changed, 158 insertions(+), 140 deletions(-) diff --git a/src/components.tsx b/src/components.tsx index 0e0a7f1..060fedc 100644 --- a/src/components.tsx +++ b/src/components.tsx @@ -35,7 +35,7 @@ import type { /** * NativeMaterialView - Exposes UIVisualEffectView with system materials - * + * * Uses Apple's blur, vibrancy, and depth rendering pipeline. * All visual properties controlled by iOS. */ @@ -45,7 +45,7 @@ export const NativeMaterialView: React.FC = (props) => /** * NativeButton - Exposes UIButton with system configurations - * + * * Uses native button styles and animations. */ export const NativeButton: React.FC = (props) => { @@ -54,7 +54,7 @@ export const NativeButton: React.FC = (props) => { /** * NativeSwitch - Exposes UISwitch - * + * * Native iOS toggle control. */ export const NativeSwitch: React.FC = (props) => { @@ -63,16 +63,18 @@ export const NativeSwitch: React.FC = (props) => { /** * NativeSegmentedControl - Exposes UISegmentedControl - * + * * Native segmented control with system styling. */ export const NativeSegmentedControl: React.FC = (props) => { - return ; + return ( + + ); }; /** * NativeSearchBar - Exposes UISearchBar - * + * * Native search bar with minimal style. */ export const NativeSearchBar: React.FC = (props) => { @@ -81,7 +83,7 @@ export const NativeSearchBar: React.FC = (props) => { /** * NativeNavigationBar - Exposes UINavigationBar - * + * * Native navigation bar with translucent material. */ export const NativeNavigationBar: React.FC = (props) => { @@ -90,7 +92,7 @@ export const NativeNavigationBar: React.FC = (props) = /** * NativeToolbar - Exposes UIToolbar - * + * * Native toolbar with support for buttons and menus as children. * Use with NativeToolbarButton and NativeToolbarMenu components. */ @@ -100,7 +102,7 @@ export const NativeToolbar: React.FC = (props) => { /** * NativeToolbarButton - Exposes UIBarButtonItem - * + * * Native toolbar button. Must be used as a child of NativeToolbar. */ export const NativeToolbarButton: React.FC = (props) => { @@ -109,7 +111,7 @@ export const NativeToolbarButton: React.FC = (props) = /** * NativeToolbarMenu - Exposes UIBarButtonItem with UIMenu - * + * * Native toolbar menu button with nested menu support. * Automatically handles cascading menus, animations, and platform differences. * Must be used as a child of NativeToolbar. @@ -120,7 +122,7 @@ export const NativeToolbarMenu: React.FC = (props) => { /** * NativeTabBar - Exposes UITabBar - * + * * Native tab bar with system styling. */ export const NativeTabBar: React.FC = (props) => { @@ -129,7 +131,7 @@ export const NativeTabBar: React.FC = (props) => { /** * NativeGroupedContainer - UIView with system grouped background - * + * * Uses system background colors for grouped list style. */ export const NativeGroupedContainer: React.FC = (props) => { @@ -138,7 +140,7 @@ export const NativeGroupedContainer: React.FC = (pr /** * NativeCardContainer - UIView with continuous corner radius - * + * * System background with native corner curve. */ export const NativeCardContainer: React.FC = (props) => { @@ -147,7 +149,7 @@ export const NativeCardContainer: React.FC = (props) = /** * NativeStackView - Exposes UIStackView for automatic layout - * + * * Native iOS stack layout with axis, spacing, alignment, and distribution. * Automatically arranges child views without manual positioning. */ @@ -157,7 +159,7 @@ export const NativeStackView: React.FC = (props) => { /** * NativeMenuButton - Standalone UIButton with UIMenu pull-down - * + * * Shows a native iOS pull-down menu anchored to the button. * Works anywhere (no UIToolbar parent required). */ diff --git a/src/index.ts b/src/index.ts index 21e7f98..471a857 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,7 +21,6 @@ export type { MaterialType, ButtonStyle, ToolbarSystemItem, - ToolbarItem, ToolbarMenuItem, TabBarSystemItem, TabBarItem, diff --git a/src/nativeComponents.ts b/src/nativeComponents.ts index 17ef0c2..a76dcdc 100644 --- a/src/nativeComponents.ts +++ b/src/nativeComponents.ts @@ -17,22 +17,25 @@ import type { } from './types'; // On web, requireNativeComponent doesn't exist — fall back to View. -const req = Platform.OS === 'web' - ? () => View as unknown - : requireNativeComponent; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const req = Platform.OS === 'web' ? () => View as any : requireNativeComponent; // Native component registration export const RNNativeMaterialView = req('LRNativeMaterialView'); export const RNNativeButton = req('LRNativeButton'); export const RNNativeSwitch = req('LRNativeSwitch'); -export const RNNativeSegmentedControl = req('LRNativeSegmentedControl'); +export const RNNativeSegmentedControl = req( + 'LRNativeSegmentedControl', +); export const RNNativeSearchBar = req('LRNativeSearchBar'); export const RNNativeNavigationBar = req('LRNativeNavigationBar'); export const RNNativeToolbar = req('LRNativeToolbar'); export const RNNativeToolbarButton = req('LRNativeToolbarButton'); export const RNNativeToolbarMenu = req('LRNativeToolbarMenu'); export const RNNativeTabBar = req('LRNativeTabBar'); -export const RNNativeGroupedContainer = req('LRNativeGroupedContainer'); +export const RNNativeGroupedContainer = req( + 'LRNativeGroupedContainer', +); export const RNNativeCardContainer = req('LRNativeCardContainer'); export const RNNativeStackView = req('LRNativeStackView'); export const RNNativeMenuButton = req('LRNativeMenuButton'); diff --git a/src/types.ts b/src/types.ts index 036cf7f..5e95f9d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,202 +1,216 @@ import { ViewProps } from 'react-native'; -import type { BubblingEventHandler, DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes'; +import type { + BubblingEventHandler, + DirectEventHandler, +} from 'react-native/Libraries/Types/CodegenTypes'; // Material types export type MaterialType = -| 'systemUltraThinMaterial' -| 'systemThinMaterial' -| 'systemMaterial' -| 'systemThickMaterial' -| 'systemChromeMaterial' -| 'systemUltraThinMaterialLight' -| 'systemThinMaterialLight' -| 'systemMaterialLight' -| 'systemThickMaterialLight' -| 'systemChromeMaterialLight' -| 'systemUltraThinMaterialDark' -| 'systemThinMaterialDark' -| 'systemMaterialDark' -| 'systemThickMaterialDark' -| 'systemChromeMaterialDark'; + | 'systemUltraThinMaterial' + | 'systemThinMaterial' + | 'systemMaterial' + | 'systemThickMaterial' + | 'systemChromeMaterial' + | 'systemUltraThinMaterialLight' + | 'systemThinMaterialLight' + | 'systemMaterialLight' + | 'systemThickMaterialLight' + | 'systemChromeMaterialLight' + | 'systemUltraThinMaterialDark' + | 'systemThinMaterialDark' + | 'systemMaterialDark' + | 'systemThickMaterialDark' + | 'systemChromeMaterialDark'; // Button types export type ButtonStyle = -| 'filled' -| 'gray' -| 'tinted' -| 'plain' -| 'bordered' -| 'borderedTinted' -| 'borderedProminent'; + | 'filled' + | 'gray' + | 'tinted' + | 'plain' + | 'bordered' + | 'borderedTinted' + | 'borderedProminent'; // Toolbar item types export type ToolbarSystemItem = -| 'done' -| 'cancel' -| 'edit' -| 'save' -| 'add' -| 'flexibleSpace' -| 'fixedSpace' -| 'compose' -| 'reply' -| 'action' -| 'organize' -| 'bookmarks' -| 'search' -| 'refresh' -| 'stop' -| 'camera' -| 'trash' -| 'play' -| 'pause' -| 'rewind' -| 'fastForward' -| 'undo' -| 'redo' -| 'close'; + | 'done' + | 'cancel' + | 'edit' + | 'save' + | 'add' + | 'flexibleSpace' + | 'fixedSpace' + | 'compose' + | 'reply' + | 'action' + | 'organize' + | 'bookmarks' + | 'search' + | 'refresh' + | 'stop' + | 'camera' + | 'trash' + | 'play' + | 'pause' + | 'rewind' + | 'fastForward' + | 'undo' + | 'redo' + | 'close'; export interface ToolbarMenuItem { -id?: string; -title: string; -icon?: string; -destructive?: boolean; -disabled?: boolean; -children?: ToolbarMenuItem[]; + id?: string; + title: string; + icon?: string; + destructive?: boolean; + disabled?: boolean; + children?: ToolbarMenuItem[]; } export interface ToolbarMenuActionEvent { -id: string; -title: string; + id: string; + title: string; } // TabBar types export type TabBarSystemItem = -| 'more' -| 'favorites' -| 'featured' -| 'topRated' -| 'recents' -| 'contacts' -| 'history' -| 'bookmarks' -| 'search' -| 'downloads' -| 'mostRecent' -| 'mostViewed'; + | 'more' + | 'favorites' + | 'featured' + | 'topRated' + | 'recents' + | 'contacts' + | 'history' + | 'bookmarks' + | 'search' + | 'downloads' + | 'mostRecent' + | 'mostViewed'; export interface TabBarItem { -title: string; -icon?: string; -systemItem?: TabBarSystemItem; + title: string; + icon?: string; + systemItem?: TabBarSystemItem; } // Event types export interface ValueChangeEvent { -value: boolean; + value: boolean; } export interface SegmentedControlValueChangeEvent { -selectedIndex: number; + selectedIndex: number; } export interface SearchBarChangeEvent { -text: string; + text: string; } export interface TabBarPressEvent { -index: number; + index: number; } // Component prop types export interface NativeMaterialViewProps extends ViewProps { -material?: MaterialType; -onPress?: BubblingEventHandler>; + material?: MaterialType; + onPress?: BubblingEventHandler>; } export interface NativeButtonProps extends ViewProps { -title: string; -buttonStyle?: ButtonStyle; -onPress?: BubblingEventHandler>; + title: string; + buttonStyle?: ButtonStyle; + onPress?: BubblingEventHandler>; } export interface NativeSwitchProps extends ViewProps { -value?: boolean; -onTintColor?: string; -thumbTintColor?: string; -disabled?: boolean; -onValueChange?: BubblingEventHandler; + value?: boolean; + onTintColor?: string; + thumbTintColor?: string; + disabled?: boolean; + onValueChange?: BubblingEventHandler; } export interface NativeSegmentedControlProps extends ViewProps { -segments: string[]; -selectedIndex?: number; -onValueChange?: BubblingEventHandler; + segments: string[]; + selectedIndex?: number; + onValueChange?: BubblingEventHandler; } export interface NativeSearchBarProps extends ViewProps { -placeholder?: string; -text?: string; -onTextChanged?: DirectEventHandler; -onSearchPressed?: DirectEventHandler; -onCancelPressed?: DirectEventHandler>; + placeholder?: string; + text?: string; + onTextChanged?: DirectEventHandler; + onSearchPressed?: DirectEventHandler; + onCancelPressed?: DirectEventHandler>; } export interface NativeNavigationBarProps extends ViewProps { -title?: string; -translucent?: boolean; + title?: string; + translucent?: boolean; } export interface NativeToolbarProps extends ViewProps { -translucent?: boolean; -children?: React.ReactNode; + translucent?: boolean; + children?: React.ReactNode; } export interface NativeToolbarButtonProps extends ViewProps { -icon?: string; -title?: string; -systemItem?: ToolbarSystemItem; -disabled?: boolean; -onPress?: BubblingEventHandler>; + icon?: string; + title?: string; + systemItem?: ToolbarSystemItem; + disabled?: boolean; + onPress?: BubblingEventHandler>; } export interface NativeToolbarMenuProps extends ViewProps { -icon?: string; -title?: string; -menuItems: ToolbarMenuItem[]; -disabled?: boolean; -onMenuAction?: BubblingEventHandler; + icon?: string; + title?: string; + menuItems: ToolbarMenuItem[]; + disabled?: boolean; + onMenuAction?: BubblingEventHandler; } export interface NativeTabBarProps extends ViewProps { -items: TabBarItem[]; -selectedIndex?: number; -translucent?: boolean; -onTabPress?: BubblingEventHandler; + items: TabBarItem[]; + selectedIndex?: number; + translucent?: boolean; + onTabPress?: BubblingEventHandler; } export interface NativeGroupedContainerProps extends ViewProps { -insetGrouped?: boolean; + insetGrouped?: boolean; } export interface NativeCardContainerProps extends ViewProps { -cornerRadius?: number; + cornerRadius?: number; } // Stack view types export type StackAxis = 'vertical' | 'horizontal'; -export type StackAlignment = 'fill' | 'leading' | 'trailing' | 'center' | 'firstBaseline' | 'lastBaseline'; -export type StackDistribution = 'fill' | 'fillEqually' | 'fillProportionally' | 'equalSpacing' | 'equalCentering'; +export type StackAlignment = + | 'fill' + | 'leading' + | 'trailing' + | 'center' + | 'firstBaseline' + | 'lastBaseline'; +export type StackDistribution = + | 'fill' + | 'fillEqually' + | 'fillProportionally' + | 'equalSpacing' + | 'equalCentering'; export interface NativeStackViewProps extends ViewProps { -axis?: StackAxis; -spacing?: number; -alignment?: StackAlignment; -distribution?: StackDistribution; + axis?: StackAxis; + spacing?: number; + alignment?: StackAlignment; + distribution?: StackDistribution; } export interface NativeMenuButtonProps extends ViewProps { icon?: string; tintColorHex?: string; menuItems: ToolbarMenuItem[]; onMenuAction?: DirectEventHandler; -} \ No newline at end of file +} From b2def23ce92ab38fe353622843ef4ee5bd300309 Mon Sep 17 00:00:00 2001 From: levinismynameirl Date: Wed, 25 Feb 2026 15:09:52 +0100 Subject: [PATCH 07/12] Add docstrings to swift, header, objC and ts/tsx files --- CONTRIBUTING.md | 4 + LICENSE | 3 - ios/LRNativeButtonManager.m | 26 +++++ ios/LRNativeButtonManager.swift | 56 +++++++--- ios/LRNativeCardContainerManager.m | 26 +++++ ios/LRNativeCardContainerManager.swift | 43 ++++++-- ios/LRNativeGroupedContainerManager.m | 26 +++++ ios/LRNativeGroupedContainerManager.swift | 40 ++++++-- ios/LRNativeMaterialViewManager.m | 26 +++++ ios/LRNativeMaterialViewManager.swift | 58 +++++++---- ios/LRNativeMenuButtonManager.m | 26 +++++ ios/LRNativeMenuButtonManager.swift | 26 +++++ ios/LRNativeNavigationBarManager.m | 26 +++++ ios/LRNativeNavigationBarManager.swift | 52 +++++++--- ios/LRNativeSearchBarManager.m | 26 +++++ ios/LRNativeSearchBarManager.swift | 54 +++++++--- ios/LRNativeSegmentedControlManager.m | 26 +++++ ios/LRNativeSegmentedControlView.swift | 33 +++++- ios/LRNativeStackViewManager.m | 26 +++++ ios/LRNativeStackViewManager.swift | 65 ++++++++---- ios/LRNativeSwitchManager.m | 26 +++++ ios/LRNativeSwitchManager.swift | 55 +++++++--- ios/LRNativeTabBarManager.m | 26 +++++ ios/LRNativeTabBarManager.swift | 70 +++++++++---- ios/LRNativeToolbarButtonManager.m | 26 +++++ ios/LRNativeToolbarButtonManager.swift | 61 +++++++---- ios/LRNativeToolbarManager.m | 26 +++++ ios/LRNativeToolbarManager.swift | 67 ++++++++---- ios/LRNativeToolbarMenuManager.m | 26 +++++ ios/LRNativeToolbarMenuManager.swift | 65 ++++++++---- ios/LiquidReact-Bridging-Header.h | 32 ++++-- ios/LiquidReactModule.m | 26 +++++ ios/LiquidReactModule.swift | 26 +++++ src/components.tsx | 119 ++++++++-------------- src/index.ts | 28 ++++- src/nativeComponents.ts | 29 +++++- src/types.ts | 26 +++++ 37 files changed, 1118 insertions(+), 284 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index edefa65..83054b5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,6 +32,10 @@ We have a few standards that we ask all contributors to follow when submitting a **7.1. NOTE:** As the library is focused specifically on iOS Liquid-Glass components, which can be difficult to implement and often require a lot of knowledge on how the infrastructure of the library works, we ask that all contributions related to new components (this doesn't include improvements, bug fixes, documentation, etc) be made by trusted contributors and/or maintainers. This is not a hard rule, but if you're unexperienced with the library, it's easier to let someone with more expertise handle the implementation of new components so no confusion arises from who does what and no duplicate pull requests come up. + **8. Style guidelines:** We ask that all code contributions follow our style guidelines to maintain consistency across the codebase. This includes using clear and descriptive variable names, writing comments where necessary, and following the existing code structure. Please refer to our style guidelines below for more details. + + **9. OS and IDE:** We would prefer that all contributions be made on a macOS device using Xcode and a code editor of your choice (VSCode, WebStorm, etc) to ensure that the code is properly tested and works as expected on the intended platform. However, we understand that not everyone has access to a macOS device, so if you are contributing from a different operating system, please make sure to test your changes on an iOS simulator or device to ensure compatibility. This is important because we want to make sure that all contributions work as expected on the intended platform and do not introduce any issues or bugs. If you are unable to test your changes on an iOS simulator or device, please let us know in the pull request description so that we can assist you with testing and ensure that your contribution meets our standards. + ## Style guidelines When contributing to Liquid-React, please follow our style guidelines to ensure that your code is consistent with the rest of the library. This includes using clear and descriptive variable names, writing comments where necessary, and following the existing code structure. diff --git a/LICENSE b/LICENSE index 600810b..0effdaa 100644 --- a/LICENSE +++ b/LICENSE @@ -19,6 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -Thank you pookies :3 diff --git a/ios/LRNativeButtonManager.m b/ios/LRNativeButtonManager.m index 9ea7783..a74f01c 100644 --- a/ios/LRNativeButtonManager.m +++ b/ios/LRNativeButtonManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeButton view properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeButtonManager, RCTViewManager) diff --git a/ios/LRNativeButtonManager.swift b/ios/LRNativeButtonManager.swift index 81c2f0b..e554ea8 100644 --- a/ios/LRNativeButtonManager.swift +++ b/ios/LRNativeButtonManager.swift @@ -1,47 +1,73 @@ +/** + * RCT view manager and UIView for NativeButton, bridging UIButton with system button configurations. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeButtonManager) class LRNativeButtonManager: RCTViewManager { - + override func view() -> UIView! { return NativeButton() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeButton: UIView { - + private var button: UIButton! - + @objc var title: NSString = "" { didSet { updateButton() } } - + @objc var buttonStyle: NSString = "filled" { didSet { updateButton() } } - + @objc var onPress: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) setupButton() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupButton() } - + private func setupButton() { var configuration = UIButton.Configuration.filled() button = UIButton(configuration: configuration, primaryAction: nil) @@ -51,10 +77,10 @@ class NativeButton: UIView { addSubview(button) updateButton() } - + private func updateButton() { var configuration: UIButton.Configuration - + switch buttonStyle as String { case "filled": configuration = .filled() @@ -73,20 +99,20 @@ class NativeButton: UIView { default: configuration = .filled() } - + configuration.title = title as String button.configuration = configuration } - + @objc private func handlePress() { onPress?([:]) } - + override func layoutSubviews() { super.layoutSubviews() button.frame = self.bounds } - + override var intrinsicContentSize: CGSize { return CGSize(width: UIView.noIntrinsicMetric, height: 44) } diff --git a/ios/LRNativeCardContainerManager.m b/ios/LRNativeCardContainerManager.m index 27c4eda..4ea2f6a 100644 --- a/ios/LRNativeCardContainerManager.m +++ b/ios/LRNativeCardContainerManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeCardContainer properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeCardContainerManager, RCTViewManager) diff --git a/ios/LRNativeCardContainerManager.swift b/ios/LRNativeCardContainerManager.swift index 53f652b..0bf9443 100644 --- a/ios/LRNativeCardContainerManager.swift +++ b/ios/LRNativeCardContainerManager.swift @@ -1,46 +1,69 @@ +/** + * RCT view manager and UIView for NativeCardContainer, a UIView with system background and continuous corner radius. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeCardContainerManager) class LRNativeCardContainerManager: RCTViewManager { - + override func view() -> UIView! { return NativeCardContainer() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeCardContainer: UIView { - + @objc var cornerRadius: CGFloat = 10.0 { didSet { updateAppearance() } } - + override init(frame: CGRect) { super.init(frame: frame) setupView() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupView() } - + private func setupView() { updateAppearance() } - + private func updateAppearance() { - // Use system background color (UIKit decides on light/dark) backgroundColor = .secondarySystemGroupedBackground - - // Use native corner radius layer.cornerRadius = cornerRadius layer.cornerCurve = .continuous layer.masksToBounds = true diff --git a/ios/LRNativeGroupedContainerManager.m b/ios/LRNativeGroupedContainerManager.m index 3dda5a9..a5b7803 100644 --- a/ios/LRNativeGroupedContainerManager.m +++ b/ios/LRNativeGroupedContainerManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeGroupedContainer properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeGroupedContainerManager, RCTViewManager) diff --git a/ios/LRNativeGroupedContainerManager.swift b/ios/LRNativeGroupedContainerManager.swift index 53fbeba..c0664a3 100644 --- a/ios/LRNativeGroupedContainerManager.swift +++ b/ios/LRNativeGroupedContainerManager.swift @@ -1,41 +1,67 @@ +/** + * RCT view manager and UIView for NativeGroupedContainer, providing system grouped background colors. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeGroupedContainerManager) class LRNativeGroupedContainerManager: RCTViewManager { - + override func view() -> UIView! { return NativeGroupedContainer() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeGroupedContainer: UIView { - + @objc var insetGrouped: Bool = true { didSet { updateBackground() } } - + override init(frame: CGRect) { super.init(frame: frame) setupView() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupView() } - + private func setupView() { updateBackground() } - + private func updateBackground() { if insetGrouped { backgroundColor = .systemGroupedBackground diff --git a/ios/LRNativeMaterialViewManager.m b/ios/LRNativeMaterialViewManager.m index e2495a1..dc2ed98 100644 --- a/ios/LRNativeMaterialViewManager.m +++ b/ios/LRNativeMaterialViewManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeMaterialView properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeMaterialViewManager, RCTViewManager) diff --git a/ios/LRNativeMaterialViewManager.swift b/ios/LRNativeMaterialViewManager.swift index 83ca573..44e729c 100644 --- a/ios/LRNativeMaterialViewManager.swift +++ b/ios/LRNativeMaterialViewManager.swift @@ -1,14 +1,41 @@ +/** + * RCT view manager and UIView for NativeMaterialView, bridging UIVisualEffectView with system blur materials. + * ⚠️ Currently broken — React Native children do not render correctly inside this view. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeMaterialViewManager) class LRNativeMaterialViewManager: RCTViewManager { - + override func view() -> UIView! { return NativeMaterialView() } - + override static func requiresMainQueueSetup() -> Bool { return true } @@ -16,40 +43,37 @@ class LRNativeMaterialViewManager: RCTViewManager { class NativeMaterialView: UIView { // WARNING: This implementation is currently broken. React Native children do not render correctly. - + private var effectView: UIVisualEffectView! private var contentView: UIView! - + @objc var material: NSString = "systemMaterial" { didSet { updateMaterial() } } - // ...existing code... - + @objc var onPress: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) self.clipsToBounds = true setupView() } - + required init?(coder: NSCoder) { super.init(coder: coder) self.clipsToBounds = true setupView() } - + private func setupView() { - // Create blur effect view at the back let blurEffect = getBlurEffect(for: material as String) effectView = UIVisualEffectView(effect: blurEffect) effectView.frame = bounds effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] effectView.isUserInteractionEnabled = false addSubview(effectView) - // Create a content view for React Native children contentView = UIView() contentView.frame = bounds contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] @@ -71,15 +95,15 @@ class NativeMaterialView: UIView { override func didUpdateReactSubviews() { contentView.setNeedsLayout() } - + private func updateMaterial() { let blurEffect = getBlurEffect(for: material as String) effectView.effect = blurEffect } - + private func getBlurEffect(for material: String) -> UIBlurEffect { let style: UIBlurEffect.Style - + switch material { case "systemUltraThinMaterial": style = .systemUltraThinMaterial @@ -114,14 +138,14 @@ class NativeMaterialView: UIView { default: style = .systemMaterial } - + return UIBlurEffect(style: style) } - + @objc private func handleTap() { onPress?([:]) } - + override func layoutSubviews() { super.layoutSubviews() effectView.frame = bounds diff --git a/ios/LRNativeMenuButtonManager.m b/ios/LRNativeMenuButtonManager.m index 0b94409..c8672f5 100644 --- a/ios/LRNativeMenuButtonManager.m +++ b/ios/LRNativeMenuButtonManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeMenuButton properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeMenuButtonManager, RCTViewManager) diff --git a/ios/LRNativeMenuButtonManager.swift b/ios/LRNativeMenuButtonManager.swift index 6106c1d..13567e6 100644 --- a/ios/LRNativeMenuButtonManager.swift +++ b/ios/LRNativeMenuButtonManager.swift @@ -1,3 +1,29 @@ +/** + * RCT view manager and UIView for NativeMenuButton, a standalone UIButton that shows a UIMenu on press. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React diff --git a/ios/LRNativeNavigationBarManager.m b/ios/LRNativeNavigationBarManager.m index c2785ef..3c08f46 100644 --- a/ios/LRNativeNavigationBarManager.m +++ b/ios/LRNativeNavigationBarManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeNavigationBar properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeNavigationBarManager, RCTViewManager) diff --git a/ios/LRNativeNavigationBarManager.swift b/ios/LRNativeNavigationBarManager.swift index 0c11f0b..5326bc6 100644 --- a/ios/LRNativeNavigationBarManager.swift +++ b/ios/LRNativeNavigationBarManager.swift @@ -1,52 +1,78 @@ +/** + * RCT view manager and UIView for NativeNavigationBar, bridging UINavigationBar. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeNavigationBarManager) class LRNativeNavigationBarManager: RCTViewManager { - + override func view() -> UIView! { return NativeNavigationBar() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeNavigationBar: UIView { - + private var navigationBar: UINavigationBar! private var navigationItem: UINavigationItem! - + @objc var title: NSString = "" { didSet { navigationItem.title = title as String } } - + @objc var barTintColor: UIColor? { didSet { updateAppearance() } } - + @objc var translucent: Bool = true { didSet { navigationBar.isTranslucent = translucent } } - + override init(frame: CGRect) { super.init(frame: frame) setupNavigationBar() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupNavigationBar() } - + private func setupNavigationBar() { navigationBar = UINavigationBar() navigationItem = UINavigationItem() @@ -55,21 +81,21 @@ class NativeNavigationBar: UIView { addSubview(navigationBar) updateAppearance() } - + private func updateAppearance() { let appearance = UINavigationBarAppearance() - + if let color = barTintColor { appearance.backgroundColor = color } else { appearance.configureWithDefaultBackground() } - + navigationBar.standardAppearance = appearance navigationBar.scrollEdgeAppearance = appearance navigationBar.compactAppearance = appearance } - + override func layoutSubviews() { super.layoutSubviews() navigationBar.frame = bounds diff --git a/ios/LRNativeSearchBarManager.m b/ios/LRNativeSearchBarManager.m index 34b5fde..6cd4a95 100644 --- a/ios/LRNativeSearchBarManager.m +++ b/ios/LRNativeSearchBarManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeSearchBar properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeSearchBarManager, RCTViewManager) diff --git a/ios/LRNativeSearchBarManager.swift b/ios/LRNativeSearchBarManager.swift index 1f4b83e..782a1d3 100644 --- a/ios/LRNativeSearchBarManager.swift +++ b/ios/LRNativeSearchBarManager.swift @@ -1,29 +1,55 @@ +/** + * RCT view manager and UIView for NativeSearchBar, bridging UISearchBar. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeSearchBarManager) class LRNativeSearchBarManager: RCTViewManager { - + override func view() -> UIView! { return NativeSearchBar() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeSearchBar: UIView, UISearchBarDelegate { - + private var searchBar: UISearchBar! - + @objc var placeholder: NSString = "" { didSet { searchBar.placeholder = placeholder as String } } - + @objc var text: NSString = "" { didSet { if searchBar.text != text as String { @@ -31,23 +57,23 @@ class NativeSearchBar: UIView, UISearchBarDelegate { } } } - + @objc var onTextChanged: RCTDirectEventBlock? @objc var onSearchPressed: RCTDirectEventBlock? @objc var onCancelPressed: RCTDirectEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) setupSearchBar() backgroundColor = .clear } - + required init?(coder: NSCoder) { super.init(coder: coder) setupSearchBar() backgroundColor = .clear } - + private func setupSearchBar() { searchBar = UISearchBar() searchBar.delegate = self @@ -56,24 +82,24 @@ class NativeSearchBar: UIView, UISearchBarDelegate { searchBar.backgroundImage = UIImage() addSubview(searchBar) } - + // MARK: - UISearchBarDelegate - + func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { onTextChanged?(["text": searchText]) } - + func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() onSearchPressed?(["text": searchBar.text ?? ""]) } - + func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() searchBar.text = "" onCancelPressed?([:]) } - + override func layoutSubviews() { super.layoutSubviews() searchBar.frame = bounds diff --git a/ios/LRNativeSegmentedControlManager.m b/ios/LRNativeSegmentedControlManager.m index abc9928..f834000 100644 --- a/ios/LRNativeSegmentedControlManager.m +++ b/ios/LRNativeSegmentedControlManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeSegmentedControl properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeSegmentedControlManager, RCTViewManager) diff --git a/ios/LRNativeSegmentedControlView.swift b/ios/LRNativeSegmentedControlView.swift index 910c1df..3770d47 100644 --- a/ios/LRNativeSegmentedControlView.swift +++ b/ios/LRNativeSegmentedControlView.swift @@ -1,3 +1,30 @@ +/** + * RCT view manager and UIView for NativeSegmentedControl, bridging UISegmentedControl. + * ⚠️ Currently broken — liquid glass selection rendering is unreliable when bridged into React Native. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @@ -16,7 +43,7 @@ class NativeSegmentedControlView: UIView { // WARNING: This implementation is currently broken. UIKit liquid glass rendering is not reliable in React Native context. private let materialView = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterial)) private let segmentedControl = UISegmentedControl() - + @objc var segments: NSArray = [] { didSet { updateSegments() @@ -32,7 +59,7 @@ class NativeSegmentedControlView: UIView { } } @objc var onValueChange: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) self.backgroundColor = .clear @@ -46,7 +73,7 @@ class NativeSegmentedControlView: UIView { segmentedControl.selectedSegmentTintColor = nil } required init?(coder: NSCoder) { fatalError() } - + private func updateSegments() { segmentedControl.removeAllSegments() for (index, segment) in segments.enumerated() { diff --git a/ios/LRNativeStackViewManager.m b/ios/LRNativeStackViewManager.m index 7d57737..713d360 100644 --- a/ios/LRNativeStackViewManager.m +++ b/ios/LRNativeStackViewManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeStackView properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeStackViewManager, RCTViewManager) diff --git a/ios/LRNativeStackViewManager.swift b/ios/LRNativeStackViewManager.swift index b42c672..801eeeb 100644 --- a/ios/LRNativeStackViewManager.swift +++ b/ios/LRNativeStackViewManager.swift @@ -1,61 +1,87 @@ +/** + * RCT view manager and UIView for NativeStackView, bridging UIStackView for axis-based child layout. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeStackViewManager) class LRNativeStackViewManager: RCTViewManager { - + override func view() -> UIView! { return NativeStackView() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeStackView: UIView { - + private var stackView: UIStackView! - + @objc var axis: NSString = "vertical" { didSet { updateAxis() } } - + @objc var spacing: NSNumber = 8 { didSet { stackView.spacing = CGFloat(truncating: spacing) } } - + @objc var alignment: NSString = "fill" { didSet { updateAlignment() } } - + @objc var distribution: NSString = "fill" { didSet { updateDistribution() } } - + override init(frame: CGRect) { super.init(frame: frame) self.backgroundColor = .clear self.clipsToBounds = false setupStackView() } - + required init?(coder: NSCoder) { super.init(coder: coder) self.backgroundColor = .clear self.clipsToBounds = false setupStackView() } - + private func setupStackView() { stackView = UIStackView() stackView.translatesAutoresizingMaskIntoConstraints = false @@ -64,7 +90,7 @@ class NativeStackView: UIView { stackView.alignment = .fill stackView.distribution = .fill addSubview(stackView) - + NSLayoutConstraint.activate([ stackView.topAnchor.constraint(equalTo: topAnchor), stackView.leadingAnchor.constraint(equalTo: leadingAnchor), @@ -72,11 +98,11 @@ class NativeStackView: UIView { stackView.bottomAnchor.constraint(equalTo: bottomAnchor) ]) } - + private func updateAxis() { stackView.axis = (axis as String) == "horizontal" ? .horizontal : .vertical } - + private func updateAlignment() { switch alignment as String { case "leading": @@ -95,7 +121,7 @@ class NativeStackView: UIView { stackView.alignment = .fill } } - + private func updateDistribution() { switch distribution as String { case "fill": @@ -112,7 +138,7 @@ class NativeStackView: UIView { stackView.distribution = .fill } } - + override func insertReactSubview(_ subview: UIView!, at atIndex: Int) { if atIndex >= stackView.arrangedSubviews.count { stackView.addArrangedSubview(subview) @@ -123,27 +149,26 @@ class NativeStackView: UIView { setNeedsLayout() layoutIfNeeded() } - + override func removeReactSubview(_ subview: UIView!) { stackView.removeArrangedSubview(subview) subview.removeFromSuperview() invalidateIntrinsicContentSize() setNeedsLayout() } - + override func didUpdateReactSubviews() { super.didUpdateReactSubviews() invalidateIntrinsicContentSize() setNeedsLayout() layoutIfNeeded() } - + override var intrinsicContentSize: CGSize { - // Calculate total height from all arranged subviews let height = stackView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height return CGSize(width: UIView.noIntrinsicMetric, height: height) } - + override func layoutSubviews() { super.layoutSubviews() invalidateIntrinsicContentSize() diff --git a/ios/LRNativeSwitchManager.m b/ios/LRNativeSwitchManager.m index 9c9a75c..f4ecf0f 100644 --- a/ios/LRNativeSwitchManager.m +++ b/ios/LRNativeSwitchManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeSwitch properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeSwitchManager, RCTViewManager) diff --git a/ios/LRNativeSwitchManager.swift b/ios/LRNativeSwitchManager.swift index 5f62f00..071fa88 100644 --- a/ios/LRNativeSwitchManager.swift +++ b/ios/LRNativeSwitchManager.swift @@ -1,23 +1,49 @@ +/** + * RCT view manager and UIView for NativeSwitch, bridging UISwitch. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeSwitchManager) class LRNativeSwitchManager: RCTViewManager { - + override func view() -> UIView! { return NativeSwitch() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeSwitch: UIView { - + private var switchControl: UISwitch! - + @objc var value: Bool = false { didSet { if switchControl.isOn != value { @@ -25,51 +51,50 @@ class NativeSwitch: UIView { } } } - + @objc var onTintColor: UIColor? { didSet { switchControl.onTintColor = onTintColor } } - + @objc var thumbTintColor: UIColor? { didSet { switchControl.thumbTintColor = thumbTintColor } } - + @objc var disabled: Bool = false { didSet { switchControl.isEnabled = !disabled } } - + @objc var onValueChange: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) setupSwitch() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupSwitch() } - + private func setupSwitch() { switchControl = UISwitch() switchControl.addTarget(self, action: #selector(handleValueChange), for: .valueChanged) autoresizingMask = [.flexibleWidth, .flexibleHeight] addSubview(switchControl) } - + @objc private func handleValueChange() { onValueChange?(["value": switchControl.isOn]) } - + override func layoutSubviews() { super.layoutSubviews() - // Center the switch within this view's bounds let switchSize = switchControl.intrinsicContentSize switchControl.frame = CGRect( x: (bounds.width - switchSize.width) / 2, @@ -78,7 +103,7 @@ class NativeSwitch: UIView { height: switchSize.height ) } - + override var intrinsicContentSize: CGSize { return switchControl.intrinsicContentSize } diff --git a/ios/LRNativeTabBarManager.m b/ios/LRNativeTabBarManager.m index a16dbf4..929137b 100644 --- a/ios/LRNativeTabBarManager.m +++ b/ios/LRNativeTabBarManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeTabBar properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeTabBarManager, RCTViewManager) diff --git a/ios/LRNativeTabBarManager.swift b/ios/LRNativeTabBarManager.swift index d11f392..63c6f38 100644 --- a/ios/LRNativeTabBarManager.swift +++ b/ios/LRNativeTabBarManager.swift @@ -1,14 +1,40 @@ +/** + * RCT view manager and UIView for NativeTabBar, bridging UITabBar. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeTabBarManager) class LRNativeTabBarManager: RCTViewManager { - + override func view() -> UIView! { return NativeTabBar() } - + override static func requiresMainQueueSetup() -> Bool { return true } @@ -21,15 +47,15 @@ class NativeTabBar: UIView { let height = barHeight?.doubleValue ?? 49.0 return CGSize(width: UIView.noIntrinsicMetric, height: CGFloat(height)) } - + private var tabBar: UITabBar! - + @objc var items: NSArray = [] { didSet { updateItems() } } - + @objc var selectedIndex: NSInteger = 0 { didSet { if let items = tabBar.items, selectedIndex >= 0 && selectedIndex < items.count { @@ -37,67 +63,67 @@ class NativeTabBar: UIView { } } } - + @objc var translucent: Bool = true { didSet { tabBar.isTranslucent = translucent } } - + @objc var onTabPress: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) setupTabBar() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupTabBar() } - + private func setupTabBar() { tabBar = UITabBar() tabBar.isTranslucent = true tabBar.delegate = self addSubview(tabBar) } - + private func updateItems() { var tabBarItems: [UITabBarItem] = [] - + for item in items { if let itemDict = item as? [String: Any], let title = itemDict["title"] as? String { - + let tabBarItem = UITabBarItem() tabBarItem.title = title - + if let systemItem = itemDict["systemItem"] as? String { if let systemTabBarItem = getSystemTabBarItem(systemItem) { tabBarItems.append(systemTabBarItem) continue } } - + if let iconName = itemDict["icon"] as? String { tabBarItem.image = UIImage(systemName: iconName) } - + tabBarItems.append(tabBarItem) } } - + tabBar.items = tabBarItems - + if selectedIndex >= 0 && selectedIndex < tabBarItems.count { tabBar.selectedItem = tabBarItems[selectedIndex] } } - + private func getSystemTabBarItem(_ systemItem: String) -> UITabBarItem? { let type: UITabBarItem.SystemItem - + switch systemItem { case "more": type = .more @@ -126,10 +152,10 @@ class NativeTabBar: UIView { default: return nil } - + return UITabBarItem(tabBarSystemItem: type, tag: 0) } - + override func layoutSubviews() { super.layoutSubviews() let height = barHeight?.doubleValue ?? Double(bounds.height) diff --git a/ios/LRNativeToolbarButtonManager.m b/ios/LRNativeToolbarButtonManager.m index 53b4362..552733e 100644 --- a/ios/LRNativeToolbarButtonManager.m +++ b/ios/LRNativeToolbarButtonManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeToolbarButton properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeToolbarButtonManager, RCTViewManager) diff --git a/ios/LRNativeToolbarButtonManager.swift b/ios/LRNativeToolbarButtonManager.swift index fcc1717..cad167b 100644 --- a/ios/LRNativeToolbarButtonManager.swift +++ b/ios/LRNativeToolbarButtonManager.swift @@ -1,50 +1,77 @@ +/** + * RCT view manager and UIView for NativeToolbarButton, bridging UIBarButtonItem. + * Must be used as a direct child of NativeToolbar. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeToolbarButtonManager) class LRNativeToolbarButtonManager: RCTViewManager { - + override func view() -> UIView! { return NativeToolbarButtonContainer() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeToolbarButtonContainer: UIView { - + private(set) var barButtonItem: UIBarButtonItem! weak var parentToolbar: NativeToolbar? - + @objc var icon: NSString = "" { didSet { updateButton() } } - + @objc var title: NSString = "" { didSet { updateButton() } } - + @objc var systemItem: NSString = "" { didSet { updateButton() } } - + @objc var disabled: Bool = false { didSet { barButtonItem.isEnabled = !disabled } } - + @objc var onPress: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) setupButton() @@ -55,19 +82,19 @@ class NativeToolbarButtonContainer: UIView { self.alpha = 0 self.isUserInteractionEnabled = false } - + required init?(coder: NSCoder) { super.init(coder: coder) setupButton() } - + private func setupButton() { barButtonItem = UIBarButtonItem() barButtonItem.target = self barButtonItem.action = #selector(handlePress) updateButton() } - + private func updateButton() { if systemItem.length > 0 { if let item = createSystemItem(systemItem as String) { @@ -82,13 +109,13 @@ class NativeToolbarButtonContainer: UIView { barButtonItem.title = title as String barButtonItem.image = nil } - + barButtonItem.isEnabled = !disabled } - + private func createSystemItem(_ systemItem: String) -> UIBarButtonItem? { let type: UIBarButtonItem.SystemItem - + switch systemItem { case "done": type = .done case "cancel": type = .cancel @@ -114,10 +141,10 @@ class NativeToolbarButtonContainer: UIView { case "close": type = .close default: return nil } - + return UIBarButtonItem(barButtonSystemItem: type, target: self, action: #selector(handlePress)) } - + @objc private func handlePress() { let data: [String: Any] = ["icon": icon as String, "title": title as String] // Dispatch through parent toolbar (visible view) so RN receives the event diff --git a/ios/LRNativeToolbarManager.m b/ios/LRNativeToolbarManager.m index e909361..426c805 100644 --- a/ios/LRNativeToolbarManager.m +++ b/ios/LRNativeToolbarManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeToolbar properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeToolbarManager, RCTViewManager) diff --git a/ios/LRNativeToolbarManager.swift b/ios/LRNativeToolbarManager.swift index 36d2742..9330fb9 100644 --- a/ios/LRNativeToolbarManager.swift +++ b/ios/LRNativeToolbarManager.swift @@ -1,65 +1,92 @@ +/** + * RCT view manager and UIView for NativeToolbar, bridging UIToolbar. + * Accepts NativeToolbarButton and NativeToolbarMenu as React children. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeToolbarManager) class LRNativeToolbarManager: RCTViewManager { - + override func view() -> UIView! { return NativeToolbar() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeToolbar: UIView { - + private var toolbar: UIToolbar! private var buttonContainers: [NativeToolbarButtonContainer] = [] private var menuContainers: [NativeToolbarMenuContainer] = [] - + // Event blocks dispatched from the toolbar (visible view) so RN receives them @objc var onToolbarButtonPress: RCTDirectEventBlock? @objc var onToolbarMenuAction: RCTDirectEventBlock? - + @objc var translucent: Bool = true { didSet { toolbar.isTranslucent = translucent } } - + override init(frame: CGRect) { super.init(frame: frame) setupToolbar() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupToolbar() } - + private func setupToolbar() { toolbar = UIToolbar() toolbar.isTranslucent = true addSubview(toolbar) } - + override func insertReactSubview(_ subview: UIView!, at atIndex: Int) { if let buttonContainer = subview as? NativeToolbarButtonContainer { - // Wire the button to call our onButtonPress instead of its own + // routes events through the toolbar so RN receives them from the visible view buttonContainer.parentToolbar = self buttonContainers.append(buttonContainer) updateToolbarItems() } else if let menuContainer = subview as? NativeToolbarMenuContainer { - // Wire the menu to call our onMenuAction instead of its own + // routes events through the toolbar so RN receives them from the visible view menuContainer.parentToolbar = self menuContainers.append(menuContainer) updateToolbarItems() } } - + override func removeReactSubview(_ subview: UIView!) { if let buttonContainer = subview as? NativeToolbarButtonContainer { if let index = buttonContainers.firstIndex(of: buttonContainer) { @@ -73,35 +100,33 @@ class NativeToolbar: UIView { } } } - - // Called by child NativeToolbarButtonContainer + func dispatchButtonPress(_ data: [String: Any]) { DispatchQueue.main.async { [weak self] in self?.onToolbarButtonPress?(data) } } - - // Called by child NativeToolbarMenuContainer + func dispatchMenuAction(_ data: [String: Any]) { DispatchQueue.main.async { [weak self] in self?.onToolbarMenuAction?(data) } } - + private func updateToolbarItems() { var barButtonItems: [UIBarButtonItem] = [] - + for container in buttonContainers { barButtonItems.append(container.barButtonItem) } - + for container in menuContainers { barButtonItems.append(container.barButtonItem) } - + toolbar.items = barButtonItems } - + override func layoutSubviews() { super.layoutSubviews() toolbar.frame = bounds diff --git a/ios/LRNativeToolbarMenuManager.m b/ios/LRNativeToolbarMenuManager.m index 426d797..602985b 100644 --- a/ios/LRNativeToolbarMenuManager.m +++ b/ios/LRNativeToolbarMenuManager.m @@ -1,3 +1,29 @@ +/** + * Exports NativeToolbarMenu properties to the React Native bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LRNativeToolbarMenuManager, RCTViewManager) diff --git a/ios/LRNativeToolbarMenuManager.swift b/ios/LRNativeToolbarMenuManager.swift index 98010cd..a434741 100644 --- a/ios/LRNativeToolbarMenuManager.swift +++ b/ios/LRNativeToolbarMenuManager.swift @@ -1,50 +1,77 @@ +/** + * RCT view manager and UIView for NativeToolbarMenu, bridging UIBarButtonItem with UIMenu. + * Must be used as a direct child of NativeToolbar. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import UIKit import React @objc(LRNativeToolbarMenuManager) class LRNativeToolbarMenuManager: RCTViewManager { - + override func view() -> UIView! { return NativeToolbarMenuContainer() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeToolbarMenuContainer: UIView { - + private(set) var barButtonItem: UIBarButtonItem! - + @objc var icon: NSString = "ellipsis" { didSet { updateButton() } } - + @objc var title: NSString = "" { didSet { updateButton() } } - + @objc var menuItems: NSArray = [] { didSet { updateMenu() } } - + @objc var disabled: Bool = false { didSet { barButtonItem.isEnabled = !disabled } } - + @objc var onMenuAction: RCTDirectEventBlock? weak var parentToolbar: NativeToolbar? - + override init(frame: CGRect) { super.init(frame: frame) setupButton() @@ -55,18 +82,18 @@ class NativeToolbarMenuContainer: UIView { self.alpha = 0 self.isUserInteractionEnabled = false } - + required init?(coder: NSCoder) { super.init(coder: coder) setupButton() } - + private func setupButton() { let image = UIImage(systemName: "ellipsis") barButtonItem = UIBarButtonItem(image: image, menu: nil) updateButton() } - + private func updateButton() { if icon.length > 0 { barButtonItem.image = UIImage(systemName: icon as String) @@ -76,32 +103,30 @@ class NativeToolbarMenuContainer: UIView { } barButtonItem.isEnabled = !disabled } - + private func updateMenu() { let menuElements = buildMenuElements(from: menuItems as! [[String: Any]]) let menu = UIMenu(children: menuElements) barButtonItem.menu = menu } - + private func buildMenuElements(from items: [[String: Any]]) -> [UIMenuElement] { var elements: [UIMenuElement] = [] - + for item in items { if let children = item["children"] as? [[String: Any]], !children.isEmpty { - // This is a submenu let title = item["title"] as? String ?? "" let image = (item["icon"] as? String).flatMap { UIImage(systemName: $0) } let submenuElements = buildMenuElements(from: children) let submenu = UIMenu(title: title, image: image, children: submenuElements) elements.append(submenu) } else { - // This is a regular action let title = item["title"] as? String ?? "" let image = (item["icon"] as? String).flatMap { UIImage(systemName: $0) } let actionId = item["id"] as? String ?? title let isDestructive = item["destructive"] as? Bool ?? false let isDisabled = item["disabled"] as? Bool ?? false - + var attributes: UIMenuElement.Attributes = [] if isDestructive { attributes.insert(.destructive) @@ -109,7 +134,7 @@ class NativeToolbarMenuContainer: UIView { if isDisabled { attributes.insert(.disabled) } - + let action = UIAction(title: title, image: image, attributes: attributes) { [weak self] _ in let data: [String: Any] = ["id": actionId, "title": title] // Dispatch through parent toolbar (visible view) so RN receives the event @@ -122,7 +147,7 @@ class NativeToolbarMenuContainer: UIView { elements.append(action) } } - + return elements } } diff --git a/ios/LiquidReact-Bridging-Header.h b/ios/LiquidReact-Bridging-Header.h index b2d277e..4354a18 100644 --- a/ios/LiquidReact-Bridging-Header.h +++ b/ios/LiquidReact-Bridging-Header.h @@ -1,9 +1,29 @@ -// -// LiquidReact-Bridging-Header.h -// liquid-react -// -// React Native bridging header for Swift modules -// +/** + * Bridging header that imports React Native's Obj-C headers into Swift. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import #import diff --git a/ios/LiquidReactModule.m b/ios/LiquidReactModule.m index dd9a2c1..38ebd49 100644 --- a/ios/LiquidReactModule.m +++ b/ios/LiquidReactModule.m @@ -1,3 +1,29 @@ +/** + * Exposes the LiquidReact module to the React Native Obj-C bridge. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #import @interface RCT_EXTERN_MODULE(LiquidReact, NSObject) diff --git a/ios/LiquidReactModule.swift b/ios/LiquidReactModule.swift index 40c413d..d0c807f 100644 --- a/ios/LiquidReactModule.swift +++ b/ios/LiquidReactModule.swift @@ -1,3 +1,29 @@ +/** + * Entry point for the LiquidReact React Native module. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import Foundation import React diff --git a/src/components.tsx b/src/components.tsx index 060fedc..b4b8725 100644 --- a/src/components.tsx +++ b/src/components.tsx @@ -1,3 +1,30 @@ +/** + * React component wrappers around native UIKit bridges. + * Each component applies default sizing and passes props to the native layer. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import React from 'react'; import { StyleSheet } from 'react-native'; import { @@ -33,136 +60,74 @@ import type { NativeMenuButtonProps, } from './types'; -/** - * NativeMaterialView - Exposes UIVisualEffectView with system materials - * - * Uses Apple's blur, vibrancy, and depth rendering pipeline. - * All visual properties controlled by iOS. - */ +/** Wraps UIVisualEffectView with system blur materials. ⚠️ Currently broken — RN children don't render inside it. */ export const NativeMaterialView: React.FC = (props) => { return ; }; -/** - * NativeButton - Exposes UIButton with system configurations - * - * Uses native button styles and animations. - */ +/** Wraps UIButton with system button configurations. */ export const NativeButton: React.FC = (props) => { return ; }; -/** - * NativeSwitch - Exposes UISwitch - * - * Native iOS toggle control. - */ +/** Wraps UISwitch. */ export const NativeSwitch: React.FC = (props) => { return ; }; -/** - * NativeSegmentedControl - Exposes UISegmentedControl - * - * Native segmented control with system styling. - */ +/** Wraps UISegmentedControl. Note: liquid glass selection rendering is unreliable when bridged into React Native. */ export const NativeSegmentedControl: React.FC = (props) => { return ( ); }; -/** - * NativeSearchBar - Exposes UISearchBar - * - * Native search bar with minimal style. - */ +/** Wraps UISearchBar. */ export const NativeSearchBar: React.FC = (props) => { return ; }; -/** - * NativeNavigationBar - Exposes UINavigationBar - * - * Native navigation bar with translucent material. - */ +/** Wraps UINavigationBar. */ export const NativeNavigationBar: React.FC = (props) => { return ; }; -/** - * NativeToolbar - Exposes UIToolbar - * - * Native toolbar with support for buttons and menus as children. - * Use with NativeToolbarButton and NativeToolbarMenu components. - */ +/** Wraps UIToolbar. Use NativeToolbarButton and NativeToolbarMenu as children. */ export const NativeToolbar: React.FC = (props) => { return ; }; -/** - * NativeToolbarButton - Exposes UIBarButtonItem - * - * Native toolbar button. Must be used as a child of NativeToolbar. - */ +/** Wraps UIBarButtonItem. Must be a direct child of NativeToolbar. */ export const NativeToolbarButton: React.FC = (props) => { return ; }; -/** - * NativeToolbarMenu - Exposes UIBarButtonItem with UIMenu - * - * Native toolbar menu button with nested menu support. - * Automatically handles cascading menus, animations, and platform differences. - * Must be used as a child of NativeToolbar. - */ +/** Wraps UIBarButtonItem with UIMenu. Supports nested submenus. Must be a direct child of NativeToolbar. */ export const NativeToolbarMenu: React.FC = (props) => { return ; }; -/** - * NativeTabBar - Exposes UITabBar - * - * Native tab bar with system styling. - */ +/** Wraps UITabBar. Set height explicitly via the style prop. */ export const NativeTabBar: React.FC = (props) => { return ; }; -/** - * NativeGroupedContainer - UIView with system grouped background - * - * Uses system background colors for grouped list style. - */ +/** UIView with systemGroupedBackground color. */ export const NativeGroupedContainer: React.FC = (props) => { return ; }; -/** - * NativeCardContainer - UIView with continuous corner radius - * - * System background with native corner curve. - */ +/** UIView with secondary system grouped background and continuous corner radius. */ export const NativeCardContainer: React.FC = (props) => { return ; }; -/** - * NativeStackView - Exposes UIStackView for automatic layout - * - * Native iOS stack layout with axis, spacing, alignment, and distribution. - * Automatically arranges child views without manual positioning. - */ +/** Wraps UIStackView. Arranges children along a vertical or horizontal axis. */ export const NativeStackView: React.FC = (props) => { return ; }; -/** - * NativeMenuButton - Standalone UIButton with UIMenu pull-down - * - * Shows a native iOS pull-down menu anchored to the button. - * Works anywhere (no UIToolbar parent required). - */ +/** Standalone UIButton that shows a UIMenu on press. Works anywhere — no NativeToolbar required. */ export const NativeMenuButton: React.FC = (props) => { return ; }; @@ -193,6 +158,6 @@ const styles = StyleSheet.create({ overflow: 'hidden', }, defaultStack: { - // No default styling - controlled by axis, spacing, alignment, distribution props + // layout is fully prop-driven }, }); diff --git a/src/index.ts b/src/index.ts index 471a857..1368db3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,29 @@ -// Main exports +/** + * Public API surface for liquid-react. Re-exports all components and TypeScript types. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ export { NativeMaterialView, NativeButton, @@ -16,7 +41,6 @@ export { NativeMenuButton, } from './components'; -// Type exports export type { MaterialType, ButtonStyle, diff --git a/src/nativeComponents.ts b/src/nativeComponents.ts index a76dcdc..f53d915 100644 --- a/src/nativeComponents.ts +++ b/src/nativeComponents.ts @@ -1,3 +1,29 @@ +/** + * Registers native UIKit view managers with React Native's requireNativeComponent. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import { Platform, requireNativeComponent, View } from 'react-native'; import type { NativeMaterialViewProps, @@ -16,11 +42,10 @@ import type { NativeMenuButtonProps, } from './types'; -// On web, requireNativeComponent doesn't exist — fall back to View. +// On web, requireNativeComponent doesn't exist - fall back to View. // eslint-disable-next-line @typescript-eslint/no-explicit-any const req = Platform.OS === 'web' ? () => View as any : requireNativeComponent; -// Native component registration export const RNNativeMaterialView = req('LRNativeMaterialView'); export const RNNativeButton = req('LRNativeButton'); export const RNNativeSwitch = req('LRNativeSwitch'); diff --git a/src/types.ts b/src/types.ts index 5e95f9d..2621d50 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,29 @@ +/** + * TypeScript prop types and event payload types for all liquid-react native components. + * + * + * MIT License + * + * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import { ViewProps } from 'react-native'; import type { BubblingEventHandler, From a68db03b1619a427dc45b0de6cf15deb8ae67be6 Mon Sep 17 00:00:00 2001 From: levinismynameirl Date: Wed, 25 Feb 2026 19:01:14 +0100 Subject: [PATCH 08/12] Update CONTRIBUTING.md to include docstring requirements and commit message guidelines; fix wording in EXAMPLES.md and enhance fallback message in QUICK_START.md --- CONTRIBUTING.md | 28 +++++++++++++++++++++++++++- docs/EXAMPLES.md | 2 +- docs/QUICK_START.md | 13 ++++++++----- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 83054b5..7e61979 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,6 +36,15 @@ We have a few standards that we ask all contributors to follow when submitting a **9. OS and IDE:** We would prefer that all contributions be made on a macOS device using Xcode and a code editor of your choice (VSCode, WebStorm, etc) to ensure that the code is properly tested and works as expected on the intended platform. However, we understand that not everyone has access to a macOS device, so if you are contributing from a different operating system, please make sure to test your changes on an iOS simulator or device to ensure compatibility. This is important because we want to make sure that all contributions work as expected on the intended platform and do not introduce any issues or bugs. If you are unable to test your changes on an iOS simulator or device, please let us know in the pull request description so that we can assist you with testing and ensure that your contribution meets our standards. + **10. Docstrings:** We ask that all code contributions include docstrings for any new functions, classes, or components that are added to the codebase. For new source files (files containing code), a file-level docstring should be included at the top of the file in this format: + ```txt + /** + * A brief description of the file's purpose and contents. + * + * License exactly as in the LICENSE file. (can be copy-pasted from there) + */ + ``` + ## Style guidelines When contributing to Liquid-React, please follow our style guidelines to ensure that your code is consistent with the rest of the library. This includes using clear and descriptive variable names, writing comments where necessary, and following the existing code structure. @@ -44,9 +53,26 @@ When contributing to Liquid-React, please follow our style guidelines to ensure - Use PascalCase for component names. - Write clear and concise comments to explain the purpose of your code. - All commits should be prefixed with the type of change in this format: + +What Was Changed[optional Argument]: Short description of the change +Where `What Was Changed` is one of the following: + +```txt +- `Added` - for new components, functions, or features +- `Changed` - for changes to existing code that do not add new features (e.g., refactoring, code cleanup, etc) +- `Fixed` - for bug fixes +- `Docs` - for documentation changes +- `Other` - for changes that do not fit into the above categories (e.g., changes to the build process, CI/CD configuration, etc) +``` + +And `optional Argument` can be used to provide additional context about the change, such as the name of the component that was changed or the type of bug that was fixed. For example: + ```txt -[fix/feat/refactor/docs] Short description of the change +- `Added(Button): New Button component with customizable styles` +- `Fixed(NativeMaterialView): Resolved issue with incorrect rendering on iOS 14` +- `Docs(readTheDocs): Updated index.rst with new table of contents` ``` + - Use the present tense in commit messages (e.g., "Add new feature" instead of "Added new feature"). - Keep commit messages concise and to the point, ideally under 50 characters for the subject line and 72 characters for the body. - Use present tense in commit messages (e.g., "Add new feature" instead of "Added new feature"). diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 250c3cf..7297485 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -1,6 +1,6 @@ # Examples -This directory contains comprehensive examples of using Liquid-React components. +This page contains comprehensive examples of using Liquid-React components. ## Complete App Example diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md index 4ca9a6f..b4a9dd3 100644 --- a/docs/QUICK_START.md +++ b/docs/QUICK_START.md @@ -233,9 +233,12 @@ import { NativeMaterialView } from 'liquid-react'; function MyComponent() { if (Platform.OS !== 'ios') { - return ; + + Liquid-React is iOS-only + ; + return 0; } - + return ; } ``` @@ -247,9 +250,9 @@ Or use React Native's platform-specific files: ## App Store Compliance -✅ Liquid-React uses only public APIs -✅ Safe for App Store submission -✅ No private frameworks or hacks +✅ Liquid-React uses only public APIs +✅ Safe for App Store submission +✅ No private frameworks or hacks See [App Store Compliance](./APP_STORE_COMPLIANCE.md) for details. From 43ff40cc908405220157997ce6674da10036f50f Mon Sep 17 00:00:00 2001 From: levinismynameirl Date: Fri, 27 Feb 2026 18:45:47 +0100 Subject: [PATCH 09/12] fix a LOT of mistakes and oudated stuff in docs (andrei ehem...), create .rst documentation for read the docs page (future use) --- docs/API_REFERENCE.md | 556 +++++++++---------- docs/COMPONENT_MAPPING.md | 12 +- docs/EXAMPLES.md | 23 +- docs/QUICK_START.md | 4 +- docs/README.md | 6 +- docs/forReadTheDocs/api.rst | 344 ++++++++++++ docs/forReadTheDocs/components.rst | 695 ++++++++++++++++++++++++ docs/forReadTheDocs/examples.rst | 397 ++++++++++++++ docs/forReadTheDocs/getting-started.rst | 112 ++++ docs/forReadTheDocs/index.rst | 25 +- readTheDocs.yml | 1 + 11 files changed, 1861 insertions(+), 314 deletions(-) create mode 100644 docs/forReadTheDocs/api.rst create mode 100644 docs/forReadTheDocs/components.rst create mode 100644 docs/forReadTheDocs/examples.rst create mode 100644 docs/forReadTheDocs/getting-started.rst diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index 198ad78..208b820 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -1,333 +1,242 @@ # API Reference -Complete reference for all Liquid-React components, props, and types. - -## Table of Contents -- [Materials & Containers](#materials--containers) -- [Controls](#controls) -- [Navigation](#navigation) -- [Types](#types) +Complete prop reference for all liquid-react components, types, and event payloads. --- -## Materials & Containers +## Components ### NativeMaterialView -Exposes `UIVisualEffectView` with system blur materials. +Wraps `UIVisualEffectView`. Renders the system blur effect. + +> ⚠️ **React Native children don't render inside this component.** The blur effect itself is visible, but child views are not. This is a known bridging issue. + +Default style: `overflow: 'hidden'`. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `material` | `MaterialType` | `'systemMaterial'` | System blur material style | -| `onPress` | `() => void` | `undefined` | Called when view is tapped | -| `style` | `ViewStyle` | `undefined` | React Native style object | -| `children` | `ReactNode` | `undefined` | Child components | - -**Example:** -```jsx - console.log('Pressed')} -> - Content with native blur - -``` - -**UIKit Mapping:** `UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial))` +| `material` | `MaterialType` | `'systemMaterial'` | The UIKit blur material. See [MaterialType](#materialtype). | +| `onPress` | `(e) => void` | — | Fired on tap. `e.nativeEvent` is empty. | +| `style` | `ViewStyle` | — | Width/height or flex required. | --- -### NativeGroupedContainer +### NativeButton -UIView with system grouped background color. +Wraps `UIButton` with `UIButton.Configuration` styles. + +Default style: `height: 44`. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `insetGrouped` | `boolean` | `true` | Use inset grouped style | -| `style` | `ViewStyle` | `undefined` | React Native style object | -| `children` | `ReactNode` | `undefined` | Child components | - -**Example:** -```jsx - - Grouped content - -``` - -**UIKit Mapping:** `UIView` with `backgroundColor = .systemGroupedBackground` +| `title` | `string` | required | Button label. | +| `buttonStyle` | `ButtonStyle` | `'filled'` | Visual style. See [ButtonStyle](#buttonstyle). | +| `onPress` | `(e) => void` | — | Fired on tap. `e.nativeEvent` is empty. | +| `style` | `ViewStyle` | — | Use to set width. | --- -### NativeCardContainer +### NativeSwitch + +Wraps `UISwitch`. -UIView with continuous corner radius. +No default size — uses the switch's intrinsic size. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `cornerRadius` | `number` | `10` | Corner radius in points | -| `style` | `ViewStyle` | `undefined` | React Native style object | -| `children` | `ReactNode` | `undefined` | Child components | - -**Example:** -```jsx - - Card content - -``` - -**UIKit Mapping:** `UIView` with `layer.cornerRadius` and `layer.cornerCurve = .continuous` +| `value` | `boolean` | `false` | Controlled on/off state. | +| `onTintColor` | `string` | system tint | Track color when on (hex string, e.g. `'#007AFF'`). | +| `thumbTintColor` | `string` | `'#fff'` | Knob color. | +| `disabled` | `boolean` | `false` | Disables interaction. | +| `onValueChange` | `(e) => void` | — | Fired on toggle. `e.nativeEvent.value` is the new boolean. | --- -## Controls +### NativeSegmentedControl -### NativeButton +Wraps `UISegmentedControl`. + +> ⚠️ **Liquid Glass selection rendering is unreliable.** The selection indicator appears on press but disappears on release due to a UIKit material environment limitation when bridged. The control is functionally correct — `onValueChange` fires and `selectedIndex` is respected. Only the visual material effect is affected. -Native UIButton with system configurations. +Default style: `height: 32`. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `title` | `string` | `''` | Button title text (required) | -| `buttonStyle` | `ButtonStyle` | `'filled'` | System button style | -| `onPress` | `() => void` | `undefined` | Called when button is pressed | -| `style` | `ViewStyle` | `undefined` | React Native style object | - -**Example:** -```jsx - console.log('Pressed')} -/> -``` - -**UIKit Mapping:** `UIButton(configuration: .filled())` +| `segments` | `string[]` | required | Array of segment labels. | +| `selectedIndex` | `number` | `0` | Controlled selected index. | +| `onValueChange` | `(e) => void` | — | Fired on selection. `e.nativeEvent.selectedIndex` is the new index. | --- -### NativeSwitch +### NativeSearchBar -Native UISwitch toggle control. +Wraps `UISearchBar`. + +Default style: `height: 56`. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `value` | `boolean` | `false` | Switch on/off state | -| `onValueChange` | `(event) => void` | `undefined` | Called when value changes | -| `style` | `ViewStyle` | `undefined` | React Native style object | +| `placeholder` | `string` | `'Search'` | Placeholder text. | +| `text` | `string` | `''` | Controlled text value. | +| `onTextChanged` | `(e) => void` | — | Fired on every keystroke. `e.nativeEvent.text` is the current string. | +| `onSearchPressed` | `(e) => void` | — | Fired when the Search key is tapped. `e.nativeEvent.text` is the submitted string. | +| `onCancelPressed` | `(e) => void` | — | Fired when Cancel is tapped. `e.nativeEvent` is empty. | -**Event Payload:** -```typescript -{ - nativeEvent: { - value: boolean - } -} -``` +--- -**Example:** -```jsx -const [enabled, setEnabled] = useState(false); +### NativeNavigationBar - setEnabled(e.nativeEvent.value)} -/> -``` +Wraps `UINavigationBar`. -**UIKit Mapping:** `UISwitch` +Default style: `height: 44`. + +**Props:** +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `title` | `string` | — | Title text centered in the bar. | +| `translucent` | `boolean` | `true` | When true, applies the system material blur behind the bar. | --- -### NativeSegmentedControl +### NativeToolbar + +Wraps `UIToolbar`. Accepts `NativeToolbarButton` and `NativeToolbarMenu` as direct children — don't place arbitrary views inside it. -Native UISegmentedControl for segmented selection. +Default style: `height: 44`. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `segments` | `string[]` | `[]` | Array of segment titles (required) | -| `selectedIndex` | `number` | `0` | Currently selected segment index | -| `onValueChange` | `(event) => void` | `undefined` | Called when selection changes | -| `style` | `ViewStyle` | `undefined` | React Native style object | - -**Event Payload:** -```typescript -{ - nativeEvent: { - selectedIndex: number - } -} -``` +| `translucent` | `boolean` | `true` | System material blur behind the toolbar. | +| `children` | `ReactNode` | — | Only `NativeToolbarButton` and `NativeToolbarMenu`. | **Example:** -```jsx -const [index, setIndex] = useState(0); - - setIndex(e.nativeEvent.selectedIndex)} -/> +```tsx + + + + handleAction(e.nativeEvent.id)} + /> + ``` -**UIKit Mapping:** `UISegmentedControl` - --- -### NativeSearchBar +### NativeToolbarButton -Native UISearchBar for search input. +Wraps `UIBarButtonItem`. Must be a direct child of `NativeToolbar`. + +Use `systemItem` for standard system items, or `icon`/`title` for custom ones. `flexibleSpace` and `fixedSpace` are layout-only items and don't fire `onPress`. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `placeholder` | `string` | `''` | Placeholder text | -| `text` | `string` | `''` | Current search text | -| `onChangeText` | `(event) => void` | `undefined` | Called when text changes | -| `onSearchPress` | `(event) => void` | `undefined` | Called when search button pressed | -| `onCancelPress` | `() => void` | `undefined` | Called when cancel button pressed | -| `style` | `ViewStyle` | `undefined` | React Native style object | - -**Event Payload:** -```typescript -{ - nativeEvent: { - text: string - } -} -``` +| `systemItem` | `ToolbarSystemItem` | — | UIKit system bar button item. See [ToolbarSystemItem](#toolbarsystemitem). | +| `icon` | `string` | — | SF Symbols name. Ignored if `systemItem` is set. | +| `title` | `string` | — | Label text. | +| `disabled` | `boolean` | `false` | Disables interaction. | +| `onPress` | `(e) => void` | — | Fired on tap. `e.nativeEvent` is empty. | -**Example:** -```jsx -const [search, setSearch] = useState(''); - - setSearch(e.nativeEvent.text)} - onSearchPress={(e) => console.log('Search:', e.nativeEvent.text)} -/> -``` +--- -**UIKit Mapping:** `UISearchBar` +### NativeToolbarMenu + +Wraps `UIBarButtonItem` with an attached `UIMenu`. Must be a direct child of `NativeToolbar`. Supports nested submenus via `children` in `ToolbarMenuItem`. + +**Props:** +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `menuItems` | `ToolbarMenuItem[]` | required | Menu items. See [ToolbarMenuItem](#toolbarmenuitem). | +| `icon` | `string` | — | SF Symbols name for the button. | +| `title` | `string` | — | Label text for the button. | +| `disabled` | `boolean` | `false` | Disables the menu button. | +| `onMenuAction` | `(e) => void` | — | Fired on item selection. `e.nativeEvent.id` and `e.nativeEvent.title` identify the item. | --- -## Navigation +### NativeTabBar -### NativeNavigationBar +Wraps `UITabBar`. -Native UINavigationBar for top navigation. +Default style: `height: 49`. **Always set `height` explicitly in the `style` prop** — the view doesn't size itself automatically. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `title` | `string` | `''` | Navigation bar title | -| `barTintColor` | `string` | `undefined` | Bar background color | -| `translucent` | `boolean` | `true` | Enable translucency | -| `style` | `ViewStyle` | `undefined` | React Native style object | - -**Example:** -```jsx - -``` +| `items` | `TabBarItem[]` | required | Array of tab items. See [TabBarItem](#tabbaritem). | +| `selectedIndex` | `number` | `0` | Controlled selected tab. | +| `translucent` | `boolean` | `true` | System material blur behind the bar. | +| `onTabPress` | `(e) => void` | — | Fired on tab tap. `e.nativeEvent.index` is the tapped index. | -**UIKit Mapping:** `UINavigationBar` +On iPhone with a home indicator, a typical total height (including safe area) is `83`–`95pt`. --- -### NativeToolbar +### NativeGroupedContainer + +A `UIView` with `systemGroupedBackground` applied. -Native UIToolbar for bottom toolbars. +Default style: `overflow: 'hidden'`. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `items` | `ToolbarItem[]` | `[]` | Array of toolbar items | -| `translucent` | `boolean` | `true` | Enable translucency | -| `style` | `ViewStyle` | `undefined` | React Native style object | +| `insetGrouped` | `boolean` | `false` | When true, uses the inset grouped background style. | -**ToolbarItem Type:** -```typescript -{ - title?: string; // Custom title - systemItem?: ToolbarSystemItem; // System item type -} -``` +--- -**Example:** -```jsx - -``` +### NativeCardContainer + +A `UIView` with `secondarySystemGroupedBackground` and a continuous corner radius. Matches the card cells in Settings, Contacts, etc. -**UIKit Mapping:** `UIToolbar` +Default style: `overflow: 'hidden'`. + +**Props:** +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `cornerRadius` | `number` | `10` | Corner radius in points. Uses `CALayer.cornerCurve = .continuous`. | --- -### NativeTabBar +### NativeStackView -Native UITabBar for tab navigation. +Wraps `UIStackView`. No default size or spacing. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `items` | `TabBarItem[]` | `[]` | Array of tab items (required) | -| `selectedIndex` | `number` | `0` | Currently selected tab index | -| `translucent` | `boolean` | `true` | Enable translucency | -| `onTabPress` | `(event) => void` | `undefined` | Called when tab is pressed | -| `style` | `ViewStyle` | `undefined` | React Native style object | +| `axis` | `'vertical' \| 'horizontal'` | `'vertical'` | Layout direction. | +| `spacing` | `number` | `0` | Points between arranged subviews. | +| `alignment` | `StackAlignment` | `'fill'` | Cross-axis alignment. See [StackAlignment](#stackalignment). | +| `distribution` | `StackDistribution` | `'fill'` | Distribution along the axis. See [StackDistribution](#stackdistribution). | -**TabBarItem Type:** -```typescript -{ - title: string; // Tab title (required) - icon?: string; // SF Symbol name - systemItem?: TabBarSystemItem; // System tab item -} -``` +--- -**Event Payload:** -```typescript -{ - nativeEvent: { - index: number - } -} -``` +### NativeMenuButton -**Example:** -```jsx -const [tab, setTab] = useState(0); - - setTab(e.nativeEvent.index)} -/> -``` +A standalone `UIButton` that shows a `UIMenu` on press. Works anywhere — no `NativeToolbar` required. -**UIKit Mapping:** `UITabBar` +No default size. Set width/height via `style`. + +**Props:** +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `menuItems` | `ToolbarMenuItem[]` | required | Menu items. See [ToolbarMenuItem](#toolbarmenuitem). | +| `icon` | `string` | — | SF Symbols name for the button icon. | +| `tintColorHex` | `string` | system tint | Icon tint color as a hex string. | +| `onMenuAction` | `(e) => void` | — | Fired on item selection. `e.nativeEvent.id` and `e.nativeEvent.title` identify the item. | --- @@ -335,15 +244,15 @@ const [tab, setTab] = useState(0); ### MaterialType -All available UIKit system blur materials: +Controls the `UIVisualEffectView` blur material on `NativeMaterialView`. ```typescript type MaterialType = - | 'systemUltraThinMaterial' + | 'systemUltraThinMaterial' // lightest, nearly transparent | 'systemThinMaterial' - | 'systemMaterial' + | 'systemMaterial' // standard — used in sheets, cards | 'systemThickMaterial' - | 'systemChromeMaterial' + | 'systemChromeMaterial' // heaviest — used in chrome areas | 'systemUltraThinMaterialLight' | 'systemThinMaterialLight' | 'systemMaterialLight' @@ -356,42 +265,30 @@ type MaterialType = | 'systemChromeMaterialDark'; ``` -**Thickness Hierarchy:** -- `UltraThin` - Lightest blur -- `Thin` - Light blur -- `Material` - Standard blur (default) -- `Thick` - Heavy blur -- `Chrome` - Extra heavy blur - -**Appearance Variants:** -- No suffix - Adapts to system (light/dark) -- `Light` - Light appearance only -- `Dark` - Dark appearance only +The unsuffixed values adapt to light/dark mode automatically. `Light`/`Dark` suffixed variants lock to that appearance. --- ### ButtonStyle -UIButton configuration styles: +Maps to `UIButton.Configuration` styles. ```typescript type ButtonStyle = - | 'filled' // Solid background (default) - | 'gray' // Gray background - | 'tinted' // Tinted background - | 'plain' // No background - | 'bordered' // Border outline - | 'borderedTinted' // Tinted border - | 'borderedProminent'; // Prominent border + | 'filled' // solid tint background — primary action + | 'gray' // gray background — secondary action + | 'tinted' // light tinted background + | 'plain' // no background — tertiary action + | 'bordered' // border outline + | 'borderedTinted' // tinted border + | 'borderedProminent'; // prominent bordered style ``` -**UIKit Mapping:** `UIButton.Configuration.*` - --- ### ToolbarSystemItem -System toolbar item types: +Maps to `UIBarButtonItem.SystemItem`. Used on `NativeToolbarButton`. ```typescript type ToolbarSystemItem = @@ -400,18 +297,45 @@ type ToolbarSystemItem = | 'compose' | 'reply' | 'action' | 'organize' | 'bookmarks' | 'search' | 'refresh' | 'stop' | 'camera' | 'trash' | 'play' | 'pause' - | 'rewind' | 'fastForward' - | 'undo' | 'redo' | 'close'; + | 'rewind' | 'fastForward' | 'undo' | 'redo' | 'close'; ``` -**UIKit Mapping:** `UIBarButtonItem.SystemItem` +`flexibleSpace` expands to fill available space. `fixedSpace` is a fixed-size gap. Neither fires `onPress`. --- -### TabBarSystemItem +### ToolbarMenuItem -System tab bar item types: +Used in `menuItems` on `NativeToolbarMenu` and `NativeMenuButton`. Items can be nested to create submenus. +```typescript +interface ToolbarMenuItem { + id?: string; // returned in onMenuAction — defaults to title if omitted + title: string; // required + icon?: string; // SF Symbols name + destructive?: boolean; // renders in red with UIMenuElement.Attributes.destructive + disabled?: boolean; // grays out and prevents selection + children?: ToolbarMenuItem[]; // nested items become a UIMenu submenu +} +``` + +--- + +### TabBarItem + +Used in `items` on `NativeTabBar`. + +```typescript +interface TabBarItem { + title: string; + icon?: string; // SF Symbols name + systemItem?: TabBarSystemItem; +} +``` + +If `systemItem` is set, UIKit provides the system icon and label. `icon` takes precedence over `systemItem` when both are provided. + +**TabBarSystemItem values:** ```typescript type TabBarSystemItem = | 'more' | 'favorites' | 'featured' | 'topRated' @@ -419,49 +343,99 @@ type TabBarSystemItem = | 'search' | 'downloads' | 'mostRecent' | 'mostViewed'; ``` -**UIKit Mapping:** `UITabBarItem.SystemItem` +--- + +### StackAlignment + +Cross-axis alignment for `NativeStackView`. Maps to `UIStackView.Alignment`. + +```typescript +type StackAlignment = + | 'fill' + | 'leading' + | 'trailing' + | 'center' + | 'firstBaseline' // horizontal stacks only + | 'lastBaseline'; // horizontal stacks only +``` --- -## Layout Guidelines - -### Recommended Heights -- `NativeButton`: 44pt (default iOS touch target) -- `NativeSegmentedControl`: 32pt -- `NativeSearchBar`: 56pt -- `NativeNavigationBar`: 44pt -- `NativeToolbar`: 44pt -- `NativeTabBar`: 49pt -- `NativeSwitch`: Intrinsic size (51×31pt) - -### Container Sizing -All container components accept standard React Native `style` props: -- `width` / `height` -- `flex` -- `padding` / `margin` -- `backgroundColor` (overrides system colors) - -### Best Practices -1. Always provide explicit `width` and `height` or use `flex` layout -2. Use `SafeAreaView` for navigation/tab bars -3. Respect iOS safe areas -4. Test on multiple iOS versions -5. Support both light and dark mode +### StackDistribution + +How the stack distributes arranged views along its axis. Maps to `UIStackView.Distribution`. + +```typescript +type StackDistribution = + | 'fill' // one view expands to fill remaining space + | 'fillEqually' // all views the same size + | 'fillProportionally' // sized proportionally to intrinsic content size + | 'equalSpacing' // equal spacing between views + | 'equalCentering'; // equal spacing between centers +``` --- -## Platform Support +## Event Payloads + +All events follow the RN native event pattern: `(e: { nativeEvent: T }) => void`. + +| Event | `e.nativeEvent` | +|-------|----------------| +| `NativeButton.onPress` | `{}` | +| `NativeMaterialView.onPress` | `{}` | +| `NativeSwitch.onValueChange` | `{ value: boolean }` | +| `NativeSegmentedControl.onValueChange` | `{ selectedIndex: number }` | +| `NativeSearchBar.onTextChanged` | `{ text: string }` | +| `NativeSearchBar.onSearchPressed` | `{ text: string }` | +| `NativeSearchBar.onCancelPressed` | `{}` | +| `NativeTabBar.onTabPress` | `{ index: number }` | +| `NativeToolbarButton.onPress` | `{}` | +| `NativeToolbarMenu.onMenuAction` | `{ id: string; title: string }` | +| `NativeMenuButton.onMenuAction` | `{ id: string; title: string }` | + +--- -- **iOS:** 13.0+ ✅ -- **Android:** Not supported ❌ -- **Web:** Not supported ❌ +## Default Sizes + +Applied automatically; override via `style`. + +| Component | Default | +|-----------|---------| +| `NativeButton` | `height: 44` | +| `NativeSegmentedControl` | `height: 32` | +| `NativeSearchBar` | `height: 56` | +| `NativeNavigationBar` | `height: 44` | +| `NativeToolbar` | `height: 44` | +| `NativeTabBar` | `height: 49` | +| `NativeMaterialView` | `overflow: 'hidden'` | +| `NativeGroupedContainer` | `overflow: 'hidden'` | +| `NativeCardContainer` | `overflow: 'hidden'` | +| `NativeSwitch` | intrinsic (no override) | +| `NativeStackView` | none — fully prop-driven | +| `NativeMenuButton` | none — set via `style` | + +--- + +## Known Limitations + +- **iOS only.** The native module doesn't load on Android or web. +- **No Auto Layout.** React Native uses frame-based layout. Components need a frame from `style` or a flex parent. +- **System-controlled colors.** Material colors, blur appearance, and most tints are controlled by iOS. +- **No custom blur intensity.** `UIVisualEffectView` doesn't expose blur radius as a public API. +- **NativeMaterialView children.** Child views don't render inside the blur view. Tracked as a known issue. +- **NativeSegmentedControl Liquid Glass.** Selection indicator disappears on release. Functionally correct — only the material effect is affected. + +--- + +## Platform Support -Liquid-React is iOS-only by design. +iOS 13.0+ only. Android and web are not supported. --- ## See Also -- [Examples](./EXAMPLES.md) - Usage examples -- [Architecture](./ARCHITECTURE.md) - Technical architecture -- [App Store Compliance](./APP_STORE_COMPLIANCE.md) - Legal compliance +- [Examples](./EXAMPLES.md) +- [Architecture](./ARCHITECTURE.md) +- [App Store Compliance](./APP_STORE_COMPLIANCE.md) diff --git a/docs/COMPONENT_MAPPING.md b/docs/COMPONENT_MAPPING.md index d043da0..3788162 100644 --- a/docs/COMPONENT_MAPPING.md +++ b/docs/COMPONENT_MAPPING.md @@ -12,10 +12,14 @@ This table documents the **exact 1:1 mapping** between Liquid-React components a | `NativeSegmentedControl` | `LRNativeSegmentedControlManager` | `UISegmentedControl` | Segmented picker control | | `NativeSearchBar` | `LRNativeSearchBarManager` | `UISearchBar` | Search input with cancel button | | `NativeNavigationBar` | `LRNativeNavigationBarManager` | `UINavigationBar` | Top navigation bar | -| `NativeToolbar` | `LRNativeToolbarManager` | `UIToolbar` | Bottom toolbar with bar button items | +| `NativeToolbar` | `LRNativeToolbarManager` | `UIToolbar` | Bottom toolbar — accepts `NativeToolbarButton`/`NativeToolbarMenu` as children | +| `NativeToolbarButton` | `LRNativeToolbarButtonManager` | `UIBarButtonItem` | Bar button item inside a toolbar | +| `NativeToolbarMenu` | `LRNativeToolbarMenuManager` | `UIBarButtonItem` + `UIMenu` | Bar button with dropdown menu | | `NativeTabBar` | `LRNativeTabBarManager` | `UITabBar` | Tab navigation bar | | `NativeGroupedContainer` | `LRNativeGroupedContainerManager` | `UIView` | Container with system grouped background | | `NativeCardContainer` | `LRNativeCardContainerManager` | `UIView` | Card with continuous corner radius | +| `NativeStackView` | `LRNativeStackViewManager` | `UIStackView` | Axis-based layout container | +| `NativeMenuButton` | `LRNativeMenuButtonManager` | `UIButton` + `UIMenu` | Standalone button with dropdown menu | ## Implementation Patterns @@ -159,9 +163,9 @@ class NativeNavigationBar: UIView { |-----------|---------------|-----------| | `placeholder` | `placeholder: NSString` | `UISearchBar.placeholder` | | `text` | `text: NSString` | `UISearchBar.text` | -| `onChangeText` | `onChangeText: RCTBubblingEventBlock` | `UISearchBarDelegate.textDidChange` | -| `onSearchPress` | `onSearchPress: RCTBubblingEventBlock` | `UISearchBarDelegate.searchButtonClicked` | -| `onCancelPress` | `onCancelPress: RCTBubblingEventBlock` | `UISearchBarDelegate.cancelButtonClicked` | +| `onTextChanged` | `onTextChanged: RCTDirectEventBlock` | `UISearchBarDelegate.textDidChange` | +| `onSearchPressed` | `onSearchPressed: RCTDirectEventBlock` | `UISearchBarDelegate.searchButtonClicked` | +| `onCancelPressed` | `onCancelPressed: RCTDirectEventBlock` | `UISearchBarDelegate.cancelButtonClicked` | ## Public API Verification diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 7297485..20ec991 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -15,6 +15,7 @@ import { NativeSearchBar, NativeNavigationBar, NativeToolbar, + NativeToolbarButton, NativeTabBar, NativeGroupedContainer, NativeCardContainer, @@ -88,8 +89,8 @@ export default function App() { setSearchText(e.nativeEvent.text)} - onSearchPress={(e) => console.log('Search:', e.nativeEvent.text)} + onTextChanged={(e) => setSearchText(e.nativeEvent.text)} + onSearchPressed={(e) => console.log('Search:', e.nativeEvent.text)} style={styles.searchBar} /> @@ -167,17 +168,13 @@ export default function App() { {/* Toolbar */} - + + {}} /> + + {}} /> + + {}} /> + {/* Tab Bar */} setQuery(e.nativeEvent.text)} - onSearchPress={(e) => performSearch(e.nativeEvent.text)} + onTextChanged={(e) => setQuery(e.nativeEvent.text)} + onSearchPressed={(e) => performSearch(e.nativeEvent.text)} /> ); } diff --git a/docs/README.md b/docs/README.md index 6ac920c..aea72b6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -40,11 +40,15 @@ Liquid-React is a production-ready React Native iOS module that exposes Apple's - `NativeSwitch` - UISwitch toggle control - `NativeSegmentedControl` - UISegmentedControl picker - `NativeSearchBar` - UISearchBar for search input +- `NativeMenuButton` - standalone UIButton with UIMenu dropdown ### Navigation - `NativeNavigationBar` - UINavigationBar for top navigation -- `NativeToolbar` - UIToolbar for bottom toolbars +- `NativeToolbar` - UIToolbar for bottom toolbars (use `NativeToolbarButton`/`NativeToolbarMenu` as children) +- `NativeToolbarButton` - UIBarButtonItem inside a toolbar +- `NativeToolbarMenu` - UIBarButtonItem with UIMenu - `NativeTabBar` - UITabBar for tab navigation +- `NativeStackView` - UIStackView for axis-based layouts ## Learning Path diff --git a/docs/forReadTheDocs/api.rst b/docs/forReadTheDocs/api.rst new file mode 100644 index 0000000..c6d0677 --- /dev/null +++ b/docs/forReadTheDocs/api.rst @@ -0,0 +1,344 @@ +API Reference +============= + +Complete type reference for all props, event payloads, and enum values exported by liquid-react. + +.. contents:: On this page + :local: + :depth: 1 + +---- + +.. _material-types: + +MaterialType +------------ + +Controls which ``UIVisualEffectView`` material is applied to ``NativeMaterialView``. + +.. code-block:: typescript + + type MaterialType = + | 'systemUltraThinMaterial' + | 'systemThinMaterial' + | 'systemMaterial' + | 'systemThickMaterial' + | 'systemChromeMaterial' + | 'systemUltraThinMaterialLight' + | 'systemThinMaterialLight' + | 'systemMaterialLight' + | 'systemThickMaterialLight' + | 'systemChromeMaterialLight' + | 'systemUltraThinMaterialDark' + | 'systemThinMaterialDark' + | 'systemMaterialDark' + | 'systemThickMaterialDark' + | 'systemChromeMaterialDark'; + +The first five values are adaptive (they respond to light/dark mode automatically). The ``Light`` and ``Dark`` suffixed variants lock the material to that appearance regardless of the system setting. + +**Adaptive materials (lightest to heaviest)** + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Value + - Description + * - ``systemUltraThinMaterial`` + - Very subtle blur, nearly transparent. + * - ``systemThinMaterial`` + - Light blur, slightly more opaque. + * - ``systemMaterial`` + - Standard system material — used in sheets, cards, popovers. + * - ``systemThickMaterial`` + - Heavier blur, more opaque. + * - ``systemChromeMaterial`` + - Heaviest blur, used in chrome areas like tab bars. + +---- + +.. _button-styles: + +ButtonStyle +----------- + +Maps to ``UIButton.Configuration`` button styles. + +.. code-block:: typescript + + type ButtonStyle = + | 'filled' + | 'gray' + | 'tinted' + | 'plain' + | 'bordered' + | 'borderedTinted' + | 'borderedProminent'; + +.. list-table:: + :header-rows: 1 + :widths: 25 75 + + * - Value + - Description + * - ``filled`` + - Solid background in the tint color. Primary action button. + * - ``gray`` + - Gray background. Secondary action. + * - ``tinted`` + - Tinted background (lighter than filled). + * - ``plain`` + - No background, just the label. Tertiary action. + * - ``bordered`` + - Outlined border. + * - ``borderedTinted`` + - Outlined border with tinted text. + * - ``borderedProminent`` + - Prominent bordered style. + +---- + +.. _toolbar-system-items: + +ToolbarSystemItem +----------------- + +Maps to ``UIBarButtonItem.SystemItem``. Used on ``NativeToolbarButton``. + +.. code-block:: typescript + + type ToolbarSystemItem = + | 'done' | 'cancel' | 'edit' | 'save' | 'add' + | 'flexibleSpace' | 'fixedSpace' + | 'compose' | 'reply' | 'action' | 'organize' + | 'bookmarks' | 'search' | 'refresh' | 'stop' + | 'camera' | 'trash' | 'play' | 'pause' + | 'rewind' | 'fastForward' | 'undo' | 'redo' | 'close'; + +``flexibleSpace`` and ``fixedSpace`` are layout items — they don't fire ``onPress``. ``flexibleSpace`` expands to fill available space; ``fixedSpace`` is a fixed-size gap. + +---- + +.. _toolbar-menu-item: + +ToolbarMenuItem +--------------- + +Used in the ``menuItems`` prop of ``NativeToolbarMenu`` and ``NativeMenuButton``. Items can be nested to create submenus. + +.. code-block:: typescript + + interface ToolbarMenuItem { + id?: string; + title: string; + icon?: string; + destructive?: boolean; + disabled?: boolean; + children?: ToolbarMenuItem[]; + } + +.. list-table:: + :header-rows: 1 + :widths: 20 20 60 + + * - Field + - Type + - Description + * - ``id`` + - ``string`` + - Identifier returned in ``onMenuAction``. Defaults to ``title`` if omitted. + * - ``title`` + - ``string`` + - Display label. Required. + * - ``icon`` + - ``string`` + - SF Symbols name (e.g. ``'trash'``, ``'star.fill'``). + * - ``destructive`` + - ``boolean`` + - Renders the item in red with the ``UIMenuElement.Attributes.destructive`` attribute. + * - ``disabled`` + - ``boolean`` + - Grays out the item and prevents selection. + * - ``children`` + - ``ToolbarMenuItem[]`` + - Child items that form a submenu. UIKit renders this as a nested ``UIMenu``. + +---- + +.. _tab-bar-item: + +TabBarItem +---------- + +Used in the ``items`` prop of ``NativeTabBar``. + +.. code-block:: typescript + + interface TabBarItem { + title: string; + icon?: string; + systemItem?: TabBarSystemItem; + } + +If ``systemItem`` is provided, UIKit uses the system icon and label. ``icon`` is an SF Symbols name and overrides ``systemItem`` when both are set. + +**TabBarSystemItem values** + +.. code-block:: typescript + + type TabBarSystemItem = + | 'more' | 'favorites' | 'featured' | 'topRated' + | 'recents' | 'contacts' | 'history' | 'bookmarks' + | 'search' | 'downloads' | 'mostRecent' | 'mostViewed'; + +---- + +.. _stack-alignment: + +StackAlignment +-------------- + +Cross-axis alignment for ``NativeStackView``. Maps directly to ``UIStackView.Alignment``. + +.. code-block:: typescript + + type StackAlignment = + | 'fill' + | 'leading' + | 'trailing' + | 'center' + | 'firstBaseline' + | 'lastBaseline'; + +``firstBaseline`` and ``lastBaseline`` apply only to horizontal stacks. + +---- + +.. _stack-distribution: + +StackDistribution +----------------- + +How the stack distributes arranged views along its axis. Maps to ``UIStackView.Distribution``. + +.. code-block:: typescript + + type StackDistribution = + | 'fill' + | 'fillEqually' + | 'fillProportionally' + | 'equalSpacing' + | 'equalCentering'; + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Value + - Description + * - ``fill`` + - One view expands to fill remaining space. + * - ``fillEqually`` + - All views are the same size. + * - ``fillProportionally`` + - Views are sized proportionally to their intrinsic content size. + * - ``equalSpacing`` + - Views have equal spacing between them. + * - ``equalCentering`` + - Views are centered with equal space between their centers. + +---- + +Event Payloads +-------------- + +Events follow the React Native native event pattern: the handler receives ``(e: { nativeEvent: T })``. + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Event + - ``e.nativeEvent`` shape + * - ``NativeButton.onPress`` + - ``{}`` + * - ``NativeMaterialView.onPress`` + - ``{}`` + * - ``NativeSwitch.onValueChange`` + - ``{ value: boolean }`` + * - ``NativeSegmentedControl.onValueChange`` + - ``{ selectedIndex: number }`` + * - ``NativeSearchBar.onTextChanged`` + - ``{ text: string }`` + * - ``NativeSearchBar.onSearchPressed`` + - ``{ text: string }`` + * - ``NativeSearchBar.onCancelPressed`` + - ``{}`` + * - ``NativeTabBar.onTabPress`` + - ``{ index: number }`` + * - ``NativeToolbarButton.onPress`` + - ``{}`` + * - ``NativeToolbarMenu.onMenuAction`` + - ``{ id: string; title: string }`` + * - ``NativeMenuButton.onMenuAction`` + - ``{ id: string; title: string }`` + +---- + +Default Sizes +------------- + +These sizes are applied automatically unless you override them via the ``style`` prop. + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Component + - Default style + * - ``NativeButton`` + - ``height: 44`` + * - ``NativeSegmentedControl`` + - ``height: 32`` + * - ``NativeSearchBar`` + - ``height: 56`` + * - ``NativeNavigationBar`` + - ``height: 44`` + * - ``NativeToolbar`` + - ``height: 44`` + * - ``NativeTabBar`` + - ``height: 49`` + * - ``NativeMaterialView`` + - ``overflow: 'hidden'`` + * - ``NativeGroupedContainer`` + - ``overflow: 'hidden'`` + * - ``NativeCardContainer`` + - ``overflow: 'hidden'`` + * - ``NativeSwitch`` + - intrinsic size (no override) + * - ``NativeToolbarButton`` + - intrinsic size (no override) + * - ``NativeToolbarMenu`` + - intrinsic size (no override) + * - ``NativeMenuButton`` + - no default (set via ``style``) + * - ``NativeStackView`` + - no default (fully prop-driven) + +---- + +Known Limitations +----------------- + +- **iOS only.** Android and web are not supported. The native module will not load on other platforms. +- **No Auto Layout.** React Native uses frame-based layout. Components must be given a frame via the ``style`` prop or a flex parent. +- **System-controlled colors.** Background colors, blur effect colors, and tint colors are managed by iOS. You can't override the material color. +- **No custom blur intensity.** Apple's ``UIVisualEffectView`` does not expose blur radius as a public API. +- **NativeMaterialView children broken.** See the component docs. The blur renders correctly but RN children are not visible inside it. +- **NativeSegmentedControl Liquid Glass.** The selection indicator doesn't persist visually due to a UIKit material environment limitation when bridged. + +App Store Compliance +-------------------- + +liquid-react uses **only public Apple APIs**. No private frameworks, no runtime injection, no reverse-engineered internals. It is safe to ship in App Store builds. diff --git a/docs/forReadTheDocs/components.rst b/docs/forReadTheDocs/components.rst new file mode 100644 index 0000000..0c2a111 --- /dev/null +++ b/docs/forReadTheDocs/components.rst @@ -0,0 +1,695 @@ +Components +========== + +All components are re-exported from the top-level ``liquid-react`` package. Every component accepts all standard React Native ``ViewProps`` in addition to its own props (so ``style``, ``testID``, etc. all work). Events arrive as ``(e: { nativeEvent: PayloadType }) => void``. + +.. contents:: On this page + :local: + :depth: 1 + +---- + +NativeMaterialView +------------------ + +Wraps ``UIVisualEffectView`` with one of Apple's system blur materials. The view renders the blur effect and composites content on top of it. + +.. warning:: + + React Native children do not render correctly inside ``NativeMaterialView`` due to a known bridging limitation. The blur effect itself renders fine, but child views are not visible. Do not use this component to contain other React Native views until this issue is resolved. + +Default size: ``overflow: hidden`` applied automatically. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``material`` + - ``MaterialType`` + - ``'systemMaterial'`` + - The UIKit blur material to apply. See :ref:`material-types` for all values. + * - ``onPress`` + - ``(e) => void`` + - — + - Fired when the view is tapped. ``e.nativeEvent`` is empty. + * - ``style`` + - ``ViewStyle`` + - — + - Standard RN style. You must set width/height or flex. + +**Example** + +.. code-block:: tsx + + + +---- + +NativeButton +------------ + +Wraps ``UIButton`` with system button configurations. The ``buttonStyle`` prop maps directly to ``UIButton.Configuration`` styles introduced in iOS 15, with graceful fallback on older versions. + +Default size: ``height: 44``. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``title`` + - ``string`` + - required + - Button label text. + * - ``buttonStyle`` + - ``ButtonStyle`` + - ``'filled'`` + - Visual style. See :ref:`button-styles` for all values. + * - ``onPress`` + - ``(e) => void`` + - — + - Fired on tap. ``e.nativeEvent`` is empty. + * - ``style`` + - ``ViewStyle`` + - — + - Use to set width. Height defaults to 44. + +**Example** + +.. code-block:: tsx + + console.log('pressed')} + style={{ width: '100%' }} + /> + + + +---- + +NativeSwitch +------------ + +Wraps ``UISwitch``. The appearance is fully controlled by iOS — tint colors adapt automatically to light/dark mode unless explicitly overridden. + +No default size is applied; the switch uses its intrinsic size. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``value`` + - ``boolean`` + - ``false`` + - Controlled on/off state. + * - ``onTintColor`` + - ``string`` + - system tint + - Track color when the switch is on. Accepts any CSS hex color (e.g. ``'#007AFF'``). + * - ``thumbTintColor`` + - ``string`` + - ``'#fff'`` + - Knob color. + * - ``disabled`` + - ``boolean`` + - ``false`` + - Disables interaction. + * - ``onValueChange`` + - ``(e) => void`` + - — + - Fired when toggled. ``e.nativeEvent.value`` is the new boolean state. + +**Example** + +.. code-block:: tsx + + const [enabled, setEnabled] = React.useState(false); + + setEnabled(e.nativeEvent.value)} + /> + +---- + +NativeSegmentedControl +---------------------- + +Wraps ``UISegmentedControl``. + +.. warning:: + + The Liquid Glass selection indicator rendering is unreliable when this control is embedded in a React Native bridged view. The highlight appears during press but disappears on release because UIKit cannot fully resolve the material environment. The control is functionally correct — ``onValueChange`` fires properly and ``selectedIndex`` is respected. Only the visual material effect is affected. + +Default size: ``height: 32``. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``segments`` + - ``string[]`` + - required + - Array of segment labels. + * - ``selectedIndex`` + - ``number`` + - ``0`` + - Controlled selected segment index. + * - ``onValueChange`` + - ``(e) => void`` + - — + - Fired when a segment is tapped. ``e.nativeEvent.selectedIndex`` is the new index. + +**Example** + +.. code-block:: tsx + + const [tab, setTab] = React.useState(0); + + setTab(e.nativeEvent.selectedIndex)} + style={{ width: '100%' }} + /> + +---- + +NativeSearchBar +--------------- + +Wraps ``UISearchBar``. Renders the native iOS search bar with the system keyboard integration and cancel button behavior. + +Default size: ``height: 56``. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``placeholder`` + - ``string`` + - ``'Search'`` + - Placeholder text shown when the field is empty. + * - ``text`` + - ``string`` + - ``''`` + - Controlled text value. + * - ``onTextChanged`` + - ``(e) => void`` + - — + - Fired on every keystroke. ``e.nativeEvent.text`` is the current string. + * - ``onSearchPressed`` + - ``(e) => void`` + - — + - Fired when the user taps the Search key. ``e.nativeEvent.text`` is the submitted string. + * - ``onCancelPressed`` + - ``(e) => void`` + - — + - Fired when the Cancel button is tapped. ``e.nativeEvent`` is empty. + +**Example** + +.. code-block:: tsx + + const [query, setQuery] = React.useState(''); + + setQuery(e.nativeEvent.text)} + onSearchPressed={(e) => runSearch(e.nativeEvent.text)} + onCancelPressed={() => setQuery('')} + style={{ width: '100%' }} + /> + +---- + +NativeNavigationBar +------------------- + +Wraps ``UINavigationBar``. Renders a standalone navigation bar — useful for custom layouts where you want the bar without a full navigation controller. + +Default size: ``height: 44``. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``title`` + - ``string`` + - — + - Title text displayed in the center of the bar. + * - ``translucent`` + - ``boolean`` + - ``true`` + - When true, applies the system material blur behind the bar. + +**Example** + +.. code-block:: tsx + + + +---- + +NativeToolbar +------------- + +Wraps ``UIToolbar``. Accepts ``NativeToolbarButton`` and ``NativeToolbarMenu`` as direct children. The toolbar manages the native bar button item layout internally — do not place arbitrary views inside it. + +Default size: ``height: 44``. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``translucent`` + - ``boolean`` + - ``true`` + - When true, applies system material blur behind the toolbar. + * - ``children`` + - ``ReactNode`` + - — + - Should only contain ``NativeToolbarButton`` and ``NativeToolbarMenu`` components. + +**Example** + +.. code-block:: tsx + + + + + handleAction(e.nativeEvent.id)} + /> + + +---- + +NativeToolbarButton +------------------- + +Wraps ``UIBarButtonItem``. Must be a direct child of ``NativeToolbar``. + +You can configure it with a system item, a title, an SF Symbol icon, or a combination. When using ``systemItem``, the appropriate system icon and accessibility label are applied automatically. + +No default size (intrinsic to the bar button item). + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``systemItem`` + - ``ToolbarSystemItem`` + - — + - A UIKit system bar button item (e.g. ``'add'``, ``'done'``, ``'flexibleSpace'``). See :ref:`toolbar-system-items`. + * - ``icon`` + - ``string`` + - — + - SF Symbols name (e.g. ``'star.fill'``). Ignored if ``systemItem`` is set. + * - ``title`` + - ``string`` + - — + - Label text. Can be used alongside ``icon``. + * - ``disabled`` + - ``boolean`` + - ``false`` + - Disables tap interaction. + * - ``onPress`` + - ``(e) => void`` + - — + - Fired on tap. ``e.nativeEvent`` is empty. + +**Example** + +.. code-block:: tsx + + {/* system item */} + + + {/* SF Symbol icon */} + + + {/* flexible space — pushes items to edges */} + + +---- + +NativeToolbarMenu +----------------- + +Wraps ``UIBarButtonItem`` with an attached ``UIMenu``. Must be a direct child of ``NativeToolbar``. Menu items can be nested to create submenus. + +No default size (intrinsic to the bar button item). + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``menuItems`` + - ``ToolbarMenuItem[]`` + - required + - Array of menu items. See :ref:`toolbar-menu-item`. + * - ``icon`` + - ``string`` + - — + - SF Symbols name for the button that opens the menu. + * - ``title`` + - ``string`` + - — + - Label text for the button. + * - ``disabled`` + - ``boolean`` + - ``false`` + - Disables the entire menu button. + * - ``onMenuAction`` + - ``(e) => void`` + - — + - Fired when a menu item is selected. ``e.nativeEvent.id`` and ``e.nativeEvent.title`` identify the item. + +**Example** + +.. code-block:: tsx + + console.log('tapped', e.nativeEvent.id)} + /> + +---- + +NativeTabBar +------------ + +Wraps ``UITabBar``. Tab items can use SF Symbol icons, system items, or just a title. + +Default size: ``height: 49``. You must set a height explicitly in the ``style`` prop — the native view does not size itself automatically. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``items`` + - ``TabBarItem[]`` + - required + - Array of tab items. See :ref:`tab-bar-item`. + * - ``selectedIndex`` + - ``number`` + - ``0`` + - Controlled selected tab index. + * - ``translucent`` + - ``boolean`` + - ``true`` + - When true, applies system material blur behind the tab bar. + * - ``onTabPress`` + - ``(e) => void`` + - — + - Fired when a tab is tapped. ``e.nativeEvent.index`` is the selected index. + +.. note:: + + Always set ``height`` in the ``style`` prop. On iPhone with a home indicator the typical height is ``83``–``95`` to account for the safe area. Use ``SafeAreaInsets`` if you need to calculate this dynamically. + +**Example** + +.. code-block:: tsx + + const [tab, setTab] = React.useState(0); + + setTab(e.nativeEvent.index)} + translucent={true} + style={{ position: 'absolute', bottom: 0, width: '100%', height: 83 }} + /> + +---- + +NativeGroupedContainer +----------------------- + +A plain ``UIView`` with ``systemGroupedBackground`` applied. Use it as a section background, matching the look of grouped settings tables. + +Default size: ``overflow: hidden`` applied automatically. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``insetGrouped`` + - ``boolean`` + - ``false`` + - When true, uses ``systemGroupedBackground`` (same as the inset grouped table style). When false, uses the plain grouped background. + +**Example** + +.. code-block:: tsx + + + + {/* card contents */} + + + +---- + +NativeCardContainer +------------------- + +A ``UIView`` with ``secondarySystemGroupedBackground`` and a continuous corner radius. Matches the card cells in Settings, Contacts, and other system apps. + +Default size: ``overflow: hidden`` applied automatically. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``cornerRadius`` + - ``number`` + - ``10`` + - Corner radius in points. Uses ``CALayer.cornerCurve = .continuous``. + +**Example** + +.. code-block:: tsx + + + Card title + Supporting text + + +---- + +NativeStackView +--------------- + +Wraps ``UIStackView``. Arranges its children along a vertical or horizontal axis. Layout is entirely prop-driven — no default size or spacing is applied. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``axis`` + - ``'vertical' | 'horizontal'`` + - ``'vertical'`` + - The layout direction. + * - ``spacing`` + - ``number`` + - ``0`` + - Points of spacing between arranged subviews. + * - ``alignment`` + - ``StackAlignment`` + - ``'fill'`` + - Cross-axis alignment. See :ref:`stack-alignment`. + * - ``distribution`` + - ``StackDistribution`` + - ``'fill'`` + - How arranged views are distributed along the axis. See :ref:`stack-distribution`. + +**Example** + +.. code-block:: tsx + + + + + + +---- + +NativeMenuButton +---------------- + +A standalone ``UIButton`` that shows a ``UIMenu`` on press. Unlike ``NativeToolbarMenu``, this works anywhere in your layout — no ``NativeToolbar`` required. + +No default size applied; size it via the ``style`` prop. + +**Props** + +.. list-table:: + :header-rows: 1 + :widths: 20 20 10 50 + + * - Prop + - Type + - Default + - Description + * - ``menuItems`` + - ``ToolbarMenuItem[]`` + - required + - Array of menu items. See :ref:`toolbar-menu-item`. + * - ``icon`` + - ``string`` + - — + - SF Symbols name for the button icon. + * - ``tintColorHex`` + - ``string`` + - system tint + - Icon/label tint color as a hex string (e.g. ``'#FF3B30'``). + * - ``onMenuAction`` + - ``(e) => void`` + - — + - Fired when a menu item is selected. ``e.nativeEvent.id`` and ``e.nativeEvent.title`` identify the item. + +**Example** + +.. code-block:: tsx + + handleAction(e.nativeEvent.id)} + style={{ width: 44, height: 44 }} + /> diff --git a/docs/forReadTheDocs/examples.rst b/docs/forReadTheDocs/examples.rst new file mode 100644 index 0000000..d3db7b6 --- /dev/null +++ b/docs/forReadTheDocs/examples.rst @@ -0,0 +1,397 @@ +Examples +======== + +Complete, working patterns for common use cases. + +.. contents:: On this page + :local: + :depth: 1 + +---- + +Settings Screen +--------------- + +A grouped settings layout using ``NativeGroupedContainer``, ``NativeCardContainer``, and native controls. + +.. code-block:: tsx + + import React, { useState } from 'react'; + import { ScrollView, Text, StyleSheet } from 'react-native'; + import { + NativeGroupedContainer, + NativeCardContainer, + NativeSwitch, + NativeSegmentedControl, + } from 'liquid-react'; + + export default function SettingsScreen() { + const [notifications, setNotifications] = useState(true); + const [haptics, setHaptics] = useState(false); + const [theme, setTheme] = useState(0); + + return ( + + + + + Notifications + setNotifications(e.nativeEvent.value)} + /> + + + + Haptics + setHaptics(e.nativeEvent.value)} + /> + + + + + + + Appearance + setTheme(e.nativeEvent.selectedIndex)} + style={{ width: 200 }} + /> + + + + ); + } + + const styles = StyleSheet.create({ + section: { marginTop: 20, marginHorizontal: 16 }, + card: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + padding: 12, + marginBottom: 1, + }, + label: { fontSize: 17 }, + }); + +---- + +Toolbar with Buttons and Menu +------------------------------ + +A toolbar fixed to the bottom of the screen with a mix of system items and a context menu. + +.. code-block:: tsx + + import React from 'react'; + import { View, StyleSheet } from 'react-native'; + import { + NativeToolbar, + NativeToolbarButton, + NativeToolbarMenu, + } from 'liquid-react'; + + export default function EditorScreen() { + const handleAction = (id: string) => { + switch (id) { + case 'share': share(); break; + case 'duplicate': duplicate(); break; + case 'delete': confirmDelete(); break; + } + }; + + return ( + + {/* ...main content... */} + + + + + + + + handleAction(e.nativeEvent.id)} + /> + + + ); + } + + const styles = StyleSheet.create({ + container: { flex: 1 }, + toolbar: { + position: 'absolute', + bottom: 0, + width: '100%', + }, + }); + +---- + +Tab Bar Navigation +------------------ + +A native tab bar at the bottom of the screen with controlled tab state. + +.. code-block:: tsx + + import React, { useState } from 'react'; + import { View, Text, StyleSheet } from 'react-native'; + import { NativeTabBar } from 'liquid-react'; + + const TABS = [ + { title: 'Home', icon: 'house' }, + { title: 'Search', icon: 'magnifyingglass' }, + { title: 'Library', icon: 'books.vertical' }, + { title: 'Profile', icon: 'person.crop.circle' }, + ]; + + const SCREENS = ['Home', 'Search', 'Library', 'Profile']; + + export default function RootNavigator() { + const [tab, setTab] = useState(0); + + return ( + + + {SCREENS[tab]} + + + setTab(e.nativeEvent.index)} + translucent={true} + style={styles.tabBar} + /> + + ); + } + + const styles = StyleSheet.create({ + container: { flex: 1 }, + content: { flex: 1, justifyContent: 'center', alignItems: 'center' }, + heading: { fontSize: 28, fontWeight: '700' }, + tabBar: { + position: 'absolute', + bottom: 0, + width: '100%', + height: 83, + }, + }); + +---- + +Search Interface +---------------- + +A search bar wired to a filtered list. + +.. code-block:: tsx + + import React, { useState, useMemo } from 'react'; + import { FlatList, Text, StyleSheet } from 'react-native'; + import { NativeSearchBar } from 'liquid-react'; + + const DATA = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig']; + + export default function SearchScreen() { + const [query, setQuery] = useState(''); + + const results = useMemo( + () => DATA.filter((item) => item.toLowerCase().includes(query.toLowerCase())), + [query], + ); + + return ( + <> + setQuery(e.nativeEvent.text)} + onCancelPressed={() => setQuery('')} + style={styles.searchBar} + /> + item} + renderItem={({ item }) => {item}} + /> + + ); + } + + const styles = StyleSheet.create({ + searchBar: { width: '100%' }, + row: { padding: 16, fontSize: 17 }, + }); + +---- + +Context Menu Button +------------------- + +A ``NativeMenuButton`` placed inline (no toolbar needed). + +.. code-block:: tsx + + import React from 'react'; + import { View, Text, StyleSheet } from 'react-native'; + import { NativeMenuButton } from 'liquid-react'; + + export default function ListItem({ onEdit, onDelete }: Props) { + const handleAction = (id: string) => { + if (id === 'edit') onEdit(); + if (id === 'delete') onDelete(); + }; + + return ( + + My Item + handleAction(e.nativeEvent.id)} + style={styles.button} + /> + + ); + } + + const styles = StyleSheet.create({ + row: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + paddingHorizontal: 16, + paddingVertical: 12, + }, + label: { fontSize: 17 }, + button: { width: 44, height: 44 }, + }); + +---- + +Stack Layout +------------ + +A vertically arranged set of buttons using ``NativeStackView``. + +.. code-block:: tsx + + import React from 'react'; + import { NativeStackView, NativeButton } from 'liquid-react'; + + export default function ActionSheet() { + return ( + + + + + + ); + } + +---- + +Material Types Comparison +-------------------------- + +All five adaptive materials side by side. + +.. code-block:: tsx + + import React from 'react'; + import { View, Text, ImageBackground, StyleSheet } from 'react-native'; + import { NativeMaterialView } from 'liquid-react'; + + const MATERIALS = [ + 'systemUltraThinMaterial', + 'systemThinMaterial', + 'systemMaterial', + 'systemThickMaterial', + 'systemChromeMaterial', + ] as const; + + export default function MaterialShowcase() { + return ( + + + {MATERIALS.map((mat) => ( + + {/* children broken — label placed outside for now */} + + ))} + + + ); + } + + const styles = StyleSheet.create({ + bg: { flex: 1, justifyContent: 'center', alignItems: 'center' }, + grid: { gap: 12 }, + chip: { width: 260, height: 60, borderRadius: 12 }, + }); + +.. note:: + + ``NativeMaterialView`` children are currently broken — child views don't render inside the blur view. The blur itself is visible. Track progress on this at the GitHub issues page. + +---- + +Platform Guard Pattern +----------------------- + +Safely rendering liquid-react components only on iOS. + +.. code-block:: tsx + + import React from 'react'; + import { Platform, View, StyleSheet } from 'react-native'; + import { NativeButton } from 'liquid-react'; + + export default function PlatformAwareButton({ onPress }: { onPress: () => void }) { + if (Platform.OS !== 'ios') { + return ( + + {/* use a cross-platform button here */} + + ); + } + + return ( + + ); + } + + const styles = StyleSheet.create({ + fallback: { height: 44, backgroundColor: '#007AFF', borderRadius: 10 }, + }); diff --git a/docs/forReadTheDocs/getting-started.rst b/docs/forReadTheDocs/getting-started.rst new file mode 100644 index 0000000..80bac18 --- /dev/null +++ b/docs/forReadTheDocs/getting-started.rst @@ -0,0 +1,112 @@ +Getting Started +=============== + +Requirements +------------ + +- macOS with Xcode 11+ +- React Native 0.65.0+ +- iOS deployment target 13.0+ +- CocoaPods + +Installation +------------ + +.. code-block:: bash + + npm install liquid-react + # or + yarn add liquid-react + +Then link the native module: + +.. code-block:: bash + + cd ios && pod install + +Rebuild your app after pod install: + +.. code-block:: bash + + npm run ios + +That's it. No extra native configuration needed. + +First Component +--------------- + +.. code-block:: tsx + + import React from 'react'; + import { SafeAreaView, StyleSheet } from 'react-native'; + import { NativeButton } from 'liquid-react'; + + export default function App() { + return ( + + console.log('pressed')} + style={{ width: 200 }} + /> + + ); + } + + const styles = StyleSheet.create({ + container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, + }); + +iOS Version Behavior +-------------------- + +All components work on iOS 13+, but visual rendering depends on the iOS version: + +- **iOS 26+** — full Liquid Glass rendering, identical to Apple's own apps +- **iOS 13-18** — real native UIKit components, system appearance for that iOS version (no Liquid Glass, but still authentic native rendering) + +The library never simulates anything. Whatever iOS renders is what you get. + +Platform Guard +-------------- + +liquid-react is iOS-only. If your project targets multiple platforms, guard usage: + +.. code-block:: tsx + + import { Platform } from 'react-native'; + + function MyComponent() { + if (Platform.OS !== 'ios') { + return ; + } + return ; + } + +Or use React Native's platform file extensions (``MyComponent.ios.tsx``, ``MyComponent.android.tsx``). + +Troubleshooting +--------------- + +**Module not found / symbols not linked** + Run ``cd ios && pod install``, then rebuild. + +**Build errors after updating** + Clean the pods and reinstall: + + .. code-block:: bash + + cd ios + rm -rf Pods Podfile.lock + pod install + +**Blur not visible** + Make sure the parent view has a non-zero frame and you're running on a simulator or device (not just doing a type check). ``NativeMaterialView`` requires a real rendering context. + +**npm install peer dependency errors** + If you're on React Native 0.84+ with ``@types/react@18``, use: + + .. code-block:: bash + + npm install --legacy-peer-deps diff --git a/docs/forReadTheDocs/index.rst b/docs/forReadTheDocs/index.rst index 30f9522..22b41f3 100644 --- a/docs/forReadTheDocs/index.rst +++ b/docs/forReadTheDocs/index.rst @@ -1,3 +1,22 @@ -.. This text is here to serve as a placeholder for the index page of the readTheDocs documentation. -.. This folder (forReadTheDocs/) is meant to be the root of the rtd documentation, not for github. For .md docuemntation, -.. view the root docs/ folder and/or the README.md file in the root of the repository. \ No newline at end of file +liquid-react +============ + +React Native bindings for real UIKit components. This isn't a blur approximation or a custom renderer — it's ``UIButton``, ``UISwitch``, ``UIToolbar``, ``UITabBar``, etc., exposed through a thin bridge. iOS renders everything. + +Requires iOS 13+. Liquid Glass requires iOS 26+. iOS only. + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + getting-started + components + api + examples + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` + diff --git a/readTheDocs.yml b/readTheDocs.yml index e69de29..1d7dfd2 100644 --- a/readTheDocs.yml +++ b/readTheDocs.yml @@ -0,0 +1 @@ +# why? \ No newline at end of file From 4af86f7cc6cf7fb8a3960b27a96b1ffc4fb52c12 Mon Sep 17 00:00:00 2001 From: PzmuV1517 Date: Sun, 1 Mar 2026 14:50:45 +0200 Subject: [PATCH 10/12] fixed compile issues --- .eslintrc.json | 29 - .gitignore | 1 + .prettierignore | 4 - .prettierrc | 9 - .swiftlint.yml | 42 - CONTRIBUTING.md | 78 +- LICENSE | 3 + docs/API_REFERENCE.md | 556 +-- docs/COMPONENT_MAPPING.md | 12 +- docs/EXAMPLES.md | 25 +- docs/PROJECT_STRUCTURE.md | 2 - docs/QUICK_START.md | 23 +- docs/README.md | 6 +- docs/forReadTheDocs/.gitkeep | 0 docs/forReadTheDocs/api.rst | 344 -- docs/forReadTheDocs/components.rst | 695 --- docs/forReadTheDocs/examples.rst | 397 -- docs/forReadTheDocs/getting-started.rst | 112 - docs/forReadTheDocs/index.rst | 22 - ios/LRNativeButtonManager.m | 26 - ios/LRNativeButtonManager.swift | 56 +- ios/LRNativeCardContainerManager.m | 26 - ios/LRNativeCardContainerManager.swift | 43 +- ios/LRNativeGroupedContainerManager.m | 26 - ios/LRNativeGroupedContainerManager.swift | 40 +- ios/LRNativeMaterialViewManager.m | 26 - ios/LRNativeMaterialViewManager.swift | 56 +- ios/LRNativeMenuButtonManager.m | 26 - ios/LRNativeMenuButtonManager.swift | 26 - ios/LRNativeNavigationBarManager.m | 26 - ios/LRNativeNavigationBarManager.swift | 52 +- ios/LRNativeSearchBarManager.m | 26 - ios/LRNativeSearchBarManager.swift | 54 +- ios/LRNativeSegmentedControlManager.m | 26 - ios/LRNativeSegmentedControlView.swift | 33 +- ios/LRNativeStackViewManager.m | 26 - ios/LRNativeStackViewManager.swift | 65 +- ios/LRNativeSwitchManager.m | 26 - ios/LRNativeSwitchManager.swift | 55 +- ios/LRNativeTabBarManager.m | 26 - ios/LRNativeTabBarManager.swift | 70 +- ios/LRNativeToolbarButtonManager.m | 26 - ios/LRNativeToolbarButtonManager.swift | 63 +- ios/LRNativeToolbarManager.m | 26 - ios/LRNativeToolbarManager.swift | 67 +- ios/LRNativeToolbarMenuManager.m | 26 - ios/LRNativeToolbarMenuManager.swift | 68 +- ios/LiquidReact-Bridging-Header.h | 32 +- ios/LiquidReactModule.m | 26 - ios/LiquidReactModule.swift | 26 - liquid-react.podspec | 2 +- package-lock.json | 5231 --------------------- package.json | 13 +- readTheDocs.yml | 1 - src/components.tsx | 123 +- src/index.ts | 30 +- src/nativeComponents.ts | 78 +- src/types.ts | 294 +- 58 files changed, 795 insertions(+), 8533 deletions(-) delete mode 100644 .eslintrc.json delete mode 100644 .swiftlint.yml delete mode 100644 docs/forReadTheDocs/.gitkeep delete mode 100644 docs/forReadTheDocs/api.rst delete mode 100644 docs/forReadTheDocs/components.rst delete mode 100644 docs/forReadTheDocs/examples.rst delete mode 100644 docs/forReadTheDocs/getting-started.rst delete mode 100644 docs/forReadTheDocs/index.rst delete mode 100644 package-lock.json delete mode 100644 readTheDocs.yml diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 7f2bef8..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "root": true, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 2019, - "sourceType": "module", - "ecmaFeatures": { - "jsx": true - } - }, - "plugins": ["@typescript-eslint"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "rules": { - "camelcase": ["warn", { "properties": "always" }], - "@typescript-eslint/naming-convention": [ - "warn", - { "selector": "variable", "format": ["camelCase", "PascalCase", "UPPER_CASE"] }, - { "selector": "function", "format": ["camelCase", "PascalCase"] }, - { "selector": "typeLike", "format": ["PascalCase"] } - ], - "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], - "@typescript-eslint/explicit-module-boundary-types": "off", - "no-console": "warn" - }, - "ignorePatterns": ["lib/", "node_modules/", "ios/"] -} diff --git a/.gitignore b/.gitignore index 091c2e1..d8b6b62 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ lib/ # Ignore node moudules node_modules/ +.package-lock.json # MacOS .DS_Store diff --git a/.prettierignore b/.prettierignore index e4617a1..e69de29 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +0,0 @@ -lib/ -node_modules/ -dist/ -build/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 2fcf5a0..e69de29 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,9 +0,0 @@ -{ - "semi": true, - "singleQuote": true, - "trailingComma": "all", - "tabWidth": 2, - "printWidth": 100, - "bracketSpacing": true, - "arrowParens": "always" -} diff --git a/.swiftlint.yml b/.swiftlint.yml deleted file mode 100644 index c3bcd0a..0000000 --- a/.swiftlint.yml +++ /dev/null @@ -1,42 +0,0 @@ -included: - - ios - -excluded: - - Pods - - node_modules - - lib - -disabled_rules: - - trailing_whitespace - - line_length - -opt_in_rules: - - empty_count - - closure_spacing - - force_unwrapping - - implicit_return - - modifier_order - -type_name: - min_length: 2 - max_length: 50 - -identifier_name: - min_length: 2 - max_length: 50 - excluded: - - id - - x - - y - - i - - e - -file_length: - warning: 500 - error: 1000 - -function_body_length: - warning: 60 - error: 100 - -reporter: "xcode" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7e61979..4139211 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,83 +1,37 @@ -# Thanks for your interest in contributing +# Introduction -Hello! We appreciate your interest in contributing to the liquidReact library. We welcome contributions of all kinds, including but not limited to bug fixes, new features, documentation improvements, code refactoring, suggestions, and more, especially since we are a group of teenagers who also have to focus on their personal lives. To ensure a smooth collaboration process, we have outlined some guidelines and best practices for contributing to this project. Please take a moment to review the following information before submitting your contribution. Aside from the guidelines below, we also encourage you to check out our [Code of Conduct](.github/CODE_OF_CONDUCT.md) to ensure a positive and friendly environment for all contributors. +First of all, we want to thank you for your interest in contributing to Liquid-React! We are always looking for help in improving the library and adding new features, and we welcome contributions from the community. -## First off, how do I contribute? +## How to Contribute -Contributing to liquidReact is just like any other open source project. There are 2 main methods you can contribute: +If you want to contribute to Liquid-React, there are a few ways you can get involved: -**Pull Requests:** After you figure out how and what you want to add/change/remove/etc, you can fork the repository, make your changes in a *new branch* (this is mandatory), and then submit a pull request to *staging* (not main). It is best to submit your pull request as a draft after the first commit, and fill out the pull request template with the necessary information. We will review your pull request and provide feedback or merge it if it meets our standards. +1. **Report Issues**: If you find a bug or have an idea for a new feature, please open an issue on our GitHub repository. This helps us and other contributors keep track of what needs to be done and allows us to prioritize our work. -**Issues:** Another way to contribute is to simply submit an issue in the repository's issue tracker. If you find a bug or have a feature request, please submit it there so that we can track and address it. Make sure it follows the issue template and provides enough information for us to understand and reproduce the problem or implement the feature. +2. **Work on Issues**: If you want to contribute code, you can check out the open issues on our GitHub repository and see if there is anything you would like to work on. If you find an issue that you want to work on, please comment on the issue to let us know that you are working on it. Make sure that someone else is not already working on the same issue to avoid duplication of effort, you can also offer to help with an issue if you see that someone is struggling with it. -## Ok, but what are the guidelines? +## Working on Issues -We have a few standards that we ask all contributors to follow when submitting a pull request. These standards are in place to ensure that our codebase remains clear, consistent and maintainable for future helpers. It's also to make sure that no arguments arise (for example from a duplicate pull request or issue). - -**1. Follow the Code of Conduct:** We expect all contributors to adhere to our [Code of Conduct](.github/CODE_OF_CONDUCT.md) to maintain a respectful and inclusive environment for everyone. - -**2. Make sure you know what you're doing:** All code, documentation, and other contributions you make should be well thought out and intentional. If you are unsure about how to implement a feature or fix a bug, please ask for help in the discussions or open an issue to get feedback before submitting a pull request. - -**2.1. No AI Generated Content:** We prohibit AI-generated content in contributions to this project (with some exceptions for trusted contributors). This is because AI-generated content is often inaccurate, lacks context, clouds code quality (which can lead to confusion and bugs) and can sometimes infringe on intellectual property rights (we cannot verify the source of the model's training data, which could lead to unwanted legal issues). We encourage you to write your own original content to ensure the quality and integrity of our project. - -**3. Make sure your PR passes CI/CD checks:** We have automated checks in place to ensure that all contributions meet our quality standards. Please make sure your pull request passes all checks before submitting it. This includes linting, testing, and other checks that we have set up. - -**4. Follow the pull request template:** When submitting a pull request, please fill out the pull request template with all the necessary information. This helps us understand the purpose and scope of your contribution and makes it easier for us to review and merge it. - -**5. Be responsive to feedback:** We may provide feedback on your pull request, and we ask that you be responsive and open to making changes based on that feedback. This helps us maintain a high-quality codebase and ensures that your contribution is in line with our standards. - -**6. Be patient:** We receive many contributions, and it may take some time for us to review and merge your pull request. Please be patient and understand that we are doing our best to review all contributions in a timely manner. - -**7. Considering:** Considering the fact that this library is a strictly component-based library, we ask that, unless it's a documentation or bug fix contribution, all contributions should be in the form of a new component or an improvement to an existing component. This is not a hard rule, but it is a general guideline to help maintain the focus and structure of our library. - -**7.1. NOTE:** As the library is focused specifically on iOS Liquid-Glass components, which can be difficult to implement and often require a lot of knowledge on how the infrastructure of the library works, we ask that all contributions related to new components (this doesn't include improvements, bug fixes, documentation, etc) be made by trusted contributors and/or maintainers. This is not a hard rule, but if you're unexperienced with the library, it's easier to let someone with more expertise handle the implementation of new components so no confusion arises from who does what and no duplicate pull requests come up. - - **8. Style guidelines:** We ask that all code contributions follow our style guidelines to maintain consistency across the codebase. This includes using clear and descriptive variable names, writing comments where necessary, and following the existing code structure. Please refer to our style guidelines below for more details. - - **9. OS and IDE:** We would prefer that all contributions be made on a macOS device using Xcode and a code editor of your choice (VSCode, WebStorm, etc) to ensure that the code is properly tested and works as expected on the intended platform. However, we understand that not everyone has access to a macOS device, so if you are contributing from a different operating system, please make sure to test your changes on an iOS simulator or device to ensure compatibility. This is important because we want to make sure that all contributions work as expected on the intended platform and do not introduce any issues or bugs. If you are unable to test your changes on an iOS simulator or device, please let us know in the pull request description so that we can assist you with testing and ensure that your contribution meets our standards. - - **10. Docstrings:** We ask that all code contributions include docstrings for any new functions, classes, or components that are added to the codebase. For new source files (files containing code), a file-level docstring should be included at the top of the file in this format: - ```txt - /** - * A brief description of the file's purpose and contents. - * - * License exactly as in the LICENSE file. (can be copy-pasted from there) - */ - ``` +To start work on an issue, you can follow these steps: +1. Fork the repository and create a new branch for your work. +2. Make a draft pull request to the main branch of the repository. This allows us to see your changes and provide feedback before you finalize your pull request. +3. Commit your changes and push them to your forked repository. +4. Make sure you follow the style guidelines and write clear commit messages to help us understand your changes. ## Style guidelines When contributing to Liquid-React, please follow our style guidelines to ensure that your code is consistent with the rest of the library. This includes using clear and descriptive variable names, writing comments where necessary, and following the existing code structure. - +Style guide: - Use camelCase for variable and function names. - Use PascalCase for component names. - Write clear and concise comments to explain the purpose of your code. - All commits should be prefixed with the type of change in this format: - -What Was Changed[optional Argument]: Short description of the change -Where `What Was Changed` is one of the following: - -```txt -- `Added` - for new components, functions, or features -- `Changed` - for changes to existing code that do not add new features (e.g., refactoring, code cleanup, etc) -- `Fixed` - for bug fixes -- `Docs` - for documentation changes -- `Other` - for changes that do not fit into the above categories (e.g., changes to the build process, CI/CD configuration, etc) -``` - -And `optional Argument` can be used to provide additional context about the change, such as the name of the component that was changed or the type of bug that was fixed. For example: - ```txt -- `Added(Button): New Button component with customizable styles` -- `Fixed(NativeMaterialView): Resolved issue with incorrect rendering on iOS 14` -- `Docs(readTheDocs): Updated index.rst with new table of contents` +[fix/feat/refactor/docs] Short description of the change ``` - - Use the present tense in commit messages (e.g., "Add new feature" instead of "Added new feature"). - Keep commit messages concise and to the point, ideally under 50 characters for the subject line and 72 characters for the body. -- Use present tense in commit messages (e.g., "Add new feature" instead of "Added new feature"). - Use eslint and prettier to ensure that your code is properly formatted and follows our style guidelines. -## Conclusion - -We appreciate your interest in contributing to liquidReact and we look forward to collaborating with you. By following these guidelines, you can help us maintain a high-quality codebase and ensure that your contributions are valuable and impactful. If you have any questions or need help, please don't hesitate to reach out to us in the discussions or open an issue. Thank you for being a part of our community! +## Code of Conduct +We expect all contributors to follow our code of conduct, which can be found in the CODE_OF_CONDUCT.md file in our repository. This code of conduct outlines our expectations for behavior when contributing to the project, and we take it very seriously. We want to create a welcoming and inclusive environment for all contributors, and we will not tolerate any form of harassment or discrimination. diff --git a/LICENSE b/LICENSE index 0effdaa..600810b 100644 --- a/LICENSE +++ b/LICENSE @@ -19,3 +19,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Thank you pookies :3 diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index 208b820..198ad78 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -1,242 +1,333 @@ # API Reference -Complete prop reference for all liquid-react components, types, and event payloads. +Complete reference for all Liquid-React components, props, and types. + +## Table of Contents +- [Materials & Containers](#materials--containers) +- [Controls](#controls) +- [Navigation](#navigation) +- [Types](#types) --- -## Components +## Materials & Containers ### NativeMaterialView -Wraps `UIVisualEffectView`. Renders the system blur effect. - -> ⚠️ **React Native children don't render inside this component.** The blur effect itself is visible, but child views are not. This is a known bridging issue. - -Default style: `overflow: 'hidden'`. +Exposes `UIVisualEffectView` with system blur materials. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `material` | `MaterialType` | `'systemMaterial'` | The UIKit blur material. See [MaterialType](#materialtype). | -| `onPress` | `(e) => void` | — | Fired on tap. `e.nativeEvent` is empty. | -| `style` | `ViewStyle` | — | Width/height or flex required. | +| `material` | `MaterialType` | `'systemMaterial'` | System blur material style | +| `onPress` | `() => void` | `undefined` | Called when view is tapped | +| `style` | `ViewStyle` | `undefined` | React Native style object | +| `children` | `ReactNode` | `undefined` | Child components | ---- +**Example:** +```jsx + console.log('Pressed')} +> + Content with native blur + +``` -### NativeButton +**UIKit Mapping:** `UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial))` -Wraps `UIButton` with `UIButton.Configuration` styles. +--- -Default style: `height: 44`. +### NativeGroupedContainer + +UIView with system grouped background color. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `title` | `string` | required | Button label. | -| `buttonStyle` | `ButtonStyle` | `'filled'` | Visual style. See [ButtonStyle](#buttonstyle). | -| `onPress` | `(e) => void` | — | Fired on tap. `e.nativeEvent` is empty. | -| `style` | `ViewStyle` | — | Use to set width. | +| `insetGrouped` | `boolean` | `true` | Use inset grouped style | +| `style` | `ViewStyle` | `undefined` | React Native style object | +| `children` | `ReactNode` | `undefined` | Child components | ---- +**Example:** +```jsx + + Grouped content + +``` -### NativeSwitch +**UIKit Mapping:** `UIView` with `backgroundColor = .systemGroupedBackground` + +--- -Wraps `UISwitch`. +### NativeCardContainer -No default size — uses the switch's intrinsic size. +UIView with continuous corner radius. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `value` | `boolean` | `false` | Controlled on/off state. | -| `onTintColor` | `string` | system tint | Track color when on (hex string, e.g. `'#007AFF'`). | -| `thumbTintColor` | `string` | `'#fff'` | Knob color. | -| `disabled` | `boolean` | `false` | Disables interaction. | -| `onValueChange` | `(e) => void` | — | Fired on toggle. `e.nativeEvent.value` is the new boolean. | +| `cornerRadius` | `number` | `10` | Corner radius in points | +| `style` | `ViewStyle` | `undefined` | React Native style object | +| `children` | `ReactNode` | `undefined` | Child components | ---- +**Example:** +```jsx + + Card content + +``` -### NativeSegmentedControl +**UIKit Mapping:** `UIView` with `layer.cornerRadius` and `layer.cornerCurve = .continuous` -Wraps `UISegmentedControl`. +--- -> ⚠️ **Liquid Glass selection rendering is unreliable.** The selection indicator appears on press but disappears on release due to a UIKit material environment limitation when bridged. The control is functionally correct — `onValueChange` fires and `selectedIndex` is respected. Only the visual material effect is affected. +## Controls -Default style: `height: 32`. +### NativeButton + +Native UIButton with system configurations. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `segments` | `string[]` | required | Array of segment labels. | -| `selectedIndex` | `number` | `0` | Controlled selected index. | -| `onValueChange` | `(e) => void` | — | Fired on selection. `e.nativeEvent.selectedIndex` is the new index. | +| `title` | `string` | `''` | Button title text (required) | +| `buttonStyle` | `ButtonStyle` | `'filled'` | System button style | +| `onPress` | `() => void` | `undefined` | Called when button is pressed | +| `style` | `ViewStyle` | `undefined` | React Native style object | ---- +**Example:** +```jsx + console.log('Pressed')} +/> +``` -### NativeSearchBar +**UIKit Mapping:** `UIButton(configuration: .filled())` + +--- -Wraps `UISearchBar`. +### NativeSwitch -Default style: `height: 56`. +Native UISwitch toggle control. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `placeholder` | `string` | `'Search'` | Placeholder text. | -| `text` | `string` | `''` | Controlled text value. | -| `onTextChanged` | `(e) => void` | — | Fired on every keystroke. `e.nativeEvent.text` is the current string. | -| `onSearchPressed` | `(e) => void` | — | Fired when the Search key is tapped. `e.nativeEvent.text` is the submitted string. | -| `onCancelPressed` | `(e) => void` | — | Fired when Cancel is tapped. `e.nativeEvent` is empty. | - ---- +| `value` | `boolean` | `false` | Switch on/off state | +| `onValueChange` | `(event) => void` | `undefined` | Called when value changes | +| `style` | `ViewStyle` | `undefined` | React Native style object | -### NativeNavigationBar +**Event Payload:** +```typescript +{ + nativeEvent: { + value: boolean + } +} +``` -Wraps `UINavigationBar`. +**Example:** +```jsx +const [enabled, setEnabled] = useState(false); -Default style: `height: 44`. + setEnabled(e.nativeEvent.value)} +/> +``` -**Props:** -| Prop | Type | Default | Description | -|------|------|---------|-------------| -| `title` | `string` | — | Title text centered in the bar. | -| `translucent` | `boolean` | `true` | When true, applies the system material blur behind the bar. | +**UIKit Mapping:** `UISwitch` --- -### NativeToolbar - -Wraps `UIToolbar`. Accepts `NativeToolbarButton` and `NativeToolbarMenu` as direct children — don't place arbitrary views inside it. +### NativeSegmentedControl -Default style: `height: 44`. +Native UISegmentedControl for segmented selection. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `translucent` | `boolean` | `true` | System material blur behind the toolbar. | -| `children` | `ReactNode` | — | Only `NativeToolbarButton` and `NativeToolbarMenu`. | +| `segments` | `string[]` | `[]` | Array of segment titles (required) | +| `selectedIndex` | `number` | `0` | Currently selected segment index | +| `onValueChange` | `(event) => void` | `undefined` | Called when selection changes | +| `style` | `ViewStyle` | `undefined` | React Native style object | + +**Event Payload:** +```typescript +{ + nativeEvent: { + selectedIndex: number + } +} +``` **Example:** -```tsx - - - - handleAction(e.nativeEvent.id)} - /> - +```jsx +const [index, setIndex] = useState(0); + + setIndex(e.nativeEvent.selectedIndex)} +/> ``` ---- +**UIKit Mapping:** `UISegmentedControl` -### NativeToolbarButton +--- -Wraps `UIBarButtonItem`. Must be a direct child of `NativeToolbar`. +### NativeSearchBar -Use `systemItem` for standard system items, or `icon`/`title` for custom ones. `flexibleSpace` and `fixedSpace` are layout-only items and don't fire `onPress`. +Native UISearchBar for search input. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `systemItem` | `ToolbarSystemItem` | — | UIKit system bar button item. See [ToolbarSystemItem](#toolbarsystemitem). | -| `icon` | `string` | — | SF Symbols name. Ignored if `systemItem` is set. | -| `title` | `string` | — | Label text. | -| `disabled` | `boolean` | `false` | Disables interaction. | -| `onPress` | `(e) => void` | — | Fired on tap. `e.nativeEvent` is empty. | - ---- +| `placeholder` | `string` | `''` | Placeholder text | +| `text` | `string` | `''` | Current search text | +| `onChangeText` | `(event) => void` | `undefined` | Called when text changes | +| `onSearchPress` | `(event) => void` | `undefined` | Called when search button pressed | +| `onCancelPress` | `() => void` | `undefined` | Called when cancel button pressed | +| `style` | `ViewStyle` | `undefined` | React Native style object | + +**Event Payload:** +```typescript +{ + nativeEvent: { + text: string + } +} +``` -### NativeToolbarMenu +**Example:** +```jsx +const [search, setSearch] = useState(''); + + setSearch(e.nativeEvent.text)} + onSearchPress={(e) => console.log('Search:', e.nativeEvent.text)} +/> +``` -Wraps `UIBarButtonItem` with an attached `UIMenu`. Must be a direct child of `NativeToolbar`. Supports nested submenus via `children` in `ToolbarMenuItem`. - -**Props:** -| Prop | Type | Default | Description | -|------|------|---------|-------------| -| `menuItems` | `ToolbarMenuItem[]` | required | Menu items. See [ToolbarMenuItem](#toolbarmenuitem). | -| `icon` | `string` | — | SF Symbols name for the button. | -| `title` | `string` | — | Label text for the button. | -| `disabled` | `boolean` | `false` | Disables the menu button. | -| `onMenuAction` | `(e) => void` | — | Fired on item selection. `e.nativeEvent.id` and `e.nativeEvent.title` identify the item. | +**UIKit Mapping:** `UISearchBar` --- -### NativeTabBar +## Navigation -Wraps `UITabBar`. +### NativeNavigationBar -Default style: `height: 49`. **Always set `height` explicitly in the `style` prop** — the view doesn't size itself automatically. +Native UINavigationBar for top navigation. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `items` | `TabBarItem[]` | required | Array of tab items. See [TabBarItem](#tabbaritem). | -| `selectedIndex` | `number` | `0` | Controlled selected tab. | -| `translucent` | `boolean` | `true` | System material blur behind the bar. | -| `onTabPress` | `(e) => void` | — | Fired on tab tap. `e.nativeEvent.index` is the tapped index. | +| `title` | `string` | `''` | Navigation bar title | +| `barTintColor` | `string` | `undefined` | Bar background color | +| `translucent` | `boolean` | `true` | Enable translucency | +| `style` | `ViewStyle` | `undefined` | React Native style object | -On iPhone with a home indicator, a typical total height (including safe area) is `83`–`95pt`. +**Example:** +```jsx + +``` ---- +**UIKit Mapping:** `UINavigationBar` -### NativeGroupedContainer +--- -A `UIView` with `systemGroupedBackground` applied. +### NativeToolbar -Default style: `overflow: 'hidden'`. +Native UIToolbar for bottom toolbars. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `insetGrouped` | `boolean` | `false` | When true, uses the inset grouped background style. | - ---- +| `items` | `ToolbarItem[]` | `[]` | Array of toolbar items | +| `translucent` | `boolean` | `true` | Enable translucency | +| `style` | `ViewStyle` | `undefined` | React Native style object | -### NativeCardContainer - -A `UIView` with `secondarySystemGroupedBackground` and a continuous corner radius. Matches the card cells in Settings, Contacts, etc. +**ToolbarItem Type:** +```typescript +{ + title?: string; // Custom title + systemItem?: ToolbarSystemItem; // System item type +} +``` -Default style: `overflow: 'hidden'`. +**Example:** +```jsx + +``` -**Props:** -| Prop | Type | Default | Description | -|------|------|---------|-------------| -| `cornerRadius` | `number` | `10` | Corner radius in points. Uses `CALayer.cornerCurve = .continuous`. | +**UIKit Mapping:** `UIToolbar` --- -### NativeStackView +### NativeTabBar -Wraps `UIStackView`. No default size or spacing. +Native UITabBar for tab navigation. **Props:** | Prop | Type | Default | Description | |------|------|---------|-------------| -| `axis` | `'vertical' \| 'horizontal'` | `'vertical'` | Layout direction. | -| `spacing` | `number` | `0` | Points between arranged subviews. | -| `alignment` | `StackAlignment` | `'fill'` | Cross-axis alignment. See [StackAlignment](#stackalignment). | -| `distribution` | `StackDistribution` | `'fill'` | Distribution along the axis. See [StackDistribution](#stackdistribution). | - ---- +| `items` | `TabBarItem[]` | `[]` | Array of tab items (required) | +| `selectedIndex` | `number` | `0` | Currently selected tab index | +| `translucent` | `boolean` | `true` | Enable translucency | +| `onTabPress` | `(event) => void` | `undefined` | Called when tab is pressed | +| `style` | `ViewStyle` | `undefined` | React Native style object | -### NativeMenuButton +**TabBarItem Type:** +```typescript +{ + title: string; // Tab title (required) + icon?: string; // SF Symbol name + systemItem?: TabBarSystemItem; // System tab item +} +``` -A standalone `UIButton` that shows a `UIMenu` on press. Works anywhere — no `NativeToolbar` required. +**Event Payload:** +```typescript +{ + nativeEvent: { + index: number + } +} +``` -No default size. Set width/height via `style`. +**Example:** +```jsx +const [tab, setTab] = useState(0); + + setTab(e.nativeEvent.index)} +/> +``` -**Props:** -| Prop | Type | Default | Description | -|------|------|---------|-------------| -| `menuItems` | `ToolbarMenuItem[]` | required | Menu items. See [ToolbarMenuItem](#toolbarmenuitem). | -| `icon` | `string` | — | SF Symbols name for the button icon. | -| `tintColorHex` | `string` | system tint | Icon tint color as a hex string. | -| `onMenuAction` | `(e) => void` | — | Fired on item selection. `e.nativeEvent.id` and `e.nativeEvent.title` identify the item. | +**UIKit Mapping:** `UITabBar` --- @@ -244,15 +335,15 @@ No default size. Set width/height via `style`. ### MaterialType -Controls the `UIVisualEffectView` blur material on `NativeMaterialView`. +All available UIKit system blur materials: ```typescript type MaterialType = - | 'systemUltraThinMaterial' // lightest, nearly transparent + | 'systemUltraThinMaterial' | 'systemThinMaterial' - | 'systemMaterial' // standard — used in sheets, cards + | 'systemMaterial' | 'systemThickMaterial' - | 'systemChromeMaterial' // heaviest — used in chrome areas + | 'systemChromeMaterial' | 'systemUltraThinMaterialLight' | 'systemThinMaterialLight' | 'systemMaterialLight' @@ -265,30 +356,42 @@ type MaterialType = | 'systemChromeMaterialDark'; ``` -The unsuffixed values adapt to light/dark mode automatically. `Light`/`Dark` suffixed variants lock to that appearance. +**Thickness Hierarchy:** +- `UltraThin` - Lightest blur +- `Thin` - Light blur +- `Material` - Standard blur (default) +- `Thick` - Heavy blur +- `Chrome` - Extra heavy blur + +**Appearance Variants:** +- No suffix - Adapts to system (light/dark) +- `Light` - Light appearance only +- `Dark` - Dark appearance only --- ### ButtonStyle -Maps to `UIButton.Configuration` styles. +UIButton configuration styles: ```typescript type ButtonStyle = - | 'filled' // solid tint background — primary action - | 'gray' // gray background — secondary action - | 'tinted' // light tinted background - | 'plain' // no background — tertiary action - | 'bordered' // border outline - | 'borderedTinted' // tinted border - | 'borderedProminent'; // prominent bordered style + | 'filled' // Solid background (default) + | 'gray' // Gray background + | 'tinted' // Tinted background + | 'plain' // No background + | 'bordered' // Border outline + | 'borderedTinted' // Tinted border + | 'borderedProminent'; // Prominent border ``` +**UIKit Mapping:** `UIButton.Configuration.*` + --- ### ToolbarSystemItem -Maps to `UIBarButtonItem.SystemItem`. Used on `NativeToolbarButton`. +System toolbar item types: ```typescript type ToolbarSystemItem = @@ -297,45 +400,18 @@ type ToolbarSystemItem = | 'compose' | 'reply' | 'action' | 'organize' | 'bookmarks' | 'search' | 'refresh' | 'stop' | 'camera' | 'trash' | 'play' | 'pause' - | 'rewind' | 'fastForward' | 'undo' | 'redo' | 'close'; + | 'rewind' | 'fastForward' + | 'undo' | 'redo' | 'close'; ``` -`flexibleSpace` expands to fill available space. `fixedSpace` is a fixed-size gap. Neither fires `onPress`. +**UIKit Mapping:** `UIBarButtonItem.SystemItem` --- -### ToolbarMenuItem +### TabBarSystemItem -Used in `menuItems` on `NativeToolbarMenu` and `NativeMenuButton`. Items can be nested to create submenus. +System tab bar item types: -```typescript -interface ToolbarMenuItem { - id?: string; // returned in onMenuAction — defaults to title if omitted - title: string; // required - icon?: string; // SF Symbols name - destructive?: boolean; // renders in red with UIMenuElement.Attributes.destructive - disabled?: boolean; // grays out and prevents selection - children?: ToolbarMenuItem[]; // nested items become a UIMenu submenu -} -``` - ---- - -### TabBarItem - -Used in `items` on `NativeTabBar`. - -```typescript -interface TabBarItem { - title: string; - icon?: string; // SF Symbols name - systemItem?: TabBarSystemItem; -} -``` - -If `systemItem` is set, UIKit provides the system icon and label. `icon` takes precedence over `systemItem` when both are provided. - -**TabBarSystemItem values:** ```typescript type TabBarSystemItem = | 'more' | 'favorites' | 'featured' | 'topRated' @@ -343,99 +419,49 @@ type TabBarSystemItem = | 'search' | 'downloads' | 'mostRecent' | 'mostViewed'; ``` ---- - -### StackAlignment - -Cross-axis alignment for `NativeStackView`. Maps to `UIStackView.Alignment`. - -```typescript -type StackAlignment = - | 'fill' - | 'leading' - | 'trailing' - | 'center' - | 'firstBaseline' // horizontal stacks only - | 'lastBaseline'; // horizontal stacks only -``` +**UIKit Mapping:** `UITabBarItem.SystemItem` --- -### StackDistribution - -How the stack distributes arranged views along its axis. Maps to `UIStackView.Distribution`. - -```typescript -type StackDistribution = - | 'fill' // one view expands to fill remaining space - | 'fillEqually' // all views the same size - | 'fillProportionally' // sized proportionally to intrinsic content size - | 'equalSpacing' // equal spacing between views - | 'equalCentering'; // equal spacing between centers -``` - ---- - -## Event Payloads - -All events follow the RN native event pattern: `(e: { nativeEvent: T }) => void`. - -| Event | `e.nativeEvent` | -|-------|----------------| -| `NativeButton.onPress` | `{}` | -| `NativeMaterialView.onPress` | `{}` | -| `NativeSwitch.onValueChange` | `{ value: boolean }` | -| `NativeSegmentedControl.onValueChange` | `{ selectedIndex: number }` | -| `NativeSearchBar.onTextChanged` | `{ text: string }` | -| `NativeSearchBar.onSearchPressed` | `{ text: string }` | -| `NativeSearchBar.onCancelPressed` | `{}` | -| `NativeTabBar.onTabPress` | `{ index: number }` | -| `NativeToolbarButton.onPress` | `{}` | -| `NativeToolbarMenu.onMenuAction` | `{ id: string; title: string }` | -| `NativeMenuButton.onMenuAction` | `{ id: string; title: string }` | - ---- - -## Default Sizes - -Applied automatically; override via `style`. - -| Component | Default | -|-----------|---------| -| `NativeButton` | `height: 44` | -| `NativeSegmentedControl` | `height: 32` | -| `NativeSearchBar` | `height: 56` | -| `NativeNavigationBar` | `height: 44` | -| `NativeToolbar` | `height: 44` | -| `NativeTabBar` | `height: 49` | -| `NativeMaterialView` | `overflow: 'hidden'` | -| `NativeGroupedContainer` | `overflow: 'hidden'` | -| `NativeCardContainer` | `overflow: 'hidden'` | -| `NativeSwitch` | intrinsic (no override) | -| `NativeStackView` | none — fully prop-driven | -| `NativeMenuButton` | none — set via `style` | - ---- - -## Known Limitations - -- **iOS only.** The native module doesn't load on Android or web. -- **No Auto Layout.** React Native uses frame-based layout. Components need a frame from `style` or a flex parent. -- **System-controlled colors.** Material colors, blur appearance, and most tints are controlled by iOS. -- **No custom blur intensity.** `UIVisualEffectView` doesn't expose blur radius as a public API. -- **NativeMaterialView children.** Child views don't render inside the blur view. Tracked as a known issue. -- **NativeSegmentedControl Liquid Glass.** Selection indicator disappears on release. Functionally correct — only the material effect is affected. +## Layout Guidelines + +### Recommended Heights +- `NativeButton`: 44pt (default iOS touch target) +- `NativeSegmentedControl`: 32pt +- `NativeSearchBar`: 56pt +- `NativeNavigationBar`: 44pt +- `NativeToolbar`: 44pt +- `NativeTabBar`: 49pt +- `NativeSwitch`: Intrinsic size (51×31pt) + +### Container Sizing +All container components accept standard React Native `style` props: +- `width` / `height` +- `flex` +- `padding` / `margin` +- `backgroundColor` (overrides system colors) + +### Best Practices +1. Always provide explicit `width` and `height` or use `flex` layout +2. Use `SafeAreaView` for navigation/tab bars +3. Respect iOS safe areas +4. Test on multiple iOS versions +5. Support both light and dark mode --- ## Platform Support -iOS 13.0+ only. Android and web are not supported. +- **iOS:** 13.0+ ✅ +- **Android:** Not supported ❌ +- **Web:** Not supported ❌ + +Liquid-React is iOS-only by design. --- ## See Also -- [Examples](./EXAMPLES.md) -- [Architecture](./ARCHITECTURE.md) -- [App Store Compliance](./APP_STORE_COMPLIANCE.md) +- [Examples](./EXAMPLES.md) - Usage examples +- [Architecture](./ARCHITECTURE.md) - Technical architecture +- [App Store Compliance](./APP_STORE_COMPLIANCE.md) - Legal compliance diff --git a/docs/COMPONENT_MAPPING.md b/docs/COMPONENT_MAPPING.md index 3788162..d043da0 100644 --- a/docs/COMPONENT_MAPPING.md +++ b/docs/COMPONENT_MAPPING.md @@ -12,14 +12,10 @@ This table documents the **exact 1:1 mapping** between Liquid-React components a | `NativeSegmentedControl` | `LRNativeSegmentedControlManager` | `UISegmentedControl` | Segmented picker control | | `NativeSearchBar` | `LRNativeSearchBarManager` | `UISearchBar` | Search input with cancel button | | `NativeNavigationBar` | `LRNativeNavigationBarManager` | `UINavigationBar` | Top navigation bar | -| `NativeToolbar` | `LRNativeToolbarManager` | `UIToolbar` | Bottom toolbar — accepts `NativeToolbarButton`/`NativeToolbarMenu` as children | -| `NativeToolbarButton` | `LRNativeToolbarButtonManager` | `UIBarButtonItem` | Bar button item inside a toolbar | -| `NativeToolbarMenu` | `LRNativeToolbarMenuManager` | `UIBarButtonItem` + `UIMenu` | Bar button with dropdown menu | +| `NativeToolbar` | `LRNativeToolbarManager` | `UIToolbar` | Bottom toolbar with bar button items | | `NativeTabBar` | `LRNativeTabBarManager` | `UITabBar` | Tab navigation bar | | `NativeGroupedContainer` | `LRNativeGroupedContainerManager` | `UIView` | Container with system grouped background | | `NativeCardContainer` | `LRNativeCardContainerManager` | `UIView` | Card with continuous corner radius | -| `NativeStackView` | `LRNativeStackViewManager` | `UIStackView` | Axis-based layout container | -| `NativeMenuButton` | `LRNativeMenuButtonManager` | `UIButton` + `UIMenu` | Standalone button with dropdown menu | ## Implementation Patterns @@ -163,9 +159,9 @@ class NativeNavigationBar: UIView { |-----------|---------------|-----------| | `placeholder` | `placeholder: NSString` | `UISearchBar.placeholder` | | `text` | `text: NSString` | `UISearchBar.text` | -| `onTextChanged` | `onTextChanged: RCTDirectEventBlock` | `UISearchBarDelegate.textDidChange` | -| `onSearchPressed` | `onSearchPressed: RCTDirectEventBlock` | `UISearchBarDelegate.searchButtonClicked` | -| `onCancelPressed` | `onCancelPressed: RCTDirectEventBlock` | `UISearchBarDelegate.cancelButtonClicked` | +| `onChangeText` | `onChangeText: RCTBubblingEventBlock` | `UISearchBarDelegate.textDidChange` | +| `onSearchPress` | `onSearchPress: RCTBubblingEventBlock` | `UISearchBarDelegate.searchButtonClicked` | +| `onCancelPress` | `onCancelPress: RCTBubblingEventBlock` | `UISearchBarDelegate.cancelButtonClicked` | ## Public API Verification diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 20ec991..250c3cf 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -1,6 +1,6 @@ # Examples -This page contains comprehensive examples of using Liquid-React components. +This directory contains comprehensive examples of using Liquid-React components. ## Complete App Example @@ -15,7 +15,6 @@ import { NativeSearchBar, NativeNavigationBar, NativeToolbar, - NativeToolbarButton, NativeTabBar, NativeGroupedContainer, NativeCardContainer, @@ -89,8 +88,8 @@ export default function App() { setSearchText(e.nativeEvent.text)} - onSearchPressed={(e) => console.log('Search:', e.nativeEvent.text)} + onChangeText={(e) => setSearchText(e.nativeEvent.text)} + onSearchPress={(e) => console.log('Search:', e.nativeEvent.text)} style={styles.searchBar} /> @@ -168,13 +167,17 @@ export default function App() { {/* Toolbar */} - - {}} /> - - {}} /> - - {}} /> - + {/* Tab Bar */} - @@ -55,7 +55,7 @@ export default function App() { Native iOS components in React Native - + setEnabled(e.nativeEvent.value)} /> - + setQuery(e.nativeEvent.text)} - onSearchPressed={(e) => performSearch(e.nativeEvent.text)} + onChangeText={(e) => setQuery(e.nativeEvent.text)} + onSearchPress={(e) => performSearch(e.nativeEvent.text)} /> ); } @@ -233,12 +233,9 @@ import { NativeMaterialView } from 'liquid-react'; function MyComponent() { if (Platform.OS !== 'ios') { - - Liquid-React is iOS-only - ; - return 0; + return ; } - + return ; } ``` @@ -250,9 +247,9 @@ Or use React Native's platform-specific files: ## App Store Compliance -✅ Liquid-React uses only public APIs -✅ Safe for App Store submission -✅ No private frameworks or hacks +✅ Liquid-React uses only public APIs +✅ Safe for App Store submission +✅ No private frameworks or hacks See [App Store Compliance](./APP_STORE_COMPLIANCE.md) for details. diff --git a/docs/README.md b/docs/README.md index aea72b6..6ac920c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -40,15 +40,11 @@ Liquid-React is a production-ready React Native iOS module that exposes Apple's - `NativeSwitch` - UISwitch toggle control - `NativeSegmentedControl` - UISegmentedControl picker - `NativeSearchBar` - UISearchBar for search input -- `NativeMenuButton` - standalone UIButton with UIMenu dropdown ### Navigation - `NativeNavigationBar` - UINavigationBar for top navigation -- `NativeToolbar` - UIToolbar for bottom toolbars (use `NativeToolbarButton`/`NativeToolbarMenu` as children) -- `NativeToolbarButton` - UIBarButtonItem inside a toolbar -- `NativeToolbarMenu` - UIBarButtonItem with UIMenu +- `NativeToolbar` - UIToolbar for bottom toolbars - `NativeTabBar` - UITabBar for tab navigation -- `NativeStackView` - UIStackView for axis-based layouts ## Learning Path diff --git a/docs/forReadTheDocs/.gitkeep b/docs/forReadTheDocs/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docs/forReadTheDocs/api.rst b/docs/forReadTheDocs/api.rst deleted file mode 100644 index c6d0677..0000000 --- a/docs/forReadTheDocs/api.rst +++ /dev/null @@ -1,344 +0,0 @@ -API Reference -============= - -Complete type reference for all props, event payloads, and enum values exported by liquid-react. - -.. contents:: On this page - :local: - :depth: 1 - ----- - -.. _material-types: - -MaterialType ------------- - -Controls which ``UIVisualEffectView`` material is applied to ``NativeMaterialView``. - -.. code-block:: typescript - - type MaterialType = - | 'systemUltraThinMaterial' - | 'systemThinMaterial' - | 'systemMaterial' - | 'systemThickMaterial' - | 'systemChromeMaterial' - | 'systemUltraThinMaterialLight' - | 'systemThinMaterialLight' - | 'systemMaterialLight' - | 'systemThickMaterialLight' - | 'systemChromeMaterialLight' - | 'systemUltraThinMaterialDark' - | 'systemThinMaterialDark' - | 'systemMaterialDark' - | 'systemThickMaterialDark' - | 'systemChromeMaterialDark'; - -The first five values are adaptive (they respond to light/dark mode automatically). The ``Light`` and ``Dark`` suffixed variants lock the material to that appearance regardless of the system setting. - -**Adaptive materials (lightest to heaviest)** - -.. list-table:: - :header-rows: 1 - :widths: 40 60 - - * - Value - - Description - * - ``systemUltraThinMaterial`` - - Very subtle blur, nearly transparent. - * - ``systemThinMaterial`` - - Light blur, slightly more opaque. - * - ``systemMaterial`` - - Standard system material — used in sheets, cards, popovers. - * - ``systemThickMaterial`` - - Heavier blur, more opaque. - * - ``systemChromeMaterial`` - - Heaviest blur, used in chrome areas like tab bars. - ----- - -.. _button-styles: - -ButtonStyle ------------ - -Maps to ``UIButton.Configuration`` button styles. - -.. code-block:: typescript - - type ButtonStyle = - | 'filled' - | 'gray' - | 'tinted' - | 'plain' - | 'bordered' - | 'borderedTinted' - | 'borderedProminent'; - -.. list-table:: - :header-rows: 1 - :widths: 25 75 - - * - Value - - Description - * - ``filled`` - - Solid background in the tint color. Primary action button. - * - ``gray`` - - Gray background. Secondary action. - * - ``tinted`` - - Tinted background (lighter than filled). - * - ``plain`` - - No background, just the label. Tertiary action. - * - ``bordered`` - - Outlined border. - * - ``borderedTinted`` - - Outlined border with tinted text. - * - ``borderedProminent`` - - Prominent bordered style. - ----- - -.. _toolbar-system-items: - -ToolbarSystemItem ------------------ - -Maps to ``UIBarButtonItem.SystemItem``. Used on ``NativeToolbarButton``. - -.. code-block:: typescript - - type ToolbarSystemItem = - | 'done' | 'cancel' | 'edit' | 'save' | 'add' - | 'flexibleSpace' | 'fixedSpace' - | 'compose' | 'reply' | 'action' | 'organize' - | 'bookmarks' | 'search' | 'refresh' | 'stop' - | 'camera' | 'trash' | 'play' | 'pause' - | 'rewind' | 'fastForward' | 'undo' | 'redo' | 'close'; - -``flexibleSpace`` and ``fixedSpace`` are layout items — they don't fire ``onPress``. ``flexibleSpace`` expands to fill available space; ``fixedSpace`` is a fixed-size gap. - ----- - -.. _toolbar-menu-item: - -ToolbarMenuItem ---------------- - -Used in the ``menuItems`` prop of ``NativeToolbarMenu`` and ``NativeMenuButton``. Items can be nested to create submenus. - -.. code-block:: typescript - - interface ToolbarMenuItem { - id?: string; - title: string; - icon?: string; - destructive?: boolean; - disabled?: boolean; - children?: ToolbarMenuItem[]; - } - -.. list-table:: - :header-rows: 1 - :widths: 20 20 60 - - * - Field - - Type - - Description - * - ``id`` - - ``string`` - - Identifier returned in ``onMenuAction``. Defaults to ``title`` if omitted. - * - ``title`` - - ``string`` - - Display label. Required. - * - ``icon`` - - ``string`` - - SF Symbols name (e.g. ``'trash'``, ``'star.fill'``). - * - ``destructive`` - - ``boolean`` - - Renders the item in red with the ``UIMenuElement.Attributes.destructive`` attribute. - * - ``disabled`` - - ``boolean`` - - Grays out the item and prevents selection. - * - ``children`` - - ``ToolbarMenuItem[]`` - - Child items that form a submenu. UIKit renders this as a nested ``UIMenu``. - ----- - -.. _tab-bar-item: - -TabBarItem ----------- - -Used in the ``items`` prop of ``NativeTabBar``. - -.. code-block:: typescript - - interface TabBarItem { - title: string; - icon?: string; - systemItem?: TabBarSystemItem; - } - -If ``systemItem`` is provided, UIKit uses the system icon and label. ``icon`` is an SF Symbols name and overrides ``systemItem`` when both are set. - -**TabBarSystemItem values** - -.. code-block:: typescript - - type TabBarSystemItem = - | 'more' | 'favorites' | 'featured' | 'topRated' - | 'recents' | 'contacts' | 'history' | 'bookmarks' - | 'search' | 'downloads' | 'mostRecent' | 'mostViewed'; - ----- - -.. _stack-alignment: - -StackAlignment --------------- - -Cross-axis alignment for ``NativeStackView``. Maps directly to ``UIStackView.Alignment``. - -.. code-block:: typescript - - type StackAlignment = - | 'fill' - | 'leading' - | 'trailing' - | 'center' - | 'firstBaseline' - | 'lastBaseline'; - -``firstBaseline`` and ``lastBaseline`` apply only to horizontal stacks. - ----- - -.. _stack-distribution: - -StackDistribution ------------------ - -How the stack distributes arranged views along its axis. Maps to ``UIStackView.Distribution``. - -.. code-block:: typescript - - type StackDistribution = - | 'fill' - | 'fillEqually' - | 'fillProportionally' - | 'equalSpacing' - | 'equalCentering'; - -.. list-table:: - :header-rows: 1 - :widths: 30 70 - - * - Value - - Description - * - ``fill`` - - One view expands to fill remaining space. - * - ``fillEqually`` - - All views are the same size. - * - ``fillProportionally`` - - Views are sized proportionally to their intrinsic content size. - * - ``equalSpacing`` - - Views have equal spacing between them. - * - ``equalCentering`` - - Views are centered with equal space between their centers. - ----- - -Event Payloads --------------- - -Events follow the React Native native event pattern: the handler receives ``(e: { nativeEvent: T })``. - -.. list-table:: - :header-rows: 1 - :widths: 40 60 - - * - Event - - ``e.nativeEvent`` shape - * - ``NativeButton.onPress`` - - ``{}`` - * - ``NativeMaterialView.onPress`` - - ``{}`` - * - ``NativeSwitch.onValueChange`` - - ``{ value: boolean }`` - * - ``NativeSegmentedControl.onValueChange`` - - ``{ selectedIndex: number }`` - * - ``NativeSearchBar.onTextChanged`` - - ``{ text: string }`` - * - ``NativeSearchBar.onSearchPressed`` - - ``{ text: string }`` - * - ``NativeSearchBar.onCancelPressed`` - - ``{}`` - * - ``NativeTabBar.onTabPress`` - - ``{ index: number }`` - * - ``NativeToolbarButton.onPress`` - - ``{}`` - * - ``NativeToolbarMenu.onMenuAction`` - - ``{ id: string; title: string }`` - * - ``NativeMenuButton.onMenuAction`` - - ``{ id: string; title: string }`` - ----- - -Default Sizes -------------- - -These sizes are applied automatically unless you override them via the ``style`` prop. - -.. list-table:: - :header-rows: 1 - :widths: 40 60 - - * - Component - - Default style - * - ``NativeButton`` - - ``height: 44`` - * - ``NativeSegmentedControl`` - - ``height: 32`` - * - ``NativeSearchBar`` - - ``height: 56`` - * - ``NativeNavigationBar`` - - ``height: 44`` - * - ``NativeToolbar`` - - ``height: 44`` - * - ``NativeTabBar`` - - ``height: 49`` - * - ``NativeMaterialView`` - - ``overflow: 'hidden'`` - * - ``NativeGroupedContainer`` - - ``overflow: 'hidden'`` - * - ``NativeCardContainer`` - - ``overflow: 'hidden'`` - * - ``NativeSwitch`` - - intrinsic size (no override) - * - ``NativeToolbarButton`` - - intrinsic size (no override) - * - ``NativeToolbarMenu`` - - intrinsic size (no override) - * - ``NativeMenuButton`` - - no default (set via ``style``) - * - ``NativeStackView`` - - no default (fully prop-driven) - ----- - -Known Limitations ------------------ - -- **iOS only.** Android and web are not supported. The native module will not load on other platforms. -- **No Auto Layout.** React Native uses frame-based layout. Components must be given a frame via the ``style`` prop or a flex parent. -- **System-controlled colors.** Background colors, blur effect colors, and tint colors are managed by iOS. You can't override the material color. -- **No custom blur intensity.** Apple's ``UIVisualEffectView`` does not expose blur radius as a public API. -- **NativeMaterialView children broken.** See the component docs. The blur renders correctly but RN children are not visible inside it. -- **NativeSegmentedControl Liquid Glass.** The selection indicator doesn't persist visually due to a UIKit material environment limitation when bridged. - -App Store Compliance --------------------- - -liquid-react uses **only public Apple APIs**. No private frameworks, no runtime injection, no reverse-engineered internals. It is safe to ship in App Store builds. diff --git a/docs/forReadTheDocs/components.rst b/docs/forReadTheDocs/components.rst deleted file mode 100644 index 0c2a111..0000000 --- a/docs/forReadTheDocs/components.rst +++ /dev/null @@ -1,695 +0,0 @@ -Components -========== - -All components are re-exported from the top-level ``liquid-react`` package. Every component accepts all standard React Native ``ViewProps`` in addition to its own props (so ``style``, ``testID``, etc. all work). Events arrive as ``(e: { nativeEvent: PayloadType }) => void``. - -.. contents:: On this page - :local: - :depth: 1 - ----- - -NativeMaterialView ------------------- - -Wraps ``UIVisualEffectView`` with one of Apple's system blur materials. The view renders the blur effect and composites content on top of it. - -.. warning:: - - React Native children do not render correctly inside ``NativeMaterialView`` due to a known bridging limitation. The blur effect itself renders fine, but child views are not visible. Do not use this component to contain other React Native views until this issue is resolved. - -Default size: ``overflow: hidden`` applied automatically. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``material`` - - ``MaterialType`` - - ``'systemMaterial'`` - - The UIKit blur material to apply. See :ref:`material-types` for all values. - * - ``onPress`` - - ``(e) => void`` - - — - - Fired when the view is tapped. ``e.nativeEvent`` is empty. - * - ``style`` - - ``ViewStyle`` - - — - - Standard RN style. You must set width/height or flex. - -**Example** - -.. code-block:: tsx - - - ----- - -NativeButton ------------- - -Wraps ``UIButton`` with system button configurations. The ``buttonStyle`` prop maps directly to ``UIButton.Configuration`` styles introduced in iOS 15, with graceful fallback on older versions. - -Default size: ``height: 44``. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``title`` - - ``string`` - - required - - Button label text. - * - ``buttonStyle`` - - ``ButtonStyle`` - - ``'filled'`` - - Visual style. See :ref:`button-styles` for all values. - * - ``onPress`` - - ``(e) => void`` - - — - - Fired on tap. ``e.nativeEvent`` is empty. - * - ``style`` - - ``ViewStyle`` - - — - - Use to set width. Height defaults to 44. - -**Example** - -.. code-block:: tsx - - console.log('pressed')} - style={{ width: '100%' }} - /> - - - ----- - -NativeSwitch ------------- - -Wraps ``UISwitch``. The appearance is fully controlled by iOS — tint colors adapt automatically to light/dark mode unless explicitly overridden. - -No default size is applied; the switch uses its intrinsic size. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``value`` - - ``boolean`` - - ``false`` - - Controlled on/off state. - * - ``onTintColor`` - - ``string`` - - system tint - - Track color when the switch is on. Accepts any CSS hex color (e.g. ``'#007AFF'``). - * - ``thumbTintColor`` - - ``string`` - - ``'#fff'`` - - Knob color. - * - ``disabled`` - - ``boolean`` - - ``false`` - - Disables interaction. - * - ``onValueChange`` - - ``(e) => void`` - - — - - Fired when toggled. ``e.nativeEvent.value`` is the new boolean state. - -**Example** - -.. code-block:: tsx - - const [enabled, setEnabled] = React.useState(false); - - setEnabled(e.nativeEvent.value)} - /> - ----- - -NativeSegmentedControl ----------------------- - -Wraps ``UISegmentedControl``. - -.. warning:: - - The Liquid Glass selection indicator rendering is unreliable when this control is embedded in a React Native bridged view. The highlight appears during press but disappears on release because UIKit cannot fully resolve the material environment. The control is functionally correct — ``onValueChange`` fires properly and ``selectedIndex`` is respected. Only the visual material effect is affected. - -Default size: ``height: 32``. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``segments`` - - ``string[]`` - - required - - Array of segment labels. - * - ``selectedIndex`` - - ``number`` - - ``0`` - - Controlled selected segment index. - * - ``onValueChange`` - - ``(e) => void`` - - — - - Fired when a segment is tapped. ``e.nativeEvent.selectedIndex`` is the new index. - -**Example** - -.. code-block:: tsx - - const [tab, setTab] = React.useState(0); - - setTab(e.nativeEvent.selectedIndex)} - style={{ width: '100%' }} - /> - ----- - -NativeSearchBar ---------------- - -Wraps ``UISearchBar``. Renders the native iOS search bar with the system keyboard integration and cancel button behavior. - -Default size: ``height: 56``. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``placeholder`` - - ``string`` - - ``'Search'`` - - Placeholder text shown when the field is empty. - * - ``text`` - - ``string`` - - ``''`` - - Controlled text value. - * - ``onTextChanged`` - - ``(e) => void`` - - — - - Fired on every keystroke. ``e.nativeEvent.text`` is the current string. - * - ``onSearchPressed`` - - ``(e) => void`` - - — - - Fired when the user taps the Search key. ``e.nativeEvent.text`` is the submitted string. - * - ``onCancelPressed`` - - ``(e) => void`` - - — - - Fired when the Cancel button is tapped. ``e.nativeEvent`` is empty. - -**Example** - -.. code-block:: tsx - - const [query, setQuery] = React.useState(''); - - setQuery(e.nativeEvent.text)} - onSearchPressed={(e) => runSearch(e.nativeEvent.text)} - onCancelPressed={() => setQuery('')} - style={{ width: '100%' }} - /> - ----- - -NativeNavigationBar -------------------- - -Wraps ``UINavigationBar``. Renders a standalone navigation bar — useful for custom layouts where you want the bar without a full navigation controller. - -Default size: ``height: 44``. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``title`` - - ``string`` - - — - - Title text displayed in the center of the bar. - * - ``translucent`` - - ``boolean`` - - ``true`` - - When true, applies the system material blur behind the bar. - -**Example** - -.. code-block:: tsx - - - ----- - -NativeToolbar -------------- - -Wraps ``UIToolbar``. Accepts ``NativeToolbarButton`` and ``NativeToolbarMenu`` as direct children. The toolbar manages the native bar button item layout internally — do not place arbitrary views inside it. - -Default size: ``height: 44``. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``translucent`` - - ``boolean`` - - ``true`` - - When true, applies system material blur behind the toolbar. - * - ``children`` - - ``ReactNode`` - - — - - Should only contain ``NativeToolbarButton`` and ``NativeToolbarMenu`` components. - -**Example** - -.. code-block:: tsx - - - - - handleAction(e.nativeEvent.id)} - /> - - ----- - -NativeToolbarButton -------------------- - -Wraps ``UIBarButtonItem``. Must be a direct child of ``NativeToolbar``. - -You can configure it with a system item, a title, an SF Symbol icon, or a combination. When using ``systemItem``, the appropriate system icon and accessibility label are applied automatically. - -No default size (intrinsic to the bar button item). - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``systemItem`` - - ``ToolbarSystemItem`` - - — - - A UIKit system bar button item (e.g. ``'add'``, ``'done'``, ``'flexibleSpace'``). See :ref:`toolbar-system-items`. - * - ``icon`` - - ``string`` - - — - - SF Symbols name (e.g. ``'star.fill'``). Ignored if ``systemItem`` is set. - * - ``title`` - - ``string`` - - — - - Label text. Can be used alongside ``icon``. - * - ``disabled`` - - ``boolean`` - - ``false`` - - Disables tap interaction. - * - ``onPress`` - - ``(e) => void`` - - — - - Fired on tap. ``e.nativeEvent`` is empty. - -**Example** - -.. code-block:: tsx - - {/* system item */} - - - {/* SF Symbol icon */} - - - {/* flexible space — pushes items to edges */} - - ----- - -NativeToolbarMenu ------------------ - -Wraps ``UIBarButtonItem`` with an attached ``UIMenu``. Must be a direct child of ``NativeToolbar``. Menu items can be nested to create submenus. - -No default size (intrinsic to the bar button item). - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``menuItems`` - - ``ToolbarMenuItem[]`` - - required - - Array of menu items. See :ref:`toolbar-menu-item`. - * - ``icon`` - - ``string`` - - — - - SF Symbols name for the button that opens the menu. - * - ``title`` - - ``string`` - - — - - Label text for the button. - * - ``disabled`` - - ``boolean`` - - ``false`` - - Disables the entire menu button. - * - ``onMenuAction`` - - ``(e) => void`` - - — - - Fired when a menu item is selected. ``e.nativeEvent.id`` and ``e.nativeEvent.title`` identify the item. - -**Example** - -.. code-block:: tsx - - console.log('tapped', e.nativeEvent.id)} - /> - ----- - -NativeTabBar ------------- - -Wraps ``UITabBar``. Tab items can use SF Symbol icons, system items, or just a title. - -Default size: ``height: 49``. You must set a height explicitly in the ``style`` prop — the native view does not size itself automatically. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``items`` - - ``TabBarItem[]`` - - required - - Array of tab items. See :ref:`tab-bar-item`. - * - ``selectedIndex`` - - ``number`` - - ``0`` - - Controlled selected tab index. - * - ``translucent`` - - ``boolean`` - - ``true`` - - When true, applies system material blur behind the tab bar. - * - ``onTabPress`` - - ``(e) => void`` - - — - - Fired when a tab is tapped. ``e.nativeEvent.index`` is the selected index. - -.. note:: - - Always set ``height`` in the ``style`` prop. On iPhone with a home indicator the typical height is ``83``–``95`` to account for the safe area. Use ``SafeAreaInsets`` if you need to calculate this dynamically. - -**Example** - -.. code-block:: tsx - - const [tab, setTab] = React.useState(0); - - setTab(e.nativeEvent.index)} - translucent={true} - style={{ position: 'absolute', bottom: 0, width: '100%', height: 83 }} - /> - ----- - -NativeGroupedContainer ------------------------ - -A plain ``UIView`` with ``systemGroupedBackground`` applied. Use it as a section background, matching the look of grouped settings tables. - -Default size: ``overflow: hidden`` applied automatically. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``insetGrouped`` - - ``boolean`` - - ``false`` - - When true, uses ``systemGroupedBackground`` (same as the inset grouped table style). When false, uses the plain grouped background. - -**Example** - -.. code-block:: tsx - - - - {/* card contents */} - - - ----- - -NativeCardContainer -------------------- - -A ``UIView`` with ``secondarySystemGroupedBackground`` and a continuous corner radius. Matches the card cells in Settings, Contacts, and other system apps. - -Default size: ``overflow: hidden`` applied automatically. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``cornerRadius`` - - ``number`` - - ``10`` - - Corner radius in points. Uses ``CALayer.cornerCurve = .continuous``. - -**Example** - -.. code-block:: tsx - - - Card title - Supporting text - - ----- - -NativeStackView ---------------- - -Wraps ``UIStackView``. Arranges its children along a vertical or horizontal axis. Layout is entirely prop-driven — no default size or spacing is applied. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``axis`` - - ``'vertical' | 'horizontal'`` - - ``'vertical'`` - - The layout direction. - * - ``spacing`` - - ``number`` - - ``0`` - - Points of spacing between arranged subviews. - * - ``alignment`` - - ``StackAlignment`` - - ``'fill'`` - - Cross-axis alignment. See :ref:`stack-alignment`. - * - ``distribution`` - - ``StackDistribution`` - - ``'fill'`` - - How arranged views are distributed along the axis. See :ref:`stack-distribution`. - -**Example** - -.. code-block:: tsx - - - - - - ----- - -NativeMenuButton ----------------- - -A standalone ``UIButton`` that shows a ``UIMenu`` on press. Unlike ``NativeToolbarMenu``, this works anywhere in your layout — no ``NativeToolbar`` required. - -No default size applied; size it via the ``style`` prop. - -**Props** - -.. list-table:: - :header-rows: 1 - :widths: 20 20 10 50 - - * - Prop - - Type - - Default - - Description - * - ``menuItems`` - - ``ToolbarMenuItem[]`` - - required - - Array of menu items. See :ref:`toolbar-menu-item`. - * - ``icon`` - - ``string`` - - — - - SF Symbols name for the button icon. - * - ``tintColorHex`` - - ``string`` - - system tint - - Icon/label tint color as a hex string (e.g. ``'#FF3B30'``). - * - ``onMenuAction`` - - ``(e) => void`` - - — - - Fired when a menu item is selected. ``e.nativeEvent.id`` and ``e.nativeEvent.title`` identify the item. - -**Example** - -.. code-block:: tsx - - handleAction(e.nativeEvent.id)} - style={{ width: 44, height: 44 }} - /> diff --git a/docs/forReadTheDocs/examples.rst b/docs/forReadTheDocs/examples.rst deleted file mode 100644 index d3db7b6..0000000 --- a/docs/forReadTheDocs/examples.rst +++ /dev/null @@ -1,397 +0,0 @@ -Examples -======== - -Complete, working patterns for common use cases. - -.. contents:: On this page - :local: - :depth: 1 - ----- - -Settings Screen ---------------- - -A grouped settings layout using ``NativeGroupedContainer``, ``NativeCardContainer``, and native controls. - -.. code-block:: tsx - - import React, { useState } from 'react'; - import { ScrollView, Text, StyleSheet } from 'react-native'; - import { - NativeGroupedContainer, - NativeCardContainer, - NativeSwitch, - NativeSegmentedControl, - } from 'liquid-react'; - - export default function SettingsScreen() { - const [notifications, setNotifications] = useState(true); - const [haptics, setHaptics] = useState(false); - const [theme, setTheme] = useState(0); - - return ( - - - - - Notifications - setNotifications(e.nativeEvent.value)} - /> - - - - Haptics - setHaptics(e.nativeEvent.value)} - /> - - - - - - - Appearance - setTheme(e.nativeEvent.selectedIndex)} - style={{ width: 200 }} - /> - - - - ); - } - - const styles = StyleSheet.create({ - section: { marginTop: 20, marginHorizontal: 16 }, - card: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - padding: 12, - marginBottom: 1, - }, - label: { fontSize: 17 }, - }); - ----- - -Toolbar with Buttons and Menu ------------------------------- - -A toolbar fixed to the bottom of the screen with a mix of system items and a context menu. - -.. code-block:: tsx - - import React from 'react'; - import { View, StyleSheet } from 'react-native'; - import { - NativeToolbar, - NativeToolbarButton, - NativeToolbarMenu, - } from 'liquid-react'; - - export default function EditorScreen() { - const handleAction = (id: string) => { - switch (id) { - case 'share': share(); break; - case 'duplicate': duplicate(); break; - case 'delete': confirmDelete(); break; - } - }; - - return ( - - {/* ...main content... */} - - - - - - - - handleAction(e.nativeEvent.id)} - /> - - - ); - } - - const styles = StyleSheet.create({ - container: { flex: 1 }, - toolbar: { - position: 'absolute', - bottom: 0, - width: '100%', - }, - }); - ----- - -Tab Bar Navigation ------------------- - -A native tab bar at the bottom of the screen with controlled tab state. - -.. code-block:: tsx - - import React, { useState } from 'react'; - import { View, Text, StyleSheet } from 'react-native'; - import { NativeTabBar } from 'liquid-react'; - - const TABS = [ - { title: 'Home', icon: 'house' }, - { title: 'Search', icon: 'magnifyingglass' }, - { title: 'Library', icon: 'books.vertical' }, - { title: 'Profile', icon: 'person.crop.circle' }, - ]; - - const SCREENS = ['Home', 'Search', 'Library', 'Profile']; - - export default function RootNavigator() { - const [tab, setTab] = useState(0); - - return ( - - - {SCREENS[tab]} - - - setTab(e.nativeEvent.index)} - translucent={true} - style={styles.tabBar} - /> - - ); - } - - const styles = StyleSheet.create({ - container: { flex: 1 }, - content: { flex: 1, justifyContent: 'center', alignItems: 'center' }, - heading: { fontSize: 28, fontWeight: '700' }, - tabBar: { - position: 'absolute', - bottom: 0, - width: '100%', - height: 83, - }, - }); - ----- - -Search Interface ----------------- - -A search bar wired to a filtered list. - -.. code-block:: tsx - - import React, { useState, useMemo } from 'react'; - import { FlatList, Text, StyleSheet } from 'react-native'; - import { NativeSearchBar } from 'liquid-react'; - - const DATA = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig']; - - export default function SearchScreen() { - const [query, setQuery] = useState(''); - - const results = useMemo( - () => DATA.filter((item) => item.toLowerCase().includes(query.toLowerCase())), - [query], - ); - - return ( - <> - setQuery(e.nativeEvent.text)} - onCancelPressed={() => setQuery('')} - style={styles.searchBar} - /> - item} - renderItem={({ item }) => {item}} - /> - - ); - } - - const styles = StyleSheet.create({ - searchBar: { width: '100%' }, - row: { padding: 16, fontSize: 17 }, - }); - ----- - -Context Menu Button -------------------- - -A ``NativeMenuButton`` placed inline (no toolbar needed). - -.. code-block:: tsx - - import React from 'react'; - import { View, Text, StyleSheet } from 'react-native'; - import { NativeMenuButton } from 'liquid-react'; - - export default function ListItem({ onEdit, onDelete }: Props) { - const handleAction = (id: string) => { - if (id === 'edit') onEdit(); - if (id === 'delete') onDelete(); - }; - - return ( - - My Item - handleAction(e.nativeEvent.id)} - style={styles.button} - /> - - ); - } - - const styles = StyleSheet.create({ - row: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - paddingHorizontal: 16, - paddingVertical: 12, - }, - label: { fontSize: 17 }, - button: { width: 44, height: 44 }, - }); - ----- - -Stack Layout ------------- - -A vertically arranged set of buttons using ``NativeStackView``. - -.. code-block:: tsx - - import React from 'react'; - import { NativeStackView, NativeButton } from 'liquid-react'; - - export default function ActionSheet() { - return ( - - - - - - ); - } - ----- - -Material Types Comparison --------------------------- - -All five adaptive materials side by side. - -.. code-block:: tsx - - import React from 'react'; - import { View, Text, ImageBackground, StyleSheet } from 'react-native'; - import { NativeMaterialView } from 'liquid-react'; - - const MATERIALS = [ - 'systemUltraThinMaterial', - 'systemThinMaterial', - 'systemMaterial', - 'systemThickMaterial', - 'systemChromeMaterial', - ] as const; - - export default function MaterialShowcase() { - return ( - - - {MATERIALS.map((mat) => ( - - {/* children broken — label placed outside for now */} - - ))} - - - ); - } - - const styles = StyleSheet.create({ - bg: { flex: 1, justifyContent: 'center', alignItems: 'center' }, - grid: { gap: 12 }, - chip: { width: 260, height: 60, borderRadius: 12 }, - }); - -.. note:: - - ``NativeMaterialView`` children are currently broken — child views don't render inside the blur view. The blur itself is visible. Track progress on this at the GitHub issues page. - ----- - -Platform Guard Pattern ------------------------ - -Safely rendering liquid-react components only on iOS. - -.. code-block:: tsx - - import React from 'react'; - import { Platform, View, StyleSheet } from 'react-native'; - import { NativeButton } from 'liquid-react'; - - export default function PlatformAwareButton({ onPress }: { onPress: () => void }) { - if (Platform.OS !== 'ios') { - return ( - - {/* use a cross-platform button here */} - - ); - } - - return ( - - ); - } - - const styles = StyleSheet.create({ - fallback: { height: 44, backgroundColor: '#007AFF', borderRadius: 10 }, - }); diff --git a/docs/forReadTheDocs/getting-started.rst b/docs/forReadTheDocs/getting-started.rst deleted file mode 100644 index 80bac18..0000000 --- a/docs/forReadTheDocs/getting-started.rst +++ /dev/null @@ -1,112 +0,0 @@ -Getting Started -=============== - -Requirements ------------- - -- macOS with Xcode 11+ -- React Native 0.65.0+ -- iOS deployment target 13.0+ -- CocoaPods - -Installation ------------- - -.. code-block:: bash - - npm install liquid-react - # or - yarn add liquid-react - -Then link the native module: - -.. code-block:: bash - - cd ios && pod install - -Rebuild your app after pod install: - -.. code-block:: bash - - npm run ios - -That's it. No extra native configuration needed. - -First Component ---------------- - -.. code-block:: tsx - - import React from 'react'; - import { SafeAreaView, StyleSheet } from 'react-native'; - import { NativeButton } from 'liquid-react'; - - export default function App() { - return ( - - console.log('pressed')} - style={{ width: 200 }} - /> - - ); - } - - const styles = StyleSheet.create({ - container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, - }); - -iOS Version Behavior --------------------- - -All components work on iOS 13+, but visual rendering depends on the iOS version: - -- **iOS 26+** — full Liquid Glass rendering, identical to Apple's own apps -- **iOS 13-18** — real native UIKit components, system appearance for that iOS version (no Liquid Glass, but still authentic native rendering) - -The library never simulates anything. Whatever iOS renders is what you get. - -Platform Guard --------------- - -liquid-react is iOS-only. If your project targets multiple platforms, guard usage: - -.. code-block:: tsx - - import { Platform } from 'react-native'; - - function MyComponent() { - if (Platform.OS !== 'ios') { - return ; - } - return ; - } - -Or use React Native's platform file extensions (``MyComponent.ios.tsx``, ``MyComponent.android.tsx``). - -Troubleshooting ---------------- - -**Module not found / symbols not linked** - Run ``cd ios && pod install``, then rebuild. - -**Build errors after updating** - Clean the pods and reinstall: - - .. code-block:: bash - - cd ios - rm -rf Pods Podfile.lock - pod install - -**Blur not visible** - Make sure the parent view has a non-zero frame and you're running on a simulator or device (not just doing a type check). ``NativeMaterialView`` requires a real rendering context. - -**npm install peer dependency errors** - If you're on React Native 0.84+ with ``@types/react@18``, use: - - .. code-block:: bash - - npm install --legacy-peer-deps diff --git a/docs/forReadTheDocs/index.rst b/docs/forReadTheDocs/index.rst deleted file mode 100644 index 22b41f3..0000000 --- a/docs/forReadTheDocs/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -liquid-react -============ - -React Native bindings for real UIKit components. This isn't a blur approximation or a custom renderer — it's ``UIButton``, ``UISwitch``, ``UIToolbar``, ``UITabBar``, etc., exposed through a thin bridge. iOS renders everything. - -Requires iOS 13+. Liquid Glass requires iOS 26+. iOS only. - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - getting-started - components - api - examples - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`search` - diff --git a/ios/LRNativeButtonManager.m b/ios/LRNativeButtonManager.m index a74f01c..9ea7783 100644 --- a/ios/LRNativeButtonManager.m +++ b/ios/LRNativeButtonManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeButton view properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeButtonManager, RCTViewManager) diff --git a/ios/LRNativeButtonManager.swift b/ios/LRNativeButtonManager.swift index e554ea8..81c2f0b 100644 --- a/ios/LRNativeButtonManager.swift +++ b/ios/LRNativeButtonManager.swift @@ -1,73 +1,47 @@ -/** - * RCT view manager and UIView for NativeButton, bridging UIButton with system button configurations. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeButtonManager) class LRNativeButtonManager: RCTViewManager { - + override func view() -> UIView! { return NativeButton() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeButton: UIView { - + private var button: UIButton! - + @objc var title: NSString = "" { didSet { updateButton() } } - + @objc var buttonStyle: NSString = "filled" { didSet { updateButton() } } - + @objc var onPress: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) setupButton() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupButton() } - + private func setupButton() { var configuration = UIButton.Configuration.filled() button = UIButton(configuration: configuration, primaryAction: nil) @@ -77,10 +51,10 @@ class NativeButton: UIView { addSubview(button) updateButton() } - + private func updateButton() { var configuration: UIButton.Configuration - + switch buttonStyle as String { case "filled": configuration = .filled() @@ -99,20 +73,20 @@ class NativeButton: UIView { default: configuration = .filled() } - + configuration.title = title as String button.configuration = configuration } - + @objc private func handlePress() { onPress?([:]) } - + override func layoutSubviews() { super.layoutSubviews() button.frame = self.bounds } - + override var intrinsicContentSize: CGSize { return CGSize(width: UIView.noIntrinsicMetric, height: 44) } diff --git a/ios/LRNativeCardContainerManager.m b/ios/LRNativeCardContainerManager.m index 4ea2f6a..27c4eda 100644 --- a/ios/LRNativeCardContainerManager.m +++ b/ios/LRNativeCardContainerManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeCardContainer properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeCardContainerManager, RCTViewManager) diff --git a/ios/LRNativeCardContainerManager.swift b/ios/LRNativeCardContainerManager.swift index 0bf9443..53f652b 100644 --- a/ios/LRNativeCardContainerManager.swift +++ b/ios/LRNativeCardContainerManager.swift @@ -1,69 +1,46 @@ -/** - * RCT view manager and UIView for NativeCardContainer, a UIView with system background and continuous corner radius. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeCardContainerManager) class LRNativeCardContainerManager: RCTViewManager { - + override func view() -> UIView! { return NativeCardContainer() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeCardContainer: UIView { - + @objc var cornerRadius: CGFloat = 10.0 { didSet { updateAppearance() } } - + override init(frame: CGRect) { super.init(frame: frame) setupView() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupView() } - + private func setupView() { updateAppearance() } - + private func updateAppearance() { + // Use system background color (UIKit decides on light/dark) backgroundColor = .secondarySystemGroupedBackground + + // Use native corner radius layer.cornerRadius = cornerRadius layer.cornerCurve = .continuous layer.masksToBounds = true diff --git a/ios/LRNativeGroupedContainerManager.m b/ios/LRNativeGroupedContainerManager.m index a5b7803..3dda5a9 100644 --- a/ios/LRNativeGroupedContainerManager.m +++ b/ios/LRNativeGroupedContainerManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeGroupedContainer properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeGroupedContainerManager, RCTViewManager) diff --git a/ios/LRNativeGroupedContainerManager.swift b/ios/LRNativeGroupedContainerManager.swift index c0664a3..53fbeba 100644 --- a/ios/LRNativeGroupedContainerManager.swift +++ b/ios/LRNativeGroupedContainerManager.swift @@ -1,67 +1,41 @@ -/** - * RCT view manager and UIView for NativeGroupedContainer, providing system grouped background colors. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeGroupedContainerManager) class LRNativeGroupedContainerManager: RCTViewManager { - + override func view() -> UIView! { return NativeGroupedContainer() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeGroupedContainer: UIView { - + @objc var insetGrouped: Bool = true { didSet { updateBackground() } } - + override init(frame: CGRect) { super.init(frame: frame) setupView() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupView() } - + private func setupView() { updateBackground() } - + private func updateBackground() { if insetGrouped { backgroundColor = .systemGroupedBackground diff --git a/ios/LRNativeMaterialViewManager.m b/ios/LRNativeMaterialViewManager.m index dc2ed98..e2495a1 100644 --- a/ios/LRNativeMaterialViewManager.m +++ b/ios/LRNativeMaterialViewManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeMaterialView properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeMaterialViewManager, RCTViewManager) diff --git a/ios/LRNativeMaterialViewManager.swift b/ios/LRNativeMaterialViewManager.swift index 44e729c..b736d7c 100644 --- a/ios/LRNativeMaterialViewManager.swift +++ b/ios/LRNativeMaterialViewManager.swift @@ -1,41 +1,14 @@ -/** - * RCT view manager and UIView for NativeMaterialView, bridging UIVisualEffectView with system blur materials. - * ⚠️ Currently broken — React Native children do not render correctly inside this view. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeMaterialViewManager) class LRNativeMaterialViewManager: RCTViewManager { - + override func view() -> UIView! { return NativeMaterialView() } - + override static func requiresMainQueueSetup() -> Bool { return true } @@ -43,37 +16,38 @@ class LRNativeMaterialViewManager: RCTViewManager { class NativeMaterialView: UIView { // WARNING: This implementation is currently broken. React Native children do not render correctly. - + private var effectView: UIVisualEffectView! private var contentView: UIView! - + @objc var material: NSString = "systemMaterial" { didSet { updateMaterial() } } - @objc var onPress: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) self.clipsToBounds = true setupView() } - + required init?(coder: NSCoder) { super.init(coder: coder) self.clipsToBounds = true setupView() } - + private func setupView() { + // Create blur effect view at the back let blurEffect = getBlurEffect(for: material as String) effectView = UIVisualEffectView(effect: blurEffect) effectView.frame = bounds effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] effectView.isUserInteractionEnabled = false addSubview(effectView) + // Create a content view for React Native children contentView = UIView() contentView.frame = bounds contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] @@ -95,15 +69,15 @@ class NativeMaterialView: UIView { override func didUpdateReactSubviews() { contentView.setNeedsLayout() } - + private func updateMaterial() { let blurEffect = getBlurEffect(for: material as String) effectView.effect = blurEffect } - + private func getBlurEffect(for material: String) -> UIBlurEffect { let style: UIBlurEffect.Style - + switch material { case "systemUltraThinMaterial": style = .systemUltraThinMaterial @@ -138,14 +112,14 @@ class NativeMaterialView: UIView { default: style = .systemMaterial } - + return UIBlurEffect(style: style) } - + @objc private func handleTap() { onPress?([:]) } - + override func layoutSubviews() { super.layoutSubviews() effectView.frame = bounds diff --git a/ios/LRNativeMenuButtonManager.m b/ios/LRNativeMenuButtonManager.m index c8672f5..0b94409 100644 --- a/ios/LRNativeMenuButtonManager.m +++ b/ios/LRNativeMenuButtonManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeMenuButton properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeMenuButtonManager, RCTViewManager) diff --git a/ios/LRNativeMenuButtonManager.swift b/ios/LRNativeMenuButtonManager.swift index 13567e6..6106c1d 100644 --- a/ios/LRNativeMenuButtonManager.swift +++ b/ios/LRNativeMenuButtonManager.swift @@ -1,29 +1,3 @@ -/** - * RCT view manager and UIView for NativeMenuButton, a standalone UIButton that shows a UIMenu on press. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React diff --git a/ios/LRNativeNavigationBarManager.m b/ios/LRNativeNavigationBarManager.m index 3c08f46..c2785ef 100644 --- a/ios/LRNativeNavigationBarManager.m +++ b/ios/LRNativeNavigationBarManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeNavigationBar properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeNavigationBarManager, RCTViewManager) diff --git a/ios/LRNativeNavigationBarManager.swift b/ios/LRNativeNavigationBarManager.swift index 5326bc6..0c11f0b 100644 --- a/ios/LRNativeNavigationBarManager.swift +++ b/ios/LRNativeNavigationBarManager.swift @@ -1,78 +1,52 @@ -/** - * RCT view manager and UIView for NativeNavigationBar, bridging UINavigationBar. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeNavigationBarManager) class LRNativeNavigationBarManager: RCTViewManager { - + override func view() -> UIView! { return NativeNavigationBar() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeNavigationBar: UIView { - + private var navigationBar: UINavigationBar! private var navigationItem: UINavigationItem! - + @objc var title: NSString = "" { didSet { navigationItem.title = title as String } } - + @objc var barTintColor: UIColor? { didSet { updateAppearance() } } - + @objc var translucent: Bool = true { didSet { navigationBar.isTranslucent = translucent } } - + override init(frame: CGRect) { super.init(frame: frame) setupNavigationBar() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupNavigationBar() } - + private func setupNavigationBar() { navigationBar = UINavigationBar() navigationItem = UINavigationItem() @@ -81,21 +55,21 @@ class NativeNavigationBar: UIView { addSubview(navigationBar) updateAppearance() } - + private func updateAppearance() { let appearance = UINavigationBarAppearance() - + if let color = barTintColor { appearance.backgroundColor = color } else { appearance.configureWithDefaultBackground() } - + navigationBar.standardAppearance = appearance navigationBar.scrollEdgeAppearance = appearance navigationBar.compactAppearance = appearance } - + override func layoutSubviews() { super.layoutSubviews() navigationBar.frame = bounds diff --git a/ios/LRNativeSearchBarManager.m b/ios/LRNativeSearchBarManager.m index 6cd4a95..34b5fde 100644 --- a/ios/LRNativeSearchBarManager.m +++ b/ios/LRNativeSearchBarManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeSearchBar properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeSearchBarManager, RCTViewManager) diff --git a/ios/LRNativeSearchBarManager.swift b/ios/LRNativeSearchBarManager.swift index 782a1d3..1f4b83e 100644 --- a/ios/LRNativeSearchBarManager.swift +++ b/ios/LRNativeSearchBarManager.swift @@ -1,55 +1,29 @@ -/** - * RCT view manager and UIView for NativeSearchBar, bridging UISearchBar. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeSearchBarManager) class LRNativeSearchBarManager: RCTViewManager { - + override func view() -> UIView! { return NativeSearchBar() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeSearchBar: UIView, UISearchBarDelegate { - + private var searchBar: UISearchBar! - + @objc var placeholder: NSString = "" { didSet { searchBar.placeholder = placeholder as String } } - + @objc var text: NSString = "" { didSet { if searchBar.text != text as String { @@ -57,23 +31,23 @@ class NativeSearchBar: UIView, UISearchBarDelegate { } } } - + @objc var onTextChanged: RCTDirectEventBlock? @objc var onSearchPressed: RCTDirectEventBlock? @objc var onCancelPressed: RCTDirectEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) setupSearchBar() backgroundColor = .clear } - + required init?(coder: NSCoder) { super.init(coder: coder) setupSearchBar() backgroundColor = .clear } - + private func setupSearchBar() { searchBar = UISearchBar() searchBar.delegate = self @@ -82,24 +56,24 @@ class NativeSearchBar: UIView, UISearchBarDelegate { searchBar.backgroundImage = UIImage() addSubview(searchBar) } - + // MARK: - UISearchBarDelegate - + func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { onTextChanged?(["text": searchText]) } - + func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() onSearchPressed?(["text": searchBar.text ?? ""]) } - + func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() searchBar.text = "" onCancelPressed?([:]) } - + override func layoutSubviews() { super.layoutSubviews() searchBar.frame = bounds diff --git a/ios/LRNativeSegmentedControlManager.m b/ios/LRNativeSegmentedControlManager.m index f834000..abc9928 100644 --- a/ios/LRNativeSegmentedControlManager.m +++ b/ios/LRNativeSegmentedControlManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeSegmentedControl properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeSegmentedControlManager, RCTViewManager) diff --git a/ios/LRNativeSegmentedControlView.swift b/ios/LRNativeSegmentedControlView.swift index 3770d47..910c1df 100644 --- a/ios/LRNativeSegmentedControlView.swift +++ b/ios/LRNativeSegmentedControlView.swift @@ -1,30 +1,3 @@ -/** - * RCT view manager and UIView for NativeSegmentedControl, bridging UISegmentedControl. - * ⚠️ Currently broken — liquid glass selection rendering is unreliable when bridged into React Native. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @@ -43,7 +16,7 @@ class NativeSegmentedControlView: UIView { // WARNING: This implementation is currently broken. UIKit liquid glass rendering is not reliable in React Native context. private let materialView = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterial)) private let segmentedControl = UISegmentedControl() - + @objc var segments: NSArray = [] { didSet { updateSegments() @@ -59,7 +32,7 @@ class NativeSegmentedControlView: UIView { } } @objc var onValueChange: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) self.backgroundColor = .clear @@ -73,7 +46,7 @@ class NativeSegmentedControlView: UIView { segmentedControl.selectedSegmentTintColor = nil } required init?(coder: NSCoder) { fatalError() } - + private func updateSegments() { segmentedControl.removeAllSegments() for (index, segment) in segments.enumerated() { diff --git a/ios/LRNativeStackViewManager.m b/ios/LRNativeStackViewManager.m index 713d360..7d57737 100644 --- a/ios/LRNativeStackViewManager.m +++ b/ios/LRNativeStackViewManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeStackView properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeStackViewManager, RCTViewManager) diff --git a/ios/LRNativeStackViewManager.swift b/ios/LRNativeStackViewManager.swift index 801eeeb..b42c672 100644 --- a/ios/LRNativeStackViewManager.swift +++ b/ios/LRNativeStackViewManager.swift @@ -1,87 +1,61 @@ -/** - * RCT view manager and UIView for NativeStackView, bridging UIStackView for axis-based child layout. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeStackViewManager) class LRNativeStackViewManager: RCTViewManager { - + override func view() -> UIView! { return NativeStackView() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeStackView: UIView { - + private var stackView: UIStackView! - + @objc var axis: NSString = "vertical" { didSet { updateAxis() } } - + @objc var spacing: NSNumber = 8 { didSet { stackView.spacing = CGFloat(truncating: spacing) } } - + @objc var alignment: NSString = "fill" { didSet { updateAlignment() } } - + @objc var distribution: NSString = "fill" { didSet { updateDistribution() } } - + override init(frame: CGRect) { super.init(frame: frame) self.backgroundColor = .clear self.clipsToBounds = false setupStackView() } - + required init?(coder: NSCoder) { super.init(coder: coder) self.backgroundColor = .clear self.clipsToBounds = false setupStackView() } - + private func setupStackView() { stackView = UIStackView() stackView.translatesAutoresizingMaskIntoConstraints = false @@ -90,7 +64,7 @@ class NativeStackView: UIView { stackView.alignment = .fill stackView.distribution = .fill addSubview(stackView) - + NSLayoutConstraint.activate([ stackView.topAnchor.constraint(equalTo: topAnchor), stackView.leadingAnchor.constraint(equalTo: leadingAnchor), @@ -98,11 +72,11 @@ class NativeStackView: UIView { stackView.bottomAnchor.constraint(equalTo: bottomAnchor) ]) } - + private func updateAxis() { stackView.axis = (axis as String) == "horizontal" ? .horizontal : .vertical } - + private func updateAlignment() { switch alignment as String { case "leading": @@ -121,7 +95,7 @@ class NativeStackView: UIView { stackView.alignment = .fill } } - + private func updateDistribution() { switch distribution as String { case "fill": @@ -138,7 +112,7 @@ class NativeStackView: UIView { stackView.distribution = .fill } } - + override func insertReactSubview(_ subview: UIView!, at atIndex: Int) { if atIndex >= stackView.arrangedSubviews.count { stackView.addArrangedSubview(subview) @@ -149,26 +123,27 @@ class NativeStackView: UIView { setNeedsLayout() layoutIfNeeded() } - + override func removeReactSubview(_ subview: UIView!) { stackView.removeArrangedSubview(subview) subview.removeFromSuperview() invalidateIntrinsicContentSize() setNeedsLayout() } - + override func didUpdateReactSubviews() { super.didUpdateReactSubviews() invalidateIntrinsicContentSize() setNeedsLayout() layoutIfNeeded() } - + override var intrinsicContentSize: CGSize { + // Calculate total height from all arranged subviews let height = stackView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height return CGSize(width: UIView.noIntrinsicMetric, height: height) } - + override func layoutSubviews() { super.layoutSubviews() invalidateIntrinsicContentSize() diff --git a/ios/LRNativeSwitchManager.m b/ios/LRNativeSwitchManager.m index f4ecf0f..9c9a75c 100644 --- a/ios/LRNativeSwitchManager.m +++ b/ios/LRNativeSwitchManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeSwitch properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeSwitchManager, RCTViewManager) diff --git a/ios/LRNativeSwitchManager.swift b/ios/LRNativeSwitchManager.swift index 071fa88..5f62f00 100644 --- a/ios/LRNativeSwitchManager.swift +++ b/ios/LRNativeSwitchManager.swift @@ -1,49 +1,23 @@ -/** - * RCT view manager and UIView for NativeSwitch, bridging UISwitch. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeSwitchManager) class LRNativeSwitchManager: RCTViewManager { - + override func view() -> UIView! { return NativeSwitch() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeSwitch: UIView { - + private var switchControl: UISwitch! - + @objc var value: Bool = false { didSet { if switchControl.isOn != value { @@ -51,50 +25,51 @@ class NativeSwitch: UIView { } } } - + @objc var onTintColor: UIColor? { didSet { switchControl.onTintColor = onTintColor } } - + @objc var thumbTintColor: UIColor? { didSet { switchControl.thumbTintColor = thumbTintColor } } - + @objc var disabled: Bool = false { didSet { switchControl.isEnabled = !disabled } } - + @objc var onValueChange: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) setupSwitch() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupSwitch() } - + private func setupSwitch() { switchControl = UISwitch() switchControl.addTarget(self, action: #selector(handleValueChange), for: .valueChanged) autoresizingMask = [.flexibleWidth, .flexibleHeight] addSubview(switchControl) } - + @objc private func handleValueChange() { onValueChange?(["value": switchControl.isOn]) } - + override func layoutSubviews() { super.layoutSubviews() + // Center the switch within this view's bounds let switchSize = switchControl.intrinsicContentSize switchControl.frame = CGRect( x: (bounds.width - switchSize.width) / 2, @@ -103,7 +78,7 @@ class NativeSwitch: UIView { height: switchSize.height ) } - + override var intrinsicContentSize: CGSize { return switchControl.intrinsicContentSize } diff --git a/ios/LRNativeTabBarManager.m b/ios/LRNativeTabBarManager.m index 929137b..a16dbf4 100644 --- a/ios/LRNativeTabBarManager.m +++ b/ios/LRNativeTabBarManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeTabBar properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeTabBarManager, RCTViewManager) diff --git a/ios/LRNativeTabBarManager.swift b/ios/LRNativeTabBarManager.swift index 63c6f38..d11f392 100644 --- a/ios/LRNativeTabBarManager.swift +++ b/ios/LRNativeTabBarManager.swift @@ -1,40 +1,14 @@ -/** - * RCT view manager and UIView for NativeTabBar, bridging UITabBar. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeTabBarManager) class LRNativeTabBarManager: RCTViewManager { - + override func view() -> UIView! { return NativeTabBar() } - + override static func requiresMainQueueSetup() -> Bool { return true } @@ -47,15 +21,15 @@ class NativeTabBar: UIView { let height = barHeight?.doubleValue ?? 49.0 return CGSize(width: UIView.noIntrinsicMetric, height: CGFloat(height)) } - + private var tabBar: UITabBar! - + @objc var items: NSArray = [] { didSet { updateItems() } } - + @objc var selectedIndex: NSInteger = 0 { didSet { if let items = tabBar.items, selectedIndex >= 0 && selectedIndex < items.count { @@ -63,67 +37,67 @@ class NativeTabBar: UIView { } } } - + @objc var translucent: Bool = true { didSet { tabBar.isTranslucent = translucent } } - + @objc var onTabPress: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) setupTabBar() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupTabBar() } - + private func setupTabBar() { tabBar = UITabBar() tabBar.isTranslucent = true tabBar.delegate = self addSubview(tabBar) } - + private func updateItems() { var tabBarItems: [UITabBarItem] = [] - + for item in items { if let itemDict = item as? [String: Any], let title = itemDict["title"] as? String { - + let tabBarItem = UITabBarItem() tabBarItem.title = title - + if let systemItem = itemDict["systemItem"] as? String { if let systemTabBarItem = getSystemTabBarItem(systemItem) { tabBarItems.append(systemTabBarItem) continue } } - + if let iconName = itemDict["icon"] as? String { tabBarItem.image = UIImage(systemName: iconName) } - + tabBarItems.append(tabBarItem) } } - + tabBar.items = tabBarItems - + if selectedIndex >= 0 && selectedIndex < tabBarItems.count { tabBar.selectedItem = tabBarItems[selectedIndex] } } - + private func getSystemTabBarItem(_ systemItem: String) -> UITabBarItem? { let type: UITabBarItem.SystemItem - + switch systemItem { case "more": type = .more @@ -152,10 +126,10 @@ class NativeTabBar: UIView { default: return nil } - + return UITabBarItem(tabBarSystemItem: type, tag: 0) } - + override func layoutSubviews() { super.layoutSubviews() let height = barHeight?.doubleValue ?? Double(bounds.height) diff --git a/ios/LRNativeToolbarButtonManager.m b/ios/LRNativeToolbarButtonManager.m index 552733e..53b4362 100644 --- a/ios/LRNativeToolbarButtonManager.m +++ b/ios/LRNativeToolbarButtonManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeToolbarButton properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeToolbarButtonManager, RCTViewManager) diff --git a/ios/LRNativeToolbarButtonManager.swift b/ios/LRNativeToolbarButtonManager.swift index cad167b..3facf60 100644 --- a/ios/LRNativeToolbarButtonManager.swift +++ b/ios/LRNativeToolbarButtonManager.swift @@ -1,77 +1,50 @@ -/** - * RCT view manager and UIView for NativeToolbarButton, bridging UIBarButtonItem. - * Must be used as a direct child of NativeToolbar. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeToolbarButtonManager) class LRNativeToolbarButtonManager: RCTViewManager { - + override func view() -> UIView! { return NativeToolbarButtonContainer() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeToolbarButtonContainer: UIView { - + private(set) var barButtonItem: UIBarButtonItem! weak var parentToolbar: NativeToolbar? - + @objc var icon: NSString = "" { didSet { updateButton() } } - + @objc var title: NSString = "" { didSet { updateButton() } } - + @objc var systemItem: NSString = "" { didSet { updateButton() } } - + @objc var disabled: Bool = false { didSet { barButtonItem.isEnabled = !disabled } } - + @objc var onPress: RCTBubblingEventBlock? - + override init(frame: CGRect) { super.init(frame: frame) setupButton() @@ -82,19 +55,19 @@ class NativeToolbarButtonContainer: UIView { self.alpha = 0 self.isUserInteractionEnabled = false } - + required init?(coder: NSCoder) { super.init(coder: coder) setupButton() } - + private func setupButton() { barButtonItem = UIBarButtonItem() barButtonItem.target = self barButtonItem.action = #selector(handlePress) updateButton() } - + private func updateButton() { if systemItem.length > 0 { if let item = createSystemItem(systemItem as String) { @@ -109,19 +82,21 @@ class NativeToolbarButtonContainer: UIView { barButtonItem.title = title as String barButtonItem.image = nil } - + barButtonItem.isEnabled = !disabled } - + private func createSystemItem(_ systemItem: String) -> UIBarButtonItem? { let type: UIBarButtonItem.SystemItem - + switch systemItem { case "done": type = .done case "cancel": type = .cancel case "edit": type = .edit case "save": type = .save case "add": type = .add + case "flexibleSpace": type = .flexibleSpace + case "fixedSpace": type = .fixedSpace case "compose": type = .compose case "reply": type = .reply case "action": type = .action @@ -141,10 +116,10 @@ class NativeToolbarButtonContainer: UIView { case "close": type = .close default: return nil } - + return UIBarButtonItem(barButtonSystemItem: type, target: self, action: #selector(handlePress)) } - + @objc private func handlePress() { let data: [String: Any] = ["icon": icon as String, "title": title as String] // Dispatch through parent toolbar (visible view) so RN receives the event diff --git a/ios/LRNativeToolbarManager.m b/ios/LRNativeToolbarManager.m index 426c805..e909361 100644 --- a/ios/LRNativeToolbarManager.m +++ b/ios/LRNativeToolbarManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeToolbar properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeToolbarManager, RCTViewManager) diff --git a/ios/LRNativeToolbarManager.swift b/ios/LRNativeToolbarManager.swift index 9330fb9..36d2742 100644 --- a/ios/LRNativeToolbarManager.swift +++ b/ios/LRNativeToolbarManager.swift @@ -1,92 +1,65 @@ -/** - * RCT view manager and UIView for NativeToolbar, bridging UIToolbar. - * Accepts NativeToolbarButton and NativeToolbarMenu as React children. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeToolbarManager) class LRNativeToolbarManager: RCTViewManager { - + override func view() -> UIView! { return NativeToolbar() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeToolbar: UIView { - + private var toolbar: UIToolbar! private var buttonContainers: [NativeToolbarButtonContainer] = [] private var menuContainers: [NativeToolbarMenuContainer] = [] - + // Event blocks dispatched from the toolbar (visible view) so RN receives them @objc var onToolbarButtonPress: RCTDirectEventBlock? @objc var onToolbarMenuAction: RCTDirectEventBlock? - + @objc var translucent: Bool = true { didSet { toolbar.isTranslucent = translucent } } - + override init(frame: CGRect) { super.init(frame: frame) setupToolbar() } - + required init?(coder: NSCoder) { super.init(coder: coder) setupToolbar() } - + private func setupToolbar() { toolbar = UIToolbar() toolbar.isTranslucent = true addSubview(toolbar) } - + override func insertReactSubview(_ subview: UIView!, at atIndex: Int) { if let buttonContainer = subview as? NativeToolbarButtonContainer { - // routes events through the toolbar so RN receives them from the visible view + // Wire the button to call our onButtonPress instead of its own buttonContainer.parentToolbar = self buttonContainers.append(buttonContainer) updateToolbarItems() } else if let menuContainer = subview as? NativeToolbarMenuContainer { - // routes events through the toolbar so RN receives them from the visible view + // Wire the menu to call our onMenuAction instead of its own menuContainer.parentToolbar = self menuContainers.append(menuContainer) updateToolbarItems() } } - + override func removeReactSubview(_ subview: UIView!) { if let buttonContainer = subview as? NativeToolbarButtonContainer { if let index = buttonContainers.firstIndex(of: buttonContainer) { @@ -100,33 +73,35 @@ class NativeToolbar: UIView { } } } - + + // Called by child NativeToolbarButtonContainer func dispatchButtonPress(_ data: [String: Any]) { DispatchQueue.main.async { [weak self] in self?.onToolbarButtonPress?(data) } } - + + // Called by child NativeToolbarMenuContainer func dispatchMenuAction(_ data: [String: Any]) { DispatchQueue.main.async { [weak self] in self?.onToolbarMenuAction?(data) } } - + private func updateToolbarItems() { var barButtonItems: [UIBarButtonItem] = [] - + for container in buttonContainers { barButtonItems.append(container.barButtonItem) } - + for container in menuContainers { barButtonItems.append(container.barButtonItem) } - + toolbar.items = barButtonItems } - + override func layoutSubviews() { super.layoutSubviews() toolbar.frame = bounds diff --git a/ios/LRNativeToolbarMenuManager.m b/ios/LRNativeToolbarMenuManager.m index 602985b..426d797 100644 --- a/ios/LRNativeToolbarMenuManager.m +++ b/ios/LRNativeToolbarMenuManager.m @@ -1,29 +1,3 @@ -/** - * Exports NativeToolbarMenu properties to the React Native bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LRNativeToolbarMenuManager, RCTViewManager) diff --git a/ios/LRNativeToolbarMenuManager.swift b/ios/LRNativeToolbarMenuManager.swift index a434741..3edff96 100644 --- a/ios/LRNativeToolbarMenuManager.swift +++ b/ios/LRNativeToolbarMenuManager.swift @@ -1,77 +1,50 @@ -/** - * RCT view manager and UIView for NativeToolbarMenu, bridging UIBarButtonItem with UIMenu. - * Must be used as a direct child of NativeToolbar. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import UIKit import React @objc(LRNativeToolbarMenuManager) class LRNativeToolbarMenuManager: RCTViewManager { - + override func view() -> UIView! { return NativeToolbarMenuContainer() } - + override static func requiresMainQueueSetup() -> Bool { return true } } class NativeToolbarMenuContainer: UIView { - + private(set) var barButtonItem: UIBarButtonItem! - + @objc var icon: NSString = "ellipsis" { didSet { updateButton() } } - + @objc var title: NSString = "" { didSet { updateButton() } } - + @objc var menuItems: NSArray = [] { didSet { updateMenu() } } - + @objc var disabled: Bool = false { didSet { barButtonItem.isEnabled = !disabled } } - + @objc var onMenuAction: RCTDirectEventBlock? weak var parentToolbar: NativeToolbar? - + override init(frame: CGRect) { super.init(frame: frame) setupButton() @@ -82,18 +55,18 @@ class NativeToolbarMenuContainer: UIView { self.alpha = 0 self.isUserInteractionEnabled = false } - + required init?(coder: NSCoder) { super.init(coder: coder) setupButton() } - + private func setupButton() { let image = UIImage(systemName: "ellipsis") barButtonItem = UIBarButtonItem(image: image, menu: nil) updateButton() } - + private func updateButton() { if icon.length > 0 { barButtonItem.image = UIImage(systemName: icon as String) @@ -103,30 +76,33 @@ class NativeToolbarMenuContainer: UIView { } barButtonItem.isEnabled = !disabled } - + private func updateMenu() { - let menuElements = buildMenuElements(from: menuItems as! [[String: Any]]) + guard let items = menuItems as? [[String: Any]] else { return } + let menuElements = buildMenuElements(from: items) let menu = UIMenu(children: menuElements) barButtonItem.menu = menu } - + private func buildMenuElements(from items: [[String: Any]]) -> [UIMenuElement] { var elements: [UIMenuElement] = [] - + for item in items { if let children = item["children"] as? [[String: Any]], !children.isEmpty { + // This is a submenu let title = item["title"] as? String ?? "" let image = (item["icon"] as? String).flatMap { UIImage(systemName: $0) } let submenuElements = buildMenuElements(from: children) let submenu = UIMenu(title: title, image: image, children: submenuElements) elements.append(submenu) } else { + // This is a regular action let title = item["title"] as? String ?? "" let image = (item["icon"] as? String).flatMap { UIImage(systemName: $0) } let actionId = item["id"] as? String ?? title let isDestructive = item["destructive"] as? Bool ?? false let isDisabled = item["disabled"] as? Bool ?? false - + var attributes: UIMenuElement.Attributes = [] if isDestructive { attributes.insert(.destructive) @@ -134,7 +110,7 @@ class NativeToolbarMenuContainer: UIView { if isDisabled { attributes.insert(.disabled) } - + let action = UIAction(title: title, image: image, attributes: attributes) { [weak self] _ in let data: [String: Any] = ["id": actionId, "title": title] // Dispatch through parent toolbar (visible view) so RN receives the event @@ -147,7 +123,7 @@ class NativeToolbarMenuContainer: UIView { elements.append(action) } } - + return elements } } diff --git a/ios/LiquidReact-Bridging-Header.h b/ios/LiquidReact-Bridging-Header.h index 4354a18..b2d277e 100644 --- a/ios/LiquidReact-Bridging-Header.h +++ b/ios/LiquidReact-Bridging-Header.h @@ -1,29 +1,9 @@ -/** - * Bridging header that imports React Native's Obj-C headers into Swift. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// +// LiquidReact-Bridging-Header.h +// liquid-react +// +// React Native bridging header for Swift modules +// #import #import diff --git a/ios/LiquidReactModule.m b/ios/LiquidReactModule.m index 38ebd49..dd9a2c1 100644 --- a/ios/LiquidReactModule.m +++ b/ios/LiquidReactModule.m @@ -1,29 +1,3 @@ -/** - * Exposes the LiquidReact module to the React Native Obj-C bridge. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #import @interface RCT_EXTERN_MODULE(LiquidReact, NSObject) diff --git a/ios/LiquidReactModule.swift b/ios/LiquidReactModule.swift index d0c807f..40c413d 100644 --- a/ios/LiquidReactModule.swift +++ b/ios/LiquidReactModule.swift @@ -1,29 +1,3 @@ -/** - * Entry point for the LiquidReact React Native module. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import Foundation import React diff --git a/liquid-react.podspec b/liquid-react.podspec index 91ef0bc..1bada24 100644 --- a/liquid-react.podspec +++ b/liquid-react.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.homepage = package['repository']['url'] s.license = package['license'] s.author = package['author'] - s.platform = :ios, "13.0" + s.platform = :ios, "15.0" s.source = { :git => package['repository']['url'], :tag => "v#{s.version}" } s.source_files = "ios/**/*.{h,m,swift}" s.requires_arc = true diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index f47ce29..0000000 --- a/package-lock.json +++ /dev/null @@ -1,5231 +0,0 @@ -{ - "name": "liquid-react", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "liquid-react", - "version": "1.0.0", - "license": "MIT", - "devDependencies": { - "@types/react": "^18.0.0", - "@types/react-native": "^0.73.0", - "@typescript-eslint/eslint-plugin": "^7.0.0", - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0", - "prettier": "^3.2.0", - "typescript": "^5.0.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-native": ">=0.65.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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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/traverse--for-generate-function-map": { - "name": "@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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/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/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.84.0.tgz", - "integrity": "sha512-YiU9h1IN0pvvZsHbd03MaD7mE2q+ySaKMlE9tWK+3iiwtbEaMQOsMUuSJ1er2LU6ERMWfhfvCYgWpKRGOMeN8A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20.19.4" - } - }, - "node_modules/@react-native/codegen": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.84.0.tgz", - "integrity": "sha512-TcTAO58JigCw9onYTrbE2yK2js5YNgqbmnpYyq9oXz2mofbX7JcK53kIi7fhqyJhie8RkY+X85zSOTWNs6S3CA==", - "dev": true, - "license": "MIT", - "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.0", - "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.84.0.tgz", - "integrity": "sha512-uYoLBHnAzod4E5dA5rPPQeny2A5RD0PiIJQ4r+2F7cvA+5bZ8+znxw4TdaSiEk8uhN+clffI4d2bl9V4+xEK+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@react-native/dev-middleware": "0.84.0", - "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.0", - "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.84.0.tgz", - "integrity": "sha512-n7JKYVDCbA2aj8/5/OD1IK7nuiAYj5l/Z6yhGf7GG4EGaeQdthqdb0LZbseaRPyZK/7tLfdnLdqlqdTQC6/UTQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 20.19.4" - } - }, - "node_modules/@react-native/debugger-shell": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.84.0.tgz", - "integrity": "sha512-5t/NvQLYk/d0kWlGOMNobkjfimqBc+/LYRmSOkgKm+pyOhxjygCLSnRjAUkeRALSZ8h6MKGTz1Wc4pbmJr7T0Q==", - "dev": true, - "license": "MIT", - "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.0", - "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.84.0.tgz", - "integrity": "sha512-c0o7YW39AUI1FSLV/TFSszr87kQGmaePAQK0ygIRnwZ2fAGDnQ5Iu/tk3u9O5lVH6nTjfAwTKJ3El9YeEWDeEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.84.0", - "@react-native/debugger-shell": "0.84.0", - "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.0", - "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.84.0.tgz", - "integrity": "sha512-j8g/I4Z+SAdh2NXOVng4rmfYgPoeJBZwAKoGPpSe/wB/9XDLh9IRGUTg8dGS5BWUy2471xBUoGZPwHb6QMJmVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20.19.4" - } - }, - "node_modules/@react-native/js-polyfills": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.84.0.tgz", - "integrity": "sha512-xaxmzYWLgHH+2uAZQ0owEkDE58hOTWmuBKD/Gl+cDFD3mFfSK4lZpin/3hiXtE5LB4BwgqICsPN07zCAqx6Fpg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20.19.4" - } - }, - "node_modules/@react-native/normalize-colors": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.84.0.tgz", - "integrity": "sha512-7JgZyWtQ9Sz4qZvCTsURUtuv8/niEZ/iCorp7eExc3GgpBWNazPumieiUoWPdgRKofU0Bqpr2/dJevEn2hrlwA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@react-native/virtualized-lists": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.84.0.tgz", - "integrity": "sha512-ugwSj0Gb4MYrcm8uQrQw8qHPx5RKGDLuZRAP/AuwneFizHx8YCLBEFbOYRGWgxHBRtkJ70D1o+jpIx3CK3p5lw==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "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==", - "dev": true, - "license": "BSD-3-Clause", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/node": { - "version": "25.2.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", - "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", - "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-native": { - "version": "0.73.0", - "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.73.0.tgz", - "integrity": "sha512-6ZRPQrYM72qYKGWidEttRe6M5DZBEV5F+MHMHqd4TTYx0tfkcdrUFGdef6CCxY0jXU7wldvd/zA/b0A/kTeJmA==", - "deprecated": "This is a stub types definition. react-native provides its own type definitions, so you do not need this installed.", - "dev": true, - "license": "MIT", - "dependencies": { - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", - "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/type-utils": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", - "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", - "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", - "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", - "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", - "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/anser": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", - "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", - "dev": true, - "license": "MIT" - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "BSD-3-Clause", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "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/baseline-browser-mapping": { - "version": "2.9.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", - "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "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==", - "dev": true, - "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", - "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==", - "dev": true, - "license": "Apache-2.0", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001769", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", - "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", - "dev": true, - "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" - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "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/chrome-launcher": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", - "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", - "dev": true, - "license": "Apache-2.0", - "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==", - "dev": true, - "license": "Apache-2.0", - "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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "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==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "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==", - "dev": 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==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "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/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.286", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", - "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", - "dev": true, - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/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/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/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/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "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-glob/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/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==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "(MIT OR Apache-2.0)", - "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==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "MIT", - "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", - "dev": true, - "license": "ISC", - "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": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globals/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hermes-compiler": { - "version": "250829098.0.7", - "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.7.tgz", - "integrity": "sha512-8QOmg1VjAWv8poFVslJDY8qkvjTy/UiO3R/hyGoC0IAchLzBdS9/TmAvI9cN1F3yLTEjimAIQQtUslpBMPXVVg==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/hermes-parser": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz", - "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "hermes-estree": "0.32.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "queue": "6.0.2" - }, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=16.x" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "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.", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-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==", - "dev": true, - "license": "BSD-3-Clause", - "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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "0BSD" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "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==", - "dev": true, - "license": "Apache-2.0", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "BSD-3-Clause", - "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==", - "dev": true, - "license": "Apache-2.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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT" - }, - "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.3", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.3.tgz", - "integrity": "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.3", - "@babel/types": "^7.25.2", - "accepts": "^1.3.7", - "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.32.0", - "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.3", - "metro-cache": "0.83.3", - "metro-cache-key": "0.83.3", - "metro-config": "0.83.3", - "metro-core": "0.83.3", - "metro-file-map": "0.83.3", - "metro-resolver": "0.83.3", - "metro-runtime": "0.83.3", - "metro-source-map": "0.83.3", - "metro-symbolicate": "0.83.3", - "metro-transform-plugins": "0.83.3", - "metro-transform-worker": "0.83.3", - "mime-types": "^2.1.27", - "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.3", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.3.tgz", - "integrity": "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "hermes-parser": "0.32.0", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/metro-cache": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.3.tgz", - "integrity": "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "exponential-backoff": "^3.1.1", - "flow-enums-runtime": "^0.0.6", - "https-proxy-agent": "^7.0.5", - "metro-core": "0.83.3" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/metro-cache-key": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.3.tgz", - "integrity": "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/metro-config": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.3.tgz", - "integrity": "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA==", - "dev": true, - "license": "MIT", - "dependencies": { - "connect": "^3.6.5", - "flow-enums-runtime": "^0.0.6", - "jest-validate": "^29.7.0", - "metro": "0.83.3", - "metro-cache": "0.83.3", - "metro-core": "0.83.3", - "metro-runtime": "0.83.3", - "yaml": "^2.6.1" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/metro-core": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.3.tgz", - "integrity": "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "lodash.throttle": "^4.1.1", - "metro-resolver": "0.83.3" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/metro-file-map": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.3.tgz", - "integrity": "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA==", - "dev": true, - "license": "MIT", - "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.3", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.3.tgz", - "integrity": "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "terser": "^5.15.0" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/metro-resolver": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.3.tgz", - "integrity": "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/metro-runtime": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.3.tgz", - "integrity": "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw==", - "dev": true, - "license": "MIT", - "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.3", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.3.tgz", - "integrity": "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.3", - "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", - "@babel/types": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-symbolicate": "0.83.3", - "nullthrows": "^1.1.1", - "ob1": "0.83.3", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/metro-symbolicate": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.3.tgz", - "integrity": "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-source-map": "0.83.3", - "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.3", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.3.tgz", - "integrity": "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.3", - "flow-enums-runtime": "^0.0.6", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/metro-transform-worker": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.3.tgz", - "integrity": "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/types": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "metro": "0.83.3", - "metro-babel-transformer": "0.83.3", - "metro-cache": "0.83.3", - "metro-cache-key": "0.83.3", - "metro-minify-terser": "0.83.3", - "metro-source-map": "0.83.3", - "metro-transform-plugins": "0.83.3", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/ob1": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.3.tgz", - "integrity": "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/react-native": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.84.0.tgz", - "integrity": "sha512-CcBfucLDHz8MAjQx9kFXasYtpcn8zP1YapUgGtAy0psRZTLShwF9yeh5+ErSgEK2gXV1CCSz7hqCZqx1eMyBLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/create-cache-key-function": "^29.7.0", - "@react-native/assets-registry": "0.84.0", - "@react-native/codegen": "0.84.0", - "@react-native/community-cli-plugin": "0.84.0", - "@react-native/gradle-plugin": "0.84.0", - "@react-native/js-polyfills": "0.84.0", - "@react-native/normalize-colors": "0.84.0", - "@react-native/virtualized-lists": "0.84.0", - "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.7", - "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-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "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", - "dev": true, - "license": "ISC", - "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/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==", - "dev": true, - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/send/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "ISC" - }, - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "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==", - "dev": true, - "license": "BSD-3-Clause", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/terser": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", - "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", - "dev": true, - "license": "BSD-2-Clause", - "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==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "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/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "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.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "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", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, - "license": "ISC", - "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==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/package.json b/package.json index 8a27433..81e8866 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,7 @@ "types": "dist/index.d.ts", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "lint": "eslint . --ext .js,.jsx,.ts,.tsx", - "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx}\"", - "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx}\"", - "typecheck": "tsc --noEmit", - "build": "tsc" - }, - "engines": { - "node": ">=20.0.0" + "lint": "eslint . --ext .js,.jsx,.ts,.tsx" }, "keywords": [ "react-native", @@ -37,10 +30,6 @@ "devDependencies": { "@types/react": "^18.0.0", "@types/react-native": "^0.73.0", - "@typescript-eslint/eslint-plugin": "^7.0.0", - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0", - "prettier": "^3.2.0", "typescript": "^5.0.0" }, "files": [ diff --git a/readTheDocs.yml b/readTheDocs.yml deleted file mode 100644 index 1d7dfd2..0000000 --- a/readTheDocs.yml +++ /dev/null @@ -1 +0,0 @@ -# why? \ No newline at end of file diff --git a/src/components.tsx b/src/components.tsx index b4b8725..0e0a7f1 100644 --- a/src/components.tsx +++ b/src/components.tsx @@ -1,30 +1,3 @@ -/** - * React component wrappers around native UIKit bridges. - * Each component applies default sizing and passes props to the native layer. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ import React from 'react'; import { StyleSheet } from 'react-native'; import { @@ -60,74 +33,134 @@ import type { NativeMenuButtonProps, } from './types'; -/** Wraps UIVisualEffectView with system blur materials. ⚠️ Currently broken — RN children don't render inside it. */ +/** + * NativeMaterialView - Exposes UIVisualEffectView with system materials + * + * Uses Apple's blur, vibrancy, and depth rendering pipeline. + * All visual properties controlled by iOS. + */ export const NativeMaterialView: React.FC = (props) => { return ; }; -/** Wraps UIButton with system button configurations. */ +/** + * NativeButton - Exposes UIButton with system configurations + * + * Uses native button styles and animations. + */ export const NativeButton: React.FC = (props) => { return ; }; -/** Wraps UISwitch. */ +/** + * NativeSwitch - Exposes UISwitch + * + * Native iOS toggle control. + */ export const NativeSwitch: React.FC = (props) => { return ; }; -/** Wraps UISegmentedControl. Note: liquid glass selection rendering is unreliable when bridged into React Native. */ +/** + * NativeSegmentedControl - Exposes UISegmentedControl + * + * Native segmented control with system styling. + */ export const NativeSegmentedControl: React.FC = (props) => { - return ( - - ); + return ; }; -/** Wraps UISearchBar. */ +/** + * NativeSearchBar - Exposes UISearchBar + * + * Native search bar with minimal style. + */ export const NativeSearchBar: React.FC = (props) => { return ; }; -/** Wraps UINavigationBar. */ +/** + * NativeNavigationBar - Exposes UINavigationBar + * + * Native navigation bar with translucent material. + */ export const NativeNavigationBar: React.FC = (props) => { return ; }; -/** Wraps UIToolbar. Use NativeToolbarButton and NativeToolbarMenu as children. */ +/** + * NativeToolbar - Exposes UIToolbar + * + * Native toolbar with support for buttons and menus as children. + * Use with NativeToolbarButton and NativeToolbarMenu components. + */ export const NativeToolbar: React.FC = (props) => { return ; }; -/** Wraps UIBarButtonItem. Must be a direct child of NativeToolbar. */ +/** + * NativeToolbarButton - Exposes UIBarButtonItem + * + * Native toolbar button. Must be used as a child of NativeToolbar. + */ export const NativeToolbarButton: React.FC = (props) => { return ; }; -/** Wraps UIBarButtonItem with UIMenu. Supports nested submenus. Must be a direct child of NativeToolbar. */ +/** + * NativeToolbarMenu - Exposes UIBarButtonItem with UIMenu + * + * Native toolbar menu button with nested menu support. + * Automatically handles cascading menus, animations, and platform differences. + * Must be used as a child of NativeToolbar. + */ export const NativeToolbarMenu: React.FC = (props) => { return ; }; -/** Wraps UITabBar. Set height explicitly via the style prop. */ +/** + * NativeTabBar - Exposes UITabBar + * + * Native tab bar with system styling. + */ export const NativeTabBar: React.FC = (props) => { return ; }; -/** UIView with systemGroupedBackground color. */ +/** + * NativeGroupedContainer - UIView with system grouped background + * + * Uses system background colors for grouped list style. + */ export const NativeGroupedContainer: React.FC = (props) => { return ; }; -/** UIView with secondary system grouped background and continuous corner radius. */ +/** + * NativeCardContainer - UIView with continuous corner radius + * + * System background with native corner curve. + */ export const NativeCardContainer: React.FC = (props) => { return ; }; -/** Wraps UIStackView. Arranges children along a vertical or horizontal axis. */ +/** + * NativeStackView - Exposes UIStackView for automatic layout + * + * Native iOS stack layout with axis, spacing, alignment, and distribution. + * Automatically arranges child views without manual positioning. + */ export const NativeStackView: React.FC = (props) => { return ; }; -/** Standalone UIButton that shows a UIMenu on press. Works anywhere — no NativeToolbar required. */ +/** + * NativeMenuButton - Standalone UIButton with UIMenu pull-down + * + * Shows a native iOS pull-down menu anchored to the button. + * Works anywhere (no UIToolbar parent required). + */ export const NativeMenuButton: React.FC = (props) => { return ; }; @@ -158,6 +191,6 @@ const styles = StyleSheet.create({ overflow: 'hidden', }, defaultStack: { - // layout is fully prop-driven + // No default styling - controlled by axis, spacing, alignment, distribution props }, }); diff --git a/src/index.ts b/src/index.ts index 1368db3..71dfa15 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,29 +1,4 @@ -/** - * Public API surface for liquid-react. Re-exports all components and TypeScript types. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// Main exports export { NativeMaterialView, NativeButton, @@ -41,10 +16,12 @@ export { NativeMenuButton, } from './components'; +// Type exports export type { MaterialType, ButtonStyle, ToolbarSystemItem, + ToolbarItem, ToolbarMenuItem, TabBarSystemItem, TabBarItem, @@ -56,6 +33,7 @@ export type { SearchBarChangeEvent, TabBarPressEvent, ToolbarMenuActionEvent, + ToolbarButtonPressEvent, NativeMaterialViewProps, NativeButtonProps, NativeSwitchProps, diff --git a/src/nativeComponents.ts b/src/nativeComponents.ts index f53d915..1805bf8 100644 --- a/src/nativeComponents.ts +++ b/src/nativeComponents.ts @@ -1,29 +1,4 @@ -/** - * Registers native UIKit view managers with React Native's requireNativeComponent. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +import React from 'react'; import { Platform, requireNativeComponent, View } from 'react-native'; import type { NativeMaterialViewProps, @@ -42,25 +17,36 @@ import type { NativeMenuButtonProps, } from './types'; -// On web, requireNativeComponent doesn't exist - fall back to View. +/** + * Safely resolves a native component by name. + * On iOS/Android it delegates to requireNativeComponent. + * On web (Expo Web / react-native-web) no native modules exist, so + * we fall back to a plain View to avoid a hard crash at module load time. + */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -const req = Platform.OS === 'web' ? () => View as any : requireNativeComponent; +function createNativeComponent(name: string): React.ComponentType { + if (Platform.OS === 'web') { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return View as unknown as React.ComponentType; + } + // HostComponent is React.ComponentClass at runtime; the cast resolves + // dual-React-types version conflicts between the library and the host app. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return requireNativeComponent(name) as unknown as React.ComponentType; +} -export const RNNativeMaterialView = req('LRNativeMaterialView'); -export const RNNativeButton = req('LRNativeButton'); -export const RNNativeSwitch = req('LRNativeSwitch'); -export const RNNativeSegmentedControl = req( - 'LRNativeSegmentedControl', -); -export const RNNativeSearchBar = req('LRNativeSearchBar'); -export const RNNativeNavigationBar = req('LRNativeNavigationBar'); -export const RNNativeToolbar = req('LRNativeToolbar'); -export const RNNativeToolbarButton = req('LRNativeToolbarButton'); -export const RNNativeToolbarMenu = req('LRNativeToolbarMenu'); -export const RNNativeTabBar = req('LRNativeTabBar'); -export const RNNativeGroupedContainer = req( - 'LRNativeGroupedContainer', -); -export const RNNativeCardContainer = req('LRNativeCardContainer'); -export const RNNativeStackView = req('LRNativeStackView'); -export const RNNativeMenuButton = req('LRNativeMenuButton'); +// Native component registration +export const RNNativeMaterialView = createNativeComponent('LRNativeMaterialView'); +export const RNNativeButton = createNativeComponent('LRNativeButton'); +export const RNNativeSwitch = createNativeComponent('LRNativeSwitch'); +export const RNNativeSegmentedControl = createNativeComponent('LRNativeSegmentedControl'); +export const RNNativeSearchBar = createNativeComponent('LRNativeSearchBar'); +export const RNNativeNavigationBar = createNativeComponent('LRNativeNavigationBar'); +export const RNNativeToolbar = createNativeComponent('LRNativeToolbar'); +export const RNNativeToolbarButton = createNativeComponent('LRNativeToolbarButton'); +export const RNNativeToolbarMenu = createNativeComponent('LRNativeToolbarMenu'); +export const RNNativeTabBar = createNativeComponent('LRNativeTabBar'); +export const RNNativeGroupedContainer = createNativeComponent('LRNativeGroupedContainer'); +export const RNNativeCardContainer = createNativeComponent('LRNativeCardContainer'); +export const RNNativeStackView = createNativeComponent('LRNativeStackView'); +export const RNNativeMenuButton = createNativeComponent('LRNativeMenuButton'); diff --git a/src/types.ts b/src/types.ts index 2621d50..27d5cff 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,242 +1,222 @@ -/** - * TypeScript prop types and event payload types for all liquid-react native components. - * - * - * MIT License - * - * Copyright (c) 2026 Banu Andrei & Mircea Levin-Constantin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -import { ViewProps } from 'react-native'; -import type { - BubblingEventHandler, - DirectEventHandler, -} from 'react-native/Libraries/Types/CodegenTypes'; +import type { ViewProps } from 'react-native'; +import type { ReactNode } from 'react'; + +type BubblingEventHandler = (event: T) => void; +type DirectEventHandler = (event: T) => void; // Material types export type MaterialType = - | 'systemUltraThinMaterial' - | 'systemThinMaterial' - | 'systemMaterial' - | 'systemThickMaterial' - | 'systemChromeMaterial' - | 'systemUltraThinMaterialLight' - | 'systemThinMaterialLight' - | 'systemMaterialLight' - | 'systemThickMaterialLight' - | 'systemChromeMaterialLight' - | 'systemUltraThinMaterialDark' - | 'systemThinMaterialDark' - | 'systemMaterialDark' - | 'systemThickMaterialDark' - | 'systemChromeMaterialDark'; +| 'systemUltraThinMaterial' +| 'systemThinMaterial' +| 'systemMaterial' +| 'systemThickMaterial' +| 'systemChromeMaterial' +| 'systemUltraThinMaterialLight' +| 'systemThinMaterialLight' +| 'systemMaterialLight' +| 'systemThickMaterialLight' +| 'systemChromeMaterialLight' +| 'systemUltraThinMaterialDark' +| 'systemThinMaterialDark' +| 'systemMaterialDark' +| 'systemThickMaterialDark' +| 'systemChromeMaterialDark'; // Button types export type ButtonStyle = - | 'filled' - | 'gray' - | 'tinted' - | 'plain' - | 'bordered' - | 'borderedTinted' - | 'borderedProminent'; +| 'filled' +| 'gray' +| 'tinted' +| 'plain' +| 'bordered' +| 'borderedTinted' +| 'borderedProminent'; // Toolbar item types export type ToolbarSystemItem = - | 'done' - | 'cancel' - | 'edit' - | 'save' - | 'add' - | 'flexibleSpace' - | 'fixedSpace' - | 'compose' - | 'reply' - | 'action' - | 'organize' - | 'bookmarks' - | 'search' - | 'refresh' - | 'stop' - | 'camera' - | 'trash' - | 'play' - | 'pause' - | 'rewind' - | 'fastForward' - | 'undo' - | 'redo' - | 'close'; +| 'done' +| 'cancel' +| 'edit' +| 'save' +| 'add' +| 'flexibleSpace' +| 'fixedSpace' +| 'compose' +| 'reply' +| 'action' +| 'organize' +| 'bookmarks' +| 'search' +| 'refresh' +| 'stop' +| 'camera' +| 'trash' +| 'play' +| 'pause' +| 'rewind' +| 'fastForward' +| 'undo' +| 'redo' +| 'close'; export interface ToolbarMenuItem { - id?: string; - title: string; +id?: string; +title: string; +icon?: string; +destructive?: boolean; +disabled?: boolean; +children?: ToolbarMenuItem[]; +} + +export interface ToolbarItem { icon?: string; - destructive?: boolean; + title?: string; + systemItem?: ToolbarSystemItem; disabled?: boolean; - children?: ToolbarMenuItem[]; } export interface ToolbarMenuActionEvent { - id: string; - title: string; +id: string; +title: string; } // TabBar types export type TabBarSystemItem = - | 'more' - | 'favorites' - | 'featured' - | 'topRated' - | 'recents' - | 'contacts' - | 'history' - | 'bookmarks' - | 'search' - | 'downloads' - | 'mostRecent' - | 'mostViewed'; +| 'more' +| 'favorites' +| 'featured' +| 'topRated' +| 'recents' +| 'contacts' +| 'history' +| 'bookmarks' +| 'search' +| 'downloads' +| 'mostRecent' +| 'mostViewed'; export interface TabBarItem { - title: string; - icon?: string; - systemItem?: TabBarSystemItem; +title: string; +icon?: string; +systemItem?: TabBarSystemItem; } // Event types export interface ValueChangeEvent { - value: boolean; +value: boolean; } export interface SegmentedControlValueChangeEvent { - selectedIndex: number; +selectedIndex: number; } export interface SearchBarChangeEvent { - text: string; +text: string; } export interface TabBarPressEvent { - index: number; +index: number; } // Component prop types export interface NativeMaterialViewProps extends ViewProps { - material?: MaterialType; - onPress?: BubblingEventHandler>; +material?: MaterialType; +onPress?: BubblingEventHandler<{}>; } export interface NativeButtonProps extends ViewProps { - title: string; - buttonStyle?: ButtonStyle; - onPress?: BubblingEventHandler>; +title: string; +buttonStyle?: ButtonStyle; +onPress?: BubblingEventHandler<{}>; } export interface NativeSwitchProps extends ViewProps { - value?: boolean; - onTintColor?: string; - thumbTintColor?: string; - disabled?: boolean; - onValueChange?: BubblingEventHandler; +value?: boolean; +onTintColor?: string; +thumbTintColor?: string; +disabled?: boolean; +onValueChange?: BubblingEventHandler; } export interface NativeSegmentedControlProps extends ViewProps { - segments: string[]; - selectedIndex?: number; - onValueChange?: BubblingEventHandler; +segments: string[]; +selectedIndex?: number; +onValueChange?: BubblingEventHandler; } export interface NativeSearchBarProps extends ViewProps { - placeholder?: string; - text?: string; - onTextChanged?: DirectEventHandler; - onSearchPressed?: DirectEventHandler; - onCancelPressed?: DirectEventHandler>; +placeholder?: string; +text?: string; +onTextChanged?: DirectEventHandler; +onSearchPressed?: DirectEventHandler; +onCancelPressed?: DirectEventHandler<{}>; } export interface NativeNavigationBarProps extends ViewProps { - title?: string; - translucent?: boolean; +title?: string; +translucent?: boolean; +} + +// Event carrying icon+title of the bar button that was tapped. +export interface ToolbarButtonPressEvent { + icon: string; + title: string; } export interface NativeToolbarProps extends ViewProps { translucent?: boolean; - children?: React.ReactNode; + children?: ReactNode; + /** Fires when a NativeToolbarButton child is pressed. */ + onToolbarButtonPress?: DirectEventHandler; + /** Fires when a NativeToolbarMenu child action is triggered. */ + onToolbarMenuAction?: DirectEventHandler; } export interface NativeToolbarButtonProps extends ViewProps { - icon?: string; - title?: string; - systemItem?: ToolbarSystemItem; - disabled?: boolean; - onPress?: BubblingEventHandler>; +icon?: string; +title?: string; +systemItem?: ToolbarSystemItem; +disabled?: boolean; +onPress?: BubblingEventHandler<{}>; } export interface NativeToolbarMenuProps extends ViewProps { - icon?: string; - title?: string; - menuItems: ToolbarMenuItem[]; - disabled?: boolean; - onMenuAction?: BubblingEventHandler; +icon?: string; +title?: string; +menuItems: ToolbarMenuItem[]; +disabled?: boolean; +onMenuAction?: BubblingEventHandler; } export interface NativeTabBarProps extends ViewProps { - items: TabBarItem[]; - selectedIndex?: number; - translucent?: boolean; - onTabPress?: BubblingEventHandler; +items: TabBarItem[]; +selectedIndex?: number; +translucent?: boolean; +onTabPress?: BubblingEventHandler; } export interface NativeGroupedContainerProps extends ViewProps { - insetGrouped?: boolean; +insetGrouped?: boolean; } export interface NativeCardContainerProps extends ViewProps { - cornerRadius?: number; +cornerRadius?: number; } // Stack view types export type StackAxis = 'vertical' | 'horizontal'; -export type StackAlignment = - | 'fill' - | 'leading' - | 'trailing' - | 'center' - | 'firstBaseline' - | 'lastBaseline'; -export type StackDistribution = - | 'fill' - | 'fillEqually' - | 'fillProportionally' - | 'equalSpacing' - | 'equalCentering'; +export type StackAlignment = 'fill' | 'leading' | 'trailing' | 'center' | 'firstBaseline' | 'lastBaseline'; +export type StackDistribution = 'fill' | 'fillEqually' | 'fillProportionally' | 'equalSpacing' | 'equalCentering'; export interface NativeStackViewProps extends ViewProps { - axis?: StackAxis; - spacing?: number; - alignment?: StackAlignment; - distribution?: StackDistribution; +axis?: StackAxis; +spacing?: number; +alignment?: StackAlignment; +distribution?: StackDistribution; } export interface NativeMenuButtonProps extends ViewProps { icon?: string; tintColorHex?: string; menuItems: ToolbarMenuItem[]; onMenuAction?: DirectEventHandler; -} +} \ No newline at end of file From 54504557c6dee247fd9a4884b6488e1769cc88dd Mon Sep 17 00:00:00 2001 From: PzmuV1517 Date: Sun, 1 Mar 2026 15:45:22 +0200 Subject: [PATCH 11/12] ready for main --- .gitignore | 2 ++ index.js | 4 ++-- ios/LRNativeToolbarMenuManager.swift | 2 -- package.json | 10 ++++++---- src/nativeComponents.ts | 8 +++----- tsconfig.json | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index d8b6b62..c1bfcc7 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ logs/ # Ignore IDE specific files .idea/ .vscode/ +.venv +package-lock.json diff --git a/index.js b/index.js index f9a99d0..740c492 100644 --- a/index.js +++ b/index.js @@ -1,2 +1,2 @@ -// Export everything from src/index.ts -export * from './src/index'; +// Re-export compiled library output +module.exports = require('./lib/index'); diff --git a/ios/LRNativeToolbarMenuManager.swift b/ios/LRNativeToolbarMenuManager.swift index 3edff96..4a141f6 100644 --- a/ios/LRNativeToolbarMenuManager.swift +++ b/ios/LRNativeToolbarMenuManager.swift @@ -48,8 +48,6 @@ class NativeToolbarMenuContainer: UIView { override init(frame: CGRect) { super.init(frame: frame) setupButton() - // Keep the view in the hierarchy (not hidden) so RCTDirectEventBlock - // can dispatch events to JS. Make it invisible instead. self.frame = CGRect(x: 0, y: 0, width: 1, height: 1) self.clipsToBounds = true self.alpha = 0 diff --git a/package.json b/package.json index 81e8866..f74b684 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,11 @@ "name": "liquid-react", "version": "1.0.0", "description": "Production-ready React Native iOS module exposing Apple's native UIKit Liquid Glass components", - "main": "index.js", - "types": "dist/index.d.ts", + "main": "lib/index.js", + "types": "lib/index.d.ts", "scripts": { + "build": "tsc", + "prepublishOnly": "npm run build", "test": "echo \"Error: no test specified\" && exit 1", "lint": "eslint . --ext .js,.jsx,.ts,.tsx" }, @@ -28,11 +30,11 @@ "react-native": ">=0.65.0" }, "devDependencies": { - "@types/react": "^18.0.0", - "@types/react-native": "^0.73.0", + "@types/react": "^19.0.0", "typescript": "^5.0.0" }, "files": [ + "lib/", "src/", "ios/", "liquid-react.podspec", diff --git a/src/nativeComponents.ts b/src/nativeComponents.ts index 1805bf8..9c28256 100644 --- a/src/nativeComponents.ts +++ b/src/nativeComponents.ts @@ -1,4 +1,3 @@ -import React from 'react'; import { Platform, requireNativeComponent, View } from 'react-native'; import type { NativeMaterialViewProps, @@ -18,10 +17,9 @@ import type { } from './types'; /** - * Safely resolves a native component by name. - * On iOS/Android it delegates to requireNativeComponent. - * On web (Expo Web / react-native-web) no native modules exist, so - * we fall back to a plain View to avoid a hard crash at module load time. + * Resolves a native component by name. + * On web (Expo Web / react-native-web), falls back to a plain View + * to avoid a crash at module load time. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function createNativeComponent(name: string): React.ComponentType { diff --git a/tsconfig.json b/tsconfig.json index 0e1d6b6..bdd4c78 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,5 +16,5 @@ "allowSyntheticDefaultImports": true }, "include": ["src/**/*"], - "exclude": ["node_modules", "lib", "ios"] + "exclude": ["node_modules", "lib", "dist", "ios"] } From 5096ec1c1e199a5e676e5d0e8a987869b97ca8d6 Mon Sep 17 00:00:00 2001 From: Banu Andrei <77862184+PzmuV1517@users.noreply.github.com> Date: Sun, 1 Mar 2026 15:47:11 +0200 Subject: [PATCH 12/12] Delete lint-and-build workflow configuration Removed the lint and build workflow configuration from GitHub Actions. --- .github/workflows/lint-and-build.yml | 35 ---------------------------- 1 file changed, 35 deletions(-) diff --git a/.github/workflows/lint-and-build.yml b/.github/workflows/lint-and-build.yml index 5034c24..8b13789 100644 --- a/.github/workflows/lint-and-build.yml +++ b/.github/workflows/lint-and-build.yml @@ -1,36 +1 @@ -name: Lint & Build -on: - push: - branches: [main, staging, forProduction] - pull_request: - -jobs: - lint-and-build: - name: ESLint, Prettier & TypeScript - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node 20 - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: npm - - - name: Install dependencies - run: npm ci --legacy-peer-deps - - - name: ESLint - run: npm run lint - - - name: Prettier check - run: npm run format:check - - - name: TypeScript type-check - run: npm run typecheck - - - name: TypeScript build - run: npm run build