diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..7ea8386
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,78 @@
+name: Bug Report
+description: File a bug report
+labels: ["bug"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to fill out this bug report!
+ Please provide as much detail as possible to help us reproduce and fix the issue.
+
+ - type: dropdown
+ id: platform
+ attributes:
+ label: Platform
+ description: What platform(s) are you seeing this issue on?
+ multiple: true
+ options:
+ - iOS
+ - Android
+ - Both
+ validations:
+ required: true
+
+ - type: input
+ id: device
+ attributes:
+ label: Device & OS Version
+ description: What device and OS version are you using? (e.g., iPhone 14 iOS 17.2, Pixel 7 Android 14)
+ placeholder: iPhone 14 Pro iOS 17.2
+ validations:
+ required: true
+
+ - type: input
+ id: app-version
+ attributes:
+ label: App Version
+ description: What version of POWR are you running?
+ placeholder: 1.0.0
+ validations:
+ required: true
+
+ - type: textarea
+ id: what-happened
+ attributes:
+ label: What happened?
+ description: Describe the issue and what you expected to happen instead
+ placeholder: |
+ 1. Go to '...'
+ 2. Click on '...'
+ 3. Scroll down to '...'
+ 4. See error
+ validations:
+ required: true
+
+ - type: textarea
+ id: reproduction
+ attributes:
+ label: Steps to Reproduce
+ description: Clear steps to reproduce the behavior
+ placeholder: |
+ 1. Open the app
+ 2. Navigate to...
+ 3. Click on...
+ validations:
+ required: true
+
+ - type: textarea
+ id: logs
+ attributes:
+ label: Relevant log output or error messages
+ description: Please copy and paste any relevant log output. This will be automatically formatted into code.
+ render: shell
+
+ - type: textarea
+ id: additional-context
+ attributes:
+ label: Additional context
+ description: Add any other context about the problem here (screenshots, videos, etc.)
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..4aba3f9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+ - name: POWR Community Discussions
+ url: https://github.com/yourusername/powr/discussions
+ about: Please ask and answer questions here.
+ - name: POWR Documentation
+ url: https://github.com/yourusername/powr/tree/main/docs
+ about: Check out our documentation for guides and troubleshooting.
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml
new file mode 100644
index 0000000..29630c8
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/documentation.yml
@@ -0,0 +1,59 @@
+name: Documentation Update
+description: Help us improve our documentation
+labels: ["documentation"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for helping improve POWR's documentation!
+ Please provide details about what needs to be updated or added.
+
+ - type: dropdown
+ id: doc-type
+ attributes:
+ label: Documentation Type
+ description: What type of documentation needs updating?
+ options:
+ - README
+ - API Documentation
+ - Setup Guide
+ - Tutorial
+ - Code Comments
+ - Other
+ validations:
+ required: true
+
+ - type: input
+ id: page-link
+ attributes:
+ label: Documentation Link/Location
+ description: Which document or section needs updating? Provide a link if available.
+ placeholder: https://github.com/yourusername/powr/blob/main/docs/...
+
+ - type: textarea
+ id: current-content
+ attributes:
+ label: Current Content
+ description: What does the current documentation say? (if applicable)
+
+ - type: textarea
+ id: proposed-changes
+ attributes:
+ label: Proposed Changes
+ description: What would you like to add, remove, or modify?
+ validations:
+ required: true
+
+ - type: textarea
+ id: reason
+ attributes:
+ label: Reason for Change
+ description: Why should this documentation be updated?
+ validations:
+ required: true
+
+ - type: textarea
+ id: additional-context
+ attributes:
+ label: Additional Context
+ description: Add any other context about the documentation update here
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000..e613f32
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,58 @@
+name: Feature Request
+description: Suggest an idea for POWR
+labels: ["enhancement"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to suggest a new feature!
+ Please provide as much detail as possible to help us understand your suggestion.
+
+ - type: textarea
+ id: problem
+ attributes:
+ label: Is your feature request related to a problem?
+ description: A clear and concise description of what the problem is.
+ placeholder: I'm always frustrated when...
+ validations:
+ required: true
+
+ - type: textarea
+ id: solution
+ attributes:
+ label: Describe the solution you'd like
+ description: A clear and concise description of what you want to happen.
+ placeholder: |
+ Describe your proposed solution:
+ - What should it do?
+ - How should it work?
+ - What would the user experience be like?
+ validations:
+ required: true
+
+ - type: textarea
+ id: alternatives
+ attributes:
+ label: Describe alternatives you've considered
+ description: A clear and concise description of any alternative solutions or features you've considered.
+ placeholder: |
+ What other approaches have you thought about?
+ What are their pros and cons?
+
+ - type: dropdown
+ id: priority
+ attributes:
+ label: Priority
+ description: How important is this feature to you?
+ options:
+ - Nice to have
+ - Important
+ - Critical
+ validations:
+ required: true
+
+ - type: textarea
+ id: additional-context
+ attributes:
+ label: Additional context
+ description: Add any other context, screenshots, or mockups about the feature request here.
\ No newline at end of file
diff --git a/.github/pull_request_template/pull_request_template.md b/.github/pull_request_template/pull_request_template.md
new file mode 100644
index 0000000..1031a9a
--- /dev/null
+++ b/.github/pull_request_template/pull_request_template.md
@@ -0,0 +1,81 @@
+# Description
+
+Please include:
+- A summary of the changes
+- Motivation and context
+- Any dependencies that are required
+- Which issue is fixed, if applicable
+
+Fixes # (issue)
+
+## Type of change
+
+Please delete options that are not relevant.
+
+- [ ] Bug fix (non-breaking change which fixes an issue)
+- [ ] New feature (non-breaking change which adds functionality)
+- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
+- [ ] Documentation update
+- [ ] Performance improvement
+- [ ] Code refactoring
+- [ ] Test updates
+
+## How Has This Been Tested?
+
+Please describe the tests you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.
+
+- [ ] Test A
+- [ ] Test B
+
+## Checklist:
+
+- [ ] My code follows the style guidelines of this project
+- [ ] I have performed a self-review of my own code
+- [ ] I have commented my code, particularly in hard-to-understand areas
+- [ ] I have made corresponding changes to the documentation
+- [ ] My changes generate no new warnings
+- [ ] I have added tests that prove my fix is effective or that my feature works
+- [ ] New and existing unit tests pass locally with my changes
+- [ ] Any dependent changes have been merged and published in downstream modules
+- [ ] I have checked my code and corrected any misspellings
+
+## Screenshots (if appropriate):
+
+## Additional context:
+
+Add any other context about the pull request here.
+
+## Mobile Testing Checklist:
+
+If applicable, please confirm testing on:
+
+### iOS
+- [ ] iPhone (latest iOS version)
+- [ ] iPad (if applicable)
+- [ ] Different screen sizes tested
+- [ ] Dark mode tested
+
+### Android
+- [ ] Latest Android version
+- [ ] Different screen sizes tested
+- [ ] Dark mode tested
+
+## Performance Impact:
+
+- [ ] No significant performance impact
+- [ ] Performance improved
+- [ ] Performance regressed (please explain)
+
+## Database Changes:
+
+If applicable:
+- [ ] Database migrations are included
+- [ ] Backward compatibility is maintained
+- [ ] Data integrity is preserved
+
+## Future Impact:
+
+Please describe any potential future impact this change might have:
+- Impact on planned features
+- Technical debt considerations
+- Scalability implications
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..7a73a41
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,2 @@
+{
+}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..547b16d
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,84 @@
+# Changelog
+
+All notable changes to the POWR project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+### Added
+- Basic exercise template creation functionality
+ - Input validation for required fields
+ - Schema-compliant field constraints
+ - Native picker components for standardized inputs
+- Enhanced error handling in database operations
+ - Detailed SQLite error logging
+ - Improved transaction management
+ - Added proper error types and propagation
+
+### Changed
+- Updated NewExerciseScreen with constrained inputs
+ - Added dropdowns for equipment selection
+ - Added movement pattern selection
+ - Added difficulty selection
+ - Added exercise type selection
+- Improved DbService with better error handling
+ - Added proper SQLite error types
+ - Enhanced transaction rollback handling
+ - Added detailed debug logging
+
+### Technical Details
+1. Database Schema Enforcement:
+ - Added CHECK constraints for equipment types
+ - Added CHECK constraints for exercise types
+ - Added CHECK constraints for categories
+ - Proper handling of foreign key constraints
+
+2. Input Validation:
+ - Equipment options: bodyweight, barbell, dumbbell, kettlebell, machine, cable, other
+ - Exercise types: strength, cardio, bodyweight
+ - Categories: Push, Pull, Legs, Core
+ - Difficulty levels: beginner, intermediate, advanced
+ - Movement patterns: push, pull, squat, hinge, carry, rotation
+
+3. Error Handling:
+ - Added SQLite error type definitions
+ - Improved error propagation in LibraryService
+ - Added transaction rollback on constraint violations
+
+### Migration Notes
+- Exercise creation now enforces schema constraints
+- Input validation prevents invalid data entry
+- Enhanced error messages provide better debugging information
+
+## [0.1.0] - 2024-02-09
+
+### Added
+- Initial project setup with Expo and React Native
+- Basic tab navigation structure
+- Theme support (light/dark mode)
+- SQLite database integration
+- Basic exercise library interface
+
+### Changed
+- Migrated to TypeScript
+- Updated to latest Expo SDK
+- Implemented NativeWind for styling
+
+### Fixed
+- iOS status bar appearance
+- Android back button handling
+- SQLite transaction management
+
+### Security
+- Added basic input validation
+- Implemented secure storage for sensitive data
+
+## [0.0.1] - 2024-02-01
+
+### Added
+- Initial repository setup
+- Basic project structure
+- Development environment configuration
+- Documentation templates
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..562a79d
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,154 @@
+# Contributing to POWR
+
+First off, thank you for considering contributing to POWR! This document provides guidelines and steps for contributing.
+
+## Getting Started
+
+1. Fork the Repository
+2. Clone your fork
+3. Create a new branch: `git checkout -b feature/your-feature-name`
+4. Make your changes
+5. Commit with clear messages
+6. Push to your fork
+7. Submit a Pull Request
+
+## Development Setup
+
+1. Install dependencies:
+```bash
+npm install
+```
+
+2. Start the development server:
+```bash
+npx expo start
+```
+
+## Code Style Guidelines
+
+### TypeScript
+- Use TypeScript for all new code
+- Provide proper type definitions
+- Avoid using `any`
+- Document complex types
+
+### React/React Native
+- Use functional components
+- Implement proper error boundaries
+- Follow React hooks best practices
+- Keep components focused and reusable
+
+### Testing
+- Write tests for new features
+- Maintain existing test coverage
+- Use descriptive test names
+- Follow the "Arrange-Act-Assert" pattern
+
+## Documentation
+
+### Code Documentation
+- Use JSDoc comments for functions and classes
+- Document component props
+- Explain complex logic
+- Keep inline comments clear and necessary
+
+### Updating Documentation
+- Update README.md if needed
+- Document new features
+- Update CHANGELOG.md
+- Add migration notes if needed
+
+## Pull Request Process
+
+1. Create a descriptive PR title
+2. Fill out the PR template
+3. Link related issues
+4. Update documentation
+5. Ensure tests pass
+6. Request review
+7. Address feedback
+
+## Commit Messages
+
+Follow the conventional commits specification:
+
+- feat: New feature
+- fix: Bug fix
+- docs: Documentation changes
+- style: Code style changes
+- refactor: Code refactoring
+- test: Test updates
+- chore: Build process updates
+
+Example:
+```
+feat(exercise): add custom exercise creation
+
+- Add exercise form component
+- Implement validation
+- Add database integration
+```
+
+## Working with Issues
+
+1. Check existing issues first
+2. Use issue templates when available
+3. Provide clear reproduction steps
+4. Include relevant information:
+ - Platform (iOS/Android/Web)
+ - React Native version
+ - Error messages
+ - Screenshots if applicable
+
+## Code Review Process
+
+### Submitting Code
+- Keep PRs focused and small
+- Explain complex changes
+- Update tests and documentation
+- Ensure CI checks pass
+
+### Reviewing Code
+- Be respectful and constructive
+- Focus on code, not the author
+- Explain your reasoning
+- Approve once satisfied
+
+## Design Guidelines
+
+### UI/UX Principles
+- Follow platform conventions
+- Maintain consistency
+- Consider accessibility
+- Support dark mode
+
+### Component Design
+- Keep components focused
+- Use proper prop types
+- Implement error handling
+- Consider reusability
+
+## Release Process
+
+1. Version bump
+2. Update CHANGELOG.md
+3. Create release notes
+4. Tag the release
+5. Build and test
+6. Deploy
+
+## Questions?
+
+If you have questions:
+1. Check existing issues
+2. Review documentation
+3. Open a discussion
+4. Ask in our community channels
+
+## Community Guidelines
+
+- Be respectful and inclusive
+- Help others learn
+- Share knowledge
+- Give constructive feedback
+- Follow the code of conduct
\ No newline at end of file
diff --git a/README.md b/README.md
index 44d05e0..813574f 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,148 @@
-# Starter base
+# POWR - Cross-Platform Fitness Tracking App
-A starting point to help you set up your project quickly and use the common components provided by `react-native-reusables`. The idea is to make it easier for you to get started.
+POWR is a local-first fitness tracking application built with React Native and Expo, featuring planned Nostr protocol integration for decentralized social features.
## Features
-- NativeWind v4
-- Dark and light mode
- - Android Navigation Bar matches mode
- - Persistent mode
-- Common components
- - ThemeToggle, Avatar, Button, Card, Progress, Text, Tooltip
+### Current
+- Exercise library management
+- Workout template creation
+- Local-first data architecture
+- Cross-platform support (iOS, Android)
+- Dark mode support
-
+### Planned
+- Workout record and template sharing
+- Nostr integration
+- Social features
+- Training programs
+- Performance analytics
+
+## Getting Started
+
+### Prerequisites
+- Node.js (v18 or later)
+- npm or yarn
+- Expo CLI
+- iOS Simulator (for iOS development)
+- Android Studio (for Android development)
+
+### Installation
+
+1. Clone the repository
+```bash
+git clone https://github.com/docNR/powr.git
+cd powr
+```
+
+2. Install dependencies
+```bash
+npm install
+```
+
+3. Start the development server
+```bash
+npx expo start
+```
+
+### Development Options
+- Press 'i' for iOS simulator
+- Press 'a' for Android simulator
+- Scan QR code with Expo Go app for physical device
+
+## Project Structure
+
+```plaintext
+powr/
+├── app/ # Main application code
+│ ├── (tabs)/ # Tab-based navigation
+│ └── components/ # Shared components
+├── assets/ # Static assets
+├── docs/ # Documentation
+│ └── design/ # Design documents
+├── lib/ # Shared utilities
+└── types/ # TypeScript definitions
+```
+
+## Technology Stack
+
+### Core
+- React Native
+- Expo
+- TypeScript
+- SQLite (via expo-sqlite)
+
+### UI Components
+- NativeWind
+- React Navigation
+- Lucide Icons
+
+### Testing
+- Jest
+- React Native Testing Library
+
+## Development
+
+### Environment Setup
+1. Install development tools
+```bash
+npm install -g expo-cli
+```
+
+2. Configure environment
+```bash
+cp .env.example .env
+```
+
+3. Configure development settings
+```bash
+npm run setup-dev
+```
+
+### Running Tests
+```bash
+# Run all tests
+npm test
+
+# Run with coverage
+npm test -- --coverage
+
+# Run in watch mode
+npm test -- --watch
+```
+
+### Building for Production
+```bash
+# Build for iOS
+eas build -p ios
+
+# Build for Android
+eas build -p android
+```
+
+## Contributing
+
+1. Fork the repository
+2. Create a feature branch
+3. Commit your changes
+4. Push to the branch
+5. Open a Pull Request
+
+Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct and development process.
+
+## Documentation
+
+- [Project Overview](docs/project-overview.md)
+- [Architecture Guide](docs/architecture.md)
+- [API Documentation](docs/api.md)
+- [Testing Guide](docs/testing.md)
+
+## License
+
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
+
+## Acknowledgments
+
+- [Expo](https://expo.dev/)
+- [React Native](https://reactnative.dev/)
+- [Nostr Protocol](https://github.com/nostr-protocol/nostr)
\ No newline at end of file
diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx
new file mode 100644
index 0000000..38a48c8
--- /dev/null
+++ b/app/(tabs)/_layout.tsx
@@ -0,0 +1,78 @@
+// app/(tabs)/_layout.tsx
+import React from 'react';
+import { Platform } from 'react-native';
+import { Tabs } from 'expo-router';
+import { useTheme } from '@react-navigation/native'; // Change this import
+import { Dumbbell, Library, Users, History, User } from 'lucide-react-native';
+import { CUSTOM_COLORS } from '@/lib/constants';
+
+export default function TabLayout() {
+ const { colors } = useTheme();
+
+ return (
+
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+
+ );
+}
\ No newline at end of file
diff --git a/app/(tabs)/history.tsx b/app/(tabs)/history.tsx
new file mode 100644
index 0000000..bcaf98b
--- /dev/null
+++ b/app/(tabs)/history.tsx
@@ -0,0 +1,11 @@
+// app/(tabs)/history.tsx
+import { View } from 'react-native';
+import { Text } from '@/components/ui/text';
+
+export default function HomeScreen() {
+ return (
+
+ Home Screen
+
+ );
+}
\ No newline at end of file
diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx
new file mode 100644
index 0000000..8847d4c
--- /dev/null
+++ b/app/(tabs)/index.tsx
@@ -0,0 +1,11 @@
+// app/(tabs)/index.tsx
+import { View } from 'react-native';
+import { Text } from '@/components/ui/text';
+
+export default function HomeScreen() {
+ return (
+
+ Home Screen
+
+ );
+}
\ No newline at end of file
diff --git a/app/(tabs)/library/_layout.native.tsx b/app/(tabs)/library/_layout.native.tsx
new file mode 100644
index 0000000..a9328ce
--- /dev/null
+++ b/app/(tabs)/library/_layout.native.tsx
@@ -0,0 +1,59 @@
+// app/(tabs)/library/_layout.native.tsx
+import { View } from 'react-native';
+import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
+import { useTheme } from '@react-navigation/native';
+import { Text } from '@/components/ui/text';
+import { ThemeToggle } from '@/components/ThemeToggle';
+import ExercisesScreen from './exercises';
+import TemplatesScreen from './templates';
+import ProgramsScreen from './programs';
+import { CUSTOM_COLORS } from '@/lib/constants';
+
+const Tab = createMaterialTopTabNavigator();
+
+export default function LibraryLayout() {
+ const { colors } = useTheme();
+
+ return (
+
+ {/* Header */}
+
+ Library
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/(tabs)/library/_layout.tsx b/app/(tabs)/library/_layout.tsx
new file mode 100644
index 0000000..2195c6e
--- /dev/null
+++ b/app/(tabs)/library/_layout.tsx
@@ -0,0 +1,3 @@
+// app/(tabs)/library/_layout.tsx
+// This is the fallback layout that gets overridden by platform-specific files
+export { default } from './_layout.native';
\ No newline at end of file
diff --git a/app/(tabs)/library/_layout.web.tsx b/app/(tabs)/library/_layout.web.tsx
new file mode 100644
index 0000000..40a499c
--- /dev/null
+++ b/app/(tabs)/library/_layout.web.tsx
@@ -0,0 +1,80 @@
+// app/(tabs)/library/_layout.web.tsx
+import React from 'react';
+import { View, Pressable } from 'react-native';
+import { Text } from '@/components/ui/text';
+import { ThemeToggle } from '@/components/ThemeToggle';
+import Pager from '@/components/pager';
+import { CUSTOM_COLORS } from '@/lib/constants';
+import type { PagerRef } from '@/components/pager/types';
+import ExercisesScreen from './exercises';
+import TemplatesScreen from './templates';
+import ProgramsScreen from './programs';
+
+const tabs = [
+ { key: 'exercises', title: 'Exercises', component: ExercisesScreen },
+ { key: 'templates', title: 'Templates', component: TemplatesScreen },
+ { key: 'programs', title: 'Programs', component: ProgramsScreen },
+];
+
+export default function LibraryLayout() {
+ const [activeIndex, setActiveIndex] = React.useState(0);
+ const pagerRef = React.useRef(null);
+
+ const handleTabPress = (index: number) => {
+ setActiveIndex(index);
+ pagerRef.current?.setPage(index);
+ };
+
+ return (
+
+ {/* Header */}
+
+ Library
+
+
+
+ {/* Tab Headers */}
+
+ {tabs.map((tab, index) => (
+
+ handleTabPress(index)}
+ className="px-4 py-3 items-center"
+ >
+
+ {tab.title}
+
+
+ {activeIndex === index && (
+
+ )}
+
+ ))}
+
+
+ {/* Content */}
+
+ setActiveIndex(e.nativeEvent.position)}
+ style={{ flex: 1 }}
+ >
+ {tabs.map((tab) => (
+
+
+
+ ))}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/(tabs)/library/exercises.tsx b/app/(tabs)/library/exercises.tsx
new file mode 100644
index 0000000..a92fe26
--- /dev/null
+++ b/app/(tabs)/library/exercises.tsx
@@ -0,0 +1,180 @@
+// app/(tabs)/library/exercises.tsx
+import React, { useState, useCallback } from 'react';
+import { View, ScrollView } from 'react-native';
+import { Text } from '@/components/ui/text';
+import { ExerciseCard } from '@/components/exercises/ExerciseCard';
+import { FloatingActionButton } from '@/components/shared/FloatingActionButton';
+import { SearchHeader } from '@/components/library/SearchHeader';
+import { FilterSheet, type FilterOptions } from '@/components/library/FilterSheet';
+import { NewExerciseSheet } from '@/components/library/NewExerciseSheet';
+import { Dumbbell } from 'lucide-react-native';
+import { Exercise, ExerciseCategory, ExerciseEquipment, ContentSource } from '@/types/library';
+
+const initialExercises: Exercise[] = [
+ {
+ id: '1',
+ title: 'Barbell Back Squat',
+ category: 'Legs' as ExerciseCategory,
+ equipment: 'barbell' as ExerciseEquipment,
+ tags: ['compound', 'strength'],
+ source: 'local' as ContentSource,
+ description: 'A compound exercise that primarily targets the quadriceps, hamstrings, and glutes.',
+ },
+ {
+ id: '2',
+ title: 'Pull-ups',
+ category: 'Pull' as ExerciseCategory,
+ equipment: 'bodyweight' as ExerciseEquipment,
+ tags: ['upper-body', 'compound'],
+ source: 'local' as ContentSource,
+ description: 'An upper body pulling exercise that targets the latissimus dorsi and biceps.',
+ },
+ {
+ id: '3',
+ title: 'Bench Press',
+ category: 'Push' as ExerciseCategory,
+ equipment: 'barbell' as ExerciseEquipment,
+ tags: ['push', 'strength'],
+ source: 'nostr' as ContentSource,
+ description: 'A compound pushing exercise that targets the chest, shoulders, and triceps.',
+ },
+];
+
+export default function ExercisesScreen() {
+ const [exercises, setExercises] = useState(initialExercises);
+ const [searchQuery, setSearchQuery] = useState('');
+ const [showFilters, setShowFilters] = useState(false);
+ const [showNewExercise, setShowNewExercise] = useState(false);
+ const [filterOptions, setFilterOptions] = useState({
+ equipment: [],
+ tags: [],
+ source: []
+ });
+
+ // Filter exercises
+ const filteredExercises = useCallback(() => {
+ return exercises.filter(exercise => {
+ // Search filter - make case insensitive
+ if (searchQuery.trim()) {
+ const searchLower = searchQuery.toLowerCase().trim();
+ const matchesSearch =
+ exercise.title.toLowerCase().includes(searchLower) ||
+ exercise.description?.toLowerCase().includes(searchLower) ||
+ exercise.tags.some(tag => tag.toLowerCase().includes(searchLower)) ||
+ exercise.equipment?.toLowerCase().includes(searchLower);
+
+ if (!matchesSearch) return false;
+ }
+
+ // Equipment filter
+ if (filterOptions.equipment.length > 0) {
+ if (!filterOptions.equipment.includes(exercise.equipment || '')) {
+ return false;
+ }
+ }
+
+ // Tags filter
+ if (filterOptions.tags.length > 0) {
+ if (!exercise.tags.some(tag => filterOptions.tags.includes(tag))) {
+ return false;
+ }
+ }
+
+ // Source filter
+ if (filterOptions.source.length > 0) {
+ if (!filterOptions.source.includes(exercise.source)) {
+ return false;
+ }
+ }
+
+ return true;
+ });
+ }, [exercises, searchQuery, filterOptions]);
+
+ const handleAddExercise = (newExercise: Exercise) => {
+ setExercises(prev => [...prev, newExercise]);
+ setShowNewExercise(false);
+ };
+
+ // Get recent and filtered exercises
+ const recentExercises = exercises.slice(0, 2);
+ const allExercises = filteredExercises();
+ const activeFilterCount = Object.values(filterOptions)
+ .reduce((count, filters) => count + filters.length, 0);
+
+ const handleDelete = (id: string) => {
+ setExercises(current => current.filter(ex => ex.id !== id));
+ };
+
+ const handleExercisePress = (exerciseId: string) => {
+ console.log('Selected exercise:', exerciseId);
+ };
+
+ const availableFilters = {
+ equipment: ['barbell', 'dumbbell', 'bodyweight', 'machine', 'cable', 'other'] as ExerciseEquipment[],
+ tags: ['strength', 'compound', 'isolation', 'push', 'pull', 'legs'],
+ source: ['local', 'powr', 'nostr'] as ContentSource[]
+ };
+
+ return (
+
+ setShowFilters(true)}
+ />
+
+
+ {/* Recent Exercises Section */}
+
+ Recent Exercises
+
+ {recentExercises.map(exercise => (
+ handleExercisePress(exercise.id)}
+ onDelete={() => handleDelete(exercise.id)}
+ />
+ ))}
+
+
+
+ {/* All Exercises Section */}
+
+ All Exercises
+
+ {allExercises.map(exercise => (
+ handleExercisePress(exercise.id)}
+ onDelete={() => handleDelete(exercise.id)}
+ />
+ ))}
+
+
+
+
+ setShowNewExercise(true)}
+ />
+
+ setShowFilters(false)}
+ options={filterOptions}
+ onApplyFilters={setFilterOptions}
+ availableFilters={availableFilters}
+ />
+
+ setShowNewExercise(false)}
+ onSubmit={handleAddExercise}
+ />
+
+ );
+}
\ No newline at end of file
diff --git a/app/(tabs)/library/index.tsx b/app/(tabs)/library/index.tsx
new file mode 100644
index 0000000..ea5aa52
--- /dev/null
+++ b/app/(tabs)/library/index.tsx
@@ -0,0 +1,93 @@
+// app/(tabs)/library/index.tsx
+import React from 'react';
+import { View, StyleSheet, Platform } from 'react-native';
+import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
+import { useTheme } from '@react-navigation/native';
+import { Text } from '@/components/ui/text';
+import { ThemeToggle } from '@/components/ThemeToggle';
+import ExercisesScreen from './exercises';
+
+const Tab = createMaterialTopTabNavigator();
+
+function TemplatesTab() {
+ return (
+
+ Templates Content
+
+ );
+}
+
+function ProgramsTab() {
+ return (
+
+ Programs (Coming Soon)
+
+ );
+}
+
+export default function LibraryScreen() {
+ const { colors } = useTheme();
+
+ return (
+
+ {/* Header with Theme Toggle */}
+
+ Library
+
+
+
+ {/* Material Top Tabs */}
+
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ header: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ paddingHorizontal: 16,
+ paddingTop: Platform.OS === 'ios' ? 60 : 16,
+ paddingBottom: 16,
+ },
+});
\ No newline at end of file
diff --git a/app/(tabs)/library/programs.tsx b/app/(tabs)/library/programs.tsx
new file mode 100644
index 0000000..acc790a
--- /dev/null
+++ b/app/(tabs)/library/programs.tsx
@@ -0,0 +1,11 @@
+// app/(tabs)/library/(tabs)/programs.tsx
+import { View } from 'react-native';
+import { Text } from '@/components/ui/text';
+
+export default function ProgramsScreen() {
+ return (
+
+ Programs (Coming Soon)
+
+ );
+}
\ No newline at end of file
diff --git a/app/(tabs)/library/templates.tsx b/app/(tabs)/library/templates.tsx
new file mode 100644
index 0000000..af729ef
--- /dev/null
+++ b/app/(tabs)/library/templates.tsx
@@ -0,0 +1,214 @@
+// app/(tabs)/library/templates.tsx
+import { View, ScrollView } from 'react-native';
+import { useState, useCallback } from 'react';
+import { Text } from '@/components/ui/text';
+import { TemplateCard } from '@/components/templates/TemplateCard';
+import { FloatingActionButton } from '@/components/shared/FloatingActionButton';
+import { SearchHeader } from '@/components/library/SearchHeader';
+import { FilterSheet } from '@/components/library/FilterSheet';
+import { NewTemplateSheet } from '@/components/library/NewTemplateSheet';
+import { useRouter } from 'expo-router';
+import { Plus } from 'lucide-react-native';
+import { Template, FilterOptions, ContentSource, ExerciseEquipment } from '@/types/library';
+
+// Mock data - move to a separate file later
+const initialTemplates: Template[] = [
+ {
+ id: '1',
+ title: 'Full Body Strength',
+ type: 'strength',
+ category: 'Full Body',
+ exercises: [
+ { title: 'Barbell Squat', targetSets: 3, targetReps: 8 },
+ { title: 'Bench Press', targetSets: 3, targetReps: 8 },
+ { title: 'Bent Over Row', targetSets: 3, targetReps: 8 }
+ ],
+ tags: ['strength', 'compound'],
+ source: 'local',
+ isFavorite: true
+ },
+ {
+ id: '2',
+ title: '20min EMOM',
+ type: 'emom',
+ category: 'Conditioning',
+ exercises: [
+ { title: 'Kettlebell Swings', targetSets: 1, targetReps: 15 },
+ { title: 'Push-ups', targetSets: 1, targetReps: 10 },
+ { title: 'Air Squats', targetSets: 1, targetReps: 20 }
+ ],
+ tags: ['conditioning', 'kettlebell'],
+ source: 'powr',
+ isFavorite: false
+ }
+];
+
+export default function TemplatesScreen() {
+ const [searchQuery, setSearchQuery] = useState('');
+ const [showFilters, setShowFilters] = useState(false);
+ const [showNewTemplate, setShowNewTemplate] = useState(false);
+ const [filterOptions, setFilterOptions] = useState({
+ equipment: [],
+ tags: [],
+ source: []
+ });
+ const [templates, setTemplates] = useState(initialTemplates);
+
+ const availableFilters = {
+ equipment: ['barbell', 'dumbbell', 'bodyweight', 'machine', 'cable', 'other'] as ExerciseEquipment[],
+ tags: ['strength', 'circuit', 'emom', 'amrap', 'Full Body', 'Upper Body', 'Lower Body', 'Conditioning'],
+ source: ['local', 'powr', 'nostr'] as ContentSource[]
+ };
+
+ const filteredTemplates = useCallback(() => {
+ return templates.filter(template => {
+ // Search filter
+ if (searchQuery) {
+ const searchLower = searchQuery.toLowerCase();
+ if (!template.title.toLowerCase().includes(searchLower) &&
+ !template.exercises.some(ex =>
+ ex.title.toLowerCase().includes(searchLower)
+ )) {
+ return false;
+ }
+ }
+
+ // Tags filter (includes type and category)
+ if (filterOptions.tags.length > 0) {
+ if (!filterOptions.tags.includes(template.type) &&
+ !filterOptions.tags.includes(template.category) &&
+ !template.tags.some(tag => filterOptions.tags.includes(tag))) {
+ return false;
+ }
+ }
+
+ // Source filter
+ if (filterOptions.source.length > 0) {
+ if (!filterOptions.source.includes(template.source)) {
+ return false;
+ }
+ }
+
+ return true;
+ });
+ }, [templates, searchQuery, filterOptions]);
+
+ const activeFilterCount = Object.values(filterOptions)
+ .reduce((count, filters) => count + filters.length, 0);
+
+ const handleDelete = (id: string) => {
+ setTemplates(current => current.filter(t => t.id !== id));
+ };
+
+ const handleTemplatePress = (template: Template) => {
+ // TODO: Show template details
+ console.log('Selected template:', template);
+ };
+
+ const handleStartWorkout = (template: Template) => {
+ // TODO: Navigate to workout screen with template
+ console.log('Starting workout with template:', template);
+ };
+
+ const handleFavorite = (template: Template) => {
+ setTemplates(current =>
+ current.map(t =>
+ t.id === template.id
+ ? { ...t, isFavorite: !t.isFavorite }
+ : t
+ )
+ );
+ };
+
+ const handleAddTemplate = (template: Template) => {
+ setTemplates(prev => [...prev, template]);
+ setShowNewTemplate(false);
+ };
+
+ // Separate favorites and regular templates
+ const favoriteTemplates = templates.filter(t => t.isFavorite);
+ const regularTemplates = templates.filter(t => !t.isFavorite);
+
+ return (
+
+ setShowFilters(true)}
+ />
+
+
+ {/* Favorites Section */}
+ {favoriteTemplates.length > 0 && (
+
+
+ Favorites
+
+
+ {favoriteTemplates.map(template => (
+ handleTemplatePress(template)}
+ onDelete={handleDelete}
+ onFavorite={() => handleFavorite(template)}
+ onStartWorkout={() => handleStartWorkout(template)}
+ />
+ ))}
+
+
+ )}
+
+ {/* All Templates Section */}
+
+
+ All Templates
+
+ {regularTemplates.length > 0 ? (
+
+ {regularTemplates.map(template => (
+ handleTemplatePress(template)}
+ onDelete={handleDelete}
+ onFavorite={() => handleFavorite(template)}
+ onStartWorkout={() => handleStartWorkout(template)}
+ />
+ ))}
+
+ ) : (
+
+
+ No templates found. Create one by clicking the + button.
+
+
+ )}
+
+
+ {/* Add some bottom padding for FAB */}
+
+
+
+ setShowNewTemplate(true)}
+ />
+
+ setShowNewTemplate(false)}
+ onSubmit={handleAddTemplate}
+ />
+
+ setShowFilters(false)}
+ options={filterOptions}
+ onApplyFilters={setFilterOptions}
+ availableFilters={availableFilters}
+ />
+
+ );
+}
\ No newline at end of file
diff --git a/app/(tabs)/profile.tsx b/app/(tabs)/profile.tsx
new file mode 100644
index 0000000..d7407df
--- /dev/null
+++ b/app/(tabs)/profile.tsx
@@ -0,0 +1,100 @@
+// app/(tabs)/profile.tsx
+import React from 'react';
+import { View, ScrollView } from 'react-native';
+import { Settings } from 'lucide-react-native';
+import { H1 } from '@/components/ui/typography';
+import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
+import { Button } from '@/components/ui/button';
+import { Text } from '@/components/ui/text';
+import Header from '@/components/Header';
+
+const PLACEHOLDER_IMAGE = 'https://github.com/shadcn.png'; // Placeholder profile image
+
+export default function ProfileScreen() {
+ return (
+
+ {
+ // TODO: Navigate to settings
+ console.log('Open settings');
+ }}
+ >
+
+
+ }
+ />
+
+
+ {/* Profile Header Section */}
+
+
+
+
+ JD
+
+
+ John Doe
+ @johndoe
+
+
+ {/* Stats Section */}
+
+
+ 24
+ Workouts
+
+
+ 12
+ Templates
+
+
+ 3
+ Programs
+
+
+
+ {/* Profile Actions */}
+
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/(tabs)/social.tsx b/app/(tabs)/social.tsx
new file mode 100644
index 0000000..a6deae2
--- /dev/null
+++ b/app/(tabs)/social.tsx
@@ -0,0 +1,11 @@
+// app/(tabs)/index.tsx (and similar for other tab screens)
+import { View } from 'react-native';
+import { Text } from '@/components/ui/text';
+
+export default function HomeScreen() {
+ return (
+
+ Home Screen
+
+ );
+}
\ No newline at end of file
diff --git a/app/(workout)/_layout.tsx b/app/(workout)/_layout.tsx
new file mode 100644
index 0000000..ebd18e7
--- /dev/null
+++ b/app/(workout)/_layout.tsx
@@ -0,0 +1,15 @@
+// app/(workout)/_layout.tsx
+import { Stack } from 'expo-router';
+
+export default function WorkoutLayout() {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/+not-found.tsx b/app/+not-found.tsx
index 08c97b6..ae21740 100644
--- a/app/+not-found.tsx
+++ b/app/+not-found.tsx
@@ -1,6 +1,6 @@
import { Link, Stack } from 'expo-router';
import { View } from 'react-native';
-import { Text } from '~/components/ui/text';
+import { Text } from '@/components/ui/text';
export default function NotFoundScreen() {
return (
diff --git a/app/_layout.tsx b/app/_layout.tsx
index f6639b8..4dc2c74 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -1,15 +1,15 @@
-import '~/global.css';
-
+// app/_layout.tsx
+import '@/global.css';
import { DarkTheme, DefaultTheme, Theme, ThemeProvider } from '@react-navigation/native';
import { Stack } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import * as React from 'react';
import { Platform } from 'react-native';
-import { NAV_THEME } from '~/lib/constants';
-import { useColorScheme } from '~/lib/useColorScheme';
+import { NAV_THEME } from '@/lib/constants';
+import { useColorScheme } from '@/lib/useColorScheme';
import { PortalHost } from '@rn-primitives/portal';
-import { ThemeToggle } from '~/components/ThemeToggle';
-import { setAndroidNavigationBar } from '~/lib/android-navigation-bar';
+import { setAndroidNavigationBar } from '@/lib/android-navigation-bar';
+import { GestureHandlerRootView } from 'react-native-gesture-handler';
const LIGHT_THEME: Theme = {
...DefaultTheme,
@@ -20,23 +20,17 @@ const DARK_THEME: Theme = {
colors: NAV_THEME.dark,
};
-export {
- // Catch any errors thrown by the Layout component.
- ErrorBoundary,
-} from 'expo-router';
-
export default function RootLayout() {
const hasMounted = React.useRef(false);
const { colorScheme, isDarkColorScheme } = useColorScheme();
const [isColorSchemeLoaded, setIsColorSchemeLoaded] = React.useState(false);
- useIsomorphicLayoutEffect(() => {
+ React.useEffect(() => {
if (hasMounted.current) {
return;
}
if (Platform.OS === 'web') {
- // Adds the background color to the html element to prevent white background on overscroll.
document.documentElement.classList.add('bg-background');
}
setAndroidNavigationBar(colorScheme);
@@ -49,21 +43,21 @@ export default function RootLayout() {
}
return (
-
-
-
- ,
- }}
- />
-
-
-
+
+
+
+
+
+
+
+
+
);
-}
-
-const useIsomorphicLayoutEffect =
- Platform.OS === 'web' && typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect;
+}
\ No newline at end of file
diff --git a/babel.config.js b/babel.config.js
index 7d507e1..145ab71 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -1,6 +1,20 @@
module.exports = function (api) {
api.cache(true);
return {
- presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }], 'nativewind/babel'],
+ presets: [
+ ['babel-preset-expo', { jsxImportSource: 'nativewind' }],
+ 'nativewind/babel'
+ ],
+ plugins: [
+ [
+ 'module-resolver',
+ {
+ root: ['.'],
+ alias: {
+ '@': './',
+ },
+ },
+ ],
+ ],
};
-};
+};
\ No newline at end of file
diff --git a/components.json b/components.json
new file mode 100644
index 0000000..a8e16a5
--- /dev/null
+++ b/components.json
@@ -0,0 +1,6 @@
+{
+ "aliases": {
+ "components": "@/components",
+ "lib": "@/lib"
+ }
+}
\ No newline at end of file
diff --git a/components/Header.tsx b/components/Header.tsx
new file mode 100644
index 0000000..7928ff0
--- /dev/null
+++ b/components/Header.tsx
@@ -0,0 +1,19 @@
+// components/Header.tsx
+import React from 'react';
+import { View } from 'react-native';
+import { Text } from '@/components/ui/text';
+import { ThemeToggle } from '@/components/ThemeToggle';
+
+interface HeaderProps {
+ title: string;
+ rightElement?: React.ReactNode;
+}
+
+export default function Header({ title, rightElement }: HeaderProps) {
+ return (
+
+ {title}
+ {rightElement || }
+
+ );
+}
\ No newline at end of file
diff --git a/components/ThemeToggle.tsx b/components/ThemeToggle.tsx
index c89471f..248f0ff 100644
--- a/components/ThemeToggle.tsx
+++ b/components/ThemeToggle.tsx
@@ -1,9 +1,9 @@
import { Pressable, View } from 'react-native';
-import { setAndroidNavigationBar } from '~/lib/android-navigation-bar';
-import { MoonStar } from '~/lib/icons/MoonStar';
-import { Sun } from '~/lib/icons/Sun';
-import { useColorScheme } from '~/lib/useColorScheme';
-import { cn } from '~/lib/utils';
+import { setAndroidNavigationBar } from '@/lib/android-navigation-bar';
+import { MoonStar } from '@/lib/icons/MoonStar';
+import { Sun } from '@/lib/icons/Sun';
+import { useColorScheme } from '@/lib/useColorScheme';
+import { cn } from '@/lib/utils';
export function ThemeToggle() {
const { isDarkColorScheme, setColorScheme } = useColorScheme();
diff --git a/components/examples/ProfileCard.tsx b/components/examples/ProfileCard.tsx
new file mode 100644
index 0000000..10bc73e
--- /dev/null
+++ b/components/examples/ProfileCard.tsx
@@ -0,0 +1,97 @@
+// components/examples/ProfileCard.tsx
+import * as React from 'react';
+import { View } from 'react-native';
+import Animated, { FadeInUp, FadeOutDown, LayoutAnimationConfig } from 'react-native-reanimated';
+import { Info } from '@/lib/icons/Info';
+import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
+import { Button } from '@/components/ui/button';
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
+} from '@/components/ui/card';
+import { Progress } from '@/components/ui/progress';
+import { Text } from '@/components/ui/text';
+import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
+
+const GITHUB_AVATAR_URI =
+ 'https://i.pinimg.com/originals/ef/a2/8d/efa28d18a04e7fa40ed49eeb0ab660db.jpg';
+
+export default function ProfileCardExample() {
+ const [progress, setProgress] = React.useState(78);
+
+ function updateProgressValue() {
+ setProgress(Math.floor(Math.random() * 100));
+ }
+
+ return (
+
+
+
+
+
+
+ RS
+
+
+
+ Rick Sanchez
+
+ Scientist
+
+
+
+
+
+ Freelance
+
+
+
+
+
+
+
+ Dimension
+ C-137
+
+
+ Age
+ 70
+
+
+ Species
+ Human
+
+
+
+
+
+ Productivity:
+
+
+ {progress}%
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/exercises/ExerciseCard.tsx b/components/exercises/ExerciseCard.tsx
new file mode 100644
index 0000000..c304a8f
--- /dev/null
+++ b/components/exercises/ExerciseCard.tsx
@@ -0,0 +1,233 @@
+// components/exercises/ExerciseCard.tsx
+import React from 'react';
+import { View, TouchableOpacity, Platform } from 'react-native';
+import { Text } from '@/components/ui/text';
+import { Card, CardContent } from '@/components/ui/card';
+import { Button } from '@/components/ui/button';
+import { Badge } from '@/components/ui/badge';
+import { Trash2, Star } from 'lucide-react-native';
+import {
+ Sheet,
+ SheetContent,
+ SheetHeader,
+ SheetTitle
+} from '@/components/ui/sheet';
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+} from '@/components/ui/alert-dialog';
+import { Exercise } from '@/types/library';
+
+interface ExerciseCardProps extends Exercise {
+ onPress: () => void;
+ onDelete: (id: string) => void;
+ onFavorite?: () => void;
+}
+
+export function ExerciseCard({
+ id,
+ title,
+ category,
+ equipment,
+ description,
+ tags = [],
+ source = 'local',
+ usageCount,
+ lastUsed,
+ onPress,
+ onDelete,
+ onFavorite
+}: ExerciseCardProps) {
+ const [showSheet, setShowSheet] = React.useState(false);
+ const [showDeleteAlert, setShowDeleteAlert] = React.useState(false);
+
+ const handleDeletePress = () => {
+ setShowDeleteAlert(true);
+ };
+
+ const handleConfirmDelete = () => {
+ onDelete(id);
+ setShowDeleteAlert(false);
+ };
+
+ const handleCardPress = () => {
+ setShowSheet(true);
+ onPress();
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+ {title}
+
+
+ {source}
+
+
+
+
+ {category}
+
+ {equipment && (
+
+ {equipment}
+
+ )}
+ {description && (
+
+ {description}
+
+ )}
+
+ {(usageCount || lastUsed) && (
+
+ {usageCount && (
+
+ Used {usageCount} times
+
+ )}
+ {lastUsed && (
+
+ Last used: {lastUsed.toLocaleDateString()}
+
+ )}
+
+ )}
+
+ {tags.length > 0 && (
+
+ {tags.map(tag => (
+
+ {tag}
+
+ ))}
+
+ )}
+
+
+
+ {onFavorite && (
+
+ )}
+
+
+
+
+
+
+
+
+ Delete Exercise
+
+
+ Are you sure you want to delete {title}? This action cannot be undone.
+
+
+
+
+ Cancel
+
+
+ Delete
+
+
+
+
+
+
+
+
+
+
+ {/* Bottom sheet section */}
+ setShowSheet(false)}>
+
+
+ {title}
+
+
+
+
+ {description && (
+
+ Description
+ {description}
+
+ )}
+
+ Details
+
+ Category: {category}
+ {equipment && Equipment: {equipment}}
+ Source: {source}
+
+
+ {(usageCount || lastUsed) && (
+
+ Statistics
+
+ {usageCount && (
+ Used {usageCount} times
+ )}
+ {lastUsed && (
+
+ Last used: {lastUsed.toLocaleDateString()}
+
+ )}
+
+
+ )}
+ {tags.length > 0 && (
+
+ Tags
+
+ {tags.map(tag => (
+
+ {tag}
+
+ ))}
+
+
+ )}
+
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/components/library/FilterSheet.tsx b/components/library/FilterSheet.tsx
new file mode 100644
index 0000000..d604e50
--- /dev/null
+++ b/components/library/FilterSheet.tsx
@@ -0,0 +1,124 @@
+import React from 'react';
+import { View } from 'react-native';
+import { Text } from '@/components/ui/text';
+import { Button } from '@/components/ui/button';
+import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet';
+import { Badge } from '@/components/ui/badge';
+import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
+
+export type SourceType = 'local' | 'powr' | 'nostr';
+
+export interface FilterOptions {
+ equipment: string[];
+ tags: string[];
+ source: SourceType[];
+}
+
+interface FilterSheetProps {
+ isOpen: boolean;
+ onClose: () => void;
+ options: FilterOptions;
+ onApplyFilters: (filters: FilterOptions) => void;
+ availableFilters: {
+ equipment: string[];
+ tags: string[];
+ source: SourceType[];
+ };
+}
+
+function renderFilterSection(
+ title: string,
+ category: keyof FilterOptions,
+ values: T[],
+ selectedValues: T[],
+ onToggle: (category: keyof FilterOptions, value: T) => void
+) {
+ return (
+
+
+
+ {title}
+ {selectedValues.length > 0 && (
+
+ {selectedValues.length}
+
+ )}
+
+
+
+
+ {values.map(value => {
+ const isSelected = selectedValues.includes(value);
+ return (
+
+ );
+ })}
+
+
+
+ );
+}
+
+export function FilterSheet({
+ isOpen,
+ onClose,
+ options,
+ onApplyFilters,
+ availableFilters
+}: FilterSheetProps) {
+ const [localOptions, setLocalOptions] = React.useState(options);
+
+ const toggleFilter = (
+ category: keyof FilterOptions,
+ value: string | SourceType
+ ) => {
+ setLocalOptions(prev => ({
+ ...prev,
+ [category]: prev[category].includes(value as any)
+ ? prev[category].filter(v => v !== value)
+ : [...prev[category], value as any]
+ }));
+ };
+
+ return (
+
+
+ Filter Exercises
+
+
+
+
+ {renderFilterSection('Equipment', 'equipment', availableFilters.equipment, localOptions.equipment, toggleFilter)}
+ {renderFilterSection('Tags', 'tags', availableFilters.tags, localOptions.tags, toggleFilter)}
+ {renderFilterSection('Source', 'source', availableFilters.source, localOptions.source, toggleFilter)}
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/library/NewExerciseSheet.tsx b/components/library/NewExerciseSheet.tsx
new file mode 100644
index 0000000..d339ea3
--- /dev/null
+++ b/components/library/NewExerciseSheet.tsx
@@ -0,0 +1,190 @@
+// components/library/NewExerciseSheet.tsx
+import React from 'react';
+import { View } from 'react-native';
+import { Text } from '@/components/ui/text';
+import { Input } from '@/components/ui/input';
+import { Button } from '@/components/ui/button';
+import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet';
+import { generateId } from '@/utils/ids';
+import { BaseExercise, ExerciseType, ExerciseCategory, Equipment } from '@/types/exercise';
+import { StorageSource } from '@/types/shared';
+
+interface NewExerciseSheetProps {
+ isOpen: boolean;
+ onClose: () => void;
+ onSubmit: (exercise: BaseExercise) => void;
+}
+
+const EXERCISE_TYPES: ExerciseType[] = ['strength', 'cardio', 'bodyweight'];
+const CATEGORIES: ExerciseCategory[] = ['Push', 'Pull', 'Legs', 'Core'];
+const EQUIPMENT_OPTIONS: Equipment[] = [
+ 'bodyweight',
+ 'barbell',
+ 'dumbbell',
+ 'kettlebell',
+ 'machine',
+ 'cable',
+ 'other'
+];
+
+export function NewExerciseSheet({ isOpen, onClose, onSubmit }: NewExerciseSheetProps) {
+ const [formData, setFormData] = React.useState({
+ title: '',
+ type: 'strength' as ExerciseType,
+ category: 'Push' as ExerciseCategory,
+ equipment: undefined as Equipment | undefined,
+ description: '',
+ tags: [] as string[],
+ format: {
+ weight: true,
+ reps: true,
+ rpe: true,
+ set_type: true
+ },
+ format_units: {
+ weight: 'kg' as const,
+ reps: 'count' as const,
+ rpe: '0-10' as const,
+ set_type: 'warmup|normal|drop|failure' as const
+ }
+ });
+
+ const handleSubmit = () => {
+ if (!formData.title || !formData.equipment) return;
+
+ // Cast to any as a temporary workaround for the TypeScript error
+ const exercise = {
+ // BaseExercise properties
+ title: formData.title,
+ type: formData.type,
+ category: formData.category,
+ equipment: formData.equipment,
+ description: formData.description,
+ tags: formData.tags,
+ format: formData.format,
+ format_units: formData.format_units,
+ // SyncableContent properties
+ id: generateId('local'),
+ created_at: Date.now(),
+ availability: {
+ source: ['local' as StorageSource]
+ }
+ } as BaseExercise;
+
+ onSubmit(exercise);
+ onClose();
+
+ // Reset form
+ setFormData({
+ title: '',
+ type: 'strength',
+ category: 'Push',
+ equipment: undefined,
+ description: '',
+ tags: [],
+ format: {
+ weight: true,
+ reps: true,
+ rpe: true,
+ set_type: true
+ },
+ format_units: {
+ weight: 'kg',
+ reps: 'count',
+ rpe: '0-10',
+ set_type: 'warmup|normal|drop|failure'
+ }
+ });
+ };
+
+ return (
+
+
+ New Exercise
+
+
+
+
+ Exercise Name
+ setFormData(prev => ({ ...prev, title: text }))}
+ placeholder="e.g., Barbell Back Squat"
+ />
+
+
+
+ Type
+
+ {EXERCISE_TYPES.map((type) => (
+
+ ))}
+
+
+
+
+ Category
+
+ {CATEGORIES.map((category) => (
+
+ ))}
+
+
+
+
+ Equipment
+
+ {EQUIPMENT_OPTIONS.map((eq) => (
+
+ ))}
+
+
+
+
+ Description
+ setFormData(prev => ({ ...prev, description: text }))}
+ placeholder="Exercise description..."
+ multiline
+ numberOfLines={4}
+ />
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/library/NewTemplateSheet.tsx b/components/library/NewTemplateSheet.tsx
new file mode 100644
index 0000000..91d3046
--- /dev/null
+++ b/components/library/NewTemplateSheet.tsx
@@ -0,0 +1,146 @@
+// components/library/NewTemplateSheet.tsx
+import React from 'react';
+import { View } from 'react-native';
+import { Text } from '@/components/ui/text';
+import { Input } from '@/components/ui/input';
+import { Button } from '@/components/ui/button';
+import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet';
+import { generateId } from '@/utils/ids';
+import { TemplateType, TemplateCategory } from '@/types/library';
+import { cn } from '@/lib/utils';
+
+interface NewTemplateSheetProps {
+ isOpen: boolean;
+ onClose: () => void;
+ onSubmit: (template: Template) => void;
+}
+
+const WORKOUT_TYPES: TemplateType[] = ['strength', 'circuit', 'emom', 'amrap'];
+
+const CATEGORIES: TemplateCategory[] = [
+ 'Full Body',
+ 'Upper/Lower',
+ 'Push/Pull/Legs',
+ 'Cardio',
+ 'CrossFit',
+ 'Strength',
+ 'Conditioning',
+ 'Custom'
+];
+
+export function NewTemplateSheet({ isOpen, onClose, onSubmit }: NewTemplateSheetProps) {
+ const [formData, setFormData] = React.useState({
+ title: '',
+ type: '' as TemplateType,
+ category: '' as TemplateCategory,
+ description: '',
+ });
+
+ const handleSubmit = () => {
+ const template: Template = {
+ id: generateId(),
+ title: formData.title,
+ type: formData.type,
+ category: formData.category,
+ description: formData.description,
+ exercises: [],
+ tags: [],
+ source: 'local',
+ isFavorite: false,
+ created_at: Date.now(),
+ };
+
+ onSubmit(template);
+ onClose();
+ setFormData({
+ title: '',
+ type: '' as TemplateType,
+ category: '' as TemplateCategory,
+ description: '',
+ });
+ };
+
+ return (
+
+
+ New Template
+
+
+
+
+ Template Name
+ setFormData(prev => ({ ...prev, title: text }))}
+ placeholder="e.g., Full Body Strength"
+ />
+
+
+
+ Workout Type
+
+ {WORKOUT_TYPES.map((type) => (
+
+ ))}
+
+
+
+
+ Category
+
+ {CATEGORIES.map((category) => (
+
+ ))}
+
+
+
+
+ Description
+ setFormData(prev => ({ ...prev, description: text }))}
+ placeholder="Template description..."
+ multiline
+ numberOfLines={4}
+ />
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/library/SearchHeader.tsx b/components/library/SearchHeader.tsx
new file mode 100644
index 0000000..29bb224
--- /dev/null
+++ b/components/library/SearchHeader.tsx
@@ -0,0 +1,47 @@
+// components/library/SearchHeader.tsx
+import React from 'react';
+import { View } from 'react-native';
+import { Input } from '@/components/ui/input';
+import { Button } from '@/components/ui/button';
+import { SlidersHorizontal } from 'lucide-react-native';
+import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
+import { Badge } from '@/components/ui/badge';
+import { useTheme } from '@react-navigation/native';
+
+interface SearchHeaderProps {
+ searchQuery: string;
+ onSearchChange: (query: string) => void;
+ activeFilters: number;
+ onOpenFilters: () => void;
+}
+
+export function SearchHeader({ searchQuery, onSearchChange, activeFilters, onOpenFilters }: SearchHeaderProps) {
+ const { colors } = useTheme();
+ return (
+
+
+
+
+ {activeFilters > 0 && (
+
+ {activeFilters}
+
+ )}
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/pager/index.ts b/components/pager/index.ts
new file mode 100644
index 0000000..7cd3703
--- /dev/null
+++ b/components/pager/index.ts
@@ -0,0 +1,14 @@
+// components/pager/index.ts
+import { Platform } from 'react-native';
+import type { PagerProps, PagerRef } from './types';
+
+let PagerComponent: React.ForwardRefExoticComponent>;
+
+if (Platform.OS === 'web') {
+ PagerComponent = require('./pager.web').default;
+} else {
+ PagerComponent = require('./pager.native').default;
+}
+
+export type { PagerProps, PagerRef, PageSelectedEvent } from './types';
+export default PagerComponent;
\ No newline at end of file
diff --git a/components/pager/pager.native.tsx b/components/pager/pager.native.tsx
new file mode 100644
index 0000000..6c30444
--- /dev/null
+++ b/components/pager/pager.native.tsx
@@ -0,0 +1,8 @@
+// components/pager/pager.native.tsx
+import React from 'react';
+import PagerView from 'react-native-pager-view';
+import type { PagerProps, PagerRef } from './types';
+
+const NativePager: React.ForwardRefExoticComponent = PagerView as unknown as React.ForwardRefExoticComponent;
+
+export default NativePager;
\ No newline at end of file
diff --git a/components/pager/pager.web.tsx b/components/pager/pager.web.tsx
new file mode 100644
index 0000000..e74488a
--- /dev/null
+++ b/components/pager/pager.web.tsx
@@ -0,0 +1,70 @@
+// components/pager/pager.web.tsx
+import React from 'react';
+import { ScrollView, StyleSheet, View, useWindowDimensions } from 'react-native';
+import type { PagerProps, PagerRef, PageSelectedEvent } from './types';
+
+const Pager = React.forwardRef(
+ ({ children, onPageSelected, initialPage = 0, style }, ref) => {
+ const scrollRef = React.useRef(null);
+ const [currentPage, setCurrentPage] = React.useState(initialPage);
+ const { width } = useWindowDimensions();
+
+ React.useImperativeHandle(ref, () => ({
+ setPage: (pageNumber: number) => {
+ const scrollView = scrollRef.current;
+ if (scrollView) {
+ const width = scrollView.getInnerViewNode?.()?.getBoundingClientRect?.()?.width ?? 0;
+ scrollView.scrollTo({ x: pageNumber * width, animated: true });
+ }
+ },
+ scrollTo: (options) => {
+ scrollRef.current?.scrollTo(options);
+ }
+ }));
+
+ const handleScroll = (event: any) => {
+ const offsetX = event.nativeEvent.contentOffset.x;
+ const page = Math.round(offsetX / event.nativeEvent.layoutMeasurement.width);
+
+ if (page !== currentPage) {
+ setCurrentPage(page);
+ onPageSelected?.({
+ nativeEvent: { position: page }
+ } as PageSelectedEvent);
+ }
+ };
+
+ React.useEffect(() => {
+ if (initialPage > 0) {
+ scrollRef.current?.scrollTo({
+ x: initialPage * width,
+ animated: false
+ });
+ }
+ }, [initialPage, width]);
+
+ return (
+
+ {React.Children.map(children, (child) => (
+ {child}
+ ))}
+
+ );
+ }
+);
+
+export default Pager;
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+});
\ No newline at end of file
diff --git a/components/pager/types.ts b/components/pager/types.ts
new file mode 100644
index 0000000..7cde2ec
--- /dev/null
+++ b/components/pager/types.ts
@@ -0,0 +1,20 @@
+// components/pager/types.ts
+import { StyleProp, ViewStyle } from 'react-native';
+
+export interface PageSelectedEvent {
+ nativeEvent: {
+ position: number;
+ };
+}
+
+export interface PagerProps {
+ children: React.ReactNode[];
+ style?: StyleProp;
+ initialPage?: number;
+ onPageSelected?: (e: PageSelectedEvent) => void;
+}
+
+export interface PagerRef {
+ setPage: (page: number) => void;
+ scrollTo?: (options: { x: number; animated?: boolean }) => void;
+}
\ No newline at end of file
diff --git a/components/shared/FloatingActionButton.tsx b/components/shared/FloatingActionButton.tsx
new file mode 100644
index 0000000..960020c
--- /dev/null
+++ b/components/shared/FloatingActionButton.tsx
@@ -0,0 +1,35 @@
+// components/shared/FloatingActionButton.tsx
+import React from 'react';
+import { View, ViewStyle } from 'react-native';
+import { LucideIcon, Dumbbell } from 'lucide-react-native';
+import { Button } from '@/components/ui/button';
+
+interface FloatingActionButtonProps {
+ icon?: LucideIcon;
+ onPress?: () => void;
+ className?: string;
+}
+
+export function FloatingActionButton({
+ icon: Icon = Dumbbell,
+ onPress,
+ className,
+ style
+}: FloatingActionButtonProps & { style?: ViewStyle }) {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/templates/TemplateCard.tsx b/components/templates/TemplateCard.tsx
new file mode 100644
index 0000000..915c08e
--- /dev/null
+++ b/components/templates/TemplateCard.tsx
@@ -0,0 +1,248 @@
+// components/templates/TemplateCard.tsx
+import React from 'react';
+import { View, TouchableOpacity, Platform } from 'react-native';
+import { Text } from '@/components/ui/text';
+import { Card, CardContent } from '@/components/ui/card';
+import { Button } from '@/components/ui/button';
+import { Badge } from '@/components/ui/badge';
+import { Trash2, Star, Play } from 'lucide-react-native';
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+} from '@/components/ui/alert-dialog';
+import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet';
+import { Template } from '@/types/library';
+
+interface TemplateCardProps {
+ template: Template;
+ onPress: () => void;
+ onDelete: (id: string) => void;
+ onFavorite: () => void;
+ onStartWorkout: () => void;
+}
+
+export function TemplateCard({
+ template,
+ onPress,
+ onDelete,
+ onFavorite,
+ onStartWorkout
+}: TemplateCardProps) {
+ const [showSheet, setShowSheet] = React.useState(false);
+ const [showDeleteAlert, setShowDeleteAlert] = React.useState(false);
+
+ const {
+ id,
+ title,
+ type,
+ category,
+ exercises,
+ description,
+ tags = [],
+ source,
+ lastUsed,
+ isFavorite
+ } = template;
+
+ const handleConfirmDelete = () => {
+ onDelete(id);
+ setShowDeleteAlert(false);
+ };
+
+ const handleCardPress = () => {
+ setShowSheet(true);
+ onPress();
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+ {title}
+
+
+ {source}
+
+
+
+
+
+ {type}
+
+
+ {category}
+
+
+
+ {exercises.length > 0 && (
+
+
+ Exercises:
+
+
+ {exercises.slice(0, 3).map((exercise, index) => (
+
+ • {exercise.title} ({exercise.targetSets}×{exercise.targetReps})
+
+ ))}
+ {exercises.length > 3 && (
+
+ +{exercises.length - 3} more
+
+ )}
+
+
+ )}
+
+ {description && (
+
+ {description}
+
+ )}
+
+ {tags.length > 0 && (
+
+ {tags.map(tag => (
+
+ {tag}
+
+ ))}
+
+ )}
+
+ {lastUsed && (
+
+ Last used: {lastUsed.toLocaleDateString()}
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+ Delete Template
+
+
+ Are you sure you want to delete {title}? This action cannot be undone.
+
+
+
+
+ Cancel
+
+
+ Delete
+
+
+
+
+
+
+
+
+
+
+ {/* Sheet for detailed view */}
+ setShowSheet(false)}>
+
+
+ {title}
+
+
+
+
+ {description && (
+
+ Description
+ {description}
+
+ )}
+
+ Details
+
+ Type: {type}
+ Category: {category}
+ Source: {source}
+
+
+
+ Exercises
+
+ {exercises.map((exercise, index) => (
+
+ {exercise.title} ({exercise.targetSets}×{exercise.targetReps})
+
+ ))}
+
+
+ {tags.length > 0 && (
+
+ Tags
+
+ {tags.map(tag => (
+
+ {tag}
+
+ ))}
+
+
+ )}
+
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/components/ui/accordion.tsx b/components/ui/accordion.tsx
new file mode 100644
index 0000000..89622df
--- /dev/null
+++ b/components/ui/accordion.tsx
@@ -0,0 +1,125 @@
+import * as AccordionPrimitive from '@rn-primitives/accordion';
+import * as React from 'react';
+import { Platform, Pressable, View } from 'react-native';
+import Animated, {
+ Extrapolation,
+ FadeIn,
+ FadeOutUp,
+ LayoutAnimationConfig,
+ LinearTransition,
+ interpolate,
+ useAnimatedStyle,
+ useDerivedValue,
+ withTiming,
+} from 'react-native-reanimated';
+import { ChevronDown } from '@/lib/icons/ChevronDown';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const Accordion = React.forwardRef(
+ ({ children, ...props }, ref) => {
+ return (
+
+
+ {children}
+
+
+ );
+ }
+);
+
+Accordion.displayName = AccordionPrimitive.Root.displayName;
+
+const AccordionItem = React.forwardRef(
+ ({ className, value, ...props }, ref) => {
+ return (
+
+
+
+ );
+ }
+);
+AccordionItem.displayName = AccordionPrimitive.Item.displayName;
+
+const Trigger = Platform.OS === 'web' ? View : Pressable;
+
+const AccordionTrigger = React.forwardRef<
+ AccordionPrimitive.TriggerRef,
+ AccordionPrimitive.TriggerProps
+>(({ className, children, ...props }, ref) => {
+ const { isExpanded } = AccordionPrimitive.useItemContext();
+
+ const progress = useDerivedValue(() =>
+ isExpanded ? withTiming(1, { duration: 250 }) : withTiming(0, { duration: 200 })
+ );
+ const chevronStyle = useAnimatedStyle(() => ({
+ transform: [{ rotate: `${progress.value * 180}deg` }],
+ opacity: interpolate(progress.value, [0, 1], [1, 0.8], Extrapolation.CLAMP),
+ }));
+
+ return (
+
+
+
+
+ <>{children}>
+
+
+
+
+
+
+
+ );
+});
+AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
+
+const AccordionContent = React.forwardRef<
+ AccordionPrimitive.ContentRef,
+ AccordionPrimitive.ContentProps
+>(({ className, children, ...props }, ref) => {
+ const { isExpanded } = AccordionPrimitive.useItemContext();
+ return (
+
+
+ {children}
+
+
+ );
+});
+
+function InnerContent({ children, className }: { children: React.ReactNode; className?: string }) {
+ if (Platform.OS === 'web') {
+ return {children};
+ }
+ return (
+
+ {children}
+
+ );
+}
+
+AccordionContent.displayName = AccordionPrimitive.Content.displayName;
+
+export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx
new file mode 100644
index 0000000..18c09d3
--- /dev/null
+++ b/components/ui/alert-dialog.tsx
@@ -0,0 +1,160 @@
+import * as AlertDialogPrimitive from '@rn-primitives/alert-dialog';
+import * as React from 'react';
+import { Platform, StyleSheet, View, type ViewProps } from 'react-native';
+import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
+import { buttonTextVariants, buttonVariants } from '@/components/ui/button';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const AlertDialog = AlertDialogPrimitive.Root;
+
+const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
+
+const AlertDialogPortal = AlertDialogPrimitive.Portal;
+
+const AlertDialogOverlayWeb = React.forwardRef<
+ AlertDialogPrimitive.OverlayRef,
+ AlertDialogPrimitive.OverlayProps
+>(({ className, ...props }, ref) => {
+ const { open } = AlertDialogPrimitive.useRootContext();
+ return (
+
+ );
+});
+
+AlertDialogOverlayWeb.displayName = 'AlertDialogOverlayWeb';
+
+const AlertDialogOverlayNative = React.forwardRef<
+ AlertDialogPrimitive.OverlayRef,
+ AlertDialogPrimitive.OverlayProps
+>(({ className, children, ...props }, ref) => {
+ return (
+
+
+ {children}
+
+
+ );
+});
+
+AlertDialogOverlayNative.displayName = 'AlertDialogOverlayNative';
+
+const AlertDialogOverlay = Platform.select({
+ web: AlertDialogOverlayWeb,
+ default: AlertDialogOverlayNative,
+});
+
+const AlertDialogContent = React.forwardRef<
+ AlertDialogPrimitive.ContentRef,
+ AlertDialogPrimitive.ContentProps & { portalHost?: string }
+>(({ className, portalHost, ...props }, ref) => {
+ const { open } = AlertDialogPrimitive.useRootContext();
+
+ return (
+
+
+
+
+
+ );
+});
+AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
+
+const AlertDialogHeader = ({ className, ...props }: ViewProps) => (
+
+);
+AlertDialogHeader.displayName = 'AlertDialogHeader';
+
+const AlertDialogFooter = ({ className, ...props }: ViewProps) => (
+
+);
+AlertDialogFooter.displayName = 'AlertDialogFooter';
+
+const AlertDialogTitle = React.forwardRef<
+ AlertDialogPrimitive.TitleRef,
+ AlertDialogPrimitive.TitleProps
+>(({ className, ...props }, ref) => (
+
+));
+AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
+
+const AlertDialogDescription = React.forwardRef<
+ AlertDialogPrimitive.DescriptionRef,
+ AlertDialogPrimitive.DescriptionProps
+>(({ className, ...props }, ref) => (
+
+));
+AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
+
+const AlertDialogAction = React.forwardRef<
+ AlertDialogPrimitive.ActionRef,
+ AlertDialogPrimitive.ActionProps
+>(({ className, ...props }, ref) => (
+
+
+
+));
+AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
+
+const AlertDialogCancel = React.forwardRef<
+ AlertDialogPrimitive.CancelRef,
+ AlertDialogPrimitive.CancelProps
+>(({ className, ...props }, ref) => (
+
+
+
+));
+AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
+
+export {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogOverlay,
+ AlertDialogPortal,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+};
diff --git a/components/ui/alert.tsx b/components/ui/alert.tsx
new file mode 100644
index 0000000..155f6e8
--- /dev/null
+++ b/components/ui/alert.tsx
@@ -0,0 +1,75 @@
+import { useTheme } from '@react-navigation/native';
+import { cva, type VariantProps } from 'class-variance-authority';
+import type { LucideIcon } from 'lucide-react-native';
+import * as React from 'react';
+import { View, type ViewProps } from 'react-native';
+import { cn } from '@/lib/utils';
+import { Text } from '@/components/ui/text';
+
+const alertVariants = cva(
+ 'relative bg-background w-full rounded-lg border border-border p-4 shadow shadow-foreground/10',
+ {
+ variants: {
+ variant: {
+ default: '',
+ destructive: 'border-destructive',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ },
+ }
+);
+
+const Alert = React.forwardRef<
+ React.ElementRef,
+ ViewProps &
+ VariantProps & {
+ icon: LucideIcon;
+ iconSize?: number;
+ iconClassName?: string;
+ }
+>(({ className, variant, children, icon: Icon, iconSize = 16, iconClassName, ...props }, ref) => {
+ const { colors } = useTheme();
+ return (
+
+
+
+
+ {children}
+
+ );
+});
+Alert.displayName = 'Alert';
+
+const AlertTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+AlertTitle.displayName = 'AlertTitle';
+
+const AlertDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+AlertDescription.displayName = 'AlertDescription';
+
+export { Alert, AlertDescription, AlertTitle };
diff --git a/components/ui/aspect-ratio.tsx b/components/ui/aspect-ratio.tsx
new file mode 100644
index 0000000..d5f98c2
--- /dev/null
+++ b/components/ui/aspect-ratio.tsx
@@ -0,0 +1,5 @@
+import * as AspectRatioPrimitive from '@rn-primitives/aspect-ratio';
+
+const AspectRatio = AspectRatioPrimitive.Root;
+
+export { AspectRatio };
diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx
index b2343d7..98090d3 100644
--- a/components/ui/avatar.tsx
+++ b/components/ui/avatar.tsx
@@ -1,6 +1,6 @@
import * as AvatarPrimitive from '@rn-primitives/avatar';
import * as React from 'react';
-import { cn } from '~/lib/utils';
+import { cn } from '@/lib/utils';
const AvatarPrimitiveRoot = AvatarPrimitive.Root;
const AvatarPrimitiveImage = AvatarPrimitive.Image;
diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx
new file mode 100644
index 0000000..fbb6a95
--- /dev/null
+++ b/components/ui/badge.tsx
@@ -0,0 +1,51 @@
+import * as Slot from '@rn-primitives/slot';
+import type { SlottableViewProps } from '@rn-primitives/types';
+import { cva, type VariantProps } from 'class-variance-authority';
+import { View } from 'react-native';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const badgeVariants = cva(
+ 'web:inline-flex items-center rounded-full border border-border px-2.5 py-0.5 web:transition-colors web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2',
+ {
+ variants: {
+ variant: {
+ default: 'border-transparent bg-primary web:hover:opacity-80 active:opacity-80',
+ secondary: 'border-transparent bg-secondary web:hover:opacity-80 active:opacity-80',
+ destructive: 'border-transparent bg-destructive web:hover:opacity-80 active:opacity-80',
+ outline: 'text-foreground',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ },
+ }
+);
+
+const badgeTextVariants = cva('text-xs font-semibold ', {
+ variants: {
+ variant: {
+ default: 'text-primary-foreground',
+ secondary: 'text-secondary-foreground',
+ destructive: 'text-destructive-foreground',
+ outline: 'text-foreground',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ },
+});
+
+type BadgeProps = SlottableViewProps & VariantProps;
+
+function Badge({ className, variant, asChild, ...props }: BadgeProps) {
+ const Component = asChild ? Slot.View : View;
+ return (
+
+
+
+ );
+}
+
+export { Badge, badgeTextVariants, badgeVariants };
+export type { BadgeProps };
diff --git a/components/ui/button.tsx b/components/ui/button.tsx
index 5e0e4a0..e4e0ac5 100644
--- a/components/ui/button.tsx
+++ b/components/ui/button.tsx
@@ -1,8 +1,16 @@
+// lib/constants.ts - First update the CUSTOM_COLORS
+export const CUSTOM_COLORS = {
+ purple: '#8B5CF6',
+ purplePressed: '#7C3AED', // Slightly darker for pressed state
+ orange: '#F97316'
+} as const;
+
+// components/ui/button.tsx
import { cva, type VariantProps } from 'class-variance-authority';
import * as React from 'react';
import { Pressable } from 'react-native';
-import { TextClassContext } from '~/components/ui/text';
-import { cn } from '~/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+import { cn } from '@/lib/utils';
const buttonVariants = cva(
'group flex items-center justify-center rounded-md web:ring-offset-background web:transition-colors web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2',
@@ -15,7 +23,8 @@ const buttonVariants = cva(
'border border-input bg-background web:hover:bg-accent web:hover:text-accent-foreground active:bg-accent',
secondary: 'bg-secondary web:hover:opacity-80 active:opacity-80',
ghost: 'web:hover:bg-accent web:hover:text-accent-foreground active:bg-accent',
- link: 'web:underline-offset-4 web:hover:underline web:focus:underline ',
+ link: 'web:underline-offset-4 web:hover:underline web:focus:underline',
+ purple: 'bg-[#8B5CF6] web:hover:bg-[#7C3AED] active:bg-[#7C3AED]', // Added purple variant
},
size: {
default: 'h-10 px-4 py-2 native:h-12 native:px-5 native:py-3',
@@ -42,6 +51,7 @@ const buttonTextVariants = cva(
secondary: 'text-secondary-foreground group-active:text-secondary-foreground',
ghost: 'group-active:text-accent-foreground',
link: 'text-primary group-active:underline',
+ purple: 'text-white', // Added purple variant text color
},
size: {
default: '',
@@ -57,6 +67,7 @@ const buttonTextVariants = cva(
}
);
+// Rest of the code remains the same
type ButtonProps = React.ComponentPropsWithoutRef &
VariantProps;
@@ -85,4 +96,4 @@ const Button = React.forwardRef, ButtonProps>
Button.displayName = 'Button';
export { Button, buttonTextVariants, buttonVariants };
-export type { ButtonProps };
+export type { ButtonProps };
\ No newline at end of file
diff --git a/components/ui/card.tsx b/components/ui/card.tsx
index 9f190c2..72f6abf 100644
--- a/components/ui/card.tsx
+++ b/components/ui/card.tsx
@@ -1,8 +1,8 @@
import type { TextRef, ViewRef } from '@rn-primitives/types';
import * as React from 'react';
import { Text, TextProps, View, ViewProps } from 'react-native';
-import { TextClassContext } from '~/components/ui/text';
-import { cn } from '~/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+import { cn } from '@/lib/utils';
const Card = React.forwardRef(({ className, ...props }, ref) => (
(
+ ({ className, ...props }, ref) => {
+ return (
+
+
+
+
+
+ );
+ }
+);
+Checkbox.displayName = CheckboxPrimitive.Root.displayName;
+
+export { Checkbox };
diff --git a/components/ui/collapsible.tsx b/components/ui/collapsible.tsx
new file mode 100644
index 0000000..a2d66dd
--- /dev/null
+++ b/components/ui/collapsible.tsx
@@ -0,0 +1,9 @@
+import * as CollapsiblePrimitive from '@rn-primitives/collapsible';
+
+const Collapsible = CollapsiblePrimitive.Root;
+
+const CollapsibleTrigger = CollapsiblePrimitive.Trigger;
+
+const CollapsibleContent = CollapsiblePrimitive.Content;
+
+export { Collapsible, CollapsibleTrigger, CollapsibleContent };
diff --git a/components/ui/context-menu.tsx b/components/ui/context-menu.tsx
new file mode 100644
index 0000000..2ea29bf
--- /dev/null
+++ b/components/ui/context-menu.tsx
@@ -0,0 +1,245 @@
+import * as ContextMenuPrimitive from '@rn-primitives/context-menu';
+import * as React from 'react';
+import {
+ Platform,
+ type StyleProp,
+ StyleSheet,
+ Text,
+ type TextProps,
+ View,
+ type ViewStyle,
+} from 'react-native';
+import { Check } from '@/lib/icons/Check';
+import { ChevronDown } from '@/lib/icons/ChevronDown';
+import { ChevronRight } from '@/lib/icons/ChevronRight';
+import { ChevronUp } from '@/lib/icons/ChevronUp';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const ContextMenu = ContextMenuPrimitive.Root;
+const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
+const ContextMenuGroup = ContextMenuPrimitive.Group;
+const ContextMenuSub = ContextMenuPrimitive.Sub;
+const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
+
+const ContextMenuSubTrigger = React.forwardRef<
+ ContextMenuPrimitive.SubTriggerRef,
+ ContextMenuPrimitive.SubTriggerProps & {
+ inset?: boolean;
+ }
+>(({ className, inset, children, ...props }, ref) => {
+ const { open } = ContextMenuPrimitive.useSubContext();
+ const Icon = Platform.OS === 'web' ? ChevronRight : open ? ChevronUp : ChevronDown;
+ return (
+
+
+ <>{children}>
+
+
+
+ );
+});
+ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
+
+const ContextMenuSubContent = React.forwardRef<
+ ContextMenuPrimitive.SubContentRef,
+ ContextMenuPrimitive.SubContentProps
+>(({ className, ...props }, ref) => {
+ const { open } = ContextMenuPrimitive.useSubContext();
+ return (
+
+ );
+});
+ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
+
+const ContextMenuContent = React.forwardRef<
+ ContextMenuPrimitive.ContentRef,
+ ContextMenuPrimitive.ContentProps & {
+ overlayStyle?: StyleProp;
+ overlayClassName?: string;
+ portalHost?: string;
+ }
+>(({ className, overlayClassName, overlayStyle, portalHost, ...props }, ref) => {
+ const { open } = ContextMenuPrimitive.useRootContext();
+ return (
+
+
+
+
+
+ );
+});
+ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
+
+const ContextMenuItem = React.forwardRef<
+ ContextMenuPrimitive.ItemRef,
+ ContextMenuPrimitive.ItemProps & {
+ inset?: boolean;
+ }
+>(({ className, inset, ...props }, ref) => (
+
+
+
+));
+ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
+
+const ContextMenuCheckboxItem = React.forwardRef<
+ ContextMenuPrimitive.CheckboxItemRef,
+ ContextMenuPrimitive.CheckboxItemProps
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+ <>{children}>
+
+));
+ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;
+
+const ContextMenuRadioItem = React.forwardRef<
+ ContextMenuPrimitive.RadioItemRef,
+ ContextMenuPrimitive.RadioItemProps
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+ <>{children}>
+
+));
+ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
+
+const ContextMenuLabel = React.forwardRef<
+ ContextMenuPrimitive.LabelRef,
+ ContextMenuPrimitive.LabelProps & {
+ inset?: boolean;
+ }
+>(({ className, inset, ...props }, ref) => (
+
+));
+ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
+
+const ContextMenuSeparator = React.forwardRef<
+ ContextMenuPrimitive.SeparatorRef,
+ ContextMenuPrimitive.SeparatorProps
+>(({ className, ...props }, ref) => (
+
+));
+ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
+
+const ContextMenuShortcut = ({ className, ...props }: TextProps) => {
+ return (
+
+ );
+};
+ContextMenuShortcut.displayName = 'ContextMenuShortcut';
+
+export {
+ ContextMenu,
+ ContextMenuCheckboxItem,
+ ContextMenuContent,
+ ContextMenuGroup,
+ ContextMenuItem,
+ ContextMenuLabel,
+ ContextMenuRadioGroup,
+ ContextMenuRadioItem,
+ ContextMenuSeparator,
+ ContextMenuShortcut,
+ ContextMenuSub,
+ ContextMenuSubContent,
+ ContextMenuSubTrigger,
+ ContextMenuTrigger,
+};
diff --git a/components/ui/dialog.tsx b/components/ui/dialog.tsx
new file mode 100644
index 0000000..1937352
--- /dev/null
+++ b/components/ui/dialog.tsx
@@ -0,0 +1,147 @@
+import * as DialogPrimitive from '@rn-primitives/dialog';
+import * as React from 'react';
+import { Platform, StyleSheet, View, type ViewProps } from 'react-native';
+import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
+import { X } from '@/lib/icons/X';
+import { cn } from '@/lib/utils';
+
+const Dialog = DialogPrimitive.Root;
+
+const DialogTrigger = DialogPrimitive.Trigger;
+
+const DialogPortal = DialogPrimitive.Portal;
+
+const DialogClose = DialogPrimitive.Close;
+
+const DialogOverlayWeb = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ const { open } = DialogPrimitive.useRootContext();
+ return (
+
+ );
+ }
+);
+
+DialogOverlayWeb.displayName = 'DialogOverlayWeb';
+
+const DialogOverlayNative = React.forwardRef<
+ DialogPrimitive.OverlayRef,
+ DialogPrimitive.OverlayProps
+>(({ className, children, ...props }, ref) => {
+ return (
+
+
+ <>{children}>
+
+
+ );
+});
+
+DialogOverlayNative.displayName = 'DialogOverlayNative';
+
+const DialogOverlay = Platform.select({
+ web: DialogOverlayWeb,
+ default: DialogOverlayNative,
+});
+
+const DialogContent = React.forwardRef<
+ DialogPrimitive.ContentRef,
+ DialogPrimitive.ContentProps & { portalHost?: string }
+>(({ className, children, portalHost, ...props }, ref) => {
+ const { open } = DialogPrimitive.useRootContext();
+ return (
+
+
+
+ {children}
+
+
+
+
+
+
+ );
+});
+DialogContent.displayName = DialogPrimitive.Content.displayName;
+
+const DialogHeader = ({ className, ...props }: ViewProps) => (
+
+);
+DialogHeader.displayName = 'DialogHeader';
+
+const DialogFooter = ({ className, ...props }: ViewProps) => (
+
+);
+DialogFooter.displayName = 'DialogFooter';
+
+const DialogTitle = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+DialogTitle.displayName = DialogPrimitive.Title.displayName;
+
+const DialogDescription = React.forwardRef<
+ DialogPrimitive.DescriptionRef,
+ DialogPrimitive.DescriptionProps
+>(({ className, ...props }, ref) => (
+
+));
+DialogDescription.displayName = DialogPrimitive.Description.displayName;
+
+export {
+ Dialog,
+ DialogClose,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogOverlay,
+ DialogPortal,
+ DialogTitle,
+ DialogTrigger,
+};
diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx
new file mode 100644
index 0000000..e9d98a6
--- /dev/null
+++ b/components/ui/dropdown-menu.tsx
@@ -0,0 +1,253 @@
+import * as DropdownMenuPrimitive from '@rn-primitives/dropdown-menu';
+import * as React from 'react';
+import {
+ Platform,
+ type StyleProp,
+ StyleSheet,
+ Text,
+ type TextProps,
+ View,
+ type ViewStyle,
+} from 'react-native';
+import { Check } from '@/lib/icons/Check';
+import { ChevronDown } from '@/lib/icons/ChevronDown';
+import { ChevronRight } from '@/lib/icons/ChevronRight';
+import { ChevronUp } from '@/lib/icons/ChevronUp';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const DropdownMenu = DropdownMenuPrimitive.Root;
+
+const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
+
+const DropdownMenuGroup = DropdownMenuPrimitive.Group;
+
+const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
+
+const DropdownMenuSub = DropdownMenuPrimitive.Sub;
+
+const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
+
+const DropdownMenuSubTrigger = React.forwardRef<
+ DropdownMenuPrimitive.SubTriggerRef,
+ DropdownMenuPrimitive.SubTriggerProps & {
+ inset?: boolean;
+ }
+>(({ className, inset, children, ...props }, ref) => {
+ const { open } = DropdownMenuPrimitive.useSubContext();
+ const Icon = Platform.OS === 'web' ? ChevronRight : open ? ChevronUp : ChevronDown;
+ return (
+
+
+ <>{children}>
+
+
+
+ );
+});
+DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
+
+const DropdownMenuSubContent = React.forwardRef<
+ DropdownMenuPrimitive.SubContentRef,
+ DropdownMenuPrimitive.SubContentProps
+>(({ className, ...props }, ref) => {
+ const { open } = DropdownMenuPrimitive.useSubContext();
+ return (
+
+ );
+});
+DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
+
+const DropdownMenuContent = React.forwardRef<
+ DropdownMenuPrimitive.ContentRef,
+ DropdownMenuPrimitive.ContentProps & {
+ overlayStyle?: StyleProp;
+ overlayClassName?: string;
+ portalHost?: string;
+ }
+>(({ className, overlayClassName, overlayStyle, portalHost, ...props }, ref) => {
+ const { open } = DropdownMenuPrimitive.useRootContext();
+ return (
+
+
+
+
+
+ );
+});
+DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
+
+const DropdownMenuItem = React.forwardRef<
+ DropdownMenuPrimitive.ItemRef,
+ DropdownMenuPrimitive.ItemProps & {
+ inset?: boolean;
+ }
+>(({ className, inset, ...props }, ref) => (
+
+
+
+));
+DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
+
+const DropdownMenuCheckboxItem = React.forwardRef<
+ DropdownMenuPrimitive.CheckboxItemRef,
+ DropdownMenuPrimitive.CheckboxItemProps
+>(({ className, children, checked, ...props }, ref) => (
+
+
+
+
+
+
+ <>{children}>
+
+));
+DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
+
+const DropdownMenuRadioItem = React.forwardRef<
+ DropdownMenuPrimitive.RadioItemRef,
+ DropdownMenuPrimitive.RadioItemProps
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+ <>{children}>
+
+));
+DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
+
+const DropdownMenuLabel = React.forwardRef<
+ DropdownMenuPrimitive.LabelRef,
+ DropdownMenuPrimitive.LabelProps & {
+ inset?: boolean;
+ }
+>(({ className, inset, ...props }, ref) => (
+
+));
+DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
+
+const DropdownMenuSeparator = React.forwardRef<
+ DropdownMenuPrimitive.SeparatorRef,
+ DropdownMenuPrimitive.SeparatorProps
+>(({ className, ...props }, ref) => (
+
+));
+DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
+
+const DropdownMenuShortcut = ({ className, ...props }: TextProps) => {
+ return (
+
+ );
+};
+DropdownMenuShortcut.displayName = 'DropdownMenuShortcut';
+
+export {
+ DropdownMenu,
+ DropdownMenuCheckboxItem,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuPortal,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubContent,
+ DropdownMenuSubTrigger,
+ DropdownMenuTrigger,
+};
diff --git a/components/ui/hover-card.tsx b/components/ui/hover-card.tsx
new file mode 100644
index 0000000..3ab52c3
--- /dev/null
+++ b/components/ui/hover-card.tsx
@@ -0,0 +1,45 @@
+import * as HoverCardPrimitive from '@rn-primitives/hover-card';
+import * as React from 'react';
+import { Platform, StyleSheet } from 'react-native';
+import Animated, { FadeIn } from 'react-native-reanimated';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const HoverCard = HoverCardPrimitive.Root;
+
+const HoverCardTrigger = HoverCardPrimitive.Trigger;
+
+const HoverCardContent = React.forwardRef<
+ HoverCardPrimitive.ContentRef,
+ HoverCardPrimitive.ContentProps
+>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => {
+ const { open } = HoverCardPrimitive.useRootContext();
+ return (
+
+
+
+
+
+
+
+
+
+ );
+});
+HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
+
+export { HoverCard, HoverCardContent, HoverCardTrigger };
diff --git a/components/ui/input.tsx b/components/ui/input.tsx
new file mode 100644
index 0000000..835d37e
--- /dev/null
+++ b/components/ui/input.tsx
@@ -0,0 +1,40 @@
+import * as React from 'react';
+import { TextInput, type TextInputProps } from 'react-native';
+import { cn } from '@/lib/utils';
+
+const Input = React.forwardRef, TextInputProps>(
+ ({ className, placeholderClassName, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+
+Input.displayName = 'Input';
+
+export { Input };
\ No newline at end of file
diff --git a/components/ui/label.tsx b/components/ui/label.tsx
new file mode 100644
index 0000000..1655e47
--- /dev/null
+++ b/components/ui/label.tsx
@@ -0,0 +1,27 @@
+import * as LabelPrimitive from '@rn-primitives/label';
+import * as React from 'react';
+import { cn } from '@/lib/utils';
+
+const Label = React.forwardRef(
+ ({ className, onPress, onLongPress, onPressIn, onPressOut, ...props }, ref) => (
+
+
+
+ )
+);
+Label.displayName = LabelPrimitive.Root.displayName;
+
+export { Label };
diff --git a/components/ui/menubar.tsx b/components/ui/menubar.tsx
new file mode 100644
index 0000000..a8b539b
--- /dev/null
+++ b/components/ui/menubar.tsx
@@ -0,0 +1,261 @@
+import * as MenubarPrimitive from '@rn-primitives/menubar';
+import * as React from 'react';
+import { Platform, Text, type TextProps, View } from 'react-native';
+import { Check } from '@/lib/icons/Check';
+import { ChevronDown } from '@/lib/icons/ChevronDown';
+import { ChevronRight } from '@/lib/icons/ChevronRight';
+import { ChevronUp } from '@/lib/icons/ChevronUp';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const MenubarMenu = MenubarPrimitive.Menu;
+
+const MenubarGroup = MenubarPrimitive.Group;
+
+const MenubarPortal = MenubarPrimitive.Portal;
+
+const MenubarSub = MenubarPrimitive.Sub;
+
+const MenubarRadioGroup = MenubarPrimitive.RadioGroup;
+
+const Menubar = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+Menubar.displayName = MenubarPrimitive.Root.displayName;
+
+const MenubarTrigger = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ const { value } = MenubarPrimitive.useRootContext();
+ const { value: itemValue } = MenubarPrimitive.useMenuContext();
+
+ return (
+
+ );
+ }
+);
+MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName;
+
+const MenubarSubTrigger = React.forwardRef<
+ MenubarPrimitive.SubTriggerRef,
+ MenubarPrimitive.SubTriggerProps & {
+ inset?: boolean;
+ }
+>(({ className, inset, children, ...props }, ref) => {
+ const { open } = MenubarPrimitive.useSubContext();
+ const Icon = Platform.OS === 'web' ? ChevronRight : open ? ChevronUp : ChevronDown;
+ return (
+
+
+ <>{children}>
+
+
+
+ );
+});
+MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName;
+
+const MenubarSubContent = React.forwardRef<
+ MenubarPrimitive.SubContentRef,
+ MenubarPrimitive.SubContentProps
+>(({ className, ...props }, ref) => {
+ const { open } = MenubarPrimitive.useSubContext();
+ return (
+
+ );
+});
+MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;
+
+const MenubarContent = React.forwardRef<
+ MenubarPrimitive.ContentRef,
+ MenubarPrimitive.ContentProps & { portalHost?: string }
+>(({ className, portalHost, ...props }, ref) => {
+ const { value } = MenubarPrimitive.useRootContext();
+ const { value: itemValue } = MenubarPrimitive.useMenuContext();
+ return (
+
+
+
+ );
+});
+MenubarContent.displayName = MenubarPrimitive.Content.displayName;
+
+const MenubarItem = React.forwardRef<
+ MenubarPrimitive.ItemRef,
+ MenubarPrimitive.ItemProps & {
+ inset?: boolean;
+ }
+>(({ className, inset, ...props }, ref) => (
+
+
+
+));
+MenubarItem.displayName = MenubarPrimitive.Item.displayName;
+
+const MenubarCheckboxItem = React.forwardRef<
+ MenubarPrimitive.CheckboxItemRef,
+ MenubarPrimitive.CheckboxItemProps
+>(({ className, children, checked, ...props }, ref) => (
+
+
+
+
+
+
+ <>{children}>
+
+));
+MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName;
+
+const MenubarRadioItem = React.forwardRef<
+ MenubarPrimitive.RadioItemRef,
+ MenubarPrimitive.RadioItemProps
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+ <>{children}>
+
+));
+MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName;
+
+const MenubarLabel = React.forwardRef<
+ MenubarPrimitive.LabelRef,
+ MenubarPrimitive.LabelProps & {
+ inset?: boolean;
+ }
+>(({ className, inset, ...props }, ref) => (
+
+));
+MenubarLabel.displayName = MenubarPrimitive.Label.displayName;
+
+const MenubarSeparator = React.forwardRef<
+ MenubarPrimitive.SeparatorRef,
+ MenubarPrimitive.SeparatorProps
+>(({ className, ...props }, ref) => (
+
+));
+MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName;
+
+const MenubarShortcut = ({ className, ...props }: TextProps) => {
+ return (
+
+ );
+};
+MenubarShortcut.displayName = 'MenubarShortcut';
+
+export {
+ Menubar,
+ MenubarCheckboxItem,
+ MenubarContent,
+ MenubarGroup,
+ MenubarItem,
+ MenubarLabel,
+ MenubarMenu,
+ MenubarPortal,
+ MenubarRadioGroup,
+ MenubarRadioItem,
+ MenubarSeparator,
+ MenubarShortcut,
+ MenubarSub,
+ MenubarSubContent,
+ MenubarSubTrigger,
+ MenubarTrigger,
+};
diff --git a/components/ui/navigation-menu.tsx b/components/ui/navigation-menu.tsx
new file mode 100644
index 0000000..8afd151
--- /dev/null
+++ b/components/ui/navigation-menu.tsx
@@ -0,0 +1,181 @@
+import * as NavigationMenuPrimitive from '@rn-primitives/navigation-menu';
+import { cva } from 'class-variance-authority';
+import * as React from 'react';
+import { Platform, View } from 'react-native';
+import Animated, {
+ Extrapolation,
+ FadeInLeft,
+ FadeOutLeft,
+ interpolate,
+ useAnimatedStyle,
+ useDerivedValue,
+ withTiming,
+} from 'react-native-reanimated';
+import { ChevronDown } from '@/lib/icons/ChevronDown';
+import { cn } from '@/lib/utils';
+
+const NavigationMenu = React.forwardRef<
+ NavigationMenuPrimitive.RootRef,
+ NavigationMenuPrimitive.RootProps
+>(({ className, children, ...props }, ref) => (
+
+ {children}
+ {Platform.OS === 'web' && }
+
+));
+NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
+
+const NavigationMenuList = React.forwardRef<
+ NavigationMenuPrimitive.ListRef,
+ NavigationMenuPrimitive.ListProps
+>(({ className, ...props }, ref) => (
+
+));
+NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
+
+const NavigationMenuItem = NavigationMenuPrimitive.Item;
+
+const navigationMenuTriggerStyle = cva(
+ 'web:group web:inline-flex flex-row h-10 native:h-12 native:px-3 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium web:transition-colors web:hover:bg-accent active:bg-accent web:hover:text-accent-foreground web:focus:bg-accent web:focus:text-accent-foreground web:focus:outline-none web:disabled:pointer-events-none disabled:opacity-50 web:data-[active]:bg-accent/50 web:data-[state=open]:bg-accent/50'
+);
+
+const NavigationMenuTrigger = React.forwardRef<
+ NavigationMenuPrimitive.TriggerRef,
+ NavigationMenuPrimitive.TriggerProps
+>(({ className, children, ...props }, ref) => {
+ const { value } = NavigationMenuPrimitive.useRootContext();
+ const { value: itemValue } = NavigationMenuPrimitive.useItemContext();
+
+ const progress = useDerivedValue(() =>
+ value === itemValue ? withTiming(1, { duration: 250 }) : withTiming(0, { duration: 200 })
+ );
+ const chevronStyle = useAnimatedStyle(() => ({
+ transform: [{ rotate: `${progress.value * 180}deg` }],
+ opacity: interpolate(progress.value, [0, 1], [1, 0.8], Extrapolation.CLAMP),
+ }));
+
+ return (
+
+ <>{children}>
+
+
+
+
+ );
+});
+NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
+
+const NavigationMenuContent = React.forwardRef<
+ NavigationMenuPrimitive.ContentRef,
+ NavigationMenuPrimitive.ContentProps & {
+ portalHost?: string;
+ }
+>(({ className, children, portalHost, ...props }, ref) => {
+ const { value } = NavigationMenuPrimitive.useRootContext();
+ const { value: itemValue } = NavigationMenuPrimitive.useItemContext();
+ return (
+
+
+
+ {children}
+
+
+
+ );
+});
+NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
+
+const NavigationMenuLink = NavigationMenuPrimitive.Link;
+
+const NavigationMenuViewport = React.forwardRef<
+ NavigationMenuPrimitive.ViewportRef,
+ NavigationMenuPrimitive.ViewportProps
+>(({ className, ...props }, ref) => {
+ return (
+
+
+
+
+
+ );
+});
+NavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName;
+
+const NavigationMenuIndicator = React.forwardRef<
+ NavigationMenuPrimitive.IndicatorRef,
+ NavigationMenuPrimitive.IndicatorProps
+>(({ className, ...props }, ref) => {
+ const { value } = NavigationMenuPrimitive.useRootContext();
+ const { value: itemValue } = NavigationMenuPrimitive.useItemContext();
+
+ return (
+
+
+
+ );
+});
+NavigationMenuIndicator.displayName = NavigationMenuPrimitive.Indicator.displayName;
+
+export {
+ NavigationMenu,
+ NavigationMenuContent,
+ NavigationMenuIndicator,
+ NavigationMenuItem,
+ NavigationMenuLink,
+ NavigationMenuList,
+ NavigationMenuTrigger,
+ navigationMenuTriggerStyle,
+ NavigationMenuViewport,
+};
diff --git a/components/ui/popover.tsx b/components/ui/popover.tsx
new file mode 100644
index 0000000..fced000
--- /dev/null
+++ b/components/ui/popover.tsx
@@ -0,0 +1,39 @@
+import * as PopoverPrimitive from '@rn-primitives/popover';
+import * as React from 'react';
+import { Platform, StyleSheet } from 'react-native';
+import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const Popover = PopoverPrimitive.Root;
+
+const PopoverTrigger = PopoverPrimitive.Trigger;
+
+const PopoverContent = React.forwardRef<
+ PopoverPrimitive.ContentRef,
+ PopoverPrimitive.ContentProps & { portalHost?: string }
+>(({ className, align = 'center', sideOffset = 4, portalHost, ...props }, ref) => {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+});
+PopoverContent.displayName = PopoverPrimitive.Content.displayName;
+
+export { Popover, PopoverContent, PopoverTrigger };
diff --git a/components/ui/progress.tsx b/components/ui/progress.tsx
index f73bf40..cd53b7d 100644
--- a/components/ui/progress.tsx
+++ b/components/ui/progress.tsx
@@ -8,7 +8,7 @@ import Animated, {
useDerivedValue,
withSpring,
} from 'react-native-reanimated';
-import { cn } from '~/lib/utils';
+import { cn } from '@/lib/utils';
const Progress = React.forwardRef<
ProgressPrimitive.RootRef,
diff --git a/components/ui/radio-group.tsx b/components/ui/radio-group.tsx
new file mode 100644
index 0000000..575abac
--- /dev/null
+++ b/components/ui/radio-group.tsx
@@ -0,0 +1,36 @@
+import * as RadioGroupPrimitive from '@rn-primitives/radio-group';
+import * as React from 'react';
+import { View } from 'react-native';
+import { cn } from '@/lib/utils';
+
+const RadioGroup = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
+
+const RadioGroupItem = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ return (
+
+
+
+
+
+ );
+ }
+);
+RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
+
+export { RadioGroup, RadioGroupItem };
diff --git a/components/ui/select.tsx b/components/ui/select.tsx
new file mode 100644
index 0000000..4329e82
--- /dev/null
+++ b/components/ui/select.tsx
@@ -0,0 +1,173 @@
+import * as SelectPrimitive from '@rn-primitives/select';
+import * as React from 'react';
+import { Platform, StyleSheet, View } from 'react-native';
+import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
+import { Check } from '@/lib/icons/Check';
+import { ChevronDown } from '@/lib/icons/ChevronDown';
+import { ChevronUp } from '@/lib/icons/ChevronUp';
+import { cn } from '@/lib/utils';
+
+type Option = SelectPrimitive.Option;
+
+const Select = SelectPrimitive.Root;
+
+const SelectGroup = SelectPrimitive.Group;
+
+const SelectValue = SelectPrimitive.Value;
+
+const SelectTrigger = React.forwardRef(
+ ({ className, children, ...props }, ref) => (
+ span]:line-clamp-1',
+ props.disabled && 'web:cursor-not-allowed opacity-50',
+ className
+ )}
+ {...props}
+ >
+ <>{children}>
+
+
+ )
+);
+SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
+
+/**
+ * Platform: WEB ONLY
+ */
+const SelectScrollUpButton = ({ className, ...props }: SelectPrimitive.ScrollUpButtonProps) => {
+ if (Platform.OS !== 'web') {
+ return null;
+ }
+ return (
+
+
+
+ );
+};
+
+/**
+ * Platform: WEB ONLY
+ */
+const SelectScrollDownButton = ({ className, ...props }: SelectPrimitive.ScrollDownButtonProps) => {
+ if (Platform.OS !== 'web') {
+ return null;
+ }
+ return (
+
+
+
+ );
+};
+
+const SelectContent = React.forwardRef<
+ SelectPrimitive.ContentRef,
+ SelectPrimitive.ContentProps & { portalHost?: string }
+>(({ className, children, position = 'popper', portalHost, ...props }, ref) => {
+ const { open } = SelectPrimitive.useRootContext();
+
+ return (
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+ );
+});
+SelectContent.displayName = SelectPrimitive.Content.displayName;
+
+const SelectLabel = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+SelectLabel.displayName = SelectPrimitive.Label.displayName;
+
+const SelectItem = React.forwardRef(
+ ({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+
+
+ )
+);
+SelectItem.displayName = SelectPrimitive.Item.displayName;
+
+const SelectSeparator = React.forwardRef<
+ SelectPrimitive.SeparatorRef,
+ SelectPrimitive.SeparatorProps
+>(({ className, ...props }, ref) => (
+
+));
+SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
+
+export {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+ type Option,
+};
diff --git a/components/ui/separator.tsx b/components/ui/separator.tsx
new file mode 100644
index 0000000..20aba57
--- /dev/null
+++ b/components/ui/separator.tsx
@@ -0,0 +1,22 @@
+import * as SeparatorPrimitive from '@rn-primitives/separator';
+import * as React from 'react';
+import { cn } from '@/lib/utils';
+
+const Separator = React.forwardRef(
+ ({ className, orientation = 'horizontal', decorative = true, ...props }, ref) => (
+
+ )
+);
+Separator.displayName = SeparatorPrimitive.Root.displayName;
+
+export { Separator };
diff --git a/components/ui/sheet/CloseButton.tsx b/components/ui/sheet/CloseButton.tsx
new file mode 100644
index 0000000..069c270
--- /dev/null
+++ b/components/ui/sheet/CloseButton.tsx
@@ -0,0 +1,46 @@
+// components/ui/sheet/CloseButton.tsx
+import React from 'react';
+import { TouchableOpacity, View, StyleSheet } from 'react-native';
+import { X } from 'lucide-react-native';
+import { useColorScheme } from '@/lib/useColorScheme';
+import { NAV_THEME } from '@/lib/constants';
+
+interface CloseButtonProps {
+ onPress: () => void;
+}
+
+export function CloseButton({ onPress }: CloseButtonProps) {
+ const { isDarkColorScheme } = useColorScheme();
+ const theme = isDarkColorScheme ? NAV_THEME.dark : NAV_THEME.light;
+
+ return (
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ button: {
+ minWidth: 40,
+ minHeight: 40,
+ shadowColor: "#000",
+ shadowOffset: {
+ width: 0,
+ height: 1,
+ },
+ shadowOpacity: 0.2,
+ shadowRadius: 1.41,
+ elevation: 2,
+ },
+});
\ No newline at end of file
diff --git a/components/ui/sheet/Sheet.native.tsx b/components/ui/sheet/Sheet.native.tsx
new file mode 100644
index 0000000..3356b6e
--- /dev/null
+++ b/components/ui/sheet/Sheet.native.tsx
@@ -0,0 +1,142 @@
+// components/ui/Sheet.native.tsx
+import React from 'react';
+import {
+ Modal,
+ View,
+ TouchableOpacity,
+ Platform,
+ Dimensions,
+ ScrollView,
+ StyleSheet,
+ Animated,
+ BackHandler
+} from 'react-native';
+import { Text } from '../text';
+import { CloseButton } from './CloseButton';
+import type { SheetProps, SheetContentProps, SheetHeaderProps, SheetTitleProps } from './Sheet.types';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+
+const { height: SCREEN_HEIGHT } = Dimensions.get('window');
+const SHEET_HEIGHT = SCREEN_HEIGHT * 0.7;
+
+export function Sheet({ isOpen, onClose, children }: SheetProps) {
+ const translateY = React.useRef(new Animated.Value(SCREEN_HEIGHT)).current;
+ const [isVisible, setIsVisible] = React.useState(false);
+
+ // Handle back button on Android
+ React.useEffect(() => {
+ const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {
+ if (isOpen) {
+ onClose();
+ return true;
+ }
+ return false;
+ });
+
+ return () => backHandler.remove();
+ }, [isOpen, onClose]);
+
+ React.useEffect(() => {
+ if (isOpen) {
+ setIsVisible(true);
+ Animated.spring(translateY, {
+ toValue: SCREEN_HEIGHT - SHEET_HEIGHT,
+ useNativeDriver: true,
+ damping: 25,
+ mass: 0.7,
+ stiffness: 300,
+ }).start();
+ } else {
+ Animated.timing(translateY, {
+ toValue: SCREEN_HEIGHT,
+ duration: 200,
+ useNativeDriver: true,
+ }).start(() => {
+ setIsVisible(false);
+ });
+ }
+ }, [isOpen]);
+
+ if (!isVisible && !isOpen) return null;
+
+ return (
+
+
+
+
+ {/* Handle indicator */}
+
+
+
+
+
+
+ {children}
+
+
+
+ );
+}
+
+export function SheetHeader({ children }: SheetHeaderProps) {
+ return (
+
+ {children}
+
+ );
+}
+
+export function SheetTitle({ children }: SheetTitleProps) {
+ return {children};
+}
+
+export function SheetContent({ children }: SheetContentProps) {
+ const insets = useSafeAreaInsets();
+
+ return (
+
+ {children}
+
+ );
+}
+
+const styles = StyleSheet.create({
+ backdrop: {
+ backgroundColor: 'rgba(0,0,0,0.25)',
+ },
+ sheetContainer: {
+ height: SHEET_HEIGHT,
+ shadowColor: "#000",
+ shadowOffset: {
+ width: 0,
+ height: -2,
+ },
+ shadowOpacity: 0.25,
+ shadowRadius: 3.84,
+ elevation: 5,
+ },
+});
\ No newline at end of file
diff --git a/components/ui/sheet/Sheet.tsx b/components/ui/sheet/Sheet.tsx
new file mode 100644
index 0000000..352c21a
--- /dev/null
+++ b/components/ui/sheet/Sheet.tsx
@@ -0,0 +1,4 @@
+// components/ui/sheet.ts
+export * from './Sheet.native';
+
+// The above line will automatically be replaced with sheet.web.tsx on web platform
\ No newline at end of file
diff --git a/components/ui/sheet/Sheet.types.ts b/components/ui/sheet/Sheet.types.ts
new file mode 100644
index 0000000..6452bd9
--- /dev/null
+++ b/components/ui/sheet/Sheet.types.ts
@@ -0,0 +1,20 @@
+// components/ui/Sheet/types.ts
+import { ReactNode } from 'react';
+
+export interface SheetProps {
+ isOpen: boolean;
+ onClose: () => void;
+ children: ReactNode;
+}
+
+export interface SheetContentProps {
+ children: ReactNode;
+}
+
+export interface SheetHeaderProps {
+ children: ReactNode;
+}
+
+export interface SheetTitleProps {
+ children: ReactNode;
+}
\ No newline at end of file
diff --git a/components/ui/sheet/Sheet.web.tsx b/components/ui/sheet/Sheet.web.tsx
new file mode 100644
index 0000000..6666300
--- /dev/null
+++ b/components/ui/sheet/Sheet.web.tsx
@@ -0,0 +1,66 @@
+// components/ui/Sheet.web.tsx
+import React from 'react';
+import {
+ View,
+ TouchableOpacity,
+ StyleSheet,
+ Modal as RNModal
+} from 'react-native';
+import { CloseButton } from './CloseButton';
+import type { SheetProps } from './sheet.types';
+
+// Re-export components
+export { SheetContent, SheetHeader, SheetTitle } from './Sheet.native';
+
+export function Sheet({ isOpen, onClose, children }: SheetProps) {
+ if (!isOpen) return null;
+
+ return (
+
+
+
+
+ {/* Handle indicator */}
+
+
+
+
+
+
+ {children}
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ backdrop: {
+ backgroundColor: 'rgba(0,0,0,0.25)',
+ },
+ sheetContainer: {
+ height: '70%',
+ shadowColor: "#000",
+ shadowOffset: {
+ width: 0,
+ height: -2,
+ },
+ shadowOpacity: 0.1,
+ shadowRadius: 10,
+ },
+});
\ No newline at end of file
diff --git a/components/ui/sheet/index.ts b/components/ui/sheet/index.ts
new file mode 100644
index 0000000..9495028
--- /dev/null
+++ b/components/ui/sheet/index.ts
@@ -0,0 +1,6 @@
+// components/ui/sheet/index.ts
+export { Sheet } from './Sheet.native';
+export { SheetHeader } from './Sheet.native';
+export { SheetTitle } from './Sheet.native';
+export { SheetContent } from './Sheet.native';
+export type { SheetProps, SheetContentProps, SheetHeaderProps, SheetTitleProps } from './sheet.types';
\ No newline at end of file
diff --git a/components/ui/skeleton.tsx b/components/ui/skeleton.tsx
new file mode 100644
index 0000000..e42d5ab
--- /dev/null
+++ b/components/ui/skeleton.tsx
@@ -0,0 +1,39 @@
+import * as React from 'react';
+import Animated, {
+ useAnimatedStyle,
+ useSharedValue,
+ withRepeat,
+ withSequence,
+ withTiming,
+} from 'react-native-reanimated';
+import { cn } from '@/lib/utils';
+
+const duration = 1000;
+
+function Skeleton({
+ className,
+ ...props
+}: Omit, 'style'>) {
+ const sv = useSharedValue(1);
+
+ React.useEffect(() => {
+ sv.value = withRepeat(
+ withSequence(withTiming(0.5, { duration }), withTiming(1, { duration })),
+ -1
+ );
+ }, []);
+
+ const style = useAnimatedStyle(() => ({
+ opacity: sv.value,
+ }));
+
+ return (
+
+ );
+}
+
+export { Skeleton };
diff --git a/components/ui/switch.tsx b/components/ui/switch.tsx
new file mode 100644
index 0000000..27237c0
--- /dev/null
+++ b/components/ui/switch.tsx
@@ -0,0 +1,95 @@
+import * as SwitchPrimitives from '@rn-primitives/switch';
+import * as React from 'react';
+import { Platform } from 'react-native';
+import Animated, {
+ interpolateColor,
+ useAnimatedStyle,
+ useDerivedValue,
+ withTiming,
+} from 'react-native-reanimated';
+import { useColorScheme } from '@/lib/useColorScheme';
+import { cn } from '@/lib/utils';
+
+const SwitchWeb = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+
+
+ )
+);
+
+SwitchWeb.displayName = 'SwitchWeb';
+
+const RGB_COLORS = {
+ light: {
+ primary: 'rgb(24, 24, 27)',
+ input: 'rgb(228, 228, 231)',
+ },
+ dark: {
+ primary: 'rgb(250, 250, 250)',
+ input: 'rgb(39, 39, 42)',
+ },
+} as const;
+
+const SwitchNative = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ const { colorScheme } = useColorScheme();
+ const translateX = useDerivedValue(() => (props.checked ? 18 : 0));
+ const animatedRootStyle = useAnimatedStyle(() => {
+ return {
+ backgroundColor: interpolateColor(
+ translateX.value,
+ [0, 18],
+ [RGB_COLORS[colorScheme].input, RGB_COLORS[colorScheme].primary]
+ ),
+ };
+ });
+ const animatedThumbStyle = useAnimatedStyle(() => ({
+ transform: [{ translateX: withTiming(translateX.value, { duration: 200 }) }],
+ }));
+ return (
+
+
+
+
+
+
+
+ );
+ }
+);
+SwitchNative.displayName = 'SwitchNative';
+
+const Switch = Platform.select({
+ web: SwitchWeb,
+ default: SwitchNative,
+});
+
+export { Switch };
diff --git a/components/ui/table.tsx b/components/ui/table.tsx
new file mode 100644
index 0000000..2be7439
--- /dev/null
+++ b/components/ui/table.tsx
@@ -0,0 +1,92 @@
+import * as TablePrimitive from '@rn-primitives/table';
+import * as React from 'react';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const Table = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+Table.displayName = 'Table';
+
+const TableHeader = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+TableHeader.displayName = 'TableHeader';
+
+const TableBody = React.forwardRef(
+ ({ className, style, ...props }, ref) => (
+
+ )
+);
+TableBody.displayName = 'TableBody';
+
+const TableFooter = React.forwardRef(
+ ({ className, ...props }, ref) => (
+ tr]:last:border-b-0', className)}
+ {...props}
+ />
+ )
+);
+TableFooter.displayName = 'TableFooter';
+
+const TableRow = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+TableRow.displayName = 'TableRow';
+
+const TableHead = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+
+
+ )
+);
+TableHead.displayName = 'TableHead';
+
+const TableCell = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+TableCell.displayName = 'TableCell';
+
+export { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow };
diff --git a/components/ui/tabs.tsx b/components/ui/tabs.tsx
new file mode 100644
index 0000000..0dadfe6
--- /dev/null
+++ b/components/ui/tabs.tsx
@@ -0,0 +1,62 @@
+import * as TabsPrimitive from '@rn-primitives/tabs';
+import * as React from 'react';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const Tabs = TabsPrimitive.Root;
+
+const TabsList = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+TabsList.displayName = TabsPrimitive.List.displayName;
+
+const TabsTrigger = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ const { value } = TabsPrimitive.useRootContext();
+ return (
+
+
+
+ );
+ }
+);
+TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
+
+const TabsContent = React.forwardRef(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+TabsContent.displayName = TabsPrimitive.Content.displayName;
+
+export { Tabs, TabsContent, TabsList, TabsTrigger };
diff --git a/components/ui/text.tsx b/components/ui/text.tsx
index 0d7af0f..2ca5713 100644
--- a/components/ui/text.tsx
+++ b/components/ui/text.tsx
@@ -2,7 +2,7 @@ import * as Slot from '@rn-primitives/slot';
import type { SlottableTextProps, TextRef } from '@rn-primitives/types';
import * as React from 'react';
import { Text as RNText } from 'react-native';
-import { cn } from '~/lib/utils';
+import { cn } from '@/lib/utils';
const TextClassContext = React.createContext(undefined);
diff --git a/components/ui/textarea.tsx b/components/ui/textarea.tsx
new file mode 100644
index 0000000..771e6b2
--- /dev/null
+++ b/components/ui/textarea.tsx
@@ -0,0 +1,27 @@
+import * as React from 'react';
+import { TextInput, type TextInputProps } from 'react-native';
+import { cn } from '@/lib/utils';
+
+const Textarea = React.forwardRef, TextInputProps>(
+ ({ className, multiline = true, numberOfLines = 4, placeholderClassName, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+
+Textarea.displayName = 'Textarea';
+
+export { Textarea };
diff --git a/components/ui/toggle-group.tsx b/components/ui/toggle-group.tsx
new file mode 100644
index 0000000..eb4a3cf
--- /dev/null
+++ b/components/ui/toggle-group.tsx
@@ -0,0 +1,84 @@
+import type { VariantProps } from 'class-variance-authority';
+import type { LucideIcon } from 'lucide-react-native';
+import * as React from 'react';
+import { toggleTextVariants, toggleVariants } from '@/components/ui/toggle';
+import { TextClassContext } from '@/components/ui/text';
+import * as ToggleGroupPrimitive from '@rn-primitives/toggle-group';
+import { cn } from '@/lib/utils';
+
+const ToggleGroupContext = React.createContext | null>(null);
+
+const ToggleGroup = React.forwardRef<
+ ToggleGroupPrimitive.RootRef,
+ ToggleGroupPrimitive.RootProps & VariantProps
+>(({ className, variant, size, children, ...props }, ref) => (
+
+ {children}
+
+));
+
+ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
+
+function useToggleGroupContext() {
+ const context = React.useContext(ToggleGroupContext);
+ if (context === null) {
+ throw new Error(
+ 'ToggleGroup compound components cannot be rendered outside the ToggleGroup component'
+ );
+ }
+ return context;
+}
+
+const ToggleGroupItem = React.forwardRef<
+ ToggleGroupPrimitive.ItemRef,
+ ToggleGroupPrimitive.ItemProps & VariantProps
+>(({ className, children, variant, size, ...props }, ref) => {
+ const context = useToggleGroupContext();
+ const { value } = ToggleGroupPrimitive.useRootContext();
+
+ return (
+
+
+ {children}
+
+
+ );
+});
+
+ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
+
+function ToggleGroupIcon({
+ className,
+ icon: Icon,
+ ...props
+}: React.ComponentPropsWithoutRef & {
+ icon: LucideIcon;
+}) {
+ const textClass = React.useContext(TextClassContext);
+ return ;
+}
+
+export { ToggleGroup, ToggleGroupIcon, ToggleGroupItem };
diff --git a/components/ui/toggle.tsx b/components/ui/toggle.tsx
new file mode 100644
index 0000000..e2e6940
--- /dev/null
+++ b/components/ui/toggle.tsx
@@ -0,0 +1,85 @@
+import * as TogglePrimitive from '@rn-primitives/toggle';
+import { cva, type VariantProps } from 'class-variance-authority';
+import type { LucideIcon } from 'lucide-react-native';
+import * as React from 'react';
+import { cn } from '@/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+
+const toggleVariants = cva(
+ 'web:group web:inline-flex items-center justify-center rounded-md web:ring-offset-background web:transition-colors web:hover:bg-muted active:bg-muted web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2',
+ {
+ variants: {
+ variant: {
+ default: 'bg-transparent',
+ outline:
+ 'border border-input bg-transparent web:hover:bg-accent active:bg-accent active:bg-accent',
+ },
+ size: {
+ default: 'h-10 px-3 native:h-12 native:px-[12]',
+ sm: 'h-9 px-2.5 native:h-10 native:px-[9]',
+ lg: 'h-11 px-5 native:h-14 native:px-6',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ size: 'default',
+ },
+ }
+);
+
+const toggleTextVariants = cva('text-sm native:text-base text-foreground font-medium', {
+ variants: {
+ variant: {
+ default: '',
+ outline: 'web:group-hover:text-accent-foreground web:group-active:text-accent-foreground',
+ },
+ size: {
+ default: '',
+ sm: '',
+ lg: '',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ size: 'default',
+ },
+});
+
+const Toggle = React.forwardRef<
+ TogglePrimitive.RootRef,
+ TogglePrimitive.RootProps & VariantProps
+>(({ className, variant, size, ...props }, ref) => (
+
+
+
+));
+
+Toggle.displayName = TogglePrimitive.Root.displayName;
+
+function ToggleIcon({
+ className,
+ icon: Icon,
+ ...props
+}: React.ComponentPropsWithoutRef & {
+ icon: LucideIcon;
+}) {
+ const textClass = React.useContext(TextClassContext);
+ return ;
+}
+
+export { Toggle, ToggleIcon, toggleTextVariants, toggleVariants };
diff --git a/components/ui/tooltip.tsx b/components/ui/tooltip.tsx
index 82b65a9..950ab53 100644
--- a/components/ui/tooltip.tsx
+++ b/components/ui/tooltip.tsx
@@ -2,8 +2,8 @@ import * as TooltipPrimitive from '@rn-primitives/tooltip';
import * as React from 'react';
import { Platform, StyleSheet } from 'react-native';
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
-import { TextClassContext } from '~/components/ui/text';
-import { cn } from '~/lib/utils';
+import { TextClassContext } from '@/components/ui/text';
+import { cn } from '@/lib/utils';
const Tooltip = TooltipPrimitive.Root;
diff --git a/components/ui/typography.tsx b/components/ui/typography.tsx
new file mode 100644
index 0000000..7b1ec7c
--- /dev/null
+++ b/components/ui/typography.tsx
@@ -0,0 +1,205 @@
+import * as Slot from '@rn-primitives/slot';
+import type { SlottableTextProps, TextRef } from '@rn-primitives/types';
+import * as React from 'react';
+import { Platform, Text as RNText } from 'react-native';
+import { cn } from '@/lib/utils';
+
+const H1 = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+H1.displayName = 'H1';
+
+const H2 = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+H2.displayName = 'H2';
+
+const H3 = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+H3.displayName = 'H3';
+
+const H4 = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+H4.displayName = 'H4';
+
+const P = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+P.displayName = 'P';
+
+const BlockQuote = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+BlockQuote.displayName = 'BlockQuote';
+
+const Code = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+Code.displayName = 'Code';
+
+const Lead = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+Lead.displayName = 'Lead';
+
+const Large = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+Large.displayName = 'Large';
+
+const Small = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+Small.displayName = 'Small';
+
+const Muted = React.forwardRef(
+ ({ className, asChild = false, ...props }, ref) => {
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+
+ );
+ }
+);
+
+Muted.displayName = 'Muted';
+
+export { BlockQuote, Code, H1, H2, H3, H4, Large, Lead, Muted, P, Small };
diff --git a/docs/ai_collaboration_guide.md b/docs/ai_collaboration_guide.md
new file mode 100644
index 0000000..d5f6393
--- /dev/null
+++ b/docs/ai_collaboration_guide.md
@@ -0,0 +1,215 @@
+# AI Collaboration Guidelines for POWR Project
+
+## Project Overview
+
+POWR is a cross-platform fitness tracking application built with React Native and Expo. It follows a local-first architecture with planned Nostr protocol integration for decentralized social features.
+
+### Key Features
+- Exercise and workout tracking
+- Workout template creation and management
+- Local-first data storage
+- Cross-platform compatibility (iOS, Android)
+- Future Nostr integration for social features
+
+### Technical Stack
+- React Native & Expo
+- TypeScript
+- SQLite for local storage
+- Nostr protocol (planned)
+
+## Collaboration Guidelines
+
+### 1. Development Process
+
+#### 1.1 Problem Statement
+Before starting any implementation:
+- Define the specific problem or feature
+- Outline key requirements and constraints
+- Identify success criteria
+- Document any dependencies or prerequisites
+
+Example:
+```markdown
+Problem: Users need a way to create and manage custom exercise templates
+Requirements:
+- Support for different exercise types
+- Custom fields for sets/reps/weight
+- Offline functionality
+- Future Nostr compatibility
+Success Criteria:
+- Users can create, edit, and delete exercises
+- Exercise data persists locally
+- UI performs smoothly
+```
+
+#### 1.2 Design Document
+Create a design document that includes:
+- Technical approach
+- Data structures
+- Component hierarchy
+- State management
+- Error handling
+- Testing strategy
+
+Store design documents in: `@/docs/design/`
+
+#### 1.3 Implementation Phases
+Break implementation into manageable chunks:
+1. Core functionality
+2. UI/UX implementation
+3. Data persistence
+4. Testing and validation
+5. Documentation
+
+#### 1.4 Review Process
+- Review code in logical chunks
+- Include tests with new features
+- Document any configuration changes
+- Update relevant documentation
+
+### 2. Code Quality Standards
+
+#### 2.1 TypeScript Usage
+- Use proper type definitions
+- Avoid `any` types
+- Document complex types
+- Use interfaces for shared types
+
+Example:
+```typescript
+interface Exercise {
+ id: string;
+ name: string;
+ type: ExerciseType;
+ equipment?: Equipment;
+ notes?: string;
+ created_at: number;
+}
+```
+
+#### 2.2 Documentation
+- Include JSDoc comments for functions
+- Document component props
+- Explain complex logic
+- Keep README files updated
+
+Example:
+```typescript
+/**
+ * Creates a new exercise template in the local database
+ * @param exercise - The exercise data to save
+ * @returns Promise - The ID of the created exercise
+ * @throws {DatabaseError} If the save operation fails
+ */
+async function createExercise(exercise: Exercise): Promise
+```
+
+#### 2.3 Error Handling
+- Use typed errors
+- Implement error boundaries
+- Log errors appropriately
+- Provide user feedback
+
+#### 2.4 Testing
+- Write unit tests for utilities
+- Component testing
+- Integration tests for workflows
+- Document test cases
+
+### 3. Project Structure
+
+```plaintext
+powr/
+├── app/ # Main application code
+│ ├── (tabs)/ # Tab-based navigation
+│ └── components/ # Shared components
+├── assets/ # Static assets
+├── docs/ # Documentation
+│ └── design/ # Design documents
+├── lib/ # Shared utilities
+└── types/ # TypeScript definitions
+```
+
+### 4. Contribution Process
+
+1. **Start with Documentation**
+ - Create/update design doc
+ - Document planned changes
+ - Update relevant READMEs
+
+2. **Implementation**
+ - Follow TypeScript best practices
+ - Add tests for new features
+ - Include error handling
+ - Add logging where appropriate
+
+3. **Review**
+ - Self-review checklist
+ - Documentation updates
+ - Test coverage
+ - Performance considerations
+
+### 5. Future-Proofing
+
+#### 5.1 Nostr Integration
+- Design data structures for Nostr compatibility
+- Plan for event-based architecture
+- Consider relay infrastructure
+- Document Nostr-specific features
+
+#### 5.2 Offline First
+- Local data persistence
+- Sync status tracking
+- Conflict resolution strategy
+- Clear offline indicators
+
+## Communication Guidelines
+
+### 1. When Asking for Help
+- Provide context
+- Share relevant code
+- Describe expected vs actual behavior
+- Include any error messages
+
+### 2. When Implementing Features
+- Break down complex tasks
+- Document assumptions
+- Ask for clarification when needed
+- Provide progress updates
+
+### 3. When Reviewing Code
+- Follow the checklist
+- Provide constructive feedback
+- Suggest improvements
+- Document decisions
+
+## Resources
+
+### Documentation Templates
+- Problem Statement Template
+- Design Document Template
+- Pull Request Template
+
+### Style Guides
+- TypeScript Style Guide
+- React Native Best Practices
+- Component Design Guidelines
+
+### Tools
+- ESLint Configuration
+- Prettier Setup
+- Testing Utilities
+
+## Getting Started
+
+1. Review project documentation
+2. Set up development environment
+3. Run initial build
+4. Review current codebase
+5. Start with small tasks
+
+Remember to:
+- Ask questions when stuck
+- Document decisions
+- Follow the process
+- Think about maintainability
\ No newline at end of file
diff --git a/docs/coding_style.md b/docs/coding_style.md
new file mode 100644
index 0000000..714fb70
--- /dev/null
+++ b/docs/coding_style.md
@@ -0,0 +1,277 @@
+## **Overview**
+
+This guide is written in the spirit of [Google Style Guides](https://github.com/google/styleguide), especially the most well written ones like for [Obj-C](https://github.com/google/styleguide/blob/gh-pages/objcguide.md).
+
+Coding style guides are meant to help everyone who contributes to a project to forget about how code feels and easily understand the logic.
+
+These are guidelines with rationales for all rules. If the rationale doesn't apply, or changes make the rationale moot, the guidelines can safely be ignored.
+
+## **General Principles**
+
+### **Consistency is king**
+
+Above all other principles, be consistent.
+
+If a single file all follows one convention, just keep following the convention. Separate style changes from logic changes.
+
+**Rationale**: If same thing is named differently (`Apple`, `a`, `fruit`, `redThing`), it becomes hard to understand how they're related.
+
+### **Readability above efficiency**
+
+Prefer readable code over fewer lines of cryptic code.
+
+**Rationale**: Code will be read many more times than it will be written, by different people. Different people includes you, only a year from now.
+
+### **All code is either obviously right, or non-obviously wrong.**
+
+Almost all code should strive to be obviously right at first glance. It shouldn't strike readers as "somewhat odd", and need detailed study to read and decipher.
+
+**Rationale**: If code is obviously right, it's probably right. The goal is to have suspicious code look suspiciously wrong and stick out like a sore thumb. This happens when everything else is very clear, and there's a tricky bit that needs to be worked on.
+
+*Corollary*: Code comments are a sign that the code isn't particularly well explained via the code itself. Either through naming, or ordering, or chunking of the logic. Both code and comments have maintenance cost, but comments don't explicitly do work, and often go out of sync with associated code. While not explicitly disallowed, strive to make code require almost no comments.
+
+Good cases to use comments include describing **why** the code is written that way (if naming, ordering, scoping, etc doesn't work) or explaining details which couldn't be easily explained in code (e.g., which algorithm/pattern/approach is used and why).
+
+*Exception*: API interfaces *should* be commented, as close to code as possible for keeping up to date easily.
+
+**Further Reading**: https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/
+
+### **Boring is best**
+
+Make your code the most boring version it could be.
+
+**Rationale**: While you may have won competitions in code golf, the goal of production code is NOT to have the smartest code that only geniuses can figure out, but that which can easily be maintained. On the other hand, devote your creativity to making interesting test cases with fun constant values.
+
+### **Split implementation from interface**
+
+Storage, presentation, communication protocols should always be separate.
+
+**Rationale**: While the content may coincidentally look the same, all these layers have different uses. If you tie things in the wrong place, then you will break unintentionally in non-obvious bad ways.
+
+### **Split "policy" and "mechanics"**
+
+Always separate the configuration/policy ("the why") from the implementation/mechanics ("the how").
+
+**Rationale**: You can test the implementation of what needs to be done. You can also test the policy triggers at the right time. Turning a feature on and off makes it much easier to throw in more features and later turn them on/off and canary.
+
+**Corollary**: Create separate functions for "doing" and for "choosing when to do".
+
+**Corollary**: Create flags for all implementation features.
+
+# **Deficiency Documentation (`TODO`s and `FIXME`s)**
+
+### **`TODO` comments**
+
+Use `TODO` comments *liberally* to describe anything that is potentially missing.
+
+Code reviewers can also liberally ask for adding `TODO`s to different places.
+
+Format:
+
+`// TODO[(Context)]: by/when `
+
+`TODO` comments should have these parts:
+
+- **Context** - (*Optional*) JIRA issue, etc. that can describe what this thing means better.
+ - Issues or other documentation should be used when the explanations are pretty long or involved.
+ - Code reviewers should verify that important `TODO`s have filed JIRA Issues.
+ - Examples:
+ - `CARE-XXX` - Issue description
+- **Action** - Very specific actionable thing to be done. Explanations can come after the particular action.
+ - Examples:
+ - `Refactor into single class...`
+ - `Add ability to query Grafana...`
+ - `Replace this hack with ...`
+- **Deadline Condition** - when to get the thing done by.
+ - Deadline Conditions should **NOT** be relied on to *track* something done by a time or milestone.
+ - Examples:
+ - `... before General Availability release.`
+ - `... when we add capability.`
+ - `... when XXX bug/feature is fixed.`
+ - `... once approves of .`
+ - `... when first customer asks for it.`
+ - Empty case implies "`...when we get time`". Use *only* for relatively unimportant things.
+
+**Rationale**: `TODO` comments help readers understand what is missing. Sometimes you know what you're doing is not the best it could be, but is good enough. That's fine. Just explain how it can be improved.
+
+Feel free to add `TODO` comments as you edit code and read other code that you interact with. If you don't understand something, add `TODO` to document how it might be better, so others may be able to help out.
+
+Good Examples:
+
+`// TODO: Replace certificate with staging version once we get letsencrypt to work.
+
+// TODO(CARE-XXX): Replace old logic with new logic when out of experimental mode.
+
+// TODO(SCIENCE-XXX): Colonize new planets when we get cold fusion capability.`
+
+Mediocre examples(lacks Deadline Condition) - Good for documenting, but not as important:
+
+`// TODO: Add precompiling templates here if we need it.
+
+// TODO: Remove use of bash.
+
+// TODO: Clean up for GetPatient/GetCaseWorker, which might be called from http handlers separately.
+
+// TODO: Figure out how to launch spaceships instead of rubber duckies.`
+
+Bad examples:
+
+`// TODO: wtf? (what are we f'ing about?)
+
+// TODO: We shouldn't do this. (doesn't say what to do instead, or why it exists)
+
+// TODO: err...`
+
+### **`FIXME` comments**
+
+Use `FIXME` comments as **stronger** `TODO`s that **MUST** be done before code submission. These comments are **merge-blocking**.
+
+`FIXME` should be liberally used for notes during development, either for developer or reviewers, to remind and prompt discussion. Remove these comments by fixing them before submitting code.
+
+During code review, reviewer *may* suggest converting `FIXME` -> `TODO`, if it's not important to get done before getting something submitted. Then [`TODO` comment](https://github.com/MindStrongHealth/experimental/blob/master/users/teejae/coding-style.md#todo-comments) formatting applies.
+
+Format (same as [`TODO` comments](https://github.com/MindStrongHealth/experimental/blob/master/users/teejae/coding-style.md#todo-comments), but more relaxed):
+
+`// FIXME:
+
+// FIXME: Remove hack
+
+// FIXME: Revert hardcoding of server URL
+
+// FIXME: Implement function
+
+// FIXME: Refactor these usages across codebase.
+
+// FIXME: Why does this work this way? `
+
+**Rationale**: These are great self-reminders as you code that you haven't finished something, like stubbed out functions, unimplemented parts, etc. The reviewer can also see the `FIXME`s to eye potential problems, and help out things that are not understandable, suggesting better fixes.
+
+# **Code**
+
+## **Naming**
+
+### **Variables should always be named semantically.**
+
+Names of variables should reflect their content and intent. Try to pick very specific names. Avoid adding parts that don't add any context to the name. Use only well-known abbreviations, otherwise, don't shorten the name in order to save a couple of symbols.
+
+```
+// Bad
+input = "123-4567"
+dialPhoneNumber(input) // unclear whether this makes semantic sense.
+
+// Good
+phoneNumber = "123-4567"
+dialPhoneNumber(phoneNumber) // more obvious that this is intentional.
+
+// Bad
+text = 1234
+address = "http://some-address/patient/" + text // why is text being added to a string?
+
+// Good
+patientId = 1234
+address = "http://some-address/patient/" + patientId // ah, a patient id is added to an address.
+
+```
+
+**Rationale**: Good semantic names make bugs obvious and expresses intention, without needing lots of comments.
+
+### **Always add units for measures.**
+
+Time is especially ambiguous.
+
+Time intervals (duration): `timeoutSec`, `timeoutMs`, `refreshIntervalHours`
+
+Timestamp (specific instant in time): `startTimestamp`. (Use language-provided representations once inside code, rather than generic `number`, `int` for raw timestamps. JS/Java: `Date`, Python: `datetime.date/time`, Go: `time.Time`)
+
+Distances: `LengthFt`, `LengthMeter`, `LengthCm`, `LengthMm`
+
+Computer Space: `DiskMib` (1 Mebibyte is 1024 Kibibytes), `RamMb` (1 Megabyte is 1000 Kilobytes)
+
+```
+// Bad
+Cost = Disk * Cents
+
+// Good
+CostCents = DiskMib * 1024 * CentsPerKilobyte
+
+```
+
+**Rationale**: Large classes of bugs are avoided when you name everything with units.
+
+## **Constants**
+
+### **All literals should be assigned to constants (or constant-like treatments).**
+
+Every string or numeric literal needs to be assigned to a constant.
+
+**Exceptions**: Identity-type zero/one values: `0`, `1`, `-1`, `""`
+
+**Rationale**: It is never obvious why random number or string literals appear in different places. Even if they are somewhat obvious, it's hard to debug/find random constants and what they mean unless they are explicitly defined. Looking at collected constants allows the reader to see what is important, and see tricky edge cases while spelunking through the rest of the code.
+
+# **Tests**
+
+All commentary in the Code section applies here as well, with a few relaxations.
+
+### **Repetitive test code allowed**
+
+In general, do not repeat yourself. However, IF the test code is clearer, it's ok to repeat.
+
+**Rationale**: Readability above all else. Sometimes tests are meant to test lots of niggling nefarious code, so we make exceptions for those cases.
+
+### **Small Test Cases**
+
+Make test cases as small and targeted as possible.
+
+**Rationale**: Large tests are both unwieldy to write, and hard to debug. If something takes lots of setup, it's usually a sign of a design problem with the thing you're testing. Try breaking up the code/class/object into more manageable pieces.
+
+### **No complex logic**
+
+Avoid adding complex logic to test cases. It's more likely to have a bug in this case, while the purpose of the test cases is to prevent bugs. It's better to [repeat](https://github.com/MindStrongHealth/experimental/blob/master/users/teejae/coding-style.md#repetitive-test-code-allowed) or use a helper function covered with test cases.
+
+### **Be creative in the content, but *not* the variable names.**
+
+Just as for regular code, name variables for how they will be used. Intent is unclear when placeholders litter the code.
+
+Use creative values for testing that don't look too "normal", so maintainers can tell values are obviously test values.
+
+```
+// Bad
+login("abc", "badpassword") // Are "abc" and "badpassword" important?
+testMemberId = "NA12312412" // Looks too "real", and unclear if it needs to follow this form
+
+// Good
+testMemberId = "some random member id"
+testName = "abc"
+testPassword = "open sesame"
+testBadPassword = "really bad password! stop it!"
+
+login(testName, testPassword) // Success
+login(testName, testBadPassword) // Failure
+
+```
+
+**Rationale**: When the names of the variables are obvious, it becomes clear what is important in the tests.
+
+### **No "spooky action at a distance"**
+
+Collect all related logic/conditions into a single place, so it's easy to grasp how the different parts are related.
+
+```
+// Bad
+startingInvestmentDollars = 100
+invest()
+... lots of test code ...
+invest()
+loseMoney()
+expect(investment == 167) // Why 167?
+
+// Good
+startingInvestmentDollars = 100
+returnInterestRatePercent = 67
+endingInvestmentDollars = 167 // More obvious where 167 comes from.
+... lots of test code ...
+expect(investment == endingInvestmentDollars)
+
+```
+
+**Rationale**: When all related things are collected in a single place, you can more clearly understand what you think you'll read. The rest is just checking for mechanics.
\ No newline at end of file
diff --git a/app/index.tsx b/docs/design/RNR-original-example.tsx
similarity index 90%
rename from app/index.tsx
rename to docs/design/RNR-original-example.tsx
index fbbe261..a585794 100644
--- a/app/index.tsx
+++ b/docs/design/RNR-original-example.tsx
@@ -1,9 +1,9 @@
import * as React from 'react';
import { View } from 'react-native';
import Animated, { FadeInUp, FadeOutDown, LayoutAnimationConfig } from 'react-native-reanimated';
-import { Info } from '~/lib/icons/Info';
-import { Avatar, AvatarFallback, AvatarImage } from '~/components/ui/avatar';
-import { Button } from '~/components/ui/button';
+import { Info } from '@/lib/icons/Info';
+import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
+import { Button } from '@/components/ui/button';
import {
Card,
CardContent,
@@ -11,10 +11,10 @@ import {
CardFooter,
CardHeader,
CardTitle,
-} from '~/components/ui/card';
-import { Progress } from '~/components/ui/progress';
-import { Text } from '~/components/ui/text';
-import { Tooltip, TooltipContent, TooltipTrigger } from '~/components/ui/tooltip';
+} from '@/components/ui/card';
+import { Progress } from '@/components/ui/progress';
+import { Text } from '@/components/ui/text';
+import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
const GITHUB_AVATAR_URI =
'https://i.pinimg.com/originals/ef/a2/8d/efa28d18a04e7fa40ed49eeb0ab660db.jpg';
diff --git a/docs/design/library_tab.md b/docs/design/library_tab.md
new file mode 100644
index 0000000..30cbcc2
--- /dev/null
+++ b/docs/design/library_tab.md
@@ -0,0 +1,343 @@
+# POWR Library Tab PRD
+
+## Overview
+
+### Problem Statement
+Users need a centralized location to manage their fitness content (exercises and workout templates) while supporting both local content creation and Nostr-based content discovery. The library must maintain usability in offline scenarios while preparing for future social features.
+
+### Goals
+1. Provide organized access to exercises and workout templates
+2. Enable efficient content discovery and reuse
+3. Support clear content ownership and source tracking
+4. Maintain offline-first functionality
+5. Prepare for future Nostr integration
+
+## Feature Requirements
+
+### Navigation Structure
+- Material Top Tabs navigation with three sections:
+ - Templates (default tab)
+ - Exercises
+ - Programs (placeholder for future implementation)
+
+### Templates Tab
+
+#### Content Organization
+- Favorites section
+- Recently performed section
+- Alphabetical list of remaining templates
+- Clear source badges (Local/POWR/Nostr)
+
+#### Template Item Display
+- Template title
+- Workout type (strength, circuit, EMOM, etc.)
+- Preview of included exercises (first 3)
+- Source badge
+- Favorite star button
+- Usage stats
+
+#### Search & Filtering
+- Persistent search bar with real-time filtering
+- Filter options:
+ - Workout type
+ - Equipment needed
+ - Tags
+
+### Exercises Tab
+
+#### Content Organization
+- Recent section (10 most recent exercises)
+- Alphabetical list of all exercises
+- Tag-based categorization
+- Clear source badges
+
+#### Exercise Item Display
+- Exercise name
+- Category/tags
+- Equipment type
+- Source badge
+- Usage stats
+
+#### Search & Filtering
+- Persistent search bar with real-time filtering
+- Filter options:
+ - Equipment
+ - Tags
+ - Source
+
+### Programs Tab (Future)
+- Placeholder implementation
+- "Coming Soon" messaging
+- Basic description of future functionality
+
+## Content Interaction
+
+### Progressive Disclosure Pattern
+
+#### 1. Card Display
+- Basic info
+- Source badge (Local/POWR/Nostr)
+- Quick stats/preview
+- Favorite button (templates only)
+
+#### 2. Quick Preview (Hover/Long Press)
+- Extended preview info
+- Key stats
+- Quick actions
+
+#### 3. Bottom Sheet Details
+- Basic Information:
+ - Full title and description
+ - Category/tags
+ - Equipment requirements
+
+- Stats & History:
+ - Personal records
+ - Usage history
+ - Performance trends
+
+- Source Information:
+ - For local content:
+ - Creation date
+ - Last modified
+ - For Nostr content:
+ - Author information
+ - Original post date
+ - Relay source
+
+- Action Buttons:
+ - For local content:
+ - Start Workout (templates)
+ - Edit
+ - Publish to Nostr
+ - Delete
+ - For Nostr content:
+ - Start Workout (templates)
+ - Delete from Library
+
+#### 4. Full Details Modal
+- Comprehensive view
+- Complete history
+- Advanced options
+
+## Technical Requirements
+
+### Data Storage
+- SQLite for local storage
+- Schema supporting:
+ - Exercise templates
+ - Workout templates
+ - Usage history
+ - Source tracking
+ - Nostr metadata
+
+### Content Management
+- No limit on custom exercises/templates
+- Tag character limit: 30 characters
+- Support for external media links (images/videos)
+- Local caching of Nostr content
+
+### Media Content Handling
+- For Nostr content:
+ - Store media URLs in metadata
+ - Cache images locally when saved
+ - Lazy load images when online
+ - Show placeholders when offline
+- For local content:
+ - Optional image/video links
+ - No direct media upload in MVP
+
+### Offline Capabilities
+- Full functionality without internet
+- Local-first architecture
+- Graceful degradation of Nostr features
+- Clear offline state indicators
+
+## User Interface Components
+
+### Core Components
+1. MaterialTopTabs navigation
+2. Persistent search header
+3. Filter button and sheet
+4. Content cards
+5. Bottom sheet previews
+6. Tab-specific FABs:
+ - Templates Tab: FAB for creating new workout templates
+ - Exercises Tab: FAB for creating new custom exercises
+ - Programs Tab: FAB for creating training programs (future)
+
+### Component Details
+
+#### Templates Tab FAB
+- Primary action: Create new workout template
+- Icon: Layout/Template icon
+- Navigation: Routes to template creation flow
+- Fixed position at bottom right
+
+#### Exercises Tab FAB
+- Primary action: Create new exercise
+- Icon: Dumbbell icon
+- Navigation: Routes to exercise creation flow
+- Fixed position at bottom right
+
+#### Programs Tab FAB (Future)
+- Primary action: Create new program
+- Icon: Calendar/Program icon
+- Navigation: Routes to program creation flow
+- Fixed position at bottom right
+
+### Component States
+1. Loading states
+2. Empty states
+3. Error states
+4. Offline states
+5. Content creation/editing modes
+
+## Implementation Phases
+
+### Phase 1: Core Structure
+1. Tab navigation setup
+2. Basic content display
+3. Search and filtering
+4. Local content management
+
+### Phase 2: Enhanced Features
+1. Favorite system
+2. History tracking
+3. Performance stats
+4. Tag management
+
+### Phase 3: Nostr Integration
+1. Content syncing
+2. Publishing flow
+3. Author attribution
+4. Media handling
+
+## Success Metrics
+
+### Performance
+- Search response: < 100ms
+- Scroll performance: 60fps
+- Image load time: < 500ms
+
+### User Experience
+- Content discovery time
+- Search success rate
+- Template reuse rate
+- Exercise reference frequency
+
+### Technical
+- Offline reliability
+- Storage efficiency
+- Cache hit rate
+- Sync success rate
+
+## Future Considerations
+
+### Programs Tab Development
+- Program creation
+- Calendar integration
+- Progress tracking
+- Social sharing
+
+### Enhanced Social Features
+- Content recommendations
+- Author following
+- Usage analytics
+- Community features
+
+### Additional Enhancements
+- Advanced media support
+- Custom collections
+- Export/import functionality
+- Backup solutions
+
+2025-02-09 Update
+
+Progress Analysis:
+
+✅ COMPLETED:
+1. Navigation Structure
+- Implemented Material Top Tabs with Templates, Exercises, and Programs sections
+- Clear visual hierarchy with proper styling
+
+2. Basic Content Management
+- Search functionality
+- Filter system with proper categorization
+- Source badges (Local/POWR/Nostr)
+- Basic CRUD operations for exercises and templates
+
+3. UI Components
+- SearchHeader component
+- FilterSheet with proper categorization
+- Content cards with consistent styling
+- FAB for content creation
+- Sheet components for new content creation
+
+🟡 IN PROGRESS/PARTIAL:
+1. Content Organization
+- We have basic favorites for templates but need to implement:
+ - Recently performed section
+ - Usage stats tracking
+ - Better categorization system
+
+2. Progressive Disclosure Pattern
+- We have basic cards and creation sheets but need:
+ - Quick Preview on long press
+ - Bottom Sheet Details view
+ - Full Details Modal
+
+3. Content Interaction
+- Basic CRUD operations exist but need:
+ - Performance tracking
+ - History integration
+ - Better stats visualization
+
+❌ NOT STARTED:
+1. Technical Implementation
+- Nostr integration preparation
+- SQLite database setup
+- Proper caching system
+- Offline capabilities
+
+2. Advanced Features
+- Performance tracking
+- Usage history
+- Media content handling
+- Import/export functionality
+
+Recommended Next Steps:
+
+1. Data Layer Implementation
+```typescript
+// First set up SQLite database schema and service
+class LibraryService {
+ // Exercise management
+ getExercises(): Promise
+ createExercise(exercise: Exercise): Promise
+ updateExercise(id: string, exercise: Partial): Promise
+ deleteExercise(id: string): Promise
+
+ // Template management
+ getTemplates(): Promise
+ createTemplate(template: Template): Promise
+ updateTemplate(id: string, template: Partial): Promise
+ deleteTemplate(id: string): Promise
+
+ // Usage tracking
+ logExerciseUse(exerciseId: string): Promise
+ logTemplateUse(templateId: string): Promise
+ getExerciseHistory(exerciseId: string): Promise
+ getTemplateHistory(templateId: string): Promise
+}
+```
+
+2. Detail Views
+- Create a detailed view component for exercises and templates
+- Implement proper state management for tracking usage
+- Add performance metrics visualization
+
+3. Progressive Disclosure
+- Implement long press preview
+- Create bottom sheet details view
+- Add full screen modal for editing
diff --git a/docs/design_doc.md b/docs/design_doc.md
new file mode 100644
index 0000000..19a9ea0
--- /dev/null
+++ b/docs/design_doc.md
@@ -0,0 +1,137 @@
+# [Feature Name] Design Document
+
+## Problem Statement
+[Concise description of the problem being solved]
+
+## Requirements
+
+### Functional Requirements
+- [List of must-have functionality]
+- [User-facing features]
+- [Core capabilities]
+
+### Non-Functional Requirements
+- Performance targets
+- Security requirements
+- Reliability goals
+- Usability standards
+
+## Design Decisions
+
+### 1. [Major Decision Area]
+[Description of approach chosen]
+
+Rationale:
+- [Key reason]
+- [Supporting factors]
+- [Trade-offs considered]
+
+### 2. [Major Decision Area]
+[Description of approach chosen]
+
+Rationale:
+- [Key reason]
+- [Supporting factors]
+- [Trade-offs considered]
+
+## Technical Design
+
+### Core Components
+```typescript
+// Key interfaces/types
+interface ComponentName {
+ // Critical fields
+}
+
+// Core functionality
+function mainOperation() {
+ // Key logic
+}
+```
+
+### Integration Points
+- [System interfaces]
+- [External dependencies]
+- [API definitions]
+
+## Implementation Plan
+
+### Phase 1: [Initial Phase]
+1. [Step 1]
+2. [Step 2]
+3. [Step 3]
+
+### Phase 2: [Next Phase]
+1. [Step 1]
+2. [Step 2]
+3. [Step 3]
+
+## Testing Strategy
+
+### Unit Tests
+- [Key test areas]
+- [Critical test cases]
+- [Test tooling]
+
+### Integration Tests
+- [End-to-end scenarios]
+- [Cross-component tests]
+- [Test environments]
+
+## Observability
+
+### Logging
+- [Key log points]
+- [Log levels]
+- [Critical events]
+
+### Metrics
+- [Performance metrics]
+- [Business metrics]
+- [System health metrics]
+
+## Future Considerations
+
+### Potential Enhancements
+- [Future feature ideas]
+- [Scalability improvements]
+- [Technical debt items]
+
+### Known Limitations
+- [Current constraints]
+- [Technical restrictions]
+- [Scope boundaries]
+
+## Dependencies
+
+### Runtime Dependencies
+- [External services]
+- [Libraries]
+- [System requirements]
+
+### Development Dependencies
+- [Build tools]
+- [Test frameworks]
+- [Development utilities]
+
+## Security Considerations
+- [Security measures]
+- [Privacy concerns]
+- [Data protection]
+
+## Rollout Strategy
+
+### Development Phase
+1. [Development steps]
+2. [Testing approach]
+3. [Documentation needs]
+
+### Production Deployment
+1. [Deployment steps]
+2. [Migration plan]
+3. [Monitoring setup]
+
+## References
+- [Related documents]
+- [External resources]
+- [Research materials]
\ No newline at end of file
diff --git a/docs/writing_good_interfaces.md b/docs/writing_good_interfaces.md
new file mode 100644
index 0000000..ecb24b8
--- /dev/null
+++ b/docs/writing_good_interfaces.md
@@ -0,0 +1,198 @@
+# Why?
+
+We should first ask ourselves why (or if) spending the time to write good interfaces matters. Is it really worth the investment in a fast paced environment (e.g. startup)? We think yes:
+
+- Well designed interfaces result in localized changes [9]
+- Well designed interfaces result in less "support" [5]
+- Well designed interfaces are easier to learn for new teammates [3]
+
+The essence is that good interfaces are *more scalable* than bad interfaces (in terms of people working on the API and people using it). Consequently, it can be important for a high-growth environment.
+
+# What?
+
+If we agree on the value of good interfaces, we should then talk about what makes an interface good or bad, and whether there are objective criteria for determining the goodness of an interface.
+
+The first thing to get out of the way is that there is no perfect interface and how good an interface is can only be determined within the scope of use cases. For example, reading text via a byte stream is a poor interface for string processing, but could be a great interface for e.g. finding the first 0 bit.
+
+Good interfaces generally satisfy many of the following properties:
+
+- Easy to use correctly
+- Hard to use incorrectly
+- Unsurprising
+- Reports actionable errors
+- Fails fast
+- Minimal boilerplate
+- Consistent mental model or theory [3]
+- Extensible (e.g. via plugins, inheritance, etc)
+- Limited mutability
+- Small (i.e. does "one" thing)
+- Well documented
+- No implementation details leaked
+- Easy to learn and memorize
+
+## Examples
+
+Here we have a few examples of good and bad APIs
+
+- **Python defaultdict**
+
+ It's common to group a collection by some key. We often see folks write python code such as:
+
+ ```python
+ d = {}
+ for word in words:
+ first_letter = word[0]
+ if first_letter in d:
+ d[first_letter].append(word)
+ else:
+ d[first_letter] = [word]
+ ```
+
+ But if we use`defaultdict` instead, we can see it's a much better fit for our use case:
+
+ ```python
+ d = defaultdict(list)
+ for word in words:
+ first_letter = word[0]
+ d[first_letter].append(word)
+ ```
+
+ Important point is that python dicts are not necessarily a "bad API" — but when we consider our use case here, the standard dict API doesn't quite meet the mark!
+
+- **Avoiding Roundtrips**
+
+ Often, some APIs expose implementation or storage details of data. For example, if we wanted to fetch messages for users, it's not uncommon to see an API such as:
+
+ ```java
+ Collection messageIds = getUsers(userIds).messages;
+ Collection messages = getMessages(messageIds);
+ ```
+
+ The reason APIs tend to look like this is that they generally just reflect how our services and such are organized. Note: code architecture and company org structure tend to change over time. Tying APIs to the data layout (rather than how it's consumed) is a recipe for a brittle API. Instead just give users what they want in a single step:
+
+ ```java
+ Collection messages = getMessagesForUsers(userIds);
+ ```
+
+- **Limit Mutability**
+
+ In general, it's preferable to use immutable objects. Consider the following example:
+
+ ```java
+
+ Map m = new HashMap<>();
+ m.put("a", "b");
+
+ int z = someFunc(m);
+
+ assert m.containsKey("a"); // Does this pass or fail?
+ ```
+
+ When objects are mutable, any where they are passed is a place where it is potentially mutated. Mutable objects make it difficult to locally reason about code and generally results in situations where to understand *anything* you have to understand *everything* . I don't know about you, but I'm generally not smart enough to understand everything 😉. A better option would be to have `someFunc` take an `ImmutableMap` so that readers don't need to understand the function to know what the value of `m` might be later in the code!
+
+- **Give Good Errors**
+
+ We often see errors in the wild which don't provide a lot of information; for example:
+
+ ```python
+ IndexError: index out of range
+ ```
+
+ Good errors should have [7]:
+
+ 1. What input was wrong
+ 2. What is wrong about it
+ 3. How to fix it (or next steps for investigation)
+
+ A better error message here would be:
+
+ ```python
+ IndexError: index=7 out of range for object (len=6) with items (showing first 3): 'apple', 'strawberry', 'banana', ...
+ Did you forget to check that your index was not beyond the length of the object?
+ ```
+
+- **Returning Exceptional Values**
+
+ In many cases, there's not a difference between returning something like `null` vs an empty collection. Consider the following interface:
+
+ ```java
+ // Returns null if no known favorite numbers
+ List getFavoriteNumbers(String name);
+
+ // Example usage:
+ List gregFave = getFavoriteNumbers("greg");
+ if (gregFave != null) {
+ gregFave.forEach(System.out.println);
+ }
+ ```
+
+ It may be better to return an empty List instead of null to simplify a user's code here. Note, that's not to say you should never return null. There are many cases where there is a legitimate and well-intentioned difference between null and empty List.
+
+- **Make the interface hard to mis-use**
+
+ Users shouldn't easily mis-use your API. One common error prone practice in APIs is initializing resources which callers are expected to release. For example:
+
+ ```python
+ f = open('myfile.txt', 'r')
+ f.write("blah")
+ f.close()
+ ```
+
+ It's really easy to forget that `close` ! Especially when we consider the possibility of exceptions that may occur between open and close. There are generally language-specific idioms to handle this; such as context managers in python:
+
+ ```python
+ with open('myfile.txt', 'r') as f:
+ f.write("blah")
+ # even if error occurs, the file context manager will ensure file is closed
+ ```
+
+ or in Java, the analogous pattern is [try with resources](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html).
+
+
+See "How" section for some tips, tricks, and best practices for designing good APIs.
+
+# Who? When? Where?
+
+Every engineer writes interfaces [2, 5]. As a guideline, you should always try to write good interfaces. However, it is only a guideline; there are of course legitimate reasons to ignore the guideline. However, the guideline should be ignored consciously rather than haphazardly.
+
+If you are choosing to build a worse-than-you-could API, consider the following actions to limit the effect:
+
+- Use a non-public access modifier
+- Document the costs or problems with the interface
+- Mark the interface as experimental
+
+# How?
+
+We generally refer readers to Sean Parent [1], Scott Meyers [2], Joshua Bloch [5], and Jasmin Blanchette [8] for tips on writing good interfaces, but we leave a summary of advice below:
+
+1. Get use cases to inform requirements
+ - Drive the design based on use cases; remember, an interface can only be good within the context of use cases!
+2. Get a tight feedback loop with users
+ - Write the API first (without implementation), make many examples and share with potential users. Bonus points if you yourself will be a user
+ - These examples can later become test cases
+ - Users are often ambivalent; find people who will use the API and provide you necessary/critical feedback
+3. Keep the API as small as possible
+ - Hyrum's Law: all observable behaviors of your implementation will be depended on by someone
+4. Design for extensibility
+ - Think about what users can extend via inheritance; block inheritance if your API is not designed for it
+ - Think about what hooks/callbacks might be valuable
+ - Accept interfaces instead of implementations in functions/methods
+5. Keep implementation details out of the interface (where possible)
+ - If you must include implementation details, keep it as separated as possible and use "scary" names to denote that users should generally stay away (e.g. `ImplementationSpecificParameters` )
+6. Document every public entity: classes, methods, functions, variables
+ - Bonus points for including example usage
+ - Documentation should explain the "why"
+7. Make errors actionable
+8. Limit mutability
+
+# References
+
+1. [Better Code: Relationships](https://www.youtube.com/watch?v=ejF6qqohp3M) (Sean Parent, Adobe)
+2. [The Most Important Design Guideline](https://www.aristeia.com/Papers/IEEE_Software_JulAug_2004_revised.htm) (Scott Meyers, Effective C++)
+3. [Programming as Theory Building](https://gist.github.com/dpritchett/fd7115b6f556e40103ef) (Peter Naur, Turing Award)
+4. [You Can't Tell People Anything](http://habitatchronicles.com/2004/04/you-cant-tell-people-anything/) (Chip Morningstar, industry veteran)
+5. [How to Design a Good API and Why it Matters](https://www.youtube.com/watch?v=aAb7hSCtvGw) (Joshua Bloch, Effective Java)
+6. [The Mythical Man-Month](https://web.eecs.umich.edu/~weimerw/2018-481/readings/mythical-man-month.pdf) (Fred Brooks, Turing Award)
+7. [What makes a good API?](https://medium.com/@rkuris/good-apis-cd861b8b70a3) (Ron Kuris, industry veteran)
+8. [The Little Manual of API Design](https://web.archive.org/web/20090520234149/http://chaos.troll.no/~shausman/api-design/api-design.pdf) (Jasmin Blanchette, Nokia / Qt)
+9. [Coupling (Wikipedia)](https://en.wikipedia.org/wiki/Coupling_(computer_programming)#Disadvantages_of_tight_coupling)
\ No newline at end of file
diff --git a/global.css b/global.css
index 1259622..27f0765 100644
--- a/global.css
+++ b/global.css
@@ -4,6 +4,7 @@
@layer base {
:root {
+ /* Light mode colors remain unchanged */
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
@@ -26,24 +27,39 @@
}
.dark:root {
+ /* Darkest - Main background */
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
- --card: 240 10% 3.9%;
+
+ /* Slightly lighter - Cards and popovers */
+ --card: 240 10% 5.9%;
--card-foreground: 0 0% 98%;
- --popover: 240 10% 3.9%;
+ --popover: 240 10% 5.9%;
--popover-foreground: 0 0% 98%;
+
+ /* Contrast colors */
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
- --secondary: 240 3.7% 15.9%;
+
+ /* Sheet background - Darker than before */
+ --secondary: 240 3.7% 13%;
--secondary-foreground: 0 0% 98%;
- --muted: 240 3.7% 15.9%;
+
+ /* Interactive elements - Lighter than secondary */
+ --muted: 240 3.7% 18%;
--muted-foreground: 240 5% 64.9%;
- --accent: 240 3.7% 15.9%;
+
+ /* Accents and highlights */
+ --accent: 240 3.7% 18%;
--accent-foreground: 0 0% 98%;
+
+ /* Destructive actions */
--destructive: 0 72% 51%;
--destructive-foreground: 0 0% 98%;
- --border: 240 3.7% 15.9%;
- --input: 240 3.7% 15.9%;
+
+ /* Interactive elements and borders */
+ --border: 240 3.7% 25%;
+ --input: 240 3.7% 25%;
--ring: 240 4.9% 83.9%;
}
-}
+}
\ No newline at end of file
diff --git a/lib/android-navigation-bar.ts b/lib/android-navigation-bar.ts
index 78187e6..ad163f0 100644
--- a/lib/android-navigation-bar.ts
+++ b/lib/android-navigation-bar.ts
@@ -1,6 +1,6 @@
import * as NavigationBar from 'expo-navigation-bar';
import { Platform } from 'react-native';
-import { NAV_THEME } from '~/lib/constants';
+import { NAV_THEME } from '@/lib/constants';
export async function setAndroidNavigationBar(theme: 'light' | 'dark') {
if (Platform.OS !== 'android') return;
diff --git a/lib/constants.ts b/lib/constants.ts
index 7c3d02f..b0f53dc 100644
--- a/lib/constants.ts
+++ b/lib/constants.ts
@@ -1,3 +1,4 @@
+// lib/constants.ts
export const NAV_THEME = {
light: {
background: 'hsl(0 0% 100%)', // background
@@ -16,3 +17,9 @@ export const NAV_THEME = {
text: 'hsl(0 0% 98%)', // foreground
},
};
+
+export const CUSTOM_COLORS = {
+ purple: '#8B5CF6',
+ purplePressed: '#7C3AED', // Slightly darker for pressed state
+ orange: '#F97316'
+} as const;
diff --git a/lib/icons/Check.tsx b/lib/icons/Check.tsx
new file mode 100644
index 0000000..6c56d6d
--- /dev/null
+++ b/lib/icons/Check.tsx
@@ -0,0 +1,4 @@
+import { Check } from 'lucide-react-native';
+import { iconWithClassName } from './iconWithClassName';
+iconWithClassName(Check);
+export { Check };
\ No newline at end of file
diff --git a/lib/icons/ChevronDown.tsx b/lib/icons/ChevronDown.tsx
new file mode 100644
index 0000000..5dd7333
--- /dev/null
+++ b/lib/icons/ChevronDown.tsx
@@ -0,0 +1,4 @@
+import { ChevronDown } from 'lucide-react-native';
+import { iconWithClassName } from './iconWithClassName';
+iconWithClassName(ChevronDown);
+export { ChevronDown };
\ No newline at end of file
diff --git a/lib/icons/ChevronRight.tsx b/lib/icons/ChevronRight.tsx
new file mode 100644
index 0000000..0549a41
--- /dev/null
+++ b/lib/icons/ChevronRight.tsx
@@ -0,0 +1,4 @@
+import { ChevronRight } from 'lucide-react-native';
+import { iconWithClassName } from './iconWithClassName';
+iconWithClassName(ChevronRight);
+export { ChevronRight };
\ No newline at end of file
diff --git a/lib/icons/ChevronUp.tsx b/lib/icons/ChevronUp.tsx
new file mode 100644
index 0000000..21bbea5
--- /dev/null
+++ b/lib/icons/ChevronUp.tsx
@@ -0,0 +1,4 @@
+import { ChevronUp } from 'lucide-react-native';
+import { iconWithClassName } from './iconWithClassName';
+iconWithClassName(ChevronUp);
+export { ChevronUp };
\ No newline at end of file
diff --git a/lib/icons/X.tsx b/lib/icons/X.tsx
new file mode 100644
index 0000000..f3ba2a4
--- /dev/null
+++ b/lib/icons/X.tsx
@@ -0,0 +1,4 @@
+import { X } from 'lucide-react-native';
+import { iconWithClassName } from './iconWithClassName';
+iconWithClassName(X);
+export { X };
\ No newline at end of file
diff --git a/metro.config.js b/metro.config.js
index f3321ba..2f23cd5 100644
--- a/metro.config.js
+++ b/metro.config.js
@@ -1,6 +1,11 @@
+// metro.config.js
const { getDefaultConfig } = require('expo/metro-config');
const { withNativeWind } = require('nativewind/metro');
const config = getDefaultConfig(__dirname);
-module.exports = withNativeWind(config, { input: './global.css' });
+// Add platform-specific extensions
+config.resolver.sourceExts = [...config.resolver.sourceExts, 'web.tsx', 'web.ts', 'web.jsx', 'web.js'];
+config.resolver.platforms = ['ios', 'android', 'web'];
+
+module.exports = withNativeWind(config, { input: './global.css' });
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 5f7a6ee..b720fc4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,11 +9,34 @@
"version": "1.0.0",
"hasInstallScript": true,
"dependencies": {
+ "@radix-ui/react-alert-dialog": "^1.1.6",
+ "@react-navigation/material-top-tabs": "^7.1.0",
"@react-navigation/native": "^7.0.0",
+ "@rn-primitives/accordion": "^1.1.0",
+ "@rn-primitives/alert-dialog": "^1.1.0",
+ "@rn-primitives/aspect-ratio": "^1.1.0",
"@rn-primitives/avatar": "~1.1.0",
+ "@rn-primitives/checkbox": "^1.1.0",
+ "@rn-primitives/collapsible": "^1.1.0",
+ "@rn-primitives/context-menu": "^1.1.0",
+ "@rn-primitives/dialog": "^1.1.0",
+ "@rn-primitives/dropdown-menu": "^1.1.0",
+ "@rn-primitives/hover-card": "^1.1.0",
+ "@rn-primitives/label": "^1.1.0",
+ "@rn-primitives/menubar": "^1.1.0",
+ "@rn-primitives/navigation-menu": "^1.1.0",
+ "@rn-primitives/popover": "^1.1.0",
"@rn-primitives/portal": "~1.1.0",
"@rn-primitives/progress": "~1.1.0",
+ "@rn-primitives/radio-group": "^1.1.0",
+ "@rn-primitives/select": "^1.1.0",
+ "@rn-primitives/separator": "^1.1.0",
"@rn-primitives/slot": "~1.1.0",
+ "@rn-primitives/switch": "^1.1.0",
+ "@rn-primitives/table": "^1.1.0",
+ "@rn-primitives/tabs": "^1.1.0",
+ "@rn-primitives/toggle": "^1.1.0",
+ "@rn-primitives/toggle-group": "^1.1.0",
"@rn-primitives/tooltip": "~1.1.0",
"@rn-primitives/types": "~1.1.0",
"class-variance-authority": "^0.7.0",
@@ -30,10 +53,13 @@
"react": "18.3.1",
"react-dom": "18.3.1",
"react-native": "0.76.6",
+ "react-native-gesture-handler": "~2.20.2",
+ "react-native-pager-view": "^6.5.1",
"react-native-reanimated": "~3.16.1",
"react-native-safe-area-context": "4.12.0",
"react-native-screens": "~4.4.0",
"react-native-svg": "15.8.0",
+ "react-native-tab-view": "^4.0.5",
"react-native-web": "~0.19.13",
"tailwind-merge": "^2.2.1",
"tailwindcss": "3.3.5",
@@ -43,6 +69,7 @@
"devDependencies": {
"@babel/core": "^7.26.0",
"@types/react": "~18.3.12",
+ "babel-plugin-module-resolver": "^5.0.2",
"typescript": "^5.3.3"
}
},
@@ -2203,6 +2230,18 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@egjs/hammerjs": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
+ "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hammerjs": "^2.0.36"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/@expo/bunyan": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@expo/bunyan/-/bunyan-4.0.1.tgz",
@@ -3267,12 +3306,238 @@
"node": ">=14"
}
},
+ "node_modules/@radix-ui/number": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz",
+ "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==",
+ "license": "MIT"
+ },
"node_modules/@radix-ui/primitive": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==",
"license": "MIT"
},
+ "node_modules/@radix-ui/react-alert-dialog": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.6.tgz",
+ "integrity": "sha512-p4XnPqgej8sZAAReCAKgz1REYZEBLR8hU9Pg27wFnCWIMc8g1ccCs0FjBcy05V15VTu8pAePw/VDYeOm/uZ6yQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-dialog": "1.1.6",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-dialog": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz",
+ "integrity": "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.5",
+ "@radix-ui/react-focus-guards": "1.1.1",
+ "@radix-ui/react-focus-scope": "1.1.2",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-portal": "1.1.4",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
+ "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz",
+ "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
+ "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz",
@@ -3300,6 +3565,36 @@
}
}
},
+ "node_modules/@radix-ui/react-direction": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
+ "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-guards": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz",
+ "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-id": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
@@ -3397,6 +3692,21 @@
}
}
},
+ "node_modules/@radix-ui/react-use-previous": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz",
+ "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-use-rect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz",
@@ -3869,6 +4179,23 @@
}
}
},
+ "node_modules/@react-navigation/material-top-tabs": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@react-navigation/material-top-tabs/-/material-top-tabs-7.1.0.tgz",
+ "integrity": "sha512-bTFgeHWZmkyE9CAVMTc+lw/b1n2ES3bk0JZoCNSTIrDP+tXfsS8CB4lpOhBybfX1q0C4NQ/i4qMlV7p1iO0eKA==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/elements": "^2.2.5",
+ "color": "^4.2.3",
+ "react-native-tab-view": "^4.0.5"
+ },
+ "peerDependencies": {
+ "@react-navigation/native": "^7.0.14",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-pager-view": ">= 6.0.0"
+ }
+ },
"node_modules/@react-navigation/native": {
"version": "7.0.14",
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.0.14.tgz",
@@ -4029,6 +4356,247 @@
"web-streams-polyfill": "^3.1.1"
}
},
+ "node_modules/@rn-primitives/accordion": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/accordion/-/accordion-1.1.0.tgz",
+ "integrity": "sha512-CzqseeoPfw+NT+cb9+Z8ejd6YGM9dJK2YDjD4ODoiYe/eSSbE+AwOaEs4J5hU6nMS1awraDZmBLqUNw7FCDBRA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-accordion": "^1.2.0",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/accordion/node_modules/@radix-ui/react-accordion": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.3.tgz",
+ "integrity": "sha512-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collapsible": "1.1.3",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/accordion/node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collapsible": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.3.tgz",
+ "integrity": "sha512-jFSerheto1X03MUC0g6R7LedNW9EEGWdg9W1+MlpkMLwGkgkbUXLPBH/KIuWKXUoeYRVY11llqbTBDzuLg7qrw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/accordion/node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/accordion/node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
+ "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/accordion/node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/accordion/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/accordion/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/alert-dialog": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/alert-dialog/-/alert-dialog-1.1.0.tgz",
+ "integrity": "sha512-8jp0TeoELezad/VSdq0jflYKXG0j9Ib8MA3eJEmbTp+KhAiZ9bgz3ARVep/4TU7NAigdu6I7zuX1TM2hFbiqTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-alert-dialog": "^1.1.1",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "@rn-primitives/portal": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/aspect-ratio": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/aspect-ratio/-/aspect-ratio-1.1.0.tgz",
+ "integrity": "sha512-yehI3Zvlv9GOhIRELuwVxHv7ERQZBYhGnOsxwFqjA2XPMoOMwuGfh5Pm8LgVJaTEsrKWqsOw4JJ/Hqt87XdTKw==",
+ "license": "MIT",
+ "dependencies": {
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rn-primitives/avatar": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rn-primitives/avatar/-/avatar-1.1.0.tgz",
@@ -4053,6 +4621,1247 @@
}
}
},
+ "node_modules/@rn-primitives/checkbox": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/checkbox/-/checkbox-1.1.0.tgz",
+ "integrity": "sha512-drIWeB41LOkkGDHUKM++7e5vuODB6KeX7qJR3JfYoF0FDRGMG23f3cCo6cQy6DNgsjBctGPpTojQQxuLjuuTWg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-checkbox": "^1.1.1",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/checkbox/node_modules/@radix-ui/react-checkbox": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.4.tgz",
+ "integrity": "sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "@radix-ui/react-use-previous": "1.1.0",
+ "@radix-ui/react-use-size": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/checkbox/node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/checkbox/node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/checkbox/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/checkbox/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/collapsible": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/collapsible/-/collapsible-1.1.0.tgz",
+ "integrity": "sha512-ca4lzjG1/ku8f9QA/yw99PNYXPJI1IF3cdOL102mrLDl8O5wuD/21bGA3vvvBMR246hOF1AvCpB9ZN+XnnhngQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-collapsible": "^1.1.0",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/collapsible/node_modules/@radix-ui/react-collapsible": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.3.tgz",
+ "integrity": "sha512-jFSerheto1X03MUC0g6R7LedNW9EEGWdg9W1+MlpkMLwGkgkbUXLPBH/KIuWKXUoeYRVY11llqbTBDzuLg7qrw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/collapsible/node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/collapsible/node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/collapsible/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/collapsible/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/context-menu/-/context-menu-1.1.0.tgz",
+ "integrity": "sha512-VDgbrQpKtsInnVOhgC9cnKzcV7pYNpicImtmjJyS+BuDRcItwMAwy/4Q7jSoloB0eylFrpM0GClf4HWVAcoYDg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-context-menu": "^2.2.1",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0",
+ "@rn-primitives/utils": "1.1.0"
+ },
+ "peerDependencies": {
+ "@rn-primitives/portal": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.6.tgz",
+ "integrity": "sha512-aUP99QZ3VU84NPsHeaFt4cQUNgJqFsLLOt/RbbWXszZ6MP0DpDyjkFZORr4RpAEx3sUBk+Kc8h13yGtC5Qw8dg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-menu": "2.1.6",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-menu": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.6.tgz",
+ "integrity": "sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-dismissable-layer": "1.1.5",
+ "@radix-ui/react-focus-guards": "1.1.1",
+ "@radix-ui/react-focus-scope": "1.1.2",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-popper": "1.2.2",
+ "@radix-ui/react-portal": "1.1.4",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-roving-focus": "1.1.2",
+ "@radix-ui/react-slot": "1.1.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
+ "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
+ "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz",
+ "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
+ "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0",
+ "@radix-ui/react-use-rect": "1.1.0",
+ "@radix-ui/react-use-size": "1.1.0",
+ "@radix-ui/rect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper/node_modules/@floating-ui/react-dom": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
+ "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
+ "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
+ "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz",
+ "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/context-menu/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dialog": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/dialog/-/dialog-1.1.0.tgz",
+ "integrity": "sha512-ZEq0eayERy9Nwys9GFAM2Q1UHu/JOBuSSCSLXUXtAn26SAdFfKn2KAWZwCxQXGW2Kph9GV9B/Vm6X5vCe8Ct2w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-dialog": "^1.1.1",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "@rn-primitives/portal": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dialog/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dialog/node_modules/@radix-ui/react-dialog": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz",
+ "integrity": "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.5",
+ "@radix-ui/react-focus-guards": "1.1.1",
+ "@radix-ui/react-focus-scope": "1.1.2",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-portal": "1.1.4",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dialog/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
+ "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dialog/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz",
+ "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dialog/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
+ "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dialog/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dialog/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dialog/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/dropdown-menu/-/dropdown-menu-1.1.0.tgz",
+ "integrity": "sha512-vf+n9daClIUfydT43uIOpscISftha0oweZXQJqwcSkoDXM6+4GHc6+Q26uirBb3mccD1dwyfoTiHPAHygOHHSw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-dropdown-menu": "^2.1.1",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0",
+ "@rn-primitives/utils": "1.1.0"
+ },
+ "peerDependencies": {
+ "@rn-primitives/portal": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.6.tgz",
+ "integrity": "sha512-no3X7V5fD487wab/ZYSHXq3H37u4NVeLDKI/Ks724X/eEFSSEFYZxWgsIlr1UBeEyDaM29HM5x9p1Nv8DuTYPA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-menu": "2.1.6",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.6.tgz",
+ "integrity": "sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-dismissable-layer": "1.1.5",
+ "@radix-ui/react-focus-guards": "1.1.1",
+ "@radix-ui/react-focus-scope": "1.1.2",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-popper": "1.2.2",
+ "@radix-ui/react-portal": "1.1.4",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-roving-focus": "1.1.2",
+ "@radix-ui/react-slot": "1.1.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
+ "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
+ "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz",
+ "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
+ "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0",
+ "@radix-ui/react-use-rect": "1.1.0",
+ "@radix-ui/react-use-size": "1.1.0",
+ "@radix-ui/rect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper/node_modules/@floating-ui/react-dom": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
+ "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
+ "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
+ "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz",
+ "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/dropdown-menu/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rn-primitives/hooks": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rn-primitives/hooks/-/hooks-1.1.0.tgz",
@@ -4075,6 +5884,1252 @@
}
}
},
+ "node_modules/@rn-primitives/hover-card": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/hover-card/-/hover-card-1.1.0.tgz",
+ "integrity": "sha512-djnts2OqZPNup2n6gnvO+ndOcDNBBeMVzf1U1kp3V2DNsk+63D8/gj8kBygMk33/EzjtxyvIIZrqGe1/8HrGlw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-hover-card": "^1.1.1",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/popover": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "@rn-primitives/portal": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/hover-card/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/hover-card/node_modules/@radix-ui/react-hover-card": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.6.tgz",
+ "integrity": "sha512-E4ozl35jq0VRlrdc4dhHrNSV0JqBb4Jy73WAhBEK7JoYnQ83ED5r0Rb/XdVKw89ReAJN38N492BAPBZQ57VmqQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.5",
+ "@radix-ui/react-popper": "1.2.2",
+ "@radix-ui/react-portal": "1.1.4",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/hover-card/node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
+ "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/hover-card/node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-popper": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
+ "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0",
+ "@radix-ui/react-use-rect": "1.1.0",
+ "@radix-ui/react-use-size": "1.1.0",
+ "@radix-ui/rect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/hover-card/node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-popper/node_modules/@floating-ui/react-dom": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
+ "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@rn-primitives/hover-card/node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
+ "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/hover-card/node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
+ "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/hover-card/node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/hover-card/node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/hover-card/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/label": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/label/-/label-1.1.0.tgz",
+ "integrity": "sha512-wNxXu45wzE12M0LYPR6g2DYVZsD4zf9EiXecP46pJfC8XEhUPhcgzAE8oa1xfEUU+P8O29ZIWoK/CPtAodFBfw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-label": "^2.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/label/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/label/node_modules/@radix-ui/react-label": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.2.tgz",
+ "integrity": "sha512-zo1uGMTaNlHehDyFQcDZXRJhUPDuukcnHz0/jnrup0JA6qL+AFpAnty+7VKa9esuU5xTblAZzTGYJKSKaBxBhw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/label/node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/label/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/menubar/-/menubar-1.1.0.tgz",
+ "integrity": "sha512-tWwWPAVHe/RN+FLjpeqHO02ZSGSPqmpZb4tmoqN1P/KhEd9ES1aI+yrLdQWZ3jcyaVnJCXsXHZLFEBndVr26ug==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-menubar": "^1.1.1",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0",
+ "@rn-primitives/utils": "1.1.0"
+ },
+ "peerDependencies": {
+ "@rn-primitives/portal": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.6.tgz",
+ "integrity": "sha512-FHq7+3DlXwh/7FOM4i0G4bC4vPjiq89VEEvNF4VMLchGnaUuUbE5uKXMUCjdKaOghEEMeiKa5XCa2Pk4kteWmg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-menu": "2.1.6",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-roving-focus": "1.1.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
+ "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-menu": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.6.tgz",
+ "integrity": "sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-dismissable-layer": "1.1.5",
+ "@radix-ui/react-focus-guards": "1.1.1",
+ "@radix-ui/react-focus-scope": "1.1.2",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-popper": "1.2.2",
+ "@radix-ui/react-portal": "1.1.4",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-roving-focus": "1.1.2",
+ "@radix-ui/react-slot": "1.1.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
+ "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz",
+ "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
+ "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0",
+ "@radix-ui/react-use-rect": "1.1.0",
+ "@radix-ui/react-use-size": "1.1.0",
+ "@radix-ui/rect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper/node_modules/@floating-ui/react-dom": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
+ "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
+ "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
+ "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-menubar/node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz",
+ "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/menubar/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/navigation-menu": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/navigation-menu/-/navigation-menu-1.1.0.tgz",
+ "integrity": "sha512-ONrOJIzxqogO8fYyVJ7d9ycwfy74qrnT47OtVRIqXJrll268FCWm5uNeWsAGuq2yyIdGx59AyXrAhpjVScZgcA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-navigation-menu": "^1.2.0",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0",
+ "@rn-primitives/utils": "1.1.0"
+ },
+ "peerDependencies": {
+ "@rn-primitives/portal": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/navigation-menu/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/navigation-menu/node_modules/@radix-ui/react-navigation-menu": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.5.tgz",
+ "integrity": "sha512-myMHHQUZ3ZLTi8W381/Vu43Ia0NqakkQZ2vzynMmTUtQQ9kNkjzhOwkZC9TAM5R07OZUVIQyHC06f/9JZJpvvA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-dismissable-layer": "1.1.5",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0",
+ "@radix-ui/react-use-previous": "1.1.0",
+ "@radix-ui/react-visually-hidden": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/navigation-menu/node_modules/@radix-ui/react-navigation-menu/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
+ "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/navigation-menu/node_modules/@radix-ui/react-navigation-menu/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
+ "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/navigation-menu/node_modules/@radix-ui/react-navigation-menu/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/navigation-menu/node_modules/@radix-ui/react-navigation-menu/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/navigation-menu/node_modules/@radix-ui/react-navigation-menu/node_modules/@radix-ui/react-visually-hidden": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz",
+ "integrity": "sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/navigation-menu/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/popover/-/popover-1.1.0.tgz",
+ "integrity": "sha512-2LU6sGdITvmRtKJwfGDHZ5pFz0eOySlw2lJERqrfAmMiiYWhq4WItkBh386u/IzlAyAoPVQVDmIrYgQVH1rkfA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-popover": "^1.1.1",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "@rn-primitives/portal": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-popover": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.6.tgz",
+ "integrity": "sha512-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.5",
+ "@radix-ui/react-focus-guards": "1.1.1",
+ "@radix-ui/react-focus-scope": "1.1.2",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-popper": "1.2.2",
+ "@radix-ui/react-portal": "1.1.4",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
+ "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz",
+ "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
+ "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0",
+ "@radix-ui/react-use-rect": "1.1.0",
+ "@radix-ui/react-use-size": "1.1.0",
+ "@radix-ui/rect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper/node_modules/@floating-ui/react-dom": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
+ "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
+ "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
+ "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/popover/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rn-primitives/portal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rn-primitives/portal/-/portal-1.1.0.tgz",
@@ -4201,6 +7256,620 @@
}
}
},
+ "node_modules/@rn-primitives/radio-group": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/radio-group/-/radio-group-1.1.0.tgz",
+ "integrity": "sha512-CBmOfStZvX00B1e3MooORrVu8m/acsN8W0jZY2ptSZb1nWYfQI2Su6zka+O6gmoytBpun16LNTxD5/ZCz95e+A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-radio-group": "^1.2.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/radio-group/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/radio-group/node_modules/@radix-ui/react-radio-group": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.2.3.tgz",
+ "integrity": "sha512-xtCsqt8Rp09FK50ItqEqTJ7Sxanz8EM8dnkVIhJrc/wkMMomSmXHvYbhv3E7Zx4oXh98aaLt9W679SUYXg4IDA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-roving-focus": "1.1.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "@radix-ui/react-use-previous": "1.1.0",
+ "@radix-ui/react-use-size": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/radio-group/node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/radio-group/node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/radio-group/node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz",
+ "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/radio-group/node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
+ "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/radio-group/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/select/-/select-1.1.0.tgz",
+ "integrity": "sha512-DgBzEGi36NjXfrftMEuitDrfwaD0zgCNfTWnLtIzYkZ9G19uHSEnO2PL6wCy8qInPgDWevKvcy8Cilj2lj9+jA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-select": "^2.1.1",
+ "@rn-primitives/hooks": "1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "@rn-primitives/portal": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-select": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.6.tgz",
+ "integrity": "sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/number": "1.1.0",
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-dismissable-layer": "1.1.5",
+ "@radix-ui/react-focus-guards": "1.1.1",
+ "@radix-ui/react-focus-scope": "1.1.2",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-popper": "1.2.2",
+ "@radix-ui/react-portal": "1.1.4",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0",
+ "@radix-ui/react-use-previous": "1.1.0",
+ "@radix-ui/react-visually-hidden": "1.1.2",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
+ "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
+ "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz",
+ "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
+ "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0",
+ "@radix-ui/react-use-rect": "1.1.0",
+ "@radix-ui/react-use-size": "1.1.0",
+ "@radix-ui/rect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper/node_modules/@floating-ui/react-dom": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
+ "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
+ "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
+ "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-visually-hidden": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz",
+ "integrity": "sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/select/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/separator/-/separator-1.1.0.tgz",
+ "integrity": "sha512-U38RYkC/PI3P8TbSvSwdVjTer/eqel9GlfY1E5I0XHvn0o7A0ca+he6ud4KvJeanT0CJma1OFKBOE7n6r/DI/Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-separator": "^1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/separator/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/separator/node_modules/@radix-ui/react-separator": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.2.tgz",
+ "integrity": "sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/separator/node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/separator/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rn-primitives/slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rn-primitives/slot/-/slot-1.1.0.tgz",
@@ -4220,6 +7889,626 @@
}
}
},
+ "node_modules/@rn-primitives/switch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/switch/-/switch-1.1.0.tgz",
+ "integrity": "sha512-Ng58j1p0w4Y2+wBa93jE/kDh/+WNajqxBeBoCERQxKBDtE1BFLVHh7c0dhQo48IZpL2r8EHuyeTrbMPad/tPMg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-switch": "^1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/switch/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/switch/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/switch/node_modules/@radix-ui/react-switch": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.3.tgz",
+ "integrity": "sha512-1nc+vjEOQkJVsJtWPSiISGT6OKm4SiOdjMo+/icLxo2G4vxz1GntC5MzfL4v8ey9OEfw787QCD1y3mUv0NiFEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "@radix-ui/react-use-previous": "1.1.0",
+ "@radix-ui/react-use-size": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/switch/node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/table": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/table/-/table-1.1.0.tgz",
+ "integrity": "sha512-uazg7vokxbPz0QId2ZCsIQfpSCxSso9oWUy6iYPMNXsMkvqMIwVdL60EF1+UsqhseQ2UK+4uQJQkYRhce3jxbA==",
+ "license": "MIT",
+ "dependencies": {
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/tabs": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/tabs/-/tabs-1.1.0.tgz",
+ "integrity": "sha512-zOEBjjmEoJas9t6c7Z5EhGGeG5RdQ4J9QBtm255kKa9uO+a5EL9QV6gWzDnmsFq2tPSggKeNVxjsjfS3j5BrHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-tabs": "^1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/tabs/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/tabs/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/tabs/node_modules/@radix-ui/react-tabs": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.3.tgz",
+ "integrity": "sha512-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-roving-focus": "1.1.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/tabs/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+ "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/tabs/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/tabs/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz",
+ "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/tabs/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
+ "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/toggle/-/toggle-1.1.0.tgz",
+ "integrity": "sha512-vE1rpRj/apqlSV9+/WOwKwkR9TlQQN5E9L/deQehFVaUVln+830pIkl7rsdmFVCqkOEC+mUw9gaYYVLhejJSww==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-toggle": "^1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle-group": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/toggle-group/-/toggle-group-1.1.0.tgz",
+ "integrity": "sha512-ENjizzEC9UnWCXxSSG9myBgZUO7J6ObulF3Gcgmpgpj+HZ0c60yfc7cwm5jS10/oFhvlG8zqpUEDblEZ7q03sQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-toggle-group": "^1.1.0",
+ "@rn-primitives/slot": "1.1.0",
+ "@rn-primitives/types": "1.1.0",
+ "@rn-primitives/utils": "1.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle-group/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle-group/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle-group/node_modules/@radix-ui/react-toggle-group": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.2.tgz",
+ "integrity": "sha512-JBm6s6aVG/nwuY5eadhU2zDi/IwYS0sDM5ZWb4nymv/hn3hZdkw+gENn0LP4iY1yCd7+bgJaCwueMYJIU3vk4A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-roving-focus": "1.1.2",
+ "@radix-ui/react-toggle": "1.1.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle-group/node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle-group/node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz",
+ "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle-group/node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
+ "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle-group/node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-toggle": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.2.tgz",
+ "integrity": "sha512-lntKchNWx3aCHuWKiDY+8WudiegQvBpDRAYL8dKLRvKEH8VOpl0XX6SSU/bUBqIRJbcTy4+MW06Wv8vgp10rzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle/node_modules/@radix-ui/react-toggle": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.2.tgz",
+ "integrity": "sha512-lntKchNWx3aCHuWKiDY+8WudiegQvBpDRAYL8dKLRvKEH8VOpl0XX6SSU/bUBqIRJbcTy4+MW06Wv8vgp10rzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rn-primitives/toggle/node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rn-primitives/tooltip": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rn-primitives/tooltip/-/tooltip-1.1.0.tgz",
@@ -4521,6 +8810,25 @@
}
}
},
+ "node_modules/@rn-primitives/utils": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rn-primitives/utils/-/utils-1.1.0.tgz",
+ "integrity": "sha512-pIlKWQeYkKRxOy5FZe6B1YWSYFqrfuA7hBUFz8Ryi9KmySNLsB49iAuXV/ZtqDAkxQvNKNSzpqS4omQOCftvXw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native": {
+ "optional": true
+ },
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@segment/loosely-validate-event": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz",
@@ -4610,6 +8918,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/hammerjs": {
+ "version": "2.0.46",
+ "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz",
+ "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==",
+ "license": "MIT"
+ },
"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",
@@ -4935,6 +9249,18 @@
"sprintf-js": "~1.0.2"
}
},
+ "node_modules/aria-hidden": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz",
+ "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/array-timsort": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz",
@@ -5065,6 +9391,75 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/babel-plugin-module-resolver": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.2.tgz",
+ "integrity": "sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-babel-config": "^2.1.1",
+ "glob": "^9.3.3",
+ "pkg-up": "^3.1.0",
+ "reselect": "^4.1.7",
+ "resolve": "^1.22.8"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/glob": {
+ "version": "9.3.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz",
+ "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "minimatch": "^8.0.2",
+ "minipass": "^4.2.4",
+ "path-scurry": "^1.6.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/minimatch": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz",
+ "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/minipass": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
+ "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/babel-plugin-polyfill-corejs2": {
"version": "0.4.12",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz",
@@ -6366,6 +10761,12 @@
"node": ">=0.10"
}
},
+ "node_modules/detect-node-es": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
+ "license": "MIT"
+ },
"node_modules/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@@ -7234,6 +11635,16 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
+ "node_modules/find-babel-config": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.1.2.tgz",
+ "integrity": "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json5": "^2.2.3"
+ }
+ },
"node_modules/find-cache-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
@@ -7445,6 +11856,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-nonce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/get-package-type": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
@@ -7684,6 +12104,21 @@
"hermes-estree": "0.23.1"
}
},
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/hoist-non-react-statics/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT"
+ },
"node_modules/hosted-git-info": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
@@ -10351,6 +14786,85 @@
"node": ">=4"
}
},
+ "node_modules/pkg-up": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
+ "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-up": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pkg-up/node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pkg-up/node_modules/locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pkg-up/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/pkg-up/node_modules/p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pkg-up/node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/plist": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
@@ -10950,6 +15464,22 @@
"node": ">=10"
}
},
+ "node_modules/react-native-gesture-handler": {
+ "version": "2.20.2",
+ "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.20.2.tgz",
+ "integrity": "sha512-HqzFpFczV4qCnwKlvSAvpzEXisL+Z9fsR08YV5LfJDkzuArMhBu2sOoSPUF/K62PCoAb+ObGlTC83TKHfUd0vg==",
+ "license": "MIT",
+ "dependencies": {
+ "@egjs/hammerjs": "^2.0.17",
+ "hoist-non-react-statics": "^3.3.0",
+ "invariant": "^2.2.4",
+ "prop-types": "^15.7.2"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/react-native-helmet-async": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/react-native-helmet-async/-/react-native-helmet-async-2.0.4.tgz",
@@ -10974,6 +15504,16 @@
"react-native": ">=0.73.0"
}
},
+ "node_modules/react-native-pager-view": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.5.1.tgz",
+ "integrity": "sha512-YdX7bP+rPYvATMU7HzlMq9JaG3ui/+cVRbFZFGW+QshDULANFg9ECR1BA7H7JTIcO/ZgWCwF+1aVmYG5yBA9Og==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/react-native-reanimated": {
"version": "3.16.7",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.16.7.tgz",
@@ -11037,6 +15577,20 @@
"react-native": "*"
}
},
+ "node_modules/react-native-tab-view": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-4.0.5.tgz",
+ "integrity": "sha512-Xn3TpYo4yvKRC/f4+cOcvsXlitdnSaYkacshckrEI3JiDmFKNFIRVNxtZFggm4MwbJafq2RzuzR6xrgKoxgkTw==",
+ "license": "MIT",
+ "dependencies": {
+ "use-latest-callback": "^0.2.1"
+ },
+ "peerDependencies": {
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-pager-view": ">= 6.0.0"
+ }
+ },
"node_modules/react-native-web": {
"version": "0.19.13",
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.13.tgz",
@@ -11162,6 +15716,75 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-remove-scroll": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz",
+ "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==",
+ "license": "MIT",
+ "dependencies": {
+ "react-remove-scroll-bar": "^2.3.7",
+ "react-style-singleton": "^2.2.3",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.3",
+ "use-sidecar": "^1.1.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-remove-scroll-bar": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
+ "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
+ "license": "MIT",
+ "dependencies": {
+ "react-style-singleton": "^2.2.2",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-style-singleton": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
+ "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "get-nonce": "^1.0.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -11369,6 +15992,13 @@
"path-parse": "^1.0.5"
}
},
+ "node_modules/reselect": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz",
+ "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@@ -12907,6 +17537,27 @@
"browserslist": ">= 4.21.0"
}
},
+ "node_modules/use-callback-ref": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
+ "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/use-latest-callback": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.3.tgz",
@@ -12916,6 +17567,28 @@
"react": ">=16.8"
}
},
+ "node_modules/use-sidecar": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
+ "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "detect-node-es": "^1.1.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/use-sync-external-store": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz",
diff --git a/package.json b/package.json
index 078e047..3d41f19 100644
--- a/package.json
+++ b/package.json
@@ -13,11 +13,34 @@
"postinstall": "npx tailwindcss -i ./global.css -o ./node_modules/.cache/nativewind/global.css"
},
"dependencies": {
+ "@radix-ui/react-alert-dialog": "^1.1.6",
+ "@react-navigation/material-top-tabs": "^7.1.0",
"@react-navigation/native": "^7.0.0",
+ "@rn-primitives/accordion": "^1.1.0",
+ "@rn-primitives/alert-dialog": "^1.1.0",
+ "@rn-primitives/aspect-ratio": "^1.1.0",
"@rn-primitives/avatar": "~1.1.0",
+ "@rn-primitives/checkbox": "^1.1.0",
+ "@rn-primitives/collapsible": "^1.1.0",
+ "@rn-primitives/context-menu": "^1.1.0",
+ "@rn-primitives/dialog": "^1.1.0",
+ "@rn-primitives/dropdown-menu": "^1.1.0",
+ "@rn-primitives/hover-card": "^1.1.0",
+ "@rn-primitives/label": "^1.1.0",
+ "@rn-primitives/menubar": "^1.1.0",
+ "@rn-primitives/navigation-menu": "^1.1.0",
+ "@rn-primitives/popover": "^1.1.0",
"@rn-primitives/portal": "~1.1.0",
"@rn-primitives/progress": "~1.1.0",
+ "@rn-primitives/radio-group": "^1.1.0",
+ "@rn-primitives/select": "^1.1.0",
+ "@rn-primitives/separator": "^1.1.0",
"@rn-primitives/slot": "~1.1.0",
+ "@rn-primitives/switch": "^1.1.0",
+ "@rn-primitives/table": "^1.1.0",
+ "@rn-primitives/tabs": "^1.1.0",
+ "@rn-primitives/toggle": "^1.1.0",
+ "@rn-primitives/toggle-group": "^1.1.0",
"@rn-primitives/tooltip": "~1.1.0",
"@rn-primitives/types": "~1.1.0",
"class-variance-authority": "^0.7.0",
@@ -34,10 +57,13 @@
"react": "18.3.1",
"react-dom": "18.3.1",
"react-native": "0.76.6",
+ "react-native-gesture-handler": "~2.20.2",
+ "react-native-pager-view": "^6.5.1",
"react-native-reanimated": "~3.16.1",
"react-native-safe-area-context": "4.12.0",
"react-native-screens": "~4.4.0",
"react-native-svg": "15.8.0",
+ "react-native-tab-view": "^4.0.5",
"react-native-web": "~0.19.13",
"tailwind-merge": "^2.2.1",
"tailwindcss": "3.3.5",
@@ -47,6 +73,7 @@
"devDependencies": {
"@babel/core": "^7.26.0",
"@types/react": "~18.3.12",
+ "babel-plugin-module-resolver": "^5.0.2",
"typescript": "^5.3.3"
},
"private": true
diff --git a/tests/type-test.ts b/tests/type-test.ts
new file mode 100644
index 0000000..fa594b4
--- /dev/null
+++ b/tests/type-test.ts
@@ -0,0 +1,19 @@
+// tests/type-test.ts (just to verify types)
+import { BaseExercise } from '@/types/exercise';
+import { StorageSource } from '@/types/shared';
+
+// This should compile if our types are correct
+const testExercise: BaseExercise = {
+ // SyncableContent properties
+ id: 'test-id',
+ created_at: Date.now(),
+ availability: {
+ source: ['local' as StorageSource]
+ },
+
+ // BaseExercise properties
+ title: 'Test Exercise',
+ type: 'strength',
+ category: 'Push',
+ tags: [],
+};
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 7819c6e..d1781a5 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,7 +4,7 @@
"strict": true,
"baseUrl": ".",
"paths": {
- "~/*": [
+ "@/*": [
"*"
]
}
diff --git a/types/exercise.ts b/types/exercise.ts
new file mode 100644
index 0000000..d9bd749
--- /dev/null
+++ b/types/exercise.ts
@@ -0,0 +1,139 @@
+// types/exercise.ts - handles everything about individual exercises
+import { NostrEventKind } from './events';
+import { SyncableContent } from './shared';
+
+// Exercise classification types
+export type ExerciseType = 'strength' | 'cardio' | 'bodyweight';
+export type ExerciseCategory = 'Push' | 'Pull' | 'Legs' | 'Core';
+export type Equipment =
+ | 'bodyweight'
+ | 'barbell'
+ | 'dumbbell'
+ | 'kettlebell'
+ | 'machine'
+ | 'cable'
+ | 'other';
+
+// Base library content interface
+export interface LibraryContent extends SyncableContent {
+ title: string;
+ type: 'exercise' | 'workout' | 'program';
+ description?: string;
+ author?: {
+ name: string;
+ pubkey?: string;
+ };
+ category?: ExerciseCategory;
+ equipment?: Equipment;
+ source: 'local' | 'pow' | 'nostr';
+ tags: string[];
+ isPublic?: boolean;
+}
+
+// Basic exercise definition
+export interface BaseExercise extends SyncableContent {
+ title: string;
+ type: ExerciseType;
+ category: ExerciseCategory;
+ equipment?: Equipment;
+ description?: string;
+ instructions?: string[];
+ tags: string[];
+ format?: {
+ weight?: boolean;
+ reps?: boolean;
+ rpe?: boolean;
+ set_type?: boolean;
+ };
+ format_units?: {
+ weight?: 'kg' | 'lbs';
+ reps?: 'count';
+ rpe?: '0-10';
+ set_type?: 'warmup|normal|drop|failure';
+ };
+}
+
+// Set types and formats
+export type SetType = 'warmup' | 'normal' | 'drop' | 'failure';
+
+export interface WorkoutSet {
+ id: string;
+ weight?: number;
+ reps?: number;
+ rpe?: number;
+ type: SetType;
+ isCompleted: boolean;
+ notes?: string;
+ timestamp?: number;
+}
+
+// Exercise with workout-specific data
+export interface WorkoutExercise extends BaseExercise {
+ sets: WorkoutSet[];
+ totalWeight?: number;
+ notes?: string;
+ restTime?: number; // Rest time in seconds
+ targetSets?: number;
+ targetReps?: number;
+}
+
+// Exercise template specific types
+export interface ExerciseTemplate extends BaseExercise {
+ defaultSets?: {
+ type: SetType;
+ weight?: number;
+ reps?: number;
+ rpe?: number;
+ }[];
+ recommendations?: {
+ beginnerWeight?: number;
+ intermediateWeight?: number;
+ advancedWeight?: number;
+ restTime?: number;
+ tempo?: string;
+ };
+ variations?: string[];
+ progression?: {
+ type: 'linear' | 'percentage' | 'custom';
+ increment?: number;
+ rules?: string[];
+ };
+}
+
+// Exercise history and progress tracking
+export interface ExerciseHistory {
+ exerciseId: string;
+ entries: Array<{
+ date: number;
+ workoutId: string;
+ sets: WorkoutSet[];
+ totalWeight: number;
+ notes?: string;
+ }>;
+ personalBests: {
+ weight?: {
+ value: number;
+ date: number;
+ workoutId: string;
+ };
+ reps?: {
+ value: number;
+ date: number;
+ workoutId: string;
+ };
+ volume?: {
+ value: number;
+ date: number;
+ workoutId: string;
+ };
+ };
+}
+
+// Type guards
+export function isWorkoutExercise(exercise: any): exercise is WorkoutExercise {
+ return exercise && Array.isArray(exercise.sets);
+}
+
+export function isExerciseTemplate(exercise: any): exercise is ExerciseTemplate {
+ return exercise && 'recommendations' in exercise;
+}
\ No newline at end of file
diff --git a/types/library.ts b/types/library.ts
new file mode 100644
index 0000000..59b04a2
--- /dev/null
+++ b/types/library.ts
@@ -0,0 +1,55 @@
+// types/library.ts
+interface TemplateExercise {
+ title: string;
+ targetSets: number;
+ targetReps: number;
+ }
+
+export type TemplateType = 'strength' | 'circuit' | 'emom' | 'amrap';
+
+export type TemplateCategory =
+ | 'Full Body'
+ | 'Custom'
+ | 'Push/Pull/Legs'
+ | 'Upper/Lower'
+ | 'Cardio'
+ | 'CrossFit'
+ | 'Strength'
+ | 'Conditioning';
+export type ContentSource = 'local' | 'powr' | 'nostr';
+
+export interface Template {
+ id: string;
+ title: string;
+ type: TemplateType; // 'strength' | 'circuit' | 'emom' | 'amrap'
+ category: TemplateCategory;
+ exercises: TemplateExercise[];
+ description?: string;
+ tags: string[];
+ source: ContentSource;
+ isFavorite?: boolean;
+ lastUsed?: Date;
+ }
+
+export interface FilterOptions {
+ equipment: string[];
+ tags: string[];
+ source: ContentSource[];
+}
+
+export type ExerciseType = 'strength' | 'cardio' | 'bodyweight';
+export type ExerciseCategory = 'Push' | 'Pull' | 'Legs' | 'Core';
+export type ExerciseEquipment = 'bodyweight' | 'barbell' | 'dumbbell' | 'kettlebell' | 'machine' | 'cable' | 'other';
+
+export interface Exercise {
+ id: string;
+ title: string;
+ category: ExerciseCategory;
+ type?: ExerciseType;
+ equipment?: ExerciseEquipment;
+ description?: string;
+ tags: string[];
+ source: ContentSource;
+ usageCount?: number;
+ lastUsed?: Date;
+}
\ No newline at end of file
diff --git a/types/shared.ts b/types/shared.ts
new file mode 100644
index 0000000..f673292
--- /dev/null
+++ b/types/shared.ts
@@ -0,0 +1,54 @@
+// types/shared.ts
+/**
+ * Available storage sources for content
+ */
+export type StorageSource = 'local' | 'backup' | 'nostr';
+
+/**
+ * Nostr sync metadata
+ */
+export interface NostrSyncMetadata {
+ timestamp: number;
+ metadata: {
+ id: string;
+ pubkey: string;
+ relayUrl: string;
+ created_at: number;
+ };
+}
+
+/**
+ * Last synced information for different storage sources
+ */
+export interface LastSyncedInfo {
+ backup?: number;
+ nostr?: NostrSyncMetadata;
+}
+
+/**
+ * Content availability information
+ * Tracks where content is stored and when it was last synced
+ */
+export interface ContentAvailability {
+ source: StorageSource[];
+ lastSynced?: LastSyncedInfo;
+}
+
+/**
+ * Generic content metadata interface
+ * Can be extended by specific content types
+ */
+export interface ContentMetadata {
+ created_at: number;
+ updated_at?: number;
+ deleted_at?: number;
+ version?: number;
+}
+
+/**
+ * Base interface for all syncable content
+ */
+export interface SyncableContent extends ContentMetadata {
+ id: string;
+ availability: ContentAvailability;
+}
\ No newline at end of file
diff --git a/utils/ids.ts b/utils/ids.ts
new file mode 100644
index 0000000..7cdbc2b
--- /dev/null
+++ b/utils/ids.ts
@@ -0,0 +1,48 @@
+// utils/ids.ts
+
+/**
+ * Generates a unique identifier with optional source prefix
+ * @param source - Optional source identifier ('local' or 'nostr')
+ * @returns A unique string identifier
+ */
+export function generateId(source: 'local' | 'nostr' = 'local'): string {
+ // Generate timestamp and random parts
+ const timestamp = Date.now().toString(36);
+ const randomPart = Math.random().toString(36).substring(2, 15);
+
+ // For local IDs, use the current format with a prefix
+ if (source === 'local') {
+ return `local:${timestamp}-${randomPart}`;
+ }
+
+ // For Nostr-compatible IDs (temporary until we integrate actual Nostr)
+ // This creates a similar format to Nostr but is clearly marked as temporary
+ return `nostr:temp:${timestamp}-${randomPart}`;
+ }
+
+ /**
+ * Checks if an ID is a Nostr event ID or temporary Nostr-format ID
+ */
+ export function isNostrId(id: string): boolean {
+ return id.startsWith('note1') || id.startsWith('nostr:');
+ }
+
+ /**
+ * Checks if an ID is a local ID
+ */
+ export function isLocalId(id: string): boolean {
+ return id.startsWith('local:');
+ }
+
+ /**
+ * Extracts the timestamp from an ID
+ */
+ export function getTimestampFromId(id: string): number | null {
+ try {
+ const parts = id.split(':').pop()?.split('-');
+ if (!parts?.[0]) return null;
+ return parseInt(parts[0], 36);
+ } catch {
+ return null;
+ }
+ }
\ No newline at end of file